1

I have a DLL written in C++ and I need to call a function called print_matrix(Eigen::MatrixXf *m) from a Rust program.

I created the a 4x3 mactrix and the function in question takes a pointer as its input parameter.

Rust code:

use nalgebra::Matrix;

pub type MatrixX = Matrix<f32, Dynamic, Dynamic, VecStorage<f32, Dynamic, Dynamic>>;

pub fn main() {
    match call_dynamic() {
       Ok(_) => println!("Func ok",),
       Err(e) => println!("{:?}", e),
    }
}

pub fn call_dynamic() -> Result<(), Box<dyn std::error::Error>> {
    let lib = dll::Library::new("MyDLL.dll")?;
    unsafe {
        let func: dll::Symbol<fn(*mut MatrixX)> = lib.get(b"print_matrix")?;

        func(init_cube());
        Ok(())
    }
}

// Init matrix and return raw pointer
pub fn init_matrix() -> *mut MatrixX {
    let points: MatrixX = DMatrix::from_row_slice(
        4,
        3,
        &[0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0],
    );
    Box::into_raw(Box::new(points))
}

C++ code:

extern "C" __declspec(dllexport) void print_matrix(Eigen::MatrixXf *m);

void print_matrix(Eigen::MatrixXf* m) {
    using namespace Eigen;
    using namespace std;
    // Print size of a matrix
    std::cout << "m->size() : " << m->size() << std::endl;
    // Print number of rows
    std::cout << "m->rows() : " << m->rows() << std::endl;
    // Print number of columns 
    std::cout << "m->cols() : " << m->cols() << std::endl;
    // Print first column
    std::cout << "m->col(0) : " << m->col(0) << std::endl;
}

And my output looks like this:

m->size() : 144
m->rows() : 12
m->cols() : 12
m->col(0) : 
0
0
0
0
0
0
1
1
0
1
0
1

But i can't understand why the output of m->rows() = 12 and this is equal to rows * cols (4 * 3).

Do you have any idea why it's happening? Thank you!

Teymour
  • 1,832
  • 1
  • 13
  • 34
  • 1
    How do you know that an `nalgebra` matrix is "compatible" (e.g. in terms of memory layout) to an `eigen` matrix? Is that documented anywhere? Otherwise I think simply passing back and forth between the two systems is bound to produce strange results. – phimuemue Apr 30 '20 at 08:51
  • @phimuemue Yes, i couldn't found any information about that and used array to pass the data to an Eigen::Matrix. Thank you for the tip. – Artem Kolokoltsev Jun 04 '20 at 15:59

1 Answers1

2

I didn't found that an nalgebra matrix is compatible to an eigen matrix and used Array to pass the data to an eigen matrix.

C++ Code:

// Create Eigen::Matrix
void* create_matrix(size_t rows, size_t cols, int points[]) {

    // Init pointer
    Eigen::MatrixXi* M;
    M = new Eigen::MatrixXi;

    Map<Eigen::MatrixXi, Unaligned, Stride<1, 3> > Temp_M(points, rows, cols);

    *M = Temp_M;

    return M;
}

// Print Matrix
void print_matrix(Eigen::MatrixXi* M) {
    cout << *M << std::endl;
}

Rust Code:

// Get pointer to the function
let create_matrix: dll::Symbol<fn(usize, usize, *mut i32) -> *mut u8> =
   lib.get(b"create_matrix")?;

// Store pointer to Matrix
let m_ptr = create_matrix(2, 2, [1, 2, 3, 4].as_mut_ptr());

let print_matrix: dll::Symbol<fn(*mut u8)> =
   lib.get(b"print_matrix")?;

print_matrix(m_ptr);