Rust凸优化求解器库Clarabel的使用,Clarabel提供高效二次规划(QP)和半定规划(SDP)求解功能

Rust凸优化求解器库Clarabel的使用

简介

Clarabel.rs是一个Rust实现的用于凸优化问题的内点法数值求解器,使用新颖的齐次嵌入技术。Clarabel.rs解决以下形式的优化问题:

$$ \begin{array}{r} \text{minimize} & \frac{1}{2}x^T P x + q^T x\[2ex] \text{subject to} & Ax + s = b \[1ex] & s \in \mathcal{K} \end{array} $$

决策变量为$x \in \mathbb{R}^n$, $s \in \mathbb{R}^m$,数据矩阵为$P=P^\top \succeq 0$, $q \in \mathbb{R}^n$, $A \in \mathbb{R}^{m \times n}$, 和 $b \in \mathbb{R}^m$。凸集$\mathcal{K}$是凸锥的组合。

特性

  • 多功能:解决线性规划(LPs)、二次规划(QPs)、二阶锥规划(SOCPs)和半定规划(SDPs),以及具有指数、幂锥和广义幂锥约束的问题
  • 二次目标:无需对目标函数进行任何改写即可处理二次目标
  • 不可行性检测:使用齐次嵌入技术检测不可行问题
  • 开源:代码在Apache 2.0许可下可用

安装

在Cargo项目中添加以下依赖:

[dependencies]
clarabel = "0.11.1"

Python接口安装:

pip install clarabel

示例代码

以下是一个完整的Rust示例,展示如何使用Clarabel解决一个二次规划问题:

use clarabel::algebra::*;
use clarabel::solver::*;

fn main() {
    // 定义问题数据
    let P = CscMatrix::new(
        2,                    // 行数
        2,                    // 列数
        vec![0, 1, 3],        // 列指针
        vec![0, 1, 0, 1],     // 行索引
        vec![3., 1., 4.],     // 非零值
    );
    
    let q = vec![1., 1.];
    
    let A = CscMatrix::new(
        3,                    // 行数
        2,                    // 列数
        vec![0, 2, 4],        // 列指针
        vec![0, 1, 0, 1],     // 行索引
        vec![1., 1., 1., 1.], // 非零值
    );
    
    let b = vec![1., 1., 1.];
    
    let cones = [ZeroConeT(1), NonnegativeConeT(2)];
    
    // 定义求解器
    let settings = DefaultSettings::default();
    let mut solver = DefaultSolver::new(&P, &q, &A, &b, &cones, settings);
    
    // 求解问题
    solver.solve();
    
    // 获取结果
    println!("Solution status: {:?}", solver.solution.status);
    println!("Solution x: {:?}", solver.solution.x);
    println!("Solution z: {:?}", solver.solution.z);
}

完整示例demo

以下是一个更完整的示例,展示如何使用Clarabel解决一个带约束的二次规划问题:

use clarabel::algebra::*;
use clarabel::solver::*;

fn main() {
    // 定义二次目标函数: 最小化 3x1² + 2x1x2 + 4x2² + x1 + x2
    let P = CscMatrix::new(
        2,                    // 变量数
        2,                    // 变量数
        vec![0, 1, 3],        // 列指针 (CSC格式)
        vec![0, 1, 0, 1],     // 行索引
        vec![6., 2., 8.],     // 值 (注意: 矩阵P需要乘以1/2)
    );
    
    let q = vec![1., 1.];     // 线性项
    
    // 定义约束条件:
    // 1. x1 + x2 = 1 (等式约束)
    // 2. x1 >= 0     (非负约束)
    // 3. x2 >= 0     (非负约束)
    let A = CscMatrix::new(
        3,                    // 约束数
        2,                    // 变量数
        vec![0, 2, 4],        // 列指针
        vec![0, 1, 0, 1],     // 行索引
        vec![1., 1., 1., 1.], // 值
    );
    
    let b = vec![1., 0., 0.]; // 约束右边值
    
    // 定义锥约束:
    // 1. 第一个约束是等式约束 (Zero锥)
    // 2. 后两个约束是非负约束 (Nonnegative锥)
    let cones = [ZeroConeT(1), NonnegativeConeT(2)];
    
    // 使用默认设置创建求解器
    let settings = DefaultSettings::default();
    let mut solver = DefaultSolver::new(&P, &q, &A, &b, &cones, settings);
    
    // 求解问题
    solver.solve();
    
    // 输出详细结果
    println!("=== 求解结果 ===");
    println!("状态: {:?}", solver.solution.status);
    println!("最优解 x: {:?}", solver.solution.x);
    println!("对偶变量 z: {:?}", solver.solution.z);
    println!("目标值: {}", solver.solution.obj_val);
    println!("求解时间: {}秒", solver.solution.solve_time);
    println!("迭代次数: {}", solver.solution.iterations);
    
    // 检查解的状态
    match solver.solution.status {
        SolverStatus::Solved => {
            println!("问题成功求解!");
            println!("最优解: x1 = {:.4}, x2 = {:.4}", 
                    solver.solution.x[0], 
                    solver.solution.x[1]);
        },
        SolverStatus::Infeasible => println!("问题不可行!"),
        SolverStatus::MaxIterations => println!("达到最大迭代次数!"),
        _ => println!("求解器返回未处理的状态"),
    }
}

引用

@misc{Clarabel_2024,
      title={Clarabel: An interior-point solver for conic programs with quadratic objectives}, 
      author={Paul J. Goulart and Yuwen Chen},
      year={2024},
      eprint={2405.12762},
      archivePrefix={arXiv},
      primaryClass={math.OC}
}

许可证

本项目采用Apache License 2.0许可。


1 回复

Rust凸优化求解器库Clarabel的使用指南

介绍

Clarabel是一个用纯Rust编写的凸优化求解器库,专门用于解决二次规划(QP)和半定规划(SDP)问题。它提供了高效的求解能力,特别适合需要高性能和内存安全的优化应用场景。

主要特性

  • 纯Rust实现,无外部依赖
  • 支持二次规划(QP)和半定规划(SDP)
  • 内点法求解器
  • 数值稳定且高效
  • 提供简洁的API接口

安装方法

在Cargo.toml中添加依赖:

[dependencies]
clarabel = "0.5"  # 请使用最新版本

基本使用方法

1. 解决二次规划问题(QP)

use clarabel::algebra::*;
use clarabel::solver::*;

fn main() {
    // 定义问题数据
    let P = CscMatrix::new(
        2,                    // 行数
        2,                    // 列数
        vec![0, 1, 3],        // 列指针
        vec![0, 0, 1],        // 行索引
        vec![2., 1., 2.],     // 值
    );
    
    let q = vec![-2., -4.];
    
    // 约束条件 A*x = b
    let A = CscMatrix::new(
        2,                    // 行数
        2,                    // 列数
        vec![0, 1, 2],        // 列指针
        vec![0, 1],           // 行索引
        vec![1., 1.],         // 值
    );
    
    let b = vec![1., 1.];
    
    // 构建求解器
    let settings = DefaultSettings::default();
    let mut solver = DefaultSolver::new(&P, &q, &A, &b, settings);
    
    // 求解
    solver.solve();
    
    // 获取结果
    println!("Solution: {:?}", solver.solution.x);
}

2. 解决半定规划问题(SDP)

use clarabel::algebra::*;
use clarabel::solver::*;

fn main() {
    // 定义SDP问题数据
    let c = vec![1., 2., 3.];
    
    // 约束矩阵 A_i
    let A0 = CscMatrix::new(
        2, 2,
        vec![0, 1, 2],
        vec![0, 1],
        vec![1., 1.]
    );
    
    let A1 = CscMatrix::new(
        2, 2,
        vec![0, 1, 2],
        vec![0, 1],
        vec![1., -1.]
    );
    
    let A = vec![A0, A1];
    let b = vec![1., 0.5];
    
    // 构建求解器
    let settings = DefaultSettings::default();
    let mut solver = DefaultSolver::new_sdp(&c, &A, &b, settings);
    
    // 求解
    solver.solve();
    
    // 获取结果
    println!("SDP Solution: {:?}", solver.solution.x);
}

高级用法

自定义求解器设置

use clarabel::solver::*;

let settings = Settings {
    max_iter: 1000,          // 最大迭代次数
    time_limit: Some(10.0),  // 时间限制(秒)
    verbose: true,           // 显示求解过程
    tol_gap_abs: 1e-8,       // 绝对间隙容差
    tol_gap_rel: 1e-8,       // 相对间隙容差
    ..Default::default()     // 其他参数使用默认值
};

处理不等式约束

// 添加不等式约束 Ax <= b
let A_ineq = CscMatrix::new(
    1, 2,
    vec![0, 1, 2],
    vec![0, 1],
    vec![1., 1.]
);
let b_ineq = vec![2.];

// 构建求解器时传入不等式约束
let mut solver = DefaultSolver::new_with_ineq(&P, &q, &A, &b, &A_极速, &b_ineq, settings);

完整示例demo

下面是一个完整的二次规划问题示例,展示了如何使用Clarabel解决一个实际的优化问题:

use clarabel::algebra::*;
use clarabel::solver::*;

fn main() {
    // 最小化目标函数: 2x² + xy + 2y² - 2x - 4y
    // 约束条件: x + y = 1
    
    // 构建二次项矩阵P (2x2)
    let P = CscMatrix::new(
        2,                    // 行数
        2,                    // 列数
        vec![0, 1, 3],        // 列指针
        vec![0, 0, 1],        // 行索引 (0,0), (0,1), (1,1)
        vec![4., 1., 4.],     // 值 (注意: 原问题中的2x²需要乘以2)
    );
    
    // 构建线性项向量q
    let q = vec![-2., -4.];
    
    // 等式约束矩阵A (1x2)
    let A = CscMatrix::new(
        1,                    // 行数 (1个等式约束)
        2,                    // 列数
        vec![0, 1, 2],        // 列指针
        vec![0, 0],           // 行索引 (0,0), (0,1)
        vec![1., 1.],         // 值
    );
    
    // 等式约束右侧b
    let b = vec![1.];
    
    // 自定义求解器设置
    let settings = Settings {
        max_iter: 100,
        time_limit: None,
        verbose: true,
        tol_gap_abs: 1e-6,
        tol_gap_rel: 1e-6,
        ..Default::default()
    };
    
    // 构建并求解问题
    let mut solver = DefaultSolver::new(&P, &q, &A, &b, settings);
    solver.solve();
    
    // 输出结果
    println!("优化状态: {:?}", solver.solution.status);
    println!("最优解: x = {:.4}, y = {:.4}", 
             solver.solution.x[0], 
             solver.solution.x[1]);
    println!("目标函数值: {:.4}", solver.solution.obj_val);
    println!("求解时间: {:.2}ms", solver.solution.solve_time * 1000.0);
}

注意事项

  1. Clarabel使用稀疏矩阵格式(CSC)来表示问题数据,确保数据格式正确
  2. 对于大规模问题,考虑使用更高效的矩阵构建方法
  3. 检查求解器返回的状态信息,确保问题已成功解决
  4. 可以通过调整求解器参数来优化性能

性能建议

  • 尽量重用求解器实例以减少内存分配
  • 对于重复求解类似问题,考虑热启动
  • 使用rayon等并行库预处理问题数据可提高性能

Clarabel为Rust生态提供了一个强大而高效的凸优化求解方案,特别适合嵌入到需要高性能和内存安全的应用程序中。

回到顶部