历史模拟与蒙特卡洛模拟_在PHP中运行蒙特卡洛模拟

历史模拟与蒙特卡洛模拟

One of the exciting things in the 1980’s was programming simulations to solve complex analytical problems, and one of the most useful techniques employed was running Monte Carlo simulations. The approach repeatedly runs a simulation many times over to calculate the most likely outcome.

1980年代激动人心的事情之一是编程模拟以解决复杂的分析问题,而采用的最有用的技术之一就是运行蒙特卡洛模拟。 该方法多次重复进行仿真以计算最可能的结果。

Although PHP isn’t known as a scientific or research programming language, Monte Carlo simulations can easily be written in a PHP web app. In this article, I’ll show you how.

尽管PHP不被称为科学或研究编程语言,但是Monte Carlo模拟可以很容易地在PHP Web应用程序中编写。 在本文中,我将向您展示如何进行。

现实问题 (A Real-World Problem)

The day before yesterday I had a meeting at 9:00 AM about 100 miles away from my home. At 6:30 I was awake and dressed, and while having breakfast I began to work out the next couple of hours on a notepad. I obviously wanted to arrive at the meeting safely and on time, so I started sketching the drive split in eight stages: urban departure, country road, state road northbound, state road eastbound, state highway eastbound, urban crossing, state highway northbound, and urban arrival. The sketch more or less looked like this:

前天,我在离家大约100英里处的上午9:00开会。 在6:30时,我醒着并穿着衣服,在吃早餐时,我开始在接下来的几个小时里用记事本锻炼身体。 我显然想安全,准时地到达会议,因此我开始草拟驱动器划分的八个阶段:城市出发,乡村道路,州际公路北行,州际公路东行,州际公路东行,城市交叉路口,州际公路北行以及城市到来。 草图大致如下所示:

montecarlo1

My wife had filled the gas tank the evening before and ideally I could drive straight out to the country road. The tires seemed alright when I looked at them, but doubt whether or not to make a 10 minute detour to properly check their pressure hounded me. If I stopped and checked the tires, I’d be certain of their pressure. Otherwise, I’d have to travel with the uncertainty. Poor tire pressure could have an effect on my driving stability and speed.

我的妻子在前一天晚上给汽油箱加油,理想情况下,我可以直奔乡间小路。 当我看着轮胎时,它们看起来还不错,但是怀疑是否要绕道行驶10分钟以正确检查它们的压力使我感到困扰。 如果我停下来检查轮胎,我肯定会感到压力。 否则,我将不得不面对不确定性。 轮胎压力差可能会影响我的驾驶稳定性和速度。

I could leave as early as 6:40 but then my wife would have to take our daughter to school instead of going straight to work. If I waited another 10 minutes, I could be at the school as their gates opened for the morning and spare my wife the trouble. The school is on my way out of town so there’d be no significant added travel time.

我可能最早在6:40离开,但那时我的妻子将不得不带我们的女儿去上学,而不是直接去上班。 如果我再等10分钟,我可能会在学校里,因为他们的大门早上开了,省了我老婆的麻烦。 学校正在我出城的路上,因此不会增加旅行时间。

I went back to my drawing and added the following:

我回到绘图并添加以下内容:

montecarlo2

Sipping my second cup of coffee, I stood by the window. A clear dusk sky and brisk morning breeze agreed with the perfect day forecast on my smartphone which made me believe the drive would be a fast one. To finish my planning, I drew from past experience and wrote down the estimated drive times:

我ing着第二杯咖啡,站在窗户旁边。 晴朗的黄昏天空和清晨的微风与我的智能手机上的理想天气预报相符,这使我相信驱动器将是快速的。 为了完成我的计划,我借鉴了以往的经验,并写下了预计的行驶时间:

montecarlo3

The expected time en route was 115 minutes (1 hour 55 minutes), which I could cover non-stop. My ETA was 8:35 if I left straight for the road and 8:55 if I decided take my daughter to school and check the tires.

途中的预计时间为115分钟(1小时55分钟),我可以不停地讲。 如果我直走上路,我的预计到达时间是8:35,如果我决定带女儿去学校检查轮胎,我的预计到达时间是8:55。

But no plan survives its first encounter with the enemy! For some mysterious reason, many other parents decided to drop their children off at school earlier than usual, and I had lost more than 5 minutes on what was planned to be a quick detour. Knowing that my baseline was already compromised, I decided to skip the tire check and drive straight to the country road.

但是,没有任何计划能够幸免于与敌人的第一次相遇! 由于某些神秘的原因,许多其他父母决定比平时更早放学,而我原本打算快速绕道的时间损失了5分钟以上。 知道自己的基准已经被破坏后,我决定跳过轮胎检查,直接驶向乡间小路。

I reached the road actually five minutes sooner than the original worst case estimate and the drive went well until, somewhere between milestones B and C, I ran into dense fog which reduced my visibility. This reduced my average speed and made it harder to overtake the slow but long trucks.

我实际上比最初的最坏情况估计要早五分钟到达公路,并且行驶顺利,直到在里程碑B和C之间的某个地方遇到浓雾,这降低了我的视野。 这降低了我的平均速度,使它难以超越缓慢而又长的卡车。

The urban traffic in the town I had to cross was much lighter than usual and it didn’t take me more than 10 minutes to go across. And a few miles onto state highway southbound the fog lifted so I was able to drive at the full legal speed. But when I approached my destination, I realized that some road work that was in progress had blocked the exit I planned to take. This added another 10 minutes to my travel time and needless to say I arrived late.

我不得不穿越的小镇上的城市交通比往常要轻得多,经过我的时间也不过十分钟。 沿着州际公路向南行驶了几英里,雾气散开了,所以我能够以全速行驶。 但是,当我到达目的地时,我意识到一些正在进行的修路工作阻塞了我计划要驶出的出口。 这又使我的旅行时间增加了10分钟,不用说我迟到了。

用PHP建模旅程 (Modeling the Trip in PHP)

I believe most PHP coding is dedicated to profit and non-profit business websites. But PHP can be a fine tool for scientific research and might as well be easier to teach non-professional programmers, like engineers and scientists, than other languages like my beloved Python.

我相信大多数PHP编码都致力于盈利和非盈利的商业网站。 但是PHP可以是科学研究的好工具,而且比像我心爱的Python这样的其他语言,更容易教给像工程师和科学家这样的非专业程序员。

Let’s write the basic code that will help me understand how much earlier or later I could have arrived at the meeting if one or more stages of my plan varied substantially from their baseline estimates. We can begin to model the trip as follows:

让我们写一些基本代码,这些代码可以帮助我了解,如果我的计划的一个或多个阶段与他们的基准估算值相差很大,我可能早晚到达会议。 我们可以开始对旅行进行建模,如下所示:

<?php 
class MyTrip 
{ 
    protected $departureTime; 
    protected $meetingTime; 
    protected $travelTimes; 

    public function __construct() { 
        $this->setDepartureTime('0640'); 
        $this->setMeetingTime('0900'); 

        // travel times in minutes between milestones 
        $this->setTravelTimes(array( 
            'AB' => 17, 
            'BC' => 17, 
            'CD' => 36, 
            'DE' => 9, 
            'EF' => 15, 
            'FG' => 15, 
            'GH' => 6 
        )); 
    } 

    // for convenience convert time string to minutes past
    // midnight 
    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) {
        // ...
    }
}

Plans must be feasible, and the suitable criteria to judge this one is whether the sum of all times plus the earliest departure time is less than or equal to the time of the meeting. That is what the checkPlan() method determines:

计划必须是可行的,并且判断该时间的合适标准是所有时间的总和加上最早的离开时间是否小于或等于会议时间。 那就是checkPlan()方法确定的:

<?php
public checkPlan($stopAtSchool = true, $checkTires = true) {
    // calculate the sum of travel times between milestones
    $travelTime = array_sum($this->travelTimes);

    // add delay if dropping kid off at school
    $schoolDelay = ($stopAtSchool) ? 10 : 0;

    // add delay if checking tire pressure
    $tiresDelay = ($checkTires) ? 10 : 0;

    // find the total schedule baseline
    $meetingArriveTime = $this->departureTime + $travelTime +
        $schoolDelay + $tiresDelay;

    // does the traveller make the meeting on time?
    $arriveOnTime = $meetingArriveTime <= $this->meetingTime;

    return array($meetingArriveTime, $this->meetingTime,
        $arriveOnTime);
}

Now all we have to do is create an instance of the class and ask it to check my plan:

现在,我们要做的就是创建该类的实例,并要求它检查我的计划:

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

Given the default values, the above will output that my original plan was okay:

给定默认值,以上内容将输出我的原始计划是可以的:

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

I should be there 535 minutes after midnight, and the meeting takes place 540 minutes after midnight. According to the baseline, I’ll arrive at the meeting at 8:45 AM, just 5 minutes before the scheduled time!

我应该在午夜后535分钟到达那里,会议在午夜后540分钟举行。 根据基准,我将在预定时间的5分钟前于上午8:45到达会议!

But what about the inevitable variations? How can we account for the uncertain elements?

但是不可避免的变化呢? 我们如何解释不确定因素?

蒙特卡洛和增加随机性 (Monte Carlo and Adding Randomness)

In a very simplistic way we can define a safety margin to every event and say it could happen 10% earlier and 25% later of the scheduled time. Such margins can be randomly added to the departure delays and every travel time between milestones by multiplying each factor by rand(90,125)/100.

以一种非常简单的方式,我们可以为每个事件定义一个安全裕度,并说它可以在计划时间的10%之前和25%以后发生。 通过将每个因子乘以rand(90,125)/100可以将此类边距随机添加到出发延误和里程碑之间的每个旅行时间。

We can also assign a 50% probability for both decisions to drop my daughter off at school and to check the tires. Again the rand() function can helps us:

我们还可以为两个决定让我的女儿放学和检查轮胎的可能性分配50%的概率。 同样, rand()函数可以帮助我们:

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

Putting it all together, we can define a method checkPlanRisk() to computer whether or not I can arrive on time given the many uncertainties that stand in my way:

checkPlanRisk() ,我们可以定义一个方法checkPlanRisk()来计算机处理,因为存在很多不确定性,我是否可以按时到达:

<?php
public function checkPlanRisk() {
    // adjust and sum travel times between milestones
    $travelTime = 0;
    foreach ($this->travelTimes as $t) {
        $travelTime += $t * rand(90, 125) / 100;
    }

    // decide whether to drop kid off at school and randomly set
    // the delay time
    $schoolDelay = 0;
    if (rand(1, 100) > 50) {
        $schoolDelay = 10 * rand(90, 125) / 100;
    }
    
    // ditto for checking tires
    $tiresDelay = 0;
    if (rand(1, 100) > 50) {
        $tiresDelay = 10 * rand(90, 125) / 100;
    }

    // find the total schedule baseline
    $meetingArriveTime = $this->departureTime + $travelTime +
        $schoolDelay + $tiresDelay;

    // does the traveller make the meeting on time?
    $arriveOnTime = $meetingArriveTime <= $this->meetingTime;

    return array($schoolDelay, $tiresDelay, $meetingArriveTime,
        $this->meetingTime, $arriveOnTime);
}

The question now is, how likely is the traveller to arrive on time given the initial conditions and the assumed uncertainty? Monte Carlo simulations answer this by running a large number of times and computing a “level of confidence”, defined as the ratio of arrivals on time to total number of trials.

现在的问题是,考虑到初始条件和假定的不确定性,旅行者准时到达的可能性有多大? 蒙特卡洛模拟通过运行大量次并计算“置信度”(定义为准时到达次数与试验总数之比)来回答这一问题。

If we run this method a sufficient number of times and record how often the traveller arrives on time, we can establish some sort of margin of confidence whether the trip is feasible as planned.

如果我们运行此方法足够的次数并记录旅行者按时到达的频率,我们可以建立某种程度的信心裕度,表明旅行是否如计划的那样可行。

<?php
public function runCheckPlanRisk($numTrials) {
    $arriveOnTime = 0;
    for ($i = 1; $i <= $numTrials; $i++) {
        $result = $this->checkPlanRisk();
        if ($result[4]) {
            $arriveOnTime++;
        }

        echo "Trial: " . $i;
        echo " School delay: " . $result[0];
        echo " Tire delay: " . $result[1];
        echo " Enroute time: " . $result[2];

        if ($result[4]) {
            echo " -- Arrive ON TIME";
        }
        else {
            echo " -- Arrive late";
        }

        $confidence = $arriveOnTime / $i;
        echo "nConfidence level: $confidencenn";
    }
}

Creating a new instance of MyTrip and asking it compute the confidence level for 1,000 trials is straightforward:

创建MyTrip的新实例并要求其计算1,000个试验的置信度很简单:

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

The output will be a screen print-out of 1,000 entries like this:

输出将是1,000个条目的屏幕打印,如下所示:

Trial: 1000 School delay: 0 Delay tires: 11.3 Enroute time: 530.44 -- Arrive ON TIME
Confidence level: 0.716

With the parameters above, the confidence level seems to converge to 0.72, which roughly indicates that the traveler has 72% chance of getting to the meeting on time.

使用上述参数,信心度似乎收敛到0.72,这大致表明旅行者有72%的机会准时参加会议。

Grosso modo, Monte Carlo relies on the convergence of the mean result of a sequence of identical experiments. The mean result is also known as the expected value and can be thought of as the probability of a desired result occurring. Of course this is quite an old concept and such simulations have been done a long time before the arrival of the digital computer.

Grosso modo和Monte Carlo依靠一系列相同实验的平均结果的收敛性。 平均结果也称为期望值,可以认为是出现期望结果的可能性。 当然,这是一个非常古老的概念,并且这种模拟已经在数字计算机到来之前很长时间了。

结论 (Conclusion)

Today, we have immensely powerful resources at our disposal and a very convenient language like PHP which can be used to create both the simulation logic and a user friendly web interface for it. With a few lines of code, we created a model and applied Monte Carlo simulations with it, producing an intelligible result useful for business decisions. This is a field worth exploring and it would be nice to see some scientific computation functions added to PHP so scientists and engineers could take advantage of this versatile, non-nonsense language.

如今,我们拥有大量强大的资源可供使用,并且像PHP这样非常方便的语言可用于创建仿真逻辑和用户友好的Web界面。 用几行代码,我们创建了一个模型,并对其进行了蒙特卡洛模拟,从而产生了可理解的结果,可用于业务决策。 这是一个值得探索的领域,很高兴看到PHP中添加了一些科学计算功能,以便科学家和工程师可以利用这种通用的,无意义的语言。

Code for this article is available on GitHub.

GitHub上提供了本文的代码

Image via Fotolia

图片来自Fotolia

翻译自: https://www.sitepoint.com/running-monte-carlo-simulations-in-php/

历史模拟与蒙特卡洛模拟

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值