diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b43200..3fd3245 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.13) # Project properties -set(CLARABEL_PROJECT_VERSION 0.8.0) +set(CLARABEL_PROJECT_VERSION 0.9.0) project(Clarabel VERSION ${CLARABEL_PROJECT_VERSION}) # Specify the default C++ standard applied to all targets @@ -12,7 +12,9 @@ set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED True) -# SDP feature configuration +#---------------------------------------------- +# Clarabel feature configuration +#---------------------------------------------- set(CLARABEL_FEATURE_SDP "none" CACHE STRING "Package for SDP to be selected") set_property(CACHE CLARABEL_FEATURE_SDP PROPERTY STRINGS none @@ -23,6 +25,15 @@ set_property(CACHE CLARABEL_FEATURE_SDP PROPERTY STRINGS sdp-r ) +option(CLARABEL_FEATURE_SERDE "Enable clarabel `serde` option " OFF) +option(CLARABEL_FEATURE_FAER_SPARSE "Enable `faer-sparse` option" OFF) +option(CLARABEL_FEATURE_SERDE "Enable `faer-sparse` option" OFF) + + +#---------------------------------------------- +#---------------------------------------------- + + # Get dependencies # Eigen3 diff --git a/Clarabel.rs b/Clarabel.rs index 32dbc0c..f23fd15 160000 --- a/Clarabel.rs +++ b/Clarabel.rs @@ -1 +1 @@ -Subproject commit 32dbc0c092dd9a4ff444009822291d83c8e1203e +Subproject commit f23fd155a08a53cd2a0f130d4e734c9b5b7e4a27 diff --git a/README.md b/README.md index 17e0cf7..b0b19a6 100644 --- a/README.md +++ b/README.md @@ -86,14 +86,25 @@ where `VCPKG_TOOLCHAIN_PATH` is the path to the vcpkg toolchain file. ### SDP support -To enable SDP features, set the `CLARABEL_FEATURE_SDP` option to one of the following values: +To enable SDP features, set the `-DCLARABEL_FEATURE_SDP` option to one of the following values: - `sdp-accelerate` - `sdp-netlib` - `sdp-openblas` - `sdp-mkl` - `sdp-r` -By default, `CLARABEL_FEATURE_SDP` is `none` and SDP support is disabled. +By default, `-DCLARABEL_FEATURE_SDP=none` and SDP support is disabled. + +### JSON file input/output support + +To enable reading and writing of problem data to JSON files, set +`-DCLARABEL_FEATURE_SERDE=true`. + +When reporting issues with the solver, it can be helpful to provide a JSON file that reproduces the problem. + +### Alternative linear algebra libraries + +To enable the use of the [faer-rs](https://faer-rs.github.io/) sparse linear algebra library as an additional solver option, set `-DCLARABEL_FEATURE_FAER_SPARSE=true`. ### Unit tests diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index af0fc9d..8755c74 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,4 +1,5 @@ project(clarabel_examples VERSION ${CLARABEL_PROJECT_VERSION}) +add_compile_definitions("EXAMPLES_ROOT_DIR=${CMAKE_CURRENT_SOURCE_DIR}") add_subdirectory(c) add_subdirectory(cpp) \ No newline at end of file diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index 5554f24..31c86fc 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -9,6 +9,7 @@ set(C_EXAMPLES example_qp_f64 example_socp example_sdp + example_json ) # Compile utils.c as a library diff --git a/examples/c/example_json.c b/examples/c/example_json.c new file mode 100644 index 0000000..c0d3f93 --- /dev/null +++ b/examples/c/example_json.c @@ -0,0 +1,34 @@ +// #define FEATURE_SDP +#include "utils.h" +#include +#include +#include +#include + +#define STRING(string) #string +#define TO_STRING(string) STRING(string) + +int main(void) +{ +#ifndef FEATURE_SERDE + printf("This example requires JSON serde support.\n"); + return 1; +#else + + char filename[1024]; + strcpy(filename, TO_STRING(EXAMPLES_ROOT_DIR)); + strcat(filename, "/data/hs35.json"); + + ClarabelDefaultSolver* solver = clarabel_DefaultSolver_read_from_file(filename); + clarabel_DefaultSolver_solve(solver); + + // write it back to a file + // char filename_out[1024]; + // strcpy(filename_out, TO_STRING(EXAMPLES_ROOT_DIR)); + // strcat(filename_out, "/data/output_c.json"); + // clarabel_DefaultSolver_write_to_file(solver, filename_out); + + clarabel_DefaultSolver_free(solver); + return 0; +#endif +} diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt index ec7ced6..e3f3bbb 100644 --- a/examples/cpp/CMakeLists.txt +++ b/examples/cpp/CMakeLists.txt @@ -7,6 +7,8 @@ set(CPP_EXAMPLES example_qp example_socp example_sdp + example_faer + example_json ) # Define an executable target for each example diff --git a/examples/cpp/example_faer.cpp b/examples/cpp/example_faer.cpp new file mode 100644 index 0000000..1ef8876 --- /dev/null +++ b/examples/cpp/example_faer.cpp @@ -0,0 +1,74 @@ +#include "utils.h" + +#include +#include +#include + +using namespace clarabel; +using namespace std; +using namespace Eigen; + +// NB: this example requires that the solver be built with -DCLARABEL_FEATURE_FAER_SPARSE + +int main(void) +{ + +#ifndef FEATURE_FAER_SPARSE + + printf("This example requires faer-rs support.\n"); + return 1; + +#else + + + /* From dense matrix: + * [[6., 0.], + * [0., 4.]] + */ + MatrixXd P_dense(2, 2); + P_dense << + 6., 0., + 0., 4.; + + SparseMatrix P = P_dense.sparseView(); + P.makeCompressed(); + + Vector q = { -1., -4. }; + + MatrixXd A_dense(5, 2); + A_dense << + 1., -2., // <-- LHS of equality constraint (lower bound) + 1., 0., // <-- LHS of inequality constraint (upper bound) + 0., 1., // <-- LHS of inequality constraint (upper bound) + -1., 0., // <-- LHS of inequality constraint (lower bound) + 0., -1.; // <-- LHS of inequality constraint (lower bound) + + SparseMatrix A = A_dense.sparseView(); + A.makeCompressed(); + + Vector b = { 0., 1., 1., 1., 1. }; + + vector> cones + { + ZeroConeT(1), + NonnegativeConeT(4), + }; + + // Settings + DefaultSettings settings = DefaultSettings::default_settings(); + settings.direct_solve_method = ClarabelDirectSolveMethods::FAER; + + // Build solver + DefaultSolver solver(P, q, A, b, cones, settings); + + // Solve + solver.solve(); + + // Get solution + DefaultSolution solution = solver.solution(); + utils::print_solution(solution); + + return 0; + +#endif // FEATURE_FAER_SPARSE +} diff --git a/examples/cpp/example_json.cpp b/examples/cpp/example_json.cpp new file mode 100644 index 0000000..4265bd0 --- /dev/null +++ b/examples/cpp/example_json.cpp @@ -0,0 +1,38 @@ +// #define FEATURE_SDP +#include "utils.h" +#include +#include + +using namespace clarabel; +using namespace std; + +#define STRING(string) #string +#define TO_STRING(string) STRING(string) + +int main(void) +{ +#ifndef FEATURE_SERDE + + printf("This example requires JSON serde support.\n"); + return 1; + +#else + + std::string rootdir = TO_STRING(EXAMPLES_ROOT_DIR); + std::string filepath = "/data/hs35.json"; + std::string filename = rootdir + filepath; + cout << "Read from file: " << filename << endl; + + DefaultSolver solver = DefaultSolver::read_from_file(filename); + solver.solve(); + + // write it back to a file + // std::string outpath = "/data/output.json"; + // std::string filename_out = rootdir + outpath; + // solver.write_to_file(filename_out); + + return 0; + +#endif // FEATURE_SERDE + +} \ No newline at end of file diff --git a/examples/data/hs35.json b/examples/data/hs35.json new file mode 100644 index 0000000..99e22d7 --- /dev/null +++ b/examples/data/hs35.json @@ -0,0 +1 @@ +{"P":{"m":3,"n":3,"colptr":[0,1,3,5],"rowval":[0,0,1,0,2],"nzval":[4.000000000000001,2.0000000000000004,4.000000000000001,2.0,2.0]},"q":[-8.0,-6.0,-4.0],"A":{"m":4,"n":3,"colptr":[0,2,4,6],"rowval":[0,1,0,2,0,3],"nzval":[1.0,-1.0,1.0,-1.0,2.0,-1.0]},"b":[3.0,0.0,0.0,0.0],"cones":[{"NonnegativeConeT":4}],"settings":{"max_iter":200,"time_limit":1.7976931348623157e308,"verbose":true,"max_step_fraction":0.99,"tol_gap_abs":1e-8,"tol_gap_rel":1e-8,"tol_feas":1e-8,"tol_infeas_abs":1e-8,"tol_infeas_rel":1e-8,"tol_ktratio":1e-6,"reduced_tol_gap_abs":0.00005,"reduced_tol_gap_rel":0.00005,"reduced_tol_feas":0.0001,"reduced_tol_infeas_abs":0.00005,"reduced_tol_infeas_rel":0.00005,"reduced_tol_ktratio":0.0001,"equilibrate_enable":true,"equilibrate_max_iter":10,"equilibrate_min_scaling":0.0001,"equilibrate_max_scaling":10000.0,"linesearch_backtrack_step":0.8,"min_switch_step_length":0.1,"min_terminate_step_length":0.0001,"direct_kkt_solver":true,"direct_solve_method":"qdldl","static_regularization_enable":true,"static_regularization_constant":1e-8,"static_regularization_proportional":4.930380657631324e-32,"dynamic_regularization_enable":true,"dynamic_regularization_eps":1e-13,"dynamic_regularization_delta":2e-7,"iterative_refinement_enable":true,"iterative_refinement_reltol":1e-13,"iterative_refinement_abstol":1e-12,"iterative_refinement_max_iter":10,"iterative_refinement_stop_ratio":5.0,"presolve_enable":true,"chordal_decomposition_enable":true,"chordal_decomposition_merge_method":"clique_graph","chordal_decomposition_compact":true,"chordal_decomposition_complete_dual":true}} \ No newline at end of file diff --git a/include/Clarabel b/include/Clarabel index 52e62e3..2631557 100644 --- a/include/Clarabel +++ b/include/Clarabel @@ -6,7 +6,6 @@ #include "cpp/DefaultSettings.h" #include "cpp/DefaultSolution.h" #include "cpp/DefaultSolver.h" -// #include "cpp/DefaultSolverEigen.h" #include "cpp/SupportedConeT.h" #endif // CLARABEL_H diff --git a/include/c/DefaultSettings.h b/include/c/DefaultSettings.h index b6ba762..140c359 100644 --- a/include/c/DefaultSettings.h +++ b/include/c/DefaultSettings.h @@ -11,6 +11,9 @@ typedef enum ClarabelDirectSolveMethods { QDLDL, + #ifdef FEATURE_FAER_SPARSE + FAER, + #endif // MKL, (not supported in Rust yet) // CHOLMOD, (not supported in Rust yet) } ClarabelDirectSolveMethods; diff --git a/include/c/DefaultSolver.h b/include/c/DefaultSolver.h index 053bb6a..67a7ab5 100644 --- a/include/c/DefaultSolver.h +++ b/include/c/DefaultSolver.h @@ -57,6 +57,40 @@ static inline ClarabelDefaultSolver *clarabel_DefaultSolver_new(const ClarabelCs #endif } +#ifdef FEATURE_SERDE +// DefaultSolver::read_from_file +ClarabelDefaultSolver_f64 *clarabel_DefaultSolver_f64_read_from_file(const char *filename); +ClarabelDefaultSolver_f32 *clarabel_DefaultSolver_f32_read_from_file(const char *filename); + #ifdef CLARABEL_USE_FLOAT + static inline ClarabelDefaultSolver *clarabel_DefaultSolver_read_from_file(const char *filename) + { + return clarabel_DefaultSolver_f32_read_from_file(filename); + } + #else + static inline ClarabelDefaultSolver *clarabel_DefaultSolver_read_from_file(const char *filename) + { + return clarabel_DefaultSolver_f64_read_from_file(filename); + } + #endif // CLARABEL_USE_FLOAT + +// DefaultSolver::write_to_file +void clarabel_DefaultSolver_f64_write_to_file(ClarabelDefaultSolver_f64 *solver, const char *filename); +void clarabel_DefaultSolver_f32_write_to_file(ClarabelDefaultSolver_f32 *solver, const char *filename); + #ifdef CLARABEL_USE_FLOAT + static inline void clarabel_DefaultSolver_write_to_file(ClarabelDefaultSolver *solver, const char *filename) + { + clarabel_DefaultSolver_f32_write_to_file(solver,filename); + } + #else + static inline void clarabel_DefaultSolver_write_to_file(ClarabelDefaultSolver *solver, const char *filename) + { + clarabel_DefaultSolver_f64_write_to_file(solver,filename); + } + #endif // CLARABEL_USE_FLOAT +#endif // FEATURE_SERDE + + + // DefaultSolver::solve void clarabel_DefaultSolver_f64_solve(ClarabelDefaultSolver_f64 *solver); diff --git a/include/cpp/DefaultSettings.h b/include/cpp/DefaultSettings.h index 06a2d95..6b4d07d 100644 --- a/include/cpp/DefaultSettings.h +++ b/include/cpp/DefaultSettings.h @@ -9,6 +9,9 @@ namespace clarabel enum class ClarabelDirectSolveMethods { QDLDL, + #ifdef FEATURE_FAER_SPARSE + FAER, + #endif // MKL, (not supported in Rust yet) // CHOLMOD, (not supported in Rust yet) }; diff --git a/include/cpp/DefaultSolver.h b/include/cpp/DefaultSolver.h index 27cfd85..a0adfaf 100644 --- a/include/cpp/DefaultSolver.h +++ b/include/cpp/DefaultSolver.h @@ -104,6 +104,7 @@ class DefaultSolver const std::vector> &cones, const DefaultSettings &settings); + DefaultSolver(void* handle); ~DefaultSolver(); void solve(); @@ -141,6 +142,12 @@ class DefaultSolver void update_b(const Eigen::Ref> &index, const Eigen::Ref> &values); void update_b(const uintptr_t* index, const T* values, uintptr_t nvals); + // Read / write to JSON file + #ifdef FEATURE_SERDE + void write_to_file(const std::string &filename); + static DefaultSolver read_from_file(const std::string &filename); + #endif + }; template @@ -177,16 +184,13 @@ RustDefaultSolverHandle_f32 clarabel_DefaultSolver_f32_new(const CscMatrix *settings); void clarabel_DefaultSolver_f64_solve(RustDefaultSolverHandle_f64 solver); - void clarabel_DefaultSolver_f32_solve(RustDefaultSolverHandle_f32 solver); void clarabel_DefaultSolver_f64_free(RustDefaultSolverHandle_f64 solver); - void clarabel_DefaultSolver_f32_free(RustDefaultSolverHandle_f32 solver); DefaultSolution::ClarabelDefaultSolution clarabel_DefaultSolver_f64_solution(RustDefaultSolverHandle_f64 solver); - DefaultSolution::ClarabelDefaultSolution clarabel_DefaultSolver_f32_solution(RustDefaultSolverHandle_f32 solver); DefaultInfo clarabel_DefaultSolver_f64_info(RustDefaultSolverHandle_f64 solver); @@ -217,6 +221,14 @@ void clarabel_DefaultSolver_f32_update_b(RustDefaultSolverHandle_f32 solver, con void clarabel_DefaultSolver_f64_update_b_partial(RustDefaultSolverHandle_f64 solver, const uintptr_t* index, const double *values, uintptr_t nvals); void clarabel_DefaultSolver_f32_update_b_partial(RustDefaultSolverHandle_f32 solver, const uintptr_t* index, const float *values, uintptr_t nvals); +#ifdef FEATURE_SERDE +void clarabel_DefaultSolver_f64_write_to_file(RustDefaultSolverHandle_f64 solver, const char *filename); +void clarabel_DefaultSolver_f32_write_to_file(RustDefaultSolverHandle_f32 solver, const char *filename); +RustDefaultSolverHandle_f64 clarabel_DefaultSolver_f64_read_from_file( const char *filename); +RustDefaultSolverHandle_f32 clarabel_DefaultSolver_f32_read_from_file( const char *filename); +#endif + + } // Convert unique_ptr P, A to CscMatrix objects, then init the solver @@ -263,6 +275,16 @@ inline DefaultSolver::DefaultSolver(const Eigen::SparseMatrixhandle = clarabel_DefaultSolver_f32_new(&p, q.data(), &a, b.data(), cones.size(), cones.data(), &settings); } +template<> +inline DefaultSolver::DefaultSolver(void* handle){ + this->handle = handle; +} + +template<> +inline DefaultSolver::DefaultSolver(void* handle){ + this->handle = handle; +} + template<> inline DefaultSolver::~DefaultSolver() { @@ -538,4 +560,28 @@ inline void DefaultSolver::update_b(const uintptr_t* index, const float * clarabel_DefaultSolver_f32_update_b_partial(this->handle, index, values, nvals); } +#ifdef FEATURE_SERDE +template<> +inline void DefaultSolver::write_to_file(const std::string &filename){ + clarabel_DefaultSolver_f64_write_to_file(this->handle, filename.c_str()); +} + +template<> +inline void DefaultSolver::write_to_file(const std::string &filename){ + clarabel_DefaultSolver_f32_write_to_file(this->handle, filename.c_str()); +} + +template<> +inline DefaultSolver DefaultSolver::read_from_file(const std::string &filename){ + RustDefaultSolverHandle_f64 handle = clarabel_DefaultSolver_f64_read_from_file(filename.c_str()); + return DefaultSolver(handle); +} + +template<> +inline DefaultSolver DefaultSolver::read_from_file(const std::string &filename){ + RustDefaultSolverHandle_f32 handle = clarabel_DefaultSolver_f32_read_from_file(filename.c_str()); + return DefaultSolver(handle); +} +#endif // FEATURE_SERDE + } // namespace clarabel \ No newline at end of file diff --git a/rust_wrapper/CMakeLists.txt b/rust_wrapper/CMakeLists.txt index 46cf701..14ed1ca 100644 --- a/rust_wrapper/CMakeLists.txt +++ b/rust_wrapper/CMakeLists.txt @@ -18,16 +18,58 @@ endif() set(CLARABEL_C_OUTPUT_DIR ${clarabel_c_output_directory} PARENT_SCOPE) + +# ------------------------------------- +# Cargo features configuration +#-------------------------------------- + +# A list of features to pass to rustc +set(CLARABEL_BUILD_FEATURES "") + # SDP feature flag if(NOT CLARABEL_FEATURE_SDP STREQUAL "none") + # Set the Rust feature flag - set(clarabel_c_build_flags "${clarabel_c_build_flags};--features;${CLARABEL_FEATURE_SDP}") + set(CLARABEL_BUILD_FEATURES "${CLARABEL_BUILD_FEATURES},${CLARABEL_FEATURE_SDP}") # Define the FEATURE_SDP flag for all targets that link against clarabel_c target_compile_definitions(libclarabel_c_static INTERFACE FEATURE_SDP) target_compile_definitions(libclarabel_c_shared INTERFACE FEATURE_SDP) endif() +# FAER_SPARSE feature flag +if(CLARABEL_FEATURE_FAER_SPARSE) + + # Set the Rust feature flag + set(CLARABEL_BUILD_FEATURES "${CLARABEL_BUILD_FEATURES},faer-sparse") + + # Define the FEATURE_FAER_SPARSE flag for all targets that link against clarabel_c + target_compile_definitions(libclarabel_c_static INTERFACE FEATURE_FAER_SPARSE) + target_compile_definitions(libclarabel_c_shared INTERFACE FEATURE_FAER_SPARSE) +endif() + +# SERDE feature flag +if(CLARABEL_FEATURE_SERDE) + + # Set the Rust feature flag + set(CLARABEL_BUILD_FEATURES "${CLARABEL_BUILD_FEATURES},serde") + + # Define the FEATURE_SERDE flag for all targets that link against clarabel_c + target_compile_definitions(libclarabel_c_static INTERFACE FEATURE_SERDE) + target_compile_definitions(libclarabel_c_shared INTERFACE FEATURE_SERDE) +endif() + + + +set(clarabel_c_build_flags "${clarabel_c_build_flags};--features=${CLARABEL_BUILD_FEATURES}") +message("-- Rust feature list: " ${CLARABEL_BUILD_FEATURES}) +message("-- Cargo options: " "${clarabel_c_build_flags}") + + +# ------------------------------------- +# ------------------------------------- + + # Add the cargo project as a custom target add_custom_target( libclarabel_c diff --git a/rust_wrapper/Cargo.toml b/rust_wrapper/Cargo.toml index f98207a..6534687 100644 --- a/rust_wrapper/Cargo.toml +++ b/rust_wrapper/Cargo.toml @@ -6,6 +6,8 @@ edition = "2021" [dependencies] clarabel = { path = "../Clarabel.rs" } paste = "1.0" +serde = { version = "1", optional = true } +cfg-if = "1.0" [lib] crate-type = ["cdylib", "staticlib"] @@ -23,3 +25,6 @@ sdp-netlib = ["sdp", "clarabel/sdp-netlib"] sdp-openblas = ["sdp", "clarabel/sdp-openblas"] sdp-mkl = ["sdp", "clarabel/sdp-mkl"] sdp-r = ["sdp", "clarabel/sdp-r"] + +serde = ["dep:serde", "clarabel/serde"] +faer-sparse = ["clarabel/faer-sparse"] diff --git a/rust_wrapper/cbindgen.toml b/rust_wrapper/cbindgen.toml index 392ea25..e1afcb3 100644 --- a/rust_wrapper/cbindgen.toml +++ b/rust_wrapper/cbindgen.toml @@ -12,3 +12,5 @@ documentation = false [defines] "feature = sdp" = "FEATURE_SDP" +"feature = faer-sparse" = "FEATURE_FAER_SPARSE" +"feature = serde" = "FEATURE_SERDE" \ No newline at end of file diff --git a/rust_wrapper/src/solver/implementations/default/settings.rs b/rust_wrapper/src/solver/implementations/default/settings.rs index cb6d680..8caaace 100644 --- a/rust_wrapper/src/solver/implementations/default/settings.rs +++ b/rust_wrapper/src/solver/implementations/default/settings.rs @@ -2,8 +2,11 @@ use clarabel::algebra::FloatT; /// Used to replace the String type in the DefaultSettings struct #[repr(C)] +#[allow(dead_code)] pub enum ClarabelDirectSolveMethods { QDLDL, + #[cfg(feature = "faer-sparse")] + FAER, // MKL, (not supported yet) // CHOLMOD, (not supported yet) } diff --git a/rust_wrapper/src/solver/implementations/default/solver.rs b/rust_wrapper/src/solver/implementations/default/solver.rs index fcbde2f..436858f 100644 --- a/rust_wrapper/src/solver/implementations/default/solver.rs +++ b/rust_wrapper/src/solver/implementations/default/solver.rs @@ -1,3 +1,7 @@ +#![allow(non_snake_case)] +#![allow(non_camel_case_types)] + + use crate::algebra::ClarabelCscMatrix; use crate::core::cones::ClarabelSupportedConeT; use crate::solver::implementations::default::settings::*; @@ -7,12 +11,19 @@ use clarabel::solver::{self as lib, IPSolver, SolverStatus}; use std::slice; use std::{ffi::c_void, mem::forget}; +cfg_if::cfg_if! { + if #[cfg(feature = "serde")] { + use std::ffi::c_char; + use serde::{de::DeserializeOwned, Serialize}; + use clarabel::solver::SolverJSONReadWrite; + } +} + + use super::info::ClarabelDefaultInfo; use super::solution::DefaultSolution; -#[allow(non_camel_case_types)] pub type ClarabelDefaultSolver_f32 = c_void; -#[allow(non_camel_case_types)] pub type ClarabelDefaultSolver_f64 = c_void; // Wrapper function to create a DefaultSolver object from C using dynamic memory allocation @@ -21,7 +32,6 @@ pub type ClarabelDefaultSolver_f64 = c_void; // - Settings are converted from C struct to Rust struct // // b and cones are allowed to be null pointers, in which case they form zero-length slices and this is consistent with Clarabel.rs. -#[allow(non_snake_case)] unsafe fn _internal_DefaultSolver_new( P: *const ClarabelCscMatrix, // Matrix P q: *const T, // Array of double from C @@ -85,7 +95,6 @@ unsafe fn _internal_DefaultSolver_new( } #[no_mangle] -#[allow(non_snake_case)] pub unsafe extern "C" fn clarabel_DefaultSolver_f64_new( P: *const ClarabelCscMatrix, q: *const f64, @@ -99,7 +108,6 @@ pub unsafe extern "C" fn clarabel_DefaultSolver_f64_new( } #[no_mangle] -#[allow(non_snake_case)] pub unsafe extern "C" fn clarabel_DefaultSolver_f32_new( P: *const ClarabelCscMatrix, q: *const f32, @@ -113,7 +121,6 @@ pub unsafe extern "C" fn clarabel_DefaultSolver_f32_new( } // Wrapper function to call DefaultSolver.solve() from C -#[allow(non_snake_case)] fn _internal_DefaultSolver_solve(solver: *mut c_void) { // Recover the solver object from the opaque pointer let mut solver = unsafe { Box::from_raw(solver as *mut lib::DefaultSolver) }; @@ -136,7 +143,6 @@ pub extern "C" fn clarabel_DefaultSolver_f32_solve(solver: *mut ClarabelDefaultS } // Function to free the memory of the solver object -#[allow(non_snake_case)] unsafe fn _internal_DefaultSolver_free(solver: *mut c_void) { if !solver.is_null() { // Reconstruct the box to drop the solver object @@ -155,6 +161,73 @@ pub unsafe extern "C" fn clarabel_DefaultSolver_f32_free(solver: *mut ClarabelDe _internal_DefaultSolver_free::(solver); } +#[cfg(feature = "serde")] +pub unsafe fn _internal_DefaultSolver_read_from_file(filename: *const c_char) + -> *mut c_void +where T: FloatT + DeserializeOwned + Serialize, +{ + if filename.is_null() { + return std::ptr::null_mut(); + } + let filename = unsafe{std::ffi::CStr::from_ptr(filename).to_str().expect("Invalid filename")}; + let mut file = std::fs::File::open(filename).expect("File not found"); + let solver = lib::DefaultSolver::::read_from_file(&mut file); + Box::into_raw(Box::new(solver)) as *mut c_void +} + +#[cfg(feature = "serde")] +fn _internal_DefaultSolver_write_to_file(solver: *mut c_void, filename: *const c_char) +where T: FloatT + DeserializeOwned + Serialize, +{ + if filename.is_null() { + return; + } + let filename = unsafe{std::ffi::CStr::from_ptr(filename).to_str().expect("Invalid filename")}; + let mut file = std::fs::File::create(filename).expect("File not found"); + + // Recover the solver object from the opaque pointer + let solver = unsafe { Box::from_raw(solver as *mut lib::DefaultSolver) }; + + // Use the recovered solver object + solver.write_to_file(&mut file).unwrap(); + + // Leave the solver object on the heap + Box::into_raw(solver); +} + +#[no_mangle] +#[cfg(feature = "serde")] +pub unsafe extern "C" fn clarabel_DefaultSolver_f64_read_from_file( + filename: *const c_char, +) -> *mut ClarabelDefaultSolver_f64 { + + _internal_DefaultSolver_read_from_file::(filename) +} + +#[no_mangle] +#[cfg(feature = "serde")] +pub unsafe extern "C" fn clarabel_DefaultSolver_f32_read_from_file( + filename: *const c_char, +) -> *mut ClarabelDefaultSolver_f32 { + + _internal_DefaultSolver_read_from_file::(filename) +} + +#[no_mangle] +#[cfg(feature = "serde")] +pub extern "C" fn clarabel_DefaultSolver_f64_write_to_file(solver: *mut ClarabelDefaultSolver_f64,filename: *const c_char) { + _internal_DefaultSolver_write_to_file::(solver,filename); +} + +#[no_mangle] +#[cfg(feature = "serde")] +pub extern "C" fn clarabel_DefaultSolver_f32_write_to_file(solver: *mut ClarabelDefaultSolver_f32,filename: *const c_char) { + _internal_DefaultSolver_write_to_file::(solver,filename); +} + + + + #[repr(C)] #[allow(dead_code)] pub enum ClarabelSolverStatus { @@ -209,7 +282,6 @@ impl From<&mut SolverStatus> for ClarabelSolverStatus { /// Get the solution field from a DefaultSolver object. /// /// The solution is returned as a C struct. -#[allow(non_snake_case)] fn _internal_DefaultSolver_solution(solver: *mut c_void) -> DefaultSolution { // Recover the solver object from the opaque pointer let mut solver = unsafe { Box::from_raw(solver as *mut lib::DefaultSolver) }; @@ -239,7 +311,6 @@ pub extern "C" fn clarabel_DefaultSolver_f32_solution( } /// Get the info field from a DefaultSolver object. -#[allow(non_snake_case)] fn _internal_DefaultSolver_info(solver: *mut c_void) -> ClarabelDefaultInfo { // Recover the solver object from the opaque pointer let mut solver = unsafe { Box::from_raw(solver as *mut lib::DefaultSolver) }; diff --git a/rust_wrapper/src/utils/mod.rs b/rust_wrapper/src/utils/mod.rs index 6ab4cbc..cd2bf71 100644 --- a/rust_wrapper/src/utils/mod.rs +++ b/rust_wrapper/src/utils/mod.rs @@ -42,6 +42,8 @@ pub fn get_solver_settings_from_c( direct_kkt_solver: value.direct_kkt_solver, direct_solve_method: match value.direct_solve_method { ClarabelDirectSolveMethods::QDLDL => String::from("qdldl"), + #[cfg(feature = "faer-sparse")] + ClarabelDirectSolveMethods::FAER => String::from("faer"), // Not supported yet //ClarabelDirectSolveMethods::MKL => String::from("mkl"), //ClarabelDirectSolveMethods::CHOLMOD => String::from("cholmod"),