モンテカルロ法で到着時間を数えたので

簡単で「半日」の投稿。 休日に関係するすべて:)



80年代で最もエキサイティングなことの1つは、いくつかの複雑な分析問題を解決するためのソフトウェアモデリングであり、最もよく使用されるテクニックの1つはモンテカルロ法でした。 それは、ますます信頼性の高い結果を得るために、シミュレーションを何度も開始するという事実にあります。



PHPは科学的な言語ではなく、研究目的で使用されることはほとんどないという事実にもかかわらず、モンテカルロ法はPHPに簡単に実装できます。 この記事では、その方法を示します。



実生活の課題


数日前、私は家から100マイルの午前9時に会議を開く必要がありました。 朝の6.30に目を覚まし、服を着て、朝食をとりながら、次の数時間ノートブックで把握し始めました。 私はいつものように時間通りに到着したかったので、ルートを概説し始めました:都市、田舎道、そして州を北、東、東へのローカル道路を出て、都市を通ってドライブし、再び北に移動して都市に到着しました。 それはすべて次のように見えました:





画像



昨夜、妻がタンクを満タンにしたので、田舎道を静かに運転できました。 タイヤを見てみると、タイヤは正常に見えたが、空気圧をチェックするために10分間停止するかどうかの考えから、休息は取れなかった。 結局のところ、私がそれらを止めてチェックすると、私は彼らの圧力を確信するでしょう、なぜなら私は今それを確信していなかったからです、そしてタイヤの空気圧は私の運動と速度に影響を与える可能性があります...



たとえば、早めに6.40に出発することもできますが、その場合、妻は仕事に直接行く代わりに、娘を学校に連れて行く必要があります。 さらに10分待つと、彼らがちょうどドアを開けた瞬間に学校に行くことができます。これにより、妻が不便から解放されます。特に、学校が都市からの出口に向かう途中であり、これは私をそれほど遅らせなかったからです。



私が描いていたものに戻って、以下を追加しました:



画像



2杯目のコーヒーを飲みながら、私は窓に立った。 晴れた朝空、明るい朝風が私のスマートフォンで良い予報を確認し、今回の旅行は早くなると思いました。 計画を終えて、以前に描いた各段階のおおよその時間を描きました。



画像



余分な停止なしで移動できる場合、予想される旅行時間は115分(1時間55分)でした。 すぐに行く場合は8.35に到着し、娘を連れて学校に行かせて同時にタイヤをチェックする必要がある場合は8.55に到着することを期待していました。



しかし、現実に出会った後は、どんな計画も理想的ではなくなります! なんらかの奇妙な理由で、多くの親が子供たちをいつもよりも早く学校に通わせることに決めたので、私の急な旅行を計画していたのに比べて5分以上も失いました。 少し遅れたことに気付いて、タイヤの空気圧をチェックせずにすぐに行くことにしました。



最悪のシナリオでの計画より5分早く都市の出口に着き、計画のポイントBとCの間のどこかで、視界に大きく影響する霧に出くわすまですべてが順調に進みました道路で。 霧は私の平均速度を遅くしましたか? 遅いが長いトラックを追い越すことさえできませんでした。 私は通常よりもずっと簡単に市内の都市の流れを克服し、10分もかかりませんでした。 南の道を数マイル走った後、霧が減り、許容速度で安全に乗ることができました。 しかし、目標に近づいたとき、私は道路工事が進んでおり、計画された時間を再び奪うことに気づきました。 全体として、私は旅行にさらに10分を費やし、最終的には遅れました。



旅をシミュレートします


PHPのほとんどの作業は、あらゆる種類のオンラインストアや他のWebサイトを対象としていることを理解しています。 しかし、私のお気に入りのPythonとは異なり、PHPはエンジニアや科学者などのプロではないプログラマーを簡単にトレーニングできるため、PHPは研究に最適なツールです。



私の旅のいくつかの段階が意図した経路から少し離れた場合、遅かれ早かれ会議に到着できることを理解するのに役立つ小さなコードを書きます。 手始めに、パスをそのまま説明できます。



<?php class MyTrip { protected $departureTime; protected $meetingTime; protected $travelTimes; public function __construct() { $this->setDepartureTime('0640'); $this->setMeetingTime('0900'); //       $this->setTravelTimes(array( 'AB' => 17, 'BC' => 17, 'CD' => 36, 'DE' => 9, 'EF' => 15, 'FG' => 15, 'GH' => 6 )); } //       protected static function convertToMinutes($timeStr) { return substr($timeStr, 0, 2) * 60 + substr($timeStr, 2, 2); } public function setDepartureTime($timeStr) { $this->departureTime = self::convertToMinutes($timeStr); } public function setMeetingTime($timeStr) { $this->meetingTime = self::convertToMinutes($timeStr); } public function setTravelTimes(array $travelTimes) { $this->travelTimes = $travelTimes; } public checkPlan($stopAtSchool = true, $checkTires = true) { // ... } }
      
      







計画は、これを決定するための実行可能で適切な基準である必要があります。これにより、すべての時間と早期出発時間の合計が、予定が予定されている時間以下になります。 実際、これはcheckPlan()メソッドが定義するものです:



 <?php public checkPlan($stopAtSchool = true, $checkTires = true) { //       $travelTime = array_sum($this->travelTimes); //  ,        $schoolDelay = ($stopAtSchool) ? 10 : 0; //       $tiresDelay = ($checkTires) ? 10 : 0; //     $meetingArriveTime = $this->departureTime + $travelTime + $schoolDelay + $tiresDelay; //    ? $arriveOnTime = $meetingArriveTime <= $this->meetingTime; return array($meetingArriveTime, $this->meetingTime, $arriveOnTime); }
      
      







それだけです。このクラスのインスタンスを作成して確認するだけです。



 <?php $trip = new MyTrip(); print_r($trip->checkPlan());
      
      







デフォルト設定では、出力は次のようになります。



 Array ( [0] => 535 [1] => 540 [2] => 1 )
      
      







私は535分で到着しなければならず、予約は540分に予定されています。 時間に換算すると、スケジュールより15分早く8.45に到着します。



しかし、遅延の可能性はどうでしょうか? それらを予測し計算する方法は?



モンテカルロ法またはランダム性の追加


最も単純な形式では、各イベントに特定の安全なギャップを定義し、指定した時間よりも10%早く、25%遅く発生する可能性があると言えます。 これらのギャップは、各因子にrand(90,125)/ 100を掛けることにより、初期遅延(娘、プレッシャー)およびステップ間の時間に誤って追加される可能性があります。

また、2つの決定に50%の確率を割り当てることができます-娘を学校に連れて行き、タイヤをチェックします。 ここでrand()が再び役立ちます。



 $this->checkTires = rand(1, 100) > 50;
      
      







これらすべてを組み合わせて、checkPlanRisk()メソッドを定義して、旅行中のさまざまな状況を考慮して、時間通りに到着するかどうかの決定を計算できます。



 <?php public function checkPlanRisk() { //    $travelTime = 0; foreach ($this->travelTimes as $t) { $travelTime += $t * rand(90, 125) / 100; } //      $schoolDelay = 0; if (rand(1, 100) > 50) { $schoolDelay = 10 * rand(90, 125) / 100; } //    $tiresDelay = 0; if (rand(1, 100) > 50) { $tiresDelay = 10 * rand(90, 125) / 100; } //    $meetingArriveTime = $this->departureTime + $travelTime + $schoolDelay + $tiresDelay; //    ? $arriveOnTime = $meetingArriveTime <= $this->meetingTime; return array($schoolDelay, $tiresDelay, $meetingArriveTime, $this->meetingTime, $arriveOnTime); }
      
      







ここで問題は、すべての可能な遅延を考慮して、時間通りに到着するかどうかです。 モンテカルロ法では、このタスクを何度も起動し、タスクの起動回数に対する到着時間の比率として「信頼レベル」を計算することで、この問題を解決できます。



これを十分な回数実行し、時間どおりに到着する頻度を記録すると、予定どおりに到着する可能性を判断できます。



 <?php public function runCheckPlanRisk($numTrials) { $arriveOnTime = 0; for ($i = 1; $i <= $numTrials; $i++) { $result = $this->checkPlanRisk(); if ($result[4]) { $arriveOnTime++; } echo ": " . $i; echo " : " . $result[0]; echo " : " . $result[1]; echo "  : " . $result[2]; if ($result[4]) { echo " -- "; } else { echo " -- "; } $confidence = $arriveOnTime / $i; echo " : $confidencen"; } }
      
      







新しいインスタンスを作成し、次々に1000回の計算を実行します。



 <?php $trip = new MyTrip(); $trip->runCheckPlanRisk(1000);
      
      







完了後、予測を取得します。



 : 1000 : 0 : 11.3  : 530.44 --   : 0.716
      
      







ご覧のとおり、現在の設定では、72%の確率で会議に到着します。 もちろん、これは単なる平均値ですが、生命に対する権利もあります。



私自身から:おそらくこの記事はまったく新しいものではなく、タイトルは少し黄色っぽいですが、この記事は私には面白そうに思えました。 私は長い間読んでいましたが、モンテカルロについてのハブに関する記事の出現で思い出しました。 たぶん誰かが役に立つでしょう。



All Articles