From adbbf5e32537f588d2354ec8ee78e9400ae5b9dd Mon Sep 17 00:00:00 2001
From: Pantelis Sopasakis
Date: Mon, 30 Oct 2023 17:36:19 +0000
Subject: [PATCH 01/13] EpigraphSquaredNorm: first untested implementation
---
Cargo.toml | 1 +
src/constraints/epigraph_squared_norm.rs | 56 ++++++++++++++++++++++++
src/constraints/mod.rs | 2 +
src/constraints/tests.rs | 8 ++++
4 files changed, 67 insertions(+)
create mode 100644 src/constraints/epigraph_squared_norm.rs
diff --git a/Cargo.toml b/Cargo.toml
index e130711f..4fcbbf8f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -99,6 +99,7 @@ rpmalloc = { version = "0.2.0", features = [
[target.'cfg(not(target_env = "msvc"))'.dependencies]
jemallocator = { version = "0.5.0", optional = true }
+roots = "0.0.8"
# --------------------------------------------------------------------------
# F.E.A.T.U.R.E.S.
diff --git a/src/constraints/epigraph_squared_norm.rs b/src/constraints/epigraph_squared_norm.rs
new file mode 100644
index 00000000..fbb09626
--- /dev/null
+++ b/src/constraints/epigraph_squared_norm.rs
@@ -0,0 +1,56 @@
+use crate::matrix_operations;
+
+use super::Constraint;
+
+#[derive(Copy, Clone)]
+/// A
+pub struct EpigraphSquaredNorm {}
+
+impl EpigraphSquaredNorm {
+ /// A
+ pub fn new() -> Self {
+ EpigraphSquaredNorm {}
+ }
+}
+
+impl Constraint for EpigraphSquaredNorm {
+ fn project(&self, x: &mut [f64]) {
+ let nx = x.len() - 1;
+ let z: &[f64] = &x[..nx];
+ let t: f64 = x[nx];
+ let norm_z_sq = matrix_operations::norm2_squared(&z);
+ if norm_z_sq <= t {
+ return;
+ }
+ let theta = 1. - 2. * t;
+ let a0 = 1.;
+ let a1 = theta;
+ let a2 = 0.25 * theta * theta;
+ let a3 = -0.25 * norm_z_sq;
+
+ let cubic_poly_roots = roots::find_roots_cubic(a3, a2, a1, a0);
+ let mut right_root = f64::NAN;
+ let mut scaling = f64::NAN;
+
+ // Find right root
+ cubic_poly_roots.as_ref().iter().for_each(|ri| {
+ if *ri > 0. {
+ let denom = 1. + 2. * (*ri - t);
+ if ((norm_z_sq / (denom * denom)) - *ri) < 1e-6f64 {
+ right_root = *ri;
+ scaling = denom;
+ }
+ return;
+ }
+ });
+
+ // Project
+ x.iter_mut().for_each(|xi| {
+ *xi /= scaling;
+ });
+ }
+
+ fn is_convex(&self) -> bool {
+ true
+ }
+}
diff --git a/src/constraints/mod.rs b/src/constraints/mod.rs
index ea8895da..66ac7b33 100644
--- a/src/constraints/mod.rs
+++ b/src/constraints/mod.rs
@@ -12,6 +12,7 @@ mod ball1;
mod ball2;
mod ballinf;
mod cartesian_product;
+mod epigraph_squared_norm;
mod finite;
mod halfspace;
mod hyperplane;
@@ -26,6 +27,7 @@ pub use ball1::Ball1;
pub use ball2::Ball2;
pub use ballinf::BallInf;
pub use cartesian_product::CartesianProduct;
+pub use epigraph_squared_norm::EpigraphSquaredNorm;
pub use finite::FiniteSet;
pub use halfspace::Halfspace;
pub use hyperplane::Hyperplane;
diff --git a/src/constraints/tests.rs b/src/constraints/tests.rs
index a09b3c16..5e9216d8 100644
--- a/src/constraints/tests.rs
+++ b/src/constraints/tests.rs
@@ -872,3 +872,11 @@ fn t_sphere2_center_projection_of_center() {
fn t_ball1_alpha_negative() {
let _ = Ball1::new(None, -1.);
}
+
+#[test]
+fn t_cubic_roots() {
+ let epi = EpigraphSquaredNorm::new();
+ let mut x = [1., 2., 3., 4.];
+ epi.project(&mut x);
+ println!("x = {:?}", x);
+}
From 3ec808b9258c94299080faf3b66d6a9e32c7a22b Mon Sep 17 00:00:00 2001
From: Pantelis Sopasakis
Date: Mon, 30 Oct 2023 17:54:23 +0000
Subject: [PATCH 02/13] EpigraphSquaredNorm: tested
---
src/constraints/epigraph_squared_norm.rs | 22 +++++++++++++---------
src/constraints/tests.rs | 12 +++++++++---
2 files changed, 22 insertions(+), 12 deletions(-)
diff --git a/src/constraints/epigraph_squared_norm.rs b/src/constraints/epigraph_squared_norm.rs
index fbb09626..a60ac473 100644
--- a/src/constraints/epigraph_squared_norm.rs
+++ b/src/constraints/epigraph_squared_norm.rs
@@ -22,11 +22,12 @@ impl Constraint for EpigraphSquaredNorm {
if norm_z_sq <= t {
return;
}
+
let theta = 1. - 2. * t;
- let a0 = 1.;
- let a1 = theta;
- let a2 = 0.25 * theta * theta;
- let a3 = -0.25 * norm_z_sq;
+ let a3 = 4.;
+ let a2 = 4. * theta;
+ let a1 = theta * theta;
+ let a0 = -norm_z_sq;
let cubic_poly_roots = roots::find_roots_cubic(a3, a2, a1, a0);
let mut right_root = f64::NAN;
@@ -36,7 +37,7 @@ impl Constraint for EpigraphSquaredNorm {
cubic_poly_roots.as_ref().iter().for_each(|ri| {
if *ri > 0. {
let denom = 1. + 2. * (*ri - t);
- if ((norm_z_sq / (denom * denom)) - *ri) < 1e-6f64 {
+ if ((norm_z_sq / (denom * denom)) - *ri).abs() < 1e-6 {
right_root = *ri;
scaling = denom;
}
@@ -44,10 +45,13 @@ impl Constraint for EpigraphSquaredNorm {
}
});
- // Project
- x.iter_mut().for_each(|xi| {
- *xi /= scaling;
- });
+ // TODO: refinement of root
+
+ // Projection
+ for i in 0..nx {
+ x[i] /= scaling;
+ }
+ x[nx] = right_root;
}
fn is_convex(&self) -> bool {
diff --git a/src/constraints/tests.rs b/src/constraints/tests.rs
index 5e9216d8..77956722 100644
--- a/src/constraints/tests.rs
+++ b/src/constraints/tests.rs
@@ -1,3 +1,5 @@
+use crate::matrix_operations;
+
use super::*;
use rand;
@@ -876,7 +878,11 @@ fn t_ball1_alpha_negative() {
#[test]
fn t_cubic_roots() {
let epi = EpigraphSquaredNorm::new();
- let mut x = [1., 2., 3., 4.];
- epi.project(&mut x);
- println!("x = {:?}", x);
+ for i in 0..100 {
+ let t = 0.01 * i as f64;
+ let mut x = [1., 2., 3., t];
+ epi.project(&mut x);
+ let err = (matrix_operations::norm2_squared(&x[..3]) - x[3]).abs();
+ assert!(err < 1e-10, "wrong projection on epigraph of squared norm");
+ }
}
From 2bb00cc81581211957858fd409b25f07fd08727c Mon Sep 17 00:00:00 2001
From: Pantelis Sopasakis
Date: Mon, 30 Oct 2023 18:32:47 +0000
Subject: [PATCH 03/13] EpigraphSquaredNorm: refinement of root
---
src/constraints/epigraph_squared_norm.rs | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/src/constraints/epigraph_squared_norm.rs b/src/constraints/epigraph_squared_norm.rs
index a60ac473..bac317e4 100644
--- a/src/constraints/epigraph_squared_norm.rs
+++ b/src/constraints/epigraph_squared_norm.rs
@@ -45,7 +45,22 @@ impl Constraint for EpigraphSquaredNorm {
}
});
- // TODO: refinement of root
+ // Refinement of root with Newton-Raphson
+ let mut refinement_error = 1.;
+ let newton_max_iters: usize = 5;
+ let newton_eps = 1e-14;
+ let mut zsol = right_root;
+ let mut iter = 0;
+ while refinement_error > newton_eps && iter < newton_max_iters {
+ let zsol_sq = zsol * zsol;
+ let zsol_cb = zsol_sq * zsol;
+ let p_z = a3 * zsol_cb + a2 * zsol_sq + a1 * zsol + a0;
+ let dp_z = 3. * a3 * zsol_sq + 2. * a2 * zsol + a1;
+ zsol = zsol - p_z / dp_z;
+ refinement_error = p_z.abs();
+ iter += 1;
+ }
+ right_root = zsol;
// Projection
for i in 0..nx {
From 78802a9c79990b16efcd2ae5cee509eee8fa6b43 Mon Sep 17 00:00:00 2001
From: Pantelis Sopasakis
Date: Mon, 30 Oct 2023 18:57:09 +0000
Subject: [PATCH 04/13] EpigraphSquaredNorm: more tests
---
appveyor.yml | 1 +
src/constraints/tests.rs | 37 ++++++++++++++++++++++++++++++++++++-
2 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/appveyor.yml b/appveyor.yml
index 614b3b7e..066a1956 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -68,4 +68,5 @@ build: false
#directly or perform other testing commands. Rust will automatically be placed in the PATH
# environment variable.
test_script:
+ - cargo build
- cargo test --verbose %cargoflags%
diff --git a/src/constraints/tests.rs b/src/constraints/tests.rs
index 77956722..d0cf1d0b 100644
--- a/src/constraints/tests.rs
+++ b/src/constraints/tests.rs
@@ -876,7 +876,22 @@ fn t_ball1_alpha_negative() {
}
#[test]
-fn t_cubic_roots() {
+fn t_epigraph_squared_norm_inside() {
+ let epi = EpigraphSquaredNorm::new();
+ let mut x = [1., 2., 10.];
+ let x_correct = x.clone();
+ epi.project(&mut x);
+ unit_test_utils::assert_nearly_equal_array(
+ &x_correct,
+ &x,
+ 1e-12,
+ 1e-14,
+ "wrong projection on epigraph of squared norm",
+ );
+}
+
+#[test]
+fn t_epigraph_squared_norm() {
let epi = EpigraphSquaredNorm::new();
for i in 0..100 {
let t = 0.01 * i as f64;
@@ -886,3 +901,23 @@ fn t_cubic_roots() {
assert!(err < 1e-10, "wrong projection on epigraph of squared norm");
}
}
+
+#[test]
+fn t_epigraph_squared_norm_correctness() {
+ let epi = EpigraphSquaredNorm::new();
+ let mut x = [1., 2., 3., 4.];
+ let x_correct = [
+ 0.560142228903570,
+ 1.120284457807140,
+ 1.680426686710711,
+ 4.392630432414829,
+ ];
+ epi.project(&mut x);
+ unit_test_utils::assert_nearly_equal_array(
+ &x_correct,
+ &x,
+ 1e-12,
+ 1e-14,
+ "wrong projection on epigraph of squared norm",
+ );
+}
From 89e72f63bebd0e495163bbf08996bee6450007ad Mon Sep 17 00:00:00 2001
From: Pantelis Sopasakis
Date: Mon, 30 Oct 2023 19:11:49 +0000
Subject: [PATCH 05/13] fighting with appveyor
---
appveyor.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/appveyor.yml b/appveyor.yml
index 066a1956..20bd0b3d 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -68,5 +68,6 @@ build: false
#directly or perform other testing commands. Rust will automatically be placed in the PATH
# environment variable.
test_script:
+ - cargo add roots
- cargo build
- cargo test --verbose %cargoflags%
From 036784e009105a8b7202d92e4b7afbcef4e68f03 Mon Sep 17 00:00:00 2001
From: Pantelis Sopasakis
Date: Mon, 30 Oct 2023 22:32:00 +0000
Subject: [PATCH 06/13] [ci-skip] add documentation
---
Cargo.toml | 2 ++
src/constraints/epigraph_squared_norm.rs | 17 +++++++++++++++--
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index 4fcbbf8f..be7a64b8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -99,6 +99,8 @@ rpmalloc = { version = "0.2.0", features = [
[target.'cfg(not(target_env = "msvc"))'.dependencies]
jemallocator = { version = "0.5.0", optional = true }
+# computation of roots of cubic equation needed for the projection on the
+# epigraph of the squared Eucliean norm
roots = "0.0.8"
# --------------------------------------------------------------------------
diff --git a/src/constraints/epigraph_squared_norm.rs b/src/constraints/epigraph_squared_norm.rs
index bac317e4..3ab2bc7c 100644
--- a/src/constraints/epigraph_squared_norm.rs
+++ b/src/constraints/epigraph_squared_norm.rs
@@ -3,19 +3,31 @@ use crate::matrix_operations;
use super::Constraint;
#[derive(Copy, Clone)]
-/// A
+/// The epigraph of the squared Eucliden norm is a set of the form
+/// $X = \\{x = (z, t) \in \mathbb{R}^{n}\times \mathbb{R} {}:{} \\|z\\|^2 \leq t \\}.$
pub struct EpigraphSquaredNorm {}
impl EpigraphSquaredNorm {
- /// A
+ /// Create a new instance of the epigraph of the squared norm.
+ ///
+ /// Note that you do not need to specify the dimension.
pub fn new() -> Self {
EpigraphSquaredNorm {}
}
}
impl Constraint for EpigraphSquaredNorm {
+ ///Project on the epigraph of the squared Euclidean norm.
+ ///
+ /// The projection is computed as detailed
+ /// [here](https://mathematix.wordpress.com/2017/05/02/projection-on-the-epigraph-of-the-squared-euclidean-norm/).
+ ///
+ /// ## Arguments
+ /// - `x`: The given vector $x$ is updated with the projection on the set
+ ///
fn project(&self, x: &mut [f64]) {
let nx = x.len() - 1;
+ assert!(nx > 0, "x must have a length of at least 2");
let z: &[f64] = &x[..nx];
let t: f64 = x[nx];
let norm_z_sq = matrix_operations::norm2_squared(&z);
@@ -69,6 +81,7 @@ impl Constraint for EpigraphSquaredNorm {
x[nx] = right_root;
}
+ /// This is a convex set, so this function returns `True`
fn is_convex(&self) -> bool {
true
}
From e2a6b7b4c34cb9ef1ba94a077227b2fc93c1c071 Mon Sep 17 00:00:00 2001
From: Pantelis Sopasakis
Date: Mon, 30 Oct 2023 22:34:02 +0000
Subject: [PATCH 07/13] [ci-skip] update changelog
---
CHANGELOG.md | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 54b22078..64ac85cf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,7 +10,11 @@ Note: This is the main Changelog file for the Rust solver. The Changelog file fo
-## Unreleased
+## [v0.9.0] - Unreleased
+
+### Added
+
+- Rust implementation of epigraph of squared Euclidean norm (constraint)
### Fixed
@@ -275,6 +279,7 @@ This is a breaking API change.
--------------------- -->
+[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
[v0.8.0]: https://github.com/alphaville/optimization-engine/compare/v0.7.7...v0.8.0
[v0.7.7]: https://github.com/alphaville/optimization-engine/compare/v0.7.6...v0.7.7
From b8eaeea72c923c5f557c63717bf57ca897926093 Mon Sep 17 00:00:00 2001
From: Pantelis Sopasakis
Date: Mon, 30 Oct 2023 22:35:14 +0000
Subject: [PATCH 08/13] [ci skip] update Cargo
---
Cargo.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Cargo.toml b/Cargo.toml
index be7a64b8..963f797b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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.8.1"
+version = "0.9.0"
edition = "2018"
From 29c125721e54be08a3b837f3f09891df22ca3a0a Mon Sep 17 00:00:00 2001
From: Pantelis Sopasakis
Date: Tue, 31 Oct 2023 01:20:03 +0000
Subject: [PATCH 09/13] [ci skip] epigraph sq norm: API docs
---
src/constraints/epigraph_squared_norm.rs | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/constraints/epigraph_squared_norm.rs b/src/constraints/epigraph_squared_norm.rs
index 3ab2bc7c..e8d128d5 100644
--- a/src/constraints/epigraph_squared_norm.rs
+++ b/src/constraints/epigraph_squared_norm.rs
@@ -25,6 +25,15 @@ impl Constraint for EpigraphSquaredNorm {
/// ## Arguments
/// - `x`: The given vector $x$ is updated with the projection on the set
///
+ /// ## Example
+ ///
+ /// ```rust
+ /// use optimization_engine::constraints::*;
+ ///
+ /// let epi = EpigraphSquaredNorm::new();
+ /// let mut x = [1., 2., 3., 4.];
+ /// epi.project(&mut x);
+ /// ```
fn project(&self, x: &mut [f64]) {
let nx = x.len() - 1;
assert!(nx > 0, "x must have a length of at least 2");
From 1d19ab304f7180d9d7ceed851b8d47dc4b73fde7 Mon Sep 17 00:00:00 2001
From: Pantelis Sopasakis
Date: Wed, 20 Mar 2024 13:49:04 +0000
Subject: [PATCH 10/13] merge master; fix clippy issues; fix typo in Cargo
---
Cargo.toml | 2 +-
src/constraints/epigraph_squared_norm.rs | 11 +++++------
src/constraints/tests.rs | 3 ++-
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index d4ca6231..c0e43aa9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -101,7 +101,7 @@ jemallocator = { version = "0.5.0", optional = true }
# computation of roots of cubic equation needed for the projection on the
-# epigraph of the squared Eucliean norm
+# epigraph of the squared Euclidean norm
roots = "0.0.8"
# Least squares solver
diff --git a/src/constraints/epigraph_squared_norm.rs b/src/constraints/epigraph_squared_norm.rs
index e8d128d5..560b34bd 100644
--- a/src/constraints/epigraph_squared_norm.rs
+++ b/src/constraints/epigraph_squared_norm.rs
@@ -2,7 +2,7 @@ use crate::matrix_operations;
use super::Constraint;
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Default)]
/// The epigraph of the squared Eucliden norm is a set of the form
/// $X = \\{x = (z, t) \in \mathbb{R}^{n}\times \mathbb{R} {}:{} \\|z\\|^2 \leq t \\}.$
pub struct EpigraphSquaredNorm {}
@@ -39,7 +39,7 @@ impl Constraint for EpigraphSquaredNorm {
assert!(nx > 0, "x must have a length of at least 2");
let z: &[f64] = &x[..nx];
let t: f64 = x[nx];
- let norm_z_sq = matrix_operations::norm2_squared(&z);
+ let norm_z_sq = matrix_operations::norm2_squared(z);
if norm_z_sq <= t {
return;
}
@@ -62,7 +62,6 @@ impl Constraint for EpigraphSquaredNorm {
right_root = *ri;
scaling = denom;
}
- return;
}
});
@@ -77,15 +76,15 @@ impl Constraint for EpigraphSquaredNorm {
let zsol_cb = zsol_sq * zsol;
let p_z = a3 * zsol_cb + a2 * zsol_sq + a1 * zsol + a0;
let dp_z = 3. * a3 * zsol_sq + 2. * a2 * zsol + a1;
- zsol = zsol - p_z / dp_z;
+ zsol -= p_z / dp_z;
refinement_error = p_z.abs();
iter += 1;
}
right_root = zsol;
// Projection
- for i in 0..nx {
- x[i] /= scaling;
+ for xi in x.iter_mut().take(nx) {
+ *xi /= scaling;
}
x[nx] = right_root;
}
diff --git a/src/constraints/tests.rs b/src/constraints/tests.rs
index 1533ec55..26343688 100644
--- a/src/constraints/tests.rs
+++ b/src/constraints/tests.rs
@@ -1,7 +1,6 @@
use crate::matrix_operations;
use super::*;
-use modcholesky::ModCholeskySE99;
use rand;
#[test]
@@ -922,6 +921,8 @@ fn t_epigraph_squared_norm_correctness() {
"wrong projection on epigraph of squared norm",
);
}
+
+#[test]
fn t_affine_space() {
let a = vec![
0.5, 0.1, 0.2, -0.3, -0.6, 0.3, 0., 0.5, 1.0, 0.1, -1.0, -0.4,
From 5c98f5ff9b92e8842340d451fadb5c47b6fa0b50 Mon Sep 17 00:00:00 2001
From: Pantelis Sopasakis
Date: Wed, 20 Mar 2024 14:09:48 +0000
Subject: [PATCH 11/13] update dependencies in Cargo.toml
---
Cargo.toml | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index c0e43aa9..ae50f398 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -77,7 +77,7 @@ rustdoc-args = ["--html-in-header", "katex-header.html"]
# D.E.P.E.N.D.E.N.C.I.E.S
# --------------------------------------------------------------------------
[dependencies]
-num = "0.4.0"
+num = "0.4"
# Our own stuff - L-BFGS: limited-memory BFGS directions
lbfgs = "0.2"
@@ -86,10 +86,10 @@ lbfgs = "0.2"
instant = { version = "0.1" }
# Wasm-bindgen is only activated if OpEn is compiled with `--features wasm`
-wasm-bindgen = { version = "0.2.74", optional = true }
+wasm-bindgen = { version = "0.2", optional = true }
# sc-allocator provides an implementation of a bump allocator
-rpmalloc = { version = "0.2.0", features = [
+rpmalloc = { version = "0.2", features = [
"guards",
"statistics",
], optional = true }
@@ -97,7 +97,7 @@ rpmalloc = { version = "0.2.0", features = [
# 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`)
[target.'cfg(not(target_env = "msvc"))'.dependencies]
-jemallocator = { version = "0.5.0", optional = true }
+jemallocator = { version = "0.5", optional = true }
# computation of roots of cubic equation needed for the projection on the
@@ -106,7 +106,7 @@ roots = "0.0.8"
# Least squares solver
ndarray = { version = "0.15", features = ["approx"] }
-modcholesky = "0.1.3"
+modcholesky = "0.1"
# --------------------------------------------------------------------------
From 55188a8327601b16d101a4458e12e686fddf36d8 Mon Sep 17 00:00:00 2001
From: Pantelis Sopasakis
Date: Wed, 20 Mar 2024 14:18:45 +0000
Subject: [PATCH 12/13] [ci skip] update webside docs for EpigraphSquaredNorm
---
docs/python-interface.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/docs/python-interface.md b/docs/python-interface.md
index a332ea29..77983d8a 100644
--- a/docs/python-interface.md
+++ b/docs/python-interface.md
@@ -87,6 +87,7 @@ following types of constraints:
| `NoConstraints` | No constraints - the whole $\mathbb{R}^{n}$|
| `Rectangle` | Rectangle, $$R = \\{u \in \mathbb{R}^{n_u} {}:{} f_{\min} \leq u \leq f_{\max}\\},$$ for example, `Rectangle(fmin, fmax)` |
| `SecondOrderCone` | Second-order aka "ice cream" aka "Lorenz" cone |
+| `EpigraphSquaredNorm`| The epigraph of the squared Eucliden norm is a set of the form $X = \\{(z, t) \in \mathbb{R}^{n+1}: \Vert z \Vert \leq t\\}$. |
| `CartesianProduct` | Cartesian product of any of the above. See more information below. |
From ad45f27bbd1379a9f26add188a39c38230108042 Mon Sep 17 00:00:00 2001
From: Pantelis Sopasakis
Date: Wed, 20 Mar 2024 14:20:25 +0000
Subject: [PATCH 13/13] update main changelog (v0.9.0)
---
CHANGELOG.md | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c8fa985d..076bda35 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,10 +7,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
Note: This is the main Changelog file for the Rust solver. The Changelog file for the Python interface (`opengen`) can be found in [/open-codegen/CHANGELOG.md](open-codegen/CHANGELOG.md)
+
+
+
+
-## [v0.9.0] - Unreleased
+## [v0.9.0] - 2024-03-20
### Added