Skip to content

Instantly share code, notes, and snippets.

@alphaville
Last active September 24, 2019 18:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alphaville/78535a806e7ebe6c53573a6275275d15 to your computer and use it in GitHub Desktop.
Save alphaville/78535a806e7ebe6c53573a6275275d15 to your computer and use it in GitHub Desktop.
Memory allocator in C for Optimization Engine
#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;
}
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");
}
//! # 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