Last active
September 24, 2019 18:53
-
-
Save alphaville/78535a806e7ebe6c53573a6275275d15 to your computer and use it in GitHub Desktop.
Memory allocator in C for Optimization Engine
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#ifndef casadi_real | |
#define casadi_real double | |
#endif | |
#ifndef casadi_int | |
#define casadi_int long long int | |
#endif | |
#define TRUE 1 | |
#define FALSE 0 | |
extern int phi_JjQKKsHwhykwQwMSTKKI_work( | |
casadi_int *sz_arg, | |
casadi_int *sz_res, | |
casadi_int *sz_iw, | |
casadi_int *sz_w); | |
extern int grad_phi_JjQKKsHwhykwQwMSTKKI_work( | |
casadi_int *sz_arg, | |
casadi_int *sz_res, | |
casadi_int *sz_iw, | |
casadi_int *sz_w); | |
static char is_allocated = FALSE; | |
static casadi_int *allocated_i_workspace_cost; | |
static casadi_real *allocated_r_workspace_cost; | |
static casadi_int *allocated_i_workspace_grad; | |
static casadi_real *allocated_r_workspace_grad; | |
/* returns 0 if the allocation of memory was successful */ | |
static int allocate_if_not_yet() { | |
/* Sizes for cost function */ | |
casadi_int sz_arg_cost = 0; | |
casadi_int sz_res_cost = 0; | |
casadi_int sz_iw_cost = 0; | |
casadi_int sz_w_cost = 0; | |
/* Sizes for gradient */ | |
casadi_int sz_arg_grad = 0; | |
casadi_int sz_res_grad = 0; | |
casadi_int sz_iw_grad = 0; | |
casadi_int sz_w_grad = 0; | |
/* Obtain sizes */ | |
phi_JjQKKsHwhykwQwMSTKKI_work(&sz_arg_cost, &sz_res_cost, &sz_iw_cost, &sz_w_cost); | |
grad_phi_JjQKKsHwhykwQwMSTKKI_work(&sz_arg_grad, &sz_res_grad, &sz_iw_grad, &sz_w_grad); | |
printf("cost = (%lld, %lld, %lld, %lld)", sz_arg_cost, sz_res_cost, sz_iw_cost, sz_w_cost); | |
/* Allocate memory, if not allocated before */ | |
if (!is_allocated) { | |
/* Allocate memory for cost function */ | |
allocated_i_workspace_cost = (casadi_int*)malloc(sz_iw_cost*sizeof(casadi_int)); | |
if (allocated_i_workspace_cost == NULL) goto fail_1; | |
allocated_r_workspace_cost = (casadi_real*)malloc(sz_w_cost*sizeof(casadi_real)); | |
if (allocated_r_workspace_cost == NULL) goto fail_2; | |
/* Allocate memory for gradient */ | |
allocated_i_workspace_grad = (casadi_int*)malloc(sz_iw_grad*sizeof(casadi_int)); | |
if (allocated_i_workspace_grad == NULL) goto fail_3; | |
allocated_r_workspace_grad = (casadi_real*)malloc(sz_w_grad*sizeof(casadi_real)); | |
if (allocated_r_workspace_grad == NULL) goto fail_4; | |
} | |
return 0; | |
/* Free memory that has been previously allocated (failure!) */ | |
fail_4: | |
free(allocated_i_workspace_grad); | |
fail_3: | |
free(allocated_r_workspace_cost); | |
fail_2: | |
free(allocated_i_workspace_cost); | |
fail_1: | |
return 1; | |
} | |
int init_JjQKKsHwhykwQwMSTKKI() { | |
if (!is_allocated){ | |
return allocate_if_not_yet(); | |
} | |
return 0; | |
} | |
int destroy_JjQKKsHwhykwQwMSTKKI() { | |
return 0; | |
} | |
casadi_int * allocated_JjQKKsHwhykwQwMSTKKI_iwork() { | |
if (!is_allocated) allocate_if_not_yet(); | |
return allocated_i_workspace_cost; | |
} | |
casadi_real * allocated_JjQKKsHwhykwQwMSTKKI_work() { | |
if (!is_allocated) allocate_if_not_yet(); | |
return allocated_r_workspace_cost; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use cc; | |
use std::path::Path; | |
fn main() { | |
// Sanity checks to get better error messages | |
assert!( | |
Path::new("extern/auto_casadi_constraints_type_penalty.c").exists(), | |
"extern/auto_casadi_mapping_f1.c is missing" | |
); | |
assert!( | |
Path::new("extern/auto_casadi_constraints_type_penalty.c").exists(), | |
"extern/auto_casadi_constraints_type_penalty.c is missing" | |
); | |
assert!( | |
Path::new("extern/auto_casadi_cost.c").exists(), | |
"extern/auto_casadi_cost.c is missing" | |
); | |
assert!( | |
Path::new("extern/auto_casadi_grad.c").exists(), | |
"extern/auto_casadi_grad.c is missing" | |
); | |
cc::Build::new() | |
.flag_if_supported("-Wall") | |
.flag_if_supported("-Wpedantic") | |
.flag_if_supported("-Wno-long-long") | |
.flag_if_supported("-Wno-unused-parameter") | |
.pic(true) | |
.include("src") | |
.file("extern/auto_casadi_cost.c") | |
.file("extern/auto_casadi_grad.c") | |
.file("extern/auto_casadi_constraints_type_penalty.c") | |
.file("extern/auto_casadi_mapping_f1.c") | |
.file("extern/icallocator.c") | |
.compile("icasadi"); | |
// Rerun if these autogenerated files change | |
println!("cargo:rerun-if-changed=extern/icallocator.c"); | |
println!("cargo:rerun-if-changed=extern/auto_casadi_cost.c"); | |
println!("cargo:rerun-if-changed=extern/auto_casadi_grad.c"); | |
println!("cargo:rerun-if-changed=extern/auto_casadi_constraints_type_penalty.c"); | |
println!("cargo:rerun-if-changed=extern/auto_casadi_mapping_f1.c"); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! # CasADi Rust interface | |
//! | |
//! This is a Rust interface to CasADi C functions. | |
//! | |
//! This is a `no-std` library (however, mind that the CasADi-generated code | |
//! requires `libm` to call math functions such as `sqrt`, `sin`, etc...) | |
//! | |
//! --- | |
//! | |
//! Auto-generated header file | |
//! This file is part of OptimizationEngine | |
//! (see https://alphaville.github.io/optimization-engine/) | |
//! | |
//! Generated at: 2019-09-24 18:53:07.045414 | |
//! | |
// We can't use no_std... | |
#![no_std] | |
/// Number of static parameters (this also includes penalty constraints) | |
pub const NUM_STATIC_PARAMETERS: usize = 4; | |
/// Number of decision variables | |
pub const NUM_DECISION_VARIABLES: usize = 5; | |
/// Number of ALM-type constraints (dimension of F1, i.e., n1) | |
pub const NUM_CONSTRAINTS_TYPE_ALM: usize = 5; | |
/// Number of penalty constraints (dimension of F2, i.e., n2) | |
pub const NUM_CONSTAINTS_TYPE_PENALTY: usize = 2; | |
use libc::{c_double, c_int, c_longlong, c_void}; | |
/// C interface (Function API exactly as provided by CasADi) | |
extern "C" { | |
// ----------------------------------------------------------- | |
// Main External (C) functions | |
// ----------------------------------------------------------- | |
/// Cost function, f(u, p), generated by CasADi | |
/// | |
/// | |
/// ## Arguments | |
/// | |
/// - `arg`: function arguemnts (u and p) | |
/// - `casadi_results`: | |
/// - `iw`: integer workspace (here: empty) | |
/// - `w`: workspace (here: empty) | |
/// - `mem`: memory (here, 0) | |
fn phi_JjQKKsHwhykwQwMSTKKI( | |
arg: *const *const c_double, | |
casadi_results: *mut *mut c_double, | |
iw: *mut c_longlong, | |
w: *mut c_double, | |
mem: *mut c_void, | |
) -> c_int; | |
/// Gradient of the cost function, Df(u, p), generated by CasADi | |
/// | |
/// | |
/// ## Arguments | |
/// | |
/// - `arg`: function arguemnts (u and p) | |
/// - `casadi_results`: | |
/// - `iw`: integer workspace (here: empty) | |
/// - `w`: workspace (here: empty) | |
/// - `mem`: memory (here, 0) | |
fn grad_phi_JjQKKsHwhykwQwMSTKKI( | |
arg: *const *const c_double, | |
casadi_results: *mut *mut c_double, | |
iw: *mut c_longlong, | |
w: *mut c_double, | |
mem: *mut c_void, | |
) -> c_int; | |
/// Penalty-related mapping, F1(u, p), generated by CasADi | |
/// | |
/// | |
/// ## Arguments | |
/// | |
/// - `arg`: function arguemnts (u and p) | |
/// - `casadi_results`: | |
/// - `iw`: integer workspace (here: empty) | |
/// - `w`: workspace (here: empty) | |
/// - `mem`: memory (here, 0) | |
fn mapping_f1_JjQKKsHwhykwQwMSTKKI( | |
arg: *const *const c_double, | |
casadi_results: *mut *mut c_double, | |
iw: *mut c_longlong, | |
w: *mut c_double, | |
mem: *mut c_void, | |
) -> c_int; | |
/// Penalty-related mapping, F2(u, p), generated by CasADi | |
/// | |
/// | |
/// ## Arguments | |
/// | |
/// - `arg`: function arguemnts (u and p) | |
/// - `casadi_results`: | |
/// - `iw`: integer workspace (here: empty) | |
/// - `w`: workspace (here: empty) | |
/// - `mem`: memory (here, 0) | |
fn mapping_f2_JjQKKsHwhykwQwMSTKKI( | |
arg: *const *const c_double, | |
casadi_results: *mut *mut c_double, | |
iw: *mut c_longlong, | |
w: *mut c_double, | |
mem: *mut c_void, | |
) -> c_int; | |
// ----------------------------------------------------------- | |
// Workspace Length External (C) functions | |
// ----------------------------------------------------------- | |
/// Workspace lengths of cost function | |
fn allocated_JjQKKsHwhykwQwMSTKKI_iwork() -> *mut c_longlong; | |
fn allocated_JjQKKsHwhykwQwMSTKKI_work() -> *mut c_double; | |
fn init_JjQKKsHwhykwQwMSTKKI() -> c_int; | |
} // END of extern C | |
// Initialisation | |
pub fn init() -> i32 { | |
unsafe { | |
return init_JjQKKsHwhykwQwMSTKKI(); | |
} | |
} | |
// ----------------------------------------------------------- | |
// *MAIN* API Functions in Rust | |
// ----------------------------------------------------------- | |
/// | |
/// Consume the cost function written in C | |
/// | |
/// # Example | |
/// | |
/// ```ignore | |
/// fn tst_call_casadi_cost() { | |
/// let u = [1.0, 2.0, 3.0, -5.0, 1.0, 10.0, 14.0, 17.0, 3.0, 5.0]; | |
/// let p = [1.0, -1.0]; | |
/// let mut cost_value = 0.0; | |
/// icasadi::cost(&u, &p, &mut cost_value); | |
/// } | |
/// ``` | |
/// | |
/// # Panics | |
/// This method panics if the following conditions are not satisfied | |
/// | |
/// - `u.len() == NUM_DECISION_VARIABLES` | |
/// - `static_params.len() == NUM_STATIC_PARAMETERS` | |
/// | |
pub fn cost(u: &[f64], static_params: &[f64], cost_value: &mut f64) -> i32 { | |
assert_eq!(u.len(), NUM_DECISION_VARIABLES); | |
assert_eq!(static_params.len(), NUM_STATIC_PARAMETERS); | |
let arguments = &[u.as_ptr(), static_params.as_ptr()]; | |
let cost = &mut [cost_value as *mut c_double]; | |
unsafe { | |
phi_JjQKKsHwhykwQwMSTKKI( | |
arguments.as_ptr(), | |
cost.as_mut_ptr(), | |
allocated_JjQKKsHwhykwQwMSTKKI_iwork(), | |
allocated_JjQKKsHwhykwQwMSTKKI_work(), | |
0 as *mut c_void, | |
) as i32 | |
} | |
} | |
/// | |
/// Consume the Jacobian function written in C | |
/// | |
/// # Example | |
/// | |
/// ```ignore | |
/// fn tst_call_casadi_cost() { | |
/// let u = [1.0, 2.0, 3.0, -5.0, 1.0, 10.0, 14.0, 17.0, 3.0, 5.0]; | |
/// let p = [1.0, -1.0]; | |
/// let mut jac = [0.0; 10]; | |
/// icasadi::grad(&u, &p, &mut jac); | |
/// } | |
/// ``` | |
/// | |
/// # Panics | |
/// This method panics if the following conditions are not satisfied | |
/// | |
/// - `u.len() == icasadi::num_decision_variables()` | |
/// - `static_params.len() == icasadi::num_static_parameters()` | |
/// - `cost_jacobian.len() == icasadi::num_decision_variables()` | |
/// | |
pub fn grad(u: &[f64], static_params: &[f64], cost_jacobian: &mut [f64]) -> i32 { | |
assert_eq!(u.len(), NUM_DECISION_VARIABLES); | |
assert_eq!(cost_jacobian.len(), NUM_DECISION_VARIABLES); | |
assert_eq!(static_params.len(), NUM_STATIC_PARAMETERS); | |
let arguments = &[u.as_ptr(), static_params.as_ptr()]; | |
let grad = &mut [cost_jacobian.as_mut_ptr()]; | |
unsafe { | |
grad_phi_JjQKKsHwhykwQwMSTKKI( | |
arguments.as_ptr(), | |
grad.as_mut_ptr(), | |
0 as *mut c_longlong, | |
0 as *mut c_double, | |
0 as *mut c_void, | |
) as i32 | |
} | |
} | |
/// Consume mapping F1, which has been generated by CasADi | |
/// | |
/// This is a wrapper function | |
/// | |
/// ## Arguments | |
/// | |
/// - `u`: (in) decision variables | |
/// - `p`: (in) vector of parameters | |
/// - `f1`: (out) value F2(u, p) | |
/// | |
/// ## Returns | |
/// | |
/// Returns `0` iff the computation is successful | |
/// | |
pub fn mapping_f1(u: &[f64], static_params: &[f64], f1: &mut [f64]) -> i32 { | |
assert_eq!(u.len(), NUM_DECISION_VARIABLES); | |
assert_eq!(static_params.len(), NUM_STATIC_PARAMETERS); | |
assert!(f1.len() == NUM_CONSTAINTS_TYPE_PENALTY || NUM_CONSTAINTS_TYPE_PENALTY == 0); | |
let arguments = &[u.as_ptr(), static_params.as_ptr()]; | |
let constraints = &mut [f1.as_mut_ptr()]; | |
unsafe { | |
mapping_f1_JjQKKsHwhykwQwMSTKKI( | |
arguments.as_ptr(), | |
constraints.as_mut_ptr(), | |
0 as *mut c_longlong, | |
0 as *mut c_double, | |
0 as *mut c_void, | |
) as i32 | |
} | |
} | |
/// Consume mapping F2, which has been generated by CasADi | |
/// | |
/// This is a wrapper function | |
/// | |
/// ## Arguments | |
/// | |
/// - `u`: (in) decision variables | |
/// - `p`: (in) vector of parameters | |
/// - `f2`: (out) value F2(u, p) | |
/// | |
/// ## Returns | |
/// | |
/// Returns `0` iff the computation is successful | |
pub fn mapping_f2(u: &[f64], static_params: &[f64], f2: &mut [f64]) -> i32 { | |
assert_eq!(u.len(), NUM_DECISION_VARIABLES); | |
assert_eq!(static_params.len(), NUM_STATIC_PARAMETERS); | |
assert!(f2.len() == NUM_CONSTAINTS_TYPE_PENALTY || NUM_CONSTAINTS_TYPE_PENALTY == 0); | |
let arguments = &[u.as_ptr(), static_params.as_ptr()]; | |
let constraints = &mut [f2.as_mut_ptr()]; | |
unsafe { | |
mapping_f2_JjQKKsHwhykwQwMSTKKI( | |
arguments.as_ptr(), | |
constraints.as_mut_ptr(), | |
0 as *mut c_longlong, | |
0 as *mut c_double, | |
0 as *mut c_void, | |
) as i32 | |
} | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn tst_num_static() { | |
let _np = NUM_STATIC_PARAMETERS; | |
} | |
#[test] | |
fn tst_num_decision_var() { | |
let _nu = NUM_DECISION_VARIABLES; | |
} | |
#[test] | |
fn tst_initialize() { | |
assert_eq!(0, init()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment