qp_to_nlp.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 
26 #include "qp_to_nlp.hpp"
27 #include "casadi/core/nlpsol.hpp"
28 #include "casadi/core/nlpsol_impl.hpp"
29 
30 namespace casadi {
31 
32  extern "C"
33  int CASADI_CONIC_NLPSOL_EXPORT
34  casadi_register_conic_nlpsol(Conic::Plugin* plugin) {
35  plugin->creator = QpToNlp::creator;
36  plugin->name = "nlpsol";
37  plugin->doc = QpToNlp::meta_doc.c_str();
38  plugin->version = CASADI_VERSION;
39  plugin->options = &QpToNlp::options_;
40  plugin->deserialize = &QpToNlp::deserialize;
41  return 0;
42  }
43 
44  extern "C"
45  void CASADI_CONIC_NLPSOL_EXPORT casadi_load_conic_nlpsol() {
47  }
48 
49  QpToNlp::QpToNlp(const std::string& name, const std::map<std::string, Sparsity> &st)
50  : Conic(name, st) {
51  }
52 
54  clear_mem();
55  }
56 
57 
58  void* QpToNlp::alloc_mem() const {
59  QpToNlpMemory *m = new QpToNlpMemory();
60  m->nlp_mem = solver_.checkout();
61  return m;
62  }
63 
64  void QpToNlp::free_mem(void *mem) const {
65  auto m = static_cast<QpToNlpMemory*>(mem);
66  solver_.release(m->nlp_mem);
67  delete m;
68  }
69 
70 
72  = {{&Conic::options_},
73  {{"nlpsol",
74  {OT_STRING,
75  "Name of solver."}},
76  {"nlpsol_options",
77  {OT_DICT,
78  "Options to be passed to solver."}}
79  }
80  };
81 
82  void QpToNlp::init(const Dict& opts) {
83  // Initialize the base classes
84  Conic::init(opts);
85 
86  // Default options
87  std::string nlpsol_plugin;
89 
90  // Read user options
91  for (auto&& op : opts) {
92  if (op.first=="nlpsol") {
93  nlpsol_plugin = op.second.to_string();
94  } else if (op.first=="nlpsol_options") {
95  nlpsol_options = op.second;
96  }
97  }
98 
99  // Create a symbolic matrix for the decision variables
100  SX X = SX::sym("X", nx_, 1);
101 
102  // Parameters to the problem
103  SX H = SX::sym("H", H_);
104  SX G = SX::sym("G", nx_);
105  SX A = SX::sym("A", A_);
106 
107  // Put parameters in a vector
108  std::vector<SX> par;
109  par.push_back(H.nonzeros());
110  par.push_back(G.nonzeros());
111  par.push_back(A.nonzeros());
112 
113  // The nlp looks exactly like a mathematical description of the NLP
114  SXDict nlp = {{"x", X}, {"p", vertcat(par)},
115  {"f", densify(mtimes(G.T(), X) + 0.5*mtimes(mtimes(X.T(), H), X))},
116  {"g", densify(mtimes(A, X))}};
117 
118  // Create an Nlpsol instance
119  casadi_assert(!nlpsol_plugin.empty(), "'nlpsol' option has not been set");
120  solver_ = nlpsol("nlpsol", nlpsol_plugin, nlp, nlpsol_options);
121  alloc(solver_);
122 
123  // Allocate storage for NLP solver parameters
124  alloc_w(solver_.nnz_in(NLPSOL_P), true);
125  }
126 
128  solve(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const {
129  // Inputs
130  const double *h_, *g_, *a_, *lba_, *uba_, *lbx_, *ubx_, *x0_;
131  // Outputs
132  double *x_, *f_, *lam_a_, *lam_x_;
133 
134  // Get input pointers
135  h_ = arg[CONIC_H];
136  g_ = arg[CONIC_G];
137  a_ = arg[CONIC_A];
138  lba_ = arg[CONIC_LBA];
139  uba_ = arg[CONIC_UBA];
140  lbx_ = arg[CONIC_LBX];
141  ubx_ = arg[CONIC_UBX];
142  x0_ = arg[CONIC_X0];
143 
144  // Get output pointers
145  x_ = res[CONIC_X];
146  f_ = res[CONIC_COST];
147  lam_a_ = res[CONIC_LAM_A];
148  lam_x_ = res[CONIC_LAM_X];
149 
150  // Buffers for calling the NLP solver
151  const double** arg1 = arg + n_in_;
152  double** res1 = res + n_out_;
153  std::fill_n(arg1, static_cast<casadi_int>(NLPSOL_NUM_IN), nullptr);
154  std::fill_n(res1, static_cast<casadi_int>(NLPSOL_NUM_OUT), nullptr);
155 
156  // NLP inputs
157  arg1[NLPSOL_X0] = x0_;
158  arg1[NLPSOL_LBG] = lba_;
159  arg1[NLPSOL_UBG] = uba_;
160  arg1[NLPSOL_LBX] = lbx_;
161  arg1[NLPSOL_UBX] = ubx_;
162 
163  // NLP parameters
164  arg1[NLPSOL_P] = w;
165 
166  // Quadratic term
167  casadi_int nh = nnz_in(CONIC_H);
168  if (h_) {
169  std::copy_n(h_, nh, w);
170  } else {
171  std::fill_n(w, nh, 0);
172  }
173  w += nh;
174 
175  // Linear objective term
176  casadi_int ng = nnz_in(CONIC_G);
177  if (g_) {
178  std::copy_n(g_, ng, w);
179  } else {
180  std::fill_n(w, ng, 0);
181  }
182  w += ng;
183 
184  // Linear constraints
185  casadi_int na = nnz_in(CONIC_A);
186  if (a_) {
187  std::copy_n(a_, na, w);
188  } else {
189  std::fill_n(w, na, 0);
190  }
191  w += na;
192 
193  // Solution
194  res1[NLPSOL_X] = x_;
195  res1[NLPSOL_F] = f_;
196  res1[NLPSOL_LAM_X] = lam_x_;
197  res1[NLPSOL_LAM_G] = lam_a_;
198 
199  // Solve the NLP
200  auto m = static_cast<QpToNlpMemory*>(mem);
201  int ret = solver_(arg1, res1, iw, w, m->nlp_mem);
202  auto nlp_m = static_cast<NlpsolMemory*>(solver_.memory(m->nlp_mem));
203 
204  m->d_qp.success = nlp_m->success;
205  m->d_qp.unified_return_status = nlp_m->unified_return_status;
206  return ret;
207  }
208 
209  Dict QpToNlp::get_stats(void* mem) const {
210  Dict stats = Conic::get_stats(mem);
211  auto m = static_cast<QpToNlpMemory*>(mem);
212  auto nlp_m = static_cast<NlpsolMemory*>(solver_.memory(m->nlp_mem));
213  stats["solver_stats"] = solver_->get_stats(nlp_m);
214  return stats;
215  }
216 
218  s.version("QpToNlp", 1);
219  s.unpack("QpToNlp::solver", solver_);
220  }
221 
224 
225  s.version("QpToNlp", 1);
226  s.pack("QpToNlp::solver", solver_);
227  }
228 
229 } // namespace casadi
Internal class.
Definition: conic_impl.hpp:44
static const Options options_
Options.
Definition: conic_impl.hpp:83
casadi_int nx_
Number of decision variables.
Definition: conic_impl.hpp:169
Sparsity H_
Problem structure.
Definition: conic_impl.hpp:166
void init(const Dict &opts) override
Initialize.
Definition: conic.cpp:412
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: conic.cpp:738
Dict get_stats(void *mem) const override
Get all statistics.
Definition: conic.cpp:711
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
Dict get_stats(void *mem) const override
Get all statistics.
size_t n_in_
Number of inputs and outputs.
casadi_int nnz_in() const
Number of input/output nonzeros.
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
void alloc(const Function &f, bool persistent=false, int num_threads=1)
Ensure work vectors long enough to evaluate function.
void release(int mem) const
Release a memory object.
Definition: function.cpp:1777
casadi_int checkout() const
Checkout a memory object.
Definition: function.cpp:1773
void * memory(int ind) const
Get memory object.
Definition: function.cpp:1781
casadi_int nnz_in() const
Get number of input nonzeros.
Definition: function.cpp:851
static Matrix< Scalar > sym(const std::string &name, casadi_int nrow=1, casadi_int ncol=1)
Create an nrow-by-ncol symbolic primitive.
Sparse matrix class. SX and DM are specializations.
Definition: matrix_decl.hpp:99
std::vector< Scalar > & nonzeros()
Matrix< Scalar > T() const
Transpose the matrix.
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
void clear_mem()
Clear all memory (called from destructor)
void * alloc_mem() const override
Create memory block.
Definition: qp_to_nlp.cpp:58
QpToNlp(const std::string &name, const std::map< std::string, Sparsity > &st)
Create a new Solver.
Definition: qp_to_nlp.cpp:49
static Conic * creator(const std::string &name, const std::map< std::string, Sparsity > &st)
Create a new QP Solver.
Definition: qp_to_nlp.hpp:71
Function solver_
Solve with.
Definition: qp_to_nlp.hpp:110
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
Definition: qp_to_nlp.hpp:115
static const Options options_
Options.
Definition: qp_to_nlp.hpp:93
~QpToNlp() override
Destructor.
Definition: qp_to_nlp.cpp:53
int solve(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Solve the QP.
Definition: qp_to_nlp.cpp:128
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: qp_to_nlp.cpp:222
void init(const Dict &opts) override
Initialize.
Definition: qp_to_nlp.cpp:82
Dict get_stats(void *mem) const override
Get all statistics.
Definition: qp_to_nlp.cpp:209
static const std::string meta_doc
A documentation string.
Definition: qp_to_nlp.hpp:107
void free_mem(void *mem) const override
Free memory block.
Definition: qp_to_nlp.cpp:64
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
std::vector< std::string > nlpsol_options(const std::string &name)
Get all options for a plugin.
Definition: nlpsol.cpp:830
Function nlpsol(const std::string &name, const std::string &solver, const SXDict &nlp, const Dict &opts)
Definition: nlpsol.cpp:118
The casadi namespace.
Definition: archiver.cpp:28
@ NLPSOL_P
Value of fixed parameters (np x 1)
Definition: nlpsol.hpp:198
@ NLPSOL_UBX
Decision variables upper bound (nx x 1), default +inf.
Definition: nlpsol.hpp:202
@ NLPSOL_X0
Decision variables, initial guess (nx x 1)
Definition: nlpsol.hpp:196
@ NLPSOL_UBG
Constraints upper bound (ng x 1), default +inf.
Definition: nlpsol.hpp:206
@ NLPSOL_NUM_IN
Definition: nlpsol.hpp:211
@ NLPSOL_LBG
Constraints lower bound (ng x 1), default -inf.
Definition: nlpsol.hpp:204
@ NLPSOL_LBX
Decision variables lower bound (nx x 1), default -inf.
Definition: nlpsol.hpp:200
@ NLPSOL_X
Decision variables at the optimal solution (nx x 1)
Definition: nlpsol.hpp:217
@ NLPSOL_NUM_OUT
Definition: nlpsol.hpp:228
@ NLPSOL_F
Cost function value at the optimal solution (1 x 1)
Definition: nlpsol.hpp:219
@ NLPSOL_LAM_G
Lagrange multipliers for bounds on G at the solution (ng x 1)
Definition: nlpsol.hpp:225
@ NLPSOL_LAM_X
Lagrange multipliers for bounds on X at the solution (nx x 1)
Definition: nlpsol.hpp:223
@ CONIC_UBA
dense, (nc x 1)
Definition: conic.hpp:181
@ CONIC_X0
dense, (n x 1)
Definition: conic.hpp:187
@ CONIC_A
The matrix A: sparse, (nc x n) - product with x must be dense.
Definition: conic.hpp:177
@ CONIC_G
The vector g: dense, (n x 1)
Definition: conic.hpp:175
@ CONIC_LBA
dense, (nc x 1)
Definition: conic.hpp:179
@ CONIC_UBX
dense, (n x 1)
Definition: conic.hpp:185
@ CONIC_H
Definition: conic.hpp:173
@ CONIC_LBX
dense, (n x 1)
Definition: conic.hpp:183
std::map< std::string, SX > SXDict
Definition: sx_fwd.hpp:40
void CASADI_CONIC_NLPSOL_EXPORT casadi_load_conic_nlpsol()
Definition: qp_to_nlp.cpp:45
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
int CASADI_CONIC_NLPSOL_EXPORT casadi_register_conic_nlpsol(Conic::Plugin *plugin)
Definition: qp_to_nlp.cpp:34
@ CONIC_X
The primal solution.
Definition: conic.hpp:201
@ CONIC_LAM_A
The dual solution corresponding to linear bounds.
Definition: conic.hpp:205
@ CONIC_COST
The optimal cost.
Definition: conic.hpp:203
@ CONIC_LAM_X
The dual solution corresponding to simple bounds.
Definition: conic.hpp:207
Integrator memory.
Definition: nlpsol_impl.hpp:40
Options metadata for a class.
Definition: options.hpp:40