0%

使用Pybind11从C++向Python返回Matrix

今天在写代码的时候发现使用pybind11返回矩阵比我想的要简单的多,原本都打算转换成eigen来返回数据了,囧。 使用pybind11返回矩阵仅需要将一维向量resize为二维矩阵即可,囧。 注意,如下代码里面进行resizee操作的时候,需要指定一个特定数据格式的shape。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
py::array_t<double> calculate_iv_array(
const py::array_t<bool> &is_call,
const py::array_t<double> &premium,
const py::array_t<double> &S,
const py::array_t<double> &X,
const py::array_t<double> &T,
const py::array_t<double> &b,
const py::array_t<double> &r,
const double &iv_lower_limit,
const double &iv_upper_limit,
const double &ttm_clip,
const int &num_steps,
const double &precision)
{

py::buffer_info buf_is_call = is_call.request();
py::buffer_info buf_premium = premium.request();
py::buffer_info buf_spot = S.request();
py::buffer_info buf_strike = X.request();
py::buffer_info buf_time = T.request();
py::buffer_info buf_carry_cost = b.request();
py::buffer_info buf_risk_free = r.request();

std::vector<ssize_t> shape = {buf_spot.size, 3};
auto result = py::array_t<double>(buf_spot.size * 3);
result.resize({shape[0], shape[1]});
py::buffer_info buffer_result = result.request();

bool *ptr_is_call = static_cast<bool *>(buf_is_call.ptr);
auto *ptr_premium = static_cast<double *>(buf_premium.ptr);
auto *ptr_spot = static_cast<double *>(buf_spot.ptr);
auto *ptr_strike = static_cast<double *>(buf_strike.ptr);
auto *ptr_time = static_cast<double *>(buf_time.ptr);
auto *ptr_carry_cost = static_cast<double *>(buf_carry_cost.ptr);
auto *ptr_risk_free = static_cast<double *>(buf_risk_free.ptr);
auto *ptr_result = static_cast<double *>(buffer_result.ptr);

for (int idx = 0; idx < buf_spot.shape[0]; idx++)
{
double sigma = flow::model::bjerk02::calculate_iv(ptr_is_call[idx],
ptr_premium[idx],
ptr_spot[idx],
ptr_strike[idx],
ptr_time[idx],
ptr_carry_cost[idx],
ptr_risk_free[idx],
iv_lower_limit,
iv_upper_limit,
ttm_clip,
num_steps,
precision);

ptr_result[idx * shape[0] + 0] = sigma;
ptr_result[idx * shape[0] + 1] = flow::model::bjerk02::calculate_delta(ptr_is_call[idx],
ptr_spot[idx],
ptr_strike[idx],
ptr_time[idx],
ptr_carry_cost[idx],
ptr_risk_free[idx],
sigma);

ptr_result[idx * shape[0] + 2] = flow::model::bjerk02::calculate_vega(ptr_is_call[idx],
ptr_spot[idx],
ptr_strike[idx],
ptr_time[idx],
ptr_carry_cost[idx],
ptr_risk_free[idx],
sigma);
};
return result;
}
1
2
3
4
5
6
7
8
9
PYBIND11_MODULE(pybjerk, m)
{
m.doc() = " Bjerksund and Stensland (2002) Pricing Formula"; // optional module docstring

m.def("calculate_iv_array", &calculate_iv_array, "calculate iv delta vega", py::arg("is_call"),
py::arg("premium"), py::arg("S"), py::arg("X"), py::arg("T"), py::arg("b"),
py::arg("r"), py::arg("iv_lower_limit") = 1e-8, py::arg("iv_upper_limit") = 10, py::arg("ttm_clip") = 1e-6,
py::arg("num_steps") = 128, py::arg("precision") = 1e-8);
}