As I counted the arrival time by the Monte Carlo method

Original author: J Armando Jeronymo
  • Transfer
Easy and "half-holiday" post. Everyone involved with the holiday :)
One of the most exciting things in the eighties was software modeling to solve any complex analytical problems and one of the most used techniques was the Monte Carlo method. It consists in the fact that it starts the simulation a large number of times to obtain an increasingly reliable result.

Despite the fact that PHP is not a scientific language and is rarely used for research purposes, the Monte Carlo method can easily be implemented on it. And in this article I will show how to do it.

Real life challenge

A couple of days ago I should have a meeting at 9 a.m., 100 miles from my house. At 6.30 in the morning I woke up, got dressed, and while I had breakfast, I began to figure out in the notebook the next couple of hours. I, as usual, wanted to arrive on time, so I began to sketch the route: leaving the city, a country road, then the state to the north, east, the local road to the east, drive through the city, then north again and arrive in the city. It all looked something like this:


image

My wife filled the tank last night and I could calmly drive along a country road. The tires seemed to be in order when I looked at them, but the thought of whether or not to stop for 10 minutes to check their pressure did not give me rest. After all, if I stop and check them, then I will be sure of their pressure, because I wasn’t sure of it now, and tire pressure can affect my movement and speed ...
I can leave earlier, for example, at 6.40, but then my wife will have to take her daughter to school herself, instead of going straight to work. If I wait another 10 minutes, then I can be at the school just at the moment when they just open their doors, thereby relieving my wife of the inconvenience, especially since the school on the way to the exit from the city and this did not delay me much .

I went back to what I was painting and added the following:
Drinking a second cup of coffee, I stood at the window. A clear morning sky, a light morning breeze confirmed a good forecast on my smartphone and I thought that the trip this time would be quick. Finishing my planning, I drew an approximate time for each stage that I drew earlier: The
expected trip time was 115 minutes (1 hour and 55 minutes) if I could move without extra stops. I expected to arrive at 8.35 if I went straight away, or at 8.55 if I had to take my daughter with me to send her to school and check the tires at the same time.

But any planning ceases to be ideal after it encounters reality! For some strange reason, many parents decide to leave their children at school earlier than usual, so I lost more than 5 minutes compared to what I planned for my quick trip. Realizing that I was a little late, I decided not to check the tire pressure and go immediately.

I got to the exit of the city 5 minutes earlier than I planned in the worst scenario and everything went well smoothly until somewhere between points B and C in my plan I came across a fog that greatly affected visibility on road. Did the fog slow my average speed? and even prevented to overtake slow, but long trucks. I overcame the city flow in the city much easier than usual and it did not take more than 10 minutes. After a few miles on the southern road, the fog decreased and I could safely ride at the permitted speed. But when I approached my goal, I realized that road work was ahead, and this again would take away my planned time. All in all, I spent another 10 extra minutes on my trip and in the end I was late.

We simulate a journey

I understand that most of the work with PHP is aimed at all kinds of online stores and other websites. But PHP can be a great tool for scientific research, as it is easy for him to train non-professional programmers such as engineers and scientists, unlike my beloved Python.

We will write a small code that will help me understand how sooner or later I can arrive at the meeting if a couple of stages of my journey depart a little from the intended path. For starters, we can describe our path as it is:

<?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) {
        // ...
    }
}


The plan should be a feasible and suitable criterion for determining this so that the sum of all times plus the early departure time should be less than or equal to the time for which my appointment is scheduled. Actually, this is what the checkPlan () method defines:

<?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);
}


That's all, we just have to make an instance of this class and check:

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


Given the default settings, the output will be like this:

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


I have to arrive in 535 minutes, and the appointment is scheduled for 540 minutes. If you translate to hours, then I will arrive at 8.45, ahead of schedule by 15 minutes.

But what about possible delays? How to foresee and calculate them?

Monte Carlo method or add randomness

In its simplest form, we can define a certain safe gap for each event and say that it can happen 10% earlier and 25% later than the specified time. These gaps can be accidentally added to the initial delays (daughter, pressure) and the time between steps by multiplying each factor by rand (90,125) / 100.
You can also assign a 50% probability to two decisions - take your daughter to school and check the tires. Here rand () will help again:

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


Combining all this together, you can define the checkPlanRisk () method to calculate the decision whether I will arrive on time or not, taking into account different situations during the trip:

<?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);
}


Now the question is whether I will arrive on time, taking into account all the possible delays? The Monte Carlo method allows you to solve this problem by launching a large number of times this task and calculating the "level of confidence" as the ratio of the time of arrival on time to the total number of task launches.

If I run this a sufficient number of times and record how often I arrive on time, then I can determine some likelihood that I will arrive as planned.

<?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";
    }
}


Create a new instance and do 1000 calculations one after another:

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


After completion, we get the forecast:

Попыток: 1000 Школа: 0 Шины: 11.3 Время прибытия: 530.44 -- Вовремя
Уровень доверия: 0.716


With the current settings, as you can see, I have a 72% chance of arriving at the meeting on time. Of course, this is just an average value, but it also has the right to life.

On my own: most likely the article is absolutely nothing new, the title is a little yellowish, but this article seemed funny to me. I read for a long time, but I remembered with the appearance of an article on the hub about Monte Carlo. Maybe someone will come in handy.