solve_impl.hpp
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 #ifndef CASADI_SOLVE_IMPL_HPP
27 #define CASADI_SOLVE_IMPL_HPP
28 
29 #include "solve.hpp"
30 #include "linsol_internal.hpp"
31 
32 namespace casadi {
33 
34  template<bool Tr>
35  Solve<Tr>::Solve(const MX& r, const MX& A) {
36  casadi_assert(r.size1() == A.size2(),
37  "Solve::Solve: dimension mismatch. Got r " + r.dim() + " and A " + A.dim());
38  set_dep(r, A);
39  set_sparsity(r.sparsity());
40  }
41 
42  template<bool Tr>
43  std::string Solve<Tr>::disp(const std::vector<std::string>& arg) const {
44  std::stringstream ss;
45  ss << "(" << mod_prefix() << arg.at(1) << mod_suffix();
46  if (Tr) ss << "'";
47  ss << "\\" << arg.at(0) << ")";
48  return ss.str();
49  }
50 
51  template<bool Tr>
52  LinsolCall<Tr>::LinsolCall(const MX& r, const MX& A, const Linsol& linear_solver) :
53  Solve<Tr>(r, A), linsol_(linear_solver) {
54  }
55 
56  template<bool Tr>
57  int LinsolCall<Tr>::eval(const double** arg, double** res, casadi_int* iw, double* w) const {
58  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
59  scoped_checkout<Linsol> mem(linsol_);
60 
61  auto m = static_cast<LinsolMemory*>(linsol_->memory(mem));
62  // Reset statistics
63  for (auto&& s : m->fstats) s.second.reset();
64  if (m->t_total) m->t_total->tic();
65 
66  if (linsol_.sfact(arg[1], mem)) return 1;
67  if (linsol_.nfact(arg[1], mem)) return 1;
68  if (linsol_.solve(arg[1], res[0], this->dep(0).size2(), Tr, mem)) return 1;
69 
70  linsol_->print_time(m->fstats);
71 
72  return 0;
73  }
74 
75  template<bool Tr>
76  int LinsolCall<Tr>::eval_sx(const SXElem** arg, SXElem** res, casadi_int* iw, SXElem* w) const {
77  linsol_->linsol_eval_sx(arg, res, iw, w, linsol_->memory(0), Tr, this->dep(0).size2());
78  return 0;
79  }
80 
81  template<bool Tr>
82  void Solve<Tr>::eval_mx(const std::vector<MX>& arg, std::vector<MX>& res,
83  const std::vector<bool>& unique) const {
84  if (arg[0].is_zero()) {
85  res[0] = MX(arg[0].size());
86  } else {
87  res[0] = solve(arg[1], arg[0], Tr);
88  }
89  }
90 
91  template<bool Tr>
92  void Solve<Tr>::ad_forward(const std::vector<std::vector<MX> >& fseed,
93  std::vector<std::vector<MX> >& fsens) const {
94  // Nondifferentiated inputs and outputs
95  std::vector<MX> arg(this->n_dep());
96  for (casadi_int i=0; i<arg.size(); ++i) arg[i] = this->dep(i);
97  std::vector<MX> res(this->nout());
98  for (casadi_int i=0; i<res.size(); ++i) res[i] = this->get_output(i);
99 
100  // Number of derivatives
101  casadi_int nfwd = fseed.size();
102  const MX& A = arg[1];
103  const MX& X = res[0];
104 
105  // Solve for all directions at once
106  std::vector<MX> rhs(nfwd);
107  std::vector<casadi_int> col_offset(nfwd+1, 0);
108  for (casadi_int d=0; d<nfwd; ++d) {
109  const MX& B_hat = fseed[d][0];
110  const MX& A_hat = fseed[d][1];
111  rhs[d] = Tr ? B_hat - mtimes(A_hat.T(), X) : B_hat - mtimes(A_hat, X);
112  col_offset[d+1] = col_offset[d] + rhs[d].size2();
113  }
114  rhs = horzsplit(solve(A, horzcat(rhs), Tr), col_offset);
115 
116  // Fetch result
117  fsens.resize(nfwd);
118  for (casadi_int d=0; d<nfwd; ++d) {
119  fsens[d].resize(1);
120  fsens[d][0] = rhs[d];
121  }
122  }
123 
124  template<bool Tr>
125  void Solve<Tr>::ad_reverse(const std::vector<std::vector<MX> >& aseed,
126  std::vector<std::vector<MX> >& asens) const {
127  // Nondifferentiated inputs and outputs
128  std::vector<MX> arg(this->n_dep());
129  for (casadi_int i=0; i<arg.size(); ++i) arg[i] = this->dep(i);
130  std::vector<MX> res(this->nout());
131  for (casadi_int i=0; i<res.size(); ++i) res[i] = this->get_output(i);
132 
133  // Number of derivatives
134  casadi_int nadj = aseed.size();
135  const MX& A = arg[1];
136  const MX& X = res[0];
137 
138  // Solve for all directions at once
139  std::vector<MX> rhs(nadj);
140  std::vector<casadi_int> col_offset(nadj+1, 0);
141  for (casadi_int d=0; d<nadj; ++d) {
142  rhs[d] = aseed[d][0];
143  col_offset[d+1] = col_offset[d] + rhs[d].size2();
144  }
145  rhs = horzsplit(solve(A, horzcat(rhs), !Tr), col_offset);
146 
147  // Collect sensitivities
148  asens.resize(nadj);
149  for (casadi_int d=0; d<nadj; ++d) {
150  asens[d].resize(2);
151 
152  // Propagate to A
153  MX a;
154  if (!Tr) {
155  a = -mac(rhs[d], X.T(), MX::zeros(A.sparsity()));
156  } else {
157  a = -mac(X, rhs[d].T(), MX::zeros(A.sparsity()));
158  }
159  if (asens[d][1].is_empty(true)) {
160  asens[d][1] = a;
161  } else {
162  asens[d][1] += a;
163  }
164 
165  // Propagate to B
166  if (asens[d][0].is_empty(true)) {
167  asens[d][0] = rhs[d];
168  } else {
169  asens[d][0] += rhs[d];
170  }
171  }
172  }
173 
174  template<bool Tr>
175  int Solve<Tr>::sp_forward(const bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w) const {
176  // Number of right-hand-sides
177  casadi_int nrhs = dep(0).size2();
178 
179  // Sparsities
180  const Sparsity& A_sp = this->A_sp();
181  const casadi_int* A_colind = A_sp.colind();
182  const casadi_int* A_row = A_sp.row();
183  casadi_int n = A_sp.size1();
184 
185  // Get pointers to data
186  const bvec_t *B=arg[0], *A = arg[1];
187  bvec_t* X = res[0];
188  bvec_t* tmp = w;
189 
190  // For all right-hand-sides
191  for (casadi_int r=0; r<nrhs; ++r) {
192  // Copy B to a temporary vector
193  std::copy(B, B+n, tmp);
194 
195  // Add A_hat contribution to tmp
196  for (casadi_int cc=0; cc<n; ++cc) {
197  for (casadi_int k=A_colind[cc]; k<A_colind[cc+1]; ++k) {
198  casadi_int rr = A_row[k];
199  tmp[Tr ? cc : rr] |= A[k];
200  }
201  }
202 
203  // Propagate to X
204  std::fill(X, X+n, 0);
205  A_sp.spsolve(X, tmp, Tr);
206 
207  // Continue to the next right-hand-side
208  B += n;
209  X += n;
210  }
211  return 0;
212  }
213 
214  template<bool Tr>
215  int Solve<Tr>::eval_activity(const bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w) const {
216  // X = A \ B. A's values cannot activate X on their own, so a zero right-hand-side
217  // column gives a zero result column. A nonzero column may, through a (generally
218  // dense) inverse, activate the whole column, so we keep this conservative: a result
219  // column is active iff its rhs column has any active entry. (We deliberately do not
220  // reuse sp_forward's structural spsolve: it requires seeding A into the work vector,
221  // which would reactivate a zero rhs and lose the zero-rhs guarantee.)
222  casadi_int n = A_sp().size1();
223  casadi_int nrhs = dep(0).size2();
224  const bvec_t* B = arg[0];
225  bvec_t* X = res[0];
226  for (casadi_int r=0; r<nrhs; ++r) {
227  bvec_t col = 0;
228  for (casadi_int i=0; i<n; ++i) col |= B[i];
229  std::fill(X, X+n, col);
230  B += n;
231  X += n;
232  }
233  return 0;
234  }
235 
236  template<bool Tr>
237  int Solve<Tr>::sp_reverse(bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w) const {
238  // Number of right-hand-sides
239  casadi_int nrhs = dep(0).size2();
240 
241  // Sparsities
242  const Sparsity& A_sp = this->A_sp();
243  const casadi_int* A_colind = A_sp.colind();
244  const casadi_int* A_row = A_sp.row();
245  casadi_int n = A_sp.size1();
246 
247  // Get pointers to data
248  bvec_t *B=arg[0], *A=arg[1], *X=res[0];
249  bvec_t* tmp = w;
250 
251  // For all right-hand-sides
252  for (casadi_int r=0; r<nrhs; ++r) {
253  // Solve transposed
254  std::fill(tmp, tmp+n, 0);
255  A_sp.spsolve(tmp, X, !Tr);
256 
257  // Clear seeds
258  std::fill(X, X+n, 0);
259 
260  // Propagate to B
261  for (casadi_int i=0; i<n; ++i) B[i] |= tmp[i];
262 
263  // Propagate to A
264  for (casadi_int cc=0; cc<n; ++cc) {
265  for (casadi_int k=A_colind[cc]; k<A_colind[cc+1]; ++k) {
266  casadi_int rr = A_row[k];
267  A[k] |= tmp[Tr ? cc : rr];
268  }
269  }
270 
271  // Continue to the next right-hand-side
272  B += n;
273  X += n;
274  }
275  return 0;
276  }
277 
278  template<bool Tr>
279  size_t LinsolCall<Tr>::sz_w() const {
280  return this->sparsity().size1();
281  }
282 
283  template<bool Tr>
285  // The generated C carves the QR factorization buffers from w
286  return linsol_->sz_w_fact();
287  }
288 
289  template<bool Tr>
291  const std::vector<casadi_int>& arg,
292  const std::vector<casadi_int>& res,
293  const std::vector<bool>& arg_is_ref,
294  std::vector<bool>& res_is_ref) const {
295  // Number of right-hand-sides
296  casadi_int nrhs = this->dep(0).size2();
297 
298  // Array for x
299  g.local("rr", "casadi_real", "*");
300  g << "rr = " << g.work(res[0], this->nnz(), false) << ";\n";
301 
302  // Array for A
303  g.local("ss", "const casadi_real", "*");
304  g << "ss = " << g.work(arg[1], this->dep(1).nnz(), arg_is_ref[1]) << ";\n";
305 
306  // Copy b to x if not inplace
307  if (arg[0]!=res[0] || arg_is_ref[0]) {
308  g << g.copy(g.work(arg[0], this->nnz(), arg_is_ref[0]), this->nnz(), "rr") << '\n';
309  }
310  // Solver specific codegen
311  linsol_->generate(g, "ss", "rr", nrhs, Tr);
312  }
313 
314  template<bool Tr>
317  }
318 
319  template<bool Tr>
322  s.pack("Solve::Tr", Tr);
323  }
324 
325  template<bool Tr>
327  }
328 
329  template<bool Tr>
331  bool tr;
332  s.unpack("Solve::Tr", tr);
333  casadi_error("Not implemented");
334  }
335 
336  template<bool Tr>
339  s.pack("Solve::Linsol", linsol_);
340  }
341 
342  template<bool Tr>
345  }
346 
347  template<bool Tr>
349  s.unpack("Solve::Linsol", linsol_);
350  }
351 
352  template<bool Tr>
354  bool tr;
355  s.unpack("Solve::Tr", tr);
356 
357  if (tr) {
358  return new LinsolCall<true>(s);
359  } else {
360  return new LinsolCall<false>(s);
361  }
362  }
363 
364  template<bool Tr>
365  TriuSolve<Tr>::TriuSolve(const MX& r, const MX& A) : Solve<Tr>(r, A) {
366  }
367 
368  template<bool Tr>
369  int TriuSolve<Tr>::eval(const double** arg, double** res, casadi_int* iw, double* w) const {
370  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
371  casadi_triusolve(this->dep(1).sparsity(), arg[1], res[0], Tr, false, this->dep(0).size2());
372  return 0;
373  }
374 
375  template<bool Tr>
376  int TriuSolve<Tr>::eval_sx(const SXElem** arg, SXElem** res, casadi_int* iw, SXElem* w) const {
377  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
378  casadi_triusolve(this->dep(1).sparsity(), arg[1], res[0], Tr, false, this->dep(0).size2());
379  return 0;
380  }
381 
382  template<bool Tr>
383  TrilSolve<Tr>::TrilSolve(const MX& r, const MX& A) : Solve<Tr>(r, A) {
384  }
385 
386  template<bool Tr>
387  int TrilSolve<Tr>::eval(const double** arg, double** res, casadi_int* iw, double* w) const {
388  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
389  casadi_trilsolve(this->dep(1).sparsity(), arg[1], res[0], Tr, false, this->dep(0).size2());
390  return 0;
391  }
392 
393  template<bool Tr>
394  int TrilSolve<Tr>::eval_sx(const SXElem** arg, SXElem** res, casadi_int* iw, SXElem* w) const {
395  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
396  casadi_trilsolve(this->dep(1).sparsity(), arg[1], res[0], Tr, false, this->dep(0).size2());
397  return 0;
398  }
399 
400  template<bool Tr>
401  SolveUnity<Tr>::SolveUnity(const MX& r, const MX& A) : Solve<Tr>(r, A) {
402  }
403 
404  template<bool Tr>
406 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
407  // Safe access to A_sp_
408  std::lock_guard<std::mutex> lock(A_sp_mtx_);
409 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
410  // Create on first call
411  if (A_sp_.is_null()) {
412  const Sparsity& no_diag = this->dep(1).sparsity();
413  A_sp_ = no_diag + Sparsity::diag(no_diag.size1());
414  }
415  // Return reference
416  return A_sp_;
417  }
418 
419  template<bool Tr>
421  : SolveUnity<Tr>(r, A) {
422  }
423 
424  template<bool Tr>
425  int TriuSolveUnity<Tr>::eval(const double** arg, double** res, casadi_int* iw, double* w) const {
426  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
427  casadi_triusolve(this->dep(1).sparsity(), arg[1], res[0], Tr, true, this->dep(0).size2());
428  return 0;
429  }
430 
431  template<bool Tr>
432  int TriuSolveUnity<Tr>::eval_sx(const SXElem** arg, SXElem** res, casadi_int* iw,
433  SXElem* w) const {
434  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
435  casadi_triusolve(this->dep(1).sparsity(), arg[1], res[0], Tr, true, this->dep(0).size2());
436  return 0;
437  }
438 
439  template<bool Tr>
441  : SolveUnity<Tr>(r, A) {
442  }
443 
444  template<bool Tr>
445  int TrilSolveUnity<Tr>::eval(const double** arg, double** res, casadi_int* iw, double* w) const {
446  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
447  casadi_trilsolve(this->dep(1).sparsity(), arg[1], res[0], Tr, true, this->dep(0).size2());
448  return 0;
449  }
450 
451  template<bool Tr>
452  int TrilSolveUnity<Tr>::eval_sx(const SXElem** arg, SXElem** res, casadi_int* iw,
453  SXElem* w) const {
454  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
455  casadi_trilsolve(this->dep(1).sparsity(), arg[1], res[0], Tr, true, this->dep(0).size2());
456  return 0;
457  }
458 
459  template<bool Tr>
461  const std::vector<casadi_int>& arg,
462  const std::vector<casadi_int>& res,
463  const std::vector<bool>& arg_is_ref,
464  std::vector<bool>& res_is_ref) const {
465  // Number of right-hand-sides
466  casadi_int nrhs = this->dep(0).size2();
467  // Copy first argument if not inplace
468  if (arg[0]!=res[0] || arg_is_ref[0]) {
469  g << g.copy(g.work(arg[0], this->nnz(), arg_is_ref[0]),
470  this->nnz(),
471  g.work(res[0], this->nnz(), false)) << '\n';
472  }
473  // Perform sparse matrix multiplication
474  g << g.triusolve(this->dep(1).sparsity(), g.work(arg[1], this->dep(1).nnz(), arg_is_ref[1]),
475  g.work(res[0], this->nnz(), false), Tr, false, nrhs) << '\n';
476  }
477 
478  template<bool Tr>
480  const std::vector<casadi_int>& arg,
481  const std::vector<casadi_int>& res,
482  const std::vector<bool>& arg_is_ref,
483  std::vector<bool>& res_is_ref) const {
484  // Number of right-hand-sides
485  casadi_int nrhs = this->dep(0).size2();
486  // Copy first argument if not inplace
487  if (arg[0]!=res[0] || arg_is_ref[0]) {
488  g << g.copy(g.work(arg[0], this->nnz(), arg_is_ref[0]),
489  this->nnz(),
490  g.work(res[0], this->nnz(), false)) << '\n';
491  }
492  // Perform sparse matrix multiplication
493  g << g.trilsolve(this->dep(1).sparsity(), g.work(arg[1], this->dep(1).nnz(), arg_is_ref[1]),
494  g.work(res[0], this->nnz(), false), Tr, false, nrhs) << '\n';
495  }
496 
497  template<bool Tr>
499  const std::vector<casadi_int>& arg,
500  const std::vector<casadi_int>& res,
501  const std::vector<bool>& arg_is_ref,
502  std::vector<bool>& res_is_ref) const {
503  // Number of right-hand-sides
504  casadi_int nrhs = this->dep(0).size2();
505  // Copy first argument if not inplace
506  if (arg[0]!=res[0] || arg_is_ref[0]) {
507  g << g.copy(g.work(arg[0], this->nnz(), arg_is_ref[0]),
508  this->nnz(),
509  g.work(res[0], this->nnz(), false)) << '\n';
510  }
511  // Perform sparse matrix multiplication
512  g << g.triusolve(this->dep(1).sparsity(), g.work(arg[1], this->dep(1).nnz(), arg_is_ref[1]),
513  g.work(res[0], this->nnz(), false), Tr, true, nrhs) << '\n';
514  }
515 
516  template<bool Tr>
518  const std::vector<casadi_int>& arg,
519  const std::vector<casadi_int>& res,
520  const std::vector<bool>& arg_is_ref,
521  std::vector<bool>& res_is_ref) const {
522  // Number of right-hand-sides
523  casadi_int nrhs = this->dep(0).size2();
524  // Copy first argument if not inplace
525  if (arg[0]!=res[0] || arg_is_ref[0]) {
526  g << g.copy(g.work(arg[0], this->nnz(), arg_is_ref[0]),
527  this->nnz(),
528  g.work(res[0], this->nnz(), false)) << '\n';
529  }
530  // Perform sparse matrix multiplication
531  g << g.trilsolve(this->dep(1).sparsity(), g.work(arg[1], this->dep(1).nnz(), arg_is_ref[1]),
532  g.work(res[0], this->nnz(), false), Tr, true, nrhs) << '\n';
533  }
534 
535 } // namespace casadi
536 
537 #endif // CASADI_SOLVE_IMPL_HPP
Helper class for C code generation.
std::string generate(const std::string &prefix="")
Generate file(s)
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
Sparsity sparsity() const
Get the sparsity pattern.
casadi_int size2() const
Get the second dimension (i.e. number of columns)
casadi_int size1() const
Get the first dimension (i.e. number of rows)
std::string dim(bool with_nz=false) const
Get string representation of dimensions.
static MX zeros(casadi_int nrow=1, casadi_int ncol=1)
Create a dense matrix or a matrix with specified sparsity with all entries zero.
Linear solve operation with a linear solver instance.
Definition: solve.hpp:154
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: solve_impl.hpp:337
int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w) const override
Evaluate the function symbolically (SX)
Definition: solve_impl.hpp:76
size_t codegen_sz_w() const override
Length of w the generated code needs (QR factorization buffers)
Definition: solve_impl.hpp:284
size_t sz_w() const override
Get required length of w field.
Definition: solve_impl.hpp:279
void generate(CodeGenerator &g, const std::vector< casadi_int > &arg, const std::vector< casadi_int > &res, const std::vector< bool > &arg_is_ref, std::vector< bool > &res_is_ref) const override
Generate code for the operation.
Definition: solve_impl.hpp:290
static MXNode * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
Definition: solve_impl.hpp:353
void serialize_type(SerializingStream &s) const override
Serialize type information.
Definition: solve_impl.hpp:343
int eval(const double **arg, double **res, casadi_int *iw, double *w) const override
Evaluate the function numerically.
Definition: solve_impl.hpp:57
LinsolCall(const MX &r, const MX &A, const Linsol &linear_solver)
Constructor.
Definition: solve_impl.hpp:52
Linsol linsol_
Linear solver (may be shared between multiple nodes)
Definition: solve.hpp:193
Linear solver.
Definition: linsol.hpp:55
Node class for MX objects.
Definition: mx_node.hpp:51
virtual void serialize_type(SerializingStream &s) const
Serialize type information.
virtual void serialize_body(SerializingStream &s) const
Serialize an object without type information.
MX - Matrix expression.
Definition: mx.hpp:92
MX T() const
Transpose the matrix.
Helper class for Serialization.
void pack(const Sparsity &e)
Serializes an object to the output stream.
Linear solve with unity diagonal added.
Definition: solve.hpp:310
const Sparsity & A_sp() const override
Sparsity pattern for the linear system.
Definition: solve_impl.hpp:405
SolveUnity(const MX &r, const MX &A)
Constructor.
Definition: solve_impl.hpp:401
An MX atomic for linear solver solution: x = r * A^-1 or x = r * A^-T.
Definition: solve.hpp:47
static MXNode * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
Definition: solve_impl.hpp:330
Solve(const MX &r, const MX &A)
Constructor.
Definition: solve_impl.hpp:35
void ad_forward(const std::vector< std::vector< MX > > &fseed, std::vector< std::vector< MX > > &fsens) const override
Calculate forward mode directional derivatives.
Definition: solve_impl.hpp:92
std::string disp(const std::vector< std::string > &arg) const override
Print expression.
Definition: solve_impl.hpp:43
void eval_mx(const std::vector< MX > &arg, std::vector< MX > &res, const std::vector< bool > &unique={}) const override
Evaluate symbolically (MX)
Definition: solve_impl.hpp:82
void ad_reverse(const std::vector< std::vector< MX > > &aseed, std::vector< std::vector< MX > > &asens) const override
Calculate reverse mode directional derivatives.
Definition: solve_impl.hpp:125
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: solve_impl.hpp:315
int sp_reverse(bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w) const override
Propagate sparsity backwards.
Definition: solve_impl.hpp:237
int sp_forward(const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w) const override
Propagate sparsity forward.
Definition: solve_impl.hpp:175
int eval_activity(const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w) const override
Propagate signal activity forward (bit set = active)
Definition: solve_impl.hpp:215
void serialize_type(SerializingStream &s) const override
Serialize type information.
Definition: solve_impl.hpp:320
General sparsity class.
Definition: sparsity.hpp:106
casadi_int colind(casadi_int cc) const
Get a reference to the colindex of column cc (see class description)
casadi_int size1() const
Get the number of rows.
static Sparsity diag(casadi_int nrow)
Create diagonal sparsity pattern *.
Definition: sparsity.hpp:190
casadi_int row(casadi_int el) const
Get the row of a non-zero element.
void generate(CodeGenerator &g, const std::vector< casadi_int > &arg, const std::vector< casadi_int > &res, const std::vector< bool > &arg_is_ref, std::vector< bool > &res_is_ref) const override
Generate code for the operation.
Definition: solve_impl.hpp:517
TrilSolveUnity(const MX &r, const MX &A)
Constructor.
Definition: solve_impl.hpp:440
int eval(const double **arg, double **res, casadi_int *iw, double *w) const override
Evaluate the function numerically.
Definition: solve_impl.hpp:445
int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w) const override
Evaluate the function symbolically (SX)
Definition: solve_impl.hpp:452
TrilSolve(const MX &r, const MX &A)
Constructor.
Definition: solve_impl.hpp:383
int eval(const double **arg, double **res, casadi_int *iw, double *w) const override
Evaluate the function numerically.
Definition: solve_impl.hpp:387
int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w) const override
Evaluate the function symbolically (SX)
Definition: solve_impl.hpp:394
void generate(CodeGenerator &g, const std::vector< casadi_int > &arg, const std::vector< casadi_int > &res, const std::vector< bool > &arg_is_ref, std::vector< bool > &res_is_ref) const override
Generate code for the operation.
Definition: solve_impl.hpp:479
void generate(CodeGenerator &g, const std::vector< casadi_int > &arg, const std::vector< casadi_int > &res, const std::vector< bool > &arg_is_ref, std::vector< bool > &res_is_ref) const override
Generate code for the operation.
Definition: solve_impl.hpp:498
TriuSolveUnity(const MX &r, const MX &A)
Constructor.
Definition: solve_impl.hpp:420
int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w) const override
Evaluate the function symbolically (SX)
Definition: solve_impl.hpp:432
int eval(const double **arg, double **res, casadi_int *iw, double *w) const override
Evaluate the function numerically.
Definition: solve_impl.hpp:425
int eval(const double **arg, double **res, casadi_int *iw, double *w) const override
Evaluate the function numerically.
Definition: solve_impl.hpp:369
TriuSolve(const MX &r, const MX &A)
Constructor.
Definition: solve_impl.hpp:365
void generate(CodeGenerator &g, const std::vector< casadi_int > &arg, const std::vector< casadi_int > &res, const std::vector< bool > &arg_is_ref, std::vector< bool > &res_is_ref) const override
Generate code for the operation.
Definition: solve_impl.hpp:460
int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w) const override
Evaluate the function symbolically (SX)
Definition: solve_impl.hpp:376
The casadi namespace.
Definition: archiver.hpp:32
bool is_zero(const T &x)