Back to projects
Mathematics/2026 - Present/Active

F1 Probabilistic Strategy Optimiser

A probabilistic race-strategy engine that simulates thousands of possible F1 races to understand which decisions remain strong when the race does not go to plan.

Monte CarloProbabilityOptimisationSimulation

Built with

PythonNumPypandasMonte Carlo SimulationProbabilityStatistical ModellingOptimisationMultiprocessingGit

Overview

I built this because I was interested in a question that a simple lap-time model cannot really answer: "If I make this strategy call, how likely is it to actually work?" Rather than predicting one race and calling that the answer, I built a simulation engine that generates many possible races and evaluates how a strategy performs across them. The project combines probability, statistics, simulation, optimisation and software engineering, with the longer-term aim of calibrating the model against real F1 data and testing strategies against historical races.

01

What I built

Formula 1 strategy is interesting because there is rarely a single "correct" decision. A pit stop that looks perfect if a Safety Car appears on lap 25 can be terrible if the race stays green. A strategy can also have a better average result while being much more exposed to bad outcomes. That led me away from simply predicting a race time. I wanted to model the **distribution of possible outcomes**. The engine therefore generates candidate strategies, simulates the race repeatedly under different conditions and compares the resulting outcomes. The current engine models things including tyre compounds, tyre degradation, driver performance, fuel effects, pit stops, weather and Safety Car events, with multiprocessing used to make large simulation runs practical.

02

The problem

The first problem was deciding what "best strategy" actually means. If I only minimise average race time, I can end up selecting a strategy that is fast when everything goes right but performs badly when conditions change. That does not really represent how strategy decisions are made. I therefore started thinking about the problem as **decision-making under uncertainty**. Instead of asking: "What is the expected race time?" the engine can ask: "How does this strategy behave across thousands of possible races?" That distinction became one of the most important ideas in the project.

03

Why I built it

I watch Formula 1 and have always found the strategy side of the sport more interesting than simply looking at who finished first. What bothered me was how easy it is to judge a strategy after the race. A strategy can fail because of an unlucky Safety Car or weather change without necessarily being a bad decision. I wanted to build something that separated the **quality of a decision from the outcome of one particular race**. That gave me a project where I could combine something I genuinely enjoy with probability, statistics and software engineering.

Architecture

I deliberately separated the project into different components rather than putting the entire simulation into one large program. The idea is simple: real or estimated race parameters feed into the race model, the strategy generator creates possible decisions, the Monte Carlo engine samples possible races, and the evaluation layer turns those simulations into information that can actually be used to compare strategies. This separation also makes it possible to improve one part of the model without rewriting everything around it.

01

Race data & parameters

Tyres, pace, track characteristics, weather and race conditions

02

Race models

Driver, track, tyre and environment behaviour

03

Strategy generator

Different compounds, pit windows and stop combinations

04

Monte Carlo engine

Thousands of possible race scenarios

05

Outcome analysis

Race time, consistency, risk and strategic performance

06

Decision engine

Compare strategies against the chosen objective

Engineering

Monte Carlo simulation

Instead of running one deterministic race, the engine repeatedly samples uncertain parts of the race and produces a distribution of possible outcomes. This changed the way I thought about the problem. The output is no longer simply "strategy A takes 92.4 minutes". It becomes a picture of how strategy A behaves when the race changes. That same idea is useful far beyond motorsport whenever decisions have uncertain outcomes.

Tyre degradation

Tyres are not simply assigned a fixed lap-time penalty. Their performance changes as the stint develops, meaning the timing of a pit stop becomes part of the optimisation problem. This forced me to think about how a mathematical model represents something that is continuously changing rather than just assigning one value to it.

Risk-aware strategy evaluation

One of the biggest changes in the project was moving away from treating average performance as the whole story. A strategy can have a good expected result while also having much greater downside. That led me to introduce risk and consistency into the decision process so that strategies can be compared using more than one statistic.

Multiprocessing

Monte Carlo simulation becomes computationally expensive very quickly because every additional strategy requires many possible races. I therefore used multiprocessing so independent simulations can be distributed across CPU workers. This gave me a practical introduction to the difference between writing code that works and writing code that can actually scale to the amount of computation the problem requires.

Modular modelling

I separated concepts such as drivers, tracks, tyres, race state and the simulation engine into distinct components. That made the project easier to extend and, more importantly, forced me to think about what each part of the system should actually be responsible for.

Validation

A simulation can produce extremely convincing graphs while still being completely wrong. That became one of the biggest lessons of the project. Before trusting an optimisation result, I need to know whether the underlying model behaves sensibly. This pushed me towards validation, parameter calibration and eventually backtesting against real races.

Algorithms

Monte Carlo simulation

Generate many possible race scenarios and estimate the behaviour of a strategy from the resulting distribution rather than from a single run.

Probability modelling

Represent uncertain race events such as weather and Safety Cars probabilistically rather than assuming that the future is known.

Discrete strategy search

Pit laps and tyre choices form a discrete decision space, so the engine evaluates candidate strategies rather than attempting to optimise a continuous mathematical function.

Risk-aware optimisation

Strategies can be compared using expected performance alongside variability and downside risk. This is much closer to how I now think about real decision problems: the fastest option is not automatically the best option.

Mathematics

Monte Carlo estimate

V^(s)=1Ni=1Nf(ωi,s)\hat{V}(s) = \frac{1}{N} \sum_{i=1}^{N} f(\omega_i, s)

Estimate the value of strategy s by averaging its performance across N simulated race scenarios.

Expected value vs risk

Score(s)=E[T(s)]+λR(s)Score(s) = E[T(s)] + \lambda R(s)

A simple representation of the idea that a strategy can be evaluated using both expected performance and risk.

Results

Monte Carlo

Simulation approach

Thousands per strategy

Race scenarios

Tyres, pace, fuel, weather & Safety Cars

Core race factors

Multiprocessing

Simulation execution

What broke

01

Making randomness useful rather than noisy

At first, adding randomness simply made the outputs move around. The challenge was making that randomness represent something meaningful. I learned that stochastic modelling is not just "add random numbers". The distributions, assumptions and parameters behind those random values matter just as much as the simulation itself.

02

Knowing whether an optimisation result is actually meaningful

An optimiser will happily return an answer even when the underlying model is poor. That made validation one of the most important parts of the project. I became much more cautious about treating an impressive-looking result as evidence.

03

Balancing realism with complexity

It would be possible to model almost every part of an F1 race, but that does not automatically make the model better. I had to decide which effects were worth modelling explicitly and which could initially be represented through uncertainty. That taught me an important engineering lesson: **a model is useful because it is appropriate, not because it is complicated.**

What I learned

I stopped thinking in single predictions

The biggest change was learning to think about distributions rather than single answers. That is useful whenever the future is uncertain — from financial modelling to engineering reliability to resource planning.

The model is only as good as its assumptions

A sophisticated simulation does not automatically produce a sophisticated answer. If the assumptions are wrong, more simulations simply give me a more precise wrong answer.

Performance matters when the mathematics scales

A model that works for ten simulations is not necessarily useful for ten thousand. The project made me think much more carefully about algorithmic cost, multiprocessing and where computation is actually being spent.

Optimisation is really about defining "better"

The hardest part is not always finding the optimum. Sometimes it is deciding what the objective should be in the first place. That idea has changed how I approach optimisation problems outside F1 as well.

Next

  • Calibrate model parameters using real F1 session data
  • Backtest strategies against historical races
  • Model rival teams as responsive agents
  • Introduce circuit-specific tyre degradation models
  • Propagate parameter uncertainty through the simulation
  • Investigate more advanced optimisation methods
  • Build a browser-based interface for exploring strategy distributions