use ripopt::NlpProblem;
use std::f64::consts::PI;
pub struct ChainedRosenbrock {
pub n: usize,
}
impl NlpProblem for ChainedRosenbrock {
fn num_variables(&self) -> usize {
self.n
}
fn num_constraints(&self) -> usize {
0
}
fn bounds(&self, x_l: &mut [f64], x_u: &mut [f64]) {
for i in 0..self.n {
x_l[i] = f64::NEG_INFINITY;
x_u[i] = f64::INFINITY;
}
}
fn constraint_bounds(&self, _g_l: &mut [f64], _g_u: &mut [f64]) {}
fn initial_point(&self, x0: &mut [f64]) {
for i in 0..self.n {
x0[i] = -1.2;
}
}
fn objective(&self, x: &[f64]) -> f64 {
let mut f = 0.0;
for i in 0..self.n - 1 {
let a = 1.0 - x[i];
let b = x[i + 1] - x[i] * x[i];
f += a * a + 100.0 * b * b;
}
f
}
fn gradient(&self, x: &[f64], grad: &mut [f64]) {
let n = self.n;
for g in grad.iter_mut() {
*g = 0.0;
}
for i in 0..n - 1 {
let xi = x[i];
let xi1 = x[i + 1];
let r = xi1 - xi * xi;
grad[i] += -2.0 * (1.0 - xi) + 200.0 * r * (-2.0 * xi);
grad[i + 1] += 200.0 * r;
}
}
fn constraints(&self, _x: &[f64], _g: &mut [f64]) {}
fn jacobian_structure(&self) -> (Vec<usize>, Vec<usize>) {
(vec![], vec![])
}
fn jacobian_values(&self, _x: &[f64], _vals: &mut [f64]) {}
fn hessian_structure(&self) -> (Vec<usize>, Vec<usize>) {
let n = self.n;
let nnz = 2 * n - 1;
let mut rows = Vec::with_capacity(nnz);
let mut cols = Vec::with_capacity(nnz);
rows.push(0);
cols.push(0);
for i in 1..n {
rows.push(i);
cols.push(i - 1);
rows.push(i);
cols.push(i);
}
(rows, cols)
}
fn hessian_values(&self, x: &[f64], obj_factor: f64, _lambda: &[f64], vals: &mut [f64]) {
let n = self.n;
for v in vals.iter_mut() {
*v = 0.0;
}
for i in 0..n - 1 {
let xi = x[i];
let xi1 = x[i + 1];
let diag_i_idx = if i == 0 { 0 } else { 2 * i };
vals[diag_i_idx] += obj_factor * (2.0 + 1200.0 * xi * xi - 400.0 * xi1);
let sub_idx = 2 * (i + 1) - 1;
vals[sub_idx] += obj_factor * (-400.0 * xi);
let diag_i1_idx = 2 * (i + 1);
vals[diag_i1_idx] += obj_factor * 200.0;
}
}
}
pub struct BratuProblem {
pub n: usize,
lambda_bratu: f64,
h: f64,
}
impl BratuProblem {
pub fn new(n: usize) -> Self {
let h = 1.0 / (n as f64 + 1.0);
Self {
n,
lambda_bratu: 1.0,
h,
}
}
}
impl NlpProblem for BratuProblem {
fn num_variables(&self) -> usize {
self.n
}
fn num_constraints(&self) -> usize {
self.n - 2
}
fn bounds(&self, x_l: &mut [f64], x_u: &mut [f64]) {
for i in 0..self.n {
x_l[i] = f64::NEG_INFINITY;
x_u[i] = f64::INFINITY;
}
x_l[0] = 0.0;
x_u[0] = 0.0;
x_l[self.n - 1] = 0.0;
x_u[self.n - 1] = 0.0;
}
fn constraint_bounds(&self, g_l: &mut [f64], g_u: &mut [f64]) {
for j in 0..self.n - 2 {
g_l[j] = 0.0;
g_u[j] = 0.0;
}
}
fn initial_point(&self, x0: &mut [f64]) {
for i in 0..self.n {
x0[i] = 0.0;
}
}
fn objective(&self, _x: &[f64]) -> f64 {
0.0
}
fn gradient(&self, _x: &[f64], grad: &mut [f64]) {
for g in grad.iter_mut() {
*g = 0.0;
}
}
fn constraints(&self, x: &[f64], g: &mut [f64]) {
let h2 = self.h * self.h;
for j in 0..self.n - 2 {
let i = j + 1;
g[j] = (-x[i - 1] + 2.0 * x[i] - x[i + 1]) / h2
- self.lambda_bratu * x[i].exp();
}
}
fn jacobian_structure(&self) -> (Vec<usize>, Vec<usize>) {
let m = self.n - 2;
let mut rows = Vec::with_capacity(3 * m);
let mut cols = Vec::with_capacity(3 * m);
for j in 0..m {
let i = j + 1;
rows.push(j);
cols.push(i - 1);
rows.push(j);
cols.push(i);
rows.push(j);
cols.push(i + 1);
}
(rows, cols)
}
fn jacobian_values(&self, x: &[f64], vals: &mut [f64]) {
let h2 = self.h * self.h;
let m = self.n - 2;
for j in 0..m {
let i = j + 1;
let base = 3 * j;
vals[base] = -1.0 / h2; vals[base + 1] = 2.0 / h2 - self.lambda_bratu * x[i].exp(); vals[base + 2] = -1.0 / h2; }
}
fn hessian_structure(&self) -> (Vec<usize>, Vec<usize>) {
let mut rows = Vec::with_capacity(self.n);
let mut cols = Vec::with_capacity(self.n);
for k in 0..self.n {
rows.push(k);
cols.push(k);
}
(rows, cols)
}
fn hessian_values(&self, x: &[f64], _obj_factor: f64, lambda: &[f64], vals: &mut [f64]) {
for v in vals.iter_mut() {
*v = 0.0;
}
for j in 0..self.n - 2 {
let k = j + 1;
vals[k] += lambda[j] * (-self.lambda_bratu * x[k].exp());
}
}
}
pub struct OptimalControl {
t: usize, h: f64,
alpha: f64,
}
impl OptimalControl {
pub fn new(t: usize) -> Self {
Self {
t,
h: 1.0 / t as f64,
alpha: 0.01,
}
}
fn n(&self) -> usize {
2 * self.t + 1
}
}
impl NlpProblem for OptimalControl {
fn num_variables(&self) -> usize {
self.n()
}
fn num_constraints(&self) -> usize {
self.t + 1
}
fn bounds(&self, x_l: &mut [f64], x_u: &mut [f64]) {
let n = self.n();
for i in 0..n {
x_l[i] = f64::NEG_INFINITY;
x_u[i] = f64::INFINITY;
}
}
fn constraint_bounds(&self, g_l: &mut [f64], g_u: &mut [f64]) {
let m = self.t + 1;
for j in 0..m {
g_l[j] = 0.0;
g_u[j] = 0.0;
}
}
fn initial_point(&self, x0: &mut [f64]) {
for v in x0.iter_mut() {
*v = 0.0;
}
}
fn objective(&self, x: &[f64]) -> f64 {
let h = self.h;
let t = self.t;
let mut f = 0.0;
for i in 0..=t {
let dy = x[i] - 1.0;
f += h * dy * dy;
}
for i in 0..t {
let u = x[t + 1 + i];
f += self.alpha * h * u * u;
}
f
}
fn gradient(&self, x: &[f64], grad: &mut [f64]) {
let h = self.h;
let t = self.t;
for i in 0..=t {
grad[i] = 2.0 * h * (x[i] - 1.0);
}
for i in 0..t {
grad[t + 1 + i] = 2.0 * self.alpha * h * x[t + 1 + i];
}
}
fn constraints(&self, x: &[f64], g: &mut [f64]) {
let h = self.h;
let t = self.t;
g[0] = x[0];
for i in 0..t {
g[i + 1] = x[i + 1] - (1.0 - h) * x[i] - h * x[t + 1 + i];
}
}
fn jacobian_structure(&self) -> (Vec<usize>, Vec<usize>) {
let t = self.t;
let nnz = 1 + 3 * t;
let mut rows = Vec::with_capacity(nnz);
let mut cols = Vec::with_capacity(nnz);
rows.push(0);
cols.push(0);
for i in 0..t {
rows.push(i + 1);
cols.push(i);
rows.push(i + 1);
cols.push(i + 1);
rows.push(i + 1);
cols.push(t + 1 + i);
}
(rows, cols)
}
fn jacobian_values(&self, _x: &[f64], vals: &mut [f64]) {
let h = self.h;
let t = self.t;
vals[0] = 1.0; for i in 0..t {
let base = 1 + 3 * i;
vals[base] = -(1.0 - h); vals[base + 1] = 1.0; vals[base + 2] = -h; }
}
fn hessian_structure(&self) -> (Vec<usize>, Vec<usize>) {
let n = self.n();
let mut rows = Vec::with_capacity(n);
let mut cols = Vec::with_capacity(n);
for k in 0..n {
rows.push(k);
cols.push(k);
}
(rows, cols)
}
fn hessian_values(&self, _x: &[f64], obj_factor: f64, _lambda: &[f64], vals: &mut [f64]) {
let h = self.h;
let t = self.t;
for i in 0..=t {
vals[i] = obj_factor * 2.0 * h;
}
for i in 0..t {
vals[t + 1 + i] = obj_factor * 2.0 * self.alpha * h;
}
}
}
pub struct PoissonControl {
k: usize, h: f64,
alpha: f64,
}
impl PoissonControl {
pub fn new(k: usize) -> Self {
let h = 1.0 / (k as f64 + 1.0);
Self {
k,
h,
alpha: 0.01,
}
}
#[inline]
fn idx_u(&self, i: usize, j: usize) -> usize {
i + j * self.k
}
#[inline]
fn idx_f(&self, i: usize, j: usize) -> usize {
self.k * self.k + i + j * self.k
}
fn u_desired(&self, i: usize, j: usize) -> f64 {
let x = (i as f64 + 1.0) * self.h;
let y = (j as f64 + 1.0) * self.h;
(PI * x).sin() * (PI * y).sin()
}
}
impl NlpProblem for PoissonControl {
fn num_variables(&self) -> usize {
2 * self.k * self.k
}
fn num_constraints(&self) -> usize {
self.k * self.k
}
fn bounds(&self, x_l: &mut [f64], x_u: &mut [f64]) {
let n = self.num_variables();
for i in 0..n {
x_l[i] = f64::NEG_INFINITY;
x_u[i] = f64::INFINITY;
}
}
fn constraint_bounds(&self, g_l: &mut [f64], g_u: &mut [f64]) {
let m = self.num_constraints();
for j in 0..m {
g_l[j] = 0.0;
g_u[j] = 0.0;
}
}
fn initial_point(&self, x0: &mut [f64]) {
for v in x0.iter_mut() {
*v = 0.0;
}
}
fn objective(&self, x: &[f64]) -> f64 {
let k = self.k;
let h2 = self.h * self.h;
let mut f = 0.0;
for j in 0..k {
for i in 0..k {
let u = x[self.idx_u(i, j)];
let ud = self.u_desired(i, j);
f += 0.5 * h2 * (u - ud) * (u - ud);
let fi = x[self.idx_f(i, j)];
f += 0.5 * self.alpha * h2 * fi * fi;
}
}
f
}
fn gradient(&self, x: &[f64], grad: &mut [f64]) {
let k = self.k;
let h2 = self.h * self.h;
for v in grad.iter_mut() {
*v = 0.0;
}
for j in 0..k {
for i in 0..k {
let u = x[self.idx_u(i, j)];
let ud = self.u_desired(i, j);
grad[self.idx_u(i, j)] = h2 * (u - ud);
grad[self.idx_f(i, j)] = self.alpha * h2 * x[self.idx_f(i, j)];
}
}
}
fn constraints(&self, x: &[f64], g: &mut [f64]) {
let k = self.k;
let h2 = self.h * self.h;
for j in 0..k {
for i in 0..k {
let c = j * k + i; let center = x[self.idx_u(i, j)];
let mut laplacian = 4.0 * center;
if i > 0 {
laplacian -= x[self.idx_u(i - 1, j)];
}
if i < k - 1 {
laplacian -= x[self.idx_u(i + 1, j)];
}
if j > 0 {
laplacian -= x[self.idx_u(i, j - 1)];
}
if j < k - 1 {
laplacian -= x[self.idx_u(i, j + 1)];
}
g[c] = laplacian / h2 - x[self.idx_f(i, j)];
}
}
}
fn jacobian_structure(&self) -> (Vec<usize>, Vec<usize>) {
let k = self.k;
let mut rows = Vec::with_capacity(6 * k * k);
let mut cols = Vec::with_capacity(6 * k * k);
for j in 0..k {
for i in 0..k {
let c = j * k + i;
rows.push(c);
cols.push(self.idx_u(i, j));
if i > 0 {
rows.push(c);
cols.push(self.idx_u(i - 1, j));
}
if i < k - 1 {
rows.push(c);
cols.push(self.idx_u(i + 1, j));
}
if j > 0 {
rows.push(c);
cols.push(self.idx_u(i, j - 1));
}
if j < k - 1 {
rows.push(c);
cols.push(self.idx_u(i, j + 1));
}
rows.push(c);
cols.push(self.idx_f(i, j));
}
}
(rows, cols)
}
fn jacobian_values(&self, _x: &[f64], vals: &mut [f64]) {
let k = self.k;
let h2 = self.h * self.h;
let mut idx = 0;
for j in 0..k {
for i in 0..k {
vals[idx] = 4.0 / h2;
idx += 1;
if i > 0 {
vals[idx] = -1.0 / h2;
idx += 1;
}
if i < k - 1 {
vals[idx] = -1.0 / h2;
idx += 1;
}
if j > 0 {
vals[idx] = -1.0 / h2;
idx += 1;
}
if j < k - 1 {
vals[idx] = -1.0 / h2;
idx += 1;
}
vals[idx] = -1.0;
idx += 1;
}
}
}
fn hessian_structure(&self) -> (Vec<usize>, Vec<usize>) {
let n = self.num_variables();
let mut rows = Vec::with_capacity(n);
let mut cols = Vec::with_capacity(n);
for k in 0..n {
rows.push(k);
cols.push(k);
}
(rows, cols)
}
fn hessian_values(&self, _x: &[f64], obj_factor: f64, _lambda: &[f64], vals: &mut [f64]) {
let k = self.k;
let h2 = self.h * self.h;
for j in 0..k {
for i in 0..k {
vals[self.idx_u(i, j)] = obj_factor * h2;
vals[self.idx_f(i, j)] = obj_factor * self.alpha * h2;
}
}
}
}
pub struct SparseQP {
pub n: usize,
}
impl NlpProblem for SparseQP {
fn num_variables(&self) -> usize {
self.n
}
fn num_constraints(&self) -> usize {
self.n
}
fn bounds(&self, x_l: &mut [f64], x_u: &mut [f64]) {
for i in 0..self.n {
x_l[i] = 0.0;
x_u[i] = 10.0;
}
}
fn constraint_bounds(&self, g_l: &mut [f64], g_u: &mut [f64]) {
for j in 0..self.n {
g_l[j] = f64::NEG_INFINITY;
g_u[j] = 2.5;
}
}
fn initial_point(&self, x0: &mut [f64]) {
for i in 0..self.n {
x0[i] = 0.5;
}
}
fn objective(&self, x: &[f64]) -> f64 {
let n = self.n;
let mut f = 0.0;
for i in 0..n {
f += 0.5 * 4.0 * x[i] * x[i];
if i < n - 1 {
f += 0.5 * (-1.0) * x[i] * x[i + 1] * 2.0; }
}
for i in 0..n {
f -= x[i];
}
f
}
fn gradient(&self, x: &[f64], grad: &mut [f64]) {
let n = self.n;
for i in 0..n {
grad[i] = 4.0 * x[i] - 1.0;
if i > 0 {
grad[i] -= x[i - 1];
}
if i < n - 1 {
grad[i] -= x[i + 1];
}
}
}
fn constraints(&self, x: &[f64], g: &mut [f64]) {
let n = self.n;
for j in 0..n {
g[j] = x[j] + x[(j + 1) % n] + x[(j + 2) % n];
}
}
fn jacobian_structure(&self) -> (Vec<usize>, Vec<usize>) {
let n = self.n;
let mut rows = Vec::with_capacity(3 * n);
let mut cols = Vec::with_capacity(3 * n);
for j in 0..n {
rows.push(j);
cols.push(j);
rows.push(j);
cols.push((j + 1) % n);
rows.push(j);
cols.push((j + 2) % n);
}
(rows, cols)
}
fn jacobian_values(&self, _x: &[f64], vals: &mut [f64]) {
let n = self.n;
for j in 0..n {
let base = 3 * j;
vals[base] = 1.0;
vals[base + 1] = 1.0;
vals[base + 2] = 1.0;
}
}
fn hessian_structure(&self) -> (Vec<usize>, Vec<usize>) {
let n = self.n;
let mut rows = Vec::with_capacity(2 * n - 1);
let mut cols = Vec::with_capacity(2 * n - 1);
rows.push(0);
cols.push(0);
for i in 1..n {
rows.push(i);
cols.push(i - 1);
rows.push(i);
cols.push(i);
}
(rows, cols)
}
fn hessian_values(&self, _x: &[f64], obj_factor: f64, _lambda: &[f64], vals: &mut [f64]) {
let n = self.n;
vals[0] = obj_factor * 4.0;
for i in 1..n {
vals[2 * i - 1] = obj_factor * (-1.0);
vals[2 * i] = obj_factor * 4.0;
}
}
}