This repository contains the source code for my bachelor thesis:
- π A fast C++ simulator for the Traffic signaling problemπ¦π from Google Hash Code 2021, with pybind11 bindings
- 𧬠Heuristic optimization algorithms (Genetic Algorithm, Hill Climbing, Simulated Annealing)
- π Experiments comparing the optimization algorithms and reporting new best scores
For the thesis text itself, please refer to bachelor-thesis repository.
| directory / file | description |
|---|---|
traffic_signaling/ |
Contains the source code of the simulator for the Traffic signaling problem; see the README for more details. |
optimizer.py operators.py |
Scripts for running the optimization using Genetic Algorithm, Hill Climbing, and Simulated Annealing. |
experiments/ |
Contains scripts for running the experiments presented in the thesis, see the README for more details. Also see best_solutions for the best schedules found during the experiments. |
Makefile |
Provides a convenient way to set up the environment for optimization and running experiments (see Optimization). Also enables to easily run unit tests. |
When listing version requirements for the tools below, we specify the minimum supported version. As of July 2025, the latest available versions (e.g., Python 3.13) are also compatible. However, we cannot guarantee compatibility with all future versions.
To build and install the traffic-signaling package, you need:
- C++ compiler with C++20 code support; e.g., gcc 11, clang 16, or MSVC 19.29 (or later versions)
- Python 3.10 or later
- Python headers (most likely already installed with Python)
-
You can verify that the headers are available by inspecting their expected location with e.g.:
python3 -c "import sysconfig; print(sysconfig.get_path('include'))" -
If not available, install the headers with e.g.:
sudo apt install python3-dev
-
To easily set up the environment for optimization and run the experiments, you further need:
- GNU Make
Optionally, if you want to run all unit tests for both C++ and Python, you additionally need:
- Git
- CMake 3.24 or later
After satisfying the prerequisites, you can simply build and install
the traffic-signaling Python package by running the following command in the top-level directory:
pip install ./traffic_signalingThis will install the package into your Python environment (preferably into a virtual environment), making it available for use in your Python scripts.
To run Python unit tests for the package using Python's unittest built-in framework, use the following command:
python -m unittest discover -s traffic_signaling/testsTo run both C++ and Python unit tests using CMake, use the following command:
make test_package_cmakeNote that running the make commands will create a virtual environment .venv and install all required packages there using pip.
To quickly set up the environment for optimization, run the following command in the top-level directory:
make setupThis will create a virtual environment .venv, build and install the simulator and other necessary packages into it using pip, and compile the operators.py file using Cython for better performance during optimization.
Do not forget to activate the virtual environment before running any scripts, e.g.:
source .venv/bin/activateIf you encounter any issues, try running make clean and then make setup again.
Now you can run the optimization algorithms using the optimizer.py script. The script has two required positional arguments:
algorithmβ algorithm to use for optimization; possible values arega,hc,sadataβ input dataset to use; possible values area,b,c,d,e,f
After specifying the required arguments, you can easily run the script with, e.g.:
python3 optimizer.py hc eThis will run the Hill Climbing algorithm on dataset E using default values. However, you probably want to explicitly set some parameters, especially the hyperparameter values.
If you prefer, you can run:
python3 optimizer.py --helpto see the full usage. Below is a concise list of the parameters:
--order_initβ order initialization hyperparameter; possible values:adaptive,random,default--times_initβ times initialization hyperparameter; possible values:scaled,default--mutation_bit_rateβ mutation bit rate hyperparameter--populationβ population size hyperparameter (GA only)--generationsβ generations hyperparameter (GA only)--crossoverβ crossover probability hyperparameter (GA only)--mutationβ mutation probability hyperparameter (GA only)--elitismβ elitism hyperparameter (GA only)--tournsizeβ tournament size hyperparameter (GA only)--iterationsβ iterations hyperparameter (HC and SA)--temperatureβ initial temperature hyperparameter (SA only)--seedβ value of the random seed for reproducibility--threadsβ number of threads for parallel evaluation--logdirβ custom name of the directory with results and logs--verboseβ whether to print detailed output during optimization--no-saveβ skip saving results to the log directory
An example of running the script with more parameters could look like this:
python3 optimizer.py ga e \
--order_init random --times_init scaled \
--mutation_bit_rate 5 --population 100 --generations 200 \
--threads 16 --seed 21 --verboseWhen the optimization finishes (and if the --no-save option was not used), the optimizer will save the following files in the log directory:
- A CSV file containing statistics for each iteration/generation of the algorithm
- A file with the best schedules found, stored in the competition format
- A PDF file visualizing the optimization process
- An information file listing all parameters, their values, and additional details
Optionally, you can run unit tests for the optimizer with the following command in the top-level directory:
make test_optimizerTo replicate the experiments presented in this thesis, ensure that you have already run the make setup command, then navigate to the experiments directory.
We recommend reading the experiments/README.md file for more details, but for convenience, we also include the list of commands below. We strongly suggest running each algorithm and dataset separately.
make testβ run a simple sanity check experimentmake init_experimentβ run a quick experiment comparing different initialization methodsmake run_{b,c,d,e,f}_{ga,hc,sa}β run a specific algorithm on a specific dataset (using 10 runs with different fixed seeds)make run_{b,c,d,e,f}β run all algorithms on a specific datasetmake plot_{b,c,d,e,f}β plot the results of a specific datasetmake plotsβ plot all datasetsmake allβ run everything and plot all results
The schedules corresponding to the best scores achieved for each dataset during optimization are stored in the experiments/best_solutions directory.