-
Notifications
You must be signed in to change notification settings - Fork 0
SMS++ Project Developer's Guide
This guide orients new developers and maintainers of the SMS++ framework: how the project is laid out as an umbrella of git submodules, how to clone and build it for development, where the core abstractions live, the high-level model that ties everything together, and how to contribute.
If you just want to install and use SMS++, follow the
Installation guide and the
Getting started tutorial first. The complete API
is documented in the SMS++ API reference,
whose narrative design rationale lives in
doxygen/mainpage.md.
[[TOC]]
SMS++ is a C++17 framework for modeling and solving block-structured mathematical optimization problems. It is organized as an umbrella project: the SMS++ Project repository is composed almost entirely of git submodules, each a separate repository. The umbrella itself only tracks which commit of each submodule is currently in use, produces unified documentation, and hosts project-wide issues.
The submodules fall into a few groups:
-
Core library —
SMS++/, the framework itself (theBlock,Solver,Variable,Constraint,Objective,Function,ConfigurationandSolutionabstractions). -
Blocks — problem-specific models, e.g.
BinaryKnapsackBlock,UCBlock,MCFBlock,MMCFBlock,LukFiBlock,StochasticBlock,SDDPBlock,CapacitatedFacilityLocationBlock,InvestmentBlock,TwoStageStochasticBlock,MultiStageStochasticBlock,PolyhedralFunctionBlock. -
Solvers — algorithm implementations, e.g.
MILPSolver(wrapping CPLEX, Gurobi, SCIP and HiGHS),BundleSolver,LagrangianDualSolver,FrankWolfeSolver,BendersDecompositionSolver,MCFClassSolver,MCFLemonSolver,BranchAndXSolver. -
Support —
tools/(command-line utilities),tests/(system tests),vcpkg-registry/(Windows packaging) and thepySMSppPython interface.
Each Block/Solver submodule follows the same internal layout: include/,
src/, lib/, test/, tools/, a CMakeLists.txt and makefiles.
Note: the canonical list of submodules and their repository URLs is the umbrella's
.gitmodulesfile. The top-levelCMakeLists.txtexposes oneBUILD_*flag per optional module (see Customize the configuration).
At its heart, SMS++ represents an optimization problem as a tree of Blocks.
A Block is "a part of a model": it exposes Variables, Constraints and an
Objective, and it can nest arbitrarily many inner Blocks, so structure in the
problem maps directly onto structure in the model.
A Solver is an abstract algorithm that attaches to a Block. Several Solvers can
be attached to the same Block at once, and different Solvers may exploit either
the abstract representation (Variables/Constraints/Objective) or a Block's
physical representation (a specialized data structure for fast,
structure-exploiting algorithms).
The glue between them is the Modification object. Whenever anything in a Block
changes, the Block emits a Modification that is communicated to every attached
Solver. This lets a Solver reuse previous solution information and re-optimize
efficiently instead of solving from scratch.
The core abstractions all live in
SMS++/include/:
| Abstraction | Key headers |
|---|---|
| Block |
Block.h, AbstractBlock.h
|
| Solver |
Solver.h, CDASolver.h
|
| Variable |
Variable.h, ColVariable.h
|
| Constraint |
Constraint.h, RowConstraint.h, FRowConstraint.h, OneVarConstraint.h
|
| Objective |
Objective.h, FRealObjective.h
|
| Function |
Function.h, LinearFunction.h, DQuadFunction.h, C05Function.h, C15Function.h, PolyhedralFunction.h, LagBFunction.h, BendersBFunction.h
|
| Configuration |
Configuration.h, BlockConfig.h, BlockSolverConfig.h
|
| Solution |
Solution.h, ColVariableSolution.h, RowConstraintSolution.h, ColRowSolution.h
|
| Modification | Modification.h |
For the full design rationale and the per-class documentation, read
doxygen/mainpage.md
and browse the SMS++ API reference.
Clone the umbrella with its submodules and check out the develop branch, which
is the canonical entry point for development (the master branch lags behind):
git clone -b develop --recurse-submodules https://gitlab.com/smspp/smspp-project.git
cd smspp-project
git submodule sync --recursive
git submodule update --init --recursiveIf you only need a few modules, clone without --recurse-submodules and
initialize only what you want:
git clone -b develop https://gitlab.com/smspp/smspp-project.git
cd smspp-project
git submodule update --init SMS++ MILPSolver tools # etc.Note: each submodule is checked out at the commit pinned by the umbrella, which leaves it in a detached HEAD state. Before committing inside a submodule,
cdinto it and check out itsdevelopbranch so your work lands on a branch rather than on a detached commit.
To pull the latest tracked commits later:
git pull --recurse-submodules
git submodule sync --recursive
git submodule update --init --recursiveTo advance every submodule to the tip of its tracked branch:
git submodule update --remoteThe primary build system is CMake; each module also ships a makefile for incremental work. From the umbrella:
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build . -- -j$(nproc)Enable optional modules and tests with -D flags (each auto-enables its
dependencies):
cmake -DBUILD_UCBlock=ON -DBUILD_MILPSolver=ON -DBUILD_tests=ON ..For the full set of BUILD_* flags, build-type/shared-library options, compiler
flags and output directories, see Customize the configuration.
For dependencies and the one-shot INSTALL scripts, see the
Installation guide.
The makefile route is described in the umbrella and per-module
READMEs: external library paths default toextlib/makefile-default-paths-<os>and can be overridden in a gitignoredextlib/makefile-paths.
SMS++ uses two kinds of tests:
-
Unit tests live in the
test/directory of each module and exercise that module in isolation (or together with dependencies it already requires). -
System tests live in the
tests/submodule and exercise the interaction between otherwise-independent modules (e.g. solving aUCBlockwithMILPSolver). They are kept separate so that no module gains a horizontal dependency on another just for testing.
A rule of thumb on where to put a new test: if it uses only your module (and its
existing requirements), make it a unit test in your module; if it also needs an
independent module, make it a system test in tests/. The same logic applies to
new command-line utilities (module-local tools/ vs. the shared
tools/ submodule).
Build with -DBUILD_tests=ON, then run them through CTest:
ctest -V -C Release # all tests
ctest -V -R <test-name> # a single test by name patternSome suites also provide a ./batch script for comprehensive runs. See the
tests/README.md
for a description of every suite.
New Block/Solver repositories are not written from scratch: the
ModuleTemplate repository is a
complete, compilable module skeleton (builds, CI, tests and boilerplate in
the standard SMS++ layout) whose init.sh script renames everything after
your module, wires its dependencies and registers it in the umbrella
project. See Creating a new module for the
walkthrough.
Work belongs in the relevant submodule repository: the umbrella only records which submodule commit is in use. A typical change therefore is committed (and merged) inside the module, after which a maintainer bumps the submodule reference in the umbrella:
# inside the umbrella, after the submodule has a new commit on its remote
git add <submodule-dir>
git commit -m "updated submodules"The contribution process itself is defined once, in the project's CONTRIBUTING.md. In short:
- Discuss the change with the authors first (issue or email).
- Develop on a feature branch off
develop; keepdevelopat least compiling so you don't disrupt other developers. - Open a Merge Request. Before requesting a merge: remove build/temporary
files, update the module's
CHANGELOG.md(Keep a Changelog format), and bump the version number — including in the CMake files — following Semantic Versioning (MAJOR for incompatible API changes, MINOR for backwards-compatible features, PATCH for backwards-compatible fixes). - A project maintainer signs off and merges; the changelog feeds straight into the release notes.
Please read the full CONTRIBUTING.md (it also contains the Code of Conduct) before submitting changes.
SMS++ runs its builds and tests through GitLab CI/CD. For how the pipelines are configured, the runners involved, and how to work with them, see the GitLab CI/CD guide.
For help with a single module, see the Getting help section of its README.
For project-level questions, or to propose a new module,
open a new issue.