From 33c203c4fa4f26540ec4c9f0ec12bafc1ba4557f Mon Sep 17 00:00:00 2001 From: goulart-paul Date: Thu, 6 Feb 2025 00:44:49 +0000 Subject: [PATCH] configurable print streams --- .gitignore | 13 +- Clarabel.rs | 2 +- examples/c/CMakeLists.txt | 1 + examples/c/example_json.c | 4 +- examples/c/example_print_stream.c | 75 ++++++++++ examples/cpp/CMakeLists.txt | 1 + examples/cpp/example_json.cpp | 4 +- examples/cpp/example_print_stream.cpp | 73 ++++++++++ include/c/DefaultSolver.h | 92 +++++++++++-- include/cpp/DefaultInfo.h | 1 + include/cpp/DefaultSolver.h | 88 ++++++++++-- .../solver/implementations/default/solver.rs | 129 ++++++++++++++++-- 12 files changed, 432 insertions(+), 51 deletions(-) create mode 100644 examples/c/example_print_stream.c create mode 100644 examples/cpp/example_print_stream.cpp diff --git a/.gitignore b/.gitignore index 52498a1..f61d8fd 100644 --- a/.gitignore +++ b/.gitignore @@ -3,11 +3,20 @@ rust_wrapper/target rust_wrapper/headers rust_wrapper/Cargo.lock -# CMake build directory -build +# CMake build directory and other cruft +build/* +*.cmake +Makefile +CmakeFiles/* .*/ !.vscode/ !.github CMakePresets.json + +# compiled examples, but not source +examples/cpp/* +examples/c/* +!examples/c/*.c +!examples/cpp/*.cpp \ No newline at end of file diff --git a/Clarabel.rs b/Clarabel.rs index e951280..770d408 160000 --- a/Clarabel.rs +++ b/Clarabel.rs @@ -1 +1 @@ -Subproject commit e951280e95f6d75a45640f362d39e4f3f2c4cb94 +Subproject commit 770d4082a5fdcf9d875af6d95ce3b7034a029210 diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index 31c86fc..d058db1 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -10,6 +10,7 @@ set(C_EXAMPLES example_socp example_sdp example_json + example_print_stream ) # Compile utils.c as a library diff --git a/examples/c/example_json.c b/examples/c/example_json.c index c0d3f93..497c3ae 100644 --- a/examples/c/example_json.c +++ b/examples/c/example_json.c @@ -19,14 +19,14 @@ int main(void) strcpy(filename, TO_STRING(EXAMPLES_ROOT_DIR)); strcat(filename, "/data/hs35.json"); - ClarabelDefaultSolver* solver = clarabel_DefaultSolver_read_from_file(filename); + ClarabelDefaultSolver* solver = clarabel_DefaultSolver_load_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_save_to_file(solver, filename_out); clarabel_DefaultSolver_free(solver); return 0; diff --git a/examples/c/example_print_stream.c b/examples/c/example_print_stream.c new file mode 100644 index 0000000..b904e31 --- /dev/null +++ b/examples/c/example_print_stream.c @@ -0,0 +1,75 @@ +// #define FEATURE_SDP +#include "utils.h" +#include +#include +#include +#include + + +int main(void) +{ + + ClarabelCscMatrix P; + clarabel_CscMatrix_init( + &P, + 2, // row + 2, // col + (uintptr_t[]){ 0, 1, 2 }, // colptr + (uintptr_t[]){ 0, 1 }, // rowval + (ClarabelFloat[]){ 6., 4. } // nzval + ); + + ClarabelFloat q[2] = { -1., -4. }; + ClarabelCscMatrix A; + clarabel_CscMatrix_init( + &A, + 5, // row + 2, // col + (uintptr_t[]){ 0, 3, 6 }, // colptr + (uintptr_t[]){ 0, 1, 3, 0, 2, 4 }, // rowval + (ClarabelFloat[]){ 1., 1., -1., -2., 1., -1. } // nzval + ); + + ClarabelFloat b[5] = { 0., 1., 1., 1., 1. }; + + ClarabelSupportedConeT cones[2] = { ClarabelZeroConeT(1), ClarabelNonnegativeConeT(4) }; + + // Settings + ClarabelDefaultSettings settings = clarabel_DefaultSettings_default(); + + // Build solver + ClarabelDefaultSolver *solver = clarabel_DefaultSolver_new( + &P, // P + q, // q + &A, // A + b, // b + 2, // n_cones + cones, &settings + ); + + // redirect progress output to a file + printf("Printing to file ....\n"); + clarabel_DefaultSolver_print_to_file(solver,"clarabel_example_print_stream.txt"); + + // solve + clarabel_DefaultSolver_solve(solver); + + // redirect progress output to a buffer + printf("Printing to buffer ....\n"); + clarabel_DefaultSolver_print_to_buffer(solver); + + // solve again + clarabel_DefaultSolver_solve(solver); + + // fetch and print the buffer + printf("Recovering from buffer ....\n"); + const char* buffer = clarabel_DefaultSolver_get_print_buffer(solver); + printf("%s\n", buffer); + clarabel_free_print_buffer(buffer); + + // restore the buffer to stdout + printf("Printing to stdout ....\n"); + clarabel_DefaultSolver_print_to_stdout(solver); + clarabel_DefaultSolver_solve(solver); + +} diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt index 3d67a57..7826711 100644 --- a/examples/cpp/CMakeLists.txt +++ b/examples/cpp/CMakeLists.txt @@ -9,6 +9,7 @@ set(CPP_EXAMPLES example_sdp example_faer example_json + example_print_stream ) # Define an executable target for each example diff --git a/examples/cpp/example_json.cpp b/examples/cpp/example_json.cpp index 0ef5545..e411d33 100644 --- a/examples/cpp/example_json.cpp +++ b/examples/cpp/example_json.cpp @@ -23,13 +23,13 @@ int main(void) std::string filename = rootdir + filepath; std::cout << "Read from file: " << filename << endl; - DefaultSolver solver = DefaultSolver::read_from_file(filename); + DefaultSolver solver = DefaultSolver::load_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); + // solver.save_to_file(filename_out); return 0; diff --git a/examples/cpp/example_print_stream.cpp b/examples/cpp/example_print_stream.cpp new file mode 100644 index 0000000..320f7f3 --- /dev/null +++ b/examples/cpp/example_print_stream.cpp @@ -0,0 +1,73 @@ +#include "utils.h" + +#include +#include +#include +#include + +using namespace clarabel; +using namespace std; +using namespace Eigen; + +int main(void) +{ + /* 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(); + + // Build solver + DefaultSolver solver(P, q, A, b, cones, settings); + + // redirect progress output to a file + std::cout << "Printing to file ...." << std::endl; + solver.print_to_file("clarabel_example_print_stream.txt"); + solver.solve(); + + // redirect progress output to a buffer + std::cout << "Printing to buffer ...." << std::endl; + solver.print_to_buffer(); + solver.solve(); + + std::cout << "Recovering from buffer ...." << std::endl; + std::string bufstr = solver.get_print_buffer(); + std::cout << bufstr << std::endl; + + // restore the buffer to stdout + std::cout << "Printing to stdout ...." << std::endl; + solver.print_to_stdout(); + solver.solve(); + + return 0; +} diff --git a/include/c/DefaultSolver.h b/include/c/DefaultSolver.h index c4001cc..74e275b 100644 --- a/include/c/DefaultSolver.h +++ b/include/c/DefaultSolver.h @@ -58,37 +58,101 @@ static inline ClarabelDefaultSolver *clarabel_DefaultSolver_new(const ClarabelCs } #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); +// DefaultSolver::load_from_file +ClarabelDefaultSolver_f64 *clarabel_DefaultSolver_f64_load_from_file(const char *filename); +ClarabelDefaultSolver_f32 *clarabel_DefaultSolver_f32_load_from_file(const char *filename); #ifdef CLARABEL_USE_FLOAT - static inline ClarabelDefaultSolver *clarabel_DefaultSolver_read_from_file(const char *filename) + static inline ClarabelDefaultSolver *clarabel_DefaultSolver_load_from_file(const char *filename) { - return clarabel_DefaultSolver_f32_read_from_file(filename); + return clarabel_DefaultSolver_f32_load_from_file(filename); } #else - static inline ClarabelDefaultSolver *clarabel_DefaultSolver_read_from_file(const char *filename) + static inline ClarabelDefaultSolver *clarabel_DefaultSolver_load_from_file(const char *filename) { - return clarabel_DefaultSolver_f64_read_from_file(filename); + return clarabel_DefaultSolver_f64_load_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); +// DefaultSolver::save_to_file +void clarabel_DefaultSolver_f64_save_to_file(ClarabelDefaultSolver_f64 *solver, const char *filename); +void clarabel_DefaultSolver_f32_save_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) + static inline void clarabel_DefaultSolver_save_to_file(ClarabelDefaultSolver *solver, const char *filename) { - clarabel_DefaultSolver_f32_write_to_file(solver,filename); + clarabel_DefaultSolver_f32_save_to_file(solver,filename); } #else - static inline void clarabel_DefaultSolver_write_to_file(ClarabelDefaultSolver *solver, const char *filename) + static inline void clarabel_DefaultSolver_save_to_file(ClarabelDefaultSolver *solver, const char *filename) { - clarabel_DefaultSolver_f64_write_to_file(solver,filename); + clarabel_DefaultSolver_f64_save_to_file(solver,filename); } #endif // CLARABEL_USE_FLOAT #endif // FEATURE_SERDE +// DefaultSolver::print_to_stdout +void clarabel_DefaultSolver_f64_print_to_stdout(ClarabelDefaultSolver_f64 *solver); +void clarabel_DefaultSolver_f32_print_to_stdout(ClarabelDefaultSolver_f32 *solver); +#ifdef CLARABEL_USE_FLOAT + static inline void clarabel_DefaultSolver_print_to_stdout(ClarabelDefaultSolver *solver) + { + clarabel_DefaultSolver_f32_print_to_stdout(solver); + } +#else + static inline void clarabel_DefaultSolver_print_to_stdout(ClarabelDefaultSolver *solver) + { + clarabel_DefaultSolver_f64_print_to_stdout(solver); + } +#endif // CLARABEL_USE_FLOAT + +// DefaultSolver::print_to_file +void clarabel_DefaultSolver_f64_print_to_file(ClarabelDefaultSolver_f64 *solver, const char *filename); +void clarabel_DefaultSolver_f32_print_to_file(ClarabelDefaultSolver_f32 *solver, const char *filename); +#ifdef CLARABEL_USE_FLOAT + static inline void clarabel_DefaultSolver_print_to_file(ClarabelDefaultSolver *solver, const char *filename) + { + clarabel_DefaultSolver_f32_print_to_file(solver, const char *filename); + } +#else + static inline void clarabel_DefaultSolver_print_to_file(ClarabelDefaultSolver *solver, const char *filename) + { + clarabel_DefaultSolver_f64_print_to_file(solver, filename); + } +#endif // CLARABEL_USE_FLOAT + +// DefaultSolver::print_to_buffer +void clarabel_DefaultSolver_f64_print_to_buffer(ClarabelDefaultSolver_f64 *solver); +void clarabel_DefaultSolver_f32_print_to_buffer(ClarabelDefaultSolver_f32 *solver); +#ifdef CLARABEL_USE_FLOAT + static inline void clarabel_DefaultSolver_print_to_buffer(ClarabelDefaultSolver *solver) + { + clarabel_DefaultSolver_f32_print_to_buffer(solver); + } +#else + static inline void clarabel_DefaultSolver_print_to_buffer(ClarabelDefaultSolver *solver) + { + clarabel_DefaultSolver_f64_print_to_buffer(solver); + } +#endif // CLARABEL_USE_FLOAT + +// DefaultSolver::print_to_buffer +// NB: The buffer is owned by rust and should not be freed by the C side caller. +// Call clarabel_free_print_buffer to free the buffer. Failure to do so will +// result in a memory leak. +const char* clarabel_DefaultSolver_f64_get_print_buffer(ClarabelDefaultSolver_f64 *solver); +const char* clarabel_DefaultSolver_f32_get_print_buffer(ClarabelDefaultSolver_f32 *solver); +void clarabel_free_print_buffer(const char* buffer); + +#ifdef CLARABEL_USE_FLOAT + static inline const char* clarabel_DefaultSolver_get_print_buffer(ClarabelDefaultSolver *solver) + { + return clarabel_DefaultSolver_f32_get_print_buffer(solver); + } + #else +static inline const char* clarabel_DefaultSolver_get_print_buffer(ClarabelDefaultSolver *solver) + { + return clarabel_DefaultSolver_f64_get_print_buffer(solver); + } +#endif // CLARABEL_USE_FLOAT // DefaultSolver::solve diff --git a/include/cpp/DefaultInfo.h b/include/cpp/DefaultInfo.h index 6919750..162d1a9 100644 --- a/include/cpp/DefaultInfo.h +++ b/include/cpp/DefaultInfo.h @@ -28,6 +28,7 @@ struct DefaultInfo T ktratio; double solve_time; clarabel::SolverStatus status; + // NB : `PrintStream stream` not passed to C++ API }; // Instantiate the templates diff --git a/include/cpp/DefaultSolver.h b/include/cpp/DefaultSolver.h index 7f298d3..8ea124c 100644 --- a/include/cpp/DefaultSolver.h +++ b/include/cpp/DefaultSolver.h @@ -150,10 +150,16 @@ class DefaultSolver // 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); + void save_to_file(const std::string &filename); + static DefaultSolver load_from_file(const std::string &filename); #endif + // print stream configurations + void print_to_stdout(); + void print_to_file(const std::string &filename); + void print_to_buffer(); + std::string get_print_buffer(); + }; template @@ -244,14 +250,25 @@ void clarabel_DefaultSolver_f64_update_b_partial(RustDefaultSolverHandle_f64 sol 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); +void clarabel_DefaultSolver_f64_save_to_file(RustDefaultSolverHandle_f64 solver, const char *filename); +void clarabel_DefaultSolver_f32_save_to_file(RustDefaultSolverHandle_f32 solver, const char *filename); +RustDefaultSolverHandle_f64 clarabel_DefaultSolver_f64_load_from_file( const char *filename); +RustDefaultSolverHandle_f32 clarabel_DefaultSolver_f32_load_from_file( const char *filename); #endif +void clarabel_DefaultSolver_f64_print_to_stdout(RustDefaultSolverHandle_f64 solver); +void clarabel_DefaultSolver_f32_print_to_stdout(RustDefaultSolverHandle_f32 solver); +void clarabel_DefaultSolver_f64_print_to_file(RustDefaultSolverHandle_f64 solver, const char *filename); +void clarabel_DefaultSolver_f32_print_to_file(RustDefaultSolverHandle_f32 solver, const char *filename); +void clarabel_DefaultSolver_f64_print_to_buffer(RustDefaultSolverHandle_f64 solver); +void clarabel_DefaultSolver_f32_print_to_buffer(RustDefaultSolverHandle_f32 solver); +const char* clarabel_DefaultSolver_f64_get_print_buffer(RustDefaultSolverHandle_f64 solver); +const char* clarabel_DefaultSolver_f32_get_print_buffer(RustDefaultSolverHandle_f32 solver); +void clarabel_free_print_buffer(const char *s); + +} // extern "C" + -} // Convert unique_ptr P, A to CscMatrix objects, then init the solver // The CscMatrix objects are only used to pass the information needed to Rust. @@ -584,26 +601,67 @@ inline void DefaultSolver::update_b(const uintptr_t* index, const float * #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()); +inline void DefaultSolver::save_to_file(const std::string &filename){ + clarabel_DefaultSolver_f64_save_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()); +inline void DefaultSolver::save_to_file(const std::string &filename){ + clarabel_DefaultSolver_f32_save_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()); +inline DefaultSolver DefaultSolver::load_from_file(const std::string &filename){ + RustDefaultSolverHandle_f64 handle = clarabel_DefaultSolver_f64_load_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()); +inline DefaultSolver DefaultSolver::load_from_file(const std::string &filename){ + RustDefaultSolverHandle_f32 handle = clarabel_DefaultSolver_f32_load_from_file(filename.c_str()); return DefaultSolver(handle); } #endif // FEATURE_SERDE +// print configurations + +template<> +inline void DefaultSolver::print_to_stdout(){ + clarabel_DefaultSolver_f64_print_to_stdout(this->handle); +} +template<> +inline void DefaultSolver::print_to_stdout(){ + clarabel_DefaultSolver_f32_print_to_stdout(this->handle); +} +template<> +inline void DefaultSolver::print_to_file(const std::string &filename){ + clarabel_DefaultSolver_f64_print_to_file(this->handle, filename.c_str()); +} +template<> +inline void DefaultSolver::print_to_file(const std::string &filename){ + clarabel_DefaultSolver_f32_print_to_file(this->handle, filename.c_str()); +} +template<> +inline void DefaultSolver::print_to_buffer(){ + clarabel_DefaultSolver_f64_print_to_buffer(this->handle); +} +template<> +inline void DefaultSolver::print_to_buffer(){ + clarabel_DefaultSolver_f32_print_to_buffer(this->handle); +} +template<> +inline std::string DefaultSolver::get_print_buffer(){ + const char* buffer = clarabel_DefaultSolver_f64_get_print_buffer(this->handle); + std::string str(buffer); + clarabel_free_print_buffer(buffer); + return str; +} +template<> +inline std::string DefaultSolver::get_print_buffer(){ + const char* buffer = clarabel_DefaultSolver_f32_get_print_buffer(this->handle); + std::string str(buffer); + clarabel_free_print_buffer(buffer); + return str; +} + } // namespace clarabel \ No newline at end of file diff --git a/rust_wrapper/src/solver/implementations/default/solver.rs b/rust_wrapper/src/solver/implementations/default/solver.rs index 2e81862..bf31b71 100644 --- a/rust_wrapper/src/solver/implementations/default/solver.rs +++ b/rust_wrapper/src/solver/implementations/default/solver.rs @@ -2,6 +2,8 @@ #![allow(non_camel_case_types)] +use std::ffi::c_char; +use clarabel::io::*; use crate::algebra::ClarabelCscMatrix; use crate::core::cones::ClarabelSupportedConeT; use crate::solver::implementations::default::settings::*; @@ -13,7 +15,6 @@ 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; } @@ -158,8 +159,107 @@ pub unsafe extern "C" fn clarabel_DefaultSolver_f32_free(solver: *mut ClarabelDe _internal_DefaultSolver_free::(solver); } +fn _internal_DefaultSolver_print_to_stdout(solver: *mut c_void) +where T: FloatT, +{ + // Recover the solver object from the opaque pointer + let solver = unsafe { &mut *(solver as *mut lib::DefaultSolver) }; + + // Use the recovered solver object + solver.print_to_stdout(); +} + +#[no_mangle] +pub unsafe extern "C" fn clarabel_DefaultSolver_f64_print_to_stdout(solver: *mut ClarabelDefaultSolver_f64) { + _internal_DefaultSolver_print_to_stdout::(solver); +} + +#[no_mangle] +pub unsafe extern "C" fn clarabel_DefaultSolver_f32_print_to_stdout(solver: *mut ClarabelDefaultSolver_f32) { + _internal_DefaultSolver_print_to_stdout::(solver); +} + +fn _internal_DefaultSolver_print_to_file(solver: *mut c_void, filename: *const c_char) +where T: FloatT, +{ + if filename.is_null() { + return; + } + let filename = unsafe{std::ffi::CStr::from_ptr(filename).to_str().expect("Invalid filename")}; + let file = std::fs::File::create(filename).expect("File not found"); + + // Recover the solver object from the opaque pointer + let solver = unsafe { &mut *(solver as *mut lib::DefaultSolver) }; + + // Use the recovered solver object + solver.print_to_file(file); +} + +#[no_mangle] +pub unsafe extern "C" fn clarabel_DefaultSolver_f64_print_to_file(solver: *mut ClarabelDefaultSolver_f64, filename: *const c_char) { + _internal_DefaultSolver_print_to_file::(solver,filename); +} + +#[no_mangle] +pub unsafe extern "C" fn clarabel_DefaultSolver_f32_print_to_file(solver: *mut ClarabelDefaultSolver_f32, filename: *const c_char) { + _internal_DefaultSolver_print_to_file::(solver,filename); +} + + +fn _internal_DefaultSolver_print_to_buffer(solver: *mut c_void) +where T: FloatT, +{ + // Recover the solver object from the opaque pointer + let solver = unsafe { &mut *(solver as *mut lib::DefaultSolver) }; + + // Use the recovered solver object + solver.print_to_buffer(); +} + +#[no_mangle] +pub unsafe extern "C" fn clarabel_DefaultSolver_f64_print_to_buffer(solver: *mut ClarabelDefaultSolver_f64) { + _internal_DefaultSolver_print_to_buffer::(solver); +} + +#[no_mangle] +pub unsafe extern "C" fn clarabel_DefaultSolver_f32_print_to_buffer(solver: *mut ClarabelDefaultSolver_f32) { + _internal_DefaultSolver_print_to_buffer::(solver); +} + +fn _internal_DefaultSolver_get_from_buffer(solver: *mut c_void) -> *const c_char +where T: FloatT, +{ + // Recover the solver object from the opaque pointer + let solver = unsafe { &mut *(solver as *mut lib::DefaultSolver) }; + let out = solver.get_print_buffer().unwrap_or("".to_string()); + let c_str = std::ffi::CString::new(out).unwrap(); + // Return the string as a raw pointer. It must be returned to + // rust to freed here. Can't call free from C on it. + c_str.into_raw() +} + +#[no_mangle] +pub unsafe extern "C" fn clarabel_DefaultSolver_f64_get_print_buffer(solver: *mut ClarabelDefaultSolver_f64) -> *const c_char { + _internal_DefaultSolver_get_from_buffer::(solver) +} + +#[no_mangle] +pub unsafe extern "C" fn clarabel_DefaultSolver_f32_get_print_buffer(solver: *mut ClarabelDefaultSolver_f32) -> *const c_char { + _internal_DefaultSolver_get_from_buffer::(solver) +} + +#[no_mangle] +pub unsafe extern "C" fn clarabel_free_print_buffer(ptr: *const c_char){ + // This function should be called from C to free the memory of the string + // returned by get_from_buffer. + unsafe { + let _ = std::ffi::CString::from_raw(ptr as *mut c_char); + } +} + + #[cfg(feature = "serde")] -pub unsafe fn _internal_DefaultSolver_read_from_file( +pub unsafe fn _internal_DefaultSolver_load_from_file( filename: *const c_char, settings: *const ClarabelDefaultSettings, ) @@ -173,17 +273,17 @@ where T: FloatT + DeserializeOwned + Serialize, let mut file = std::fs::File::open(filename).expect("File not found"); let solver = if settings.is_null() { - lib::DefaultSolver::::read_from_file(&mut file, None) + lib::DefaultSolver::::load_from_file(&mut file, None) } else { let settings_struct = &*(settings); let settings = utils::get_solver_settings_from_c::(settings_struct); - lib::DefaultSolver::::read_from_file(&mut file, Some(settings)) + lib::DefaultSolver::::load_from_file(&mut file, Some(settings)) }; 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) +fn _internal_DefaultSolver_save_to_file(solver: *mut c_void, filename: *const c_char) where T: FloatT + DeserializeOwned + Serialize, { if filename.is_null() { @@ -196,40 +296,39 @@ where T: FloatT + DeserializeOwned + Serialize, let solver = unsafe { &mut *(solver as *mut lib::DefaultSolver) }; // Use the recovered solver object - solver.write_to_file(&mut file).unwrap(); - + solver.save_to_file(&mut file).unwrap(); } #[no_mangle] #[cfg(feature = "serde")] -pub unsafe extern "C" fn clarabel_DefaultSolver_f64_read_from_file( +pub unsafe extern "C" fn clarabel_DefaultSolver_f64_load_from_file( filename: *const c_char, settings: *const ClarabelDefaultSettings, ) -> *mut ClarabelDefaultSolver_f64 { - _internal_DefaultSolver_read_from_file::(filename,settings) + _internal_DefaultSolver_load_from_file::(filename,settings) } #[no_mangle] #[cfg(feature = "serde")] -pub unsafe extern "C" fn clarabel_DefaultSolver_f32_read_from_file( +pub unsafe extern "C" fn clarabel_DefaultSolver_f32_load_from_file( filename: *const c_char, settings: *const ClarabelDefaultSettings, ) -> *mut ClarabelDefaultSolver_f32 { - _internal_DefaultSolver_read_from_file::(filename,settings) + _internal_DefaultSolver_load_from_file::(filename,settings) } #[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); +pub extern "C" fn clarabel_DefaultSolver_f64_save_to_file(solver: *mut ClarabelDefaultSolver_f64,filename: *const c_char) { + _internal_DefaultSolver_save_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); +pub extern "C" fn clarabel_DefaultSolver_f32_save_to_file(solver: *mut ClarabelDefaultSolver_f32,filename: *const c_char) { + _internal_DefaultSolver_save_to_file::(solver,filename); }