Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bf7f875
Update lbfgs requirement from 0.2 to 0.3
dependabot[bot] Nov 17, 2025
58727b2
Update rand requirement from 0.9 to 0.10
dependabot[bot] Feb 9, 2026
7feebc6
rewrite definitions without pkg_resources
alphaville Mar 9, 2026
3a93213
removed AffineSpace for now
alphaville Mar 9, 2026
b549f84
getting rid of pkg_resources
alphaville Mar 9, 2026
3ec4e4b
Cholesky factorizer implemented
alphaville Mar 9, 2026
d877fee
matrix_operations: implement aa'
alphaville Mar 9, 2026
f5a912d
wip: cholesky factorisation, aat, and affine subspaces
alphaville Mar 9, 2026
d137cb0
run cargo-fmt
alphaville Mar 9, 2026
e6b8535
remove unnecessary dependencies
alphaville Mar 9, 2026
53178a8
unit tests for CholeskyFactorizer
alphaville Mar 10, 2026
3ff6048
matrix_operations::mul_a_at unit tests
alphaville Mar 10, 2026
a7e09cd
matrix_operations::mul_a_at implementation with ndarray
alphaville Mar 10, 2026
0de30ff
affine space projetion: new implementation
alphaville Mar 10, 2026
72a57c6
[ci skip] cargo-fmt
alphaville Mar 10, 2026
e0533cf
RPi with local OpEn version
alphaville Mar 10, 2026
63e006c
update changelogs; bump versions
alphaville Mar 10, 2026
353414c
mild refactoring
alphaville Mar 10, 2026
cac1c40
cargo fmt
alphaville Mar 10, 2026
81f7c5b
clippy fixes and docs
alphaville Mar 10, 2026
3d563d4
Merge pull request #377 from alphaville/dependabot/cargo/rand-0.10
alphaville Mar 10, 2026
5f7beb3
Merge pull request #375 from alphaville/dependabot/cargo/lbfgs-0.3
alphaville Mar 10, 2026
cfae0a1
Update icasadi_test requirement from 0.0.2 to 0.0.3
dependabot[bot] Mar 10, 2026
7325d57
Merge pull request #371 from alphaville/dependabot/cargo/icasadi_test…
alphaville Mar 11, 2026
2124049
self.is_factorized safety (in CholeskyFactorizer)
alphaville Mar 10, 2026
f8e4c68
[ci skip] fix clippy warnings
alphaville Mar 11, 2026
6eb43a9
bump unit_test_utils version to 0.1.4
alphaville Mar 11, 2026
6f48dd7
Safer templates_dir implementation
alphaville Mar 11, 2026
b4a209d
CholeskyFactorizer: better testing
alphaville Mar 11, 2026
876616e
Run cargo-fmt to format Rust code
alphaville Mar 11, 2026
61abed5
Merge pull request #382 from alphaville/hotfix/templates_dir
alphaville Mar 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@ Note: This is the main Changelog file for the Rust solver. The Changelog file fo


<!-- ---------------------
Unreleased
v0.10.0
--------------------- -->
## [v0.9.2] - Unreleased
## [v0.10.0] - 2026-03-10

### Added

- Custom implementation of Cholesky factorisation (and solver); this is used in `AffineSpace` now.
- New function in `matrix_operations` to compute AA' given a matrix A

### Changed

- Update version of `rand`, `ndarray`, and `modcholesky` in `Cargo.toml`
- Update version of `ndarray`, in `Cargo.toml`
- Removed `modcholesky` because it was causing a bug (see issue #378)

<!-- ---------------------
v0.9.0
Expand Down Expand Up @@ -302,7 +308,7 @@ This is a breaking API change.
--------------------- -->

<!-- Releases -->
[v0.9.2]: https://github.com/alphaville/optimization-engine/compare/v0.9.1...v0.9.2
[v0.10.0]: https://github.com/alphaville/optimization-engine/compare/v0.9.1...v0.10.0
[v0.9.1]: https://github.com/alphaville/optimization-engine/compare/v0.9.0...v0.9.1
[v0.9.0]: https://github.com/alphaville/optimization-engine/compare/v0.8.1...v0.9.0
[v0.8.1]: https://github.com/alphaville/optimization-engine/compare/v0.8.0...v0.8.1
Expand Down
15 changes: 6 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ homepage = "https://alphaville.github.io/optimization-engine/"
repository = "https://github.com/alphaville/optimization-engine"

# Version of this crate (SemVer)
version = "0.9.1"
version = "0.10.0"

edition = "2018"

Expand Down Expand Up @@ -80,7 +80,7 @@ rustdoc-args = ["--html-in-header", "katex-header.html"]
num = "0.4"

# Our own stuff - L-BFGS: limited-memory BFGS directions
lbfgs = "0.2"
lbfgs = "0.3"

# Instant is a generic timer that works on Wasm (with wasm-bindgen)
instant = { version = "0.1" }
Expand All @@ -98,10 +98,7 @@ rpmalloc = { version = "0.2", features = [
# epigraph of the squared Euclidean norm
roots = "0.0.8"

# Least squares solver (NOTE: ndarray must be version 0.15 - not 0.16)
# Bug report: https://github.com/argmin-rs/modcholesky/issues/34
ndarray = { version = "=0.16.1", features = ["approx"] }
modcholesky = "0.2"
ndarray = { version = "=0.17.2", features = ["approx"] }

# jemallocator is an optional feature; it will only be loaded if the feature
# `jem` is used (i.e., if we compile with `cargo build --features jem`)
Expand All @@ -127,15 +124,15 @@ wasm = ["wasm-bindgen", "instant/wasm-bindgen", "instant/inaccurate"]
# --------------------------------------------------------------------------
# These dependencies are only used for testing
[dev-dependencies]
unit_test_utils = "0.1.3"
unit_test_utils = "0.1.4"
# Note: path dependencies (even dev-dependencies) cannot be local in order
# to publish a crate, so the following line can only be used when
# testing locally
# icasadi_test = { path = "test/icasadi_test/" }
# instead, use:
icasadi_test = "0.0.2"
icasadi_test = "0.0.3"
# Random number generators for unit tests:
rand = "0.9"
rand = "0.10"


# --------------------------------------------------------------------------
Expand Down
1 change: 0 additions & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,5 @@ build: false
test_script:
- cargo add roots
- cargo add ndarray --features approx
- cargo add modcholesky
- cargo build
- cargo test --verbose %cargoflags%
1 change: 1 addition & 0 deletions open-codegen/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Note: This is the Changelog file of `opengen` - the Python interface of OpEn

### Changed

- Removed dependence on `pkg_resources` (issue #380)
- Additional unit tests: increased coverage to 92%

## [0.9.4] - 2025-05-08
Expand Down
2 changes: 1 addition & 1 deletion open-codegen/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.9.4
0.9.5
4 changes: 2 additions & 2 deletions open-codegen/opengen/builder/optimizer_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
import os
import jinja2
import logging
import pkg_resources
import sys

from importlib.metadata import version
from .ros_builder import RosBuilder

_AUTOGEN_COST_FNAME = 'auto_casadi_cost.c'
Expand Down Expand Up @@ -750,7 +750,7 @@ def __generate_yaml_data_file(self):

target_yaml_file_path = os.path.join(target_dir, "optimizer.yml")

opengen_version = pkg_resources.require("opengen")[0].version
opengen_version = version("opengen")

tcp_details = None if tcp_config is None \
else {'ip': tcp_config.bind_ip, 'port': tcp_config.bind_port}
Expand Down
15 changes: 8 additions & 7 deletions open-codegen/opengen/definitions.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import pkg_resources
from importlib.resources import files, as_file


def templates_dir():
"""Directory where the templates are found (for internal use, mainly)"""
return pkg_resources.resource_filename('opengen', 'templates/')
return files("opengen") / "templates"


def templates_subdir(subdir=None):
"""
Directory where the templates are found and subfolder relative
to that path(for internal use, mainly)
to that path (for internal use, mainly)
"""
if subdir is None:
return templates_dir()
return pkg_resources.resource_filename('opengen', 'templates/%s/' % subdir)
resource = files("opengen") / "templates"
if subdir is not None:
resource = resource / subdir
return resource


def original_icasadi_dir():
"""Directory where the original icasadi files are found (for internal use)"""
return pkg_resources.resource_filename('opengen', 'icasadi/')
return files("opengen") / "icasadi"
6 changes: 2 additions & 4 deletions open-codegen/opengen/tcp/optimizer_tcp_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
import logging
import time
import math
import pkg_resources
from threading import Thread
from retry import retry
from .solver_response import SolverResponse

from importlib.metadata import version

class OptimizerTcpManager:
"""Client for TCP interface of parametric optimizers
Expand Down Expand Up @@ -66,8 +65,7 @@ def __init__(self, optimizer_path=None, ip=None, port=None):
# Check whether the optimizer was built with the current version of opengen
# We can only check the optimizer version if the optimizer runs locally
opengen_version = self.__optimizer_details['build']['opengen_version']
current_opengen_version = pkg_resources.require("opengen")[
0].version
current_opengen_version = version("opengen")
if current_opengen_version != opengen_version:
logging.warn(
'the target optimizer was build with a different version of opengen (%s)' % opengen_version)
Expand Down
7 changes: 7 additions & 0 deletions open-codegen/test/test_raspberry_pi.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
import opengen as og
import unittest
import casadi.casadi as cs
Expand All @@ -7,6 +8,11 @@

class RaspberryPiTest(unittest.TestCase):

@staticmethod
def get_open_local_absolute_path():
cwd = os.getcwd()
return cwd.split('open-codegen')[0]

# -----------------------------------------------------------------------
# Cross-compile to Raspberry Pi
# -----------------------------------------------------------------------
Expand All @@ -25,6 +31,7 @@ def test_compile_rpi(self):
meta = og.config.OptimizerMeta()\
.with_optimizer_name(optimizer_name)
build_config = og.config.BuildConfiguration() \
.with_open_version(local_path=RaspberryPiTest.get_open_local_absolute_path()) \
.with_build_directory(optimizers_dir) \
.with_build_mode(og.config.BuildConfiguration.DEBUG_MODE) \
.with_tcp_interface_config() \
Expand Down
6 changes: 3 additions & 3 deletions src/alm/alm_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl AlmCache {
/// # Arguments
///
/// - `panoc_cache`: an instance of `PANOCCache` that will be used by
/// the inner problem
/// the inner problem
/// - `n1`, `n2`: range dimensions of mappings `F1` and `F2` respectively
///
/// # Panics
Expand All @@ -77,9 +77,9 @@ impl AlmCache {
w_pm: if n2 > 0 { Some(vec![0.0; n2]) } else { None },
iteration: 0,
delta_y_norm: 0.0,
delta_y_norm_plus: std::f64::INFINITY,
delta_y_norm_plus: f64::INFINITY,
f2_norm: 0.0,
f2_norm_plus: std::f64::INFINITY,
f2_norm_plus: f64::INFINITY,
inner_iteration_count: 0,
last_inner_problem_norm_fpr: -1.0,
available_time: None,
Expand Down
14 changes: 7 additions & 7 deletions src/alm/alm_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
/// # Types
///
/// - `Cost`: cost function $f:\mathbb{R}^{n_u} \to \mathbb{R}$ which is computed
/// by a function with signature:
/// by a function with signature:
///
///```rust,ignore
///fn f(u: &[f64], cost: &mut f64) -> FunctionCallResult
Expand All @@ -22,7 +22,7 @@
/// where `cost` is updated with the value $f(u)$,
///
/// - `CostGradient`: gradient of the cost function, $\nabla f: \mathbb{R}^{n_u} \to \mathbb{R}^{n_u}$,
/// which is computed by a function with signature
/// which is computed by a function with signature
///
/// ```rust,ignore
/// fn df(u: &[f64], grad: &mut [f64]) -> FunctionCallResult
Expand All @@ -31,19 +31,19 @@
/// where on exit `grad` stores the
///
/// - `MappingF1` and `MappingF2`: mappings $F_1:\mathbb{R}^n\to\mathbb{R}^{n_1}$
/// and $F_2:\mathbb{R}^n\to\mathbb{R}^{n_2}$ which
/// are computed by functions with signature
/// and $F_2:\mathbb{R}^n\to\mathbb{R}^{n_2}$ which are computed by functions
/// with signature
///
/// ```rust,ignore
/// fn mapping(u: &[f64], fu: &mut [f64]) -> FunctionCallResult
/// ```
///
/// - `JacobianMappingF1Trans` and `JacobianMappingF2Trans`: functions that compute
/// product of the form $JF_i(u)^\top{}d$ for given $d\in\mathbb{R}^{n_i}$ and
/// $u\in\mathbb{R}^{n_u}$
/// product of the form $JF_i(u)^\top{}d$ for given $d\in\mathbb{R}^{n_i}$ and
/// $u\in\mathbb{R}^{n_u}$
///
/// - `SetC`: A set $C\subseteq \mathbb{R}^{n_1}$, which is used in the definition
/// of the constraints $F_1(u) \in C$
/// of the constraints $F_1(u) \in C$
///
/// The above are used to compute $\psi:\mathbb{R}^{n_u}\to\mathbb{R}$ for given
/// $u\in\mathbb{R}^{n_u}$ and $\xi=(c, y)\in\mathbb{R}^{n_1+1}$, where $c\in\mathbb{R}$
Expand Down Expand Up @@ -155,16 +155,16 @@
/// );
/// ```
///
pub fn new(
f: Cost,
df: CostGradient,
mapping_f1: Option<MappingF1>,
jacobian_mapping_f1_trans: Option<JacobianMappingF1Trans>,
mapping_f2: Option<MappingF2>,
jacobian_mapping_f2_trans: Option<JacobianMappingF2Trans>,
set_c: Option<SetC>,
n2: usize,
) -> Self {

Check warning on line 167 in src/alm/alm_factory.rs

View workflow job for this annotation

GitHub Actions / clippy

this function has too many arguments (8/7)

warning: this function has too many arguments (8/7) --> src/alm/alm_factory.rs:158:5 | 158 | / pub fn new( 159 | | f: Cost, 160 | | df: CostGradient, 161 | | mapping_f1: Option<MappingF1>, ... | 166 | | n2: usize, 167 | | ) -> Self { | |_____________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.94.0/index.html#too_many_arguments = note: `#[warn(clippy::too_many_arguments)]` on by default
assert!(
!(mapping_f2.is_none() ^ (n2 == 0)),
"if n2 > 0 then and only then should you provide an F2"
Expand Down
20 changes: 10 additions & 10 deletions src/alm/alm_optimizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const DEFAULT_PENALTY_UPDATE_FACTOR: f64 = 5.0;
const DEFAULT_EPSILON_UPDATE_FACTOR: f64 = 0.1;
const DEFAULT_INFEAS_SUFFICIENT_DECREASE_FACTOR: f64 = 0.1;
const DEFAULT_INITIAL_TOLERANCE: f64 = 0.1;
const SMALL_EPSILON: f64 = std::f64::EPSILON;
const SMALL_EPSILON: f64 = f64::EPSILON;

/// Internal/private structure used by method AlmOptimizer.step
/// to return some minimal information about the inner problem
Expand Down Expand Up @@ -81,8 +81,8 @@ impl InnerProblemStatus {
/// - For $\nu=0,\ldots, \nu_{\max}$
/// - $y \gets \Pi_Y(y)$
/// - $u \gets \arg\min_{u\in U} \psi(u, \xi)$, where $\psi(u, \xi)$ is a given function: this problem is
/// solved with tolerance $\bar\epsilon$
/// (see [`AlmFactory`](./struct.AlmFactory.html) regarding how this is constructed)
/// solved with tolerance $\bar\epsilon$
/// (see [`AlmFactory`](./struct.AlmFactory.html) regarding how this is constructed)
/// - $y^+ \gets y + c(F_1(u) - \Pi_C(F_1(u) + y/c))$
/// - Define $z^+ \gets \Vert y^+ - y \Vert$ and $t^+ = \Vert F_2(u) \Vert$
/// - If $z^+ \leq c\delta$, $t^+ \leq \delta$ and $\epsilon_\nu \leq \epsilon$, return $(u, y^+)$
Expand Down Expand Up @@ -205,10 +205,10 @@ where
/// # Arguments
///
/// - `alm_cache`: a reuseable instance of [`AlmCache`](./struct.AlmCache.html), which is borrowed by
/// `AlmOptimizer`
/// `AlmOptimizer`
/// - `alm_problem`: the problem specification (data for $\psi(u, \xi)$,
/// $\nabla_u \psi(u, \xi)$, $F_1(u)$ (if any), $F_2(u)$ (if any), and sets
/// $C$, $U$ and $Y$)
/// $\nabla_u \psi(u, \xi)$, $F_1(u)$ (if any), $F_2(u)$ (if any), and sets
/// $C$, $U$ and $Y$)
///
///
/// # Example
Expand Down Expand Up @@ -467,7 +467,7 @@ where
/// # Arguments
///
/// - `initial_inner_tolerance`: the initial value of the inner tolerance, that is,
/// the value $\espilon_0$
/// the value $\espilon_0$
///
/// # Returns
///
Expand Down Expand Up @@ -530,7 +530,7 @@ where
/// # Arguments
///
/// - `y_init`: initial vector of Lagrange multipliers (type: `&[f64]`) of
/// length equal to `n1`
/// length equal to `n1`
///
/// # Returns
///
Expand Down Expand Up @@ -732,7 +732,7 @@ where
.with_max_duration(
alm_cache
.available_time
.unwrap_or_else(|| std::time::Duration::from_secs(std::u64::MAX)),
.unwrap_or_else(|| std::time::Duration::from_secs(u64::MAX)),
)
// Set the maximum number of inner iterations
.with_max_iter(self.max_inner_iterations);
Expand Down Expand Up @@ -1059,7 +1059,7 @@ mod tests {

// Test: the initial value of the penalty parameter is positive
if let Some(xi) = &alm_optimizer.alm_cache.xi {
assert!(xi[0] > std::f64::EPSILON);
assert!(xi[0] > f64::EPSILON);
}

// Test: with_initial_penalty
Expand Down
4 changes: 2 additions & 2 deletions src/alm/alm_optimizer_status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub struct AlmOptimizerStatus {
num_inner_iterations: usize,
/// Norm of the fixed-point residual of the the problem
last_problem_norm_fpr: f64,
///
/// Lagrange multipliers vector
lagrange_multipliers: Option<Vec<f64>>,
/// Total solve time
solve_time: std::time::Duration,
Expand Down Expand Up @@ -122,7 +122,7 @@ impl AlmOptimizerStatus {
/// # Arguments
///
/// - `lagrange_multipliers`: vector of Lagrange multipliers (which is copied
/// into an internal field of `AlmOptimizerStatus`)
/// into an internal field of `AlmOptimizerStatus`)
///
/// # Panics
///
Expand Down
2 changes: 1 addition & 1 deletion src/alm/alm_problem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
/// - `constraints`: hard constraints, set $U$
/// - `alm_set_c`: Set $C$ of ALM-specific constraints (convex, closed)
/// - `alm_set_y`: Compact, convex set $Y$ of Lagrange multipliers, which needs to be a
/// compact subset of $C^*$ (the convex conjugate of the convex set $C{}\subseteq{}\mathbb{R}^{n_1}$)
/// compact subset of $C^*$ (the convex conjugate of the convex set $C{}\subseteq{}\mathbb{R}^{n_1}$)
/// - `parametric_cost`: Parametric cost function, $\psi(u, \xi)$, where $\xi = (c, y)$
/// - `parametric_gradient`: Gradient of cost function wrt $u$, that is $\nabla_x \psi(u, \xi)$
/// - `mapping_f1`: Mapping `F1` of ALM-specific constraints ($F1(u) \in C$)
Expand Down Expand Up @@ -132,17 +132,17 @@
/// );
/// ```
///
pub fn new(
constraints: ConstraintsType,
alm_set_c: Option<AlmSetC>,
alm_set_y: Option<LagrangeSetY>,
parametric_cost: ParametricCostType,
parametric_gradient: ParametricGradientType,
mapping_f1: Option<MappingAlm>,
mapping_f2: Option<MappingPm>,
n1: usize,
n2: usize,
) -> Self {

Check warning on line 145 in src/alm/alm_problem.rs

View workflow job for this annotation

GitHub Actions / clippy

this function has too many arguments (9/7)

warning: this function has too many arguments (9/7) --> src/alm/alm_problem.rs:135:5 | 135 | / pub fn new( 136 | | constraints: ConstraintsType, 137 | | alm_set_c: Option<AlmSetC>, 138 | | alm_set_y: Option<LagrangeSetY>, ... | 144 | | n2: usize, 145 | | ) -> Self { | |_____________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.94.0/index.html#too_many_arguments
// if one of `mapping_f1` and `alm_set_c` is provided, the other one
// should be provided as well (it's ok for both to be None)
assert!(
Expand Down
Loading
Loading