---
jupytext:
  formats: md:myst
  text_representation:
    extension: .md
    format_name: myst
    format_version: 0.13
kernelspec:
  display_name: Python 3
  language: python
  name: python3
---

# 4회 실험 · 두 개의 합 공식

```{admonition} 이 실험
:class: seealso

| | |
|---|---|
| **짝 서술** | {doc}`L04` |
| **실험 목록** | 실험 1 (1층) — 수치 확인 / 실험 2 (3층) — 공식을 발견한다 |
```

서술 쪽 4절에서 같은 공식을 귀납법과 망원합으로 두 번 유도하였다. 이번 실험에서는 셋째 방법을 하나 더 확보하고, 세 방법의 성격이 어떻게 다른지 정리한다.

```{code-cell} ipython3
:tags: [hide-input]

# 공통 준비 — 색 규약과 한글 글꼴을 맞춘다
import numpy as np
import matplotlib.pyplot as plt
import sympy as sp

from calc_viz import 색, 칸
from calc_style import 한글글꼴설정

글꼴 = 한글글꼴설정()   # 돌려주는 값은 실제로 선택된 글꼴 이름이다
```

## 실험 1 (1층) — 수치 확인

{prf:ref}`thm-4-sum-k`와 {prf:ref}`thm-4-sum-k2`가 실제 값과 맞는지 확인한다. 왼쪽은 항을 하나씩 더한 값이고 오른쪽은 공식에 $n$을 넣은 값이다.

정수 연산만 쓰므로 반올림 오차가 없다. 일치 여부를 `==`로 판정할 수 있다.

```{code-cell} ipython3
# [4회] 두 합 공식의 확인
# 목적 : 귀납법으로 증명한 공식이 실제 값과 일치하는지 확인한다
# 층  : 1층
# 주의 : 정수 나눗셈(//)을 쓴다. 공식의 값은 언제나 정수이다

머리 = ["n", "Σk 직접", "Σk 공식", "일치", "Σk² 직접", "Σk² 공식", "일치"]
폭 = [6, 12, 12, 6, 14, 14, 6]
print(" ".join(칸(글, w) for 글, w in zip(머리, 폭)))

for 값 in (5, 20, 100):
    직접1 = sum(k for k in range(1, 값 + 1))
    공식1 = 값 * (값 + 1) // 2
    직접2 = sum(k**2 for k in range(1, 값 + 1))
    공식2 = 값 * (값 + 1) * (2 * 값 + 1) // 6
    줄 = [값, 직접1, 공식1, 직접1 == 공식1, 직접2, 공식2, 직접2 == 공식2]
    print(" ".join(칸(항목, w) for 항목, w in zip(줄, 폭)))
```

$n=5$인 줄이 서술 쪽 4절 끝에서 손으로 확인한 값이다. $\sum k = 15$이고 $\sum k^2 = 55$이다.

```{admonition} 확인할 것
:class: tip
1. 세 줄 모두에서 직접 더한 값과 공식의 값이 일치하는지 확인하자.
2. $n$을 5에서 100으로 키울 때 $\sum k$와 $\sum k^2$이 각각 몇 배로 커지는지 비교해 보자. 공식의 최고차항이 무엇인지와 관련지어 생각해 보자.
3. 세 개의 $n$에서 확인한 것으로 공식이 모든 $n$에서 참임을 보였다고 할 수 있는가.
```

## 실험 2 (3층) — 공식을 발견한다

`sympy`의 `summation`은 공식을 몰라도 합을 $n$의 식으로 돌려준다. 서술 쪽에서 유도한 두 공식이 실제로 나오는지 보고, 아직 유도하지 않은 차수까지 밀어 본다.

```{code-cell} ipython3
# [4회] 합 공식을 sympy 로 구한다
# 목적 : 답을 모르는 상태에서 공식을 얻는 방법을 하나 더 확보한다
# 층  : 3층
# 주의 : 결과가 나온다는 것과 그 결과가 왜 참인지 아는 것은 다른 문제이다

from calc_sym import k, n, 보이기

for 차수 in (1, 2, 3, 4):
    합 = sp.summation(k**차수, (k, 1, n))
    보이기(f"Σ k^{차수} (k=1..n)", sp.factor(sp.simplify(합)))
```

차수 1과 2가 서술 쪽 (4.6), (4.9)와 같다. 차수 3은 $\left(\frac{n(n+1)}{2}\right)^2$의 형태이며, 처음 $n$개 자연수의 합의 제곱이다. 차수 4에서는 인수분해가 되지 않는다.

이제 망원합의 근거가 되는 항등식을 확인한다.

```{code-cell} ipython3
# [4회] 망원합의 항등식
# 목적 : 서술 쪽 (4.10) 과 (4.11) 을 기호로 확인한다
# 층  : 3층
# 주의 : 상쇄가 실제로 일어나는지 양변을 각각 계산해 대조한다

보이기("(k+1)³ − k³", sp.expand((k + 1)**3 - k**3))

좌변 = sp.summation((k + 1)**3 - k**3, (k, 1, n))
보이기("Σ [(k+1)³ − k³]", sp.simplify(좌변))

우변 = sp.expand((n + 1)**3 - 1)
print(f"양 끝의 차 (n+1)³ − 1 = {우변}")
print(f"두 결과가 같은가 : {sp.simplify(좌변 - 우변) == 0}")
```

가운데 항이 모두 상쇄되고 양 끝만 남는다는 것이 {prf:ref}`thm-4-telescope`의 내용이며, 위 출력이 그것을 확인한다.

서술 쪽 방법 2를 그대로 따라가 $\sum k^2$을 풀어낸다.

```{code-cell} ipython3
# [4회] 망원합으로 Σk² 를 풀어낸다
# 목적 : 서술 쪽 (4.11) 에서 Σk² 를 분리하는 계산을 기호로 재현한다
# 층  : 3층
# 주의 : 공식을 대입하지 않고 미지수로 두고 푼다. 답을 모른다고 가정한 상태이다

S2 = sp.Symbol("S2")                       # 구하려는 Σk² 를 미지수로 둔다
S1 = n * (n + 1) / 2                       # (4.6) 은 이미 유도해 두었다

방정식 = sp.Eq((n + 1)**3 - 1, 3 * S2 + 3 * S1 + n)   # 서술 쪽 (4.11)
해 = sp.solve(방정식, S2)[0]

보이기("망원합에서 풀어낸 Σk²", sp.factor(sp.simplify(해)))
알려진값 = sp.summation(k**2, (k, 1, n))
print(f"summation 의 결과와 같은가 : {sp.simplify(해 - 알려진값) == 0}")
```

```{admonition} 확인할 것
:class: tip
1. $\sum k^3$의 공식이 $\left(\frac{n(n+1)}{2}\right)^2$과 같은 형태인지 확인하자.
2. $(k+1)^3-k^3$을 전개한 결과에 $k^2$, $k$, 상수가 각각 몇 개씩 있는지 확인하자.
3. 이 전개식과 망원합을 이용하여 $\sum k^2$의 공식을 손으로 유도해 보자. `sympy`의 결과와 일치하는가.
```

## 세 방법의 성격

같은 공식을 세 가지 방법으로 얻었다. 세 방법은 할 수 있는 일이 다르다.

| 방법 | 답을 모를 때 쓸 수 있는가 | 증명이 되는가 |
|---|---|---|
| 귀납법 | 아니다 | 그렇다 |
| 망원합 | 그렇다 | 그렇다 |
| `sympy` | 그렇다 | **아니다** |

```{admonition} 세 번째 열이 요점이다
:class: warning

`sympy`는 공식을 알려주지만 그것이 왜 참인지는 알려주지 않는다. `summation`이 돌려준 $\frac{n(n+1)(2n+1)}{6}$은 어떤 알고리즘의 출력이며, 그 알고리즘이 옳다는 것은 이 화면 밖의 문제이다.

그러므로 기호 계산은 **답을 짐작하는 데** 쓴다. 짐작한 답을 귀납법으로 확인하거나, 망원합으로 다시 유도하는 것이 증명이다.

서술 쪽에서 같은 공식을 두 번 유도한 이유가 여기에 있다. 망원합은 답을 몰라도 쓸 수 있으면서 동시에 증명이 되는 유일한 방법이다.
```

```{admonition} 짝이 되는 서술
:class: note
{doc}`L04`
```
