调用C ++函数,将std :: vectors作为Julia的输入和输出参数

时间:2018-02-18 11:34:45

标签: c++ julia std

我是Julia的新手,我正在尝试从Julia访问我的C ++代码。更确切地说,我试图使用Cxx从Julia调用C ++函数。 C ++函数的输入和输出参数是std :: vectors,请参见下面示例中的函数compute_sum:

#include <vector>
#include <iostream>

std::vector< int > compute_sum( const std::vector< std::vector<int> >& 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;
}

假设此函数存储为code.cpp,我将其编译为共享对象code.so使用:

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

因此我获得了一个文件code.so

有了这个,我在与code.so相同的文件夹中运行Julia。我的Julia版本是0.6.2。然后我使用:

导入Cxx和code.so文件
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")

如果过程成功,我会调用simple_function并获得正确的结果:

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

然后我想调用compute_sum函数。为此,我需要以某种方式创建,或将Julia矢量转换为C ++ std :: vector&lt; std :: vector&gt;。我正在尝试以下方法:

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

所以我假设矢量是以正确的方式创建的。然后我试着用它来调用函数,但是我失败了:

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

任何人都可以帮我解决以下问题:

  1. 如何从Julia调用compute_sum函数?我很高兴使用任何可行且速度相当快的技术(不是必需的Cxx)。
  2. 如何将compute_sum的结果转换为Julia数组?
  3. 非常感谢!

    的Pawel

3 个答案:

答案 0 :(得分:3)

因为您愿意使用Julia 数组,我认为您希望使用 matrices ,具有常量的数组尺寸长度。出于这个原因,我建议你不要使用vector的{​​{1}},而只使用vector s。然后,您应该记住Julia使用 column-major 数组,而在C / C ++中,内存布局是 row-major

下面,您可以使用迭代器找到模板的模板化版本。这样,您可以使用您喜欢的vector编译compute_sum以便在C ++中使用。或者,您可以要求编译器使用指针生成相应的代码,以便能够与其他语言一起使用,例如Julia。

std::vector

然后,像往常一样编译代码:

#include <cstdint>
#include <iterator>
#include <vector>

template <class RandomIt, class OutputIt>
OutputIt compute_sum(const std::uint64_t nrows, RandomIt xbegin, RandomIt xend,
                     OutputIt rbegin) {
  const std::size_t ncols{std::distance(xbegin, xend) / nrows};
  typename std::iterator_traits<OutputIt>::value_type sum{0};
  for (std::size_t row = 0; row < nrows; row++) {
    for (std::size_t col = 0; col < ncols; col++)
      sum += xbegin[col * nrows + row];

    *rbegin++ = sum;
    sum = 0;
  }
  return rbegin;
}

/* you can use the above code in your C++ applications as follows */
// int main() {
//   std::vector<int> matrix{1, 2, 3, 4, 5,
//                           6, 7, 8, 9}; /* 3x3 matrix in column-major */
//   std::vector<int> result(3);
//   compute_sum(3, std::begin(matrix), std::end(matrix), std::begin(result));
//   return 0;
// }

/* or, ask your compiler to generate code with C linkage (no name mangling) */
extern "C" {
void compute_sum(const std::uint64_t m /* use fixed-size integers */,
                 const std::uint64_t n /* use fixed-size integers */,
                 const std::int64_t *xbegin /* use fixed-size integers */,
                 std::int64_t *rbegin /* use fixed-size integers */) {
  compute_sum(m, xbegin, xbegin + m * n, rbegin);
}
}

然后,使用Julia的capabilities来调用已编译的C代码:

g++ -Wall -std=c++11 -O3 -fPIC -shared code.cpp -o code.so

我希望这会有所帮助。干杯!

答案 1 :(得分:3)

诀窍是使用icxx字符串宏,这允许使用$插入Julia变量。这是一个完整的例子:

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) // corrected to ++j here
    {
      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))")

在Julia中运行它应该打印:

Input vectors:
  Int32[1, 2]
  Int32[1, 2, 3]
Cxx sums: Int32[3, 6]

要使用共享库执行此操作,请按以下方式创建vector.hpp

#include <vector>
std::vector<int> compute_sum(const std::vector<std::vector<int>> &input);

vector.cpp

#include "vector.hpp"

std::vector<int> compute_sum(const std::vector<std::vector<int>> &input)
{
     // same as before
}

编译:

g++ -shared -fPIC -o libvector.so vector.cpp

朱莉娅:

using Cxx

const path_to_lib = pwd()
addHeaderDir(path_to_lib, kind=C_System)
Libdl.dlopen(joinpath(path_to_lib, "libvector"), Libdl.RTLD_GLOBAL)
cxxinclude("vector.hpp")

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))")

答案 2 :(得分:0)

我要感谢Arda Aytekin和Bart Janssens的大力帮助和建议。两种解决方案都运行良好,我想将它们都标记为我的问题的答案,但似乎我只能标记一个答案...
在接下来的几天里,我将进行速度比较测试,以确定基于纯C接口的解决方案是否更快或不使用Cxx。一旦准备就绪,我会更新你的。