眠り姫問題に１つの結論を出してみた！　ー　推定する立場で確率が変わる！？

# はじめに

今日(2023/5/24)、記事を読んでいたら、たまたま眠り姫問題というものが紹介されていました。
これは、興味深いと思い、シミュレーションを行い、一つの結論を導きました。

個人的には、相対性理論の雑誌的なやつの説明？を読んでたときと似た感覚を覚え、立場によって確率(推定値)が変わるということでは？と疑問に思ったことがきっかけです。


# 眠り姫問題とは？


[こちら](https://ja.wikipedia.org/wiki/%E7%9C%A0%E3%82%8A%E5%A7%AB%E5%95%8F%E9%A1%8C)（Wikipedia）を参照ください♪

以降は、上記Wikipedia の問題設定を前提としています。


# シミュレーション

こういう複雑な問題は、シミュレーションに限ります。ということで、早速コードを書いて測定してみました。

- コード全体は、[こちら](https://colab.research.google.com/gist/tkosht/93b193cf02fc2de900a895bff4b57c78/sleeping-beauty-problem.ipynb)

今回は、大きく２種類のシミュレーションをしています。
１つは、過去の実験の結果・履歴を次の確率推定に反映する方法と履歴を毎回忘れるようにシミュレーションする方法の２つです。

まずは、コイントス関数を定義しておきます。

```python
import numpy

def toss_coin():
    return numpy.random.randint(0, 2)
```

月曜日、火曜日における、現在のコインが表であった確率の推定値、に差分が出るかもしれない、とも思いましたので、それぞれにおける確率も算出できるようにしました。


## 履歴を反映する繰り返しシミュレーション

以下、試行結果の履歴を保持しながら、次の確率推定（現在のコインが表である確率）に反映するシミュレーションです。

```python
from tqdm import tqdm

coins = []
mondays = []
tuesdays = []
mondays_week = []
tuesdays_week = []

n_awakes = 0
n_heads = 0
n_weeks = 0

for _ in tqdm(range(100000)):
    coin = toss_coin()
    coins.append(coin)
    n_weeks += 1
    
    # at monday
    n_awakes += 1
    n_heads += coin
    mondays.append(n_heads / n_awakes)
    mondays_week.append(n_heads / n_weeks)

    # at tuesday
    if coin == 0:
        n_awakes += 1
    tuesdays.append(n_heads / n_awakes)
    tuesdays_week.append(n_heads / n_weeks)

coins = numpy.array(coins)
mondays = numpy.array(mondays)
tuesdays = numpy.array(tuesdays)
mondays_week = numpy.array(mondays_week)
tuesdays_week = numpy.array(tuesdays_week)
```

```python
print(f"{coins.mean()=}")

print(f"{mondays.mean()=}")
print(f"{tuesdays.mean()=}")

print(f"{mondays_week.mean()=}")
print(f"{tuesdays_week.mean()=}")
```


出力結果
```bash
coins.mean()=0.50042
mondays.mean()=0.33389260812597954
tuesdays.mean()=0.3338808740174647
mondays_week.mean()=0.5006085917982952
tuesdays_week.mean()=0.5006085917982952
```

一旦、意味は後で考えるとして、この結果からわかること（事実）は、
眠り姫が起きた回数を分母にすると、月曜日時点、火曜日時点ともに 表が出る確率の推定値は 0.334 ≒　1/3
週数を分母にすると、月曜日時点、火曜日時点ともに 0.501 ≒　1/2



## 履歴を反映しない繰り返しシミュレーション

次に、履歴を忘れるようにするとどうなるかのシミュレーションです。

```python
from tqdm import tqdm

coins = []
mondays = []
tuesdays = []
mondays_week = []
tuesdays_week = []

awakes = []

for _ in tqdm(range(100000)):
    n_awakes = 0
    n_heads = 0
    n_weeks = 0

    coin = toss_coin()
    coins.append(coin)
    n_weeks += 1
    
    # at monday
    n_awakes += 1
    n_heads += coin
    mondays.append(n_heads / n_awakes)
    mondays_week.append(n_heads / n_weeks)

    # at tuesday
    if coin == 0:
        n_awakes += 1
    tuesdays.append(n_heads / n_awakes)
    tuesdays_week.append(n_heads / n_weeks)
    # n_heads / n_awakes は、毎週 0 or 1 になる(履歴として次の週に反映されないため)

    awakes.append(n_awakes)

coins = numpy.array(coins)
mondays = numpy.array(mondays)
tuesdays = numpy.array(tuesdays)
mondays_week = numpy.array(mondays_week)
tuesdays_week = numpy.array(tuesdays_week)

awakes = numpy.array(awakes)
```

```python
print(f"{coins.mean()=}")

print(f"{mondays.mean()=}")
print(f"{tuesdays.mean()=}")

print(f"{mondays_week.mean()=}")
print(f"{tuesdays_week.mean()=}")

print(f"{awakes.mean()=}")
```

出力結果
```python
coins.mean()=0.50024
mondays.mean()=0.50024
tuesdays.mean()=0.50024
mondays_week.mean()=0.50024
tuesdays_week.mean()=0.50024
awakes.mean()=1.49976
```


こちらも一旦、意味は後で考えるとして、この結果からわかること（事実）は、
眠り姫が起きた回数を分母にすると、月曜日時点、火曜日時点ともに 表が出る確率の推定値は 0.500 ≒　1/2
週数を分母にしても、月曜日時点、火曜日時点ともに 0.500 ≒　1/2


# 考察

さて、事実（シミュレーションの結果）が出揃ったところで、考察してみたいと思います。

- 履歴を反映するシミュレーションでの 1/2, 1/3 の違いは、眠り姫が起きた回数を分母にするか、週数を分母にするかの違いです
- 履歴を反映しないシミュレーションでは、眠り姫が起きた回数を分母にしても、週数を分母にしても同じ結果で 1/2 でした
- 以上から、1/3 になるケースというのは、眠り姫が起きた回数を 表が出る確率を推定するのに使うか否か、という違いと考えられます


次に、眠り姫の設定から（眠り姫は毎回「記憶消去薬」を投与により）、

- 眠り姫の立場では、眠り姫が起きた回数の知識を確率の推定に使うことができない、と解釈するのが妥当そうです
- 一方で、眠り姫を観測している人からすると、眠り姫が起きた回数の知識を使うことができる、と解釈することができるでしょう


# 私の結論

まとめです。

以上の考察から自然に導かれる見解は、以下の通りです。

- 眠り姫の立場では、表である確率の推定値 1/2
- 眠り姫を観測する立場では、表である確率の推定値 1/3


結果、私が感じた相対論の性質（時間が宇宙船内部と観測者で変わるみたいなやつ）と似た、観測者と眠り姫本人によって表が出る確率の推定値が変わるのでは？という結論になります。

これが、一つの決着になるのでは？と少し期待しています。

そして、相対論の性質と確率の性質が、眠り姫問題によって関連づけられる、というのは個人的には興味深い結果になったと感じています。みなさんはどう考えるでしょうか？！


もしかしたら、眠り姫の立場での推論は頻度論、観測者の立場での推論はベイズみたいな粗い見方もありかな？！
あと、量子力学か何かでの、観測するまで位置を特定できない、みたいなものにも関連がありそうにも見えますね。だれか、ぜひ解明してください！



# 調査協力 ChatGPT さん

- 今、話題の AI、 [ChatGPT(GPT-4)](https://chat.openai.com/chat)さんにご協力いただきました！


以下、ChatGPTさんへの質問とその回答です。

この問題と相対性理論を関連させて議論することは、可能でしょうか？
---
(以下、ChatGPT さんの回答)
眠り姫問題は確率論と決定理論に関する思考実験であり、相対性理論は物理学の一分野でありますので、直接的な関連性はないかもしれません。しかし、以下のような観点から眠り姫問題と相対性理論を比較的抽象的なレベルで関連させることは可能かもしれません：

- 知覚と現実の間のギャップ：眠り姫問題では、眠り姫の知覚（すなわち、彼女が何日で目覚めたか、またはコインがどの面を向けていたかを知ることができない）と現実（コインがどの面を向けているか、または今が何日であるか）の間にはギャップが存在します。同様に、相対性理論では、特殊相対性理論の時間膨張や一般相対性理論の重力による時間の流れの遅さなど、観測者の知覚と「現実」の間にギャップが存在します。

- 知識と確率：眠り姫問題では、眠り姫が目覚めたときに「今が何日であるか」や「コインがどの面を向けていたか」を知ることができないため、彼女は自分の状況を確率的に理解する必要があります。一方、相対性理論では、粒子の位置や速度などの情報が不確定である量子力学との結びつきから、確率的な理解が必要となることがあります。

ただし、これらの関連性はあくまで抽象的なものであり、眠り姫問題が直接的に相対性理論の理解に役立つとは言えません。同様に、相対性理論が眠り姫問題の解決に寄与するとは考えられていません。


(この回答を見て、やはり関連はありそうだと、なんとなく確信しました笑)


次に、ChatGPT さんによるシミュレーションコードの回答です。この結果を見て、一方的な印象を受けたことが今回のシミュレーションに至った経緯になっています。


この眠り姫問題をシミュレーションするPythonコードを作成してくれませんか？
---
(以下、ChatGPT さんの回答)
もちろんです。以下に、この問題をシミュレートするPythonコードを示します。このコードは、公正なコインの結果に基づいて眠り姫が起こされるパターンをシミュレートします。

```python
import random

def simulate_experiment():
    # コインを投げる (0 = 表, 1 = 裏)
    coin = random.randint(0, 1)

    # 表の場合、眠り姫は月曜日だけ起こされる
    if coin == 0:
        return [0]

    # 裏の場合、眠り姫は月曜日と火曜日に起こされる
    else:
        return [1, 1]

def simulate_n_experiments(n):
    awakenings = []
    for _ in range(n):
        awakenings.extend(simulate_experiment())
    return awakenings

def calculate_probabilities(n):
    awakenings = simulate_n_experiments(n)
    total_awakenings = len(awakenings)

    # 表の確率と裏の確率を計算する
    prob_heads = awakenings.count(0) / total_awakenings
    prob_tails = awakenings.count(1) / total_awakenings

    return prob_heads, prob_tails

# 10万回の実験をシミュレートする
prob_heads, prob_tails = calculate_probabilities(100000)

print(f"表の確率: {prob_heads}")
print(f"裏の確率: {prob_tails}")
```

このコードを実行すると、眠り姫が目覚めたときにコインが表だった確率と裏だった確率が表示されます。注意すべきは、このシミュレーションは確率的なものであるため、実行するたびに結果がわずかに異なる可能性があるということです。それでもなお、何度も実行すると、表の確率が約1/3、裏の確率が約2/3に収束するはずです。これは、「1/3の立場」の主張を支持する結果となります。

---

(実際に実行した結果)
```bash
表の確率: 0.33423171602212154
裏の確率: 0.6657682839778785
```

---
以上、ChatGPT さん、ご協力ありがとうございました！


# 参考URL

- [Wikipedia - 眠り姫問題](https://ja.wikipedia.org/wiki/%E7%9C%A0%E3%82%8A%E5%A7%AB%E5%95%8F%E9%A1%8C)