affine-mpc 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. affine_mpc-0.2.0/.clang-format +55 -0
  2. affine_mpc-0.2.0/.github/workflows/build_test.yaml +65 -0
  3. affine_mpc-0.2.0/.github/workflows/check_stubs.yaml +51 -0
  4. affine_mpc-0.2.0/.github/workflows/docs.yaml +54 -0
  5. affine_mpc-0.2.0/.github/workflows/publish_pypi.yaml +132 -0
  6. affine_mpc-0.2.0/.gitignore +35 -0
  7. affine_mpc-0.2.0/CITATION.cff +22 -0
  8. affine_mpc-0.2.0/CMakeLists.txt +244 -0
  9. affine_mpc-0.2.0/CODE_OF_CONDUCT.md +48 -0
  10. affine_mpc-0.2.0/CONTRIBUTING.md +59 -0
  11. affine_mpc-0.2.0/LICENSE +31 -0
  12. affine_mpc-0.2.0/PKG-INFO +112 -0
  13. affine_mpc-0.2.0/README.md +60 -0
  14. affine_mpc-0.2.0/cmake/affine_mpcConfig.cmake.in +9 -0
  15. affine_mpc-0.2.0/cmake/extern_eigen.cmake +41 -0
  16. affine_mpc-0.2.0/cmake/extern_gtest.cmake +18 -0
  17. affine_mpc-0.2.0/cmake/extern_osqp.cmake +68 -0
  18. affine_mpc-0.2.0/docs/assets/favicon.svg +22 -0
  19. affine_mpc-0.2.0/docs/assets/input-parameterization/degree1-saturation.svg +1784 -0
  20. affine_mpc-0.2.0/docs/assets/input-parameterization/degree3-saturation.svg +1879 -0
  21. affine_mpc-0.2.0/docs/assets/input-parameterization/factory-methods.svg +2216 -0
  22. affine_mpc-0.2.0/docs/assets/input-parameterization/knot-placement.svg +1915 -0
  23. affine_mpc-0.2.0/docs/concepts/index.md +68 -0
  24. affine_mpc-0.2.0/docs/concepts/input-parameterization.md +202 -0
  25. affine_mpc-0.2.0/docs/concepts/nomenclature.md +53 -0
  26. affine_mpc-0.2.0/docs/concepts/problem-formulation.md +149 -0
  27. affine_mpc-0.2.0/docs/concepts/qp-formulation.md +754 -0
  28. affine_mpc-0.2.0/docs/concepts/runtime-updates.md +166 -0
  29. affine_mpc-0.2.0/docs/development.md +231 -0
  30. affine_mpc-0.2.0/docs/examples.md +86 -0
  31. affine_mpc-0.2.0/docs/getting-started/cpp.md +197 -0
  32. affine_mpc-0.2.0/docs/getting-started/index.md +22 -0
  33. affine_mpc-0.2.0/docs/getting-started/python.md +111 -0
  34. affine_mpc-0.2.0/docs/index.md +31 -0
  35. affine_mpc-0.2.0/docs/logging.md +193 -0
  36. affine_mpc-0.2.0/docs/usage.md +535 -0
  37. affine_mpc-0.2.0/examples/plot_sim.py +167 -0
  38. affine_mpc-0.2.0/examples/sim.cpp +86 -0
  39. affine_mpc-0.2.0/examples/sim.py +99 -0
  40. affine_mpc-0.2.0/include/affine_mpc/affine_mpc.hpp +29 -0
  41. affine_mpc-0.2.0/include/affine_mpc/condensed_mpc.hpp +88 -0
  42. affine_mpc-0.2.0/include/affine_mpc/mpc_base.hpp +511 -0
  43. affine_mpc-0.2.0/include/affine_mpc/mpc_logger.hpp +241 -0
  44. affine_mpc-0.2.0/include/affine_mpc/options.hpp +68 -0
  45. affine_mpc-0.2.0/include/affine_mpc/osqp_solver.hpp +237 -0
  46. affine_mpc-0.2.0/include/affine_mpc/parameterization.hpp +182 -0
  47. affine_mpc-0.2.0/include/affine_mpc/solve_status.hpp +111 -0
  48. affine_mpc-0.2.0/include/affine_mpc/sparse_mpc.hpp +85 -0
  49. affine_mpc-0.2.0/pyproject.toml +65 -0
  50. affine_mpc-0.2.0/python/CMakeLists.txt +164 -0
  51. affine_mpc-0.2.0/python/affine_mpc/__init__.py +36 -0
  52. affine_mpc-0.2.0/python/affine_mpc/plotter.py +5 -0
  53. affine_mpc-0.2.0/python/affine_mpc/py.typed +0 -0
  54. affine_mpc-0.2.0/python/bindings/affine_mpc_py_module.cpp +22 -0
  55. affine_mpc-0.2.0/python/bindings/affine_mpc_py_module.hpp +19 -0
  56. affine_mpc-0.2.0/python/bindings/py_condensed_mpc.cpp +58 -0
  57. affine_mpc-0.2.0/python/bindings/py_mpc_base.cpp +698 -0
  58. affine_mpc-0.2.0/python/bindings/py_mpc_logger.cpp +180 -0
  59. affine_mpc-0.2.0/python/bindings/py_options.cpp +107 -0
  60. affine_mpc-0.2.0/python/bindings/py_osqp_settings.cpp +296 -0
  61. affine_mpc-0.2.0/python/bindings/py_parameterization.cpp +249 -0
  62. affine_mpc-0.2.0/python/bindings/py_solve_status.cpp +66 -0
  63. affine_mpc-0.2.0/python/bindings/py_sparse_mpc.cpp +58 -0
  64. affine_mpc-0.2.0/python/custom_stubgen.py +139 -0
  65. affine_mpc-0.2.0/python/generate_parameterization_figs.py +393 -0
  66. affine_mpc-0.2.0/requirements/build.txt +5 -0
  67. affine_mpc-0.2.0/requirements/docs.txt +1 -0
  68. affine_mpc-0.2.0/requirements/examples.txt +3 -0
  69. affine_mpc-0.2.0/src/condensed_mpc.cpp +169 -0
  70. affine_mpc-0.2.0/src/eigen_compat.hpp +24 -0
  71. affine_mpc-0.2.0/src/mpc_base.cpp +720 -0
  72. affine_mpc-0.2.0/src/mpc_logger.cpp +596 -0
  73. affine_mpc-0.2.0/src/npy_writer.cpp +141 -0
  74. affine_mpc-0.2.0/src/npy_writer.hpp +24 -0
  75. affine_mpc-0.2.0/src/npz_writer.cpp +725 -0
  76. affine_mpc-0.2.0/src/npz_writer.hpp +69 -0
  77. affine_mpc-0.2.0/src/options.cpp +37 -0
  78. affine_mpc-0.2.0/src/osqp_solver.cpp +377 -0
  79. affine_mpc-0.2.0/src/parameterization.cpp +273 -0
  80. affine_mpc-0.2.0/src/solve_status.cpp +56 -0
  81. affine_mpc-0.2.0/src/sparse_mpc.cpp +186 -0
  82. affine_mpc-0.2.0/test/affine_mpc/condensed_mpc_tests.cpp +347 -0
  83. affine_mpc-0.2.0/test/affine_mpc/consistency_tests.cpp +1074 -0
  84. affine_mpc-0.2.0/test/affine_mpc/mpc_base_tests.cpp +1195 -0
  85. affine_mpc-0.2.0/test/affine_mpc/mpc_logger_tests.cpp +190 -0
  86. affine_mpc-0.2.0/test/affine_mpc/np_writer_fixture.cpp +120 -0
  87. affine_mpc-0.2.0/test/affine_mpc/npz_writer_tests.cpp +51 -0
  88. affine_mpc-0.2.0/test/affine_mpc/osqp_solver_tests.cpp +640 -0
  89. affine_mpc-0.2.0/test/affine_mpc/parameterization_tests.cpp +586 -0
  90. affine_mpc-0.2.0/test/affine_mpc/sparse_mpc_tests.cpp +595 -0
  91. affine_mpc-0.2.0/test/affine_mpc/utils.hpp +65 -0
  92. affine_mpc-0.2.0/test/bindings/conftest.py +129 -0
  93. affine_mpc-0.2.0/test/bindings/test_condensed_mpc.py +234 -0
  94. affine_mpc-0.2.0/test/bindings/test_mpc_base.py +84 -0
  95. affine_mpc-0.2.0/test/bindings/test_mpc_logger.py +229 -0
  96. affine_mpc-0.2.0/test/bindings/test_options.py +17 -0
  97. affine_mpc-0.2.0/test/bindings/test_osqp_settings.py +55 -0
  98. affine_mpc-0.2.0/test/bindings/test_parameterization.py +70 -0
  99. affine_mpc-0.2.0/test/bindings/test_solve_status.py +44 -0
  100. affine_mpc-0.2.0/test/bindings/test_sparse_mpc.py +118 -0
  101. affine_mpc-0.2.0/test/python_npz/conftest.py +65 -0
  102. affine_mpc-0.2.0/test/python_npz/test_np_writers.py +165 -0
  103. affine_mpc-0.2.0/zensical.toml +129 -0
@@ -0,0 +1,55 @@
1
+ # See https://clang.llvm.org/docs/ClangFormat.html
2
+ #
3
+ # Google style guide: https://google.github.io/styleguide/cppguide.html#Variable_Names
4
+ ---
5
+ BasedOnStyle: LLVM
6
+ InsertNewlineAtEOF: true
7
+ ---
8
+ Language: Cpp
9
+ # Standard: Cpp11
10
+
11
+ # ColumnLimit: 80
12
+ # AccessModifierOffset: -4
13
+ # IndentWidth: 4
14
+ # UseTab: Never
15
+
16
+ # Force pointers to the type
17
+ DerivePointerAlignment: false
18
+ PointerAlignment: Left
19
+ # IndentPPDirectives: AfterHash
20
+
21
+ # AlignTrailingComments: false # default is true
22
+
23
+ # AlignEscapedNewlines: Left
24
+ # AllowShortFunctionsOnASingleLine: Empty
25
+ # AllowShortLambdasOnASingleLine: Empty
26
+ # AlwaysBreakTemplateDeclarations: true
27
+
28
+ BreakBeforeBraces: Custom
29
+ BraceWrapping:
30
+ AfterClass: true
31
+ AfterFunction: true
32
+ AfterControlStatement: false
33
+ AfterEnum: true
34
+ AfterStruct: true
35
+ AfterUnion: true
36
+ AfterNamespace: false
37
+ SplitEmptyRecord: false
38
+ SplitEmptyFunction: false
39
+ # AfterInit: true
40
+
41
+ AllowAllConstructorInitializersOnNextLine: true
42
+ ConstructorInitializerAllOnOneLineOrOnePerLine: true
43
+
44
+ BreakConstructorInitializers: AfterColon # BeforeComma
45
+
46
+ MaxEmptyLinesToKeep: 2
47
+ SeparateDefinitionBlocks: Leave # Always
48
+
49
+ # Bin packing fits as many items as possible on one line within column limit
50
+ # With it off, each item gets its own line
51
+ BinPackParameters: false # AlwaysOnePerLine
52
+ # BinPackArguments: true
53
+ # Cpp11BracedListStyle: false
54
+ # AlignAfterOpenBracket: DontAlign
55
+ BreakBeforeBinaryOperators: NonAssignment
@@ -0,0 +1,65 @@
1
+ name: Build and Test
2
+
3
+ on:
4
+ pull_request:
5
+ paths:
6
+ - CMakeLists.txt
7
+ - cmake/**
8
+ - include/**
9
+ - src/**
10
+ - test/**
11
+ - python/CMakeLists.txt
12
+ - python/affine_mpc/**
13
+ - python/bindings/**
14
+ - requirements/build.txt
15
+ - .github/workflows/build_test.yaml
16
+ push:
17
+ branches: [main]
18
+ paths:
19
+ - CMakeLists.txt
20
+ - cmake/**
21
+ - include/**
22
+ - src/**
23
+ - test/**
24
+ - python/CMakeLists.txt
25
+ - python/affine_mpc/**
26
+ - python/bindings/**
27
+ - requirements/build.txt
28
+ - .github/workflows/build_test.yaml
29
+
30
+ jobs:
31
+ build-test:
32
+ runs-on: ubuntu-latest
33
+
34
+ steps:
35
+ - name: Checkout repository
36
+ uses: actions/checkout@v4
37
+
38
+ - name: Set up Python
39
+ uses: actions/setup-python@v5
40
+ with:
41
+ python-version: "3.14"
42
+
43
+ - name: Install Linux build dependencies
44
+ run: |
45
+ sudo apt-get update
46
+ sudo apt-get install -y cmake build-essential libeigen3-dev zlib1g-dev
47
+
48
+ - name: Install Python build dependencies
49
+ run: python -m pip install -r requirements/build.txt
50
+
51
+ - name: Configure CMake
52
+ run: |
53
+ cmake -S . -B build \
54
+ -DAFFINE_MPC_BUILD_EXAMPLES=ON \
55
+ -DAFFINE_MPC_BUILD_TESTS=ON \
56
+ -DAFFINE_MPC_BUILD_BINDINGS=ON
57
+
58
+ - name: Build project
59
+ run: cmake --build build --config Release --parallel
60
+
61
+ - name: Run examples
62
+ run: ./build/example_sim
63
+
64
+ - name: Run tests
65
+ run: ctest --test-dir build --output-on-failure
@@ -0,0 +1,51 @@
1
+ name: Check Stubs
2
+
3
+ on:
4
+ pull_request:
5
+ paths:
6
+ - python/bindings/**
7
+ - python/CMakeLists.txt
8
+ - python/custom_stubgen.py
9
+ - python/affine_mpc/_bindings.pyi
10
+ - pyproject.toml
11
+ - .github/workflows/check_stubs.yaml
12
+ push:
13
+ branches: [main]
14
+ paths:
15
+ - python/bindings/**
16
+ - python/CMakeLists.txt
17
+ - python/custom_stubgen.py
18
+ - python/affine_mpc/_bindings.pyi
19
+ - pyproject.toml
20
+ - .github/workflows/check_stubs.yaml
21
+
22
+ jobs:
23
+ check-stubs:
24
+ runs-on: ubuntu-latest
25
+
26
+ steps:
27
+ - name: Checkout repository
28
+ uses: actions/checkout@v4
29
+
30
+ - name: Set up Python
31
+ uses: actions/setup-python@v5
32
+ with:
33
+ python-version: "3.14"
34
+
35
+ - name: Install Linux build dependencies
36
+ run: |
37
+ sudo apt-get update
38
+ sudo apt-get install -y cmake build-essential libeigen3-dev zlib1g-dev
39
+
40
+ - name: Install package and regenerate stubs
41
+ run: |
42
+ python -m pip install ".[dev]"
43
+ python python/custom_stubgen.py
44
+
45
+ - name: Check committed stub file is up to date
46
+ run: |
47
+ git diff --exit-code -- python/affine_mpc/_bindings.pyi || {
48
+ echo "Generated bindings stub differs from python/affine_mpc/_bindings.pyi"
49
+ echo "Regenerate the stub locally and commit the updated file."
50
+ exit 1
51
+ }
@@ -0,0 +1,54 @@
1
+ name: Deploy Docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - "docs/**"
8
+ - "zensical.toml"
9
+ - "requirements/docs.txt"
10
+ - ".github/workflows/docs.yml"
11
+ workflow_dispatch:
12
+
13
+ permissions:
14
+ contents: read
15
+ pages: write
16
+ id-token: write
17
+
18
+ concurrency:
19
+ group: pages
20
+ cancel-in-progress: true
21
+
22
+ jobs:
23
+ build:
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - name: Checkout repository
27
+ uses: actions/checkout@v4
28
+
29
+ - name: Set up Python
30
+ uses: actions/setup-python@v5
31
+ with:
32
+ python-version: "3.12"
33
+
34
+ - name: Install docs dependencies
35
+ run: python -m pip install -r requirements/docs.txt
36
+
37
+ - name: Build docs site
38
+ run: zensical build
39
+
40
+ - name: Upload Pages artifact
41
+ uses: actions/upload-pages-artifact@v3
42
+ with:
43
+ path: site
44
+
45
+ deploy:
46
+ needs: build
47
+ runs-on: ubuntu-latest
48
+ environment:
49
+ name: github-pages
50
+ url: ${{ steps.deployment.outputs.page_url }}
51
+ steps:
52
+ - name: Deploy to GitHub Pages
53
+ id: deployment
54
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,132 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ env:
8
+ ## Manually specify versions if one ever fails
9
+ # CIBW_BUILD: "cp310-* cp311-* cp312-* cp313-* cp314-*"
10
+ CIBW_SKIP: "cp3??t-* *-win32 *-manylinux_i686 *-musllinux_i686"
11
+ CIBW_ARCHS_WINDOWS: AMD64
12
+ CIBW_TEST_REQUIRES: pytest
13
+ CIBW_ENVIRONMENT: AFFINE_MPC_HAS_ZLIB=1
14
+ CIBW_TEST_COMMAND: "python -m pytest {project}/test/bindings"
15
+ CIBW_BEFORE_ALL_LINUX: >-
16
+ bash -c 'if command -v dnf >/dev/null 2>&1; then dnf install -y zlib-devel;
17
+ elif command -v yum >/dev/null 2>&1; then yum install -y zlib-devel;
18
+ elif command -v apt-get >/dev/null 2>&1; then apt-get update && apt-get install -y zlib1g-dev;
19
+ elif command -v apk >/dev/null 2>&1; then apk add --no-cache zlib-dev;
20
+ else echo "No supported package manager found for installing zlib" >&2; exit 1; fi'
21
+ CIBW_BEFORE_BUILD_WINDOWS: "pip install delvewheel"
22
+ CIBW_ENVIRONMENT_WINDOWS: >-
23
+ AFFINE_MPC_HAS_ZLIB=1 CMAKE_ARGS='-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static'
24
+ CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair -w {dest_dir} {wheel}"
25
+
26
+ jobs:
27
+ build-wheels:
28
+ runs-on: ${{ matrix.os }}
29
+ strategy:
30
+ matrix:
31
+ ## Manually specify versions if one ever fails
32
+ # os: [ubuntu-24.04, windows-2025, macos-15]
33
+ os: [ubuntu-latest, windows-latest, macos-latest]
34
+
35
+ steps:
36
+ - name: Checkout repository
37
+ uses: actions/checkout@v4
38
+
39
+ - name: Set up Python
40
+ uses: actions/setup-python@v5
41
+ with:
42
+ python-version: "3.12"
43
+
44
+ # Windows step
45
+ - name: Install dependencies (Windows)
46
+ if: runner.os == 'Windows'
47
+ shell: pwsh
48
+ run: |
49
+ git clone https://github.com/microsoft/vcpkg.git C:\vcpkg
50
+ C:\vcpkg\bootstrap-vcpkg.bat
51
+ C:\vcpkg\vcpkg install zlib:x64-windows-static eigen3:x64-windows-static
52
+
53
+ # macOS step
54
+ - name: Install dependencies (macOS)
55
+ if: runner.os == 'macOS'
56
+ run: |
57
+ brew update
58
+ brew install cmake zlib eigen
59
+
60
+ - name: Install cibuildwheel
61
+ run: pip install cibuildwheel
62
+
63
+ - name: Build wheels
64
+ run: cibuildwheel --output-dir wheelhouse
65
+
66
+ - name: List built wheels (Windows)
67
+ if: runner.os == 'Windows'
68
+ shell: pwsh
69
+ run: |
70
+ if (Test-Path wheelhouse) {
71
+ ls wheelhouse
72
+ } else {
73
+ Write-Host "wheelhouse folder does not exist yet."
74
+ }
75
+
76
+ - name: List built wheels (Linux/macOS)
77
+ if: runner.os != 'Windows'
78
+ run: ls -l wheelhouse
79
+
80
+ - name: Upload built wheels as artifact
81
+ uses: actions/upload-artifact@v4
82
+ with:
83
+ name: python-wheels-${{ matrix.os }}
84
+ path: wheelhouse/*.whl
85
+
86
+ build-sdist:
87
+ runs-on: ubuntu-latest
88
+
89
+ steps:
90
+ - name: Checkout repository
91
+ uses: actions/checkout@v4
92
+ with:
93
+ fetch-depth: 0
94
+
95
+ - name: Set up Python
96
+ uses: actions/setup-python@v5
97
+ with:
98
+ python-version: "3.12"
99
+
100
+ - name: Install build frontend
101
+ run: python -m pip install build
102
+
103
+ - name: Build sdist
104
+ run: python -m build --sdist
105
+
106
+ - name: Upload sdist as artifact
107
+ uses: actions/upload-artifact@v4
108
+ with:
109
+ name: python-sdist
110
+ path: dist/*.tar.gz
111
+
112
+ publish-pypi:
113
+ needs: [build-wheels, build-sdist]
114
+ runs-on: ubuntu-latest
115
+ environment: pypi
116
+ permissions:
117
+ id-token: write
118
+ steps:
119
+ - name: Download distribution artifacts
120
+ uses: actions/download-artifact@v4
121
+ with:
122
+ pattern: python-*
123
+ path: dist
124
+ merge-multiple: true
125
+
126
+ - name: List downloaded distributions
127
+ run: ls -l dist
128
+
129
+ - name: Publish distributions to PyPI
130
+ uses: pypa/gh-action-pypi-publish@release/v1
131
+ with:
132
+ packages_dir: dist
@@ -0,0 +1,35 @@
1
+ build/
2
+ build*/
3
+ install/
4
+ out/
5
+ Debug/
6
+ Release/
7
+ MinSizRel/
8
+ RelWithDebInfo/
9
+ Deployment/
10
+ Development/
11
+
12
+ notes/
13
+
14
+ compile_commands.json
15
+ .cache/
16
+
17
+ # IDE files
18
+ *.user
19
+ .vscode/
20
+
21
+ # python files
22
+ *.egg-info/
23
+ __pycache__/
24
+ *.so
25
+ *.pyd
26
+ *.pyi
27
+ .pytest_cache/
28
+ .cache/
29
+ dist/
30
+
31
+ # docs
32
+ site/
33
+
34
+ # generated by scikit-build-core
35
+ python/affine_mpc/_version.py
@@ -0,0 +1,22 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software, please cite it as below."
3
+ authors:
4
+ - family-names: "Haskell"
5
+ given-names: "Mathew"
6
+ orcid: "https://orcid.org/0000-0003-3813-7312"
7
+ - family-names: "Killpack"
8
+ given-names: "Marc"
9
+ orcid: "https://orcid.org/0000-0001-9372-104X"
10
+ title: "affine_mpc: A library for affine model predictive control with C++ and Python interfaces"
11
+ version: 0.2.0
12
+ date-released: 2026-10-07
13
+ url: "https://byu-rad-lab.github.io/affine_mpc"
14
+ license: BSD-3-Clause
15
+ repository-code: "https://github.com/byu-rad-lab/affine_mpc"
16
+ keywords:
17
+ - model predictive control
18
+ - control
19
+ - robotics
20
+ - optimization
21
+ - b-spline
22
+ - quadratic-programming
@@ -0,0 +1,244 @@
1
+ cmake_minimum_required(VERSION 3.18)
2
+ project(affine_mpc
3
+ LANGUAGES CXX C
4
+ VERSION 0.2.0
5
+ )
6
+
7
+ # Default to an optimized build. Single-config generators (Makefiles, Ninja)
8
+ # otherwise build without optimization when no build type is given, and
9
+ # `cmake --build --config Release` only applies to multi-config generators.
10
+ # Only set when this is the top-level project so parent projects keep control.
11
+ get_property(AFFINE_MPC_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
12
+ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR AND NOT AFFINE_MPC_MULTI_CONFIG)
13
+ if(NOT CMAKE_BUILD_TYPE)
14
+ set(CMAKE_BUILD_TYPE Release CACHE STRING
15
+ "Build type (Debug, Release, RelWithDebInfo, MinSizeRel)" FORCE)
16
+ message(STATUS "No build type given; defaulting to Release")
17
+ endif()
18
+ # dropdown in cmake-gui and ccmake
19
+ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
20
+ Debug Release RelWithDebInfo MinSizeRel)
21
+ endif()
22
+
23
+ # --------------------------------------------------
24
+ # Standard includes
25
+ # --------------------------------------------------
26
+ include(GNUInstallDirs)
27
+ include(CMakePackageConfigHelpers)
28
+
29
+ # --------------------------------------------------
30
+ # Options
31
+ # --------------------------------------------------
32
+ option(AFFINE_MPC_BUILD_TESTS "Build unit tests" OFF)
33
+ option(AFFINE_MPC_BUILD_EXAMPLES "Build examples" OFF)
34
+
35
+ # Internal flag for building python bindings
36
+ if(NOT DEFINED AFFINE_MPC_BUILD_BINDINGS)
37
+ set(AFFINE_MPC_BUILD_BINDINGS OFF)
38
+ endif()
39
+
40
+ # --------------------------------------------------
41
+ # Dependencies
42
+ # --------------------------------------------------
43
+ include(cmake/extern_eigen.cmake)
44
+ include(cmake/extern_osqp.cmake)
45
+ find_package(ZLIB QUIET)
46
+
47
+ # --------------------------------------------------
48
+ # Main library
49
+ # --------------------------------------------------
50
+ add_library(${PROJECT_NAME}
51
+ src/options.cpp
52
+ src/parameterization.cpp
53
+ src/solve_status.cpp
54
+ src/osqp_solver.cpp
55
+ src/mpc_base.cpp
56
+ src/condensed_mpc.cpp
57
+ src/sparse_mpc.cpp
58
+ src/mpc_logger.cpp
59
+ src/npy_writer.cpp
60
+ src/npz_writer.cpp
61
+ )
62
+
63
+ # Namespaced alias
64
+ add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
65
+
66
+ # Library properties
67
+ set_target_properties(${PROJECT_NAME} PROPERTIES
68
+ POSITION_INDEPENDENT_CODE ON
69
+ )
70
+ if(NOT AFFINE_MPC_BUILD_BINDINGS)
71
+ set_target_properties(${PROJECT_NAME} PROPERTIES
72
+ VERSION ${PROJECT_VERSION}
73
+ SOVERSION ${PROJECT_VERSION_MAJOR}
74
+ )
75
+ endif()
76
+
77
+ # Include directories
78
+ target_include_directories(${PROJECT_NAME} PUBLIC
79
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
80
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
81
+ )
82
+
83
+ target_include_directories(${PROJECT_NAME} PRIVATE
84
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
85
+ )
86
+
87
+ # Link dependencies
88
+ target_link_libraries(${PROJECT_NAME}
89
+ PUBLIC Eigen3::Eigen
90
+ PUBLIC osqp::osqp
91
+ )
92
+
93
+ if(TARGET ZLIB::ZLIB)
94
+ target_link_libraries(${PROJECT_NAME} PRIVATE ZLIB::ZLIB)
95
+ target_compile_definitions(${PROJECT_NAME} PRIVATE AFFINE_MPC_HAS_ZLIB=1)
96
+ else()
97
+ target_compile_definitions(${PROJECT_NAME} PRIVATE AFFINE_MPC_HAS_ZLIB=0)
98
+ endif()
99
+
100
+ # C++ standard
101
+ target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17)
102
+
103
+ # --------------------------------------------------
104
+ # Examples
105
+ # --------------------------------------------------
106
+ if(AFFINE_MPC_BUILD_EXAMPLES)
107
+ add_executable(example_sim examples/sim.cpp)
108
+ target_link_libraries(example_sim PRIVATE ${PROJECT_NAME}::${PROJECT_NAME})
109
+ # the library is C++17; the example uses C++20 designated initializers
110
+ target_compile_features(example_sim PRIVATE cxx_std_20)
111
+ endif()
112
+
113
+ # --------------------------------------------------
114
+ # Python Bindings
115
+ # --------------------------------------------------
116
+ if(AFFINE_MPC_BUILD_BINDINGS)
117
+ if(AFFINE_MPC_BUILD_TESTS)
118
+ set(AFFINE_MPC_PY_ADD_TESTS ON)
119
+ endif()
120
+
121
+ add_subdirectory(python)
122
+ endif()
123
+
124
+ # --------------------------------------------------
125
+ # Tests
126
+ # --------------------------------------------------
127
+ if(AFFINE_MPC_BUILD_TESTS)
128
+ enable_testing()
129
+ include(GoogleTest)
130
+ include(cmake/extern_gtest.cmake)
131
+ find_package(Python COMPONENTS Interpreter QUIET)
132
+
133
+ set(TEST_SOURCES
134
+ test/affine_mpc/osqp_solver_tests.cpp
135
+ test/affine_mpc/parameterization_tests.cpp
136
+ test/affine_mpc/mpc_base_tests.cpp
137
+ test/affine_mpc/condensed_mpc_tests.cpp
138
+ test/affine_mpc/sparse_mpc_tests.cpp
139
+ test/affine_mpc/consistency_tests.cpp
140
+ test/affine_mpc/npz_writer_tests.cpp
141
+ test/affine_mpc/mpc_logger_tests.cpp
142
+ )
143
+
144
+ add_executable(np_writer_fixture test/affine_mpc/np_writer_fixture.cpp)
145
+ set_target_properties(np_writer_fixture PROPERTIES FOLDER tests)
146
+ target_link_libraries(np_writer_fixture
147
+ PRIVATE ${PROJECT_NAME}::${PROJECT_NAME}
148
+ )
149
+ target_include_directories(np_writer_fixture
150
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src
151
+ )
152
+
153
+ if(Python_Interpreter_FOUND)
154
+ execute_process(
155
+ COMMAND "${Python_EXECUTABLE}" -m pytest --version
156
+ RESULT_VARIABLE pytest_found
157
+ OUTPUT_QUIET
158
+ ERROR_QUIET
159
+ )
160
+ if(pytest_found EQUAL 0)
161
+ add_test(
162
+ NAME python_npz_tests
163
+ COMMAND "${Python_EXECUTABLE}" -m pytest
164
+ "${CMAKE_CURRENT_SOURCE_DIR}/test/python_npz"
165
+ )
166
+ set(python_npz_tests_env
167
+ "PYTHONPATH=${CMAKE_BINARY_DIR}"
168
+ "AFFINE_MPC_NP_WRITER_FIXTURE=${CMAKE_BINARY_DIR}/np_writer_fixture"
169
+ "AFFINE_MPC_HAS_ZLIB=$<IF:$<BOOL:${ZLIB_FOUND}>,1,0>"
170
+ )
171
+ set_tests_properties(python_npz_tests PROPERTIES
172
+ ENVIRONMENT "${python_npz_tests_env}"
173
+ )
174
+ else()
175
+ message(FATAL_ERROR "pytest is required to register Python NPZ tests")
176
+ endif()
177
+ else()
178
+ message(FATAL_ERROR
179
+ "Python interpreter is required to register Python NPZ tests"
180
+ )
181
+ endif()
182
+
183
+ foreach(TEST_SRC IN LISTS TEST_SOURCES)
184
+ get_filename_component(TEST_NAME "${TEST_SRC}" NAME_WE)
185
+ add_executable(${TEST_NAME} ${TEST_SRC})
186
+ set_target_properties(${TEST_NAME} PROPERTIES FOLDER tests)
187
+ # the library is C++17; the tests use C++20 designated initializers
188
+ target_compile_features(${TEST_NAME} PRIVATE cxx_std_20)
189
+ target_link_libraries(${TEST_NAME} PRIVATE
190
+ GTest::gtest_main
191
+ ${PROJECT_NAME}::${PROJECT_NAME}
192
+ )
193
+ if(TEST_NAME STREQUAL "npz_writer_tests")
194
+ target_include_directories(${TEST_NAME}
195
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src
196
+ )
197
+ endif()
198
+ gtest_discover_tests(${TEST_NAME})
199
+ endforeach()
200
+ endif()
201
+
202
+ # --------------------------------------------------
203
+ # Installation
204
+ # --------------------------------------------------
205
+ install(TARGETS ${PROJECT_NAME}
206
+ EXPORT ${PROJECT_NAME}Targets
207
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
208
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
209
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
210
+ COMPONENT core
211
+ )
212
+
213
+ install(DIRECTORY include/
214
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
215
+ COMPONENT core
216
+ )
217
+
218
+ set(config_package_location ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
219
+
220
+ install(EXPORT ${PROJECT_NAME}Targets
221
+ FILE ${PROJECT_NAME}Targets.cmake
222
+ NAMESPACE ${PROJECT_NAME}::
223
+ DESTINATION ${config_package_location}
224
+ COMPONENT core
225
+ )
226
+
227
+ write_basic_package_version_file(
228
+ "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
229
+ VERSION ${PROJECT_VERSION}
230
+ COMPATIBILITY SameMajorVersion
231
+ )
232
+
233
+ configure_package_config_file(
234
+ cmake/${PROJECT_NAME}Config.cmake.in
235
+ "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
236
+ INSTALL_DESTINATION ${config_package_location}
237
+ )
238
+
239
+ install(FILES
240
+ "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
241
+ "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
242
+ DESTINATION ${config_package_location}
243
+ COMPONENT core
244
+ )