从 Julia 调用具有 std::vectors 作为输入和输出参数的 C++ 函数
Calling C++ function having std::vectors as input and output parameters from Julia
我是 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
有了这个,我 运行 Julia 在与 code.so 相同的文件夹中。我的 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< std::vector >。我正在尝试以下操作:
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
谁能帮我解决以下问题:
- 如何从 Julia 调用 compute_sum 函数?我很乐意使用任何有效且速度相当快的技术(不一定是 Cxx)。
- 如何将compute_sum的结果转换为Julia数组?
非常感谢!
帕维尔
因为你愿意在 Julia arrays 上工作,我假设你想在 matrices、[=29= 上工作]即,在维度上具有恒定长度的数组。因此,我建议您不要使用 vector
中的 vector
,而是只使用 vector
。然后,你应该记得 Julia 使用 column-major 数组,而在 C/C++ 中,内存布局是 row-major.
在下面,您可以找到使用迭代器的代码模板版本。这样,您就可以编译 compute_sum
以在 C++ 中使用您最喜欢的 std::vector
。或者,您可以要求您的编译器生成带有指针的适当代码,以便能够与其他语言一起使用,例如 Julia。
#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);
}
}
然后,照常编译代码:
g++ -Wall -std=c++11 -O3 -fPIC -shared code.cpp -o code.so
然后,使用Julia的capabilities调用编译后的C代码:
const libhandle = Libdl.dlopen(joinpath(pwd(), "code.so"))
const funhandle = Libdl.dlsym(libhandle, :compute_sum)
function compute_sum(A::Matrix{Int64})
result = Vector{Int64}(size(A, 1))
ccall(funhandle, Void, (UInt64, UInt64, Ref{Int64}, Ref{Int64}),
size(A, 1), size(A, 2), A, result)
return result
end
result = compute_sum(ones(Int64, 5, 6)) # prints Int64[6, 6, 6, 6, 6]
希望对您有所帮助。干杯!
诀窍是使用 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))")
感谢 Arda Aytekin 和 Bart Janssens 的大力帮助和建议。两种解决方案都非常有效,我想将它们都标记为我的问题的答案,但似乎我只能标记一个答案...
在接下来的几天里,我将 运行 进行速度比较测试,看看基于纯 C 接口的解决方案是否比使用 Cxx 的解决方案更快。准备就绪后,我会通知您。
我是 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
有了这个,我 运行 Julia 在与 code.so 相同的文件夹中。我的 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< std::vector >。我正在尝试以下操作:
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
谁能帮我解决以下问题:
- 如何从 Julia 调用 compute_sum 函数?我很乐意使用任何有效且速度相当快的技术(不一定是 Cxx)。
- 如何将compute_sum的结果转换为Julia数组?
非常感谢!
帕维尔
因为你愿意在 Julia arrays 上工作,我假设你想在 matrices、[=29= 上工作]即,在维度上具有恒定长度的数组。因此,我建议您不要使用 vector
中的 vector
,而是只使用 vector
。然后,你应该记得 Julia 使用 column-major 数组,而在 C/C++ 中,内存布局是 row-major.
在下面,您可以找到使用迭代器的代码模板版本。这样,您就可以编译 compute_sum
以在 C++ 中使用您最喜欢的 std::vector
。或者,您可以要求您的编译器生成带有指针的适当代码,以便能够与其他语言一起使用,例如 Julia。
#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);
}
}
然后,照常编译代码:
g++ -Wall -std=c++11 -O3 -fPIC -shared code.cpp -o code.so
然后,使用Julia的capabilities调用编译后的C代码:
const libhandle = Libdl.dlopen(joinpath(pwd(), "code.so"))
const funhandle = Libdl.dlsym(libhandle, :compute_sum)
function compute_sum(A::Matrix{Int64})
result = Vector{Int64}(size(A, 1))
ccall(funhandle, Void, (UInt64, UInt64, Ref{Int64}, Ref{Int64}),
size(A, 1), size(A, 2), A, result)
return result
end
result = compute_sum(ones(Int64, 5, 6)) # prints Int64[6, 6, 6, 6, 6]
希望对您有所帮助。干杯!
诀窍是使用 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))")
感谢 Arda Aytekin 和 Bart Janssens 的大力帮助和建议。两种解决方案都非常有效,我想将它们都标记为我的问题的答案,但似乎我只能标记一个答案...
在接下来的几天里,我将 运行 进行速度比较测试,看看基于纯 C 接口的解决方案是否比使用 Cxx 的解决方案更快。准备就绪后,我会通知您。