26 #ifndef CASADI_SOLVE_IMPL_HPP
27 #define CASADI_SOLVE_IMPL_HPP
30 #include "linsol_internal.hpp"
37 "Solve::Solve: dimension mismatch. Got r " + r.
dim() +
" and A " + A.
dim());
45 ss <<
"(" << mod_prefix() << arg.at(1) << mod_suffix();
47 ss <<
"\\" << arg.at(0) <<
")";
53 Solve<Tr>(r, A), linsol_(linear_solver) {
58 if (arg[0] != res[0]) std::copy(arg[0], arg[0] + this->dep(0).nnz(), res[0]);
59 scoped_checkout<Linsol> mem(linsol_);
61 auto m =
static_cast<LinsolMemory*
>(linsol_->memory(mem));
63 for (
auto&& s : m->fstats) s.second.reset();
64 if (m->t_total) m->t_total->tic();
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;
70 linsol_->print_time(m->fstats);
77 linsol_->linsol_eval_sx(arg, res, iw, w, linsol_->memory(0), Tr, this->dep(0).size2());
83 const std::vector<bool>& unique)
const {
85 res[0] =
MX(arg[0].size());
87 res[0] = solve(arg[1], arg[0], Tr);
93 std::vector<std::vector<MX> >& fsens)
const {
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);
101 casadi_int nfwd = fseed.size();
102 const MX& A = arg[1];
103 const MX&
X = res[0];
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();
114 rhs = horzsplit(solve(A, horzcat(rhs), Tr), col_offset);
118 for (casadi_int d=0; d<nfwd; ++d) {
120 fsens[d][0] = rhs[d];
126 std::vector<std::vector<MX> >& asens)
const {
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);
134 casadi_int nadj = aseed.size();
135 const MX& A = arg[1];
136 const MX&
X = res[0];
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();
145 rhs = horzsplit(solve(A, horzcat(rhs), !Tr), col_offset);
149 for (casadi_int d=0; d<nadj; ++d) {
159 if (asens[d][1].is_empty(
true)) {
166 if (asens[d][0].is_empty(
true)) {
167 asens[d][0] = rhs[d];
169 asens[d][0] += rhs[d];
177 casadi_int nrhs = dep(0).size2();
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();
186 const bvec_t *B=arg[0], *A = arg[1];
191 for (casadi_int r=0; r<nrhs; ++r) {
193 std::copy(B, B+n, 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];
204 std::fill(
X,
X+n, 0);
205 A_sp.spsolve(
X, tmp, Tr);
222 casadi_int n = A_sp().size1();
223 casadi_int nrhs = dep(0).size2();
224 const bvec_t* B = arg[0];
226 for (casadi_int r=0; r<nrhs; ++r) {
228 for (casadi_int i=0; i<n; ++i) col |= B[i];
229 std::fill(
X,
X+n, col);
239 casadi_int nrhs = dep(0).size2();
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();
248 bvec_t *B=arg[0], *A=arg[1], *
X=res[0];
252 for (casadi_int r=0; r<nrhs; ++r) {
254 std::fill(tmp, tmp+n, 0);
255 A_sp.spsolve(tmp,
X, !Tr);
258 std::fill(
X,
X+n, 0);
261 for (casadi_int i=0; i<n; ++i) B[i] |= tmp[i];
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];
280 return this->sparsity().size1();
286 return linsol_->sz_w_fact();
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 {
296 casadi_int nrhs = this->dep(0).size2();
299 g.local(
"rr",
"casadi_real",
"*");
300 g <<
"rr = " << g.work(res[0], this->nnz(),
false) <<
";\n";
303 g.local(
"ss",
"const casadi_real",
"*");
304 g <<
"ss = " << g.work(arg[1], this->dep(1).nnz(), arg_is_ref[1]) <<
";\n";
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';
311 linsol_->
generate(g,
"ss",
"rr", nrhs, Tr);
322 s.
pack(
"Solve::Tr", Tr);
332 s.
unpack(
"Solve::Tr", tr);
333 casadi_error(
"Not implemented");
339 s.
pack(
"Solve::Linsol", linsol_);
355 s.
unpack(
"Solve::Tr", tr);
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());
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());
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());
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());
406 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
408 std::lock_guard<std::mutex> lock(A_sp_mtx_);
411 if (A_sp_.is_null()) {
412 const Sparsity& no_diag = this->dep(1).sparsity();
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());
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());
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());
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());
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 {
466 casadi_int nrhs = this->dep(0).size2();
468 if (arg[0]!=res[0] || arg_is_ref[0]) {
469 g << g.copy(g.work(arg[0], this->nnz(), arg_is_ref[0]),
471 g.work(res[0], this->nnz(),
false)) <<
'\n';
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';
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 {
485 casadi_int nrhs = this->dep(0).size2();
487 if (arg[0]!=res[0] || arg_is_ref[0]) {
488 g << g.copy(g.work(arg[0], this->nnz(), arg_is_ref[0]),
490 g.work(res[0], this->nnz(),
false)) <<
'\n';
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';
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 {
504 casadi_int nrhs = this->dep(0).size2();
506 if (arg[0]!=res[0] || arg_is_ref[0]) {
507 g << g.copy(g.work(arg[0], this->nnz(), arg_is_ref[0]),
509 g.work(res[0], this->nnz(),
false)) <<
'\n';
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';
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 {
523 casadi_int nrhs = this->dep(0).size2();
525 if (arg[0]!=res[0] || arg_is_ref[0]) {
526 g << g.copy(g.work(arg[0], this->nnz(), arg_is_ref[0]),
528 g.work(res[0], this->nnz(),
false)) <<
'\n';
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';
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.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w) const override
Evaluate the function symbolically (SX)
size_t codegen_sz_w() const override
Length of w the generated code needs (QR factorization buffers)
size_t sz_w() const override
Get required length of w field.
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.
static MXNode * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
void serialize_type(SerializingStream &s) const override
Serialize type information.
int eval(const double **arg, double **res, casadi_int *iw, double *w) const override
Evaluate the function numerically.
LinsolCall(const MX &r, const MX &A, const Linsol &linear_solver)
Constructor.
Linsol linsol_
Linear solver (may be shared between multiple nodes)
Node class for MX objects.
virtual void serialize_type(SerializingStream &s) const
Serialize type information.
virtual void serialize_body(SerializingStream &s) const
Serialize an object without type information.
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.
const Sparsity & A_sp() const override
Sparsity pattern for the linear system.
SolveUnity(const MX &r, const MX &A)
Constructor.
An MX atomic for linear solver solution: x = r * A^-1 or x = r * A^-T.
static MXNode * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
Solve(const MX &r, const MX &A)
Constructor.
void ad_forward(const std::vector< std::vector< MX > > &fseed, std::vector< std::vector< MX > > &fsens) const override
Calculate forward mode directional derivatives.
std::string disp(const std::vector< std::string > &arg) const override
Print expression.
void eval_mx(const std::vector< MX > &arg, std::vector< MX > &res, const std::vector< bool > &unique={}) const override
Evaluate symbolically (MX)
void ad_reverse(const std::vector< std::vector< MX > > &aseed, std::vector< std::vector< MX > > &asens) const override
Calculate reverse mode directional derivatives.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
int sp_reverse(bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w) const override
Propagate sparsity backwards.
int sp_forward(const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w) const override
Propagate sparsity forward.
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)
void serialize_type(SerializingStream &s) const override
Serialize type information.
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 *.
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.
TrilSolveUnity(const MX &r, const MX &A)
Constructor.
int eval(const double **arg, double **res, casadi_int *iw, double *w) const override
Evaluate the function numerically.
int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w) const override
Evaluate the function symbolically (SX)
TrilSolve(const MX &r, const MX &A)
Constructor.
int eval(const double **arg, double **res, casadi_int *iw, double *w) const override
Evaluate the function numerically.
int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w) const override
Evaluate the function symbolically (SX)
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.
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.
TriuSolveUnity(const MX &r, const MX &A)
Constructor.
int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w) const override
Evaluate the function symbolically (SX)
int eval(const double **arg, double **res, casadi_int *iw, double *w) const override
Evaluate the function numerically.
int eval(const double **arg, double **res, casadi_int *iw, double *w) const override
Evaluate the function numerically.
TriuSolve(const MX &r, const MX &A)
Constructor.
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.
int eval_sx(const SXElem **arg, SXElem **res, casadi_int *iw, SXElem *w) const override
Evaluate the function symbolically (SX)