Maxima-Jupyter による数式処理とグラフ作成
葛西 真寿 弘前大学大学院理工学研究科
この Notebook では,「wxMaxima による数式処理とグラフ作成」のテキストの内容を,Jupyter Notebook 上で Maxima-Jupyter を使って説明しています。
セクションの構成は,wxMaxima 版のテキストに準じています。
ターミナル等で
jupyter notebook (または jupyter-notebook)
右上の「New」から 「Maxima」を選ぶ。
計算の実行は,数値や式などを入力して最後にセミコロン ; を入力後,Shift キーを押しならが Enter キー(または Return キー)を押します。
まずは簡単なかけ算 123×456 を計算してみます。
123 * 456;
2 の 100 乗 (2100) のような大きい数でも,厳密な結果を出力します。(^ は累乗を表します。)
2^100;
float
関数を使って不動小数点表示で近似値を出力させることもできます。
float(2^100);
Enter キーのみでは改行されるだけで計算が実行されません。Shift+Enter キーが入力されるまで,Maxima は式の入力が継続していると判断します。
例として,以下のような積分を計算してみます。Shift キーを忘れて Enter キーのみを押すと単に改行されます。慌てずにセミコロン ; を入力後, Shift キーを押しながら Enter キーを押すと実行します。
答えは $\int 3x^2\ dx = x^3$ です.
integrate(3*x^2, x)
;
Jupyter Notebook (の Maxima-Jupyter)で計算した結果を保存するには,「File」メニューから「Save as ... 」でファイル名をつけて保存します。
「File」メニューの真下に,なにやら四角で右上隅がかけている形のアイコンがありますが(これが「フロッピーディスク」というものであることは,20世紀の昔を知る人にしかわからないと思います),このアイコンをクリックしても保存されます。
また,「File」メニューから「Open... 」を選び,計算結果が保存された Notebook をまた利用することもできます。
Maxima の実行に際して,いくつか表記についての約束事があります。代表的なものを以下に示します。
コメント(実行に影響しない注釈)を 入れたいときは,/* ... */
でコメント部分を囲みます。
1 + 2 + 3;
1 + 2 /* + 3 */;
加法 +
,減法 -
,乗法 *
,除法 /
における優先順位は数学と同じです。優先して計算したい箇所は ( )
で 囲みます。
1 + 2 * 3;
(1 + 2) * 3;
ただし,大カッコ [ ]
や中カッコ { }
は優先順位の指定には用いません。
変数に式や値を代入するときは :
(コロン)を使います。
変数 a に,$100 + 3/21$ を代入して, a を使って計算を続けます.
a: 100 + 3/21;
(a - 100) * 7;
変数 eq
に式 $x^2 + 3 x + 2$ を代入します。
eq: x^2 + 3*x + 2;
eq
を factor
関数で因数分解します。
factor(eq);
関数の定義には :=
を使います。$f(x) := x^2$
f(x):= x^2;
$f(4) = 4^2 = 16$
f(4);
$f(3\sqrt{A}) = (3\sqrt{A})^2 = 9 A$ です。
f(sqrt(A)*3);
$\frac{d}{dx}(x \cos x)$ を計算します。
diff(x*cos(x), x);
以下の例のように f(x):= %
のような 仕方で(直前の)計算結果を参照して関数を定義することはできません。
g(x):= %;
g(x);
このような場合には define
を使います。%o16
は 16 番目の出力結果(今の場合は $\cos(x) − x \sin(x)$ です。)
define(g(x), %o16);
integrate(g(x), x);
文末に $
をつけると実行結果の出力を省略します。
eq: x^2 + 3*x + 2$
変数 eq
を出力させると...
確かに式 $x^2 +3x+2$ ですね.
eq;
2 次方程式 $x^2 +3x+2 = 0$ を solve
を使って解いていますが,結果は出力されません。$
ではなく ;
を文末 につけると結果が出力されます。
solve(eq = 0, x)$
solve(eq = 0, x);
直前の出力結果は %
と表します。これを参照してさらに計算することができます。また,以前の結果を参照する場合は %o26
のように行番号を指定することもできます。
expand
関数を使って展開します。
expand((x - 2)^4);
直前の結果を factor
関数で因数分解します。
factor(%);
行番号 %o26
の結果を展開します。
expand(%o26);
ev
関数を使うことで,一時的に式などに値を代入する事ができます。
変数 c
に 2*x
を代入します。
c: 2*x;
x=3
を一時的に代入して c
の値を評
価します。
ev(c, x=3);
c
の定義そのものは変わりません。
c;
方程式の解などは,リスト形式 ([ ]
で囲まれた形)で出力します。
リスト成分は [ ]
で取
り出すことができます。
関数 f(x)
を定義します。
f(x):= x^2 + 3*x + 2;
solve
で方程式 f(x) = 0
を解きます。
sol: solve( f(x) = 0, x );
リストとして表されている 2 個の解のうち,1 番目を sol[1]
として, 2 番目を sol[2]
としてそれぞれ取り出します。
sol[1];
sol[2];
rhs
は右辺 (right hand side) を取り出す関数です。また,左辺を取り出す関数は lhs
(left hand side) です。
x = -2
の右辺を取り出して ans1
に代入します。
二つめの解も同様に ans2
に代入します。
ans1: rhs(sol[1]);
ans2: rhs(sol[2]);
関数 f(x)
に解を入れると確かに 0
になります。
f(ans1);
f(ans2);
以下は見慣れない書式ですが, ev(f(x), sol[1])
の簡略形です。
f(x), sol[1];
1 から 10 までの和を求めてみます。
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10;
同様の計算は公式 $\sum_{i = 1}^{n} = n (n + 1)/2$ を 使ってもできます。
n: 10$
n*(n + 1)/2;
kill(n)$
ev(n*(n + 1)/2, n = 10);
以下は,ev(n*(n + 1)/2, n = 10)
の簡略形でしたね。
n*(n+1)/2, n = 10;
基本的な四則演算 (+ - * /
) 以外によく使われる演算記号を示します。
$2^4$ の計算。累乗は ^
で表します。^
のかわりに **
でもよいようです。
2^4;
2**4;
4 の階乗の計算をします. 4! = 4*3*2*1 = 24
です。
4!;
!!
は,一つおきの階乗の計算をします。5!! = 5*3*1
です。
5!!;
(練習) 3, 2, 1 でつくる最大の数
数字の 3 と 2 と 1 を 1 個ずつ使った演算でつくることができる最大の整数は?
ヒント:
(1 + 2) × 3 = 9
じゃ全然だめ。そのまま並べると 321
ですが,累乗を使うともっと大きい数をつくることができます。
$21^3$ とか,$31^2$ とか,$2^{31}$ とか...
Maxima の基本的な定数を示します。
円周率 $\pi$ | 無限大 $\infty$ | 自然対数の底 $e$ | 虚数単位 $i$ | |
%pi |
inf |
%e |
%i |
無理数 $e$,$\pi$ と虚数単位 $i$ と整数 $−1$ の間のすてきな関係,オイラーの等式 $$e^{i\pi} = -1$$
%e^(%i * %pi);
浮動小数点で近似値を表示するには float
や bfloat
を使います。
%pi;
float(%pi);
bfloat(%pi);
float
は 16 桁の値を返します.それ以上の桁数を見たいときには,bfloat
を使います。bfloat
の表示桁数は fpprec
で指定します。
有効数字 32 桁で円周率 $\pi$ を表示す る例です。
fpprec: 32$ bfloat(%pi);
基本的な関数は以下のように表記されます。
平方根 | 指数関数 | 自然対数 | 絶対値 | 三角関数 | 逆関数 | 双曲線関数 |
sqrt |
exp |
log |
abs |
sin cos tan |
asin acos atan |
sinh cosh tanh |
うっかり $\sqrt{x^2} = x$ としないように。 $\sqrt{x^2} = |x|$ です。
sqrt(x^2);
ピタゴラスの定理をみたす整数の例。 $\sqrt{3^2 + 4^2} = 5$ ですね。
sqrt(3^2 + 4^2);
$\exp(1) = e$ のこと。
$e^{\log x}$ や $\log(e^2)$ の計算。
exp(log(x));
log(%e^2);
(練習)ピタゴラス数
$a^2 + b^2 = c^2$ を満たす正の整数の組をピタゴラス数といいます。ピタゴラス数は二つの任意の正の整数 $m, n$ から以下のように何組でもつくることができます。
$$a=|m^2 −n^2|, \ b=2mn, \ c= \sqrt{a^2 +b^2} $$このとき,$c$ は必ず整数になることを示しなさい。
試しにやってみます。
kill(m, n)$ /* m, n を初期化 */
a: abs(m^2 - n^2);
b: 2 * m * n;
c: sqrt(a^2 + b^2);
直接証明することも簡単ですが,疑似乱数を使って,ちょっとした数値実験をしてみます。
random(100)
は 0
から 99
までの整 数疑似乱数をつくる関数です。
[a, b, c], m = random(100), n = random(100);
[a, b, c], m = random(100), n = random(100);
[a, b, c], m = random(100), n = random(100);
$c = \sqrt{a^2 + b^2}$ は確かに整数になっています。証明も簡単ですね。
(練習)星の明るさと等級
夜空に見える星の明るさ $L$ は等級 $m$ で表され,以下のような関係があります。
$m = −2.5 \log_{10} L + \mbox{const.}\quad$ ($\mbox{const.}$ は定数のこと)
1 等星と 6 等星では,どちらが何倍明るいですか?
load(log10)$
とすると,常用対数
$\log_{10}$ が使えます.
ですね.
load(log10)$
log10(1000);
三角関数の値を数値で求めたいときには,以下のようにします。
$\displaystyle \sin\frac{\pi}{3}$ の値は...
sin(%pi/3);
float
関数を使って,直前の結果を
浮動小数点表示します。
float(%);
変数 pi
に浮動小数点表示の $\pi$ の値を代入します。 浮動小数点表示で数値を入れると, sin
も浮動小数点表示で答えを返します。
pi: float(%pi);
sin(pi/3);
三角関数の引数はラジアンです。度を使って求めたいときは以下のようにします。
度をラジアンに変換する関数 degrad
を定義します。
degrad(60)
を引数にして sin
の値を求めます。
degrad(x):= x/180*%pi$
sin(degrad(60));
(練習)屋根勾配
家の屋根の勾配は角度ではなく,伝統的に 3 寸勾配,4 寸勾配のように水平方向に 1 尺(10 寸)に対して垂直方向に何寸立ち上がるかで示します。
図のログハウスの屋根は 8 寸勾配です。 傾斜角度にすると何度ですか?
以下に各寸勾配の角度の表があります。10 寸勾配まで表 を完成させましょう。
勾配 | 1寸勾配 | 2寸勾配 | 3寸勾配 | ... |
---|---|---|---|---|
atan(0.1) |
atan(0.2) |
atan(0.3) |
... | |
rad | 0.0997 | 0.1974 | 0.2915 | ... |
度 | 5.7106° | 11.3099° | 16.6992° | ... |
数列の和を計算する関数 sum
の書式は,sum(一般項 a_i,i,はじめの i,最後の i)
です。
$\displaystyle \sum_{i=1}^{100} i^2$ の計算をします。
sum(i^2, i, 1, 10);
一般の $n$ までの和は $\displaystyle \sum_{i=1}^{n} i^2$ ですが...
kill(n)$
sum(i^2, i, 1, n);
sum
関数は答えを出してくれません。nusum
は $n$ までの和を知っています。
nusum(i^2, i, 1, n);
(練習)数列の和
/* 1. のヒント */
a(a1, d, i):= a1 + d*(i-1);
nusum(a(a1, d, i), i, 1, n)$
/* 2. と 3. のヒント */
kill(b, b1, r, i)$
b(b1, r, i):= b1 * r^(i-1);
nusum(b(b1, r, i), i, 1, n)$
%, b1=3, r=2, n=10$
/* 4. のヒント */
/* r の範囲を宣言して... */
assume( 0 < r, r < 1);
nusum(b(b1, r, i), i, 1, n)$
limit(%, n, inf)$
$\sin x$ を$x = 0$ のまわりで $x^5$ までテイラー展開する例。
taylor(sin(x), x, 0, 5);
$e^{ix}$($i$ は虚数単位)のテイラー展開。
ty: taylor(exp(%i*x), x, 0, 5);
上記の虚部を imagpart
,実部を realpart
でとります。
imagpart(ty);
realpart(ty);
$\cos x, \tan x, \log (1 + x)$ 等のテイラー展開もやってみましょう。
taylor(log(1 + x), x, 0, 5);
Maxima では,多項式やいろいろな関数を含んだ式の変形や整理・簡単化が可能です。
$(x + 1)^2$ を展開します。
(x + 1)^2;
expand(%);
$x^3 - 1$ を因数分解します。
factor(x^3 - 1);
$\displaystyle \frac{3}{x^3 -1}$ を部分分数に展開する例。
partfrac(3/(x^3 - 1), x);
ratsimp
を使って,上式を「簡単化」します。
ratsimp(%);
三角関数や双曲線関数を含む式の簡単化には,trigsimp
関数などを使います。
$\cos^2 x - \sin^2 x$ を「簡単化」します。
trigsimp(cos(x)^2 - sin(x)^2);
trigreduce
は三角関数同士の積をなるべく減らして「簡単化」します。
trigreduce(cos(x)^2 - sin(x)^2);
通分すればもっと簡単になりますね。このへんが Maxima のつれないところです。
trigsimp(%);
trigexpand
関数は加法定理や倍角の公式を使って「展開」します。
trigexpand(cos(3*x));
trigsimp(%);
(練習)加法定理・三倍角の公式
/* 1. のヒント */
/* trigexpand で展開します。*/
trigexpand(sin(x + y))$
trigexpand(cos(x + y))$
trigexpand(tan(x + y))$
trigexpand(sinh(x + y))$
trigexpand(cosh(x + y))$
trigexpand(tanh(x + y))$
/* 2. や 3. のヒント */
trigexpand(sin(3*x));
trigsimp(%);
$\cos(x)^2$ を $1-\sin(x)^2$ で置き換える例です。
ratsubst(1-sin(x)^2, cos(x)^2, %)$
微分・積分を行う関数の表記を以下に示します。
操作 | 表記例 |
---|---|
微分 | diff(f(x), x) |
n 階微分 | diff(f(x), x, n) |
不定積分 | integrate(f(x), x) |
定積分 | integrate(f(x), x, a, b) |
数値積分 | romberg(f(x), x, a, b) |
$x^3 +5x+2$ を $x$ で微分します。
diff(x^3 + 5*x + 2, x);
$x^3 +5x+2$ を $x$ で 2 階微分します。
diff(x^3 + 5*x + 2, x, 2);
$x^2 \cos x + 2 x \sin x$ を $x$ で積分しま す。
integrate(x^2*cos(x) + 2*x*sin(x), x);
もう少し簡単になりそうですね。このへんが Maxima のつれないところです。
trigsimp(%);
定積分の例:$\displaystyle \int_0^{\pi/2} \sin x \, dx = 1$
以下の例では '
から始めると,その部分の計算を実行せずに形を整えて表示だけしてくれるところを示しています。
'integrate(sin(x), x, 0, %pi/2) =
integrate(sin(x), x, 0, %pi/2);
有名なガウス積分。不定積分はできないのに,無限区間の定積分だけはできる!という例。
'integrate(exp(-x^2), x, -inf, inf) =
integrate(exp(-x^2), x, -inf, inf);
(練習)関数の傾き
$\displaystyle y = \frac{2x - 1}{x+1}$ が $x \neq -1$ で増加関数であることを示しなさい。
(練習)積分
以下の積分をしなさい。
$$1.\ \int e^x \sin x \ dx \qquad 2. \ \int \frac{x^2 - 2 x - 2}{x^3 -1}\ dx$$解析的に積分できない場合は,数値積分によって近似値を求めることができます。
$\displaystyle \int_0^{\pi} \sin(\sin x)\ dx$ の計算をします。
integrate(sin(sin(x)), x, 0, %pi);
解析的に解けないと,そのままで返します。
romberg
関数を使うと,数値的に積分した結果を表示します。
r1: romberg(sin(sin(x)), x, 0, %pi);
数値積分 romberg
の精度は,大域変数 rombergtol
で決まります。
rombergtol
の値を小さくすることで精度をあげることができます。
デフォルトの rombergtol
の値は...
rombergtol;
rombergtol
を $10^{-12}$ にしてもう一度同じ数値積分を行うと...
rombergtol: 1.e-12$
r2: romberg(sin(sin(x)), x, 0, %pi);
r1 - r2;
Maxima は,式の計算だけでなく,代数方程式を解くことができます.例を以下に示します。
$x^2 +2x−2 = 0$ を $x$ について解き ます.
solve(x^2 + 2*x - 2 = 0, x);
連立方程式 $x^2 + y^2 = 5, \ x + y = 1$ を $x, y$ について解きます。
solve([x^2+y^2=5, x+y=1], [x, y]);
solve
の代わりに algsys
も使えます。
algsys([x^2+y^2=5, x+y=1], [x, y]);
3 次方程式 $x^3 = 8$ を解きます。
solve(x^3 = 8, x);
確認のため,上記の1番目の答えを3乗して簡単化すると...
rhs(%[1])^3, ratsimp;
実数解のみを求める場合は,
realroots
を使います。
realroots(x^3 = 8);
(練習)鶴と亀と蟻
鶴と亀と蟻,個体数の合計は 10。足の数は全部で 34 本。蟻は亀より 1 匹少ない。鶴,亀,蟻,それぞれ何羽・何匹?
鶴と亀と蟻の個体数をそれぞれ $x, y, z$ として連立方程式をたてて solve
します。蟻の足は何本かわかりますよね?
かつて線形代数の授業でこの問題を出したとき,真っ先に出た質問が「先生,蟻の足は何本ですか?」でした... orz
1 変数多項式方程式の数値解を求める関数として,
allroots
や find_root
があります。
$f(x) := x^3 + 8x - 3$ と定義します。
f(x):= x^3 + 8*x - 3;
allroots
を使って,$f(x) = 0$ の全数値解を求めます。
asol: allroots(f(x) = 0);
realroots
を使って $f(x) = 0$ の実
数解を求めます。
rsol: realroots(f(x) = 0);
float(%);
allroots
で求めた結果と少し違いますね。
精度を指定して再計算してみます。
realroots(f(x) = 0, 1e-16)$
float(%);
多項式方程式でない場合には find_root
関数を使って,範囲を指定して解を探します。
関数 $g(x):= (x − 1)\,e^x$ の定義。
$g(x):= (x − 1)\,e^x = 1$ の解は solve
などでは求めることができません。
g(x):= (x - 1)*exp(x);
solve(g(x) = 1, x);
find_root
を使って $0 \leq x \leq 2$ の 範囲で解を探してみます。
出た答えを代入して確かめると...
find_root(g(x) = 1, x, 0, 2);
g(%);
(練習)関数の極大値
次の関数が極大値をとる $x$ の値およびその極大値を求めよ。
$$ 1. \ \ f(x) = \frac{x^3}{e^x - 1}, \qquad 2. \ \ g(x) = \frac{x^5}{e^x -1}$$/* 1. のヒント */
/* f(x) を定義して,それを微分して... */
f(x):= x^3/(exp(x) - 1);
diff(f(x), x);
define(df(x), %);
/* 導関数が 0 になる x を数値的に求める */
find_root(df(x) = 0, x, 1, 5)$
/* 極値は... */
f(%)$
ode2
¶Maxima は 1 階および 2 階の常微分方程式も扱うことができます。
まず ode2
関数を使って
解く例を示します。
微分方程式を記述する際は diff
の
前の ’
に注意。
ode2
で $\displaystyle \frac{dy}{dt} = a y$ を解きます。
kill(a, t, y)$ /* 念のため,これから使う変数を初期化。 */
ode2('diff(y, t) = a* y, y, t);
%c
は積分定数です。
1 階常微分方程式の初期条件には ic1
を使い,例えば初期条件を
$t = 0$ で $y = 1$ とすると積分定数 %c
の値が決まります。
ic1(%, t = 0, y = 1);
2階常微分方程式 $\displaystyle \frac{d^2 x}{dt^2} + K x = 0$ を解く例です。
ここでは単振動の運動方程式を想定しているので $K > 0$です。あとで聞かれないように最初に仮定しておきます。
assume( K > 0);
ode2('diff(x, t, 2) + K*x = 0, x, t);
%k1
,%k2
は積分定数です。
2 階常微分方程式の初期条件は ic2
で設定します。
初期条件を $t = 0$ で $x=x_0, v=v_0$ とすると %k1
,%k2
が決まります。
ic2(%, t = 0, x = x[0], 'diff(x, t) = v[0]);
細かいことですが,x[0]
のようにすると Maxima は下付きの添字 $x_0$ として表示します。
desolve
¶常微分方程式を解く関数としては desolve
もあります。
ode2
と書式が若干違います。
また,初期条件は atvalue
関数で先に設定しておきます。
2 階の常微分方程式 $\displaystyle \frac{d^2 x}{dt^2} + K x = 0$ を解く例を以下に示します。
atvalue(x(t), t = 0, x[0]);
atvalue('diff(x(t), t), t = 0, v[0]);
desolve('diff(x(t), t, 2) + K*x(t) = 0, x(t));
ちなみに,$K \rightarrow 0$ の極限で,この解がどうなるかというと...
limit(%, K, 0);
最初から $K = 0$ とした微分方程式 $\displaystyle \frac{d^2 x}{dt^2} = 0$ を解いても...
desolve('diff(x(t), t, 2) = 0, x(t));
(練習)重力場中の投げ上げ運動
3 次元ベクトル $\boldsymbol{a} = (a_x,a_y,a_z)$ の表記例。
a: [a[x], a[y], a[z]];
$\boldsymbol{a}$ の $x$ 成分(第 1 成分)を取り出すには...
a[1];
ベクトル $\boldsymbol{b}$ も同様に定義。
b: [b[x], b[y], b[z]];
ベクトルの内積 $\boldsymbol{a} \cdot \boldsymbol{b}$ には .
(ドット)を使います。
a.b;
内積を利用して,ベクトルの大きさを返す関数 norm
を定義します。
norm(v):= sqrt(v.v);
norm(a);
ベクトルの外積 $\boldsymbol{a} \times \boldsymbol{b}$ を返す関数 cross
を定義します。
cross(u, v):=
[u[2]*v[3] - u[3]*v[2],
u[3]*v[1] - u[1]*v[3],
u[1]*v[2] - u[2]*v[1]]$
成分ごとに見てみます。
cross(a, b)[1];
cross(a, b)[2];
cross(a, b)[3];
(練習)ベクトルの内積,外積
$\displaystyle \boldsymbol{a} = \left(-\frac{1}{\sqrt{2}}, \frac{1}{\sqrt{2}}, \sqrt{3}\right), \boldsymbol{b} = \left(-1, 1, -\sqrt{2}\right)$ について,以下の量を計算しなさい。
$$1.\ \ |\boldsymbol{a}|, \quad 2.\ \ |\boldsymbol{b}|, \quad 3. \ \ \boldsymbol{a}\cdot\boldsymbol{b}, \quad 4. \ \ \boldsymbol{a}\times\boldsymbol{b}, \quad 5. \ \ \cos\theta, \quad 6. \ \ \sin\theta$$ここで $\theta$ は2つのベクトルのなす角。
(練習)ベクトルの 3 重積
/* 1. のヒント */
kill(c)$
c: [c[x], c[y], c[z]];
a.cross(b, c) - b.cross(c, a)$
expand(%)$
変数を別に再利用する際には,以前の定義を消しておきます。
kill(a, b, c, d)$
2 行 2 列の行列 A
の定義。
A: matrix([a, b], [c, d]);
transpose
は転置行列。
transpose(A);
determinant
は行列式。
determinant(A);
逆行列は A^^-1
のように書きます。
A^^-1;
$A^{-1}\, A$ が単位行列になることを確かめます。
行列の積も .
(ドット)で 表します。
A^^-1 . A, ratsimp;
回転行列 O
の定義。
O: matrix([cos(x), -sin(x), 0],
[sin(x), cos(x), 0],
[0, 0, 1]);
直交行列とは,転置行列が逆行列になっている行列のこと。この回転を表す行列 O
が直交行列であることを示してみます。
transpose(O) - O^^-1;
うーん,この辺が Maxima のつれないところです。
transpose(O) - O^^-1, trigreduce;
以下のようにしても,直交行列であることが示せます。
O. transpose(O);
trigsimp(%);
3 次元ベクトル $\boldsymbol{r}$ を,3 行 1 列の行列として定義します。このように成分を縦に並べたものを列ベクトルと言うんでしたね。
r: matrix([x], [y], [z]);
3 次元ベクトルの直交変換の例。
O . r;
(練習)直交変換されたベクトルの大きさ
$\boldsymbol{r}' \equiv O \,\boldsymbol{r}$ の大きさは $\boldsymbol{r}$ の大きさと同じであることを示しなさい。
/* ヒント */
(O.r) . (O.r)$
trigsimp(%)$
Maxima-Jupyter を使って,関数のグラフを描くことができます。また,数値データもグラフにすることができます。
/* Jupyter Notebook にインラインでグラフを表示させる場合,*/
/* 最初に以下のようにプロットオプションをセット。 */
set_plot_option([svg_file, "~/.maxplot.svg"])$
plot2d
の例¶2 次元グラフ $y = f(x)$ を描く一般的な表記例は以下の通りです。
plot2d(f(x), [x, a, b])
例として,$y = \sin x$ のグラフを $−2\pi \leq x \leq 2\pi$ の範囲で描きます。基本的な定数の一つである円周率 $\pi$ は Maxima では %pi
と書くのでしたね。
plot2d(sin(x), [x, -2*%pi, 2*%pi])$
plot3d
の例¶3 次元グラフ $z = g(x, y)$ を描く一般的な表記例は以下の通りです。
plot3d(g(x,y), [x, a, b], [y, c, d])
例として,$z = x \sin y$ のグラフを $-3 \leq x \leq 3, -4 \leq y \leq 4$ の範囲で描きます。
plot3d(x*sin(y), [x, -3, 3], [y, -4, 4])$
Maxima は,リスト形式のリスト形式の数値データもグラフ化することができます。
以下の例では,最初(左側)の数値を $x$ 座標の値,次(右側)の数値を $y$ 座標の値として 6 個の点 からなるリスト data
の各点をつないだ折れ線グラフを描きます。
data: makelist([i, i^2], i, 0, 5);
plot2d([discrete, data])$
オプションを設定してプロットする例。
ここでは,[style, points]
を設定して線でつながずに点で描きます。プロットオプションの style
には,points
の他にも,lines
,linespoints
, dots
が設定できます。
plot2d([discrete, data], [style, points])$
でかい点ですね。点のサイズを変更して描きます。
plot2d([discrete, data], [style, [points, 1.5]])$
Maxima で複数のグラフを重ねて表示する例を示します。
$y = x^2 - 1$ と $y = 4 x - 5$ の 2 つのグラフを重ねて描きます。
$x$ の範囲は $-5 \leq x \leq 5$ です。
以下の例でわかるように,重ねて描きたい関数を [x^2 - 1, 4*x - 5]
のように [
と ]
で囲んだリスト形式にして plot2d
コマンドを使います。
plot2d([x^2 - 1, 4*x - 5], [x, -5, 5])$
いくつかオプションを設定して描く例です。
以下の例では,縦軸 ($y$ 軸) の表示範囲を制限し たために,
plot2d: some values were clipped.
というメッセージが出ています。
plot2d([x^2 - 1, 4*x - 5], [x, -5, 5],
[y, -5, 10], /* 縦軸の表示範囲の設定 */
[color, red, black], /* 線の色の設定 */
[style, [lines, 4], lines], /* 片方の線の太さを4に */
[gnuplot_preamble, "set key bottom"] /* 凡例の位置 */
)$
上のグラフをみると,2 つのグラフは 1 点で接しているように見えます。
実際に $y = 4x - 5$ が接線であることを示してみましょう。
$x^2 - 1 = 4 x - 5$ の解が1つであることを示せば十分ですね。
sol: solve(x^2 - 1 = 4*x - 5, x);
$y = f(x)$ の $x = x_1$ における接線の方程式は, $$ y - f(x_1) = f'(x_1) \,(x - x_1)$$ ですから...
f(x):= x^2 - 1;
define(df(x), diff(f(x), x));
x1: rhs(sol[1]);
y = df(x1) * (x - x1) + f(x1), ratsimp;
できたら,$y = x2 - 1$ の $x = 1$ 等における接線のグラフも描いてみましょう。
Maxima では,あらかじめ作成された数値データファイルを読み込んでグラフを描くこともできます。
以下のような内容のファイル test.dat
がカレントディレクトリにあるとします。
0 0
1 1
2 4
3 9
4 16
5 25
データファイルを読み込む Maxima の関数は,read_nested_list
を使います。
dat: read_nested_list("test.dat");
plot2d([discrete, dat],
[x, 0, 6], [y, 0, 28], /* x, y の表示範囲を設定 */
[style, [points, 1]], [color, red], /* 大きさ,色 */
[gnuplot_preamble, "set key top left"], /* 凡例の位置 */
[legend, "データ"] /* 凡例表示の設定 */
)$
前節の数値データファイル test.dat
と理論曲線 $y = x^2$ の 2 つのグラフを重ねて表示してみます。
plot2d([[discrete, dat], x^2], [x, 0, 5], [y, 0, 28],
[style, [points, 1.5], lines], [color, red, blue],
[gnuplot_preamble, "set key top left"],
[legend, "データ", "理論曲線 y=x^2"]
)$
半径 $1$ の円の方程式は $x^2 +y^2 = 1$ です.この円を描くには,$y = \pm \sqrt{1 - x^2}$ として $y = f(x)$ の形にするよりも,以下のような媒介変数表示にしたほうが簡単でしょう。
$$ x=\cos t, \quad y=\sin t \quad (0 \leq t \leq 2\pi) $$媒介変数表示の 2 次元グラフを Maxima で描くには以下のようにします。
plot2d([parametric, cos(t), sin(t), [t, 0, 2*%pi]])$
グラフの縦横の 比を1:1にして円らしく見えるように,[same_xy]
を設定してみます。
[yx_ratio, 1]
でも同等です。
plot2d([parametric, cos(t), sin(t), [t, 0, 2*%pi]],
[same_xy],
[xlabel, "x"], [ylabel, "y"], [legend, "x^2+y^2=1"],
[x,-1.1, 1.1], [y, -1.1, 1.1]
)$
(練習)楕円のグラフ(楕円中心を原点にして)
同様にして,楕円のグラフを描くこともできます。 原点を中心とし,長半径 $a$,単半径 $b$ の楕円の式は
$$\frac{x^2}{a^2} + \frac{y^2}{b^2} = 1$$媒介変数表示では,$x=a \cos t, \ y=b \sin t, \ (0\leq t\leq 2\pi)$と書けます。 $a$,$b$ に適当な値を入れて楕円のグラフを描きなさい。
/* ヒント */
x(a, t):= a*cos(t)$
y(b, t):= b*sin(t)$
plot2d([parametric, x(1,t), y(1,t), [t, 0, 2*%pi]],
[same_xy],
[xlabel, "x"], [ylabel, "y"], [legend, "a=1, b=1"],
[x,-2, 2], [y, -2, 2]
)$
太陽からの万有引力を受けて運動する惑星は,太陽(二体問題では質量中心)を焦点の一つとした楕円運動を描いて運動します。 焦点の一つを原点とし,長半径 $a$,離心率 $e$ の楕円の方程式は,極座標 $r$,$\varphi$ を使って以下のように表すことができます。
$$ r= \frac{a (1−e^2)}{ 1 + e\cos\varphi}$$さて,かつては第9惑星,現在では準惑星の一つである冥王星も楕円軌道を描きます。冥王星の軌道長半径 $𝑎_P=39.767\mbox{AU}$,離心率 $𝑒_P=0.254$ を使って冥王星の軌道を描きます。
まず,極座標表示の楕円の式を関数として定義します。
r(a, e, t):= a*(1-e^2)/(1+e*cos(t))$
x(a, e, t):= r(a, e, t)*cos(t)$
y(a, e, t):= r(a, e, t)*sin(t)$
aP: 39.767$
eP: 0.254$
plot2d([parametric, x(aP, eP, t), y(aP, eP, t), [t, 0, 2*%pi]],
[same_xy],
[xlabel, "x"], [ylabel, "y"], [legend, "冥王星"],
[x,-50, 50], [y, -50, 50]
)$
では,この冥王星の軌道と,その内側をまわる海王星の軌道を重ねて描いてみましょう。
海王星の軌道長半径は $a_N=30.1104\mbox{AU}$,離心率は $e_N=0.0090$ と小さいので簡単のために $e_N=0$ として扱います。実際の2つの天体の軌道は同じ平面上にありませんが,太陽からの距離のみをみるために,ここでは同一平面上に描きます。
aN: 30.1104$
eN: 0$
plot2d([[parametric, x(aP, eP, t), y(aP, eP, t), [t, 0, 2*%pi]],
[parametric, x(aN, eN, t), y(aN, eN, t), [t, 0, 2*%pi]]
],
[same_xy],
[xlabel, "x"], [ylabel, "y"], [legend, "冥王星", "海王星"],
[x,-50, 50], [y, -50, 50]
)$
さて,この冥王星と海王星の軌道のグラフをいると,軌道が交差しているように見えます。このことを確かめます。
表示される領域を制限して,交差しているあたりを拡大してみます。
plot2d([[parametric, x(aP, eP, t), y(aP, eP, t), [t, 0, 2*%pi]],
[parametric, x(aN, eN, t), y(aN, eN, t), [t, 0, 2*%pi]]
],
[xlabel, "x"], [ylabel, "y"], [legend, "冥王星", "海王星"],
[x, 27, 29], [y, 10, 13]
)$
海王星の軌道は半径 $a_N$ の円としますから,以下の式を満たす角度 $\varphi$ を求めればよいことになります。
$$ r(a_P, e_P, \varphi) = a_N$$$0 < \varphi < \pi/2$ のどこかで交差しているようですから,このあたりで数値的に解を求める方法は以下の通りです。
phi1: find_root(r(aP, eP, t) = aN, t, 0, %pi/2);
$ -\pi/2 < \varphi < 0$ の範囲でも交差していますね。
対称性から答えは phi1
に負号をつけたものになるのは明らかですが,念のために確かめます。
phi2: find_root(r(aP, eP, t) = aN, t, -%pi/2, 0);
求めた角度はラジアン単位ですから,度に直してみます。
fpprintprec: 3$ /* 表示するケタ数を 3 に */
float(phi1*180/%pi);
この角度の 2 倍,つまり一周 360 度のうちに約 44 度にあたる分は海王星のほうが冥王星より 太陽から遠い位置にあることがわかります。
原点と 2 つの軌道の交点を結ぶ直線を描く方法は以下の通りです。
plot2d([[discrete, [[0, 0], [aN*cos(phi1), aN*sin(phi1)]]],
[discrete, [[0, 0], [aN*cos(phi2), aN*sin(phi2)]]]
],
[same_xy], [x,-50, 50], [y, -50, 50],
[xlabel, "x"], [ylabel, "y"], [legend, "", ""],
[color, black, black]
)$
原点と2つの軌道の交点を結ぶ直線を追加して,冥王星と海王星の軌道を描いてみます。
plot2d([[discrete, [[0, 0], [aN*cos(phi1), aN*sin(phi1)]]],
[discrete, [[0, 0], [aN*cos(phi2), aN*sin(phi2)]]],
[parametric, x(aP, eP, t), y(aP, eP, t), [t, 0, 2*%pi]],
[parametric, x(aN, eN, t), y(aN, eN, t), [t, 0, 2*%pi]]
],
[same_xy], [x,-50, 50], [y, -50, 50],
[xlabel, "x"], [ylabel, "y"], [legend, "", "", "冥王星", "海王星"],
[color, black, black, red, blue]
)$
青森市の月別平年気温のデータを使って行列 M
を作ります。
M: read_matrix("aomori.dat");
このデータをグラフに描いてみます。
数値データをグラフにする際には,すでに説明したように
plot2d([discrete, ... ])
を使いますが,使用するデータはリスト形式である必要があります。
今回は,すぐ後で述べる理由により,行列形式でデータを準備したので,args
関数を使って行列をリストに変換して plot2d
に渡します。
plot2d([discrete, args(M)], [style, [points, 1.5]])$
グラフを見ると,月別平年気温は 12 ヶ月周期の三角関数でフィットできるようにみえます。
では,以下のように関数フィットをしてみましょう。
まず,最小二乗法のパッケージ lsquares
をロードします.これは lsquares_estimates
を 初めて使う際,最初に 1 回だけ行えばよいです。
load(lsquares)$
次に,次のような関数を定義して,うまくフィットするように定数 a, b, c
を求めます。
最小二乗法を行う関数 lsquares_estimates
には数値データを行列として入れてやる必要があります。このために行列形式で月別平年気温のデータを準備したのでした。
kill(a0, a1, b1, f)$
f(x) := a0 + a1*cos(2*%pi*x/12) + b1*sin(2*%pi*x/12);
lsquares_estimates(M, [x, y], y=f(x), [a0, a1, b1])$
float(%);
最小二乗法によって求めた a0, a1, b1
の値を f(x)
に代入し,この関数を描きます。
fit: ev(f(x), %);
plot2d(fit,
[x, 0.5, 12.5], [y, -5, 28],
[style,lines], [color, red],
[gnuplot_preamble, "set xtics 1"],
[xlabel, "月"], [ylabel, "月別平年気温"], [title, "青森市の月別平年気温"]
)$
最終的に,月別平年気温の数値データとフィット曲線を重ねて描いてみます。
plot2d([[discrete, args(M)], fit],
[x, 0.5, 12.5], [y, -5, 28],
[style, [points, 1.5], [lines, 2]], [color, blue, red],
[gnuplot_preamble, "set xtics 1; set key samplen 1"],
[legend, "気温データ", "フィット曲線"],
[xlabel, "月"], [ylabel, "月別平年気温"], [title, "青森市の月別平年気温"]
)$
ちなみに,関数フィットした際の定数 a0
は月別平均気温の平均値に相当します。
平均値を求めるだけなら,最小二乗法などやらなくても以下のようにして求めることができます。
sum(M[i,2], i, 1, length(M))/length(M);
Maxima を使って,さらにいくつか問題に取り組んでみます。
$\sin(x - v t)$ は$x$の正の方向に速度$v$で進む正弦型の波動をあらわす。 波が進む様子を描いてみよう。
簡単のために,$v = 1$ とする。時刻 $t=0$ では,この波は $\sin x$。少し時間がたった後,たとえば $t = 0.5$ では,$\sin (x - 0.5)$,さらに,$\sin (x - 1.0)$,,$\sin (x - 1.5)$ など...
/* Jupyter Notebook にインラインでグラフを表示させる場合,*/
/* 最初に以下のようにプロットオプションをセット。 */
set_plot_option([svg_file, "maxplot.svg"])$
plot2d(sin(x),
[x, -10, 10], [y, -1.1, 1.1],
[style, [lines,2]], [color, red],
[xlabel, "x"], [ylabel, ""],
[gnuplot_preamble, "set key outside; set key samplen 1"],
[legend, "t = 0.0"])$
plot2d([sin(x), sin(x - 0.5)],
[x, -10, 10], [y, -1.1, 1.1],
[style, dots, [lines, 2, 2]],
[xlabel, "x"], [ylabel, ""],
[gnuplot_preamble, "set key outside; set key samplen 1"],
[legend, "t = 0.0", "t = 0.5"])$
plot2d([sin(x), sin(x - 0.5), sin(x - 1.0)],
[x, -10, 10], [y, -1.1, 1.1],
[style, dots, dots, [lines, 2, 2]],
[xlabel, "x"], [ylabel, ""],
[gnuplot_preamble, "set key outside; set key samplen 1"],
[legend, "t = 0.0", "t = 0.5", "t = 1.0"]
)$
plot2d([sin(x), sin(x - 0.5), sin(x - 1.0), sin(x - 1.5)], [x, -10, 10], [y, -1.1, 1.1],
[style, dots, dots, dots, [lines, 2, 2]],
[xlabel, "x"], [ylabel, ""],
[gnuplot_preamble, "set key outside; set key samplen 1"],
[legend, "t = 0.0", "t = 0.5", "t = 1.0", "t = 1.5"]
)$
draw
で GIF アニメ¶draw
関数を使うことで,Jupyter Notebook 環境で簡単にアニメーションを作ることができる。
draw(
terminal = animated_gif,
dimensions = [400, 300],
delay = 10,
file_name = "anim1",
makelist(gr2d(explicit(sin(x - 0.314*i), x, -10, 10)), i, 20)
)$
$x$ 軸,$y$ 軸を描き,縦軸の表示範囲を [-1.1, 1.1]
に設定し,少し早く動く GIF アニメにしてみます。
draw(
terminal = animated_gif,
delay = 5,
file_name = "anim2",
makelist(gr2d(explicit(sin(x - 0.314*i), x, -10, 10),
yrange = [-1.1, 1.1], xaxis = true, yaxis = true
), i, 20)
)$
振動数が少しだけ異なる2つの波を重ね合わせると「うなり」が起こることを示してみます。(高校の物理で習ったと思いますが,三角関数の加法則との関連で説明してみます。)
plot2d(sin(x + 0.05*x) + sin(x - 0.05*x), [x, -100, 100], [y, -2.1, 2.1],
[xlabel, ""], [ylabel, ""],
[gnuplot_preamble, "set key below"], [legend, "sin(x + 0.05*x) + sin(x - 0.05*x)"])$
sin(a + b) + sin(a - b), trigexpand;
... ですから,うなりとなる波形は $2 \cos b = 2 \cos 0.05x$ と早合点してしまいそうですが,これを描いてみると...
plot2d([sin(x + 0.05*x) + sin(x - 0.05*x), 2*cos(0.05*x)],
[x, -100, 100], [y, -2.1, 2.1],
[style, lines, [lines, 2, 2]],
[xlabel, ""], [ylabel, ""],
[gnuplot_preamble, "set key below"],
[legend, "sin(x + 0.05x) + sin(x - 0.05x)", "2 cos 0.05x"])$
そうではなくて,むしろ $2 |\cos 0.05x|$ ですよね。
plot2d([sin(x + 0.05*x) + sin(x - 0.05*x), 2*abs(cos(0.05*x))],
[x, -100, 100], [y, -2.1, 2.1],
[style, lines, [lines, 2, 2]],
[xlabel, ""], [ylabel, ""],
[gnuplot_preamble, "set key below"],
[legend, "sin(x + 0.05x) + sin(x - 0.05x)", "2 |cos 0.05x|"])$
つまり,$\omega_1 = a+b, \omega_2 = a-b$ の波を重ねると, 振動数の差の半分 $\displaystyle b = \frac{\omega_1 - \omega_2}{2}$ の コサイン波 $2 \cos b t$ が生じるように思えるが...
実際には,その絶対値 $2 | \cos b t|$ なので,振動数は実質その2倍,つまり うなりの振動数は $2 b = \omega_1 - \omega_2$ となり,
「振動数のわずかに異なる2つの波を重ねると,それらの振動数の差の振動数をもつうなりが発生する」
ということになる,という理解でどうでしょう。
波長・振幅が等しい正弦波が直線上を逆向きに同じ速さで進んでいると,重ね合わせによってどのような波が生じるか。
$$ \sin (x- v t) + \sin(x + v t)$$例を参考に,GIF アニメを作ってみてください。
plot2d(sin(x - 0) + sin(x + 0),
[x, -10, 10], [y, -2.1, 2.1],
[style, [lines, 3, red]],
[xlabel, ""], [ylabel, ""],
[gnuplot_preamble, "set key outside; set key samplen 1"],
[legend, "t = 0.0"])$
plot2d([sin(x - 0) + sin(x + 0), sin(x - 0.5) + sin(x + 0.5)],
[x, -10, 10], [y, -2.1, 2.1],
[style, dots, [lines, 3, red]],
[xlabel, ""], [ylabel, ""],
[gnuplot_preamble, "set key outside; set key samplen 1"],
[legend, "t = 0.0", "t = 0.5"])$
plot2d([sin(x - 0) + sin(x + 0),
sin(x - 0.5) + sin(x + 0.5),
sin(x - 1.0) + sin(x + 1.0)],
[x, -10, 10], [y, -2.1, 2.1],
[style, dots, dots, [lines, 3, red]],
[xlabel, ""], [ylabel, ""],
[gnuplot_preamble, "set key outside; set key samplen 1"],
[legend, "t = 0.0", "t = 0.5", "t = 1.0"])$
plot2d([sin(x - 0) + sin(x + 0),
sin(x - 0.5) + sin(x + 0.5),
sin(x - 1.0) + sin(x + 1.0),
sin(x - 1.5) + sin(x + 1.5)],
[x, -10, 10], [y, -2.1, 2.1],
[style, dots, dots, dots, [lines, 3, red]],
[xlabel, ""], [ylabel, ""],
[gnuplot_preamble, "set key outside; set key samplen 1"],
[legend, "t = 0.0", "t = 0.5", "t = 1.0", "t = 1.5"])$
draw(
terminal = animated_gif,
delay = 10,
file_name = "anim3",
makelist(gr2d(explicit(sin(x - 0.0628*i) + sin(x + 0.0628*i), x, -10, 10),
yrange = [-2.1, 2.1], xaxis = true, yaxis = true
), i, 100)
)$
水平な地上で,水平となす角 $\theta$ で斜め上方に初速度の大きさ $v_0$ でボールを投げ出す。 $v_0$ を一定としたとき,水平到達距離を最大にする $\theta$ は? またそのときの水平到達距離は?
水平方向を $x$,鉛直上向きを $y$ をすると,運動方程式は,
$$\frac{d^2 x}{dt^2} = 0, \quad \frac{d^2 y}{dt^2} = -g$$初期条件を $t = 0$ で $x(0) = 0, y(0) = 0, v_x(0) = v_0 \cos\theta, v_y(0) = v_0 \sin\theta$ として解きます。
ode2('diff(x, t, 2) = 0, x, t)$
ic2(%, t = 0, x = 0, 'diff(x, t) = v[0]*cos(theta));
ode2('diff(y, t, 2) = -g, y, t)$
ic2(%, t = 0, y = 0, 'diff(y, t) = v[0]*sin(theta));
... となるが,$g$ や $v_0$ に実際の次元のついた量をいれるのではなく,まずはこの式を,この系に特徴的な量で無次元化することを考える。
今,$\displaystyle \theta=\frac{\pi}{2}$ として垂直に投げ上げると,鉛直方向の $y$ は
$$ y = v_0 t - \frac{1}{2} g t^2 = \frac{v_0^2}{2 g} - \frac{1}{2} g \left( t - \frac{v_0}{g}\right)^2 $$となることから,特徴的な量として,$y$ が最大値をとる時刻 $\displaystyle t_m \equiv \frac{v_0}{g}$ と,その時の $y$ の最大値 $\displaystyle y_m \equiv \frac{v_0^2}{2g}$ を使って,以下のような無次元量をつくる。
$$ \bar{x} \equiv \frac{x}{y_m}, \quad \bar{y} \equiv \frac{y}{y_m}, \quad \bar{t} \equiv \frac{t}{t_m}$$これらの無次元量を使って軌道をあらわすと,
$$ \bar{x} = 2 \bar{t} \cos\theta, \quad \bar{y} = 2 \bar{t} \sin\theta - \bar{t}^2 $$以後は簡単のために $\bar{\ }$(バー)を省略する。
$\theta$ の値を変えて,$t$ を媒介変数としたグラフをいくつか描いてみる。
x(theta, t):= 2*t*cos(theta);
y(theta, t):= 2*t*sin(theta) - t**2;
th: %pi/4$
plot2d([parametric, x(th, t), y(th, t), [t, 0, 2]],
[xlabel, "x"], [ylabel, "y"], [legend, "θ = π/4"])$
媒介変数 $t$ の範囲を適当に [0:2]
とした図が上図であるが,$y$ の値がマイナスの領域まで描いてしまって,このボールが地面にめり込んでしまっている!!
$\displaystyle y = 2 t \sin\theta - t^2 = 0 $ から $t$ の範囲は $\theta$ によって異なり,$0 \le t \le 2 \sin\theta$ であることがわかるので, 以下のようにして,地面にめりこまないように,$y$ がふたたび $0$ になる時刻までのプロットにする。
th: %pi/4$
plot2d([parametric, x(th, t), y(th, t), [t, 0, 2*sin(th)]],
[xlabel, "x"], [ylabel, "y"], [legend, "θ = π/4"],
[xtics, 0.2], [ytics, 0.2], grid2d,
[x, 0, 2], [y, 0, 1], [yx_ratio, 0.5])$
初速度の角度を変え,いくつかプロット。
th1: %pi/6$
th2: %pi/5$
th3: %pi/4$
th4: %pi/3$
plot2d([[parametric, x(th1, t), y(th1, t), [t, 0, 2*sin(th1)]],
[parametric, x(th2, t), y(th2, t), [t, 0, 2*sin(th2)]],
[parametric, x(th3, t), y(th3, t), [t, 0, 2*sin(th3)]],
[parametric, x(th4, t), y(th4, t), [t, 0, 2*sin(th4)]]],
[xlabel, "x"], [ylabel, "y"], grid2d,
[legend, "θ = π/6", "θ = π/5", "θ = π/4", "θ = π/3"],
[xtics, 0.2], [ytics, 0.2], [gnuplot_preamble, "set grid"],
[x, 0, 2], [y, 0, 1], [yx_ratio, 0.5])$
さて,肝心の水平到達距離を最大にする $\theta$ だが,地上から投げ上げたボールが再び地上に戻ってくるまでの時間は,$y(\theta, t) = 0$ を $t$ について解いて...
solt: solve(y(theta,t) = 0, t);
$t = 2 \sin\theta$ をあらためて $x(\theta, t)$ に代入して...
x(theta, t), solt[1];
trigreduce(%);
これから,ただちに $x$ は $\theta=\pi/4$ のとき最大値 $2$ をとることがわかる。
あたらめて無次元化するまえの $x$ についてみると,最大到達距離は
$$x_{\max} = \bar{x}_{\max} \, y_m = 2 \times \frac{v_0^2}{2g} = \frac{v_0^2}{g}$$以下のような内容のファイル planets.dat
がカレント・ディレクトリにあるとします。
0.3841 0.24085
0.7233 0.61520
1.0000 1.00002
1.5237 1.88085
5.2026 11.8620
9.5549 29.4572
19.2184 84.0205
30.1104 164.7701
39.767 248
1列目の軌道長半径を x に,2列目の平均周期を y にしてプロットしてみます。
dat: read_nested_list("planets.dat")$
以下では,離散データ dat
をプロットするので,[style, [points, 1.5, red]]
のように points
でプロットすること,および点のサイズと色を指定しています。また,grid2d
でグリッド線を表示させています。
plot2d([discrete, dat], [style, [points, 1.5, red]], grid2d,
[xlabel, "軌道長半径 a"], [ylabel, "公転周期 T"])$
上のグラフを見る限りは,直線で禁じできるような単純な比例関係ではなさそうです。
以下のように,logx, logy,
として両対数グラフにしてみます。
plot2d([discrete, dat], [style, [points, 1.5, red]], grid2d, logx, logy,
[xlabel, "軌道長半径 a"], [ylabel, "公転周期 T"])$
両対数グラフにすると,データは直線に乗っているようにみえます。ということは, $\displaystyle T = K a^p$ のような関係になっていることが予想されます。
また,$a = 1$ のとき $T=1$ であることから,$K$ の値は $1$ にしてしまいましょう。
さらに,$a=10$ のあたりで $T$ の値は $10$ と $100$ の間であることから,$1 < p < 2$ であることが予想されます。
最少二乗法で $p$ の値を求めてみます。
load(lsquares)$
M: read_matrix("planets.dat")$
f(x):=x^p;
fpprintprec: 3$
lsquares_estimates(M, [x, y], y=f(x), [ p])$
float(%);
fit: ev(f(x), %);
$\displaystyle T = a^{1.5}$ のような関係が得られました。
実際のケプラーの第3法則も,$T \propto a^{1.5}$ すなわち,$\displaystyle T^2 \propto a^3$ です。
plot2d([[discrete, dat], fit], [x, 0.1, 100],
[style, [points, 1.5, red], [lines, 1, blue]], grid2d, logx, logy,
[gnuplot_preamble, "set key top left"], [legend, "惑星データ", "T = a^{1.5}"],
[xlabel, "軌道長半径 a"], [ylabel, "公転周期 T"])$
各惑星のデータは,
dat: read_nested_list("planets.dat")$
M: read_matrix("planets.dat")$
として既に読み込んでいました。
リストか行列かによって,成分の取り出し方は微妙に違います。
dat[1]; dat[1][1];
M[1]; M[1,1];
/* args 関数で行列をリストに変換できるのでしたね。 */
args(M)[1]; args(M)[1][1];
簡単のために,惑星(および冥王星)を離心率 $e=0$ の円軌道として,地球がちょうど1周する間に他の惑星がどれだけ公転運動するかを描いてみます。
半径 $a_i$,公転周期 $T_i$ の天体の $t=0$ での初期位置を $x$ 軸上として,時刻 $t$ における位置は
$$x = a_i \cos \frac{2\pi t}{T_i} = a_i \cos \omega_i\ t, \quad y = a_i \sin \frac{2\pi t}{T_i} = a_i \sin \omega_i\ t$$です。
a(i):= M[i,1]$
T(i):= M[i,2]$
omega(i):= 2*float(%pi)/T(i)$
x(i,t):= a(i)*cos(omega(i)*t);
y(i,t):= a(i)*sin(omega(i)*t);
まずは地球の公転軌道を描きます。
plot2d([parametric, x(3, t), y(3, t), [t, 0, T(3)]], [xlabel,""], [ylabel,""],
[gnuplot_preamble,"set key top left"],
[legend, "地球"])$
地球の公転軌道が円にみえるように調整し,他の惑星の軌道もあわせて描きます。
plot2d([[parametric, x(3, t), y(3, t), [t, 0, T(3)]],
[parametric, x(4, t), y(4, t), [t, 0, T(3)]],
[parametric, x(5, t), y(5, t), [t, 0, T(3)]],
[parametric, x(6, t), y(6, t), [t, 0, T(3)]]
],
[x, -2, 10], [y, -2, 4], [yx_ratio, 0.5],
[legend, "地球", "火星", "木星", "土星"], [gnuplot_preamble,"set key top left"],
[xlabel,""], [ylabel,""] )$
(練習)
人口変化のしかたを明らかにし,将来の変化を予測するモデルを定式化するこ とは実社会において非常に重要な問題である。ここでは,まずマルサスの 「人口論」に書かれたアイデアを紹介する。
時刻 $t$ におけるある国の総人口を $N(t)$ とする。短い時間間隔 $dt$ における 出生数と死亡数は,ともにその時点での総人口と時間間隔に比例するから,
$$\mbox{出生数} = \alpha N dt, \quad \mbox{死亡数} = \beta N dt $$したがって,時間間隔$dt$での人口の増加$dN$は
$$dN = \alpha N dt - \beta N dt = \gamma N dt, \quad\mbox{ただし}\ \gamma \equiv \alpha - \beta $$これは微分方程式
$$\frac{dN}{dt} = \gamma N $$であり,次のように解ける。
ode2('diff(N, t) = gamma * N, N, t)$
ic1(%, t = t[0], N = N[0]);
つまり, $$N(t) = N_0 \,e^{\gamma (t - t_0)} $$
ここで,$N_0 = N(t_0)$ は $t_0$ 年の人口である。また,$\gamma$ は,$t_0$ 年と $t_1$ 年の人口を使って以下のように求めることができる。
$$ \gamma = \frac{1}{t_1 - t_0} \ln\left(\frac{N(t_1)}{N_0} \right)$$参考文献にあった,米国の人口データをファイルにしてあるので,これを読み込み,グラフに描きます。
usa: read_matrix("usa.dat")$
plot2d([discrete, args(usa)],
[style, [points, 1.5]], grid2d,
[xlabel,"年"], [ylabel, "人口(単位:百万人)"],
[gnuplot_preamble, "set key top left"],
[legend, "米国の人口"])$
人口データから,$t_0, N_0, \gamma$ の値を求め,マルサスモデル $N(t) = N_0 \,e^{\gamma (t - t_0)}$ を重ねて描きます。
t0: usa[1,1]$
N0: usa[1,2]$
gamma: 1/(usa[2,1]-usa[1,1])*log(usa[2,2]/usa[1,2])$
Nm(t):= N0*exp(gamma*(t-t0));
plot2d([[discrete, args(usa)], Nm(t)], [t, 1780, 1940],
[style, [points, 1.5], lines], grid2d,
[xlabel,"年"], [ylabel, "人口(単位:百万人)"],
[gnuplot_preamble, "set key top left"],
[legend, "米国の人口", "マルサスモデル"])$
マルサス・モデルは,$\gamma > 0$ の場合には人口の際限ない増加を予測する。 しかし,実際には食糧資源の供給不足,人口の過密,その他の環境的要因によ り,このような無制限な増加は続かない。
ヴェアフルストは,人口過密の要因を考慮にいれて,次のような修正を提案し た。人口は継続し続ける限り増加するが,上限 (それを$N_{\max}$としよう) があるとする。そして,人口変化は,次の各々に比例すると仮定する:
したがって微分方程式は
$$ \frac{dN}{dt} = \gamma N \left(1 - \frac{N}{N_{\rm max}}\right) $$となり,(変数分離法によってこの式は解けて)解は
$$ N(t) = N_0 \frac{N_{\rm max}}{N_0 + (N_{\rm max}-N_0)\,e^{-\gamma (t-t_0)}} $$パラメータ $N_{\max}$ をどのように選ぶと,米国の人口変化をよく再現するか,調べてみます。
t0: usa[1,1]$
N0: usa[1,2]$
gamma: 1/(usa[2,1]-usa[1,1])*log(usa[2,2]/usa[1,2])$
Nv(t):= N0*Nmax/(N0 + (Nmax - N0)*exp(-gamma*(t-t0)));
fpprintprec: 8$
lsquares_estimates(usa, [t, y], y = Nv(t), [Nmax])$
float(%);
fit: Nv(t), %;
plot2d([[discrete, args(usa)], Nm(t), fit], [t, 1780, 1940],
[style, [points, 1.5], lines, [lines, 2, blue]], grid2d,
[xlabel,"年"], [ylabel, "人口(単位:百万人)"],
[gnuplot_preamble, "set key top left"],
[legend, "米国の人口", "マルサスモデル", "ヴェアフルストモデル"])$
周期$2L$の周期関数$f(x)$のフーリエ級数展開は
$$ f(x) = \frac{a_0}{2} + \sum_{n=1}^{\infty}\left( a_n \cos\frac{n\pi x}{L} + b_n \sin \frac{n\pi x}{L}\right) $$ここで,フーリエ係数 $a_n, b_n$ は以下のように求めるのであった。
$$ a_n = \frac{1}{L} \int_{-L}^{L} f(x)\cos\frac{n\pi x}{L}\, dx, \quad b_n = \frac{1}{L} \int_{-L}^{L} f(x)\sin\frac{n\pi x}{L}\, dx. $$以下のように $\pi \le x < \pi$ で定義された矩形が,この領域外では周期 $2\pi$ の矩形波となっている例。
$$ f(x) = \left\{ \begin{array}{rl} -1 & \mbox{$(-\pi \le x < 0)$} \\ 1 & \mbox{$(0 \le x < \pi)$} \end{array} \right. $$Maxima でこの周期的矩形波をどうやって表すかが,工夫のしどころ。
私としては,以下を提案する。
$$ f(x) = \mbox{signum}(\sin x) $$ここで,$\mbox{signum}(x)$ は,$x>0$ のとき $+1$,$x<0$ のとき $-1$ を返す関数。
f(x):= signum(sin(x));
plot2d(f(x), [x, -2*%pi, 2*%pi], [y, -1.5, 1.5], [xtics, %pi], grid2d, [ylabel,""],
[gnuplot_preamble, "set format x '%4.1P π'"],
[legend,"f(x)"])$
$f(x)$ は奇関数なので,フーリエ係数は $b_n$ のみ。
b(n):= 1/%pi * integrate((-1)*sin(n*x), x, -%pi, 0)
+ 1/%pi * integrate((+1)*sin(n*x), x, 0, %pi)$
Fourier(n, x):= sum(b(i)*sin(i*x), i, 1, n)$
for i:1 thru 9 do print("b[", i, "] = ", b(i) );
plot2d([f(x), Fourier(1,x)],
[x, -2*%pi, 2*%pi], [y, -1.5, 2], [xtics, %pi], grid2d, [ylabel,""],
[style, lines, [lines, 3, red]],
[gnuplot_preamble, "set format x '%4.1P π'"],
[legend,"f(x)", "n = 1"])$
plot2d([f(x), Fourier(1,x), Fourier(3,x)],
[x, -2*%pi, 2*%pi], [y, -1.5, 2], [xtics, %pi], grid2d, [ylabel,""],
[style, lines, [dots, gray], [lines, 2, red]],
[gnuplot_preamble, "set format x '%4.1P π'"],
[legend,"f(x)", "", "n = 3"])$
plot2d([f(x), Fourier(1,x), Fourier(3,x), Fourier(5,x)],
[x, -2*%pi, 2*%pi], [y, -1.5, 2], [xtics, %pi], grid2d, [ylabel,""],
[style, lines, [dots, gray], [dots, gray], [lines, 3, red]],
[gnuplot_preamble, "set format x '%4.1P π'"],
[legend,"f(x)", "", "", "n = 5"])$
plot2d([f(x), Fourier(1,x), Fourier(3,x), Fourier(5,x), Fourier(7,x)],
[x, -2*%pi, 2*%pi], [y, -1.5, 2], [xtics, %pi], grid2d, [ylabel,""],
[style, lines, [dots, gray], [dots, gray], [dots, gray], [lines, 3, red]],
[gnuplot_preamble, "set format x '%4.1P π'"],
[legend,"f(x)", "", "", "", "n = 7"])$
以下のように $\pi \le x < \pi$ で定義された三角形が,この領域外では周期 $2\pi$ の三角波となっている例。
$$ f(x) =\left\{ \begin{array}{rl} \pi + x, &\mbox{$(-\pi \le x < 0)$} \\ \pi - x, &\mbox{$(0 \le x < \pi)$} \end{array} \right. $$Maxima でこの周期的三角波をどうやって表すかが,工夫のしどころ。
私としては,以下を提案する。
f(x):= abs(x - 2*%pi*floor(x/(2*%pi)) - %pi)
f(x):= abs(x - 2*%pi*floor(x/(2*%pi)) - %pi);
plot2d(f(x),
[x, -3*%pi, 3*%pi], [y, -0.2, 4],
[xtics, %pi], [ytics, 0.5*%pi], grid2d, [ylabel,""],
[gnuplot_preamble, "set format x '%4.1P π'; set format y '%4.1P π'"],
[legend,"f(x)"])$
$f(x)$ は偶関数なので,フーリエ係数は $a_n$ のみ。
a(n):= 1/%pi * integrate((%pi + x)*cos(n*x), x, -%pi, 0)
+ 1/%pi * integrate((%pi - x)*cos(n*x), x, 0, %pi)$
Fourier(n, x):= a(0)/2 + sum(a(i)*cos(i*x), i, 1, n)$
makelist(a(i), i, 0, 8);
plot2d([f(x), Fourier(1,x)],
[x, -3*%pi, 3*%pi], [y, -0.2, 4],
[xtics, %pi], [ytics, 0.5*%pi], grid2d, [ylabel,""],
[style, lines, [lines, 3, red]],
[gnuplot_preamble, "set format x '%4.1P π'; set format y '%4.1P π'"],
[legend,"f(x)", "n = 1"])$
plot2d([f(x), Fourier(1,x), Fourier(3,x)],
[x, -3*%pi, 3*%pi], [y, -0.2, 4],
[xtics, %pi], [ytics, 0.5*%pi], grid2d, [ylabel,""],
[style, lines, [dots, gray], [lines, 3, red]],
[gnuplot_preamble, "set format x '%4.1P π'; set format y '%4.1P π'"],
[legend,"f(x)", "", "n = 3"])$
plot2d([f(x), Fourier(1,x), Fourier(3,x), Fourier(5,x)],
[x, -3*%pi, 3*%pi], [y, -0.2, 4],
[xtics, %pi], [ytics, 0.5*%pi], grid2d, [ylabel,""],
[style, lines, [dots, gray], [dots, gray], [lines, 3, red]],
[gnuplot_preamble, "set format x '%4.1P π'; set format y '%4.1P π'"],
[legend,"f(x)", "", "", "n = 5"])$
plot2d([f(x), Fourier(1,x), Fourier(3,x), Fourier(5,x), Fourier(7,x)],
[x, -3*%pi, 3*%pi], [y, -0.2, 4],
[xtics, %pi], [ytics, 0.5*%pi], grid2d, [ylabel,""],
[style, lines, [dots, gray], [dots, gray], [dots, gray], [lines, 3, red]],
[gnuplot_preamble, "set format x '%4.1P π'; set format y '%4.1P π'"],
[legend,"f(x)", "", "", "", "n = 7"])$