Skip to content

Commit 36d8c46

Browse files
committed
Support constructing affine expression from numpy arrays quickly
1 parent 328939d commit 36d8c46

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

lib/core_ext.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@
22
#include <nanobind/operators.h>
33
#include <nanobind/stl/vector.h>
44
#include <nanobind/stl/optional.h>
5+
#include <nanobind/ndarray.h>
56

67
#include "pyoptinterface/core.hpp"
78
#include "pyoptinterface/container.hpp"
89

10+
#include <span>
11+
#include <algorithm>
12+
913
namespace nb = nanobind;
1014

15+
using CoeffNdarrayT = nb::ndarray<const double, nb::ndim<1>, nb::any_contig>;
16+
using IndexNdarrayT = nb::ndarray<int, nb::ndim<1>, nb::any_contig>;
17+
1118
NB_MODULE(core_ext, m)
1219
{
1320
nb::set_leak_warnings(false);
@@ -74,6 +81,51 @@ NB_MODULE(core_ext, m)
7481
nb::arg("variables"))
7582
.def(nb::init<const Vector<CoeffT> &, const Vector<IndexT> &, CoeffT>(),
7683
nb::arg("coefficients"), nb::arg("variables"), nb::arg("constant"))
84+
85+
// ndarray constructor
86+
.def_static(
87+
"from_numpy",
88+
[](CoeffNdarrayT coefficients, IndexNdarrayT variables) {
89+
auto *expr = new ScalarAffineFunction();
90+
91+
auto n = coefficients.size();
92+
93+
expr->coefficients.resize(n);
94+
std::span<const double> coeffs(coefficients.data(), n);
95+
std::ranges::copy(coeffs, expr->coefficients.begin());
96+
97+
n = variables.size();
98+
expr->variables.resize(n);
99+
std::span<const int> vars(variables.data(), n);
100+
std::ranges::copy(vars, expr->variables.begin());
101+
102+
expr->constant.reset();
103+
104+
return expr;
105+
},
106+
nb::arg("coefficients"), nb::arg("variables"))
107+
.def_static(
108+
"from_numpy",
109+
[](CoeffNdarrayT coefficients, IndexNdarrayT variables, CoeffT constant) {
110+
auto *expr = new ScalarAffineFunction();
111+
112+
auto n = coefficients.size();
113+
114+
expr->coefficients.resize(n);
115+
std::span<const double> coeffs(coefficients.data(), n);
116+
std::ranges::copy(coeffs, expr->coefficients.begin());
117+
118+
n = variables.size();
119+
expr->variables.resize(n);
120+
std::span<const int> vars(variables.data(), n);
121+
std::ranges::copy(vars, expr->variables.begin());
122+
123+
expr->constant = constant;
124+
125+
return expr;
126+
},
127+
nb::arg("coefficients"), nb::arg("variables"), nb::arg("constant"))
128+
77129
.def(nb::init<const ExprBuilder &>())
78130
.def_ro("coefficients", &ScalarAffineFunction::coefficients)
79131
.def_ro("variables", &ScalarAffineFunction::variables)

tests/test_basic.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,24 @@ def test_basic():
6969
assert sqf.affine_part.constant == approx(6.0)
7070

7171

72+
def test_affineexpr_from_numpy():
73+
N = 25
74+
coefs = np.arange(N, dtype=np.float64)
75+
vars = np.arange(N, dtype=np.int_)
76+
77+
expr = poi.ScalarAffineFunction.from_numpy(coefs, vars)
78+
79+
assert list(expr.variables) == list(vars)
80+
assert np.allclose(expr.coefficients, coefs)
81+
82+
constant = 3.0
83+
expr = poi.ScalarAffineFunction.from_numpy(coefs, vars, constant)
84+
85+
assert list(expr.variables) == list(vars)
86+
assert np.allclose(expr.coefficients, coefs)
87+
assert expr.constant == approx(constant)
88+
89+
7290
def test_monotoneindexer():
7391
indexer = IntMonotoneIndexer()
7492

0 commit comments

Comments
 (0)