x_function.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_X_FUNCTION_HPP
27 #define CASADI_X_FUNCTION_HPP
28 
29 #include <stack>
30 #include "function_internal.hpp"
31 #include "factory.hpp"
32 #include "serializing_stream.hpp"
33 
34 // To reuse variables we need to be able to sort by sparsity pattern
35 #include <unordered_map>
36 #define SPARSITY_MAP std::unordered_map
37 
38 // Throw informative error message
39 #define CASADI_THROW_ERROR(FNAME, WHAT) \
40 throw CasadiException("Error in XFunction::" FNAME " for '" + this->name_ + "' "\
41  "[" + this->class_name() + "] at " + CASADI_WHERE + ":\n"\
42  + std::string(WHAT));
43 
45 
46 namespace casadi {
47 
56  template<typename DerivedType, typename MatType, typename NodeType>
57  class CASADI_EXPORT XFunction : public FunctionInternal {
58  public:
59 
63  XFunction(const std::string& name,
64  const std::vector<MatType>& ex_in,
65  const std::vector<MatType>& ex_out,
66  const std::vector<std::string>& name_in,
67  const std::vector<std::string>& name_out);
68 
72  ~XFunction() override {
73  }
74 
78  void init(const Dict& opts) override;
79 
82  bool has_spfwd() const override { return true;}
83  bool has_sprev() const override { return true;}
85 
93  static void sort_depth_first(std::stack<NodeType*>& s, std::vector<NodeType*>& nodes);
94 
98  std::vector<MatType> jac(const Dict& opts) const;
99 
103  bool is_a(const std::string& type, bool recursive) const override {
104  return type=="xfunction" || (recursive && FunctionInternal::is_a(type, recursive));
105  }
106 
107  // Factory
108  Function factory(const std::string& name,
109  const std::vector<std::string>& s_in,
110  const std::vector<std::string>& s_out,
111  const Function::AuxOut& aux,
112  const Dict& opts) const override;
113 
120  std::vector<bool> which_depends(const std::string& s_in,
121  const std::vector<std::string>& s_out,
122  casadi_int order, bool tr=false) const override;
123 
125 
128  bool has_forward(casadi_int nfwd) const override { return true;}
129  Function get_forward(casadi_int nfwd, const std::string& name,
130  const std::vector<std::string>& inames,
131  const std::vector<std::string>& onames,
132  const Dict& opts) const override;
134 
136 
139  bool has_reverse(casadi_int nadj) const override { return true;}
140  Function get_reverse(casadi_int nadj, const std::string& name,
141  const std::vector<std::string>& inames,
142  const std::vector<std::string>& onames,
143  const Dict& opts) const override;
145 
147 
150  bool has_jacobian() const override { return true;}
151  Function get_jacobian(const std::string& name,
152  const std::vector<std::string>& inames,
153  const std::vector<std::string>& onames,
154  const Dict& opts) const override;
156 
160  Function slice(const std::string& name, const std::vector<casadi_int>& order_in,
161  const std::vector<casadi_int>& order_out, const Dict& opts) const override;
162 
166  void codegen_declarations(CodeGenerator& g) const override = 0;
167 
171  void codegen_body(CodeGenerator& g) const override = 0;
172 
176  void export_code(const std::string& lang,
177  std::ostream &stream, const Dict& options) const override;
178 
182  virtual void export_code_body(const std::string& lang,
183  std::ostream &stream, const Dict& options) const = 0;
184 
188  bool has_codegen() const override { return true;}
189 
193  virtual bool isInput(const std::vector<MatType>& arg) const;
194 
196  virtual bool should_inline(bool with_sx, bool always_inline, bool never_inline) const = 0;
197 
201  void call_forward(const std::vector<MatType>& arg,
202  const std::vector<MatType>& res,
203  const std::vector<std::vector<MatType> >& fseed,
204  std::vector<std::vector<MatType> >& fsens,
205  bool always_inline, bool never_inline) const override;
206 
210  void call_reverse(const std::vector<MatType>& arg,
211  const std::vector<MatType>& res,
212  const std::vector<std::vector<MatType> >& aseed,
213  std::vector<std::vector<MatType> >& asens,
214  bool always_inline, bool never_inline) const override;
215 
217 
220  size_t get_n_in() override { return in_.size(); }
221  size_t get_n_out() override { return out_.size(); }
223 
225 
228  Sparsity get_sparsity_in(casadi_int i) override { return in_.at(i).sparsity();}
229  Sparsity get_sparsity_out(casadi_int i) override { return out_.at(i).sparsity();}
231 
239  void serialize_body(SerializingStream &s) const override;
240 
251 
252  // Data members (all public)
253 
257  std::vector<MatType> in_;
258 
262  std::vector<MatType> out_;
263  };
264 
265  // Template implementations
266 
267  template<typename DerivedType, typename MatType, typename NodeType>
269  XFunction(const std::string& name,
270  const std::vector<MatType>& ex_in,
271  const std::vector<MatType>& ex_out,
272  const std::vector<std::string>& name_in,
273  const std::vector<std::string>& name_out)
274  : FunctionInternal(name), in_(ex_in), out_(ex_out) {
275  // Names of inputs
276  if (!name_in.empty()) {
277  casadi_assert(ex_in.size()==name_in.size(),
278  "Mismatching number of input names");
279  name_in_ = name_in;
280  }
281  // Names of outputs
282  if (!name_out.empty()) {
283  casadi_assert(ex_out.size()==name_out.size(),
284  "Mismatching number of output names");
285  name_out_ = name_out;
286  }
287  }
288 
289  template<typename DerivedType, typename MatType, typename NodeType>
292  s.version("XFunction", 1);
293  s.unpack("XFunction::in", in_);
294  // 'out' member needs to be delayed
295  }
296 
297  template<typename DerivedType, typename MatType, typename NodeType>
300  s.unpack("XFunction::out", out_);
301  }
302 
303  template<typename DerivedType, typename MatType, typename NodeType>
306  s.pack("XFunction::out", out_);
307  }
308 
309  template<typename DerivedType, typename MatType, typename NodeType>
313  s.version("XFunction", 1);
314  s.pack("XFunction::in", in_);
315  // 'out' member needs to be delayed
316  }
317 
318  template<typename DerivedType, typename MatType, typename NodeType>
320  // Call the init function of the base class
322 
323  bool allow_duplicate_io_names = false;
324  // Read options
325  for (auto&& op : opts) {
326  if (op.first=="allow_duplicate_io_names") {
327  allow_duplicate_io_names = op.second;
328  }
329  }
330 
331  if (verbose_) casadi_message(name_ + "::init");
332  // Make sure that inputs are symbolic
333  for (casadi_int i=0; i<n_in_; ++i) {
334  if (in_.at(i).nnz()>0 && !in_.at(i).is_valid_input()) {
335  casadi_error("For " + this->name_ + ": Xfunction input arguments must be purely symbolic."
336  "\nArgument " + str(i) + "(" + name_in_[i] + ") is not symbolic.");
337  }
338  }
339 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
340  std::lock_guard<std::mutex> lock(MatType::get_mutex_temp());
341 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
342 
343  // Check for duplicate entries among the input expressions
344  bool has_duplicates = false;
345  for (auto&& i : in_) {
346  if (i.has_duplicates()) {
347  has_duplicates = true;
348  break;
349  }
350  }
351  // Reset temporaries
352  for (auto&& i : in_) i.reset_input();
353  // Generate error
354  if (has_duplicates) {
355  std::stringstream s;
356  s << "The input expressions are not independent:\n";
357  for (casadi_int iind=0; iind<in_.size(); ++iind) {
358  s << iind << ": " << in_[iind] << "\n";
359  }
360  casadi_error(s.str());
361  }
362 
363  if (!allow_duplicate_io_names) {
364  // Collect hashes for all inputs and outputs
365  std::hash<std::string> hasher;
366  std::vector<size_t> iohash;
367  iohash.reserve(name_in_.size() + name_out_.size());
368  for (const std::string& s : name_in_) iohash.push_back(hasher(s));
369  for (const std::string& s : name_out_) iohash.push_back(hasher(s));
370  std::sort(iohash.begin(), iohash.end());
371  // Look for duplicates
372  size_t prev = -1;
373  for (size_t h : iohash) {
374  if (h == prev) {
375  // Hash duplicate found, collect strings
376  std::vector<std::string> io_names;
377  io_names.reserve(iohash.size());
378  for (const std::string& s : name_in_) io_names.push_back(s);
379  for (const std::string& s : name_out_) io_names.push_back(s);
380  std::sort(io_names.begin(), io_names.end());
381  // Look for duplicates
382  std::string prev;
383  for (std::string h : io_names) {
384  if (h == prev) casadi_error("Duplicate IO name: " + h + ". "
385  "To ignore this error, set 'allow_duplicate_io_names' option.");
386  prev = h;
387  }
388  }
389  prev = h;
390  }
391  }
392  }
393 
394  template<typename DerivedType, typename MatType, typename NodeType>
396  std::stack<NodeType*>& s, std::vector<NodeType*>& nodes) {
397  while (!s.empty()) {
398  // Get the topmost element
399  NodeType* t = s.top();
400  // If the last element on the stack has not yet been added
401  if (t && t->temp>=0) {
402  // Get the index of the next dependency
403  casadi_int next_dep = t->temp++;
404  // If there is any dependency which has not yet been added
405  if (next_dep < t->n_dep()) {
406  // Add dependency to stack
407  s.push(static_cast<NodeType*>(t->dep(next_dep).get()));
408  } else {
409  // if no dependencies need to be added, we can add the node to the algorithm
410  nodes.push_back(t);
411  // Mark the node as found
412  t->temp = -1;
413  // Remove from stack
414  s.pop();
415  }
416  } else {
417  // If the last element on the stack has already been added
418  s.pop();
419  }
420  }
421  }
422 
423  template<typename DerivedType, typename MatType, typename NodeType>
424  std::vector<MatType> XFunction<DerivedType, MatType, NodeType>
425  ::jac(const Dict& opts) const {
426  try {
427  // Read options
428  bool compact = false;
429  bool symmetric = false;
430  bool allow_forward = true;
431  bool allow_reverse = true;
432  for (auto&& op : opts) {
433  if (op.first=="compact") {
434  compact = op.second;
435  } else if (op.first=="symmetric") {
436  symmetric = op.second;
437  } else if (op.first=="allow_forward") {
438  allow_forward = op.second;
439  } else if (op.first=="allow_reverse") {
440  allow_reverse = op.second;
441  } else if (op.first=="verbose") {
442  continue;
443  } else {
444  casadi_error("No such Jacobian option: " + std::string(op.first));
445  }
446  }
447 
448  // Return object
449  std::vector<MatType> ret(n_in_ * n_out_);
450 
451  // Quick return if trivially empty
452  if (nnz_in() == 0 || nnz_out() == 0) {
453  for (casadi_int i = 0; i < n_out_; ++i) {
454  for (casadi_int j = 0; j < n_in_; ++j) {
455  if (compact) {
456  ret[i * n_in_ + j] = MatType(nnz_out(i), nnz_in(j));
457  } else {
458  ret[i * n_in_ + j] = MatType(numel_out(i), numel_in(j));
459  }
460  }
461  }
462  return ret;
463  }
464 
465  // FIXME(@jaeandersson)
466  casadi_int iind = 0, oind = 0;
467  casadi_assert(n_in_ == 1, "Not implemented");
468  casadi_assert(n_out_ == 1, "Not implemented");
469 
470  // Create return object
471  ret.at(0) = MatType::zeros(jac_sparsity(0, 0, false, symmetric).T());
472  if (verbose_) casadi_message("Allocated return value");
473 
474  // Quick return if empty
475  if (ret.at(0).nnz()==0) {
476  ret.at(0) = ret.at(0).T();
477  return ret;
478  }
479 
480  // Get a bidirectional partition
481  Sparsity D1, D2;
482  get_partition(iind, oind, D1, D2, true, symmetric, allow_forward, allow_reverse);
483  if (verbose_) casadi_message("Graph coloring completed");
484 
485  // Get the number of forward and adjoint sweeps
486  casadi_int nfdir = D1.is_null() ? 0 : D1.size2();
487  casadi_int nadir = D2.is_null() ? 0 : D2.size2();
488 
489  // Number of derivative directions supported by the function
490  casadi_int max_nfdir = max_num_dir_;
491  casadi_int max_nadir = max_num_dir_;
492 
493  // Current forward and adjoint direction
494  casadi_int offset_nfdir = 0, offset_nadir = 0;
495 
496  // Evaluation result (known)
497  std::vector<MatType> res(out_);
498 
499  // Forward and adjoint seeds and sensitivities
500  std::vector<std::vector<MatType> > fseed, aseed, fsens, asens;
501 
502  // Get the sparsity of the Jacobian block
503  Sparsity jsp = jac_sparsity(0, 0, true, symmetric).T();
504  const casadi_int* jsp_colind = jsp.colind();
505  const casadi_int* jsp_row = jsp.row();
506 
507  // Input sparsity
508  std::vector<casadi_int> input_col = sparsity_in_.at(iind).get_col();
509  const casadi_int* input_row = sparsity_in_.at(iind).row();
510 
511  // Output sparsity
512  std::vector<casadi_int> output_col = sparsity_out_.at(oind).get_col();
513  const casadi_int* output_row = sparsity_out_.at(oind).row();
514 
515  // Get transposes and mappings for jacobian sparsity pattern if we are using forward mode
516  if (verbose_) casadi_message("jac transposes and mapping");
517  std::vector<casadi_int> mapping;
518  Sparsity jsp_trans;
519  if (nfdir>0) {
520  jsp_trans = jsp.transpose(mapping);
521  }
522 
523  // The nonzeros of the sensitivity matrix
524  std::vector<casadi_int> nzmap, nzmap2;
525 
526  // Additions to the jacobian matrix
527  std::vector<casadi_int> adds, adds2;
528 
529  // Temporary vector
530  std::vector<casadi_int> tmp;
531 
532  // Progress
533  casadi_int progress = -10;
534 
535  // Number of sweeps
536  casadi_int nsweep_fwd = nfdir/max_nfdir; // Number of sweeps needed for the forward mode
537  if (nfdir%max_nfdir>0) nsweep_fwd++;
538  casadi_int nsweep_adj = nadir/max_nadir; // Number of sweeps needed for the adjoint mode
539  if (nadir%max_nadir>0) nsweep_adj++;
540  casadi_int nsweep = std::max(nsweep_fwd, nsweep_adj);
541  if (verbose_) {
542  casadi_message(str(nsweep) + " sweeps needed for " + str(nfdir) + " forward and "
543  + str(nadir) + " reverse directions");
544  }
545 
546  // Sparsity of the seeds
547  std::vector<casadi_int> seed_col, seed_row;
548 
549  // Evaluate until everything has been determined
550  for (casadi_int s=0; s<nsweep; ++s) {
551  // Print progress
552  if (verbose_) {
553  casadi_int progress_new = (s*100)/nsweep;
554  // Print when entering a new decade
555  if (progress_new / 10 > progress / 10) {
556  progress = progress_new;
557  casadi_message(str(progress) + " %");
558  }
559  }
560 
561  // Number of forward and adjoint directions in the current "batch"
562  casadi_int nfdir_batch = std::min(nfdir - offset_nfdir, max_nfdir);
563  casadi_int nadir_batch = std::min(nadir - offset_nadir, max_nadir);
564 
565  // Forward seeds
566  fseed.resize(nfdir_batch);
567  for (casadi_int d=0; d<nfdir_batch; ++d) {
568  // Nonzeros of the seed matrix
569  seed_col.clear();
570  seed_row.clear();
571 
572  // For all the directions
573  for (casadi_int el = D1.colind(offset_nfdir+d); el<D1.colind(offset_nfdir+d+1); ++el) {
574 
575  // Get the direction
576  casadi_int c = D1.row(el);
577 
578  // Give a seed in the direction
579  seed_col.push_back(input_col[c]);
580  seed_row.push_back(input_row[c]);
581  }
582 
583  // initialize to zero
584  fseed[d].resize(n_in_);
585  for (casadi_int ind=0; ind<fseed[d].size(); ++ind) {
586  casadi_int nrow = size1_in(ind), ncol = size2_in(ind); // Input dimensions
587  if (ind==iind) {
588  fseed[d][ind] = MatType::ones(Sparsity::triplet(nrow, ncol, seed_row, seed_col));
589  } else {
590  fseed[d][ind] = MatType(nrow, ncol);
591  }
592  }
593  }
594 
595  // Adjoint seeds
596  aseed.resize(nadir_batch);
597  for (casadi_int d=0; d<nadir_batch; ++d) {
598  // Nonzeros of the seed matrix
599  seed_col.clear();
600  seed_row.clear();
601 
602  // For all the directions
603  for (casadi_int el = D2.colind(offset_nadir+d); el<D2.colind(offset_nadir+d+1); ++el) {
604 
605  // Get the direction
606  casadi_int c = D2.row(el);
607 
608  // Give a seed in the direction
609  seed_col.push_back(output_col[c]);
610  seed_row.push_back(output_row[c]);
611  }
612 
613  //initialize to zero
614  aseed[d].resize(n_out_);
615  for (casadi_int ind=0; ind<aseed[d].size(); ++ind) {
616  casadi_int nrow = size1_out(ind), ncol = size2_out(ind); // Output dimensions
617  if (ind==oind) {
618  aseed[d][ind] = MatType::ones(Sparsity::triplet(nrow, ncol, seed_row, seed_col));
619  } else {
620  aseed[d][ind] = MatType(nrow, ncol);
621  }
622  }
623  }
624 
625  // Forward sensitivities
626  fsens.resize(nfdir_batch);
627  for (casadi_int d=0; d<nfdir_batch; ++d) {
628  // initialize to zero
629  fsens[d].resize(n_out_);
630  for (casadi_int oind=0; oind<fsens[d].size(); ++oind) {
631  fsens[d][oind] = MatType::zeros(sparsity_out_.at(oind));
632  }
633  }
634 
635  // Adjoint sensitivities
636  asens.resize(nadir_batch);
637  for (casadi_int d=0; d<nadir_batch; ++d) {
638  // initialize to zero
639  asens[d].resize(n_in_);
640  for (casadi_int ind=0; ind<asens[d].size(); ++ind) {
641  asens[d][ind] = MatType::zeros(sparsity_in_.at(ind));
642  }
643  }
644 
645  // Evaluate symbolically
646  if (!fseed.empty()) {
647  casadi_assert_dev(aseed.empty());
648  if (verbose_) casadi_message("Calling 'ad_forward'");
649  static_cast<const DerivedType*>(this)->ad_forward(fseed, fsens);
650  if (verbose_) casadi_message("Back from 'ad_forward'");
651  } else if (!aseed.empty()) {
652  casadi_assert_dev(fseed.empty());
653  if (verbose_) casadi_message("Calling 'ad_reverse'");
654  static_cast<const DerivedType*>(this)->ad_reverse(aseed, asens);
655  if (verbose_) casadi_message("Back from 'ad_reverse'");
656  }
657 
658  // Carry out the forward sweeps
659  for (casadi_int d=0; d<nfdir_batch; ++d) {
660  // Skip if nothing to add
661  if (fsens[d][oind].nnz()==0) {
662  continue;
663  }
664 
665  // If symmetric, see how many times each output appears
666  if (symmetric) {
667  // Initialize to zero
668  tmp.resize(nnz_out(oind));
669  std::fill(tmp.begin(), tmp.end(), 0);
670 
671  // "Multiply" Jacobian sparsity by seed vector
672  for (casadi_int el = D1.colind(offset_nfdir+d); el<D1.colind(offset_nfdir+d+1); ++el) {
673 
674  // Get the input nonzero
675  casadi_int c = D1.row(el);
676 
677  // Propagate dependencies
678  for (casadi_int el_jsp=jsp_colind[c]; el_jsp<jsp_colind[c+1]; ++el_jsp) {
679  tmp[jsp_row[el_jsp]]++;
680  }
681  }
682  }
683 
684  // Locate the nonzeros of the forward sensitivity matrix
685  sparsity_out_.at(oind).find(nzmap);
686  fsens[d][oind].sparsity().get_nz(nzmap);
687 
688  if (symmetric) {
689  sparsity_in_.at(iind).find(nzmap2);
690  fsens[d][oind].sparsity().get_nz(nzmap2);
691  }
692 
693  // Assignments to the Jacobian
694  adds.resize(fsens[d][oind].nnz());
695  std::fill(adds.begin(), adds.end(), -1);
696  if (symmetric) {
697  adds2.resize(adds.size());
698  std::fill(adds2.begin(), adds2.end(), -1);
699  }
700 
701  // For all the input nonzeros treated in the sweep
702  for (casadi_int el = D1.colind(offset_nfdir+d); el<D1.colind(offset_nfdir+d+1); ++el) {
703 
704  // Get the input nonzero
705  casadi_int c = D1.row(el);
706  //casadi_int f2_out;
707  //if (symmetric) {
708  // f2_out = nzmap2[c];
709  //}
710 
711  // Loop over the output nonzeros corresponding to this input nonzero
712  for (casadi_int el_out = jsp_trans.colind(c); el_out<jsp_trans.colind(c+1); ++el_out) {
713 
714  // Get the output nonzero
715  casadi_int r_out = jsp_trans.row(el_out);
716 
717  // Get the forward sensitivity nonzero
718  casadi_int f_out = nzmap[r_out];
719  if (f_out<0) continue; // Skip if structurally zero
720 
721  // The nonzero of the Jacobian now treated
722  casadi_int elJ = mapping[el_out];
723 
724  if (symmetric) {
725  if (tmp[r_out]==1) {
726  adds[f_out] = el_out;
727  adds2[f_out] = elJ;
728  }
729  } else {
730  // Get the output seed
731  adds[f_out] = elJ;
732  }
733  }
734  }
735 
736  // Get entries in fsens[d][oind] with nonnegative indices
737  tmp.resize(adds.size());
738  casadi_int sz = 0;
739  for (casadi_int i=0; i<adds.size(); ++i) {
740  if (adds[i]>=0) {
741  adds[sz] = adds[i];
742  tmp[sz++] = i;
743  }
744  }
745  adds.resize(sz);
746  tmp.resize(sz);
747 
748  // Add contribution to the Jacobian
749  ret.at(0).nz(adds) = fsens[d][oind].nz(tmp);
750 
751  if (symmetric) {
752  // Get entries in fsens[d][oind] with nonnegative indices
753  tmp.resize(adds2.size());
754  sz = 0;
755  for (casadi_int i=0; i<adds2.size(); ++i) {
756  if (adds2[i]>=0) {
757  adds2[sz] = adds2[i];
758  tmp[sz++] = i;
759  }
760  }
761  adds2.resize(sz);
762  tmp.resize(sz);
763 
764  // Add contribution to the Jacobian
765  ret.at(0).nz(adds2) = fsens[d][oind].nz(tmp);
766  }
767  }
768 
769  // Add elements to the Jacobian matrix
770  for (casadi_int d=0; d<nadir_batch; ++d) {
771  // Skip if nothing to add
772  if (asens[d][iind].nnz()==0) {
773  continue;
774  }
775 
776  // Locate the nonzeros of the adjoint sensitivity matrix
777  sparsity_in_.at(iind).find(nzmap);
778  asens[d][iind].sparsity().get_nz(nzmap);
779 
780  // For all the output nonzeros treated in the sweep
781  for (casadi_int el = D2.colind(offset_nadir+d); el<D2.colind(offset_nadir+d+1); ++el) {
782 
783  // Get the output nonzero
784  casadi_int r = D2.row(el);
785 
786  // Loop over the input nonzeros that influences this output nonzero
787  for (casadi_int elJ = jsp.colind(r); elJ<jsp.colind(r+1); ++elJ) {
788 
789  // Get the input nonzero
790  casadi_int inz = jsp.row(elJ);
791 
792  // Get the corresponding adjoint sensitivity nonzero
793  casadi_int anz = nzmap[inz];
794  if (anz<0) continue;
795 
796  // Get the input seed
797  ret.at(0).nz(elJ) = asens[d][iind].nz(anz);
798  }
799  }
800  }
801 
802  // Update direction offsets
803  offset_nfdir += nfdir_batch;
804  offset_nadir += nadir_batch;
805  }
806 
807  // Return
808  for (MatType& Jb : ret) Jb = Jb.T();
809  return ret;
810 
811  } catch (std::exception& e) {
812  CASADI_THROW_ERROR("jac", e.what());
813  }
814  }
815 
816  template<typename DerivedType, typename MatType, typename NodeType>
818  ::get_forward(casadi_int nfwd, const std::string& name,
819  const std::vector<std::string>& inames,
820  const std::vector<std::string>& onames,
821  const Dict& opts) const {
822  try {
823  // Seeds
824  std::vector<std::vector<MatType> > fseed = fwd_seed<MatType>(nfwd), fsens;
825 
826  // Evaluate symbolically
827  static_cast<const DerivedType*>(this)->ad_forward(fseed, fsens);
828  casadi_assert_dev(fsens.size()==fseed.size());
829 
830  // All inputs of the return function
831  std::vector<MatType> ret_in(inames.size());
832  std::copy(in_.begin(), in_.end(), ret_in.begin());
833  for (casadi_int i=0; i<n_out_; ++i) {
834  ret_in.at(n_in_+i) = MatType::sym(inames[n_in_+i], Sparsity(out_.at(i).size()));
835  }
836  std::vector<MatType> v(nfwd);
837  for (casadi_int i=0; i<n_in_; ++i) {
838  for (casadi_int d=0; d<nfwd; ++d) v[d] = fseed[d][i];
839  ret_in.at(n_in_ + n_out_ + i) = horzcat(v);
840  }
841 
842  // All outputs of the return function
843  std::vector<MatType> ret_out(onames.size());
844  for (casadi_int i=0; i<n_out_; ++i) {
845  if (is_diff_out_[i]) {
846  // Concatenate sensitivities, correct sparsity pattern if needed
847  for (casadi_int d=0; d<nfwd; ++d) v[d] = fsens[d][i];
848  ret_out.at(i) = ensure_stacked(horzcat(v), sparsity_out(i), nfwd);
849  } else {
850  // Output is non-differentable
851  ret_out.at(i) = MatType(size1_out(i), size2_out(i) * nfwd);
852  }
853  }
854 
855  Dict options = opts;
856  if (opts.find("is_diff_in")==opts.end())
857  options["is_diff_in"] = join(is_diff_in_, is_diff_out_, is_diff_in_);
858  if (opts.find("is_diff_out")==opts.end())
859  options["is_diff_out"] = is_diff_out_;
860  options["allow_duplicate_io_names"] = true;
861  // Assemble function and return
862  return Function(name, ret_in, ret_out, inames, onames, options);
863  } catch (std::exception& e) {
864  CASADI_THROW_ERROR("get_forward", e.what());
865  }
866  }
867 
868  template<typename DerivedType, typename MatType, typename NodeType>
870  ::get_reverse(casadi_int nadj, const std::string& name,
871  const std::vector<std::string>& inames,
872  const std::vector<std::string>& onames,
873  const Dict& opts) const {
874  try {
875  // Seeds
876  std::vector<std::vector<MatType> > aseed = symbolicAdjSeed(nadj, out_), asens;
877 
878  // Evaluate symbolically
879  static_cast<const DerivedType*>(this)->ad_reverse(aseed, asens);
880 
881  // All inputs of the return function
882  std::vector<MatType> ret_in(inames.size());
883  std::copy(in_.begin(), in_.end(), ret_in.begin());
884  for (casadi_int i=0; i<n_out_; ++i) {
885  ret_in.at(n_in_ + i) = MatType::sym(inames[n_in_+i], Sparsity(out_.at(i).size()));
886  }
887  std::vector<MatType> v(nadj);
888  for (casadi_int i=0; i<n_out_; ++i) {
889  for (casadi_int d=0; d<nadj; ++d) v[d] = aseed[d][i];
890  ret_in.at(n_in_ + n_out_ + i) = horzcat(v);
891  }
892 
893  // All outputs of the return function
894  std::vector<MatType> ret_out(onames.size());
895  for (casadi_int i=0; i<n_in_; ++i) {
896  if (is_diff_in_[i]) {
897  // Concatenate sensitivities, correct sparsity pattern if needed
898  for (casadi_int d=0; d<nadj; ++d) v[d] = asens[d][i];
899  ret_out.at(i) = ensure_stacked(horzcat(v), sparsity_in(i), nadj);
900  } else {
901  // Input is non-differentable
902  ret_out.at(i) = MatType(size1_in(i), size2_in(i) * nadj);
903  }
904  }
905 
906  Dict options = opts;
907  if (opts.find("is_diff_in")==opts.end())
908  options["is_diff_in"] = join(is_diff_in_, is_diff_out_, is_diff_out_);
909  if (opts.find("is_diff_out")==opts.end())
910  options["is_diff_out"] = is_diff_in_;
911 
912  options["allow_duplicate_io_names"] = true;
913  // Assemble function and return
914  return Function(name, ret_in, ret_out, inames, onames, options);
915  } catch (std::exception& e) {
916  CASADI_THROW_ERROR("get_reverse", e.what());
917  }
918  }
919 
920  template<typename DerivedType, typename MatType, typename NodeType>
922  ::get_jacobian(const std::string& name,
923  const std::vector<std::string>& inames,
924  const std::vector<std::string>& onames,
925  const Dict& opts) const {
926  try {
927  Dict tmp_options = generate_options("tmp");
928  tmp_options["allow_free"] = true;
929  tmp_options["allow_duplicate_io_names"] = true;
930  // Temporary single-input, single-output function FIXME(@jaeandersson)
931  Function tmp("flattened_" + name, {veccat(in_)}, {veccat(out_)}, tmp_options);
932 
933  // Expression for the extended Jacobian
934  MatType J = tmp.get<DerivedType>()->jac(Dict()).at(0);
935 
936  // Split up extended Jacobian
937  std::vector<casadi_int> r_offset = {0}, c_offset = {0};
938  for (auto& e : out_) r_offset.push_back(r_offset.back() + e.numel());
939  for (auto& e : in_) c_offset.push_back(c_offset.back() + e.numel());
940  auto Jblocks = MatType::blocksplit(J, r_offset, c_offset);
941 
942  // Collect all outputs
943  std::vector<MatType> ret_out;
944  ret_out.reserve(onames.size());
945  for (casadi_int i = 0; i < n_out_; ++i) {
946  for (casadi_int j = 0; j < n_in_; ++j) {
947  MatType b = Jblocks.at(i).at(j);
948  if (!is_diff_out_.at(i) || !is_diff_in_.at(j)) {
949  b = MatType(b.size());
950  }
951  ret_out.push_back(b);
952  }
953  }
954 
955  // All inputs of the return function
956  std::vector<MatType> ret_in(inames.size());
957  std::copy(in_.begin(), in_.end(), ret_in.begin());
958  for (casadi_int i=0; i<n_out_; ++i) {
959  ret_in.at(n_in_+i) = MatType::sym(inames[n_in_+i], Sparsity(out_.at(i).size()));
960  }
961 
962  Dict options = opts;
963  options["allow_free"] = true;
964  options["allow_duplicate_io_names"] = true;
965 
966  // Assemble function and return
967  return Function(name, ret_in, ret_out, inames, onames, options);
968  } catch (std::exception& e) {
969  CASADI_THROW_ERROR("get_jacobian", e.what());
970  }
971  }
972 
973  template<typename DerivedType, typename MatType, typename NodeType>
975  ::slice(const std::string& name, const std::vector<casadi_int>& order_in,
976  const std::vector<casadi_int>& order_out, const Dict& opts) const {
977  // Return expressions
978  std::vector<MatType> ret_in, ret_out;
979  std::vector<std::string> ret_in_name, ret_out_name;
980 
981  // Reorder inputs
982  for (casadi_int k : order_in) {
983  ret_in.push_back(in_.at(k));
984  ret_in_name.push_back(name_in_.at(k));
985  }
986 
987  // Reorder outputs
988  for (casadi_int k : order_out) {
989  ret_out.push_back(out_.at(k));
990  ret_out_name.push_back(name_out_.at(k));
991  }
992 
993  // Assemble function
994  return Function(name, ret_in, ret_out,
995  ret_in_name, ret_out_name, opts);
996  }
997 
998  template<typename DerivedType, typename MatType, typename NodeType>
1000  ::export_code(const std::string& lang, std::ostream &stream, const Dict& options) const {
1001 
1002  casadi_assert(!has_free(), "export_code needs a Function without free variables");
1003 
1004  casadi_assert(lang=="matlab", "Only matlab language supported for now.");
1005 
1006  // start function
1007  stream << "function [varargout] = " << name_ << "(varargin)" << std::endl;
1008 
1009  // Allocate space for output argument (segments)
1010  for (casadi_int i=0;i<n_out_;++i) {
1011  stream << " argout_" << i << " = cell(" << nnz_out(i) << ",1);" << std::endl;
1012  }
1013 
1014  Dict opts;
1015  opts["indent_level"] = 1;
1016  export_code_body(lang, stream, opts);
1017 
1018  // Process the outputs
1019  for (casadi_int i=0;i<n_out_;++i) {
1020  const Sparsity& out = sparsity_out_.at(i);
1021  if (out.is_dense()) {
1022  // Special case if dense
1023  stream << " varargout{" << i+1 << "} = reshape(vertcat(argout_" << i << "{:}), ";
1024  stream << out.size1() << ", " << out.size2() << ");" << std::endl;
1025  } else {
1026  // For sparse outputs, export sparsity and call 'sparse'
1027  Dict opts;
1028  opts["name"] = "sp";
1029  opts["indent_level"] = 1;
1030  opts["as_matrix"] = false;
1031  out.export_code("matlab", stream, opts);
1032  stream << " varargout{" << i+1 << "} = ";
1033  stream << "sparse(sp_i, sp_j, vertcat(argout_" << i << "{:}), sp_m, sp_n);" << std::endl;
1034  }
1035  }
1036 
1037  // end function
1038  stream << "end" << std::endl;
1039  stream << "function y=nonzeros_gen(x)" << std::endl;
1040  stream << " if isa(x,'casadi.SX') || isa(x,'casadi.MX') || isa(x,'casadi.DM')" << std::endl;
1041  stream << " y = x{:};" << std::endl;
1042  stream << " elseif isa(x,'sdpvar')" << std::endl;
1043  stream << " b = getbase(x);" << std::endl;
1044  stream << " f = find(sum(b~=0,2));" << std::endl;
1045  stream << " y = sdpvar(length(f),1,[],getvariables(x),b(f,:));" << std::endl;
1046  stream << " else" << std::endl;
1047  stream << " y = nonzeros(x);" << std::endl;
1048  stream << " end" << std::endl;
1049  stream << "end" << std::endl;
1050  stream << "function y=if_else_zero_gen(c,e)" << std::endl;
1051  stream << " if isa(c+e,'casadi.SX') || isa(c+e,'casadi.MX') "
1052  "|| isa(c+e,'casadi.DM')" << std::endl;
1053  stream << " y = if_else(c, e, 0);" << std::endl;
1054  stream << " else" << std::endl;
1055  stream << " if c" << std::endl;
1056  stream << " y = x;" << std::endl;
1057  stream << " else" << std::endl;
1058  stream << " y = 0;" << std::endl;
1059  stream << " end" << std::endl;
1060  stream << " end" << std::endl;
1061  stream << "end" << std::endl;
1062 
1063 
1064  }
1065 
1066  template<typename DerivedType, typename MatType, typename NodeType>
1068  ::isInput(const std::vector<MatType>& arg) const {
1069  // Check if arguments matches the input expressions, in which case
1070  // the output is known to be the output expressions
1071  const casadi_int checking_depth = 2;
1072  for (casadi_int i=0; i<arg.size(); ++i) {
1073  if (!is_equal(arg[i], in_[i], checking_depth)) {
1074  return false;
1075  }
1076  }
1077  return true;
1078  }
1079 
1080  template<typename DerivedType, typename MatType, typename NodeType>
1082  call_forward(const std::vector<MatType>& arg,
1083  const std::vector<MatType>& res,
1084  const std::vector<std::vector<MatType> >& fseed,
1085  std::vector<std::vector<MatType> >& fsens,
1086  bool always_inline, bool never_inline) const {
1087  casadi_assert(!(always_inline && never_inline), "Inconsistent options");
1088  if (!should_inline(MatType::type_name()=="SX", always_inline, never_inline)) {
1089  // The non-inlining version is implemented in the base class
1090  return FunctionInternal::call_forward(arg, res, fseed, fsens,
1091  always_inline, never_inline);
1092  }
1093 
1094  // Quick return if no seeds
1095  if (fseed.empty()) {
1096  fsens.clear();
1097  return;
1098  }
1099 
1100  // Call inlining
1101  if (isInput(arg)) {
1102  // Argument agrees with in_, call ad_forward directly
1103  static_cast<const DerivedType*>(this)->ad_forward(fseed, fsens);
1104  } else {
1105  // Need to create a temporary function
1106  Function f("tmp_call_forward", arg, res);
1107  static_cast<DerivedType *>(f.get())->ad_forward(fseed, fsens);
1108  }
1109  }
1110 
1111  template<typename DerivedType, typename MatType, typename NodeType>
1113  call_reverse(const std::vector<MatType>& arg,
1114  const std::vector<MatType>& res,
1115  const std::vector<std::vector<MatType> >& aseed,
1116  std::vector<std::vector<MatType> >& asens,
1117  bool always_inline, bool never_inline) const {
1118  casadi_assert(!(always_inline && never_inline), "Inconsistent options");
1119  if (!should_inline(MatType::type_name()=="SX", always_inline, never_inline)) {
1120  // The non-inlining version is implemented in the base class
1121  return FunctionInternal::call_reverse(arg, res, aseed, asens,
1122  always_inline, never_inline);
1123  }
1124 
1125  // Quick return if no seeds
1126  if (aseed.empty()) {
1127  asens.clear();
1128  return;
1129  }
1130 
1131  // Call inlining
1132  if (isInput(arg)) {
1133  // Argument agrees with in_, call ad_reverse directly
1134  static_cast<const DerivedType*>(this)->ad_reverse(aseed, asens);
1135  } else {
1136  // Need to create a temporary function
1137  Function f("tmp_call_reverse", arg, res);
1138  static_cast<DerivedType *>(f.get())->ad_reverse(aseed, asens);
1139  }
1140  }
1141 
1142  template<typename DerivedType, typename MatType, typename NodeType>
1144  factory(const std::string& name,
1145  const std::vector<std::string>& s_in,
1146  const std::vector<std::string>& s_out,
1147  const Function::AuxOut& aux,
1148  const Dict& opts) const {
1149 
1150  Dict g_ops = generate_options("clone");
1151  Dict f_options;
1152  f_options["helper_options"] = g_ops;
1153  f_options["final_options"] = g_ops;
1154  update_dict(f_options, opts, true);
1155 
1156  Dict final_options;
1157  extract_from_dict_inplace(f_options, "final_options", final_options);
1158  final_options["allow_duplicate_io_names"] = true;
1159 
1160  // Create an expression factory
1161  Factory<MatType> f;
1162  for (casadi_int i=0; i<in_.size(); ++i) f.add_input(name_in_[i], in_[i], is_diff_in_[i]);
1163  for (casadi_int i=0; i<out_.size(); ++i) f.add_output(name_out_[i], out_[i], is_diff_out_[i]);
1164  f.add_dual(aux);
1165 
1166  // Specify input expressions to be calculated
1167  std::vector<std::string> ret_iname;
1168  for (const std::string& s : s_in) {
1169  try {
1170  ret_iname.push_back(f.request_input(s));
1171  } catch (CasadiException& ex) {
1172  casadi_error("Cannot process factory input \"" + s + "\":" + ex.what());
1173  }
1174  }
1175 
1176  // Specify output expressions to be calculated
1177  std::vector<std::string> ret_oname;
1178  for (const std::string& s : s_out) {
1179  try {
1180  ret_oname.push_back(f.request_output(s));
1181  } catch (CasadiException& ex) {
1182  casadi_error("Cannot process factory output \"" + s + "\":" + ex.what());
1183  }
1184  }
1185 
1186  // Calculate expressions
1187  f.calculate(f_options);
1188 
1189  // Get input expressions
1190  std::vector<MatType> ret_in;
1191  ret_in.reserve(s_in.size());
1192  for (const std::string& s : s_in) ret_in.push_back(f.get_input(s));
1193 
1194  // Get output expressions
1195  std::vector<MatType> ret_out;
1196  ret_out.reserve(s_out.size());
1197  for (const std::string& s : s_out) ret_out.push_back(f.get_output(s));
1198 
1199  // Create function and return
1200  Dict final_options_allow_free = final_options;
1201  final_options_allow_free["allow_free"] = true;
1202  final_options_allow_free["allow_duplicate_io_names"] = true;
1203  Function ret(name, ret_in, ret_out, ret_iname, ret_oname, final_options_allow_free);
1204  if (ret.has_free()) {
1205  // Substitute free variables with zeros
1206  // We assume that the free variables are caused by false positive dependencies
1207  std::vector<MatType> free_in = MatType::get_free(ret);
1208  std::vector<MatType> free_sub = free_in;
1209  for (auto&& e : free_sub) e = MatType::zeros(e.sparsity());
1210  ret_out = substitute(ret_out, free_in, free_sub);
1211  ret = Function(name, ret_in, ret_out, ret_iname, ret_oname, final_options);
1212  }
1213  return ret;
1214  }
1215 
1216  template<typename DerivedType, typename MatType, typename NodeType>
1218  which_depends(const std::string& s_in, const std::vector<std::string>& s_out,
1219  casadi_int order, bool tr) const {
1220 
1221  // Input arguments
1222  auto it = std::find(name_in_.begin(), name_in_.end(), s_in);
1223  casadi_assert_dev(it!=name_in_.end());
1224  MatType arg = in_.at(it-name_in_.begin());
1225 
1226  // Output arguments
1227  std::vector<MatType> res;
1228  for (auto&& s : s_out) {
1229  it = std::find(name_out_.begin(), name_out_.end(), s);
1230  casadi_assert_dev(it!=name_out_.end());
1231  res.push_back(out_.at(it-name_out_.begin()));
1232  }
1233 
1234  // Extract variables entering nonlinearly
1235  return MatType::which_depends(veccat(res), arg, order, tr);
1236  }
1237 
1238  template<typename MatType>
1239  Sparsity _jacobian_sparsity(const MatType &expr, const MatType &var) {
1240  Dict opts{{"max_io", 0}, {"allow_free", true}};
1241  Function f = Function("tmp_jacobian_sparsity", {var}, {expr}, opts);
1242  return f.jac_sparsity(0, 0, false);
1243  }
1244 
1245  template<typename MatType>
1246  std::vector<bool> _which_depends(const MatType &expr, const MatType &var,
1247  casadi_int order, bool tr) {
1248  // Short-circuit
1249  if (expr.is_empty() || var.is_empty()) {
1250  return std::vector<bool>(tr? expr.numel() : var.numel(), false);
1251  }
1252 
1253  MatType e = expr;
1254 
1255  // Create a function for calculating a forward-mode derivative
1256  casadi_assert(order==1 || order==2,
1257  "which_depends: order argument must be 1 or 2, got " + str(order) + " instead.");
1258 
1259  MatType v = MatType::sym("v", var.sparsity());
1260  for (casadi_int i=1;i<order;++i) {
1261  e = jtimes(e, var, v);
1262  }
1263 
1264  Dict opts{{"max_io", 0}, {"allow_free", true}};
1265  Function f = Function("tmp_which_depends", {var}, {e}, opts);
1266  // Propagate sparsities backwards seeding all outputs
1267  std::vector<bvec_t> seed(tr? f.nnz_in(0) : f.nnz_out(0), 1);
1268  std::vector<bvec_t> sens(tr? f.nnz_out(0) : f.nnz_in(0), 0);
1269 
1270  if (tr)
1271  f({get_ptr(seed)}, {get_ptr(sens)});
1272  else
1273  f.rev({get_ptr(sens)}, {get_ptr(seed)});
1274  // Temporaries for evaluation
1275  std::vector<bool> ret(sens.size());
1276  std::copy(sens.begin(), sens.end(), ret.begin());
1277 
1278  // Project the result back on the original sparsity
1279  if (tr && e.sparsity()!=expr.sparsity()) {
1280  // std::vector<bool> is not accessible as bool*
1281  // bool -> casadi_int
1282  std::vector<casadi_int> source(sens.size());
1283  std::copy(ret.begin(), ret.end(), source.begin());
1284  std::vector<casadi_int> target(expr.nnz());
1285 
1286  // project
1287  std::vector<casadi_int> scratch(expr.size1());
1288  casadi_project(get_ptr(source), e.sparsity(), get_ptr(target), expr.sparsity(),
1289  get_ptr(scratch));
1290 
1291  // casadi_int -> bool
1292  ret.resize(expr.nnz());
1293  std::copy(target.begin(), target.end(), ret.begin());
1294  }
1295 
1296  return ret;
1297  }
1298 
1299 } // namespace casadi
1301 #undef CASADI_THROW_ERROR
1302 
1303 #endif // CASADI_X_FUNCTION_HPP
Casadi exception class.
Definition: exception.hpp:77
const char * what() const override
Display error.
Definition: exception.hpp:90
Helper class for C code generation.
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
MatType get_output(const std::string &s)
Definition: factory.hpp:603
std::string request_output(const std::string &s)
Definition: factory.hpp:206
void add_dual(const Function::AuxOut &aux)
Definition: factory.hpp:541
std::string request_input(const std::string &s)
Definition: factory.hpp:182
void calculate(const Dict &opts=Dict())
Definition: factory.hpp:558
MatType get_input(const std::string &s)
Definition: factory.hpp:596
void add_input(const std::string &s, const MatType &e, bool is_diff)
Definition: factory.hpp:160
void add_output(const std::string &s, const MatType &e, bool is_diff)
Definition: factory.hpp:171
Internal class for Function.
void init(const Dict &opts) override
Initialize.
virtual void call_forward(const std::vector< MX > &arg, const std::vector< MX > &res, const std::vector< std::vector< MX > > &fseed, std::vector< std::vector< MX > > &fsens, bool always_inline, bool never_inline) const
Forward mode AD, virtual functions overloaded in derived classes.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
virtual void call_reverse(const std::vector< MX > &arg, const std::vector< MX > &res, const std::vector< std::vector< MX > > &aseed, std::vector< std::vector< MX > > &asens, bool always_inline, bool never_inline) const
Reverse mode, virtual functions overloaded in derived classes.
virtual bool is_a(const std::string &type, bool recursive) const
Check if the function is of a particular type.
std::vector< std::string > name_out_
std::vector< std::string > name_in_
Input and output scheme.
Function object.
Definition: function.hpp:60
casadi_int nnz_out() const
Get number of output nonzeros.
Definition: function.cpp:855
FunctionInternal * get() const
Definition: function.cpp:353
int rev(bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, int mem=0) const
Propagate sparsity backward.
Definition: function.cpp:1100
bool has_free() const
Does the function have free variables.
Definition: function.cpp:1697
casadi_int nnz_in() const
Get number of input nonzeros.
Definition: function.cpp:851
const std::vector< Sparsity > & jac_sparsity(bool compact=false) const
Get, if necessary generate, the sparsity of all Jacobian blocks.
Definition: function.cpp:940
std::map< std::string, std::vector< std::string > > AuxOut
Definition: function.hpp:404
bool is_null() const
Is a null pointer?
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
General sparsity class.
Definition: sparsity.hpp:106
casadi_int size1() const
Get the number of rows.
Definition: sparsity.cpp:124
Sparsity transpose(std::vector< casadi_int > &mapping, bool invert_mapping=false) const
Transpose the matrix and get the reordering of the non-zero entries.
Definition: sparsity.cpp:390
Sparsity T() const
Transpose the matrix.
Definition: sparsity.cpp:394
casadi_int size2() const
Get the number of columns.
Definition: sparsity.cpp:128
const casadi_int * row() const
Get a reference to row-vector,.
Definition: sparsity.cpp:164
void export_code(const std::string &lang, std::ostream &stream=casadi::uout(), const Dict &options=Dict()) const
Export matrix in specific language.
Definition: sparsity.cpp:778
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
Definition: sparsity.cpp:168
bool is_dense() const
Is dense?
Definition: sparsity.cpp:273
static Sparsity triplet(casadi_int nrow, casadi_int ncol, const std::vector< casadi_int > &row, const std::vector< casadi_int > &col, std::vector< casadi_int > &mapping, bool invert_mapping)
Create a sparsity pattern given the nonzeros in sparse triplet form *.
Definition: sparsity.cpp:1127
Internal node class for the base class of SXFunction and MXFunction.
Definition: x_function.hpp:57
std::vector< bool > which_depends(const std::string &s_in, const std::vector< std::string > &s_out, casadi_int order, bool tr=false) const override
Which variables enter with some order.
std::vector< MatType > out_
Outputs of the function (needed for symbolic calculations)
Definition: x_function.hpp:262
void export_code(const std::string &lang, std::ostream &stream, const Dict &options) const override
Export function in a specific language.
void delayed_deserialize_members(DeserializingStream &s)
Definition: x_function.hpp:299
bool has_jacobian() const override
Return Jacobian of all input elements with respect to all output elements.
Definition: x_function.hpp:150
virtual bool should_inline(bool with_sx, bool always_inline, bool never_inline) const =0
void codegen_declarations(CodeGenerator &g) const override=0
Generate code for the declarations of the C function.
bool has_codegen() const override
Is codegen supported?
Definition: x_function.hpp:188
Function get_jacobian(const std::string &name, const std::vector< std::string > &inames, const std::vector< std::string > &onames, const Dict &opts) const override
Return Jacobian of all input elements with respect to all output elements.
Definition: x_function.hpp:922
size_t get_n_out() override
Number of function inputs and outputs.
Definition: x_function.hpp:221
Function get_reverse(casadi_int nadj, const std::string &name, const std::vector< std::string > &inames, const std::vector< std::string > &onames, const Dict &opts) const override
Generate a function that calculates nadj adjoint derivatives.
Definition: x_function.hpp:870
Sparsity get_sparsity_out(casadi_int i) override
Sparsities of function inputs and outputs.
Definition: x_function.hpp:229
void init(const Dict &opts) override
Initialize.
Definition: x_function.hpp:319
bool has_forward(casadi_int nfwd) const override
Generate a function that calculates nfwd forward derivatives.
Definition: x_function.hpp:128
void codegen_body(CodeGenerator &g) const override=0
Generate code for the body of the C function.
bool has_reverse(casadi_int nadj) const override
Generate a function that calculates nadj adjoint derivatives.
Definition: x_function.hpp:139
XFunction(const std::string &name, const std::vector< MatType > &ex_in, const std::vector< MatType > &ex_out, const std::vector< std::string > &name_in, const std::vector< std::string > &name_out)
Constructor.
Definition: x_function.hpp:269
virtual bool isInput(const std::vector< MatType > &arg) const
Helper function: Check if a vector equals ex_in.
bool has_spfwd() const override
Definition: x_function.hpp:82
Function slice(const std::string &name, const std::vector< casadi_int > &order_in, const std::vector< casadi_int > &order_out, const Dict &opts) const override
returns a new function with a selection of inputs/outputs of the original
Definition: x_function.hpp:975
std::vector< MatType > jac(const Dict &opts) const
Construct a complete Jacobian by compression.
Definition: x_function.hpp:425
std::vector< MatType > in_
Inputs of the function (needed for symbolic calculations)
Definition: x_function.hpp:257
~XFunction() override
Destructor.
Definition: x_function.hpp:72
size_t get_n_in() override
Number of function inputs and outputs.
Definition: x_function.hpp:220
Function factory(const std::string &name, const std::vector< std::string > &s_in, const std::vector< std::string > &s_out, const Function::AuxOut &aux, const Dict &opts) const override
void delayed_serialize_members(SerializingStream &s) const
Helper functions to avoid recursion limit.
Definition: x_function.hpp:305
void call_reverse(const std::vector< MatType > &arg, const std::vector< MatType > &res, const std::vector< std::vector< MatType > > &aseed, std::vector< std::vector< MatType > > &asens, bool always_inline, bool never_inline) const override
Create call to (cached) derivative function, reverse mode.
virtual void export_code_body(const std::string &lang, std::ostream &stream, const Dict &options) const =0
Export function body in a specific language.
Function get_forward(casadi_int nfwd, const std::string &name, const std::vector< std::string > &inames, const std::vector< std::string > &onames, const Dict &opts) const override
Generate a function that calculates nfwd forward derivatives.
Definition: x_function.hpp:818
XFunction(DeserializingStream &s)
Deserializing constructor.
Definition: x_function.hpp:291
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: x_function.hpp:311
bool has_sprev() const override
Definition: x_function.hpp:83
Sparsity get_sparsity_in(casadi_int i) override
Sparsities of function inputs and outputs.
Definition: x_function.hpp:228
void call_forward(const std::vector< MatType > &arg, const std::vector< MatType > &res, const std::vector< std::vector< MatType > > &fseed, std::vector< std::vector< MatType > > &fsens, bool always_inline, bool never_inline) const override
Create call to (cached) derivative function, forward mode.
static void sort_depth_first(std::stack< NodeType * > &s, std::vector< NodeType * > &nodes)
Topological sorting of the nodes based on Depth-First Search (DFS)
Definition: x_function.hpp:395
bool is_a(const std::string &type, bool recursive) const override
Check if the function is of a particular type.
Definition: x_function.hpp:103
The casadi namespace.
Definition: archiver.cpp:28
bool is_equal(double x, double y, casadi_int depth=0)
Definition: calculus.hpp:281
std::string join(const std::vector< std::string > &l, const std::string &delim)
std::vector< bool > _which_depends(const MatType &expr, const MatType &var, casadi_int order, bool tr)
void casadi_project(const T1 *x, const casadi_int *sp_x, T1 *y, const casadi_int *sp_y, T1 *w)
Sparse copy: y <- x, w work vector (length >= number of rows)
Sparsity _jacobian_sparsity(const MatType &expr, const MatType &var)
void extract_from_dict_inplace(Dict &d, const std::string &key, T &value)
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
void update_dict(Dict &target, const Dict &source, bool recurse)
Update the target dictionary in place with source elements.
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.