Calling C++ function having std::vectors as input and output parameters from Julia

Dear All
I am new to Julia and and I am trying to access my C++ code from Julia. I have asked this question already at Stack Overflow, but were not able to find an answer there.
I am trying to call a C++ function from Julia using Cxx. The input and output parameters of the C++ function are std::vectors, see the function compute_sum in the example below:

#include
#include

std::vector< int > compute_sum( const std::vector< std::vector >& input )
{
std::vector< int > resut( input.size() , 0 );
for ( std::size_t i = 0 ; i != input.size() ; ++i )
{
for ( std::size_t j = 0 ; j != input[i].size() ; ++j )
{
resut[i] += input[i][j];
}
}
return resut;
}

void simple_function( int i )
{
std::cout << "The numbers is : " << i << std::endl;
}

Assuming this function is stored as code.cpp I am compiling it to a shared object code.so using:

g++ -shared -fPIC code.cpp -o code.so

and as a result I obtain a file code.so

Having this, I run Julia in the same folder as code.so. My version of Julia is 0.6.2. Then I import Cxx and the code.so file using:

julia> using Cxx
julia> const path_to_lib = pwd()
julia> addHeaderDir(path_to_lib, kind=C_System)
julia> Libdl.dlopen(path_to_lib * “/code.so”, Libdl.RTLD_GLOBAL)
Ptr{Void} @0x00000000044bda30
julia> cxxinclude(“code.cpp”)

In odder to test if the process is successful I am calling the simple_function and obtain the correct results:

julia> @cxx simple_function(1234)
The numbers is : 1234

Then I want to call compute_sum function. For that I need somehow to create, or convert Julia vector into C++ std::vector< std::vector >. I am trying the following:

julia> cxx" std::vector< std::vector > a;"
true
julia> icxx" a.push_back( std::vector(1,2) ); "
julia> icxx" a.push_back( std::vector(1,3) ); "
julia> icxx" a.push_back( std::vector(1,4) ); "
julia> icxx" a.size(); "
0x0000000000000003

So I assume that the vector is created in a correct way. Then I trying to call the function with it, but I fail:

julia> @cxx compute_sum(a)
ERROR: UndefVarError: a not defined
julia> @cxx compute_sum(“a”)
ERROR: Got bad type information while compiling Cxx.CppNNS{Tuple{:compute_sum}} (got String for argument 1)
julia> icxx " compute_sum(a);"
ERROR: syntax: extra token “”" after end of expression

Could anyone help me please with the following question(s):

  1. How to call compute_sum function from Julia? I am happy to use any technique (not necessary Cxx) that works and is reasonably fast.
  2. How to convert the result of compute_sum to Julia array?

If one cannot do it with std::vector on C++ side, I would appreciate any advice on how to transfer large vectors (for instance in the form int**) from Julia to C++ and back.

Thank you very much!

pawel

Hi,

The following code should work in Julia, the trick is to use the icxx string macro with interpolation:

using Cxx

cxx"""
#include <iostream>
#include <vector>

std::vector<int> compute_sum(const std::vector<std::vector<int>> &input)
{
  std::vector<int> result(input.size(), 0);
  for (std::size_t i = 0; i != input.size(); ++i)
  {
    for (std::size_t j = 0; j != input[i].size(); ++j)
    {
      result[i] += input[i][j];
    }
  }
  return result;
}
"""

cxx_v = icxx"std::vector<std::vector<int>>{{1,2},{1,2,3}};"
println("Input vectors:")
for v in cxx_v
  println("  ", collect(v))
end

cxx_sum = icxx"compute_sum($cxx_v);"
println("Cxx sums: $(collect(cxx_sum))")

I have also posted this answer on Stack Overflow

4 Likes

If you want to convert a julia array of arrays to std::vectors and pass it to C++, and vice versa, you can do the following.

as = [rand(1:10,5), rand(1:10,6)]
x = convert(cxxt"std::vector< std::vector< int > > >", as)
collect(icxx"compute_sum($x);")
3 Likes

x = cxxt"std::vector< std::vector< int > > >"(as) also works. You can convert julia arrays to std::vectors for a number of different types. Cxx also implements the iterator interface on std::vectors, which is why you can call collect on it.

Thank you, that solution works, and this is what I need.

Thank you for suggesting it. It works as a way of converting Julia arrays to std::vectors.

Hello, to me (Julia 1.1, Cxx 0.3.1) this method doesn’t work (while the convert one does):

julia> x = cxxt"std::vector< std::vector< int > >"(as)
ERROR: MethodError: no method matching Cxx.CxxCore.CppValue{Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol("std::vector")},Tuple{Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol("std::vector")},Tuple{Int32,Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol("std::allocator")},Tuple{Int32}},(false, false, false)}}},(false, false, false)},Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol("std::allocator")},Tuple{Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol("std::vector")},Tuple{Int32,Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol("std::allocator")},Tuple{Int32}},(false, false, false)}}},(false, false, false)}}},(false, false, false)}}},(false, false, false)},N} where N(::Array{Array{Int64,1},1})

Also (but it seems irrelevant) there is one exceeding “>”

Hi @barche, this code throws this error for me on Windows 10

LLVM ERROR: Program used external function '__gxx_personality_v0' which could not be resolved!

Does anyone know what this means?

this is my Julia

julia> versioninfo()
Julia Version 1.3.0-DEV.294
Commit 137b21e77c (2019-05-28 15:17 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, skylake)

AFAIK windows support is still WIP, see this issue and PR.

2 Likes

This didn’t work for me, do you know why that might be?

I wrote:

jarr =[2,3]
carr=convert(cxxt"std::vector< std::vector< int > > >", jarr)

and got:

MethodError: Cannot convert an object of type Int64 to an object of type Cxx.CxxCore.CppValue{Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol(“std::__1::vector”)},Tuple{Int32,Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol(“std::__1::allocator”)},Tuple{Int32}},(false, false, false)}}},(false, false, false)},N} where N
Closest candidates are:
convert(::Type{Cxx.CxxCore.CppValue{Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol(“std::__1::vector”)},Tuple{T,Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol(“std::__1::allocator”)},Tuple{T}},(false, false, false)}}},(false, false, false)},N} where N}, !Matched::AbstractArray) where T at /Users/hannah/.julia/packages/Cxx/1RaOv/src/std.jl:127
convert(::Type{T}, !Matched::T) where T at essentials.jl:168
setindex! at std.jl:143 [inlined]
copyto!(::IndexLinear, ::Cxx.CxxStd.WrappedCppObjArray{Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol(“std::__1::vector”)},Tuple{Int32,Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol(“std::__1::allocator”)},Tuple{Int32}},(false, false, false)}}},(false, false, false)},(false, false, false)}, ::IndexLinear, ::Array{Int64,1}) at abstractarray.jl:807
copyto! at abstractarray.jl:799 [inlined]
copy! at std.jl:205 [inlined]
copy! at std.jl:114 [inlined]
convert(::Type{Cxx.CxxCore.CppValue{Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol(“std::__1::vector”)},Tuple{Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol(“std::__1::vector”)},Tuple{Int32,Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol(“std::__1::allocator”)},Tuple{Int32}},(false, false, false)}}},(false, false, false)},Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol(“std::__1::allocator”)},Tuple{Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol(“std::__1::vector”)},Tuple{Int32,Cxx.CxxCore.CxxQualType{Cxx.CxxCore.CppTemplate{Cxx.CxxCore.CppBaseType{Symbol(“std::__1::allocator”)},Tuple{Int32}},(false, false, false)}}},(false, false, false)}}},(false, false, false)}}},(false, false, false)},N} where N}, ::Array{Int64,1}) at std.jl:129
top-level scope at C++ try.jl:753

Doesn’t that fail simply because you’re trying to convert a vector to a vector of vectors? Try jarr = [[2,3], [4,5]] instead (or convert to std::vector< int >).

oh! yes! thank you, my bad.
I fixed that, but it now says “Could not parse type name”?

I tried both converting a vector of vectors(copying the code from here), and a vector (following what you said):

jarr =[2,3]
carr=convert(cxxt"std::vector< int >>", jarr)

Thanks!

I believe this should be std::vector< int >.