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) const {
83  if (arg[0].is_zero()) {
84  res[0] = MX(arg[0].size());
85  } else {
86  res[0] = solve(arg[1], arg[0], Tr);
87  }
88  }
89 
90  template<bool Tr>
91  void Solve<Tr>::ad_forward(const std::vector<std::vector<MX> >& fseed,
92  std::vector<std::vector<MX> >& fsens) const {
93  // Nondifferentiated inputs and outputs
94  std::vector<MX> arg(this->n_dep());
95  for (casadi_int i=0; i<arg.size(); ++i) arg[i] = this->dep(i);
96  std::vector<MX> res(this->nout());
97  for (casadi_int i=0; i<res.size(); ++i) res[i] = this->get_output(i);
98 
99  // Number of derivatives
100  casadi_int nfwd = fseed.size();
101  const MX& A = arg[1];
102  const MX& X = res[0];
103 
104  // Solve for all directions at once
105  std::vector<MX> rhs(nfwd);
106  std::vector<casadi_int> col_offset(nfwd+1, 0);
107  for (casadi_int d=0; d<nfwd; ++d) {
108  const MX& B_hat = fseed[d][0];
109  const MX& A_hat = fseed[d][1];
110  rhs[d] = Tr ? B_hat - mtimes(A_hat.T(), X) : B_hat - mtimes(A_hat, X);
111  col_offset[d+1] = col_offset[d] + rhs[d].size2();
112  }
113  rhs = horzsplit(solve(A, horzcat(rhs), Tr), col_offset);
114 
115  // Fetch result
116  fsens.resize(nfwd);
117  for (casadi_int d=0; d<nfwd; ++d) {
118  fsens[d].resize(1);
119  fsens[d][0] = rhs[d];
120  }
121  }
122 
123  template<bool Tr>
124  void Solve<Tr>::ad_reverse(const std::vector<std::vector<MX> >& aseed,
125  std::vector<std::vector<MX> >& asens) const {
126  // Nondifferentiated inputs and outputs
127  std::vector<MX> arg(this->n_dep());
128  for (casadi_int i=0; i<arg.size(); ++i) arg[i] = this->dep(i);
129  std::vector<MX> res(this->nout());
130  for (casadi_int i=0; i<res.size(); ++i) res[i] = this->get_output(i);
131 
132  // Number of derivatives
133  casadi_int nadj = aseed.size();
134  const MX& A = arg[1];
135  const MX& X = res[0];
136 
137  // Solve for all directions at once
138  std::vector<MX> rhs(nadj);
139  std::vector<casadi_int> col_offset(nadj+1, 0);
140  for (casadi_int d=0; d<nadj; ++d) {
141  rhs[d] = aseed[d][0];
142  col_offset[d+1] = col_offset[d] + rhs[d].size2();
143  }
144  rhs = horzsplit(solve(A, horzcat(rhs), !Tr), col_offset);
145 
146  // Collect sensitivities
147  asens.resize(nadj);
148  for (casadi_int d=0; d<nadj; ++d) {
149  asens[d].resize(2);
150 
151  // Propagate to A
152  MX a;
153  if (!Tr) {
154  a = -mac(rhs[d], X.T(), MX::zeros(A.sparsity()));
155  } else {
156  a = -mac(X, rhs[d].T(), MX::zeros(A.sparsity()));
157  }
158  if (asens[d][1].is_empty(true)) {
159  asens[d][1] = a;
160  } else {
161  asens[d][1] += a;
162  }
163 
164  // Propagate to B
165  if (asens[d][0].is_empty(true)) {
166  asens[d][0] = rhs[d];
167  } else {
168  asens[d][0] += rhs[d];
169  }
170  }
171  }
172 
173  template<bool Tr>
174  int Solve<Tr>::sp_forward(const bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w) const {
175  // Number of right-hand-sides
176  casadi_int nrhs = dep(0).size2();
177 
178  // Sparsities
179  const Sparsity& A_sp = this->A_sp();
180  const casadi_int* A_colind = A_sp.colind();
181  const casadi_int* A_row = A_sp.row();
182  casadi_int n = A_sp.size1();
183 
184  // Get pointers to data
185  const bvec_t *B=arg[0], *A = arg[1];
186  bvec_t* X = res[0];
187  bvec_t* tmp = w;
188 
189  // For all right-hand-sides
190  for (casadi_int r=0; r<nrhs; ++r) {
191  // Copy B to a temporary vector
192  std::copy(B, B+n, tmp);
193 
194  // Add A_hat contribution to tmp
195  for (casadi_int cc=0; cc<n; ++cc) {
196  for (casadi_int k=A_colind[cc]; k<A_colind[cc+1]; ++k) {
197  casadi_int rr = A_row[k];
198  tmp[Tr ? cc : rr] |= A[k];
199  }
200  }
201 
202  // Propagate to X
203  std::fill(X, X+n, 0);
204  A_sp.spsolve(X, tmp, Tr);
205 
206  // Continue to the next right-hand-side
207  B += n;
208  X += n;
209  }
210  return 0;
211  }
212 
213  template<bool Tr>
214  int Solve<Tr>::sp_reverse(bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w) const {
215  // Number of right-hand-sides
216  casadi_int nrhs = dep(0).size2();
217 
218  // Sparsities
219  const Sparsity& A_sp = this->A_sp();
220  const casadi_int* A_colind = A_sp.colind();
221  const casadi_int* A_row = A_sp.row();
222  casadi_int n = A_sp.size1();
223 
224  // Get pointers to data
225  bvec_t *B=arg[0], *A=arg[1], *X=res[0];
226  bvec_t* tmp = w;
227 
228  // For all right-hand-sides
229  for (casadi_int r=0; r<nrhs; ++r) {
230  // Solve transposed
231  std::fill(tmp, tmp+n, 0);
232  A_sp.spsolve(tmp, X, !Tr);
233 
234  // Clear seeds
235  std::fill(X, X+n, 0);
236 
237  // Propagate to B
238  for (casadi_int i=0; i<n; ++i) B[i] |= tmp[i];
239 
240  // Propagate to A
241  for (casadi_int cc=0; cc<n; ++cc) {
242  for (casadi_int k=A_colind[cc]; k<A_colind[cc+1]; ++k) {
243  casadi_int rr = A_row[k];
244  A[k] |= tmp[Tr ? cc : rr];
245  }
246  }
247 
248  // Continue to the next right-hand-side
249  B += n;
250  X += n;
251  }
252  return 0;
253  }
254 
255  template<bool Tr>
256  size_t LinsolCall<Tr>::sz_w() const {
257  return this->sparsity().size1();
258  }
259 
260  template<bool Tr>
262  const std::vector<casadi_int>& arg,
263  const std::vector<casadi_int>& res,
264  const std::vector<bool>& arg_is_ref,
265  std::vector<bool>& res_is_ref) const {
266  // Number of right-hand-sides
267  casadi_int nrhs = this->dep(0).size2();
268 
269  // Array for x
270  g.local("rr", "casadi_real", "*");
271  g << "rr = " << g.work(res[0], this->nnz(), false) << ";\n";
272 
273  // Array for A
274  g.local("ss", "const casadi_real", "*");
275  g << "ss = " << g.work(arg[1], this->dep(1).nnz(), arg_is_ref[1]) << ";\n";
276 
277  // Copy b to x if not inplace
278  if (arg[0]!=res[0] || arg_is_ref[0]) {
279  g << g.copy(g.work(arg[0], this->nnz(), arg_is_ref[0]), this->nnz(), "rr") << '\n';
280  }
281  // Solver specific codegen
282  linsol_->generate(g, "ss", "rr", nrhs, Tr);
283  }
284 
285  template<bool Tr>
288  }
289 
290  template<bool Tr>
293  s.pack("Solve::Tr", Tr);
294  }
295 
296  template<bool Tr>
298  }
299 
300  template<bool Tr>
302  bool tr;
303  s.unpack("Solve::Tr", tr);
304  casadi_error("Not implemented");
305  }
306 
307  template<bool Tr>
310  s.pack("Solve::Linsol", linsol_);
311  }
312 
313  template<bool Tr>
316  }
317 
318  template<bool Tr>
320  s.unpack("Solve::Linsol", linsol_);
321  }
322 
323  template<bool Tr>
325  bool tr;
326  s.unpack("Solve::Tr", tr);
327 
328  if (tr) {
329  return new LinsolCall<true>(s);
330  } else {
331  return new LinsolCall<false>(s);
332  }
333  }
334 
335  template<bool Tr>
336  TriuSolve<Tr>::TriuSolve(const MX& r, const MX& A) : Solve<Tr>(r, A) {
337  }
338 
339  template<bool Tr>
340  int TriuSolve<Tr>::eval(const double** arg, double** res, casadi_int* iw, double* w) const {
341  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
342  casadi_triusolve(this->dep(1).sparsity(), arg[1], res[0], Tr, false, this->dep(0).size2());
343  return 0;
344  }
345 
346  template<bool Tr>
347  int TriuSolve<Tr>::eval_sx(const SXElem** arg, SXElem** res, casadi_int* iw, SXElem* w) const {
348  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
349  casadi_triusolve(this->dep(1).sparsity(), arg[1], res[0], Tr, false, this->dep(0).size2());
350  return 0;
351  }
352 
353  template<bool Tr>
354  TrilSolve<Tr>::TrilSolve(const MX& r, const MX& A) : Solve<Tr>(r, A) {
355  }
356 
357  template<bool Tr>
358  int TrilSolve<Tr>::eval(const double** arg, double** res, casadi_int* iw, double* w) const {
359  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
360  casadi_trilsolve(this->dep(1).sparsity(), arg[1], res[0], Tr, false, this->dep(0).size2());
361  return 0;
362  }
363 
364  template<bool Tr>
365  int TrilSolve<Tr>::eval_sx(const SXElem** arg, SXElem** res, casadi_int* iw, SXElem* w) const {
366  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
367  casadi_trilsolve(this->dep(1).sparsity(), arg[1], res[0], Tr, false, this->dep(0).size2());
368  return 0;
369  }
370 
371  template<bool Tr>
372  SolveUnity<Tr>::SolveUnity(const MX& r, const MX& A) : Solve<Tr>(r, A) {
373  }
374 
375  template<bool Tr>
377 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
378  // Safe access to A_sp_
379  std::lock_guard<std::mutex> lock(A_sp_mtx_);
380 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
381  // Create on first call
382  if (A_sp_.is_null()) {
383  const Sparsity& no_diag = this->dep(1).sparsity();
384  A_sp_ = no_diag + Sparsity::diag(no_diag.size1());
385  }
386  // Return reference
387  return A_sp_;
388  }
389 
390  template<bool Tr>
392  : SolveUnity<Tr>(r, A) {
393  }
394 
395  template<bool Tr>
396  int TriuSolveUnity<Tr>::eval(const double** arg, double** res, casadi_int* iw, double* w) const {
397  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
398  casadi_triusolve(this->dep(1).sparsity(), arg[1], res[0], Tr, true, this->dep(0).size2());
399  return 0;
400  }
401 
402  template<bool Tr>
403  int TriuSolveUnity<Tr>::eval_sx(const SXElem** arg, SXElem** res, casadi_int* iw,
404  SXElem* w) const {
405  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
406  casadi_triusolve(this->dep(1).sparsity(), arg[1], res[0], Tr, true, this->dep(0).size2());
407  return 0;
408  }
409 
410  template<bool Tr>
412  : SolveUnity<Tr>(r, A) {
413  }
414 
415  template<bool Tr>
416  int TrilSolveUnity<Tr>::eval(const double** arg, double** res, casadi_int* iw, double* w) const {
417  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
418  casadi_trilsolve(this->dep(1).sparsity(), arg[1], res[0], Tr, true, this->dep(0).size2());
419  return 0;
420  }
421 
422  template<bool Tr>
423  int TrilSolveUnity<Tr>::eval_sx(const SXElem** arg, SXElem** res, casadi_int* iw,
424  SXElem* w) const {
425  if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
426  casadi_trilsolve(this->dep(1).sparsity(), arg[1], res[0], Tr, true, this->dep(0).size2());
427  return 0;
428  }
429 
430  template<bool Tr>
432  const std::vector<casadi_int>& arg,
433  const std::vector<casadi_int>& res,
434  const std::vector<bool>& arg_is_ref,
435  std::vector<bool>& res_is_ref) const {
436  // Number of right-hand-sides
437  casadi_int nrhs = this->dep(0).size2();
438  // Copy first argument if not inplace
439  if (arg[0]!=res[0] || arg_is_ref[0]) {
440  g << g.copy(g.work(arg[0], this->nnz(), arg_is_ref[0]),
441  this->nnz(),
442  g.work(res[0], this->nnz(), false)) << '\n';
443  }
444  // Perform sparse matrix multiplication
445  g << g.triusolve(this->dep(1).sparsity(), g.work(arg[1], this->dep(1).nnz(), arg_is_ref[1]),
446  g.work(res[0], this->nnz(), false), Tr, false, nrhs) << '\n';
447  }
448 
449  template<bool Tr>
451  const std::vector<casadi_int>& arg,
452  const std::vector<casadi_int>& res,
453  const std::vector<bool>& arg_is_ref,
454  std::vector<bool>& res_is_ref) const {
455  // Number of right-hand-sides
456  casadi_int nrhs = this->dep(0).size2();
457  // Copy first argument if not inplace
458  if (arg[0]!=res[0] || arg_is_ref[0]) {
459  g << g.copy(g.work(arg[0], this->nnz(), arg_is_ref[0]),
460  this->nnz(),
461  g.work(res[0], this->nnz(), false)) << '\n';
462  }
463  // Perform sparse matrix multiplication
464  g << g.trilsolve(this->dep(1).sparsity(), g.work(arg[1], this->dep(1).nnz(), arg_is_ref[1]),
465  g.work(res[0], this->nnz(), false), Tr, false, nrhs) << '\n';
466  }
467 
468  template<bool Tr>
470  const std::vector<casadi_int>& arg,
471  const std::vector<casadi_int>& res,
472  const std::vector<bool>& arg_is_ref,
473  std::vector<bool>& res_is_ref) const {
474  // Number of right-hand-sides
475  casadi_int nrhs = this->dep(0).size2();
476  // Copy first argument if not inplace
477  if (arg[0]!=res[0] || arg_is_ref[0]) {
478  g << g.copy(g.work(arg[0], this->nnz(), arg_is_ref[0]),
479  this->nnz(),
480  g.work(res[0], this->nnz(), false)) << '\n';
481  }
482  // Perform sparse matrix multiplication
483  g << g.triusolve(this->dep(1).sparsity(), g.work(arg[1], this->dep(1).nnz(), arg_is_ref[1]),
484  g.work(res[0], this->nnz(), false), Tr, true, nrhs) << '\n';
485  }
486 
487  template<bool Tr>
489  const std::vector<casadi_int>& arg,
490  const std::vector<casadi_int>& res,
491  const std::vector<bool>& arg_is_ref,
492  std::vector<bool>& res_is_ref) const {
493  // Number of right-hand-sides
494  casadi_int nrhs = this->dep(0).size2();
495  // Copy first argument if not inplace
496  if (arg[0]!=res[0] || arg_is_ref[0]) {
497  g << g.copy(g.work(arg[0], this->nnz(), arg_is_ref[0]),
498  this->nnz(),
499  g.work(res[0], this->nnz(), false)) << '\n';
500  }
501  // Perform sparse matrix multiplication
502  g << g.trilsolve(this->dep(1).sparsity(), g.work(arg[1], this->dep(1).nnz(), arg_is_ref[1]),
503  g.work(res[0], this->nnz(), false), Tr, true, nrhs) << '\n';
504  }
505 
506 } // namespace casadi
507 
508 #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:148
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: solve_impl.hpp:308
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 sz_w() const override
Get required length of w field.
Definition: solve_impl.hpp:256
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:261
static MXNode * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
Definition: solve_impl.hpp:324
void serialize_type(SerializingStream &s) const override
Serialize type information.
Definition: solve_impl.hpp:314
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:182
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:299
const Sparsity & A_sp() const override
Sparsity pattern for the linear system.
Definition: solve_impl.hpp:376
SolveUnity(const MX &r, const MX &A)
Constructor.
Definition: solve_impl.hpp:372
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:301
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:91
std::string disp(const std::vector< std::string > &arg) const override
Print expression.
Definition: solve_impl.hpp:43
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:124
void eval_mx(const std::vector< MX > &arg, std::vector< MX > &res) const override
Evaluate symbolically (MX)
Definition: solve_impl.hpp:82
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: solve_impl.hpp:286
int sp_reverse(bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w) const override
Propagate sparsity backwards.
Definition: solve_impl.hpp:214
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:174
void serialize_type(SerializingStream &s) const override
Serialize type information.
Definition: solve_impl.hpp:291
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:488
TrilSolveUnity(const MX &r, const MX &A)
Constructor.
Definition: solve_impl.hpp:411
int eval(const double **arg, double **res, casadi_int *iw, double *w) const override
Evaluate the function numerically.
Definition: solve_impl.hpp:416
int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w) const override
Evaluate the function symbolically (SX)
Definition: solve_impl.hpp:423
TrilSolve(const MX &r, const MX &A)
Constructor.
Definition: solve_impl.hpp:354
int eval(const double **arg, double **res, casadi_int *iw, double *w) const override
Evaluate the function numerically.
Definition: solve_impl.hpp:358
int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w) const override
Evaluate the function symbolically (SX)
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:450
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:469
TriuSolveUnity(const MX &r, const MX &A)
Constructor.
Definition: solve_impl.hpp:391
int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w) const override
Evaluate the function symbolically (SX)
Definition: solve_impl.hpp:403
int eval(const double **arg, double **res, casadi_int *iw, double *w) const override
Evaluate the function numerically.
Definition: solve_impl.hpp:396
int eval(const double **arg, double **res, casadi_int *iw, double *w) const override
Evaluate the function numerically.
Definition: solve_impl.hpp:340
TriuSolve(const MX &r, const MX &A)
Constructor.
Definition: solve_impl.hpp:336
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:431
int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w) const override
Evaluate the function symbolically (SX)
Definition: solve_impl.hpp:347
The casadi namespace.
Definition: archiver.hpp:32
bool is_zero(const T &x)