From d5f60a0b7f2ae2c80de3bd839c80f3e662f3815a Mon Sep 17 00:00:00 2001 From: Kieranoski Date: Wed, 1 Nov 2023 14:41:20 +0000 Subject: [PATCH 1/4] Add wrappers for basic chuffed functions in lib.rs. Recreate example/template.cpp in main.rs using wrapper functions. Update wrapper.h with ffi hacks and add wrapper.cpp. Update build.rs, build.sh and clean.sh accordingly --- solvers/chuffed/build.rs | 11 +++++++ solvers/chuffed/build.sh | 7 ++++- solvers/chuffed/clean.sh | 2 ++ solvers/chuffed/compile_flags.txt | 3 ++ solvers/chuffed/src/lib.rs | 42 +++++++++++++++++++++++++++ solvers/chuffed/src/main.rs | 48 +++++++++++++++++++++++++++---- solvers/chuffed/wrapper.cpp | 15 ++++++++++ solvers/chuffed/wrapper.h | 22 ++++++++++++++ 8 files changed, 143 insertions(+), 7 deletions(-) create mode 100644 solvers/chuffed/compile_flags.txt create mode 100644 solvers/chuffed/wrapper.cpp diff --git a/solvers/chuffed/build.rs b/solvers/chuffed/build.rs index 38f82ea62d..8ce1765783 100644 --- a/solvers/chuffed/build.rs +++ b/solvers/chuffed/build.rs @@ -16,6 +16,8 @@ fn main() { println!("cargo:rustc-link-search=all=./solvers/chuffed/vendor/build/"); println!("cargo:rustc-link-lib=static=chuffed"); println!("cargo:rustc-link-lib=static=chuffed_fzn"); + println!("cargo:rustc-link-search=all=./solvers/chuffed/"); + println!("cargo:rustc-link-lib=static=wrapper"); // also need to (dynamically) link to c++ stdlib // https://flames-of-code.netlify.app/blog/rust-and-cmake-cplusplus/ @@ -64,6 +66,15 @@ fn bind() { // in C++ stdlib that will make it crash. .allowlist_function("createVars") .allowlist_function("createVar") + .allowlist_function("all_different") + .allowlist_function("branch") + .allowlist_function("output_vars") + .allowlist_function("var_sym_break") + .allowlist_function("new_dummy_problem") + .allowlist_function("get_idx") + .allowlist_function("p_addVars") + .allowlist_function("p_setcallback") + .allowlist_function("branch_IntVar") .clang_arg("-Ivendor/build") // generated from configure.py .clang_arg("-Ivendor") .clang_arg(r"--std=gnu++11") diff --git a/solvers/chuffed/build.sh b/solvers/chuffed/build.sh index 373916388e..fac03a10e1 100644 --- a/solvers/chuffed/build.sh +++ b/solvers/chuffed/build.sh @@ -4,9 +4,14 @@ SCRIPT_DIR=$(dirname "$0") git submodule init git submodule update -cd "$SCRIPT_DIR" +cd "$SCRIPT_DIR" || exit echo "------ BUILDING ------" cd vendor || exit cmake -B build -S . cmake --build build +cd .. + +# Build wrapper.cpp as static library +g++ -c wrapper.cpp -Ivendor +ar rvs libwrapper.a wrapper.o diff --git a/solvers/chuffed/clean.sh b/solvers/chuffed/clean.sh index e3a7382500..2873cb0737 100755 --- a/solvers/chuffed/clean.sh +++ b/solvers/chuffed/clean.sh @@ -2,3 +2,5 @@ cargo clean rm -rf vendor/build +rm libwrapper.a +rm wrapper.o diff --git a/solvers/chuffed/compile_flags.txt b/solvers/chuffed/compile_flags.txt new file mode 100644 index 0000000000..fd91cc6aea --- /dev/null +++ b/solvers/chuffed/compile_flags.txt @@ -0,0 +1,3 @@ +-I./vendor +-xc++ +--std=c++11 diff --git a/solvers/chuffed/src/lib.rs b/solvers/chuffed/src/lib.rs index 6a7b2eab1e..9e7155ff7e 100644 --- a/solvers/chuffed/src/lib.rs +++ b/solvers/chuffed/src/lib.rs @@ -4,3 +4,45 @@ pub mod bindings { #![allow(non_snake_case)] include!(concat!(env!("OUT_DIR"), "/chuffed_bindings.rs")); } + +pub mod wrappers{ + use crate::bindings::{IntVar, createVar, createVars, vec, all_different, ConLevel, VarBranch, branch_IntVar, ValBranch}; + use core::ptr; + + // The signature of createVar is below for reference. + // createVar(x: *mut *mut IntVar, min: ::std::os::raw::c_int, max: ::std::os::raw::c_int, el: bool) + pub fn create_var(min: i32, max: i32, el: bool) -> *mut IntVar { + let mut ptr: *mut IntVar = ptr::null_mut(); + + unsafe { + createVar(&mut ptr, min, max, el); + ptr + } + } + + // createVars void createVars(vec& x, int n, int min, int max, bool el) + pub fn create_vars(n: i32, min:i32, max:i32, el:bool) -> *mut vec<*mut IntVar> { + + let ptr: *mut vec<*mut IntVar> = ptr::null_mut(); + + unsafe { + createVars(ptr, n, min, max, el); + ptr + } + } + + // void all_different(vec& x, ConLevel cl) + pub unsafe fn all_different_wrapper(x: *mut vec<*mut IntVar>, cl: ConLevel) { + unsafe { + all_different(x, cl); + } + } + + // void branch(vec x, VarBranch var_branch, ValBranch val_branch); + pub unsafe fn branch_wrapper(x: *mut vec<*mut IntVar>, var_branch: VarBranch, val_branch: ValBranch) { + unsafe { + branch_IntVar(x, var_branch, val_branch); + } + } +} + diff --git a/solvers/chuffed/src/main.rs b/solvers/chuffed/src/main.rs index 9504a44a4d..2d80b10d7a 100644 --- a/solvers/chuffed/src/main.rs +++ b/solvers/chuffed/src/main.rs @@ -1,8 +1,44 @@ -use chuffed_rs::bindings::createVar; -use chuffed_rs::bindings::IntVar; -pub fn main() { - let mut var = std::mem::MaybeUninit::::uninit(); - unsafe { - createVar(&mut var.as_mut_ptr(), 0, 5, false); +use chuffed_rs::wrappers::{create_vars, all_different_wrapper, branch_wrapper}; +use chuffed_rs::bindings::{IntVar, ConLevel_CL_DEF, VarBranch_VAR_INORDER, VarBranch_VAR_MIN_MIN, vec, new_dummy_problem, get_idx, p_addVars, p_setcallback}; + +unsafe fn post_constraints(_n: i32) -> *mut vec<*mut IntVar> { + // Create constant + let n: i32 = _n; + // Create some variables + let x: *mut vec<*mut IntVar> = create_vars(n, 0, n, false); + + // Post some constraints + all_different_wrapper(x, ConLevel_CL_DEF); + + // Post some branchings + branch_wrapper(x as _, VarBranch_VAR_INORDER, VarBranch_VAR_MIN_MIN); + + x +} + +// Custom printing function for this problem +#[no_mangle] +pub unsafe extern "C" fn callback(x: *mut vec<*mut IntVar>) { + print!("First output is: {:?}", get_idx(x, 0)); +} + +fn main() { + let args: Vec = std::env::args().collect(); + + if args.len() != 2 { + println!("Invalid number of arguments"); + return; + } + + let n: i32 = args[1].parse().expect("Invalid input"); + + unsafe{ + let x = post_constraints(n); + // make new dummy problem + let p = new_dummy_problem(); + // Call problem.addvars() + p_addVars(p, x); + // Call problem.setcallback() + p_setcallback(p, Some(callback)); } } diff --git a/solvers/chuffed/wrapper.cpp b/solvers/chuffed/wrapper.cpp new file mode 100644 index 0000000000..87821d749c --- /dev/null +++ b/solvers/chuffed/wrapper.cpp @@ -0,0 +1,15 @@ +#include "./wrapper.h" + +DummyProblem *new_dummy_problem() { return new DummyProblem(); } +void p_addVars(DummyProblem *p, vec *_searchVars) { + p->addVars(_searchVars); +} +void p_setcallback(DummyProblem *p, void (*_callback)(vec *)) { + p->setcallback(_callback); +} +IntVar get_idx(vec *x, int i) { return **x[i]; } + +void branch_IntVar(vec *x, VarBranch var_branch, + ValBranch val_branch) { + branch(*x, var_branch, val_branch); +} diff --git a/solvers/chuffed/wrapper.h b/solvers/chuffed/wrapper.h index 9b073dbb12..78cf60e21f 100644 --- a/solvers/chuffed/wrapper.h +++ b/solvers/chuffed/wrapper.h @@ -1 +1,23 @@ +#include "chuffed/branching/branching.h" +#include "chuffed/core/engine.h" +#include "chuffed/core/propagator.h" #include "chuffed/vars/modelling.h" + +class DummyProblem { +public: + vec *searchVars; + // callback + void (*callback)(vec *); + + void print() { callback(searchVars); } + void setcallback(void (*_callback)(vec *)) { callback = _callback; } + void addVars(vec *_searchVars) { searchVars = _searchVars; } +}; + +DummyProblem *new_dummy_problem(); +void p_addVars(DummyProblem *p, vec *_searchVars); +void p_setcallback(DummyProblem *p, void (*_callback)(vec *)); +IntVar get_idx(vec *x, int i); + +void branch_IntVar(vec *x, VarBranch var_branch, + ValBranch val_branch); From 867a251596210e07810191aada32e6c6ec96305b Mon Sep 17 00:00:00 2001 From: Kieranoski Date: Wed, 1 Nov 2023 15:17:30 +0000 Subject: [PATCH 2/4] Run rustfmt on lib.rs and main.rs --- solvers/chuffed/src/lib.rs | 21 +++++++++++++-------- solvers/chuffed/src/main.rs | 15 +++++++++------ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/solvers/chuffed/src/lib.rs b/solvers/chuffed/src/lib.rs index 9e7155ff7e..0e55b61588 100644 --- a/solvers/chuffed/src/lib.rs +++ b/solvers/chuffed/src/lib.rs @@ -5,8 +5,11 @@ pub mod bindings { include!(concat!(env!("OUT_DIR"), "/chuffed_bindings.rs")); } -pub mod wrappers{ - use crate::bindings::{IntVar, createVar, createVars, vec, all_different, ConLevel, VarBranch, branch_IntVar, ValBranch}; +pub mod wrappers { + use crate::bindings::{ + all_different, branch_IntVar, createVar, createVars, vec, ConLevel, IntVar, ValBranch, + VarBranch, + }; use core::ptr; // The signature of createVar is below for reference. @@ -16,18 +19,17 @@ pub mod wrappers{ unsafe { createVar(&mut ptr, min, max, el); - ptr + ptr } } // createVars void createVars(vec& x, int n, int min, int max, bool el) - pub fn create_vars(n: i32, min:i32, max:i32, el:bool) -> *mut vec<*mut IntVar> { - + pub fn create_vars(n: i32, min: i32, max: i32, el: bool) -> *mut vec<*mut IntVar> { let ptr: *mut vec<*mut IntVar> = ptr::null_mut(); unsafe { createVars(ptr, n, min, max, el); - ptr + ptr } } @@ -39,10 +41,13 @@ pub mod wrappers{ } // void branch(vec x, VarBranch var_branch, ValBranch val_branch); - pub unsafe fn branch_wrapper(x: *mut vec<*mut IntVar>, var_branch: VarBranch, val_branch: ValBranch) { + pub unsafe fn branch_wrapper( + x: *mut vec<*mut IntVar>, + var_branch: VarBranch, + val_branch: ValBranch, + ) { unsafe { branch_IntVar(x, var_branch, val_branch); } } } - diff --git a/solvers/chuffed/src/main.rs b/solvers/chuffed/src/main.rs index 2d80b10d7a..c97ff07353 100644 --- a/solvers/chuffed/src/main.rs +++ b/solvers/chuffed/src/main.rs @@ -1,5 +1,8 @@ -use chuffed_rs::wrappers::{create_vars, all_different_wrapper, branch_wrapper}; -use chuffed_rs::bindings::{IntVar, ConLevel_CL_DEF, VarBranch_VAR_INORDER, VarBranch_VAR_MIN_MIN, vec, new_dummy_problem, get_idx, p_addVars, p_setcallback}; +use chuffed_rs::bindings::{ + get_idx, new_dummy_problem, p_addVars, p_setcallback, vec, ConLevel_CL_DEF, IntVar, + VarBranch_VAR_INORDER, VarBranch_VAR_MIN_MIN, +}; +use chuffed_rs::wrappers::{all_different_wrapper, branch_wrapper, create_vars}; unsafe fn post_constraints(_n: i32) -> *mut vec<*mut IntVar> { // Create constant @@ -11,7 +14,7 @@ unsafe fn post_constraints(_n: i32) -> *mut vec<*mut IntVar> { all_different_wrapper(x, ConLevel_CL_DEF); // Post some branchings - branch_wrapper(x as _, VarBranch_VAR_INORDER, VarBranch_VAR_MIN_MIN); + branch_wrapper(x as _, VarBranch_VAR_INORDER, VarBranch_VAR_MIN_MIN); x } @@ -19,7 +22,7 @@ unsafe fn post_constraints(_n: i32) -> *mut vec<*mut IntVar> { // Custom printing function for this problem #[no_mangle] pub unsafe extern "C" fn callback(x: *mut vec<*mut IntVar>) { - print!("First output is: {:?}", get_idx(x, 0)); + print!("First output is: {:?}", get_idx(x, 0)); } fn main() { @@ -31,8 +34,8 @@ fn main() { } let n: i32 = args[1].parse().expect("Invalid input"); - - unsafe{ + + unsafe { let x = post_constraints(n); // make new dummy problem let p = new_dummy_problem(); From 7906d9dae099a80558b4c288f9603259298a7595 Mon Sep 17 00:00:00 2001 From: Kieranoski Date: Wed, 1 Nov 2023 15:32:04 +0000 Subject: [PATCH 3/4] Update build.sh to use c++ insetad of g++ and compile with --std=c++11 --- solvers/chuffed/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solvers/chuffed/build.sh b/solvers/chuffed/build.sh index fac03a10e1..6615852803 100644 --- a/solvers/chuffed/build.sh +++ b/solvers/chuffed/build.sh @@ -13,5 +13,5 @@ cmake --build build cd .. # Build wrapper.cpp as static library -g++ -c wrapper.cpp -Ivendor +c++ -c wrapper.cpp -Ivendor --std=c++11 ar rvs libwrapper.a wrapper.o From ac3c4c8badcc80964ccc24b253a53412ad2b518a Mon Sep 17 00:00:00 2001 From: Chris Jefferson Date: Thu, 2 Nov 2023 11:04:27 +0800 Subject: [PATCH 4/4] Fixes (IntVar -> IntVar*, create vec* instead of using nullptr) --- solvers/chuffed/build.rs | 2 ++ solvers/chuffed/src/lib.rs | 6 +++--- solvers/chuffed/wrapper.cpp | 10 +++++++++- solvers/chuffed/wrapper.h | 5 ++++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/solvers/chuffed/build.rs b/solvers/chuffed/build.rs index 8ce1765783..280dbd7d90 100644 --- a/solvers/chuffed/build.rs +++ b/solvers/chuffed/build.rs @@ -72,6 +72,8 @@ fn bind() { .allowlist_function("var_sym_break") .allowlist_function("new_dummy_problem") .allowlist_function("get_idx") + .allowlist_function("make_vec_intvar") + .allowlist_function("destroy_vec_intvar") .allowlist_function("p_addVars") .allowlist_function("p_setcallback") .allowlist_function("branch_IntVar") diff --git a/solvers/chuffed/src/lib.rs b/solvers/chuffed/src/lib.rs index 0e55b61588..f935887260 100644 --- a/solvers/chuffed/src/lib.rs +++ b/solvers/chuffed/src/lib.rs @@ -7,8 +7,8 @@ pub mod bindings { pub mod wrappers { use crate::bindings::{ - all_different, branch_IntVar, createVar, createVars, vec, ConLevel, IntVar, ValBranch, - VarBranch, + all_different, branch_IntVar, createVar, createVars, make_vec_intvar, vec, ConLevel, + IntVar, ValBranch, VarBranch, }; use core::ptr; @@ -25,7 +25,7 @@ pub mod wrappers { // createVars void createVars(vec& x, int n, int min, int max, bool el) pub fn create_vars(n: i32, min: i32, max: i32, el: bool) -> *mut vec<*mut IntVar> { - let ptr: *mut vec<*mut IntVar> = ptr::null_mut(); + let ptr: *mut vec<*mut IntVar> = unsafe { make_vec_intvar() }; unsafe { createVars(ptr, n, min, max, el); diff --git a/solvers/chuffed/wrapper.cpp b/solvers/chuffed/wrapper.cpp index 87821d749c..94d90aed20 100644 --- a/solvers/chuffed/wrapper.cpp +++ b/solvers/chuffed/wrapper.cpp @@ -7,7 +7,15 @@ void p_addVars(DummyProblem *p, vec *_searchVars) { void p_setcallback(DummyProblem *p, void (*_callback)(vec *)) { p->setcallback(_callback); } -IntVar get_idx(vec *x, int i) { return **x[i]; } +IntVar* get_idx(vec *x, int i) { return *x[i]; } + +vec* make_vec_intvar() { + return new vec(); +} + +void destroy_vec_intvar(vec* v) { + delete v; +} void branch_IntVar(vec *x, VarBranch var_branch, ValBranch val_branch) { diff --git a/solvers/chuffed/wrapper.h b/solvers/chuffed/wrapper.h index 78cf60e21f..6a0773539a 100644 --- a/solvers/chuffed/wrapper.h +++ b/solvers/chuffed/wrapper.h @@ -17,7 +17,10 @@ class DummyProblem { DummyProblem *new_dummy_problem(); void p_addVars(DummyProblem *p, vec *_searchVars); void p_setcallback(DummyProblem *p, void (*_callback)(vec *)); -IntVar get_idx(vec *x, int i); +IntVar* get_idx(vec *x, int i); + +vec* make_vec_intvar(); +void destroy_vec_intvar(vec* v); void branch_IntVar(vec *x, VarBranch var_branch, ValBranch val_branch);