Skip to content

Commit

Permalink
NLWPY: store data copies internally #30
Browse files Browse the repository at this point in the history
No need to keep the arrays around
  • Loading branch information
glebbelov committed Feb 19, 2024
1 parent e3ffc3f commit 856c482
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 47 deletions.
24 changes: 24 additions & 0 deletions nl-writer2/include/api/c/nl-model-c.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,35 @@ typedef struct NLW2_NLModel_C {
/// Construct NLW2_NLModel_C
///
/// @param probname: can be NULL.
///
/// @note All model data pointers should stay valid until
/// loading the model into NLW2_NLSolver_C.
NLW2_NLModel_C NLW2_MakeNLModel_C(const char* probname);

/// Destroy NLW2_NLModel_C
void NLW2_DestroyNLModel_C(NLW2_NLModel_C* );

/// Add variables (all at once.)
///
/// @note All model data pointers should stay valid until
/// loading the model into NLW2_NLSolver_C.
void NLW2_SetCols_C(NLW2_NLModel_C* ,
int num_col,
const double *lower,
const double *upper,
const int *type);

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

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

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

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

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

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

/// Compute objective value
Expand Down
28 changes: 26 additions & 2 deletions nl-writer2/include/mp/nl-model.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,43 +42,67 @@ class NLUtils;
/// For fully nonlinear models with expression trees,
/// use NLSolver with NLWriter2/NLFeeder2.
///
/// All pointers should stay valid until
/// @note All pointers should stay valid until
/// loading the model into NLSolver.
class NLModel {
public:
/// Construct
/// Construct.
///
/// @note All pointers should stay valid until
/// loading the model into NLSolver.
NLModel(const char* probname = nullptr)
: prob_name_(probname ? probname : "NLModelInstance") { }

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

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

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

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

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

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

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

/// Information exported by WriteNL()
Expand Down
119 changes: 76 additions & 43 deletions nl-writer2/nlwpy/src/nlw_bindings.cc
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
/**
NL Writer Python bindings.
Copyright (C) 2024 AMPL Optimization Inc.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that the copyright notice and this permission notice and warranty
disclaimer appear in supporting documentation.
The author and AMPL Optimization Inc disclaim all warranties with
regard to this software, including all implied warranties of
merchantability and fitness. In no event shall the author be liable
for any special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether in an
action of contract, negligence or other tortious action, arising out
of or in connection with the use or performance of this software.
Author: Gleb Belov
*/

#include <string>

#include <pybind11/pybind11.h>
Expand All @@ -16,12 +38,12 @@ struct NLWPY_ColData {
/// Num vars
int num_col_;
/// lower bounds
py::array_t<const double> lower_;
std::vector<double> lower_;
/// upper bounds
py::array_t<const double> upper_;
std::vector<double> upper_;
/// type: NLW2_VarType...
/// Set to NULL if all continuous.
py::array_t<const int> type_;
std::vector<int> type_;
};

/// Sparse matrix.
Expand All @@ -36,33 +58,36 @@ struct NLWPY_SparseMatrix {
/// Nonzeros
size_t num_nz_;
/// Row / col starts
py::array_t<const size_t> start_;
std::vector<size_t> start_;
/// Entry index
py::array_t<const int> index_;
std::vector<int> index_;
/// Entry value
py::array_t<const double> value_;
std::vector<double> value_;
};

/// NLWPY_NLModel.
/// TODO check array lengths etc.
/// @todo check array lengths etc.
///
/// @note In contrast to C/C++, NLWPY copies all data
/// so the provided arrays/views can be deleted straightaway.
class NLWPY_NLModel {
public:
/// Construct
NLWPY_NLModel(const char* nm=nullptr)
: prob_name_(nm ? nm : "NLWPY_Model"),
nlme_(prob_name_)
NLWPY_NLModel(std::string nm={})
: prob_name_(std::move(nm)),
nlme_(prob_name_.c_str())
{ }

/// Add variables (all at once.).
/// TODO ty can be None.
/// @todo ty can be None.
void SetCols(int n,
py::array_t<const double> lb,
py::array_t<const double> ub,
py::array_t<const int> ty) {
std::vector<double> lb,
std::vector<double> ub,
std::vector<int> ty) {
vars_.num_col_ = n;
vars_.lower_ = lb;
vars_.upper_ = ub;
vars_.type_ = ty;
vars_.lower_ = std::move(lb);
vars_.upper_ = std::move(ub);
vars_.type_ = std::move(ty);
nlme_.SetCols({n,
vars_.lower_.data(),
vars_.upper_.data(),
Expand All @@ -71,28 +96,31 @@ class NLWPY_NLModel {
}

/// Add variable names
void SetColNames(std::vector<const char *> nm) {
void SetColNames(std::vector<std::string> nm) {
var_names_=std::move(nm);
nlme_.SetColNames(var_names_.data());
var_names_c_.resize(var_names_.size());
for (auto i=var_names_.size(); i--; )
var_names_c_[i] = var_names_[i].c_str();
nlme_.SetColNames(var_names_c_.data());
}

/// Add linear constraints (all at once).
/// Only rowwise matrix supported.
void SetRows(
int nr,
py::array_t<const double> rlb, py::array_t<const double> rub,
std::vector<double> rlb, std::vector<double> rub,
int format, // TODO enum
size_t nnz,
py::array_t<const size_t> st,
std::vector<size_t> st,
/// Entry index
py::array_t<const int> ind,
std::vector<int> ind,
/// Entry value
py::array_t<const double> val
std::vector<double> val
) {
num_row_=nr; row_lb_=rlb; row_ub_=rub;
num_row_=nr; row_lb_=std::move(rlb); row_ub_=std::move(rub);
A_={
nr, format,
nnz, st, ind, val
nnz, std::move(st), std::move(ind), std::move(val)
};
nlme_.SetRows(nr, row_lb_.data(), row_ub_.data(),
{
Expand All @@ -103,17 +131,20 @@ class NLWPY_NLModel {
}

/// Add constraint names
void SetRowNames(std::vector<const char *> nm) {
void SetRowNames(std::vector<std::string> nm) {
row_names_=std::move(nm);
nlme_.SetRowNames(row_names_.data());
row_names_c_.resize(row_names_.size());
for (auto i=row_names_.size(); i--; )
row_names_c_[i] = row_names_[i].c_str();
nlme_.SetRowNames(row_names_c_.data());
}

/// Add linear objective (only single objective supported.)
/// Sense: NLW2_ObjSenseM....
/// Coefficients: dense vector.
void SetLinearObjective(int sense, double c0,
py::array_t<const double> c) {
obj_sense_=sense; obj_c0_=c0; obj_c_=c;
std::vector<double> c) {
obj_sense_=sense; obj_c0_=c0; obj_c_=std::move(c);
nlme_.SetLinearObjective(sense, c0, obj_c_.data());
}

Expand All @@ -122,16 +153,16 @@ class NLWPY_NLModel {
void SetHessian(int nr,
int format, // TODO enum
size_t nnz,
py::array_t<const size_t> st,
std::vector<size_t> st,
/// Entry index
py::array_t<const int> ind,
std::vector<int> ind,
/// Entry value
py::array_t<const double> val
std::vector<double> val
) {
Q_format_ = format;
Q_={
nr, 0,
nnz, st, ind, val
nnz, std::move(st), std::move(ind), std::move(val)
};
nlme_.SetHessian(format, {
nr, 0, nnz,
Expand All @@ -141,31 +172,33 @@ class NLWPY_NLModel {
}

/// Set obj name
void SetObjName(const char* nm) {
obj_name_=(nm ? nm : "");
nlme_.SetObjName(obj_name_);
void SetObjName(std::string nm) {
obj_name_=std::move(nm);
nlme_.SetObjName(obj_name_.c_str());
}

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

private:
/// Store the strings/arrays to keep the memory
const char* prob_name_ {"NLWPY_Model"};
std::string prob_name_ {"NLWPY_Model"};
mp::NLModel nlme_;
NLWPY_ColData vars_ {};
std::vector<const char *> var_names_ {};
std::vector<std::string> var_names_ {};
std::vector<const char*> var_names_c_ {};
NLWPY_SparseMatrix A_ {};
int num_row_ {};
py::array_t<const double> row_lb_ {};
py::array_t<const double> row_ub_ {};
std::vector<const char *> row_names_ {};
std::vector<double> row_lb_ {};
std::vector<double> row_ub_ {};
std::vector<std::string> row_names_ {};
std::vector<const char*> row_names_c_ {};
int obj_sense_ {};
double obj_c0_ {};
py::array_t<const double> obj_c_ {};
std::vector<double> obj_c_ {};
int Q_format_ {};
NLWPY_SparseMatrix Q_ {};
const char* obj_name_ {"obj[1]"};
std::string obj_name_ {"obj[1]"};
};

mp::NLSolution NLW2_Solve(mp::NLSolver& nls,
Expand Down
Loading

0 comments on commit 856c482

Please sign in to comment.