multiplication.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 #ifndef CASADI_MULTIPLICATION_CPP
27 #define CASADI_MULTIPLICATION_CPP
28 
29 #include "multiplication.hpp"
30 #include "blas_impl.hpp"
31 #include "casadi_misc.hpp"
32 #include "function_internal.hpp"
33 #include "serializing_stream.hpp"
34 
35 namespace casadi {
36 
37  MX Multiplication::create(const MX& z, const MX& x, const MX& y,
38  const std::string& blas) {
39  // Most-specific-first. Each subclass owns its own applicability test
40  // and construction; nullptr means "doesn't apply, try the next one".
41  if (auto* n = DenseMultiplication::try_create(z, x, y, blas)) return MX::create(n);
42  if (auto* n = PseudoDenseMultiplication::try_create(z, x, y, blas)) return MX::create(n);
43  if (auto* n = DenseSparseMultiplication::try_create(z, x, y, blas)) return MX::create(n);
44  return MX::create(new Multiplication(z, x, y, blas));
45  }
46 
47  Multiplication::Multiplication(const MX& z, const MX& x, const MX& y,
48  const std::string& blas) {
49  casadi_assert(x.size2() == y.size1() && x.size1() == z.size1()
50  && y.size2() == z.size2(),
51  "Multiplication::Multiplication: dimension mismatch. Attempting to multiply "
52  + x.dim() + " with " + y.dim()
53  + " and add the result to " + z.dim());
54 
55  set_dep(z, x, y);
58  }
59 
60  std::string Multiplication::disp(const std::vector<std::string>& arg) const {
61  return "mac(" + arg.at(1) + "," + arg.at(2) + "," + arg.at(0) + ")";
62  }
63 
64  void Multiplication::eval_kernel(const double** arg, double** res, double* w) const {
65  casadi_mtimes(arg[1], dep(1).sparsity(), arg[2], dep(2).sparsity(),
66  res[0], sparsity(), w, false);
67  }
68 
69  void Multiplication::eval_kernel(const SXElem** arg, SXElem** res, SXElem* w) const {
70  casadi_mtimes(arg[1], dep(1).sparsity(), arg[2], dep(2).sparsity(),
71  res[0], sparsity(), w, false);
72  }
73 
74  void Multiplication::ad_forward(const std::vector<std::vector<MX> >& fseed,
75  std::vector<std::vector<MX> >& fsens) const {
76  for (casadi_int d=0; d<fsens.size(); ++d) {
77  fsens[d][0] = fseed[d][0]
78  + mac(dep(1), fseed[d][2], MX::zeros(dep(0).sparsity()))
79  + mac(fseed[d][1], dep(2), MX::zeros(dep(0).sparsity()));
80  }
81  }
82 
83  void Multiplication::ad_reverse(const std::vector<std::vector<MX> >& aseed,
84  std::vector<std::vector<MX> >& asens) const {
85  for (casadi_int d=0; d<aseed.size(); ++d) {
86  asens[d][1] += mac(aseed[d][0], dep(2).T(), MX::zeros(dep(1).sparsity()));
87  asens[d][2] += mac(dep(1).T(), aseed[d][0], MX::zeros(dep(2).sparsity()));
88  asens[d][0] += aseed[d][0];
89  }
90  }
91 
92  void Multiplication::eval_mx(const std::vector<MX>& arg, std::vector<MX>& res,
93  const std::vector<bool>& unique) const {
94  res[0] = mac(arg[1], arg[2], arg[0]);
95  }
96 
97  void Multiplication::eval_linear(const std::vector<std::array<MX, 3> >& arg,
98  std::vector<std::array<MX, 3> >& res) const {
99  const std::array<MX, 3>& x = arg[1];
100  const std::array<MX, 3>& y = arg[2];
101  const std::array<MX, 3>& z = arg[0];
102  std::array<MX, 3>& f = res[0];
103  f[0] = mac(x[0], y[0], z[0]);
104  f[1] = mac(x[0], y[1], z[1]);
105  f[1] = mac(x[1], y[0], f[1]);
106  f[2] = mac(x[1]+x[2], y[1]+y[2], z[2]);
107  f[2] = mac(x[2], y[0], f[2]);
108  f[2] = mac(x[0], y[2], f[2]);
109  }
110 
112  sp_forward(const bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w) const {
113  copy_fwd(arg[0], res[0], nnz());
114  Sparsity::mul_sparsityF(arg[1], dep(1).sparsity(),
115  arg[2], dep(2).sparsity(),
116  res[0], sparsity(), w);
117  return 0;
118  }
119 
121  eval_activity(const bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w) const {
122  // out = z + x*y : the +z term passes through 1:1; a product term is active only
123  // when both its factors are active (mul_activityF combines factors with AND)
124  copy_fwd(arg[0], res[0], nnz());
125  Sparsity::mul_activityF(arg[1], dep(1).sparsity(),
126  arg[2], dep(2).sparsity(),
127  res[0], sparsity(), w);
128  return 0;
129  }
130 
132  sp_reverse(bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w) const {
133  Sparsity::mul_sparsityR(arg[1], dep(1).sparsity(),
134  arg[2], dep(2).sparsity(),
135  res[0], sparsity(), w);
136  copy_rev(arg[0], res[0], nnz());
137  return 0;
138  }
139 
140  // Helper: emit `if (arg!=res || arg_is_ref) copy(arg -> res, nnz)`
141  // Subclasses share this so eval_kernel only handles z += x*y.
142  static void codegen_copy_z(CodeGenerator& g, casadi_int nnz,
143  const std::vector<casadi_int>& arg,
144  const std::vector<casadi_int>& res,
145  const std::vector<bool>& arg_is_ref) {
146  if (arg[0]!=res[0] || arg_is_ref[0]) {
147  g << g.copy(g.work(arg[0], nnz, arg_is_ref[0]),
148  nnz,
149  g.work(res[0], nnz, false)) << '\n';
150  }
151  }
152 
154  const std::vector<casadi_int>& arg,
155  const std::vector<casadi_int>& res,
156  const std::vector<bool>& arg_is_ref,
157  std::vector<bool>& res_is_ref) const {
158  codegen_copy_z(g, nnz(), arg, res, arg_is_ref);
159  g << g.mtimes(g.work(arg[1], dep(1).nnz(), arg_is_ref[1]), dep(1).sparsity(),
160  g.work(arg[2], dep(2).nnz(), arg_is_ref[2]), dep(2).sparsity(),
161  g.work(res[0], nnz(), false), sparsity(), "w", false) << '\n';
162  }
163 
164  // ---------------- DenseMultiplication ----------------
165 
166  MXNode* DenseMultiplication::try_create(const MX& z, const MX& x, const MX& y,
167  const std::string& blas) {
168  if (!(x.is_dense() && y.is_dense() && z.is_dense())) return nullptr;
169  return new DenseMultiplication(z, x, y, blas);
170  }
171 
172  void DenseMultiplication::eval_kernel(const double** arg, double** res, double* w) const {
174  arg[1], dep(1).size1(), dep(1).size2(),
175  arg[2], dep(2).size2(),
176  res[0]);
177  }
178 
179  void DenseMultiplication::eval_kernel(const SXElem** arg, SXElem** res, SXElem* w) const {
180  casadi_mtimes_dense(arg[1], dep(1).size1(), dep(1).size2(),
181  arg[2], dep(2).size2(), res[0], false);
182  }
183 
185  const std::vector<casadi_int>& arg, const std::vector<casadi_int>& res,
186  const std::vector<bool>& arg_is_ref, std::vector<bool>& res_is_ref) const {
187  codegen_copy_z(g, nnz(), arg, res, arg_is_ref);
189  g.work(arg[1], dep(1).nnz(), arg_is_ref[1]),
190  dep(1).size1(), dep(1).size2(),
191  g.work(arg[2], dep(2).nnz(), arg_is_ref[2]),
192  dep(2).size2(),
193  g.work(res[0], nnz(), false));
194  }
195 
196  // ---------------- DenseSparseMultiplication ----------------
197 
198  MXNode* DenseSparseMultiplication::try_create(const MX& z, const MX& x, const MX& y,
199  const std::string& blas) {
200  if (!(x.is_dense() && z.is_dense())) return nullptr;
201  return new DenseSparseMultiplication(z, x, y, blas);
202  }
203 
204  void DenseSparseMultiplication::eval_kernel(const double** arg, double** res, double* w) const {
205  casadi_mtimes_dense_sparse(arg[1], dep(1).size1(),
206  arg[2], dep(2).sparsity(), res[0]);
207  }
208 
209  void DenseSparseMultiplication::eval_kernel(const SXElem** arg, SXElem** res, SXElem* w) const {
210  casadi_mtimes_dense_sparse(arg[1], dep(1).size1(),
211  arg[2], dep(2).sparsity(), res[0]);
212  }
213 
215  const std::vector<casadi_int>& arg, const std::vector<casadi_int>& res,
216  const std::vector<bool>& arg_is_ref, std::vector<bool>& res_is_ref) const {
217  codegen_copy_z(g, nnz(), arg, res, arg_is_ref);
218  g << g.mtimes_dense_sparse(g.work(arg[1], dep(1).nnz(), arg_is_ref[1]), dep(1).size1(),
219  g.work(arg[2], dep(2).nnz(), arg_is_ref[2]), dep(2).sparsity(),
220  g.work(res[0], nnz(), false)) << '\n';
221  }
222 
223  // ---------------- PseudoDenseMultiplication ----------------
224 
225  MXNode* PseudoDenseMultiplication::try_create(const MX& z, const MX& x, const MX& y,
226  const std::string& blas) {
227  // Result must have at least one nonzero for the compact-buffer reinterpretation
228  // to be meaningful.
229  if (z.nnz() == 0) return nullptr;
230  std::vector<casadi_int> xr, xc, yr, yc, zr, zc;
231  if (!x.sparsity().is_compactible(xr, xc)) return nullptr;
232  if (!y.sparsity().is_compactible(yr, yc)) return nullptr;
233  if (!z.sparsity().is_compactible(zr, zc)) return nullptr;
234  // Connecting index sets must agree exactly: cols(x) = rows(y), and
235  // result rows/cols inherit from x/y.
236  if (xc != yr || xr != zr || yc != zc) return nullptr;
237  return new PseudoDenseMultiplication(z, x, y,
238  static_cast<casadi_int>(xr.size()),
239  static_cast<casadi_int>(xc.size()),
240  static_cast<casadi_int>(yc.size()),
241  blas);
242  }
243 
245  casadi_int nrow_x_compact, casadi_int ncol_x_compact, casadi_int ncol_y_compact,
246  const std::string& blas)
247  : Multiplication(z, x, y, blas),
248  a_(nrow_x_compact), b_(ncol_x_compact), c_(ncol_y_compact) {}
249 
250  void PseudoDenseMultiplication::eval_kernel(const double** arg,
251  double** res, double* w) const {
252  Blas::mtimes(blas_shorthand_, arg[1], a_, b_, arg[2], c_, res[0]);
253  }
254 
256  SXElem** res, SXElem* w) const {
257  casadi_mtimes_dense(arg[1], a_, b_, arg[2], c_, res[0], false);
258  }
259 
261  const std::vector<casadi_int>& arg, const std::vector<casadi_int>& res,
262  const std::vector<bool>& arg_is_ref, std::vector<bool>& res_is_ref) const {
263  codegen_copy_z(g, nnz(), arg, res, arg_is_ref);
265  g.work(arg[1], dep(1).nnz(), arg_is_ref[1]), a_, b_,
266  g.work(arg[2], dep(2).nnz(), arg_is_ref[2]), c_,
267  g.work(res[0], nnz(), false));
268  }
269 
272  s.pack("Multiplication::kind", std::string("base"));
273  }
274 
277  s.pack("Multiplication::blas",
279  }
280 
282  if (legacy) {
283  blas_shorthand_ = 0;
284  return;
285  }
286  std::string blas;
287  s.unpack("Multiplication::blas", blas);
289  }
290 
293  s.pack("Multiplication::kind", std::string("dense"));
294  }
295 
298  s.pack("Multiplication::kind", std::string("dense_sparse"));
299  }
300 
303  s.pack("Multiplication::kind", std::string("pseudo_dense"));
304  }
305 
308  s.pack("PseudoDenseMultiplication::a", a_);
309  s.pack("PseudoDenseMultiplication::b", b_);
310  s.pack("PseudoDenseMultiplication::c", c_);
311  }
312 
314  : Multiplication(s) {
315  s.unpack("PseudoDenseMultiplication::a", a_);
316  s.unpack("PseudoDenseMultiplication::b", b_);
317  s.unpack("PseudoDenseMultiplication::c", c_);
318  }
319 
321  // Wire-format detection.
322  // pre 3.8: serialize_type packed a *bool* ("Multiplication::dense").
323  // Body did NOT include a blas field. Two variants only --
324  // DenseMultiplication and the generic Multiplication.
325  // 3.8+: serialize_type packs a *string* ("Multiplication::kind"),
326  // four variants, body always includes "Multiplication::blas".
327  //
328  // In debug mode the descriptor is on the wire and IS the discriminator;
329  // in non-debug mode we discriminate on the first wire byte: bool encodes
330  // as 2 hex chars whose first is 'a' or 'b'; string-length first byte is
331  // 'a'+(length%16), which for our kind names {"base","dense",
332  // "dense_sparse","pseudo_dense"} (lengths 4,5,12,12) is 'e','f','m','m'.
333  bool legacy_bool;
334  std::string kind;
335  if (s.debug()) {
336  std::string descr;
337  s.unpack(descr);
338  if (descr == "Multiplication::dense") {
339  legacy_bool = true;
340  } else {
341  casadi_assert(descr == "Multiplication::kind",
342  "Unexpected Multiplication descriptor: '" + descr + "'.");
343  legacy_bool = false;
344  s.unpack(kind);
345  }
346  } else {
347  const int p = s.peek_byte();
348  legacy_bool = (p == 'a' || p == 'b');
349  if (!legacy_bool) s.unpack("Multiplication::kind", kind);
350  }
351 
352  if (legacy_bool) {
353  bool dense;
354  if (s.debug()) s.unpack(dense);
355  else s.unpack("Multiplication::dense", dense);
356  if (dense) return new DenseMultiplication(s, /*legacy=*/true);
357  return new Multiplication(s, /*legacy=*/true);
358  }
359 
360  if (kind == "dense") return new DenseMultiplication(s);
361  if (kind == "dense_sparse") return new DenseSparseMultiplication(s);
362  if (kind == "pseudo_dense") return new PseudoDenseMultiplication(s);
363  return new Multiplication(s);
364  }
365 
366 } // namespace casadi
367 
368 #endif // CASADI_MULTIPLICATION_CPP
static void mtimes(casadi_int shorthand, const double *A, casadi_int m, casadi_int k, const double *B, casadi_int n, double *C)
Definition: blas.cpp:201
static const char * name_for_shorthand(casadi_int shorthand)
Definition: blas.cpp:220
static casadi_int shorthand_for(const std::string &name)
Definition: blas.cpp:141
static void codegen_mtimes(CodeGenerator &g, casadi_int shorthand, const std::string &A, casadi_int m, casadi_int k, const std::string &B, casadi_int n, const std::string &C)
Definition: blas.cpp:229
Helper class for C code generation.
std::string work(casadi_int n, casadi_int sz, bool is_ref) const
std::string copy(const std::string &arg, std::size_t n, const std::string &res)
Create a copy operation.
std::string mtimes(const std::string &x, const Sparsity &sp_x, const std::string &y, const Sparsity &sp_y, const std::string &z, const Sparsity &sp_z, const std::string &w, bool tr)
Codegen sparse matrix-matrix multiplication.
std::string mtimes_dense_sparse(const std::string &x, casadi_int nrow_x, const std::string &y, const Sparsity &sp_y, const std::string &z)
Codegen dense-sparse matrix-matrix multiplication (z, x dense)
Dense * Dense -> Dense matrix product.
void serialize_type(SerializingStream &s) const override
Serialize specific part of node.
void eval_kernel(const double **arg, double **res, double *w) const override
Subclass hook: mathematical kernel z += x*y on the input buffers.
static MXNode * try_create(const MX &z, const MX &x, const MX &y, const std::string &blas="reference")
Returns a fresh node iff x, y, z are all dense; otherwise nullptr.
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.
DenseMultiplication(const MX &z, const MX &x, const MX &y, const std::string &blas="reference")
Dense * Sparse -> Dense matrix product.
DenseSparseMultiplication(const MX &z, const MX &x, const MX &y, const std::string &blas="reference")
static MXNode * try_create(const MX &z, const MX &x, const MX &y, const std::string &blas="reference")
Returns a fresh node iff x, z are dense; otherwise nullptr.
void eval_kernel(const double **arg, double **res, double *w) const override
Subclass hook: mathematical kernel z += x*y on the input buffers.
void serialize_type(SerializingStream &s) const override
Serialize specific part of node.
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.
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
bool debug() const
Whether the stream was written in debug-decoration mode.
bool is_dense() const
Check if the matrix expression is dense.
casadi_int nnz() const
Get the number of (structural) non-zero elements.
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.
Node class for MX objects.
Definition: mx_node.hpp:51
virtual void serialize_type(SerializingStream &s) const
Serialize type information.
Definition: mx_node.cpp:535
static void copy_fwd(const bvec_t *arg, bvec_t *res, casadi_int len)
Propagate sparsities forward through a copy operation.
Definition: mx_node.cpp:1302
static void copy_rev(bvec_t *arg, bvec_t *res, casadi_int len)
Propagate sparsities backwards through a copy operation.
Definition: mx_node.cpp:1308
const Sparsity & sparsity() const
Get the sparsity.
Definition: mx_node.hpp:410
casadi_int size2() const
Definition: mx_node.hpp:429
casadi_int nnz(casadi_int i=0) const
Definition: mx_node.hpp:427
const MX & dep(casadi_int ind=0) const
dependencies - functions that have to be evaluated before this one
Definition: mx_node.hpp:392
virtual void serialize_body(SerializingStream &s) const
Serialize an object without type information.
Definition: mx_node.cpp:530
void set_sparsity(const Sparsity &sparsity)
Set the sparsity.
Definition: mx_node.cpp:224
casadi_int size1() const
Definition: mx_node.hpp:428
void set_dep(const MX &dep)
Set unary dependency.
Definition: mx_node.cpp:228
MX - Matrix expression.
Definition: mx.hpp:92
static MX create(MXNode *node)
Create from node.
Definition: mx.cpp:69
const Sparsity & sparsity() const
Get the sparsity pattern.
Definition: mx.cpp:612
An MX atomic for matrix-matrix product,.
void eval_mx(const std::vector< MX > &arg, std::vector< MX > &res, const std::vector< bool > &unique={}) const override
Evaluate symbolically (MX)
int sp_reverse(bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w) const override
Propagate sparsity backwards.
void serialize_type(SerializingStream &s) const override
Serialize specific part of node.
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 serialize_body(SerializingStream &s) const override
Serialize body (BLAS plugin name)
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.
static MXNode * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
int sp_forward(const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w) const override
Propagate sparsity forward.
virtual void eval_kernel(const double **arg, double **res, double *w) const
Subclass hook: mathematical kernel z += x*y on the input buffers.
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)
static MX create(const MX &z, const MX &x, const MX &y, const std::string &blas="reference")
Factory: dispatch to the most specific subclass for the given operands.
Multiplication(const MX &z, const MX &x, const MX &y, const std::string &blas="reference")
Constructor.
void ad_reverse(const std::vector< std::vector< MX > > &aseed, std::vector< std::vector< MX > > &asens) const override
Calculate reverse mode directional derivatives.
void eval_linear(const std::vector< std::array< MX, 3 > > &arg, std::vector< std::array< MX, 3 > > &res) const override
Evaluate the MX node on a const/linear/nonlinear partition.
Compactible * Compactible -> Compactible product.
static MXNode * try_create(const MX &z, const MX &x, const MX &y, const std::string &blas="reference")
void serialize_type(SerializingStream &s) const override
Serialize specific part of node.
void serialize_body(SerializingStream &s) const override
Serialize body (BLAS plugin name)
void eval_kernel(const double **arg, double **res, double *w) const override
Subclass hook: mathematical kernel z += x*y on the input buffers.
PseudoDenseMultiplication(const MX &z, const MX &x, const MX &y, casadi_int nrow_x_compact, casadi_int ncol_x_compact, casadi_int ncol_y_compact, const std::string &blas="reference")
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.
The basic scalar symbolic class of CasADi.
Definition: sx_elem.hpp:75
Helper class for Serialization.
void pack(const Sparsity &e)
Serializes an object to the output stream.
bool is_compactible(std::vector< casadi_int > &row, std::vector< casadi_int > &col) const
Check if the nonzero pattern is the Cartesian product of a row and a column subset.
Definition: sparsity.cpp:806
static void mul_sparsityR(bvec_t *x, const Sparsity &x_sp, bvec_t *y, const Sparsity &y_sp, bvec_t *z, const Sparsity &z_sp, bvec_t *w)
Propagate sparsity using 0-1 logic through a matrix product,.
Definition: sparsity.cpp:1881
static void mul_activityF(const bvec_t *x, const Sparsity &x_sp, const bvec_t *y, const Sparsity &y_sp, bvec_t *z, const Sparsity &z_sp, bvec_t *w)
Propagate signal activity through a matrix product, forward mode.
Definition: sparsity.cpp:1874
static void mul_sparsityF(const bvec_t *x, const Sparsity &x_sp, const bvec_t *y, const Sparsity &y_sp, bvec_t *z, const Sparsity &z_sp, bvec_t *w)
Propagate sparsity using 0-1 logic through a matrix product,.
Definition: sparsity.cpp:1867
The casadi namespace.
Definition: archiver.cpp:28
void casadi_mtimes_dense_sparse(const T1 *x, casadi_int nrow_x, const T1 *y, const casadi_int *sp_y, T1 *z)
Dense * sparse matrix multiplication: z <- z + x*y (z, x dense col-major)
unsigned long long bvec_t
void casadi_mtimes_dense(const T1 *x, casadi_int nrow_x, casadi_int ncol_x, const T1 *y, casadi_int ncol_y, T1 *z, casadi_int tr)
Dense matrix-matrix multiplication: z <- z + x*y (column-major)
static void codegen_copy_z(CodeGenerator &g, casadi_int nnz, const std::vector< casadi_int > &arg, const std::vector< casadi_int > &res, const std::vector< bool > &arg_is_ref)
void casadi_mtimes(const T1 *x, const casadi_int *sp_x, const T1 *y, const casadi_int *sp_y, T1 *z, const casadi_int *sp_z, T1 *w, casadi_int tr)
Sparse matrix-matrix multiplication: z <- z + x*y.