mjqm-simulator

Project structure

The simulator is organized as a modular C++ project with clear separation of concerns. New policies and distributions can be added without modifying core code.

The project follows the Pitchfork Layout convention for directory organisation.

Design principles

The project follows these key principles:

Folder organisation

mjqm-simulator
├── docs
├── Inputs
│   └── {your_and_default_input_files...}
├── libs
│   ├── policies
│   │   ├── include
│   │   │   └── mjqm-policies
│   │   │       ├── policies.h
│   │   │       ├── policy.h
│   │   │       └── {SpecificPolicy...}.h
│   │   ├── src
│   │   │   └── mjqm-policies
│   │   │       └── {SpecificPolicy...}.cpp
│   │   └── CMakeLists.txt
│   ├── samplers
│   │   ├── include
│   │   │   └── mjqm-samplers
│   │   │       ├── sampler.h
│   │   │       ├── samplers.h
│   │   │       └── {specific_sampler...}.hpp
│   │   └── CMakeLists.txt
│   ├── simulator
│   │   ├── include
│   │   │   ├── mjqm-settings
│   │   │   │   ├── toml_distributions_loaders.h
│   │   │   │   ├── toml_loader.h
│   │   │   │   ├── toml_overrides.h
│   │   │   │   ├── toml_policies_loaders.h
│   │   │   │   └── toml_utils.h
│   │   │   └── mjqm-simulator
│   │   │       ├── experiment.h
│   │   │       ├── experiment_stats.h
│   │   │       ├── simulator.h
│   │   │       └── stats.h
│   │   ├── src
│   │   │   ├── mjqm-settings
│   │   │   │   ├── toml_distributions_loaders.cpp
│   │   │   │   ├── toml_loader.cpp
│   │   │   │   ├── toml_overrides.cpp
│   │   │   │   ├── toml_policies_loaders.cpp
│   │   │   │   └── toml_utils.cpp
│   │   │   └── mjqm-simulator
│   │   │       └── experiment_stats.cpp
│   │   └── CMakeLists.txt
│   └── utils
│       ├── include
│       │   ├── mjqm-math
│       │   │   └── confidence_intervals.h
│       │   └── mjqm-utils
│       │       └── string.hpp
│       ├── src
│       │   └── mjqm-math
│       │       └── confidence_intervals.cpp
│       └── CMakeLists.txt
├── scripts
│   ├── convert_conf.py
│   ├── ensure_same_results.py
│   └── select-g++.sh
├── test
│   └── expected
│       └── {expected-output-files...}
├── CMakeLists.txt
├── CMakePresets.json
├── configure
├── README.md
├── rebuild
├── simulator.cpp
└── toml_loader_test.cpp

The project is organized in the following way:

Key architectural components

Library dependencies

The libraries have the following dependency structure:

simulator (top-level application)
    ├── depends on: policies
    ├── depends on: samplers
    └── depends on: utils

policies
    └── depends on: (none, pure interface)

samplers
    └── depends on: (none, pure interface)

utils
    └── depends on: (none, pure utilities)

This dependency hierarchy ensures:

Policy interface

All scheduling policies implement the Policy interface defined in libs/policies/include/mjqm-policies/policy.h. This interface defines:

See Policies for detailed implementation guidance.

Distribution interface

All service time and inter-arrival time distributions implement the DistributionSampler interface in libs/samplers/include/mjqm-samplers/sampler.h. This interface defines:

See Distributions for detailed implementation guidance.

Configuration loading

The TOML configuration system uses a loader pattern with builder functions:

This pattern allows adding new policies and distributions by:

  1. Implementing the interface
  2. Adding a builder function
  3. Registering in the builder map

No changes to core simulation engine required.

Extension points

The simulator provides several extension points:

1. New scheduling policies

Add to libs/policies/:

See: Implementing policies

2. New distributions

Add to libs/samplers/:

See: Implementing distributions

3. New statistics

Modify libs/simulator/include/mjqm-simulator/experiment_stats.h to:

4. Custom analysis tools

Add Python scripts to scripts/ directory:

Building and development workflow

Initial setup

./configure         # First time: configures CMake and Python environment

Development cycle

# After modifying code
./rebuild           # Recompiles changed files

# After modifying code with detailed debugging
./rebuild --debug   # Rebuild with debug symbols

# After major changes (CMakeLists.txt, dependencies)
./configure --clean # Full rebuild from scratch
./rebuild

Testing

./configure --test  # Configure and run tests
./rebuild --test    # Rebuild and run tests

Tests are defined in CMakeLists.txt and compare outputs against expected results in test/expected/.

File naming conventions

Best practices for contributions

  1. Follow existing patterns: Match the style of Smash policy or Exponential distribution
  2. Maintain independence: Don’t introduce dependencies between policies or samplers
  3. Document interfaces: Add comments explaining parameters and behaviour
  4. Test thoroughly: Add expected output files for new features
  5. Update documentation: Add entries to this guide when extending the system