SymPy で算額の問題を解く

# **[算額とは？](https://ja.wikipedia.org/wiki/%E7%AE%97%E9%A1%8D)**

いろいろな算額を SymPy で解いています。

SymPy は Pyhon で使うのが一般的とは思いますが，Julia の Python で書いています。

Julia なので，Python の SymPy とはちょっと書き方にくせがありますが，かえって書きやすい面もあります。

ご意見，ご感想いただければうれしいです。

https://blog.goo.ne.jp/r-de-r/e/1b3e7a7043254fc1b5c573ba784967f8

よろしければ，「いいね！」してください。

神壁算法 關龍藤田貞資門人 龜井隠岐守家士 堀田人助泉尹 天明八年
藤田貞資(1789)：神壁算法巻上
http://www.wasan.jp/jinpeki/jinpekisanpo1.pdf

直径 97 寸 5 分の大円の中に累円と，大円と甲円と累円に挟まれる円がある。
末円の直径が 1 分のとき，初円から末円まで何個の挟円があるか（つまり，末円は初円から数えて何番目か）。

![fig1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464743/1d3112df-e87b-a992-00f7-adcb8f43dc51.png)


大円の半径と中心座標を r0, (0, 0)
甲円の半径と中心座標を r1, (x1, y1); x1 = 0, y1 = r1
乙円の半径と中心座標を r2, (x2, y2); x2 = r0 - r2, y2 = 0
乙円以降 i 番目の円の半径と中心座標を ri, (xi, yi)
初円の半径と中心座標を R1, X1, Y1
初円以降 i 番目の挟円の半径と中心座標を Ri, (Xi, Yi)
とおき，順次パラメータを決定していく。

```python
from sympy import *

var('r0, r1, r2, x2, y2, r3, x3, y3')
```

    (r0, r1, r2, x2, y2, r3, x3, y3)

まず，乙円については，半径 r2 = r0/3 になる。

```python
r1 = r0/2
x2 = r0 - r2
y2 = 0
eq1 = Eq(x2**2 + r1**2, (r1 + r2)**2)
res2 = solve(eq1, r2)
print(res2[0])
```

    r0/3

次に，丙円については，半径，中心座標は (r0/6, 2*r0/3, r0/2) になる。

```python
r2 = r0/3
x2 = r0 - r2
y2 = 0
eq2 = Eq(x3**2 + y3**2, (r0 - r3)**2)
eq3 = Eq(x3**2 + (r1 - y3)**2, (r1 + r3)**2)
eq4 = Eq((x2 - x3)**2 + (y2 - y3)**2, (r2 + r3)**2)
res3 = solve([eq2, eq3, eq4], (r3, x3, y3))
print(res3)
```

    [(r0/6, 2*r0/3, r0/2), (r0/2, 0, -r0/2)]

更に，丁円については，半径，中心座標は (r0/11, 6*r0/11, 8*r0/11) になる。

```python
var('r4, x4, y4')
r3 = r0/6
x3 = 2*r0/3
y3 = r0/2
eq5 = Eq(x4**2 + y4**2, (r0 - r4)**2)
eq6 = Eq(x4**2 + (r1 - y4)**2, (r1 + r4)**2)
eq7 = Eq((x3 - x4)**2 + (y3 - y4)**2, (r3 + r4)**2)
res4 = solve([eq5, eq6, eq7], (r4, x4, y4))
res4
```

    [(r0/11, 6*r0/11, 8*r0/11), (r0/3, 2*r0/3, 0)]

```python
var('r5, x5, y5')
r4 = r0/11
x4 = 6*r0/11
y4 = 8*r0/11
eq8 = Eq(x5**2 + y5**2, (r0 - r5)**2)
eq9 = Eq(x5**2 + (r1 - y5)**2, (r1 + r5)**2)
eq10 = Eq((x4 - x5)**2 + (y4 - y5)**2, (r4 + r5)**2)
res5 = solve([eq8, eq9, eq10], (r5, x5, y5))
res5
```

    [(r0/18, 4*r0/9, 5*r0/6), (r0/6, 2*r0/3, r0/2)]

```python
var('r6, x6, y6')
(r5, x5, y5) = res5[0]
eq11 = Eq(x6**2 + y6**2, (r0 - r6)**2)
eq12 = Eq(x6**2 + (r1 - y6)**2, (r1 + r6)**2)
eq13 = Eq((x5 - x6)**2 + (y5 - y6)**2, (r5 + r6)**2)
res6 = solve([eq11, eq12, eq13], (r6, x6, y6))
res6
```

    [(r0/27, 10*r0/27, 8*r0/9), (r0/11, 6*r0/11, 8*r0/11)]

```python
var('r7, x7, y7')
(r6, x6, y6) = res6[1]
eq14 = Eq(x7**2 + y7**2,(r0 - r7)**2)
eq15 = Eq(x7**2 + (r1 - y7)**2, (r1 + r7)**2)
eq16 = Eq((x6 - x7)**2 + (y6 - y7)**2, (r6 + r7)**2)
res7= solve([eq14, eq15, eq16], (r7, x7, y7))
res7
```

    [(r0/18, 4*r0/9, 5*r0/6), (r0/6, 2*r0/3, r0/2)]

```python
var('r8, x8, y8')
(r7, x7, y7) = res7[1]
eq17 = Eq(x8**2 + y8**2, (r0 - r8)**2)
eq18 = Eq(x8**2 + (r1 - y8)**2, (r1 + r8)**2)
eq19 = Eq((x7 - x8)**2 + (y7 - y8)**2, (r7 + r8)**2)
res8= solve([eq17, eq18, eq19], (r8, x8, y8))
res8
```

    [(r0/11, 6*r0/11, 8*r0/11), (r0/3, 2*r0/3, 0)]

累円のパラメータ，半径，中心座標を表す数列には規則性があり，以下のような一般項になる。
甲円の半径 r1，中心座標 (x1, y1) は r0/2, (0, r1)
乙円の半径 r2，中心座標 (x2, y2) は r0/3, (r0 - r2, 0)
丙円以降は i ≧ 3 として，ri, (xi, yi) は以下のようになる。
ri = r0/(i**2 - 2i + 3)
xi = ri*(2i - 2)
yi = ri*(i**2 - 2i)

次に，互いに接する，外円と 2 個の累円に挟まれる円のパラメータを計算する。

```python
var('R1, X1')
X1 = r0 - 2*r2 - R1
eq20 = Eq(X1**2 + r1**2, (r1 + R1)**2)
res11 = solve(eq20, R1)
print(res11[0])
```

    r0/15

```python
R1 = r0/15
X1 = r0 - 2*r2 - R1
(R1, X1)
```

    (r0/15, 4*r0/15)

```python
var('R2, X2, Y2')
(x1, y1, x2, y2) = (0, r1, r0 - r2, 0)
(R1, X1) = (r0/15, 4*r0/15)
eq21 = Eq( X2**2       + (Y2 - y1)**2, (R2 + r1)**2)
eq22 = Eq((X2 - x2)**2 + (Y2 - y2)**2, (R2 + r2)**2)
eq23 = Eq((X2 - x3)**2 + (Y2 - y3)**2, (R2 + r3)**2)
res12 = solve([eq21, eq22, eq23], (R2, X2, Y2))
res12
```

    [(-r0, 0, 0), (r0/23, 12*r0/23, 8*r0/23)]

```python
var('R3, X3, Y3')
(R2, X2, Y2) = res12[1]
eq24 = Eq( X3**2       + (Y3 - y1)**2, (R3 + r1)**2)
eq25 = Eq((X3 - x3)**2 + (Y3 - y3)**2, (R3 + r3)**2)
eq26 = Eq((X3 - x4)**2 + (Y3 - y4)**2, (R3 + r4)**2)
res13 = solve([eq24, eq25, eq26], (R3, X3, Y3))
res13
```

    [(-r0, 0, 0), (r0/39, 20*r0/39, 8*r0/13)]

```python
var('R4, X4, Y4')
(R3, X3, Y3) = res13[1]
eq27 = Eq( X4**2       + (Y4 - y1)**2, (R4 + r1)**2)
eq28 = Eq((X4 - x4)**2 + (Y4 - y4)**2, (R4 + r4)**2)
eq29 = Eq((X4 - x5)**2 + (Y4 - y5)**2, (R4 + r5)**2)
res14 = solve([eq27, eq28, eq29], (R4, X4, Y4))
res14
```

    [(-r0, 0, 0), (r0/63, 4*r0/9, 16*r0/21)]

```python
var('R5, X5, Y5')
(R4, X4, Y4) = res14[1]
eq30 = Eq( X5**2       + (Y5 - y1)**2, (R5 + r1)**2)
eq31 = Eq((X5 - x5)**2 + (Y5 - y5)**2, (R5 + r5)**2)
eq32 = Eq((X5 - x6)**2 + (Y5 - y6)**2, (R5 + r6)**2)
res14 = solve([eq30, eq31, eq32], (R5, X5, Y5))
res14
```

    [(-r0, 0, 0), (r0/63, 4*r0/9, 16*r0/21)]

挟円のパラメータは
初円は
R1 = r0/15, X1 = 4*r0/15, Y1 = 0
二円以降 i ≧ 2 においては
半径 Ri = r0/(4i**2 - 4i + 15)
x座標 Xi = Ri * (8i - 4)
y座標 Yi = Ri * (4i**2 - 4i)

問は，「末円の径が一分であるとき，それは何番目の挟円か」ということである。
以下の方程式を解けば，16番目の挟円であることがわかる。

```python
var('i')
r0 = 975/20  # 直径 = 97.5
eq = Eq(r0/(4*i**2 - 4*i + 15), 1/20)  # 直径 = 0.1 寸
print(solve(eq, i)[1])
```

    16.0000000000000

一般的な解を求めるには，末円の半径を Rn とすれば

```python
var('i, r0, Rn')
eq = r0/(4*i**2 - 4*i + 15) - Rn
res = solve(eq, i)[1]
print(res)
```

    (Rn + sqrt(Rn*(-14*Rn + r0)))/(2*Rn)

SymPy ではこれ以上簡単にできないが，手計算で，(1 + sqrt(r0/Rn - 14))/2 となる。

「外円の半径を末円の半径で割り，14を引いたものを開平し1を加えて2で割る」となり，「術」と一致する。
なお，当たり前であるが，術は，半径を直径と読み替えても成り立つ。

ちなみに，20番目の挟円の半径は 0.031759 ほどであり，数値を丸めるとたしかに20番目である事がわかる。

```python
(sqrt(97.5/(2*0.031759) - 14) + 1)/2
```

$\displaystyle 19.999986880355$