裏 RjpWiki

Julia ときどき R, Python によるコンピュータプログラム,コンピュータ・サイエンス,統計学

SymPy/Julia(2)

2021年11月24日 | ブログラミング

SymPy/Julia

https://www.math.csi.cuny.edu/~verzani/tmp/julia/symbolic.html

5. 数式の図示

数式は,Julia へ戻ることなく,直接プロットすることができる。

f(x) = sin(x^4) - cos(x^4) を [0,1] の範囲で描くには以下のようにする。

  using Plots
  gr(label="")
  f(x) = sin(x^4) - cos(x^4)
  plot(f(x), 0, 1)

plot の第一引数は関数でなくて,数式でよい。

  g = sin(x^4) - cos(x^4)
  plot(g, 0, 1)

f(x) も g も,どちらも Sym オブジェクトである。

  println("f(x): $(f(x)),  typeof(f(x)): $(typeof(f(x)))")
  println("g:    $g,  typeof(g):    $(typeof(g))")
  f(x): sin(x^4) - cos(x^4),  typeof(f(x)): Sym
  g:    sin(x^4) - cos(x^4),  typeof(g):    Sym

複数の数式は plot(), plot!() で図示する(一回の plot() 呼び出しだけで図示する方法はできなくなった)。

  f(x) = sqrt(x)
  fp = diff(f(x)) # fp は関数ではなく数式
  c = 2
  m = fp(x => c)  # at c=2
  println("c = $c,  m = $m")
  c = 2,  m = sqrt(2)/4
  plot(f(x), 1, 3)
  plot!(f(c) + m * (x - c))

5.1. 課題

5.1.1. 問題 1.

x^4 - 3x^3 + 3x^2 - 3x +2 を [-1, 3] の範囲で描画せよ。実数解はいくつあるか。

  g = x^4 - 3x^3 + 3x^2 - 3x + 2
  plot(g, -1, 3)
  savefig("fig4.png")
  solve(g) |> println
  real_roots(g) |> println
  real_roots(g) |> length |> println
  Sym[1, 2, -I, I]
  Sym[1, 2]
  2

6. 極限

limit() 関数は,数式の極限を求める。

limit() 関数の第 1 引数に数式を指定する。第 2 引数にどの変数について計算するか,第 3 引数はその変数をどこへ近づけていくかを指定する。

  limit(sin(x)/x, x, 0) |> println
  1
  limit((1-cos(x))/x^2, x, 0) |> println
  1/2

無限大は小文字の o を 2 個続けて表す。

  limit(sin(x)/x, x, oo) |> println
  0

関数の導関数は limit() 関数を使って数式計算できる(数値計算もできるが)。

  @syms h
  f(x) = x^10
  limit((f(x + h) - f(x))/h, h, 0) |> println
  10*x^9

diff() での結果とあっている。

  diff(f(x)) |> println
  10*x^9

同じ結果を与えるがもっと複雑な計算式を使う方法もある。

  central_difference(f, x, h) = ( f(x + h) - f(x - h) ) / (2h)
  a = limit(central_difference(f, x, h), h, 0) |> println
  10*x^9

更にもっと複雑な計算式もある。

  central_4th_difference(f, x, h) = (-f(x + 2h) + 8f(x + h) - 8f(x - h) + f(x - 2h))/(12h)
  limit(central_4th_difference(f, x, h), h, 0) |> println
  10*x^9

limit() はチェイン規則にしたがう。

  func(x) = sin(x)
  limit((f(func(x + h)) - f(func(x))) / h, h, 0) |> println # 10*sin(1)^9*cos(1)
  10*sin(x)^9*cos(x)

6.1. 課題

6.1.1. 問題 1.

(3 - √(x + 5)) / (x - 4) の x を 4 に近づけていくときの極限を求めよ。

  f(x) = (3 - sqrt(x + 5)) / (x - 4)
  a = limit(f(x), x, 4)
  println("a = $a, float(a) = $(float(a))")
  a = -1/6, float(a) = -0.16666666666666666

6.1.2. 問題 2.

(x^(1/4) - 1) / (x^(1/3) - 1) の x を 1 に近づけていくときの極限を求めよ。

  f(x) = (x^(1/4) - 1) / (x^(1/3) - 1)
  limit(f(x), x, 1) |> float |> println
  0.75

6.1.3. 問題 3.

記号変数 h を定義し,f(x) = sin(x) とする。

  @syms h
  f(x) = sin(x);

(f(x+h) - 2f(x) + f(x-h)) / h^2 の h を 0 に近づけていくときの極限は,何になるか。

  gg = (f(x+h) - 2f(x) + f(x-h)) / h^2
  limit(gg, h, 0) |> println
  (diff(f(x), x), diff(f(x), x, 2), diff(f(x), x, 3)) |> println
  -sin(x)
  (cos(x), -sin(x), -cos(x))

この式は limit() 関数で 2 次の導関数を求めるための式である。

  f(x) = 3x^3 + 2x^2 +3x + 4
  limit(gg, h, 0) |> println
  expand(diff(f(x), x, 2)) |> println
  -sin(x)
  18*x + 4

6.1.4. 問題 4.

記号変数 a を定義し,

(cos(a * x) - 1) / (cos(x) - 1) において x を 0 に近づけていくときの極限は,何になるか。

  @syms a
  limit((cos(a * x) - 1) / (cos(x) - 1), x, 0) |> println
  a^2

6.1.5. 問題 5.

式 f(x) = 1/(x^(log(log(log(1/x)))-1)) の x を 0 に近づけていくときの極限を数値的に求めることができる。

  f(x) = 1/(x^(log(log(log(1/x)))-1))
  xs = 0.1 .^ (2:4:40)
  fxs = [f(x) for x in xs]
  [xs fxs]
  10×2 Matrix{Float64}:
   0.01        0.0702822
   1.0e-6      0.619862
   1.0e-10    27.0054
   1.0e-14  2695.41
   1.0e-18     4.65934e5
   1.0e-22     1.20915e8
   1.0e-26     4.32215e10
   1.0e-30     2.00968e13
   1.0e-34     1.16712e16
   1.0e-38     8.21329e18

数式的に極限を求めると,結果は ∞ になり,数値的な場合に予測されたものに一致する(途中に float() を挟まない場合は,Inf を表す "oo" が表示される)。

  limit(f(x), x, 0) |> float |> println
  Inf

6.1.6. 問題 6.

式 f(x) = log(log(xexp(xexp(x)) + 1)) - exp(exp(log(log(x)) + 1/x)) で,x を ∞ に近づけていくときの極限を求めよ。

極限は 0 であるが,数値的に確認することはできない。

例えば f(10) をもとめてみよ。

  f(x) = log(log(x*exp(x*exp(x)) + 1)) - exp(exp(log(log(x)) + 1/x))
  f(x) |> println
  -exp(exp(1/x)*log(x)) + log(log(x*exp(x*exp(x)) + 1))
  f(10) |> println
  Inf

確かに x = 10 の時点で Inf になってしまっている。

しかし,x として長精度実数を使うと実は結果は Inf ではないことがわかる。

  f(big(10))
  -0.4374481647059431342589507553638095674342208743587679099109922069614458809810611

喜びもつかの間,x が大きくなるとそのうち(いくら使用する精度を高くしても) Inf になってしまう(要するに想像を絶する大きな数値になるのだ)。

  f(big(39))
  Inf

limit() 関数を使えば,正しい答え 0 が導かれる。

  limit(f(x), x, oo) |> println
  0

7. 導関数

前述したように,limit() を使って導関数を求めることもできるが,SymPy には導関数を求めるための diff() 関数がある。

以下で,f(x) は 関数ではなく,数式 Sym である。

  f(x) = exp(exp(x))
  f (generic function with 1 method)

数式中に変数が 2 個以上ある場合は,どの変数について導関数を求めるかを指定する(デフォルトは x)。

  diff(f(x)) |> println
  diff(f(x), x)  |> println
  exp(x)*exp(exp(x))
  exp(x)*exp(exp(x))

第三引数で何階導関数かを指定する(デフォルトでは 1)

  diff(f(x), x, 2) |> println
  (exp(x) + 1)*exp(x)*exp(exp(x))

x^x と,その導関数のグラフを描いてみる。

  f(x) = x^x
  plot(f(x), 1/10, 2, label="f(x)")
  plot!(diff(f(x)), label="f'(x)")

f(x) と c = 1 での切線のグラフを描く。

  f(x) = x^x; c = 1
  m = diff(f(x))
  plot(f(x), .5, 1.5)
  plot!(f(c) + m * (x - c))

7.1. 番外

diff() と solve() を組み合わせて,閉区間内の極値 f'(x) = 0 となる x を求めることができる。

3 辺の長さの和 L が一定の長方形の面積 A を最大にする問題を考えよう。

L = 2x + y
A = x * y

すなわち,A(x) = x * (L - 2x)

L を記号変数として,A'(x) = 0 となる x を求め,A(x) を求める。

  @syms L, x, y
  A = x*y
  A = A(y => L - 2x)
  out = solve(diff(A, x), x)[1]
  out |> println # x
  L/4
  (L - 2x)(x => out) |> println # y
  L/2

7.2. 課題

7.2.1. 問題 1.

tan(x)^(-1) の導関数を求めよ。

落とし穴(?)。tan(x)^(-1) は 1/tan(x) ではない。tan(x) の逆関数なので,atan(x) だ。

  diff(atan(x)) |> println
  1/(x^2 + 1)

微分は積分の逆なのだから,結果として提示されている 3 つの選択肢を integrate() してみればよい。atan(x) が解になる。

  integrate(1/(x^2 + 1)) |> println
  atan(x)

7.2.2. 問題 2.

f(x) = exp(-cos(x)) のとき,f'(3) を求めよ。

  diff(exp(-cos(x)))(x => 3) |> println 
  diff(exp(-cos(x)))(x => 3) |> float   |> println
  exp(-cos(3))*sin(3)
  0.3797841807457766324319619290395706689950768584935908050136628093384225996266999

7.2.3. 問題 3.

f(x) = 1/x^2 + x^3 の極値を求めよ。nsolve(diff(f(x)), 1) も試してみよ。

注: Julia では,? nsolve としても No documentation found. となるばかりだ。
Python の sympy で help(nsolve) でやっと,
Solve a nonlinear equation system numerically.
nsolve(f, [args,] x0, modules=['mpmath'])
'f' is a vector function of symbolic expressions representing the system.
args are the variables. If there is only one variable, this argument can
be omitted. 'x0' is a starting vector close to a solution.

  @syms x::real
  f(x) = 1/x^2 + x^3
  solve(diff(f(x)))              |> println
  solve(diff(f(x)))     |> float |> println
  nsolve(diff(f(x)), 1) |> float |> println # 1 は初期値
  Sym[2^(1/5)*3^(4/5)/3]
  [0.9221079114817278]
  0.9221079114817277656701705309291930146705850859540336029625316749125970624956978

7.2.4. 問題 4.

f(x) = tan(x) として, ニュートン法により 切線の方程式が f(c) + f'(c)(x-c) = 0 になるときの x を求めよ。

  f(x) = tan(x)
  @syms c
  solve(f(c) + diff(f(c)) * (x - c), x) |> println
  Sym[c - sin(2*c)/2]

c = pi/4 とすると何が得られるか?

  solve(f(c) + diff(f(c)) * (x - c), x)[1](c => PI/4) |> float |> println
  0.2853981633974483096156608458198757210492923498437764552437361480769541015715538

8. 積分(不定積分)

SymPy でも数式積分を行うことができるが,Mathematica に比べると劣る。

数値積分を行うのは integrate() である。

  @syms x, a
  f(x) = cos(x) - sin(x)
  integrate(f(x), x) |> println
  sin(x) + cos(x)

定数を含むこともできる。

  integrate(1/cos(x + a), x) |> println
  -log(tan(a/2 + x/2) - 1) + log(tan(a/2 + x/2) + 1)

その他の例

  integrate(x^3 * (1-x)^4, x) |> println
  x^8/8 - 4*x^7/7 + x^6 - 4*x^5/5 + x^4/4
  integrate(x/(x^2+1), x) |> println
  log(x^2 + 1)/2

9. 定積分

積分範囲を指定することで,定積分を計算することができる。

  integrate(x^2, (x, 0, 1)) |> println
  1/3

定積分の結果から,(分布関数の)中央値を計算することができる。

  using SymPy
  @vars x b real=true positive=true # 「b は正の実数」という条件を付けないと虚数解を含めて 4 個の解が求まる
  f(x) = 4x^3
  eq = integrate(f(x), (x,  0, b)) - 1/2 * integrate(f(x), (x, 0, 1));
  println(eq)
  solve(eq, b) |> float |> println
  b^4 - 0.5
  [0.8408964152537145]

9.1. 課題   

9.1.1. 問題 1.

f(x) = 2 / (x * log(x)) の不定積分を求めよ。

  integrate(2/(x * log(x))) |> println
  2*log(log(x))

9.1.2. 問題 2.

f(x) = (2x + 5)(x^2 + 5x)^7 を [0, 1] で定積分せよ。

  integrate((2x + 5) * (x^2 + 5x)^7, (x, 0, 1)) |> float |> println
  209952.0

9.1.3. 問題 3.

f(x) = sqrt(4 - sqrt(x)) を [0,9] で定積分せよ。

  integrate(sqrt(4 - sqrt(x)), (x, 0, 9)).evalf() |> println
  12.5333333333333

integrate(sqrt(4 - sqrt(x)), (x, 0, 9)) |> float |> println ではエラーになる

コメント    この記事についてブログを書く
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする
« SymPy/Julia(1) | トップ | 2 直線の交点 SymPy/Julia »
最新の画像もっと見る

コメントを投稿

ブログラミング」カテゴリの最新記事