Skip to content

Commit 856c482

Browse files
committed
NLWPY: store data copies internally #30
No need to keep the arrays around
1 parent e3ffc3f commit 856c482

File tree

4 files changed

+150
-47
lines changed

4 files changed

+150
-47
lines changed

nl-writer2/include/api/c/nl-model-c.h

+24
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,35 @@ typedef struct NLW2_NLModel_C {
3131
/// Construct NLW2_NLModel_C
3232
///
3333
/// @param probname: can be NULL.
34+
///
35+
/// @note All model data pointers should stay valid until
36+
/// loading the model into NLW2_NLSolver_C.
3437
NLW2_NLModel_C NLW2_MakeNLModel_C(const char* probname);
3538

3639
/// Destroy NLW2_NLModel_C
3740
void NLW2_DestroyNLModel_C(NLW2_NLModel_C* );
3841

3942
/// Add variables (all at once.)
43+
///
44+
/// @note All model data pointers should stay valid until
45+
/// loading the model into NLW2_NLSolver_C.
4046
void NLW2_SetCols_C(NLW2_NLModel_C* ,
4147
int num_col,
4248
const double *lower,
4349
const double *upper,
4450
const int *type);
4551

4652
/// Add variable names
53+
///
54+
/// @note All model data pointers should stay valid until
55+
/// loading the model into NLW2_NLSolver_C.
4756
void NLW2_SetColNames_C(NLW2_NLModel_C* , const char *const *nm);
4857

4958
/// Add linear constraints (all at once).
5059
/// Only rowwise matrix supported.
60+
///
61+
/// @note All model data pointers should stay valid until
62+
/// loading the model into NLW2_NLSolver_C.
5163
void NLW2_SetRows_C(NLW2_NLModel_C* ,
5264
int nr, const double* rlb, const double* rub,
5365
int format_,
@@ -57,16 +69,25 @@ void NLW2_SetRows_C(NLW2_NLModel_C* ,
5769
const double *value_);
5870

5971
/// Add constraint names
72+
///
73+
/// @note All model data pointers should stay valid until
74+
/// loading the model into NLW2_NLSolver_C.
6075
void NLW2_SetRowNames_C(NLW2_NLModel_C* , const char *const *nm);
6176

6277
/// Add linear objective (only single objective supported.)
6378
/// Sense: NLW2_ObjSenseM....
6479
/// Coefficients: dense vector.
80+
///
81+
/// @note All model data pointers should stay valid until
82+
/// loading the model into NLW2_NLSolver_C.
6583
void NLW2_SetLinearObjective_C(NLW2_NLModel_C* ,
6684
int sense, double c0, const double* c);
6785

6886
/// Add Q for the objective quadratic part 0.5 @ x.T @ Q @ x.
6987
/// Format: NLW2_HessianFormat...
88+
///
89+
/// @note All model data pointers should stay valid until
90+
/// loading the model into NLW2_NLSolver_C.
7091
void NLW2_SetHessian_C(NLW2_NLModel_C* ,
7192
int format,
7293
int dim,
@@ -76,6 +97,9 @@ void NLW2_SetHessian_C(NLW2_NLModel_C* ,
7697
const double *value_);
7798

7899
/// Set obj name
100+
///
101+
/// @note All model data pointers should stay valid until
102+
/// loading the model into NLW2_NLSolver_C.
79103
void NLW2_SetObjName_C(NLW2_NLModel_C* , const char* nm);
80104

81105
/// Compute objective value

nl-writer2/include/mp/nl-model.h

+26-2
Original file line numberDiff line numberDiff line change
@@ -42,43 +42,67 @@ class NLUtils;
4242
/// For fully nonlinear models with expression trees,
4343
/// use NLSolver with NLWriter2/NLFeeder2.
4444
///
45-
/// All pointers should stay valid until
45+
/// @note All pointers should stay valid until
4646
/// loading the model into NLSolver.
4747
class NLModel {
4848
public:
49-
/// Construct
49+
/// Construct.
50+
///
51+
/// @note All pointers should stay valid until
52+
/// loading the model into NLSolver.
5053
NLModel(const char* probname = nullptr)
5154
: prob_name_(probname ? probname : "NLModelInstance") { }
5255

5356
/// Add variables (all at once.)
57+
///
58+
/// @note All pointers should stay valid until
59+
/// loading the model into NLSolver.
5460
void SetCols(NLW2_ColData_C vd) { vars_ = vd; }
5561

5662
/// Add variable names
63+
///
64+
/// @note All pointers should stay valid until
65+
/// loading the model into NLSolver.
5766
void SetColNames(const char *const *nm) { var_names_=nm; }
5867

5968
/// Add linear constraints (all at once).
6069
/// Only rowwise matrix supported.
70+
///
71+
/// @note All pointers should stay valid until
72+
/// loading the model into NLSolver.
6173
void SetRows(
6274
int nr, const double* rlb, const double* rub,
6375
NLW2_SparseMatrix_C A)
6476
{ num_row_=nr; row_lb_=rlb; row_ub_=rub; A_=A; }
6577

6678
/// Add constraint names
79+
///
80+
/// @note All pointers should stay valid until
81+
/// loading the model into NLSolver.
6782
void SetRowNames(const char *const *nm) { row_names_=nm; }
6883

6984
/// Add linear objective (only single objective supported.)
7085
/// Sense: NLW2_ObjSenseM....
7186
/// Coefficients: dense vector.
87+
///
88+
/// @note All pointers should stay valid until
89+
/// loading the model into NLSolver.
7290
void SetLinearObjective(int sense, double c0,
7391
const double* c = nullptr)
7492
{ obj_sense_=sense; obj_c0_=c0; obj_c_=c; }
7593

7694
/// Add Q for the objective quadratic part 0.5 @ x.T @ Q @ x.
7795
/// Format: NLW2_HessianFormat...
96+
///
97+
/// @note All pointers should stay valid until
98+
/// loading the model into NLSolver.
7899
void SetHessian(int format, NLW2_SparseMatrix_C Q)
79100
{ Q_format_ = format; Q_ = Q; }
80101

81102
/// Set obj name
103+
///
104+
/// @note All pointers should stay valid until
105+
/// loading the model into NLSolver.
82106
void SetObjName(const char* nm) { obj_name_=(nm ? nm : ""); }
83107

84108
/// Information exported by WriteNL()

nl-writer2/nlwpy/src/nlw_bindings.cc

+76-43
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,25 @@
1+
/**
2+
NL Writer Python bindings.
3+
4+
Copyright (C) 2024 AMPL Optimization Inc.
5+
6+
Permission to use, copy, modify, and distribute this software and its
7+
documentation for any purpose and without fee is hereby granted,
8+
provided that the above copyright notice appear in all copies and that
9+
both that the copyright notice and this permission notice and warranty
10+
disclaimer appear in supporting documentation.
11+
12+
The author and AMPL Optimization Inc disclaim all warranties with
13+
regard to this software, including all implied warranties of
14+
merchantability and fitness. In no event shall the author be liable
15+
for any special, indirect or consequential damages or any damages
16+
whatsoever resulting from loss of use, data or profits, whether in an
17+
action of contract, negligence or other tortious action, arising out
18+
of or in connection with the use or performance of this software.
19+
20+
Author: Gleb Belov
21+
*/
22+
123
#include <string>
224

325
#include <pybind11/pybind11.h>
@@ -16,12 +38,12 @@ struct NLWPY_ColData {
1638
/// Num vars
1739
int num_col_;
1840
/// lower bounds
19-
py::array_t<const double> lower_;
41+
std::vector<double> lower_;
2042
/// upper bounds
21-
py::array_t<const double> upper_;
43+
std::vector<double> upper_;
2244
/// type: NLW2_VarType...
2345
/// Set to NULL if all continuous.
24-
py::array_t<const int> type_;
46+
std::vector<int> type_;
2547
};
2648

2749
/// Sparse matrix.
@@ -36,33 +58,36 @@ struct NLWPY_SparseMatrix {
3658
/// Nonzeros
3759
size_t num_nz_;
3860
/// Row / col starts
39-
py::array_t<const size_t> start_;
61+
std::vector<size_t> start_;
4062
/// Entry index
41-
py::array_t<const int> index_;
63+
std::vector<int> index_;
4264
/// Entry value
43-
py::array_t<const double> value_;
65+
std::vector<double> value_;
4466
};
4567

4668
/// NLWPY_NLModel.
47-
/// TODO check array lengths etc.
69+
/// @todo check array lengths etc.
70+
///
71+
/// @note In contrast to C/C++, NLWPY copies all data
72+
/// so the provided arrays/views can be deleted straightaway.
4873
class NLWPY_NLModel {
4974
public:
5075
/// Construct
51-
NLWPY_NLModel(const char* nm=nullptr)
52-
: prob_name_(nm ? nm : "NLWPY_Model"),
53-
nlme_(prob_name_)
76+
NLWPY_NLModel(std::string nm={})
77+
: prob_name_(std::move(nm)),
78+
nlme_(prob_name_.c_str())
5479
{ }
5580

5681
/// Add variables (all at once.).
57-
/// TODO ty can be None.
82+
/// @todo ty can be None.
5883
void SetCols(int n,
59-
py::array_t<const double> lb,
60-
py::array_t<const double> ub,
61-
py::array_t<const int> ty) {
84+
std::vector<double> lb,
85+
std::vector<double> ub,
86+
std::vector<int> ty) {
6287
vars_.num_col_ = n;
63-
vars_.lower_ = lb;
64-
vars_.upper_ = ub;
65-
vars_.type_ = ty;
88+
vars_.lower_ = std::move(lb);
89+
vars_.upper_ = std::move(ub);
90+
vars_.type_ = std::move(ty);
6691
nlme_.SetCols({n,
6792
vars_.lower_.data(),
6893
vars_.upper_.data(),
@@ -71,28 +96,31 @@ class NLWPY_NLModel {
7196
}
7297

7398
/// Add variable names
74-
void SetColNames(std::vector<const char *> nm) {
99+
void SetColNames(std::vector<std::string> nm) {
75100
var_names_=std::move(nm);
76-
nlme_.SetColNames(var_names_.data());
101+
var_names_c_.resize(var_names_.size());
102+
for (auto i=var_names_.size(); i--; )
103+
var_names_c_[i] = var_names_[i].c_str();
104+
nlme_.SetColNames(var_names_c_.data());
77105
}
78106

79107
/// Add linear constraints (all at once).
80108
/// Only rowwise matrix supported.
81109
void SetRows(
82110
int nr,
83-
py::array_t<const double> rlb, py::array_t<const double> rub,
111+
std::vector<double> rlb, std::vector<double> rub,
84112
int format, // TODO enum
85113
size_t nnz,
86-
py::array_t<const size_t> st,
114+
std::vector<size_t> st,
87115
/// Entry index
88-
py::array_t<const int> ind,
116+
std::vector<int> ind,
89117
/// Entry value
90-
py::array_t<const double> val
118+
std::vector<double> val
91119
) {
92-
num_row_=nr; row_lb_=rlb; row_ub_=rub;
120+
num_row_=nr; row_lb_=std::move(rlb); row_ub_=std::move(rub);
93121
A_={
94122
nr, format,
95-
nnz, st, ind, val
123+
nnz, std::move(st), std::move(ind), std::move(val)
96124
};
97125
nlme_.SetRows(nr, row_lb_.data(), row_ub_.data(),
98126
{
@@ -103,17 +131,20 @@ class NLWPY_NLModel {
103131
}
104132

105133
/// Add constraint names
106-
void SetRowNames(std::vector<const char *> nm) {
134+
void SetRowNames(std::vector<std::string> nm) {
107135
row_names_=std::move(nm);
108-
nlme_.SetRowNames(row_names_.data());
136+
row_names_c_.resize(row_names_.size());
137+
for (auto i=row_names_.size(); i--; )
138+
row_names_c_[i] = row_names_[i].c_str();
139+
nlme_.SetRowNames(row_names_c_.data());
109140
}
110141

111142
/// Add linear objective (only single objective supported.)
112143
/// Sense: NLW2_ObjSenseM....
113144
/// Coefficients: dense vector.
114145
void SetLinearObjective(int sense, double c0,
115-
py::array_t<const double> c) {
116-
obj_sense_=sense; obj_c0_=c0; obj_c_=c;
146+
std::vector<double> c) {
147+
obj_sense_=sense; obj_c0_=c0; obj_c_=std::move(c);
117148
nlme_.SetLinearObjective(sense, c0, obj_c_.data());
118149
}
119150

@@ -122,16 +153,16 @@ class NLWPY_NLModel {
122153
void SetHessian(int nr,
123154
int format, // TODO enum
124155
size_t nnz,
125-
py::array_t<const size_t> st,
156+
std::vector<size_t> st,
126157
/// Entry index
127-
py::array_t<const int> ind,
158+
std::vector<int> ind,
128159
/// Entry value
129-
py::array_t<const double> val
160+
std::vector<double> val
130161
) {
131162
Q_format_ = format;
132163
Q_={
133164
nr, 0,
134-
nnz, st, ind, val
165+
nnz, std::move(st), std::move(ind), std::move(val)
135166
};
136167
nlme_.SetHessian(format, {
137168
nr, 0, nnz,
@@ -141,31 +172,33 @@ class NLWPY_NLModel {
141172
}
142173

143174
/// Set obj name
144-
void SetObjName(const char* nm) {
145-
obj_name_=(nm ? nm : "");
146-
nlme_.SetObjName(obj_name_);
175+
void SetObjName(std::string nm) {
176+
obj_name_=std::move(nm);
177+
nlme_.SetObjName(obj_name_.c_str());
147178
}
148179

149180
/// Get the model
150181
const mp::NLModel& GetModel() const { return nlme_; }
151182

152183
private:
153184
/// Store the strings/arrays to keep the memory
154-
const char* prob_name_ {"NLWPY_Model"};
185+
std::string prob_name_ {"NLWPY_Model"};
155186
mp::NLModel nlme_;
156187
NLWPY_ColData vars_ {};
157-
std::vector<const char *> var_names_ {};
188+
std::vector<std::string> var_names_ {};
189+
std::vector<const char*> var_names_c_ {};
158190
NLWPY_SparseMatrix A_ {};
159191
int num_row_ {};
160-
py::array_t<const double> row_lb_ {};
161-
py::array_t<const double> row_ub_ {};
162-
std::vector<const char *> row_names_ {};
192+
std::vector<double> row_lb_ {};
193+
std::vector<double> row_ub_ {};
194+
std::vector<std::string> row_names_ {};
195+
std::vector<const char*> row_names_c_ {};
163196
int obj_sense_ {};
164197
double obj_c0_ {};
165-
py::array_t<const double> obj_c_ {};
198+
std::vector<double> obj_c_ {};
166199
int Q_format_ {};
167200
NLWPY_SparseMatrix Q_ {};
168-
const char* obj_name_ {"obj[1]"};
201+
std::string obj_name_ {"obj[1]"};
169202
};
170203

171204
mp::NLSolution NLW2_Solve(mp::NLSolver& nls,

0 commit comments

Comments
 (0)