diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d789ee9..dbdd965 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -105,7 +105,7 @@ jobs: run: cargo run --example portfolio msrv: - name: Check MSRV (1.71) + name: Check MSRV (1.85) runs-on: ubuntu-latest steps: @@ -115,7 +115,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@master with: - toolchain: "1.71" + toolchain: "1.87" - name: Check build with MSRV run: cargo check --all-features diff --git a/Cargo.toml b/Cargo.toml index 15244f4..9ac73bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,33 +1,32 @@ [package] name = "cvxrust" version = "0.1.0" -edition = "2021" -authors = ["CVXPY team"] +edition = "2024" description = "A Rust implementation of Disciplined Convex Programming" license = "Apache-2.0" repository = "https://github.com/cvxpy/cvxrust" documentation = "https://docs.rs/cvxrust" keywords = ["optimization", "convex", "dcp", "solver", "math"] categories = ["mathematics", "algorithms", "science"] -rust-version = "1.71" +rust-version = "1.87" [dependencies] # Clarabel solver -clarabel = "0.9" +clarabel = "0.11" # Sparse matrices -nalgebra = "0.33" -nalgebra-sparse = "0.10" +nalgebra = "0.34" +nalgebra-sparse = "0.11" # Error handling thiserror = "2.0" # Fast hash maps -rustc-hash = "2.0" +rustc-hash = "2.1" [dev-dependencies] approx = "0.5" -rand = "0.8" +rand = "0.10" [features] default = [] diff --git a/src/atoms/affine.rs b/src/atoms/affine.rs index c0f15a3..a519659 100644 --- a/src/atoms/affine.rs +++ b/src/atoms/affine.rs @@ -9,7 +9,7 @@ use std::ops::{Add, Div, Mul, Neg, Sub}; use std::sync::Arc; -use crate::expr::{constant, Expr, Shape}; +use crate::expr::{Expr, Shape, constant}; // ============================================================================ // Operator overloading for Expr diff --git a/src/atoms/mod.rs b/src/atoms/mod.rs index 8f61ae1..8d086c0 100644 --- a/src/atoms/mod.rs +++ b/src/atoms/mod.rs @@ -16,6 +16,6 @@ pub use affine::{ // Re-export nonlinear atoms pub use nonlinear::{ - abs, entropy, exp, log, max2, maximum, min2, minimum, neg_part, norm, norm1, norm2, norm_inf, + abs, entropy, exp, log, max2, maximum, min2, minimum, neg_part, norm, norm_inf, norm1, norm2, pos, power, quad_form, quad_over_lin, sqrt, sum_squares, try_norm, }; diff --git a/src/canon/canonicalizer.rs b/src/canon/canonicalizer.rs index bcecb15..718e13b 100644 --- a/src/canon/canonicalizer.rs +++ b/src/canon/canonicalizer.rs @@ -915,7 +915,7 @@ impl CanonContext { let ai = csc_to_dense(&x.coeffs[&var_i]); // (m, ni) for &var_j in &vars { let aj = csc_to_dense(&x.coeffs[&var_j]); // (m, nj) - // A_i' * A_j: (ni, m) * (m, nj) = (ni, nj) + // A_i' * A_j: (ni, m) * (m, nj) = (ni, nj) let ai_t_aj = dense_to_csc(&(ai.transpose() * &aj)); quad_coeffs .entry((var_i, var_j)) diff --git a/src/canon/mod.rs b/src/canon/mod.rs index fed4381..1e7272c 100644 --- a/src/canon/mod.rs +++ b/src/canon/mod.rs @@ -8,5 +8,5 @@ pub mod canonicalizer; pub mod lin_expr; -pub use canonicalizer::{canonicalize, CanonExpr, CanonResult, ConeConstraint}; +pub use canonicalizer::{CanonExpr, CanonResult, ConeConstraint, canonicalize}; pub use lin_expr::{LinExpr, QuadExpr}; diff --git a/src/dcp/mod.rs b/src/dcp/mod.rs index 1b16e1d..b6249dd 100644 --- a/src/dcp/mod.rs +++ b/src/dcp/mod.rs @@ -8,5 +8,5 @@ pub mod curvature; pub mod sign; -pub use curvature::{add_curvature, scalar_mul_curvature, Curvature, PsdStatus}; -pub use sign::{add_sign, mul_sign, Sign}; +pub use curvature::{Curvature, PsdStatus, add_curvature, scalar_mul_curvature}; +pub use sign::{Sign, add_sign, mul_sign}; diff --git a/src/expr/eval.rs b/src/expr/eval.rs index 8a974bc..998cdc4 100644 --- a/src/expr/eval.rs +++ b/src/expr/eval.rs @@ -150,11 +150,7 @@ impl Expr { Expr::Exp(a) => Ok(eval_elementwise(a.eval(ctx)?, f64::exp)), Expr::Log(a) => Ok(eval_elementwise(a.eval(ctx)?, f64::ln)), Expr::Entropy(a) => Ok(eval_elementwise(a.eval(ctx)?, |x| { - if x <= 0.0 { - 0.0 - } else { - -x * x.ln() - } + if x <= 0.0 { 0.0 } else { -x * x.ln() } })), Expr::Power(a, p) => { let p = *p; @@ -506,7 +502,7 @@ fn eval_cumsum(a: Array, axis: Option) -> crate::Result { return Err(crate::CvxError::InvalidProblem(format!( "Invalid axis {} for cumsum", ax - ))) + ))); } } Ok(Array::Dense(m)) diff --git a/src/expr/expression.rs b/src/expr/expression.rs index 00308dc..aa21e04 100644 --- a/src/expr/expression.rs +++ b/src/expr/expression.rs @@ -3,8 +3,8 @@ //! The `Expr` enum represents all possible expressions in the DCP framework. //! Expressions form an immutable DAG (directed acyclic graph) using `Arc` for sharing. -use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; +use std::sync::atomic::{AtomicU64, Ordering}; use nalgebra::DMatrix; use nalgebra_sparse::CscMatrix; @@ -329,7 +329,7 @@ impl Expr { for (i, r) in spec.ranges.iter().enumerate() { match r { Some((start, stop, step)) => { - let size = (stop - start + step - 1) / step; + let size = (stop - start).div_ceil(*step); if size > 1 { new_dims.push(size); } diff --git a/src/expr/mod.rs b/src/expr/mod.rs index 7c4db4c..ed76b2d 100644 --- a/src/expr/mod.rs +++ b/src/expr/mod.rs @@ -14,13 +14,13 @@ pub mod variable; // Re-export main types pub use constant::{ - constant, constant_dmatrix, constant_matrix, constant_sparse, constant_vec, eye, ones, zeros, - IntoConstant, + IntoConstant, constant, constant_dmatrix, constant_matrix, constant_sparse, constant_vec, eye, + ones, zeros, }; pub use eval::Evaluable; pub use expression::{Array, ConstantData, Expr, ExprId, IndexSpec, VariableData}; pub use shape::Shape; pub use variable::{ - matrix_var, named_variable, nonneg_variable, nonpos_variable, scalar_var, var, variable, - vector_var, VariableBuilder, VariableExt, + VariableBuilder, VariableExt, matrix_var, named_variable, nonneg_variable, nonpos_variable, + scalar_var, var, variable, vector_var, }; diff --git a/src/expr/shape.rs b/src/expr/shape.rs index 3b31421..7a0282c 100644 --- a/src/expr/shape.rs +++ b/src/expr/shape.rs @@ -100,12 +100,10 @@ impl Shape { let mut result = Vec::with_capacity(max_ndim); // Pad shapes with 1s on the left - let self_padded: Vec = std::iter::repeat(1) - .take(max_ndim - self.ndim()) + let self_padded: Vec = std::iter::repeat_n(1, max_ndim - self.ndim()) .chain(self.0.iter().copied()) .collect(); - let other_padded: Vec = std::iter::repeat(1) - .take(max_ndim - other.ndim()) + let other_padded: Vec = std::iter::repeat_n(1, max_ndim - other.ndim()) .chain(other.0.iter().copied()) .collect(); diff --git a/src/lib.rs b/src/lib.rs index 31abb21..80c895e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,15 +79,15 @@ pub mod sparse; pub mod prelude { // Expression types pub use crate::expr::{ + Array, Evaluable, Expr, ExprId, IntoConstant, Shape, VariableBuilder, VariableExt, constant, constant_dmatrix, constant_matrix, constant_sparse, constant_vec, eye, ones, - variable, zeros, Array, Evaluable, Expr, ExprId, IntoConstant, Shape, VariableBuilder, - VariableExt, + variable, zeros, }; // Atoms pub use crate::atoms::{ abs, cumsum, diag, dot, entropy, exp, flatten, hstack, log, matmul, max2, maximum, min2, - minimum, neg_part, norm, norm1, norm2, norm_inf, pos, power, quad_form, quad_over_lin, + minimum, neg_part, norm, norm_inf, norm1, norm2, pos, power, quad_form, quad_over_lin, reshape, sqrt, sum, sum_axis, sum_squares, trace, transpose, try_norm, vstack, }; diff --git a/src/problem.rs b/src/problem.rs index bb4bf91..22e4b7f 100644 --- a/src/problem.rs +++ b/src/problem.rs @@ -13,11 +13,11 @@ use std::sync::Arc; -use crate::canon::{canonicalize, ConeConstraint}; +use crate::canon::{ConeConstraint, canonicalize}; use crate::constraints::Constraint; use crate::error::{CvxError, Result}; use crate::expr::{Expr, ExprId, Shape}; -use crate::solver::{solve, stuff_problem, Settings, Solution, SolveStatus}; +use crate::solver::{Settings, Solution, SolveStatus, solve, stuff_problem}; /// Objective type for optimization problems. #[derive(Debug, Clone)] diff --git a/src/solver/clarabel.rs b/src/solver/clarabel.rs index 4c7f380..59615c1 100644 --- a/src/solver/clarabel.rs +++ b/src/solver/clarabel.rs @@ -265,7 +265,8 @@ pub fn solve(problem: &StuffedProblem, settings: &Settings) -> Solution { .unwrap(); // Create and run solver - let mut solver = DefaultSolver::new(&p, &problem.q, &a, &problem.b, &cones, clarabel_settings); + let mut solver = DefaultSolver::new(&p, &problem.q, &a, &problem.b, &cones, clarabel_settings) + .expect("Settings to be correct"); solver.solve(); // Extract solution diff --git a/src/solver/mod.rs b/src/solver/mod.rs index f49d240..59aa3ec 100644 --- a/src/solver/mod.rs +++ b/src/solver/mod.rs @@ -7,5 +7,5 @@ pub mod clarabel; pub mod stuffing; -pub use self::clarabel::{solve, Settings, Solution, SolveStatus}; -pub use stuffing::{stuff_problem, ConeDims, StuffedProblem, VariableMap}; +pub use self::clarabel::{Settings, Solution, SolveStatus, solve}; +pub use stuffing::{ConeDims, StuffedProblem, VariableMap, stuff_problem};