integrator.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 #include "integrator_impl.hpp"
27 #include "casadi_misc.hpp"
28 
29 namespace casadi {
30 
31 std::string to_string(DynIn v) {
32  switch (v) {
33  case DYN_T: return "t";
34  case DYN_X: return "x";
35  case DYN_Z: return "z";
36  case DYN_P: return "p";
37  case DYN_U: return "u";
38  default: break;
39  }
40  return "";
41 }
42 
43 std::string to_string(DynOut v) {
44  switch (v) {
45  case DYN_ODE: return "ode";
46  case DYN_ALG: return "alg";
47  case DYN_QUAD: return "quad";
48  case DYN_ZERO: return "zero";
49  default: break;
50  }
51  return "";
52 }
53 
54 std::string to_string(EventIn v) {
55  switch (v) {
56  case EVENT_INDEX: return "index";
57  case EVENT_T: return "t";
58  case EVENT_X: return "x";
59  case EVENT_Z: return "z";
60  case EVENT_P: return "p";
61  case EVENT_U: return "u";
62  default: break;
63  }
64  return "";
65 }
66 
67 std::string to_string(EventOut v) {
68  switch (v) {
69  case EVENT_POST_X: return "post_x";
70  case EVENT_POST_Z: return "post_z";
71  default: break;
72  }
73  return "";
74 }
75 
76 std::string Integrator::bdyn_in(casadi_int i) {
77  switch (i) {
78  case BDYN_T: return "t";
79  case BDYN_X: return "x";
80  case BDYN_Z: return "z";
81  case BDYN_P: return "p";
82  case BDYN_U: return "u";
83  case BDYN_OUT_ODE: return "out_ode";
84  case BDYN_OUT_ALG: return "out_alg";
85  case BDYN_OUT_QUAD: return "out_quad";
86  case BDYN_OUT_ZERO: return "out_zero";
87  case BDYN_ADJ_ODE: return "adj_ode";
88  case BDYN_ADJ_ALG: return "adj_alg";
89  case BDYN_ADJ_QUAD: return "adj_quad";
90  case BDYN_ADJ_ZERO: return "adj_zero";
91  default: break;
92  }
93  return "";
94 }
95 
96 std::vector<std::string> Integrator::bdyn_in() {
97  std::vector<std::string> ret(BDYN_NUM_IN);
98  for (casadi_int i = 0; i < BDYN_NUM_IN; ++i)
99  ret[i] = bdyn_in(i);
100  return ret;
101 }
102 
103 std::string Integrator::bdyn_out(casadi_int i) {
104  switch (i) {
105  case BDYN_ADJ_T: return "adj_t";
106  case BDYN_ADJ_X: return "adj_x";
107  case BDYN_ADJ_Z: return "adj_z";
108  case BDYN_ADJ_P: return "adj_p";
109  case BDYN_ADJ_U: return "adj_u";
110  default: break;
111  }
112  return "";
113 }
114 
115 std::vector<std::string> Integrator::bdyn_out() {
116  std::vector<std::string> ret(BDYN_NUM_OUT);
117  for (casadi_int i = 0; i < BDYN_NUM_OUT; ++i)
118  ret[i] = bdyn_out(i);
119  return ret;
120 }
121 
122 bool has_integrator(const std::string& name) {
123  return Integrator::has_plugin(name);
124 }
125 
126 void load_integrator(const std::string& name) {
128 }
129 
130 std::string doc_integrator(const std::string& name) {
131  return Integrator::getPlugin(name).doc;
132 }
133 
134 Function integrator(const std::string& name, const std::string& solver,
135  const SXDict& dae, const Dict& opts) {
136  return integrator(name, solver, dae, 0.0, std::vector<double>{1.0}, opts);
137 }
138 
139 Function integrator(const std::string& name, const std::string& solver,
140  const MXDict& dae, const Dict& opts) {
141  return integrator(name, solver, dae, 0.0, std::vector<double>{1.0}, opts);
142 }
143 
144 Function integrator(const std::string& name, const std::string& solver,
145  const Function& dae, const Dict& opts) {
146  return integrator(name, solver, dae, 0.0, std::vector<double>{1.0}, opts);
147 }
148 
149 Function integrator(const std::string& name, const std::string& solver,
150  const SXDict& dae, double t0, const std::vector<double>& tout, const Dict& opts) {
151  return integrator(name, solver, Integrator::map2oracle("dae", dae), t0, tout, opts);
152 }
153 
154 Function integrator(const std::string& name, const std::string& solver,
155  const MXDict& dae, double t0, const std::vector<double>& tout, const Dict& opts) {
156  return integrator(name, solver, Integrator::map2oracle("dae", dae), t0, tout, opts);
157 }
158 
159 Function integrator(const std::string& name, const std::string& solver,
160  const Function& dae, double t0, const std::vector<double>& tout, const Dict& opts) {
161  // Make sure that dae is sound
162  if (dae.has_free()) {
163  casadi_error("Cannot create '" + name + "' since " + str(dae.get_free()) + " are free.");
164  }
165  Integrator* intg = Integrator::getPlugin(solver).creator(name, dae, t0, tout);
166  return intg->create_advanced(opts);
167 }
168 
169 Function integrator(const std::string& name, const std::string& solver,
170  const SXDict& dae, double t0, double tf, const Dict& opts) {
171  return integrator(name, solver, dae, t0, std::vector<double>{tf}, opts);
172 }
173 
174 Function integrator(const std::string& name, const std::string& solver,
175  const MXDict& dae, double t0, double tf, const Dict& opts) {
176  return integrator(name, solver, dae, t0, std::vector<double>{tf}, opts);
177 }
178 
179 Function integrator(const std::string& name, const std::string& solver,
180  const Function& dae, double t0, double tf, const Dict& opts) {
181  return integrator(name, solver, dae, t0, std::vector<double>{tf}, opts);
182 }
183 
184 std::vector<std::string> integrator_in() {
185  std::vector<std::string> ret(integrator_n_in());
186  for (size_t i=0; i<ret.size(); ++i) ret[i]=integrator_in(i);
187  return ret;
188 }
189 
190 std::vector<std::string> integrator_out() {
191  std::vector<std::string> ret(integrator_n_out());
192  for (size_t i=0; i<ret.size(); ++i) ret[i]=integrator_out(i);
193  return ret;
194 }
195 
196 std::string integrator_in(casadi_int ind) {
197  switch (static_cast<IntegratorInput>(ind)) {
198  case INTEGRATOR_X0: return "x0";
199  case INTEGRATOR_Z0: return "z0";
200  case INTEGRATOR_P: return "p";
201  case INTEGRATOR_U: return "u";
202  case INTEGRATOR_ADJ_XF: return "adj_xf";
203  case INTEGRATOR_ADJ_ZF: return "adj_zf";
204  case INTEGRATOR_ADJ_QF: return "adj_qf";
205  case INTEGRATOR_NUM_IN: break;
206  }
207  return std::string();
208 }
209 
210 std::string integrator_out(casadi_int ind) {
211  switch (static_cast<IntegratorOutput>(ind)) {
212  case INTEGRATOR_XF: return "xf";
213  case INTEGRATOR_ZF: return "zf";
214  case INTEGRATOR_QF: return "qf";
215  case INTEGRATOR_ADJ_X0: return "adj_x0";
216  case INTEGRATOR_ADJ_Z0: return "adj_z0";
217  case INTEGRATOR_ADJ_P: return "adj_p";
218  case INTEGRATOR_ADJ_U: return "adj_u";
219  case INTEGRATOR_NUM_OUT: break;
220  }
221  return std::string();
222 }
223 
224 casadi_int integrator_n_in() {
225  return INTEGRATOR_NUM_IN;
226 }
227 
228 casadi_int integrator_n_out() {
229  return INTEGRATOR_NUM_OUT;
230 }
231 
232 std::vector<std::string> dyn_in() {
233  return enum_names<DynIn>();
234 }
235 
236 std::vector<std::string> dyn_out() {
237  return enum_names<DynOut>();
238 }
239 
240 std::string dyn_in(casadi_int ind) {
241  return to_string(static_cast<DynIn>(ind));
242 }
243 
244 std::string dyn_out(casadi_int ind) {
245  return to_string(static_cast<DynOut>(ind));
246 }
247 
248 casadi_int dyn_n_in() {
249  return DYN_NUM_IN;
250 }
251 
252 casadi_int dyn_n_out() {
253  return DYN_NUM_OUT;
254 }
255 
256 std::vector<std::string> event_in() {
257  return enum_names<EventIn>();
258 }
259 
260 std::vector<std::string> event_out() {
261  return enum_names<EventOut>();
262 }
263 
264 Integrator::Integrator(const std::string& name, const Function& oracle,
265  double t0, const std::vector<double>& tout)
266  : OracleFunction(name, oracle), t0_(t0), tout_(tout) {
267 
268  // Negative number of parameters for consistancy checking
269  np_ = -1;
270 
271  // Default options
272  nfwd_ = 0;
273  nadj_ = 0;
274  print_stats_ = false;
275  max_event_iter_ = 3;
276  max_events_ = 20;
277  event_tol_ = 1e-6;
279 }
280 
282 }
283 
285  switch (static_cast<IntegratorInput>(i)) {
286  case INTEGRATOR_X0: return Sparsity::dense(nx1_, 1 + nfwd_);
287  case INTEGRATOR_Z0: return Sparsity::dense(nz1_, 1 + nfwd_);
288  case INTEGRATOR_P: return Sparsity::dense(np1_, 1 + nfwd_);
289  case INTEGRATOR_U: return Sparsity::dense(nu1_, nt() * (1 + nfwd_));
290  case INTEGRATOR_ADJ_XF: return Sparsity::dense(nrx1_, nadj_ * (1 + nfwd_) * nt());
291  case INTEGRATOR_ADJ_ZF: return Sparsity::dense(nrz1_, nadj_ * (1 + nfwd_) * nt());
292  case INTEGRATOR_ADJ_QF: return Sparsity::dense(nrp1_, nadj_ * (1 + nfwd_) * nt());
293  case INTEGRATOR_NUM_IN: break;
294  }
295  return Sparsity();
296 }
297 
299  switch (static_cast<IntegratorOutput>(i)) {
300  case INTEGRATOR_XF: return Sparsity::dense(nx1_, nt() * (1 + nfwd_));
301  case INTEGRATOR_ZF: return Sparsity::dense(nz1_, nt() * (1 + nfwd_));
302  case INTEGRATOR_QF: return Sparsity::dense(nq1_, nt() * (1 + nfwd_));
303  case INTEGRATOR_ADJ_X0: return Sparsity::dense(nrx1_, nadj_ * (1 + nfwd_));
304  case INTEGRATOR_ADJ_Z0: return Sparsity(nrz1_, nadj_ * (1 + nfwd_)); // always zero
305  case INTEGRATOR_ADJ_P: return Sparsity::dense(nrq1_, nadj_ * (1 + nfwd_));
306  case INTEGRATOR_ADJ_U: return Sparsity::dense(nuq1_, nadj_ * (1 + nfwd_) * nt());
307  case INTEGRATOR_NUM_OUT: break;
308  }
309  return Sparsity();
310 }
311 
312 bool Integrator::grid_in(casadi_int i) {
313  switch (static_cast<IntegratorInput>(i)) {
314  case INTEGRATOR_U:
315  case INTEGRATOR_ADJ_XF:
316  case INTEGRATOR_ADJ_ZF:
317  case INTEGRATOR_ADJ_QF:
318  return true;
319  default: break;
320  }
321  return false;
322 }
323 
324 bool Integrator::grid_out(casadi_int i) {
325  switch (static_cast<IntegratorOutput>(i)) {
326  case INTEGRATOR_XF:
327  case INTEGRATOR_ZF:
328  case INTEGRATOR_QF:
329  case INTEGRATOR_ADJ_U:
330  return true;
331  default: break;
332  }
333  return false;
334 }
335 
336 casadi_int Integrator::adjmap_out(casadi_int i) {
337  switch (static_cast<IntegratorInput>(i)) {
338  case INTEGRATOR_X0: return INTEGRATOR_ADJ_X0;
339  case INTEGRATOR_Z0: return INTEGRATOR_ADJ_Z0;
340  case INTEGRATOR_P: return INTEGRATOR_ADJ_P;
341  case INTEGRATOR_U: return INTEGRATOR_ADJ_U;
342  case INTEGRATOR_ADJ_XF: return INTEGRATOR_XF;
343  case INTEGRATOR_ADJ_ZF: return INTEGRATOR_ZF;
344  case INTEGRATOR_ADJ_QF: return INTEGRATOR_QF;
345  default: break;
346  }
347  return -1;
348 }
349 
351  return Function::create(this, opts);
352 }
353 
354 int Integrator::eval(const double** arg, double** res,
355  casadi_int* iw, double* w, void* mem) const {
356  auto m = static_cast<IntegratorMemory*>(mem);
357 
358  // Read inputs
359  const double* x0 = arg[INTEGRATOR_X0];
360  const double* z0 = arg[INTEGRATOR_Z0];
361  const double* p = arg[INTEGRATOR_P];
362  const double* u = arg[INTEGRATOR_U];
363  const double* adj_xf = arg[INTEGRATOR_ADJ_XF];
364  const double* rz0 = arg[INTEGRATOR_ADJ_ZF];
365  const double* rp = arg[INTEGRATOR_ADJ_QF];
366  arg += INTEGRATOR_NUM_IN;
367 
368  // Read outputs
369  double* x = res[INTEGRATOR_XF];
370  double* z = res[INTEGRATOR_ZF];
371  double* q = res[INTEGRATOR_QF];
372  double* adj_x = res[INTEGRATOR_ADJ_X0];
373  double* adj_p = res[INTEGRATOR_ADJ_P];
374  double* adj_u = res[INTEGRATOR_ADJ_U];
375  res += INTEGRATOR_NUM_OUT;
376 
377  // Setup memory object
378  setup(m, arg, res, iw, w);
379 
380  // Pass initial state, parameters
381  set_q(m, 0);
382  set_x(m, x0);
383  set_z(m, z0);
384  set_p(m, p);
385 
386  // Reset number of events
387  m->num_events = 0;
388 
389  // Is this the first call to reset?
390  bool first_call = true;
391 
392  // Take time to t0
393  m->t = t0_;
394 
395  // Ensure that control is updated at the first iteration
396  casadi_int k_stop = -1;
397 
398  // Do we need to reset the solver?
399  m->reset_solver = false;
400 
401  // Integrate forward
402  for (m->k = 0; m->k < nt(); ++m->k) {
403  // Start of the current interval
404  m->t_start = m->t;
405  // Next output time
406  m->t_next_out = tout_[m->k];
407  // By default, integrate until the next output time
408  m->t_next = m->t_next_out;
409  // Handle changes in control input
410  if (m->k > k_stop) {
411  // Pass new controls
412  set_u(m, u);
413  // Detect next stopping time
414  k_stop = next_stop(m->k, u);
415  m->t_stop = m->t_step = tout_[k_stop];
416  // Need to reset solver
417  m->reset_solver = true;
418  }
419  // Mark all events as not triggered
420  std::fill_n(m->event_triggered, ne_, 0);
421  // Keep integrating until we reach the next output time
422  do {
423  // Reset the solver
424  if (m->reset_solver) {
425  reset(m, first_call);
426  m->reset_solver = false;
427  first_call = false;
428  }
429  // Advance solution
430  if (verbose_) {
431  casadi_message("Interval " + str(m->k) + ": Integrating forward from "
432  + str(m->t) + " to " + str(m->t_next) + ", t_stop = " + str(m->t_stop));
433  }
434  if (advance(m)) return 1;
435  // Trigger all event, if any
436  if (m->event_index >= 0) {
437  // Clear list of triggered events
438  std::fill_n(m->event_triggered, ne_, 0);
439  // Trigger the specific event and any chained events
440  while (m->event_index >= 0) {
441  // Trigger event, get any chained event
442  if (trigger_event(m, &m->event_index)) return 1;
443  // Solver needs to be reset
444  m->reset_solver = true;
445  }
446  // Move past event
447  m->t_start = m->t;
448  m->t_stop = m->t_step;
449  m->t_next = m->t_next_out;
450  }
451  } while (m->t != m->t_next);
452  // Get solution
453  get_x(m, x);
454  get_z(m, z);
455  get_q(m, q);
456  if (x) x += nx_;
457  if (z) z += nz_;
458  if (q) q += nq_;
459  if (u) u += nu_;
460  }
461 
462  // Backwards integration, if needed
463  if (nrx_ > 0) {
464  // Take adj_xf, rz0, rp past the last grid point
465  if (adj_xf) adj_xf += nrx_ * nt();
466  if (rz0) rz0 += nrz_ * nt();
467  if (rp) rp += nrp_ * nt();
468  if (adj_u) adj_u += nuq_ * nt();
469  // Next stop time due to step change in input
470  k_stop = nt();
471  // Reset the solver
472  resetB(m);
473  // Any adjoint seed so far?
474  bool any_impulse = false;
475  // Integrate backward
476  for (m->k = nt(); m->k-- > 0; ) {
477  m->t = tout_[m->k];
478  // Add impulse to backwards integration
479  if (adj_xf) adj_xf -= nrx_;
480  if (rz0) rz0 -= nrz_;
481  if (rp) rp -= nrp_;
482  if (adj_u) adj_u -= nuq_;
483  if (u) u -= nu_;
484  if (!all_zero(adj_xf, nrx_) || !all_zero(rz0, nrz_) || !all_zero(rp, nrp_)) {
485  if (verbose_) casadi_message("Impulse from adjoint seeds at output time " + str(m->k));
486  impulseB(m, adj_xf, rz0, rp);
487  any_impulse = true;
488  }
489  // Next output time, or beginning
490  casadi_int k_next = m->k - 1;
491  m->t_next = k_next < 0 ? t0_ : tout_[k_next];
492  // Update integrator stopping time
493  if (k_next < k_stop) k_stop = next_stopB(m->k, u);
494  m->t_stop = k_stop < 0 ? t0_ : tout_[k_stop];
495  // Proceed to the previous time point or t0
496  if (any_impulse) {
497  if (verbose_) casadi_message("Integrating backward from output time " + str(m->k)
498  + ": t_next = " + str(m->t_next) + ", t_stop = " + str(m->t_stop));
499  if (m->k > 0) {
500  retreat(m, u, 0, 0, adj_u);
501  } else {
502  retreat(m, u, adj_x, adj_p, adj_u);
503  }
504  } else {
505  if (verbose_) casadi_message("No adjoint seeds from output time " + str(m->k)
506  + ": t_next = " + str(m->t_next) + ", t_stop = " + str(m->t_stop));
507  casadi_clear(adj_u, nuq_);
508  if (m->k == 0) {
509  casadi_clear(adj_x, nrx_);
510  casadi_clear(adj_p, nrq_);
511  }
512  }
513  }
514  // adj_u should contain the contribution from the grid point, not cumulative
515  if (adj_u) {
516  for (m->k = 0; m->k < nt() - 1; ++m->k) {
517  casadi_axpy(nuq_, -1., adj_u + nuq_, adj_u);
518  adj_u += nuq_;
519  }
520  }
521  }
522 
523  // Collect oracle statistics
524  join_results(m);
525 
526  // Print integrator statistics
527  if (print_stats_) print_stats(m);
528 
529  return 0;
530 }
531 
533  // Predict next event
534  if (ne_ > 0 && m->t_next_out != m->t_start) {
535  if (predict_events(m)) return 1;
536  }
537  // Event iterations
538  m->event_iter = 0;
539  while (true) {
540  // Start a new event iteration
541  m->event_iter++;
542  // No event triggered
543  m->event_index = -1;
544  // Advance solution in time
545  if (advance_noevent(m)) return 1;
546  // Update current time
547  m->t = m->t_next;
548  m->t_next = m->t_next_out;
549  // If no events or no interval, done
550  if (ne_ == 0 || m->t_next_out == m->t_start) break;
551  // Recalculate m->e and m->edot
552  if (calc_edot(m)) return 1;
553  // By default, let integrator continue to the next input step change
554  m->t_stop = m->t_step;
555  // Detect events
556  for (casadi_int i = 0; i < ne_; ++i) {
557  // Make sure that event was not already triggered
558  if (m->event_triggered[i] || m->old_e[i] <= 0) continue;
559  // Check if event was triggered or is projected to be triggered before next output time
560  if (m->e[i] < 0 || (m->edot[i] < 0 && m->e[i] + (m->t_next_out - m->t) * m->edot[i] < 0)) {
561  // Projected zero-crossing time
562  double t_zero = m->t - m->e[i] / m->edot[i];
563  // If t_zero is too small or m->edot[i] has the wrong sign, fall back to bisection
564  if (t_zero <= m->t_start || (m->e[i] < 0 && m->edot[i] >= 0)) {
565  t_zero = 0.5 * (m->t_start + m->t);
566  }
567  // Update t_next if earliest event so far
568  if (t_zero < m->t_next) {
569  m->event_index = i;
570  m->t_next = t_zero;
571  m->t_stop = std::max(m->t, m->t_next);
572  }
573  }
574  }
575  // If no events, done
576  if (m->event_index < 0) break;
577  // Distance to new time step
578  double t_diff = std::fabs(m->t_next - m->t);
579  // Check if converged
580  if (t_diff < event_tol_) {
581  if (verbose_) casadi_message("Event iteration converged, |dt| == " + str(t_diff));
582  break;
583  }
584  // Maximum number of iterations reached?
585  if (m->event_iter == max_event_iter_) {
586  // Throw error?
587  if (t_diff >= event_acceptable_tol_) {
588  casadi_error("Maximum number of event iterations reached without convergence");
589  }
590  if (verbose_) casadi_message("Max event iterations, |dt| == " + str(t_diff));
591  break;
592  }
593  // More iterations needed
594  if (verbose_) casadi_message("Event iteration " + str(m->event_iter) + ", |dt| == "
595  + str(t_diff));
596  }
597  // Successful return
598  return 0;
599 }
600 
603  {{"print_stats",
604  {OT_BOOL,
605  "Print out statistics after integration"}},
606  {"nfwd",
607  {OT_INT,
608  "Number of forward sensitivities to be calculated [0]"}},
609  {"nadj",
610  {OT_INT,
611  "Number of adjoint sensitivities to be calculated [0]"}},
612  {"t0",
613  {OT_DOUBLE,
614  "[DEPRECATED] Beginning of the time horizon"}},
615  {"tf",
616  {OT_DOUBLE,
617  "[DEPRECATED] End of the time horizon"}},
618  {"grid",
620  "[DEPRECATED] Time grid"}},
621  {"augmented_options",
622  {OT_DICT,
623  "Options to be passed down to the augmented integrator, if one is constructed"}},
624  {"transition",
625  {OT_FUNCTION,
626  "Function to be called a zero-crossing events"}},
627  {"max_event_iter",
628  {OT_INT,
629  "Maximum number of iterations to zero in on a single event"}},
630  {"max_events",
631  {OT_INT,
632  "Maximum total number of events"}},
633  {"event_tol",
634  {OT_DOUBLE,
635  "Termination tolerance for the event iteration"}},
636  {"output_t0",
637  {OT_BOOL,
638  "[DEPRECATED] Output the state at the initial time"}}
639  }
640 };
641 
642 void Integrator::init(const Dict& opts) {
643  // Default (temporary) options
644  double t0 = 0, tf = 1;
645  bool output_t0 = false;
646  std::vector<double> grid;
647  bool uses_legacy_options = false;
648 
649  // Read options
650  for (auto&& op : opts) {
651  if (op.first=="output_t0") {
652  output_t0 = op.second;
653  uses_legacy_options = true;
654  } else if (op.first=="print_stats") {
655  print_stats_ = op.second;
656  } else if (op.first=="nfwd") {
657  nfwd_ = op.second;
658  } else if (op.first=="nadj") {
659  nadj_ = op.second;
660  } else if (op.first=="grid") {
661  grid = op.second;
662  uses_legacy_options = true;
663  } else if (op.first=="augmented_options") {
664  augmented_options_ = op.second;
665  } else if (op.first=="transition") {
666  transition_ = op.second;
667  } else if (op.first=="max_event_iter") {
668  max_event_iter_ = op.second;
669  } else if (op.first=="max_events") {
670  max_events_ = op.second;
671  } else if (op.first=="event_tol") {
672  event_tol_ = op.second;
673  } else if (op.first=="event_acceptable_tol") {
674  event_acceptable_tol_ = op.second;
675  } else if (op.first=="t0") {
676  t0 = op.second;
677  uses_legacy_options = true;
678  } else if (op.first=="tf") {
679  tf = op.second;
680  uses_legacy_options = true;
681  }
682  }
683 
684  // Store a copy of the options, for creating augmented integrators
685  opts_ = opts;
686 
687  // Construct t0_ and tout_ gbased on legacy options
688  if (uses_legacy_options) {
689  static bool first_encounter = true;
690  if (first_encounter) {
691  // Deprecation warning
692  casadi_warning("The options 't0', 'tf', 'grid' and 'output_t0' have been deprecated.\n"
693  "The same functionality is provided by providing additional input arguments to "
694  "the 'integrator' function, in particular:\n"
695  " * Call integrator(..., t0, tf, options) for a single output time, or\n"
696  " * Call integrator(..., t0, grid, options) for multiple grid points.\n"
697  "The legacy 'output_t0' option can be emulated by including or excluding 't0' in 'grid'.\n"
698  "Backwards compatibility is provided in this release only.");
699  first_encounter = false;
700  }
701 
702  // If grid unset, default to [t0, tf]
703  if (grid.empty()) grid = {t0, tf};
704 
705  // Construct t0 and tout from grid and output_t0
706  t0_ = grid.front();
707  tout_ = grid;
708  if (!output_t0) tout_.erase(tout_.begin());
709  }
710 
711  // Consistency checks: Sensitivities
712  casadi_assert(nfwd_ >= 0, "Number of forward sensitivities must be non-negative");
713  casadi_assert(nadj_ >= 0, "Number of adjoint sensitivities must be non-negative");
714 
715  // Consistency check: Valid oracle
716  casadi_assert(oracle_.n_in() == DYN_NUM_IN, "DAE has wrong number of inputs");
717  casadi_assert(oracle_.n_out() == DYN_NUM_OUT, "DAE has wrong number of outputs");
718 
719  // Consistency checks, input sparsities
720  for (casadi_int i = 0; i < DYN_NUM_IN; ++i) {
721  const Sparsity& sp = oracle_.sparsity_in(i);
722  if (i == DYN_T) {
723  casadi_assert(sp.is_empty() || sp.is_scalar(), "DAE time variable must be empty or scalar. "
724  "Got dimension " + str(sp.size()));
725  } else {
726  casadi_assert(sp.is_vector(), "DAE inputs must be vectors. "
727  + dyn_in(i) + " has dimension " + str(sp.size()) + ".");
728  }
729  casadi_assert(sp.is_dense(), "DAE inputs must be dense . "
730  + dyn_in(i) + " is sparse.");
731  }
732 
733  // Consistency checks, output sparsities
734  for (casadi_int i = 0; i < DYN_NUM_OUT; ++i) {
735  const Sparsity& sp = oracle_.sparsity_out(i);
736  casadi_assert(sp.is_vector(), "DAE outputs must be vectors. "
737  + dyn_out(i) + " has dimension " + str(sp.size()));
738  casadi_assert(sp.is_dense(), "DAE outputs must be dense . "
739  + dyn_out(i) + " is sparse.");
740  }
741 
742  // Get dimensions (excluding sensitivity equations), forward problem
749 
750  // Event support not implemented
751  if (ne_ > 0) {
752  casadi_warning("Event support is experimental");
753  }
754 
755  // Consistency checks
756  casadi_assert(nx1_ > 0, "Ill-posed ODE - no state");
757  casadi_assert(nx1_ == oracle_.numel_out(DYN_ODE), "Dimension mismatch for 'ode'");
758  casadi_assert(nz1_ == oracle_.numel_out(DYN_ALG), "Dimension mismatch for 'alg'");
759 
760  // Backward problem, if any
761  if (nadj_ > 0) {
762  // Generate backward DAE
764  // Consistency checks
765  casadi_assert(rdae_.n_in() == BDYN_NUM_IN, "Backward DAE has wrong number of inputs");
766  casadi_assert(rdae_.n_out() == BDYN_NUM_OUT, "Backward DAE has wrong number of outputs");
767  casadi_assert(rdae_.numel_in(BDYN_X) == nx1_, "Dimension mismatch");
768  casadi_assert(rdae_.numel_in(BDYN_Z) == nz1_, "Dimension mismatch");
769  casadi_assert(rdae_.numel_in(BDYN_P) == np1_, "Dimension mismatch");
770  casadi_assert(rdae_.numel_in(BDYN_U) == nu1_, "Dimension mismatch");
771  casadi_assert(rdae_.numel_in(BDYN_ADJ_ODE) == nx1_ * nadj_, "Inconsistent dimensions");
772  casadi_assert(rdae_.numel_in(BDYN_ADJ_ALG) == nz1_ * nadj_, "Inconsistent dimensions");
773  casadi_assert(rdae_.numel_in(BDYN_ADJ_QUAD) == nq1_ * nadj_, "Inconsistent dimensions");
774  casadi_assert(rdae_.numel_out(BDYN_ADJ_P) == np1_ * nadj_, "Inconsistent dimensions");
775  casadi_assert(rdae_.numel_out(BDYN_ADJ_U) == nu1_ * nadj_, "Inconsistent dimensions");
776 
777  // Dimensions (excluding sensitivity equations), backward problem
778  nrx1_ = nx1_;
779  nrz1_ = nz1_;
780  nrp1_ = nq1_;
781  nrq1_ = np1_;
782  nuq1_ = nu1_;
783  } else {
784  // No backward problem
785  nrx1_ = nrz1_ = nrp1_ = nrq1_ = nuq1_ = 0;
786  }
787 
788  // Get dimensions (including sensitivity equations)
789  nx_ = nx1_ * (1 + nfwd_);
790  nz_ = nz1_ * (1 + nfwd_);
791  nq_ = nq1_ * (1 + nfwd_);
792  np_ = np1_ * (1 + nfwd_);
793  nu_ = nu1_ * (1 + nfwd_);
794  nrx_ = nrx1_ * nadj_ * (1 + nfwd_);
795  nrz_ = nrz1_ * nadj_ * (1 + nfwd_);
796  nrp_ = nrp1_ * nadj_ * (1 + nfwd_);
797  nrq_ = nrq1_ * nadj_ * (1 + nfwd_);
798  nuq_ = nuq1_ * nadj_ * (1 + nfwd_);
799 
800  // Length of tmp1, tmp2 vectors
801  ntmp_ = nx_ + nz_;
802  ntmp_ = std::max(ntmp_, nrx_ + nrz_);
803  ntmp_ = std::max(ntmp_, ne_);
804 
805  // Call the base class method
806  OracleFunction::init(opts);
807 
808  // Instantiate functions, forward and backward problem
809  set_function(oracle_, "dae");
810  if (nadj_ > 0) set_function(rdae_, "rdae");
811 
812  // Event transition function, if any
813  if (!transition_.is_null()) {
814  set_function(transition_, "transition");
815  if (nfwd_ > 0) create_forward("transition", nfwd_);
816  }
817 
818  // Event detection requires linearization of the zero-crossing function in the time direction
819  if (ne_ > 0) {
820  create_forward("dae", 1);
821  if (nfwd_ > 0) create_forward("dae", nfwd_);
822  }
823 
824  // Create problem functions, forward problem
825  create_function("daeF", dyn_in(), dae_out());
826  if (nq_ > 0) create_function("quadF", dyn_in(), quad_out());
827  if (nfwd_ > 0) {
828  // one direction to conserve memory, symbolic processing time
829  create_forward("daeF", 1);
830  if (nq_ > 0) create_forward("quadF", 1);
831  }
832 
833  // Create problem functions, backward problem
834  if (nadj_ > 0) {
835  create_function(rdae_, "daeB", bdyn_in(), bdae_out());
836  if (nrq_ > 0 || nuq_ > 0) create_function(rdae_, "quadB", bdyn_in(), bquad_out());
837  if (nfwd_ > 0) {
838  // one direction to conserve memory, symbolic processing time
839  create_forward("daeB", 1);
840  if (nrq_ > 0 || nuq_ > 0) create_forward("quadB", 1);
841  }
842  }
843 
844  // Nominal values for states
847 
848  // Get the sparsities of the forward and reverse DAE
850  casadi_assert(!sp_jac_dae_.is_singular(),
851  "Jacobian of the forward problem is structurally rank-deficient. "
852  "sprank(J)=" + str(sprank(sp_jac_dae_)) + "<" + str(nx_+nz_));
853  if (nadj_ > 0) {
855  casadi_assert(!sp_jac_rdae_.is_singular(),
856  "Jacobian of the backward problem is structurally rank-deficient. "
857  "sprank(J)=" + str(sprank(sp_jac_rdae_)) + "<" + str(nrx_+nrz_));
858  }
859 
860  alloc_w(nq_, true); // q
861  alloc_w(nx_, true); // x
862  alloc_w(nz_, true); // z
863  alloc_w(np_, true); // p
864  alloc_w(nu_, true); // u
865  alloc_w(ne_, true); // e
866  alloc_w(ne_, true); // edot
867  alloc_w(ne_, true); // old_e
868  alloc_w(nx_, true); // xdot
869  alloc_w(nz_, true); // zdot
870  alloc_iw(ne_, true); // event_triggered
871 
872  alloc_w(nrx_ + nrz_, true); // adj_x, adj_z
873  alloc_w(nrq_, true); // adj_p
874  alloc_w(nrp_, true); // adj_q
875 
876  alloc_w(2 * ntmp_, true); // tmp1, tmp2
877 
878  alloc_w(nx_ + nz_); // Sparsity::sp_solve
879  alloc_w(nrx_ + nrz_); // Sparsity::sp_solve
880 }
881 
882 void Integrator::set_work(void* mem, const double**& arg, double**& res,
883  casadi_int*& iw, double*& w) const {
884  auto m = static_cast<IntegratorMemory*>(mem);
885 
886  // Set work in base classes
887  OracleFunction::set_work(mem, arg, res, iw, w);
888 
889  // Work vectors
890  m->q = w; w += nq_; // Note: q, x, z consecutive in memory
891  m->x = w; w += nx_;
892  m->z = w; w += nz_;
893  m->p = w; w += np_;
894  m->u = w; w += nu_;
895  m->e = w; w += ne_;
896  m->edot = w; w += ne_;
897  m->old_e = w; w += ne_;
898  m->xdot = w; w += nx_;
899  m->zdot = w; w += nz_;
900  m->event_triggered = iw; iw += ne_;
901 
902  m->adj_x = w; w += nrx_; // doubles as adj_xz
903  m->adj_z = w; w += nrz_;
904  m->adj_p = w; w += nrq_;
905  m->adj_q = w; w += nrp_;
906 
907  m->tmp1 = w; w += ntmp_;
908  m->tmp2 = w; w += ntmp_;
909 }
910 
911 
912 int Integrator::init_mem(void* mem) const {
913  if (OracleFunction::init_mem(mem)) return 1;
914 
915  //auto m = static_cast<IntegratorMemory*>(mem);
916  return 0;
917 }
918 
920  // If no sensitivities, augmented oracle is the oracle itself
921  if (nfwd_ == 0) return oracle_;
922  // Name of augmented DAE
923  std::string aug_name = "fsens" + str(nfwd_) + "_" + oracle_.name();
924  // Use function in cache, if available
925  Function ret;
926  // if (incache(aug_name, ret)) return ret; // caching disabled while implementing #3047
927  // Create new augmented oracle
928  try {
929  if (oracle_.is_a("SXFunction")) {
930  ret = get_forward_dae<SX>(aug_name);
931  } else {
932  ret = get_forward_dae<MX>(aug_name);
933  }
934  } catch (std::exception& e) {
935  casadi_error("Failed to generate augmented DAE for " + name_ + ":\n" + e.what());
936  }
937  // Save to Function cache and return
938  // tocache(ret); // caching disabled while implementing #3047
939  return ret;
940 }
941 
942 template<typename MatType>
943 Function Integrator::get_forward_dae(const std::string& name) const {
944  if (verbose_) casadi_message(name_ + "::get_forward_dae");
945 
946  // Events not implemented
947  casadi_assert(ne_ == 0, "Event support not implemented for Integrator::augmented_dae");
948 
949  // Get input and output expressions
950  std::vector<MatType> arg = MatType::get_input(oracle_);
951  std::vector<MatType> res = oracle_(arg);
952 
953  // Symbolic expression for augmented DAE
954  std::vector<std::vector<MatType>> aug_in(DYN_NUM_IN);
955  for (casadi_int i = 0; i < DYN_NUM_IN; ++i) aug_in[i].push_back(arg.at(i));
956  std::vector<std::vector<MatType>> aug_out(DYN_NUM_OUT);
957  for (casadi_int i = 0; i < DYN_NUM_OUT; ++i) aug_out[i].push_back(res.at(i));
958 
959  // Zero of time dimension
960  MatType zero_t = MatType::zeros(oracle_.sparsity_in(DYN_T));
961 
962  // Augment aug_in with forward sensitivity seeds
963  std::vector<std::vector<MatType>> seed(nfwd_, std::vector<MatType>(DYN_NUM_IN));
964  for (casadi_int d = 0; d < nfwd_; ++d) {
965  // Create expressions for augmented states
966  std::string pref = "aug" + str(d) + "_";
967  for (casadi_int i = 0; i < DYN_NUM_IN; ++i) {
968  if (i == DYN_T) {
969  seed[d][i] = zero_t;
970  } else {
971  seed[d][i] = MatType::sym(pref + dyn_in(i), oracle_.sparsity_in(i));
972  }
973  }
974  // Save to augmented function inputs
975  for (casadi_int i = 0; i < DYN_NUM_IN; ++i) {
976  if (i != DYN_T) aug_in[i].push_back(seed[d][i]);
977  }
978  }
979 
980  // Calculate directional derivatives
981  std::vector<std::vector<MatType>> sens;
982  bool always_inline = oracle_.is_a("SXFunction") || oracle_.is_a("MXFunction");
983  oracle_->call_forward(arg, res, seed, sens, always_inline, false);
984 
985  // Augment aug_out with forward sensitivity equations
986  casadi_assert_dev(sens.size() == nfwd_);
987  for (casadi_int d = 0; d < nfwd_; ++d) {
988  casadi_assert_dev(sens[d].size() == DYN_NUM_OUT);
989  for (casadi_int i = 0; i < DYN_NUM_OUT; ++i) {
990  aug_out[i].push_back(project(sens[d][i], oracle_.sparsity_out(i)));
991  }
992  }
993 
994  // Concatenate arrays
995  for (casadi_int i = 0; i < DYN_NUM_IN; ++i) arg.at(i) = vertcat(aug_in[i]);
996  for (casadi_int i = 0; i < DYN_NUM_OUT; ++i) res.at(i) = vertcat(aug_out[i]);
997 
998  // Convert to oracle function and return
999  return Function(name, arg, res, dyn_in(), dyn_out());
1000 }
1001 
1003  const bvec_t* p, const bvec_t* u, bvec_t* ode, bvec_t* alg) const {
1004  // Evaluate nondifferentiated
1005  m->arg[DYN_T] = nullptr; // t
1006  m->arg[DYN_X] = x; // x
1007  m->arg[DYN_Z] = nullptr; // z
1008  m->arg[DYN_P] = p; // p
1009  m->arg[DYN_U] = u; // u
1010  m->res[DAE_ODE] = ode; // ode
1011  m->res[DAE_ALG] = alg; // alg
1012  if (calc_sp_forward("daeF", m->arg, m->res, m->iw, m->w)) return 1;
1013  // Evaluate sensitivities
1014  for (casadi_int i = 0; i < nfwd_; ++i) {
1015  m->arg[DYN_NUM_IN + DAE_ODE] = ode; // out:ode
1016  m->arg[DYN_NUM_IN + DAE_ALG] = alg; // out:alg
1017  m->arg[DYN_NUM_IN + DAE_NUM_OUT + DYN_T] = nullptr; // fwd:t
1018  m->arg[DYN_NUM_IN + DAE_NUM_OUT + DYN_X] = x + (i + 1) * nx1_; // fwd:x
1019  m->arg[DYN_NUM_IN + DAE_NUM_OUT + DYN_Z] = nullptr; // fwd:z
1020  m->arg[DYN_NUM_IN + DAE_NUM_OUT + DYN_P] = p + (i + 1) * np1_; // fwd:p
1021  m->arg[DYN_NUM_IN + DAE_NUM_OUT + DYN_U] = u + (i + 1) * nu1_; // fwd:u
1022  m->res[DAE_ODE] = ode + (i + 1) * nx1_; // fwd:ode
1023  m->res[DAE_ALG] = alg + (i + 1) * nz1_; // fwd:alg
1024  if (calc_sp_forward(forward_name("daeF", 1), m->arg, m->res, m->iw, m->w)) return 1;
1025  }
1026  return 0;
1027 }
1028 
1030  const bvec_t* p, const bvec_t* u, bvec_t* quad) const {
1031  // Evaluate nondifferentiated
1032  m->arg[DYN_T] = nullptr; // t
1033  m->arg[DYN_X] = x; // x
1034  m->arg[DYN_Z] = z; // z
1035  m->arg[DYN_P] = p; // p
1036  m->arg[DYN_U] = u; // u
1037  m->res[QUAD_QUAD] = quad; // quad
1038  if (calc_sp_forward("quadF", m->arg, m->res, m->iw, m->w)) return 1;
1039  // Evaluate sensitivities
1040  for (casadi_int i = 0; i < nfwd_; ++i) {
1041  m->arg[DYN_NUM_IN + QUAD_QUAD] = quad; // out:quad
1042  m->arg[DYN_NUM_IN + QUAD_NUM_OUT + DYN_T] = nullptr; // fwd:t
1043  m->arg[DYN_NUM_IN + QUAD_NUM_OUT + DYN_X] = x + (i + 1) * nx1_; // fwd:x
1044  m->arg[DYN_NUM_IN + QUAD_NUM_OUT + DYN_Z] = z + (i + 1) * nz1_; // fwd:z
1045  m->arg[DYN_NUM_IN + QUAD_NUM_OUT + DYN_P] = p + (i + 1) * np1_; // fwd:p
1046  m->arg[DYN_NUM_IN + QUAD_NUM_OUT + DYN_U] = u + (i + 1) * nu1_; // fwd:u
1047  m->res[QUAD_QUAD] = quad + (i + 1) * nq1_; // fwd:quad
1048  if (calc_sp_forward(forward_name("quadF", 1), m->arg, m->res, m->iw, m->w)) return 1;
1049  }
1050  return 0;
1051 }
1052 
1054  const bvec_t* p, const bvec_t* u, const bvec_t* adj_ode, const bvec_t* adj_quad,
1055  bvec_t* adj_x, bvec_t* adj_z) const {
1056  // Evaluate nondifferentiated
1057  m->arg[BDYN_T] = nullptr; // t
1058  m->arg[BDYN_X] = x; // x
1059  m->arg[BDYN_Z] = z; // z
1060  m->arg[BDYN_P] = p; // p
1061  m->arg[BDYN_U] = u; // u
1062  m->arg[BDYN_OUT_ODE] = nullptr; // out_ode
1063  m->arg[BDYN_OUT_ALG] = nullptr; // out_alg
1064  m->arg[BDYN_OUT_QUAD] = nullptr; // out_quad
1065  m->arg[BDYN_OUT_ZERO] = nullptr; // out_zero
1066  m->arg[BDYN_ADJ_ODE] = adj_ode; // adj_ode
1067  m->arg[BDYN_ADJ_ALG] = nullptr; // adj_alg
1068  m->arg[BDYN_ADJ_QUAD] = adj_quad; // adj_quad
1069  m->arg[BDYN_ADJ_ZERO] = nullptr; // adj_zero
1070  m->res[BDAE_ADJ_X] = adj_x; // adj_x
1071  m->res[BDAE_ADJ_Z] = adj_z; // adj_z
1072  if (calc_sp_forward("daeB", m->arg, m->res, m->iw, m->w)) return 1;
1073  // Evaluate sensitivities
1074  for (casadi_int i = 0; i < nfwd_; ++i) {
1075  m->arg[BDYN_NUM_IN + BDAE_ADJ_X] = adj_x; // out:adj_x
1076  m->arg[BDYN_NUM_IN + BDAE_ADJ_Z] = adj_z; // out:adj_z
1077  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_T] = nullptr; // fwd:t
1078  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_X] = x + (i + 1) * nx1_; // fwd:x
1079  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_Z] = z + (i + 1) * nz1_; // fwd:z
1080  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_P] = p + (i + 1) * np1_; // fwd:p
1081  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_U] = u + (i + 1) * nu1_; // fwd:u
1082  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_OUT_ODE] = nullptr; // fwd:out_ode
1083  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_OUT_ALG] = nullptr; // fwd:out_alg
1084  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_OUT_QUAD] = nullptr; // fwd:out_quad
1085  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_OUT_ZERO] = nullptr; // fwd:out_zero
1087  = adj_ode + (i + 1) * nrx1_ * nadj_; // fwd:adj_ode
1088  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_ADJ_ALG] = nullptr; // fwd:adj_alg
1090  = adj_quad + (i + 1) * nrz1_ * nadj_; // fwd:adj_quad
1091  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_ADJ_ZERO] = nullptr; // fwd:adj_zero
1092  m->res[BDAE_ADJ_X] = adj_x + (i + 1) * nrx1_ * nadj_; // fwd:adj_x
1093  m->res[BDAE_ADJ_Z] = adj_z + (i + 1) * nrz1_ * nadj_; // fwd:adj_z
1094  if (calc_sp_forward(forward_name("daeB", 1), m->arg, m->res, m->iw, m->w)) return 1;
1095  }
1096  return 0;
1097 }
1098 
1100  const bvec_t* p, const bvec_t* u,
1101  const bvec_t* adj_ode, const bvec_t* adj_alg, const bvec_t* adj_quad,
1102  bvec_t* adj_p, bvec_t* adj_u) const {
1103  // Evaluate nondifferentiated
1104  m->arg[BDYN_T] = nullptr; // t
1105  m->arg[BDYN_X] = x; // x
1106  m->arg[BDYN_Z] = z; // z
1107  m->arg[BDYN_P] = p; // p
1108  m->arg[BDYN_U] = u; // u
1109  m->arg[BDYN_OUT_ODE] = nullptr; // out_ode
1110  m->arg[BDYN_OUT_ALG] = nullptr; // out_alg
1111  m->arg[BDYN_OUT_QUAD] = nullptr; // out_quad
1112  m->arg[BDYN_OUT_ZERO] = nullptr; // out_zero
1113  m->arg[BDYN_ADJ_ODE] = adj_ode; // adj_ode
1114  m->arg[BDYN_ADJ_ALG] = adj_alg; // adj_alg
1115  m->arg[BDYN_ADJ_QUAD] = adj_quad; // adj_quad
1116  m->arg[BDYN_ADJ_ZERO] = nullptr; // adj_zero
1117  m->res[BQUAD_ADJ_P] = adj_p; // adj_p
1118  m->res[BQUAD_ADJ_U] = adj_u; // adj_u
1119  if (calc_sp_forward("quadB", m->arg, m->res, m->iw, m->w)) return 1;
1120  // Evaluate sensitivities
1121  for (casadi_int i = 0; i < nfwd_; ++i) {
1122  m->arg[BDYN_NUM_IN + BQUAD_ADJ_P] = adj_p; // out:adj_p
1123  m->arg[BDYN_NUM_IN + BQUAD_ADJ_U] = adj_u; // out:adj_u
1124  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_T] = nullptr; // fwd:t
1125  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_X] = x + (i + 1) * nx1_; // fwd:x
1126  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_Z] = z + (i + 1) * nz1_; // fwd:z
1127  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_P] = p + (i + 1) * np1_; // fwd:p
1128  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_U] = u + (i + 1) * nu1_; // fwd:u
1129  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_OUT_ODE] = nullptr; // fwd:out_ode
1130  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_OUT_ALG] = nullptr; // fwd:out_alg
1131  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_OUT_QUAD] = nullptr; // fwd:out_quad
1132  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_OUT_ZERO] = nullptr; // fwd:out_zero
1134  adj_ode + (i + 1) * nrx1_ * nadj_; // fwd:adj_ode
1136  adj_alg + (i + 1) * nrz1_ * nadj_; // fwd:adj_alg
1138  adj_quad + (i + 1) * nrp1_ * nadj_; // fwd:adj_quad
1139  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_ADJ_ZERO] = nullptr; // fwd:adj_zero
1140  m->res[BQUAD_ADJ_P] = adj_p ? adj_p + (i + 1) * nrq1_ * nadj_ : 0; // fwd:adj_p
1141  m->res[BQUAD_ADJ_U] = adj_u ? adj_u + (i + 1) * nuq1_ * nadj_: 0; // fwd:adj_u
1142  if (calc_sp_forward(forward_name("quadB", 1), m->arg, m->res, m->iw, m->w)) return 1;
1143  }
1144  return 0;
1145 }
1146 
1147 int Integrator::sp_forward(const bvec_t** arg, bvec_t** res,
1148  casadi_int* iw, bvec_t* w, void* mem) const {
1149  if (verbose_) casadi_message(name_ + "::sp_forward");
1150 
1151  // Inputs
1152  const bvec_t* x0 = arg[INTEGRATOR_X0];
1153  const bvec_t* p = arg[INTEGRATOR_P];
1154  const bvec_t* u = arg[INTEGRATOR_U];
1155  const bvec_t* adj_xf = arg[INTEGRATOR_ADJ_XF];
1156  const bvec_t* adj_qf = arg[INTEGRATOR_ADJ_QF];
1157  arg += n_in_;
1158 
1159  // Outputs
1160  bvec_t* xf = res[INTEGRATOR_XF];
1161  bvec_t* zf = res[INTEGRATOR_ZF];
1162  bvec_t* qf = res[INTEGRATOR_QF];
1163  bvec_t* adj_x0 = res[INTEGRATOR_ADJ_X0];
1164  bvec_t* adj_p0 = res[INTEGRATOR_ADJ_P];
1165  bvec_t* adj_u = res[INTEGRATOR_ADJ_U];
1166  res += n_out_;
1167 
1168  // Work vectors
1169  bvec_t *x = w; w += nx_;
1170 
1171  bvec_t *adj_x = w; w += nrx_;
1172  bvec_t *adj_z = w; w += nrz_;
1173  bvec_t *adj_p = w; w += nrq_;
1174 
1175  bvec_t *tmp1 = w; w += nx_ + nz_;
1176  bvec_t *tmp2 = w; w += nrx_;
1177 
1178  // Memory struct for function calls below
1179  SpForwardMem m = {arg, res, iw, w};
1180 
1181  // Copy initial guess to x
1182  std::copy_n(x0, nx_, x);
1183 
1184  // Propagate forward
1185  for (casadi_int k = 0; k < nt(); ++k) {
1186  // Propagate through DAE function
1187  if (fdae_sp_forward(&m, x, p, u, tmp1, tmp1 + nx_)) return 1;
1188  for (casadi_int i = 0; i < nx_; ++i) tmp1[i] |= x[i];
1189 
1190  // "Solve" in order to resolve interdependencies (cf. Rootfinder)
1191  std::copy_n(tmp1, nx_ + nx_, w);
1192  std::fill_n(tmp1, nx_ + nz_, 0);
1193  sp_jac_dae_.spsolve(tmp1, w, false);
1194 
1195  // Get xf and zf
1196  if (xf) std::copy_n(tmp1, nx_, xf);
1197  if (zf) std::copy_n(tmp1 + nx_, nz_, zf);
1198 
1199  // Propagate to quadratures
1200  if (nq_ > 0 && qf) {
1201  if (fquad_sp_forward(&m, tmp1, tmp1 + nx_, p, u, qf)) return 1;
1202  }
1203 
1204  // Shift time
1205  std::copy_n(tmp1, nx_, x);
1206  if (xf) xf += nx_;
1207  if (zf) zf += nz_;
1208  if (qf) qf += nq_;
1209  if (u) u += nu_;
1210  }
1211 
1212  if (nrx_ > 0) {
1213  // Clear tmp2, adj_p0
1214  std::fill_n(tmp2, nrx_, 0);
1215  if (adj_p0) std::fill_n(adj_p0, nrq_, 0);
1216 
1217  // Take adj_xf, rp, adj_u past the last grid point
1218  if (adj_xf) adj_xf += nrx_ * nt();
1219  if (adj_qf) adj_qf += nrp_ * nt();
1220  if (adj_u) adj_u += nuq_ * nt();
1221 
1222  // Integrate backward
1223  for (casadi_int k = nt(); k-- > 0; ) {
1224  // Shift time
1225  if (adj_xf) adj_xf -= nrx_;
1226  if (adj_qf) adj_qf -= nrp_;
1227  if (adj_u) adj_u -= nuq_;
1228  if (u) u -= nu_;
1229 
1230  // Add impulse from adj_xf
1231  if (adj_xf) {
1232  for (casadi_int i = 0; i < nrx_; ++i) tmp2[i] |= adj_xf[i];
1233  }
1234 
1235  // Propagate through DAE function
1236  if (bdae_sp_forward(&m, tmp1, tmp1 + nx_, p, u, tmp2, adj_qf, adj_x, adj_z)) return 1;
1237  for (casadi_int i = 0; i < nrx_; ++i) adj_x[i] |= tmp2[i];
1238 
1239  // "Solve" in order to resolve interdependencies (cf. Rootfinder)
1240  std::copy_n(adj_x, nrx_ + nrz_, w);
1241  std::fill_n(adj_x, nrx_ + nrz_, 0);
1242  sp_jac_rdae_.spsolve(adj_x, w, false);
1243 
1244  // Propagate to quadratures
1245  if ((nrq_ > 0 && adj_p0) || (nuq_ > 0 && adj_u)) {
1246  if (bquad_sp_forward(&m, tmp1, tmp1 + nx_, p, u, adj_x, adj_z, adj_qf, adj_p, adj_u))
1247  return 1;
1248  // Sum contributions to adj_p0
1249  if (adj_p0) {
1250  for (casadi_int i = 0; i < nrq_; ++i) adj_p0[i] |= adj_p[i];
1251  }
1252  }
1253 
1254  // Update tmp2
1255  std::copy_n(adj_x, nx_, tmp2);
1256  }
1257 
1258  // Get adj_x0 at initial time
1259  if (adj_x0) std::copy_n(adj_x, nrx_, adj_x0);
1260  }
1261  return 0;
1262 }
1263 
1265  bvec_t* p, bvec_t* u, bvec_t* ode, bvec_t* alg) const {
1266  // Nondifferentiated inputs
1267  m->arg[DYN_T] = nullptr; // t
1268  m->arg[DYN_X] = x; // x
1269  m->arg[DYN_Z] = nullptr; // z
1270  m->arg[DYN_P] = p; // p
1271  m->arg[DYN_U] = u; // u
1272  // Propagate through sensitivities
1273  for (casadi_int i = 0; i < nfwd_; ++i) {
1274  m->res[DAE_ODE] = ode + (i + 1) * nx1_; // fwd:ode
1275  m->res[DAE_ALG] = alg + (i + 1) * nz1_; // fwd:alg
1276  m->arg[DYN_NUM_IN + DAE_ODE] = ode; // out:ode
1277  m->arg[DYN_NUM_IN + DAE_ALG] = alg; // out:alg
1278  m->arg[DYN_NUM_IN + DAE_NUM_OUT + DYN_T] = nullptr; // fwd:t
1279  m->arg[DYN_NUM_IN + DAE_NUM_OUT + DYN_X] = x + (i + 1) * nx1_; // fwd:x
1280  m->arg[DYN_NUM_IN + DAE_NUM_OUT + DYN_Z] = nullptr; // fwd:z
1281  m->arg[DYN_NUM_IN + DAE_NUM_OUT + DYN_P] = p + (i + 1) * np1_; // fwd:p
1282  m->arg[DYN_NUM_IN + DAE_NUM_OUT + DYN_U] = u + (i + 1) * nu1_; // fwd:u
1283  if (calc_sp_reverse(forward_name("daeF", 1), m->arg, m->res, m->iw, m->w)) return 1;
1284  }
1285  // Propagate through nondifferentiated
1286  m->res[DAE_ODE] = ode; // ode
1287  m->res[DAE_ALG] = alg; // alg
1288  if (calc_sp_reverse("daeF", m->arg, m->res, m->iw, m->w)) return 1;
1289  return 0;
1290 }
1291 
1293  bvec_t* p, bvec_t* u, bvec_t* quad) const {
1294  // Nondifferentiated inputs
1295  m->arg[DYN_T] = nullptr; // t
1296  m->arg[DYN_X] = x; // x
1297  m->arg[DYN_Z] = z; // z
1298  m->arg[DYN_P] = p; // p
1299  m->arg[DYN_U] = u; // u
1300  // Propagate through sensitivities
1301  for (casadi_int i = 0; i < nfwd_; ++i) {
1302  m->res[QUAD_QUAD] = quad + (i + 1) * nq1_; // fwd:quad
1303  m->arg[DYN_NUM_IN + QUAD_QUAD] = quad; // out:quad
1304  m->arg[DYN_NUM_IN + QUAD_NUM_OUT + DYN_T] = nullptr; // fwd:t
1305  m->arg[DYN_NUM_IN + QUAD_NUM_OUT + DYN_X] = x + (i + 1) * nx1_; // fwd:x
1306  m->arg[DYN_NUM_IN + QUAD_NUM_OUT + DYN_Z] = z + (i + 1) * nz1_; // fwd:z
1307  m->arg[DYN_NUM_IN + QUAD_NUM_OUT + DYN_P] = p + (i + 1) * np1_; // fwd:p
1308  m->arg[DYN_NUM_IN + QUAD_NUM_OUT + DYN_U] = u + (i + 1) * nu1_; // fwd:u
1309  if (calc_sp_reverse(forward_name("quadF", 1), m->arg, m->res, m->iw, m->w)) return 1;
1310  }
1311  // Propagate through nondifferentiated
1312  m->res[QUAD_QUAD] = quad; // quad
1313  if (calc_sp_reverse("quadF", m->arg, m->res, m->iw, m->w)) return 1;
1314  return 0;
1315 }
1316 
1318  bvec_t* p, bvec_t* u, bvec_t* adj_ode, bvec_t* adj_quad,
1319  bvec_t* adj_x, bvec_t* adj_z) const {
1320  // Nondifferentiated inputs
1321  m->arg[BDYN_T] = nullptr; // t
1322  m->arg[BDYN_X] = x; // x
1323  m->arg[BDYN_Z] = z; // z
1324  m->arg[BDYN_P] = p; // p
1325  m->arg[BDYN_U] = u; // u
1326  m->arg[BDYN_OUT_ODE] = nullptr; // out_ode
1327  m->arg[BDYN_OUT_ALG] = nullptr; // out_alg
1328  m->arg[BDYN_OUT_QUAD] = nullptr; // out_quad
1329  m->arg[BDYN_OUT_ZERO] = nullptr; // out_zero
1330  m->arg[BDYN_ADJ_ODE] = adj_ode; // adj_ode
1331  m->arg[BDYN_ADJ_ALG] = nullptr; // adj_alg
1332  m->arg[BDYN_ADJ_QUAD] = adj_quad; // adj_quad
1333  m->arg[BDYN_ADJ_ZERO] = nullptr; // adj_zero
1334  // Propagate through sensitivities
1335  for (casadi_int i = 0; i < nfwd_; ++i) {
1336  m->res[BDAE_ADJ_X] = adj_x + (i + 1) * nrx1_ * nadj_; // fwd:adj_x
1337  m->res[BDAE_ADJ_Z] = adj_z + (i + 1) * nrz1_ * nadj_; // fwd:adj_z
1338  m->arg[BDYN_NUM_IN + BDAE_ADJ_X] = adj_x; // out:adj_x
1339  m->arg[BDYN_NUM_IN + BDAE_ADJ_Z] = adj_z; // out:adj_z
1340  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_T] = nullptr; // fwd:t
1341  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_X] = x + (i + 1) * nx1_; // fwd:x
1342  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_Z] = z + (i + 1) * nz1_; // fwd:z
1343  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_P] = p + (i + 1) * np1_; // fwd:p
1344  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_U] = u + (i + 1) * nu1_; // fwd:u
1345  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_OUT_ODE] = nullptr; // fwd:out_ode
1346  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_OUT_ALG] = nullptr; // fwd:out_alg
1347  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_OUT_QUAD] = nullptr; // fwd:out_quad
1348  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_OUT_ZERO] = nullptr; // fwd:out_zero
1350  adj_ode + (i + 1) * nrx1_ * nadj_; // fwd:adj_ode
1351  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_ADJ_ALG] = nullptr; // fwd:adj_alg
1353  adj_quad + (i + 1) * nrz1_ * nadj_; // fwd:adj_quad
1354  m->arg[BDYN_NUM_IN + BDAE_NUM_OUT + BDYN_ADJ_ZERO] = nullptr; // fwd:adj_zero
1355  if (calc_sp_reverse(forward_name("daeB", 1), m->arg, m->res, m->iw, m->w)) return 1;
1356  }
1357  // Propagate through nondifferentiated
1358  m->res[BDAE_ADJ_X] = adj_x; // adj_x
1359  m->res[BDAE_ADJ_Z] = adj_z; // adj_z
1360  if (calc_sp_reverse("daeB", m->arg, m->res, m->iw, m->w)) return 1;
1361  return 0;
1362 }
1363 
1365  bvec_t* p, bvec_t* u, bvec_t* adj_ode, bvec_t* adj_alg, bvec_t* adj_quad,
1366  bvec_t* adj_p, bvec_t* adj_u) const {
1367  // Nondifferentiated inputs
1368  m->arg[BDYN_T] = nullptr; // t
1369  m->arg[BDYN_X] = x; // x
1370  m->arg[BDYN_Z] = z; // z
1371  m->arg[BDYN_P] = p; // p
1372  m->arg[BDYN_U] = u; // u
1373  m->arg[BDYN_OUT_ODE] = adj_ode; // out_ode
1374  m->arg[BDYN_OUT_ALG] = adj_alg; // out_alg
1375  m->arg[BDYN_OUT_QUAD] = adj_quad; // out_quad
1376  m->arg[BDYN_OUT_ZERO] = nullptr; // out_zero
1377  m->arg[BDYN_ADJ_ODE] = adj_ode; // adj_ode
1378  m->arg[BDYN_ADJ_ALG] = adj_alg; // adj_alg
1379  m->arg[BDYN_ADJ_QUAD] = adj_quad; // adj_quad
1380  m->arg[BDYN_ADJ_ZERO] = nullptr; // adj_zero
1381  // Propagate through sensitivities
1382  for (casadi_int i = 0; i < nfwd_; ++i) {
1383  m->res[BQUAD_ADJ_P] = adj_p ? adj_p + (i + 1) * nrq1_ * nadj_ : 0; // fwd:adj_p
1384  m->res[BQUAD_ADJ_U] = adj_u ? adj_u + (i + 1) * nuq1_ * nadj_ : 0; // fwd:adj_u
1385  m->arg[BDYN_NUM_IN + BQUAD_ADJ_P] = adj_p; // out:adj_p
1386  m->arg[BDYN_NUM_IN + BQUAD_ADJ_U] = adj_u; // out:adj_u
1387  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_T] = nullptr; // fwd:t
1388  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_X] = x + (i + 1) * nx1_; // fwd:x
1389  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_Z] = z + (i + 1) * nz1_; // fwd:z
1390  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_P] = p + (i + 1) * np1_; // fwd:p
1391  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_U] = u + (i + 1) * nu1_; // fwd:u
1392  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_OUT_ODE] = nullptr; // fwd:out_ode
1393  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_OUT_ALG] = nullptr; // fwd:out_alg
1394  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_OUT_QUAD] = nullptr; // fwd:out_quad
1395  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_OUT_ZERO] = nullptr; // fwd:out_zero
1397  adj_ode + (i + 1) * nrx1_ * nadj_; // fwd:adj_ode
1399  adj_alg + (i + 1) * nrz1_ * nadj_; // fwd:adj_alg
1401  adj_quad + (i + 1) * nrp1_ * nadj_; // fwd:adj_quad
1402  m->arg[BDYN_NUM_IN + BQUAD_NUM_OUT + BDYN_ADJ_ZERO] = nullptr; // fwd:adj_zero
1403  if (calc_sp_reverse(forward_name("quadB", 1), m->arg, m->res, m->iw, m->w)) return 1;
1404  }
1405  // Propagate through nondifferentiated
1406  m->res[BQUAD_ADJ_P] = adj_p; // adj_p
1407  m->res[BQUAD_ADJ_U] = adj_u; // adj_u
1408  if (calc_sp_reverse("quadB", m->arg, m->res, m->iw, m->w)) return 1;
1409  return 0;
1410 }
1411 
1413  casadi_int* iw, bvec_t* w, void* mem) const {
1414  if (verbose_) casadi_message(name_ + "::sp_reverse");
1415 
1416  // Inputs
1417  bvec_t* x0 = arg[INTEGRATOR_X0];
1418  bvec_t* p = arg[INTEGRATOR_P];
1419  bvec_t* u = arg[INTEGRATOR_U];
1420  bvec_t* adj_xf = arg[INTEGRATOR_ADJ_XF];
1421  bvec_t* adj_qf = arg[INTEGRATOR_ADJ_QF];
1422  arg += n_in_;
1423 
1424  // Outputs
1425  bvec_t* xf = res[INTEGRATOR_XF];
1426  bvec_t* zf = res[INTEGRATOR_ZF];
1427  bvec_t* qf = res[INTEGRATOR_QF];
1428  bvec_t* adj_x0 = res[INTEGRATOR_ADJ_X0];
1429  bvec_t* adj_p0 = res[INTEGRATOR_ADJ_P];
1430  bvec_t* adj_u = res[INTEGRATOR_ADJ_U];
1431  res += n_out_;
1432 
1433  // Work vectors
1434  bvec_t *x = w; w += nx_;
1435 
1436  bvec_t *adj_x = w; w += nrx_;
1437  bvec_t *adj_z = w; w += nrz_;
1438  bvec_t *adj_p = w; w += nrq_;
1439 
1440  bvec_t *tmp1 = w; w += nx_ + nz_;
1441  bvec_t *tmp2 = w; w += nrx_;
1442 
1443  // Memory struct for function calls below
1444  SpReverseMem m = {arg, res, iw, w};
1445 
1446  // Clear state vector
1447  std::fill_n(tmp1, nx_ + nz_, 0);
1448 
1449  if (nrx_ > 0) {
1450  // Propagate from adj_x0 initial time
1451  if (adj_x0) {
1452  std::copy_n(adj_x0, nrx_, adj_x);
1453  std::fill_n(adj_x0, nrx_, 0);
1454  } else {
1455  std::fill_n(adj_x, nrx_, 0);
1456  }
1457  // Reset adj_z
1458  std::fill_n(adj_z, nrz_, 0);
1459 
1460  // Save adj_p0: See note below
1461  if (adj_p0) std::copy_n(adj_p0, nrq_, adj_p);
1462 
1463  // Step backwards through backward problem
1464  for (casadi_int k = 0; k < nt(); ++k) {
1465  // Restore adj_p0: See note below
1466  if (adj_p0) std::copy_n(adj_p, nrq_, adj_p0);
1467 
1468  // Add impulse from adj_xf
1469  if (adj_xf) {
1470  for (casadi_int i = 0; i < nrx_; ++i) adj_x[i] |= adj_xf[i];
1471  std::fill_n(adj_xf, nrx_, 0);
1472  }
1473 
1474  // Get dependencies from backward quadratures
1475  if ((nrq_ > 0 && adj_p0) || (nuq_ > 0 && adj_u)) {
1476  if (bquad_sp_reverse(&m, tmp1, tmp1 + nx_, p, u, adj_x, adj_z, adj_qf, adj_p0, adj_u))
1477  return 1;
1478  }
1479 
1480  // Propagate interdependencies
1481  std::fill_n(w, nrx_ + nrz_, 0);
1482  sp_jac_rdae_.spsolve(w, adj_x, true);
1483  std::copy_n(w, nrx_ + nrz_, adj_x);
1484 
1485  // Direct dependency tmp2 -> adj_x
1486  std::copy_n(adj_x, nrx_, tmp2);
1487 
1488  // Indirect dependency via g
1489  if (bdae_sp_reverse(&m, tmp1, tmp1 + nx_, p, u, tmp2, adj_qf, adj_x, adj_z)) return 1;
1490 
1491  // Update adj_x, adj_z
1492  std::copy_n(tmp2, nrx_, adj_x);
1493  std::fill_n(adj_z, nrz_, 0);
1494 
1495  // Shift time
1496  if (adj_xf) adj_xf += nrx_;
1497  if (adj_qf) adj_qf += nrp_;
1498  if (adj_u) adj_u += nuq_;
1499  if (u) u += nu_;
1500  }
1501  } else {
1502  // Take u past the last grid point
1503  if (u) u += nu_ * nt();
1504  }
1505 
1506  // Take xf, zf, qf past the last grid point
1507  if (xf) xf += nx_ * nt();
1508  if (zf) zf += nz_ * nt();
1509  if (qf) qf += nq_ * nt();
1510 
1511  // Step backwards through forward problem
1512  for (casadi_int k = nt(); k-- > 0; ) {
1513  // Shift time
1514  if (xf) xf -= nx_;
1515  if (zf) zf -= nz_;
1516  if (qf) qf -= nq_;
1517  if (u) u -= nu_;
1518 
1519  // Add impulse from outputs
1520  if (xf) {
1521  for (casadi_int i = 0; i < nx_; ++i) tmp1[i] |= xf[i];
1522  std::fill_n(xf, nx_, 0);
1523  }
1524  if (zf) {
1525  for (casadi_int i = 0; i < nz_; ++i) tmp1[nx_ + i] |= zf[i];
1526  std::fill_n(zf, nz_, 0);
1527  }
1528 
1529  // Get dependencies from forward quadratures, if any
1530  if (nq_ > 0 && qf) {
1531  if (fquad_sp_reverse(&m, tmp1, tmp1 + nx_, p, u, qf)) return 1;
1532  }
1533 
1534  // Propagate interdependencies
1535  std::fill_n(w, nx_ + nz_, 0);
1536  sp_jac_dae_.spsolve(w, tmp1, true);
1537  std::copy_n(w, nx_ + nz_, tmp1);
1538 
1539  // Direct dependency ode -> x
1540  std::copy_n(tmp1, nx_, x);
1541 
1542  // Indirect dependency through f
1543  if (fdae_sp_reverse(&m, x, p, u, tmp1, tmp1 + nx_)) return 1;
1544 
1545  // Update x, z
1546  std::copy_n(x, nx_, tmp1);
1547  std::fill_n(tmp1 + nx_, nz_, 0);
1548  }
1549 
1550  // Direct dependency x0 -> x
1551  if (x0) {
1552  for (casadi_int i = 0; i < nx_; ++i) x0[i] |= x[i];
1553  }
1554 
1555  return 0;
1556 }
1557 
1558 Function Integrator::get_forward(casadi_int nfwd, const std::string& name,
1559  const std::vector<std::string>& inames,
1560  const std::vector<std::string>& onames,
1561  const Dict& opts) const {
1562  if (verbose_) casadi_message(name_ + "::get_forward");
1563 
1564  // Integrator options
1565  Dict aug_opts = getDerivativeOptions(true);
1566  for (auto&& i : augmented_options_) {
1567  aug_opts[i.first] = i.second;
1568  }
1569 
1570  // Get current DAE, with any existing sensitivity equations augmented
1571  Function this_dae = augmented_dae();
1572 
1573  // Create integrator for augmented DAE
1574  std::string aug_prefix = "fsens" + str(nfwd) + "_";
1575  aug_opts["derivative_of"] = self();
1576  aug_opts["nfwd"] = nfwd;
1577  aug_opts["nadj"] = nadj_;
1578  Function aug_int = integrator(aug_prefix + name_, plugin_name(),
1579  this_dae, t0_, tout_, aug_opts);
1580 
1581  // All inputs of the return function
1582  std::vector<MX> ret_in;
1584 
1585  // Add nondifferentiated inputs to ret_in
1586  for (casadi_int i = 0; i < INTEGRATOR_NUM_IN; ++i) {
1587  ret_in.push_back(MX::sym(integrator_in(i), sparsity_in(i)));
1588  }
1589 
1590  // Add nondifferentiated outputs (unused) to ret_in
1591  for (casadi_int i = 0; i < INTEGRATOR_NUM_OUT; ++i) {
1592  ret_in.push_back(MX::sym("out_" + integrator_out(i), Sparsity(size_out(i))));
1593  }
1594 
1595  // Create symbolic expressions for augmented problem, add forward seeds to ret_in
1596  std::vector<std::vector<MX>> aug_in(INTEGRATOR_NUM_IN);
1597  std::vector<MX> v(nfwd);
1598  for (casadi_int i = 0; i < INTEGRATOR_NUM_IN; ++i) {
1599  for (casadi_int d = 0; d < nfwd; ++d) {
1600  v[d] = MX::sym("fwd" + str(d) + "_" + integrator_in(i), sparsity_in(i));
1601  aug_in[i].push_back(v[d]);
1602  }
1603  ret_in.push_back(horzcat(v));
1604  }
1605 
1606  // Call the augmented integrator
1607  std::vector<MX> integrator_in(INTEGRATOR_NUM_IN);
1608  for (casadi_int i = 0; i < INTEGRATOR_NUM_IN; ++i) {
1609  if (size1_in(i) > 0 && grid_in(i) && nt() > 1) {
1610  // Split nondifferentiated input by grid point
1611  std::vector<MX> ret_in_split = horzsplit_n(ret_in[i], nt());
1612  // Split augmented input by grid point
1613  std::vector<std::vector<MX>> aug_in_split(nfwd);
1614  for (casadi_int d = 0; d < nfwd; ++d) {
1615  aug_in_split[d] = horzsplit_n(aug_in[i][d], nt());
1616  }
1617  // Reorder columns
1618  v.clear();
1619  for (casadi_int k = 0; k < nt(); ++k) {
1620  v.push_back(ret_in_split.at(k));
1621  for (casadi_int d = 0; d < nfwd; ++d) {
1622  v.push_back(aug_in_split[d].at(k));
1623  }
1624  }
1625  } else {
1626  // No reordering necessary
1627  v = aug_in[i];
1628  v.insert(v.begin(), ret_in[i]);
1629  }
1630  // Flatten all elements
1631  for (MX& e : v) e = vec(e);
1632  integrator_in[i] = horzcat(v);
1633  }
1634  std::vector<MX> integrator_out = aug_int(integrator_in);
1635 
1636  // Collect forward sensitivites
1637  std::vector<MX> ret_out;
1638  ret_out.reserve(INTEGRATOR_NUM_OUT);
1639  for (casadi_int i = 0; i < INTEGRATOR_NUM_OUT; ++i) {
1640  // Split return by grid points and sensitivities
1641  casadi_int n_grid = grid_out(i) ? nt() : 1;
1642  std::vector<casadi_int> offset = {0};
1643  for (casadi_int k = 0; k < n_grid; ++k) {
1644  for (casadi_int d = 0; d <= nfwd; ++d) {
1645  offset.push_back(offset.back() + size2_out(i) / n_grid);
1646  }
1647  }
1648  std::vector<MX> integrator_out_split = horzsplit(
1649  reshape(integrator_out[i], size1_out(i), offset.back()), offset);
1650  // Collect sensitivity blocks in the right order
1651  std::vector<MX> ret_out_split;
1652  ret_out_split.reserve(n_grid * nfwd);
1653  for (casadi_int d = 0; d < nfwd; ++d) {
1654  for (casadi_int k = 0; k < n_grid; ++k) {
1655  ret_out_split.push_back(integrator_out_split.at((nfwd + 1) * k + d + 1));
1656  }
1657  }
1658  ret_out.push_back(horzcat(ret_out_split));
1659  }
1660 
1661  Dict options = opts;
1662  options["allow_duplicate_io_names"] = true;
1663 
1664  // Create derivative function and return
1665  return Function(name, ret_in, ret_out, inames, onames, options);
1666 }
1667 
1668 Function Integrator::get_reverse(casadi_int nadj, const std::string& name,
1669  const std::vector<std::string>& inames,
1670  const std::vector<std::string>& onames,
1671  const Dict& opts) const {
1672  if (verbose_) casadi_message(name_ + "::get_reverse");
1673 
1674  // Events not implemented
1675  casadi_assert(ne_ == 0, "Event support not implemented for Integrator::get_reverse");
1676 
1677  // Integrator options
1678  Dict aug_opts = getDerivativeOptions(false);
1679  for (auto&& i : augmented_options_) {
1680  aug_opts[i.first] = i.second;
1681  }
1682 
1683  // Get the current oracle, augmented with any existing forward sensitivity equations
1684  Function this_dae = augmented_dae();
1685 
1686  // Create integrator for augmented DAE
1687  std::string aug_prefix = "asens" + str(nadj) + "_";
1688  aug_opts["derivative_of"] = self();
1689  if (nrx_ == 0) {
1690  // Add backward problem
1691  aug_opts["nadj"] = nadj;
1692  aug_opts["nfwd"] = 0;
1693  } else {
1694  // Reformulate as forward-over-reverse
1695  aug_opts["nfwd"] = nadj;
1696  aug_opts["nadj"] = nadj_;
1697  }
1698  Function aug_int = integrator(aug_prefix + name_, plugin_name(),
1699  this_dae, t0_, tout_, aug_opts);
1700 
1701  // All inputs of the return function
1702  std::vector<MX> ret_in;
1704 
1705  // Add nondifferentiated inputs to ret_in
1706  for (casadi_int i = 0; i < INTEGRATOR_NUM_IN; ++i) {
1707  ret_in.push_back(MX::sym(integrator_in(i), sparsity_in(i)));
1708  }
1709 
1710  // Add nondifferentiated outputs (unused) to ret_in
1711  for (casadi_int i = 0; i < INTEGRATOR_NUM_OUT; ++i) {
1712  ret_in.push_back(MX::sym("out_" + integrator_out(i), Sparsity(size_out(i))));
1713  }
1714 
1715  // Create symbolic expressions for augmented problem, add adjoint seeds to ret_in
1716  std::vector<std::vector<MX>> aug_in(INTEGRATOR_NUM_OUT);
1717  std::vector<MX> v(nadj);
1718  for (casadi_int i = 0; i < INTEGRATOR_NUM_OUT; ++i) {
1719  for (casadi_int d=0; d<nadj; ++d) {
1720  v[d] = MX::sym("adj" + str(d) + "_" + integrator_out(i), sparsity_out(i));
1721  aug_in[i].push_back(v[d]);
1722  }
1723  ret_in.push_back(horzcat(v));
1724  }
1725 
1726  // Call the augmented integrator
1727  std::vector<MX> integrator_in(INTEGRATOR_NUM_IN);
1728  for (casadi_int i = 0; i < INTEGRATOR_NUM_IN; ++i) {
1729  // Output index contributing to adjoint seeds
1730  casadi_int j = adjmap_out(i);
1731  // Number of grid points for this integrator input
1732  casadi_int n_grid = grid_in(i) ? nt() : 1;
1733  // Split input and seeds by grid points, if necessary
1734  std::vector<MX> ret_in_split;
1735  std::vector<std::vector<MX>> aug_in_split(nadj);
1736  if (size1_in(i) > 0 && grid_in(i) && n_grid > 1) {
1737  // Split nondifferentiated input by grid point
1738  ret_in_split = horzsplit_n(ret_in[i], nt());
1739  // Split augmented input by grid point
1740  for (casadi_int d = 0; d < nadj; ++d) {
1741  aug_in_split[d] = horzsplit_n(aug_in[j][d], nt());
1742  }
1743  } else {
1744  // No reordering necessary
1745  ret_in_split = {ret_in[i]};
1746  for (casadi_int d = 0; d < nadj; ++d) aug_in_split[d] = {aug_in[j][d]};
1747  }
1748  // Vectorize all inputs to allow concatenation (unlike forward sensitivities,
1749  // number of rows for sensitivities may be different from original inputs)
1750  for (auto&& e : ret_in_split) e = vec(e);
1751  for (auto&& e1 : aug_in_split) {
1752  for (auto&& e2 : e1) e2 = vec(e2);
1753  }
1754  // Assemble input argument
1755  v.clear();
1756  for (casadi_int k = 0; k < ret_in_split.size(); ++k) {
1757  v.push_back(ret_in_split.at(k));
1758  for (casadi_int d = 0; d < nadj; ++d) {
1759  v.push_back(aug_in_split[d].at(k));
1760  }
1761  }
1762  integrator_in[i] = reshape(vertcat(v), aug_int.size_in(i));
1763  }
1764  std::vector<MX> integrator_out = aug_int(integrator_in);
1765 
1766  // Collect adjoint sensitivites
1767  std::vector<MX> ret_out;
1768  ret_out.reserve(INTEGRATOR_NUM_IN);
1769  for (casadi_int i = 0; i < INTEGRATOR_NUM_IN; ++i) {
1770  casadi_int j = adjmap_out(i);
1771  // Split return by grid points and sensitivities
1772  casadi_int n_grid = grid_out(j) ? nt() : 1;
1773  std::vector<casadi_int> offset = {0};
1774  for (casadi_int k = 0; k < n_grid; ++k) {
1775  offset.push_back(offset.back() + numel_out(j) / n_grid);
1776  for (casadi_int d = 0; d < nadj; ++d) {
1777  offset.push_back(offset.back() + numel_in(i) / n_grid);
1778  }
1779  }
1780  std::vector<MX> integrator_out_split = vertsplit(vec(integrator_out[j]), offset);
1781  // Collect sensitivity blocks in the right order
1782  std::vector<MX> ret_out_split;
1783  ret_out_split.reserve(n_grid * nadj);
1784  for (casadi_int d = 0; d < nadj; ++d) {
1785  for (casadi_int k = 0; k < n_grid; ++k) {
1786  ret_out_split.push_back(reshape(integrator_out_split.at((nadj + 1) * k + d + 1),
1787  size1_in(i), size2_in(i) / n_grid));
1788  }
1789  }
1790  ret_out.push_back(horzcat(ret_out_split));
1791  }
1792 
1793  Dict options = opts;
1794  options["allow_duplicate_io_names"] = true;
1795 
1796  // Create derivative function and return
1797  return Function(name, ret_in, ret_out, inames, onames, options);
1798 }
1799 
1801  // Copy all options
1802  return opts_;
1803 }
1804 
1805 Sparsity Integrator::sp_jac_aug(const Sparsity& J, const Sparsity& J1) const {
1806  // Row 1, column 2 in the augmented Jacobian
1807  Sparsity J12(J.size1(), nfwd_ * J.size2());
1808  // Row 2, column 1 in the augmented Jacobian
1809  Sparsity J21 = vertcat(std::vector<Sparsity>(nfwd_, J1));
1810  // Row 2, column 2 in the augmented Jacobian
1811  Sparsity J22 = diagcat(std::vector<Sparsity>(nfwd_, J));
1812  // Form block matrix
1813  return blockcat(J, J12, J21, J22);
1814 }
1815 
1816 
1818  // Get the functions
1819  const Function& F = get_function("daeF");
1820  // Sparsity pattern for nonaugmented system
1822  Sparsity J_xz = F.jac_sparsity(DAE_ODE, DYN_Z);
1823  Sparsity J_zx = F.jac_sparsity(DAE_ALG, DYN_X);
1824  Sparsity J_zz = F.jac_sparsity(DAE_ALG, DYN_Z);
1825  // Augment with sensitivity equations
1826  if (nfwd_ > 0) {
1827  const Function& fwd_F = get_function(forward_name("daeF", 1));
1828  J_xx = sp_jac_aug(J_xx, fwd_F.jac_sparsity(DAE_ODE, DYN_X));
1829  J_xz = sp_jac_aug(J_xz, fwd_F.jac_sparsity(DAE_ODE, DYN_Z));
1830  J_zx = sp_jac_aug(J_zx, fwd_F.jac_sparsity(DAE_ALG, DYN_X));
1831  J_zz = sp_jac_aug(J_zz, fwd_F.jac_sparsity(DAE_ALG, DYN_Z));
1832  }
1833  // Assemble the block matrix
1834  return blockcat(J_xx, J_xz, J_zx, J_zz);
1835 }
1836 
1838  // Get the functions
1839  const Function& G = get_function("daeB");
1840  // Sparsity pattern for nonaugmented system
1845  // Augment with sensitivity equations
1846  if (nfwd_ > 0) {
1847  const Function& fwd_G = get_function(forward_name("daeB", 1));
1848  J_xx = sp_jac_aug(J_xx, fwd_G.jac_sparsity(BDAE_ADJ_X, BDYN_ADJ_ODE));
1849  J_xz = sp_jac_aug(J_xz, fwd_G.jac_sparsity(BDAE_ADJ_X, BDYN_ADJ_ALG));
1850  J_zx = sp_jac_aug(J_zx, fwd_G.jac_sparsity(BDAE_ADJ_Z, BDYN_ADJ_ODE));
1851  J_zz = sp_jac_aug(J_zz, fwd_G.jac_sparsity(BDAE_ADJ_Z, BDYN_ADJ_ALG));
1852  }
1853  // Assemble the block matrix
1854  return blockcat(J_xx, J_xz, J_zx, J_zz);
1855 }
1856 
1857 std::map<std::string, Integrator::Plugin> Integrator::solvers_;
1858 
1859 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
1860  std::mutex Integrator::mutex_solvers_;
1861 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
1862 
1863 const std::string Integrator::infix_ = "integrator";
1864 
1865 FixedStepIntegrator::FixedStepIntegrator(const std::string& name, const Function& dae,
1866  double t0, const std::vector<double>& tout) : Integrator(name, dae, t0, tout) {
1867 
1868  // Default options
1869  nk_target_ = 20;
1870 }
1871 
1873  clear_mem();
1874 }
1875 
1877 = {{&Integrator::options_},
1878  {{"number_of_finite_elements",
1879  {OT_INT,
1880  "Target number of finite elements. "
1881  "The actual number may be higher to accommodate all output times"}},
1882  {"simplify",
1883  {OT_BOOL,
1884  "Implement as MX Function (codegeneratable/serializable) default: false"}},
1885  {"simplify_options",
1886  {OT_DICT,
1887  "Any options to pass to simplified form Function constructor"}}
1888  }
1889 };
1890 
1891 
1893  Function temp = Function::create(this, opts);
1894 
1895  // Check if we need to simplify
1896  bool simplify = false;
1897  auto it = opts.find("simplify");
1898  if (it != opts.end()) simplify = it->second;
1899 
1900  if (simplify && nrx_==0 && nt()==1) {
1901  // Retrieve explicit simulation step (one finite element)
1902  Function F = get_function("step");
1903 
1904  MX z0 = MX::sym("z0", sparsity_in(INTEGRATOR_Z0));
1905 
1906  // Create symbols
1907  std::vector<MX> F_in = F.mx_in();
1908 
1909  // Prepare return Function inputs
1910  std::vector<MX> intg_in(INTEGRATOR_NUM_IN);
1911  intg_in[INTEGRATOR_X0] = F_in[STEP_X0];
1912  intg_in[INTEGRATOR_Z0] = z0;
1913  intg_in[INTEGRATOR_P] = F_in[STEP_P];
1914  intg_in[INTEGRATOR_U] = F_in[STEP_U];
1915  F_in[STEP_V0] = algebraic_state_init(intg_in[INTEGRATOR_X0], z0);
1916 
1917  // Number of finite elements and time steps
1918  double h = (tout_.back() - t0_)/static_cast<double>(disc_.back());
1919 
1920  // Prepare return Function outputs
1921  std::vector<MX> intg_out(INTEGRATOR_NUM_OUT);
1922  F_in[STEP_T] = t0_;
1923  F_in[STEP_H] = h;
1924 
1925  std::vector<MX> F_out;
1926  // Loop over finite elements
1927  for (casadi_int k=0; k<disc_.back(); ++k) {
1928  F_out = F(F_in);
1929 
1930  F_in[STEP_X0] = F_out[STEP_XF];
1931  F_in[STEP_V0] = F_out[STEP_VF];
1932  intg_out[INTEGRATOR_QF] = k==0? F_out[STEP_QF] : intg_out[INTEGRATOR_QF]+F_out[STEP_QF];
1933  F_in[STEP_T] += h;
1934  }
1935 
1936  intg_out[INTEGRATOR_XF] = F_out[STEP_XF];
1937 
1938  // If-clause needed because rk abuses STEP_VF output for intermediate state output
1939  if (nz_) {
1940  intg_out[INTEGRATOR_ZF] = algebraic_state_output(F_out[STEP_VF]);
1941  }
1942 
1943  // Extract options for Function constructor
1944  Dict sopts;
1945  sopts["print_time"] = print_time_;
1946  auto it = opts.find("simplify_options");
1947  if (it!=opts.end()) update_dict(sopts, it->second);
1948 
1949  return Function(temp.name(), intg_in, intg_out, integrator_in(), integrator_out(), sopts);
1950  } else {
1951  return temp;
1952  }
1953 }
1954 
1955 void FixedStepIntegrator::init(const Dict& opts) {
1956  // Call the base class init
1957  Integrator::init(opts);
1958 
1959  // Read options
1960  for (auto&& op : opts) {
1961  if (op.first=="number_of_finite_elements") {
1962  nk_target_ = op.second;
1963  }
1964  }
1965 
1966  // Consistency check
1967  casadi_assert(nk_target_ > 0, "Number of finite elements must be strictly positive");
1968 
1969  // Target interval length
1970  double h_target = (tout_.back() - t0_) / nk_target_;
1971 
1972  // Number of finite elements for each control interval and in total
1973  disc_.reserve(1 + nt());
1974  disc_.push_back(0);
1975  double t_cur = t0_;
1976  for (double t_next : tout_) {
1977  disc_.push_back(disc_.back() + std::ceil((t_next - t_cur) / h_target));
1978  t_cur = t_next;
1979  }
1980 
1981  // Setup discrete time dynamics
1982  setup_step();
1983 
1984  // Get discrete time dimensions
1985  const Function& F = get_function(has_function("step") ? "step" : "implicit_step");
1986  nv1_ = F.nnz_out(STEP_VF);
1987  nrv1_ = nv1_ * nadj_;
1988  nv_ = nv1_ * (1 + nfwd_);
1989  nrv_ = nrv1_ * (1 + nfwd_);
1990 
1991  // Work vectors, forward problem
1992  alloc_w(nv_, true); // v
1993  alloc_w(nv_, true); // v_prev
1994  alloc_w(nq_, true); // q_prev
1995 
1996  // Work vectors, backward problem
1997  alloc_w(nrv_, true); // rv
1998  alloc_w(nuq_, true); // adj_u
1999  alloc_w(nrq_, true); // adj_p_prev
2000  alloc_w(nuq_, true); // adj_u_prev
2001 
2002  // Allocate tape if backward states are present
2003  if (nrx_ > 0) {
2004  alloc_w((disc_.back() + 1) * nx_, true); // x_tape
2005  alloc_w(disc_.back() * nv_, true); // v_tape
2006  }
2007 }
2008 
2009 void FixedStepIntegrator::set_work(void* mem, const double**& arg, double**& res,
2010  casadi_int*& iw, double*& w) const {
2011  auto m = static_cast<FixedStepMemory*>(mem);
2012 
2013  // Set work in base classes
2014  Integrator::set_work(mem, arg, res, iw, w);
2015 
2016  // Work vectors, forward problem
2017  m->v = w; w += nv_;
2018  m->v_prev = w; w += nv_;
2019  m->q_prev = w; w += nq_;
2020 
2021  // Work vectors, backward problem
2022  m->rv = w; w += nrv_;
2023  m->adj_u = w; w += nuq_;
2024  m->adj_p_prev = w; w += nrq_;
2025  m->adj_u_prev = w; w += nuq_;
2026 
2027  // Allocate tape if backward states are present
2028  if (nrx_ > 0) {
2029  m->x_tape = w; w += (disc_.back() + 1) * nx_;
2030  m->v_tape = w; w += disc_.back() * nv_;
2031  }
2032 }
2033 
2034 int FixedStepIntegrator::init_mem(void* mem) const {
2035  if (Integrator::init_mem(mem)) return 1;
2036  // auto m = static_cast<FixedStepMemory*>(mem);
2037 
2038  return 0;
2039 }
2040 
2042  auto m = static_cast<FixedStepMemory*>(mem);
2043 
2044  // State at previous step
2045  double* x_prev = m->tmp1;
2046 
2047  // Number of finite elements and time steps
2048  casadi_int nj = disc_[m->k + 1] - disc_[m->k];
2049  double h = (m->t_next - m->t) / nj;
2050 
2051  // Take steps
2052  for (casadi_int j = 0; j < nj; ++j) {
2053  // Current time
2054  double t = m->t + j * h;
2055 
2056  // Update the previous step
2057  casadi_copy(m->x, nx_, x_prev);
2058  casadi_copy(m->v, nv_, m->v_prev);
2059  casadi_copy(m->q, nq_, m->q_prev);
2060 
2061  // Take step
2062  stepF(m, t, h, x_prev, m->v_prev, m->x, m->v, m->q);
2063  casadi_axpy(nq_, 1., m->q_prev, m->q);
2064 
2065  // Save state, if needed
2066  if (nrx_ > 0) {
2067  casadi_int tapeind = disc_[m->k] + j;
2068  casadi_copy(m->x, nx_, m->x_tape + nx_ * (tapeind + 1));
2069  casadi_copy(m->v, nv_, m->v_tape + nv_ * tapeind);
2070  }
2071  }
2072 
2073  // Save algebraic variables
2074  casadi_copy(m->v + nv_ - nz_, nz_, m->z);
2075 
2076  return 0;
2077 }
2078 
2080  double* adj_x, double* adj_p, double* adj_u) const {
2081  auto m = static_cast<FixedStepMemory*>(mem);
2082 
2083  // Set controls
2084  casadi_copy(u, nu_, m->u);
2085 
2086  // Number of finite elements and time steps
2087  casadi_int nj = disc_[m->k + 1] - disc_[m->k];
2088  double h = (m->t - m->t_next) / nj;
2089 
2090  // Take steps
2091  for (casadi_int j = nj; j-- > 0; ) {
2092  // Current time
2093  double t = m->t_next + j * h;
2094 
2095  // Update the previous step
2096  casadi_copy(m->adj_x, nrx_, m->tmp1);
2097  casadi_copy(m->adj_p, nrq_, m->adj_p_prev);
2098  casadi_copy(m->adj_u, nuq_, m->adj_u_prev);
2099 
2100  // Take step
2101  casadi_int tapeind = disc_[m->k] + j;
2102  stepB(m, t, h,
2103  m->x_tape + nx_ * tapeind, m->x_tape + nx_ * (tapeind + 1),
2104  m->v_tape + nv_ * tapeind,
2105  m->tmp1, m->rv, m->adj_x, m->adj_p, m->adj_u);
2106  casadi_clear(m->rv, nrv_);
2107  casadi_axpy(nrq_, 1., m->adj_p_prev, m->adj_p);
2108  casadi_axpy(nuq_, 1., m->adj_u_prev, m->adj_u);
2109  }
2110 
2111  // Return to user
2112  casadi_copy(m->adj_x, nrx_, adj_x);
2113  casadi_copy(m->adj_p, nrq_, adj_p);
2114  casadi_copy(m->adj_u, nuq_, adj_u);
2115 }
2116 
2117 void FixedStepIntegrator::stepF(FixedStepMemory* m, double t, double h,
2118  const double* x0, const double* v0, double* xf, double* vf, double* qf) const {
2119  // Evaluate nondifferentiated
2120  std::fill(m->arg, m->arg + STEP_NUM_IN, nullptr);
2121  m->arg[STEP_T] = &t; // t
2122  m->arg[STEP_H] = &h; // h
2123  m->arg[STEP_X0] = x0; // x0
2124  m->arg[STEP_V0] = v0; // v0
2125  m->arg[STEP_P] = m->p; // p
2126  m->arg[STEP_U] = m->u; // u
2127  std::fill(m->res, m->res + STEP_NUM_OUT, nullptr);
2128  m->res[STEP_XF] = xf; // xf
2129  m->res[STEP_VF] = vf; // vf
2130  m->res[STEP_QF] = qf; // qf
2131  calc_function(m, "step");
2132  // Evaluate sensitivities
2133  if (nfwd_ > 0) {
2134  m->arg[STEP_NUM_IN + STEP_XF] = xf; // out:xf
2135  m->arg[STEP_NUM_IN + STEP_VF] = vf; // out:vf
2136  m->arg[STEP_NUM_IN + STEP_QF] = qf; // out:qf
2137  m->arg[STEP_NUM_IN + STEP_NUM_OUT + STEP_T] = nullptr; // fwd:t
2138  m->arg[STEP_NUM_IN + STEP_NUM_OUT + STEP_H] = nullptr; // fwd:h
2139  m->arg[STEP_NUM_IN + STEP_NUM_OUT + STEP_X0] = x0 + nx1_; // fwd:x0
2140  m->arg[STEP_NUM_IN + STEP_NUM_OUT + STEP_V0] = v0 + nv1_; // fwd:v0
2141  m->arg[STEP_NUM_IN + STEP_NUM_OUT + STEP_P] = m->p + np1_; // fwd:p
2142  m->arg[STEP_NUM_IN + STEP_NUM_OUT + STEP_U] = m->u + nu1_; // fwd:u
2143  m->res[STEP_XF] = xf + nx1_; // fwd:xf
2144  m->res[STEP_VF] = vf + nv1_; // fwd:vf
2145  m->res[STEP_QF] = qf + nq1_; // fwd:qf
2146  calc_function(m, forward_name("step", nfwd_));
2147  }
2148 }
2149 
2150 void FixedStepIntegrator::stepB(FixedStepMemory* m, double t, double h,
2151  const double* x0, const double* xf, const double* vf,
2152  const double* adj_xf, const double* rv0,
2153  double* adj_x0, double* adj_p, double* adj_u) const {
2154  // Evaluate nondifferentiated
2155  std::fill(m->arg, m->arg + BSTEP_NUM_IN, nullptr);
2156  m->arg[BSTEP_T] = &t; // t
2157  m->arg[BSTEP_H] = &h; // h
2158  m->arg[BSTEP_X0] = x0; // x0
2159  m->arg[BSTEP_V0] = nullptr; // v0
2160  m->arg[BSTEP_P] = m->p; // p
2161  m->arg[BSTEP_U] = m->u; // u
2162  m->arg[BSTEP_OUT_XF] = xf; // out:xf
2163  m->arg[BSTEP_OUT_VF] = vf; // out:vf
2164  m->arg[BSTEP_OUT_QF] = nullptr; // out:qf
2165  m->arg[BSTEP_ADJ_XF] = adj_xf; // adj:xf
2166  m->arg[BSTEP_ADJ_VF] = rv0; // adj:vf
2167  m->arg[BSTEP_ADJ_QF] = m->adj_q; // adj:qf
2168  std::fill(m->res, m->res + BSTEP_NUM_OUT, nullptr);
2169  m->res[BSTEP_ADJ_T] = nullptr; // adj:t
2170  m->res[BSTEP_ADJ_H] = nullptr; // adj:h
2171  m->res[BSTEP_ADJ_X0] = adj_x0; // adj:x0
2172  m->res[BSTEP_ADJ_V0] = nullptr; // adj:v0
2173  m->res[BSTEP_ADJ_P] = adj_p; // adj:p
2174  m->res[BSTEP_ADJ_U] = adj_u; // adj:u
2175  calc_function(m, reverse_name("step", nadj_));
2176  // Evaluate sensitivities
2177  if (nfwd_ > 0) {
2178  m->arg[BSTEP_NUM_IN + BSTEP_ADJ_T] = nullptr; // out:adj:t
2179  m->arg[BSTEP_NUM_IN + BSTEP_ADJ_H] = nullptr; // out:adj:h
2180  m->arg[BSTEP_NUM_IN + BSTEP_ADJ_X0] = adj_x0; // out:adj:x0
2181  m->arg[BSTEP_NUM_IN + BSTEP_ADJ_V0] = nullptr; // out:adj:v0
2182  m->arg[BSTEP_NUM_IN + BSTEP_ADJ_P] = adj_p; // out:adj:p
2183  m->arg[BSTEP_NUM_IN + BSTEP_ADJ_U] = adj_u; // out:adj:u
2184  m->arg[BSTEP_NUM_IN + BSTEP_NUM_OUT + BSTEP_T] = nullptr; // fwd:t
2185  m->arg[BSTEP_NUM_IN + BSTEP_NUM_OUT + BSTEP_H] = nullptr; // fwd:h
2186  m->arg[BSTEP_NUM_IN + BSTEP_NUM_OUT + BSTEP_X0] = x0 + nx1_; // fwd:x0
2187  m->arg[BSTEP_NUM_IN + BSTEP_NUM_OUT + BSTEP_V0] = nullptr; // fwd:v0
2188  m->arg[BSTEP_NUM_IN + BSTEP_NUM_OUT + BSTEP_P] = m->p + np1_; // fwd:p
2189  m->arg[BSTEP_NUM_IN + BSTEP_NUM_OUT + BSTEP_U] = m->u + nu1_; // fwd:u
2190  m->arg[BSTEP_NUM_IN + BSTEP_NUM_OUT + BSTEP_OUT_XF] = xf + nx1_; // fwd:out:xf
2191  m->arg[BSTEP_NUM_IN + BSTEP_NUM_OUT + BSTEP_OUT_VF] = vf + nv1_; // fwd:out:vf
2192  m->arg[BSTEP_NUM_IN + BSTEP_NUM_OUT + BSTEP_OUT_QF] = nullptr; // fwd:out:qf
2193  m->arg[BSTEP_NUM_IN + BSTEP_NUM_OUT + BSTEP_ADJ_XF] = adj_xf + nrx1_ * nadj_; // fwd:adj:xf
2194  m->arg[BSTEP_NUM_IN + BSTEP_NUM_OUT + BSTEP_ADJ_VF] = rv0 + nrv1_; // fwd:adj:vf
2195  m->arg[BSTEP_NUM_IN + BSTEP_NUM_OUT + BSTEP_ADJ_QF] = m->adj_q + nrp1_ * nadj_; // fwd:adj:qf
2196  m->res[BSTEP_ADJ_T] = nullptr; // fwd:adj:t
2197  m->res[BSTEP_ADJ_H] = nullptr; // fwd:adj:h
2198  m->res[BSTEP_ADJ_X0] = adj_x0 + nrx1_ * nadj_; // fwd:adj_x0
2199  m->res[BSTEP_ADJ_V0] = nullptr; // fwd:adj:v0
2200  m->res[BSTEP_ADJ_P] = adj_p + nrq1_ * nadj_; // fwd:adj_p
2201  m->res[BSTEP_ADJ_U] = adj_u + nuq1_ * nadj_; // fwd:adj_u
2203  }
2204 }
2205 
2206 void FixedStepIntegrator::reset(IntegratorMemory* mem, bool first_call) const {
2207  auto m = static_cast<FixedStepMemory*>(mem);
2208 
2209  // Reset the base classes
2210  Integrator::reset(mem, first_call);
2211 
2212  // Only reset once
2213  if (first_call) {
2214  // Get consistent initial conditions
2215  casadi_fill(m->v, nv_, std::numeric_limits<double>::quiet_NaN());
2216 
2217  // Add the first element in the tape
2218  if (nrx_ > 0) {
2219  casadi_copy(m->x, nx_, m->x_tape);
2220  }
2221  }
2222 }
2223 
2225  auto m = static_cast<FixedStepMemory*>(mem);
2226 
2227  // Clear adjoint seeds
2228  casadi_clear(m->adj_q, nrp_);
2229  casadi_clear(m->adj_x, nrx_);
2230 
2231  // Reset summation states
2232  casadi_clear(m->adj_p, nrq_);
2233  casadi_clear(m->adj_u, nuq_);
2234 
2235  // Update backwards dependent variables
2236  casadi_clear(m->rv, nrv_);
2237 }
2238 
2240  const double* adj_x, const double* adj_z, const double* adj_q) const {
2241  auto m = static_cast<FixedStepMemory*>(mem);
2242  // Add impulse to backward parameters
2243  casadi_axpy(nrp_, 1., adj_q, m->adj_q);
2244 
2245  // Add impulse to state
2246  casadi_axpy(nrx_, 1., adj_x, m->adj_x);
2247 
2248  // Add impulse to backwards dependent variables
2249  casadi_axpy(nrz_, 1., adj_z, m->rv + nrv_ - nrz_);
2250 }
2251 
2253  const std::string& name, const Function& dae, double t0, const std::vector<double>& tout)
2254  : FixedStepIntegrator(name, dae, t0, tout) {
2255 }
2256 
2258 }
2259 
2262  {{"rootfinder",
2263  {OT_STRING,
2264  "An implicit function solver"}},
2265  {"rootfinder_options",
2266  {OT_DICT,
2267  "Options to be passed to the NLP Solver"}}
2268  }
2269 };
2270 
2272  // Call the base class init
2274 
2275  // Default (temporary) options
2276  std::string implicit_function_name = "newton";
2278 
2279  // Read options
2280  for (auto&& op : opts) {
2281  if (op.first=="rootfinder") {
2282  implicit_function_name = op.second.to_string();
2283  } else if (op.first=="rootfinder_options") {
2284  rootfinder_options = op.second;
2285  }
2286  }
2287 
2288  // Complete rootfinder dictionary
2289  rootfinder_options["implicit_input"] = STEP_V0;
2290  rootfinder_options["implicit_output"] = STEP_VF;
2291 
2292  // Allocate a solver
2293  Function rf = rootfinder("step", implicit_function_name,
2294  get_function("implicit_step"), rootfinder_options);
2295  set_function(rf);
2296  if (nfwd_ > 0) set_function(rf.forward(nfwd_));
2297 
2298  // Backward integration
2299  if (nadj_ > 0) {
2300  Function adj_F = rf.reverse(nadj_);
2301  set_function(adj_F, adj_F.name(), true);
2302  if (nfwd_ > 0) {
2303  create_forward(adj_F.name(), nfwd_);
2304  }
2305  }
2306 }
2307 
2308 template<typename XType>
2309 Function Integrator::map2oracle(const std::string& name,
2310  const std::map<std::string, XType>& d) {
2311  std::vector<XType> de_in(DYN_NUM_IN), de_out(DYN_NUM_OUT);
2312  for (auto&& i : d) {
2313  if (i.first=="t") {
2314  de_in[DYN_T]=i.second;
2315  } else if (i.first=="x") {
2316  de_in[DYN_X]=i.second;
2317  } else if (i.first=="z") {
2318  de_in[DYN_Z]=i.second;
2319  } else if (i.first=="p") {
2320  de_in[DYN_P]=i.second;
2321  } else if (i.first=="u") {
2322  de_in[DYN_U]=i.second;
2323  } else if (i.first=="ode") {
2324  de_out[DYN_ODE]=i.second;
2325  } else if (i.first=="alg") {
2326  de_out[DYN_ALG]=i.second;
2327  } else if (i.first=="quad") {
2328  de_out[DYN_QUAD]=i.second;
2329  } else if (i.first=="zero") {
2330  de_out[DYN_ZERO]=i.second;
2331  } else {
2332  casadi_error("No such field: " + i.first);
2333  }
2334  }
2335 
2336  // Consistency checks, input sparsities
2337  for (casadi_int i = 0; i < DYN_NUM_IN; ++i) {
2338  const Sparsity& sp = de_in[i].sparsity();
2339  if (i == DYN_T) {
2340  casadi_assert(sp.is_empty() || sp.is_scalar(), "DAE time variable must be empty or scalar. "
2341  "Got dimension " + str(sp.size()));
2342  } else {
2343  casadi_assert(sp.is_empty() || sp.is_vector(), "DAE inputs must be empty or vectors. "
2344  + dyn_in(i) + " has dimension " + str(sp.size()) + ".");
2345  }
2346  casadi_assert(sp.is_dense(), "DAE inputs must be dense . "
2347  + dyn_in(i) + " is sparse.");
2348  // Convert row vectors to column vectors
2349  de_in[i] = vec(de_in[i]);
2350  }
2351 
2352  // Consistency checks, output sparsities
2353  for (casadi_int i = 0; i < DYN_NUM_OUT; ++i) {
2354  const Sparsity& sp = de_out[i].sparsity();
2355  casadi_assert(sp.is_empty() || sp.is_vector(), "DAE outputs must be empty or vectors. "
2356  + dyn_out(i) + " has dimension " + str(sp.size()));
2357  // Make sure dense and vector
2358  de_out[i] = vec(densify(de_out[i]));
2359  }
2360 
2361  // Construct
2362  return Function(name, de_in, de_out, dyn_in(), dyn_out());
2363 }
2364 
2367 
2368  s.version("Integrator", 3);
2369 
2370  s.pack("Integrator::sp_jac_dae", sp_jac_dae_);
2371  s.pack("Integrator::sp_jac_rdae", sp_jac_rdae_);
2372  s.pack("Integrator::t0", t0_);
2373  s.pack("Integrator::tout", tout_);
2374  s.pack("Integrator::nfwd", nfwd_);
2375  s.pack("Integrator::nadj", nadj_);
2376  s.pack("Integrator::rdae", rdae_);
2377 
2378  s.pack("Integrator::nx", nx_);
2379  s.pack("Integrator::nz", nz_);
2380  s.pack("Integrator::nq", nq_);
2381  s.pack("Integrator::nx1", nx1_);
2382  s.pack("Integrator::nz1", nz1_);
2383  s.pack("Integrator::nq1", nq1_);
2384 
2385  s.pack("Integrator::nrx", nrx_);
2386  s.pack("Integrator::nrz", nrz_);
2387  s.pack("Integrator::nrq", nrq_);
2388  s.pack("Integrator::nuq", nuq_);
2389  s.pack("Integrator::nrx1", nrx1_);
2390  s.pack("Integrator::nrz1", nrz1_);
2391  s.pack("Integrator::nrq1", nrq1_);
2392  s.pack("Integrator::nuq1", nuq1_);
2393 
2394  s.pack("Integrator::np", np_);
2395  s.pack("Integrator::nrp", nrp_);
2396  s.pack("Integrator::np1", np1_);
2397  s.pack("Integrator::nrp1", nrp1_);
2398 
2399  s.pack("Integrator::nu", nu_);
2400  s.pack("Integrator::nu1", nu1_);
2401 
2402  s.pack("Integrator::ne", ne_);
2403  s.pack("Integrator::ntmp", ntmp_);
2404 
2405  s.pack("Integrator::nom_x", nom_x_);
2406  s.pack("Integrator::nom_z", nom_z_);
2407 
2408  s.pack("Integrator::augmented_options", augmented_options_);
2409  s.pack("Integrator::opts", opts_);
2410  s.pack("Integrator::print_stats", print_stats_);
2411 
2412  s.pack("Integrator::transition", transition_);
2413  s.pack("Integrator::max_event_iter", max_event_iter_);
2414  s.pack("Integrator::max_events", max_events_);
2415  s.pack("Integrator::event_tol", event_tol_);
2416  s.pack("Integrator::event_acceptable_tol", event_acceptable_tol_);
2417 }
2418 
2422 }
2423 
2426 }
2427 
2429  s.version("Integrator", 3);
2430 
2431  s.unpack("Integrator::sp_jac_dae", sp_jac_dae_);
2432  s.unpack("Integrator::sp_jac_rdae", sp_jac_rdae_);
2433  s.unpack("Integrator::t0", t0_);
2434  s.unpack("Integrator::tout", tout_);
2435  s.unpack("Integrator::nfwd", nfwd_);
2436  s.unpack("Integrator::nadj", nadj_);
2437  s.unpack("Integrator::rdae", rdae_);
2438 
2439  s.unpack("Integrator::nx", nx_);
2440  s.unpack("Integrator::nz", nz_);
2441  s.unpack("Integrator::nq", nq_);
2442  s.unpack("Integrator::nx1", nx1_);
2443  s.unpack("Integrator::nz1", nz1_);
2444  s.unpack("Integrator::nq1", nq1_);
2445 
2446  s.unpack("Integrator::nrx", nrx_);
2447  s.unpack("Integrator::nrz", nrz_);
2448  s.unpack("Integrator::nrq", nrq_);
2449  s.unpack("Integrator::nuq", nuq_);
2450  s.unpack("Integrator::nrx1", nrx1_);
2451  s.unpack("Integrator::nrz1", nrz1_);
2452  s.unpack("Integrator::nrq1", nrq1_);
2453  s.unpack("Integrator::nuq1", nuq1_);
2454 
2455  s.unpack("Integrator::np", np_);
2456  s.unpack("Integrator::nrp", nrp_);
2457  s.unpack("Integrator::np1", np1_);
2458  s.unpack("Integrator::nrp1", nrp1_);
2459 
2460  s.unpack("Integrator::nu", nu_);
2461  s.unpack("Integrator::nu1", nu1_);
2462 
2463  s.unpack("Integrator::ne", ne_);
2464  s.unpack("Integrator::ntmp", ntmp_);
2465 
2466  s.unpack("Integrator::nom_x", nom_x_);
2467  s.unpack("Integrator::nom_z", nom_z_);
2468 
2469  s.unpack("Integrator::augmented_options", augmented_options_);
2470  s.unpack("Integrator::opts", opts_);
2471  s.unpack("Integrator::print_stats", print_stats_);
2472 
2473  s.unpack("Integrator::transition", transition_);
2474  s.unpack("Integrator::max_event_iter", max_event_iter_);
2475  s.unpack("Integrator::max_events", max_events_);
2476  s.unpack("Integrator::event_tol", event_tol_);
2477  s.unpack("Integrator::event_acceptable_tol", event_acceptable_tol_);
2478 }
2479 
2482 
2483  s.version("FixedStepIntegrator", 3);
2484  s.pack("FixedStepIntegrator::nk_target", nk_target_);
2485  s.pack("FixedStepIntegrator::disc", disc_);
2486  s.pack("FixedStepIntegrator::nv", nv_);
2487  s.pack("FixedStepIntegrator::nv1", nv1_);
2488  s.pack("FixedStepIntegrator::nrv", nrv_);
2489  s.pack("FixedStepIntegrator::nrv1", nrv1_);
2490 }
2491 
2493  s.version("FixedStepIntegrator", 3);
2494  s.unpack("FixedStepIntegrator::nk_target", nk_target_);
2495  s.unpack("FixedStepIntegrator::disc", disc_);
2496  s.unpack("FixedStepIntegrator::nv", nv_);
2497  s.unpack("FixedStepIntegrator::nv1", nv1_);
2498  s.unpack("FixedStepIntegrator::nrv", nrv_);
2499  s.unpack("FixedStepIntegrator::nrv1", nrv1_);
2500 }
2501 
2504 
2505  s.version("ImplicitFixedStepIntegrator", 2);
2506 }
2507 
2509  FixedStepIntegrator(s) {
2510  s.version("ImplicitFixedStepIntegrator", 2);
2511 }
2512 
2513 void Integrator::set_q(IntegratorMemory* m, const double* q) const {
2514  casadi_copy(q, nq_, m->q);
2515 }
2516 
2517 void Integrator::set_x(IntegratorMemory* m, const double* x) const {
2518  casadi_copy(x, nx_, m->x);
2519 }
2520 
2521 void Integrator::set_z(IntegratorMemory* m, const double* z) const {
2522  casadi_copy(z, nz_, m->z);
2523 }
2524 
2525 void Integrator::set_p(IntegratorMemory* m, const double* p) const {
2526  casadi_copy(p, np_, m->p);
2527 }
2528 
2529 void Integrator::set_u(IntegratorMemory* m, const double* u) const {
2530  casadi_copy(u, nu_, m->u);
2531 }
2532 
2533 void Integrator::get_q(IntegratorMemory* m, double* q) const {
2534  casadi_copy(m->q, nq_, q);
2535 }
2536 
2537 void Integrator::get_x(IntegratorMemory* m, double* x) const {
2538  casadi_copy(m->x, nx_, x);
2539 }
2540 
2541 void Integrator::get_z(IntegratorMemory* m, double* z) const {
2542  casadi_copy(m->z, nz_, z);
2543 }
2544 
2545 casadi_int Integrator::next_stop(casadi_int k, const double* u) const {
2546  // Integrate till the end if no input signals
2547  if (nu_ == 0 || u == 0) return nt() - 1;
2548  // Find the next discontinuity, if any
2549  for (; k + 1 < nt(); ++k) {
2550  // Next control value
2551  const double *u_next = u + nu_;
2552  // Check if there is any change in input from k to k + 1
2553  for (casadi_int i = 0; i < nu_; ++i) {
2554  // Step change detected: stop integration at k
2555  if (u[i] != u_next[i]) return k;
2556  }
2557  // Shift u
2558  u = u_next;
2559  }
2560  // No step changes detected
2561  return k;
2562 }
2563 
2565  // Evaluate the DAE and zero crossing function
2566  m->arg[DYN_T] = &m->t; // t
2567  m->arg[DYN_X] = m->x; // x
2568  m->arg[DYN_Z] = m->z; // z
2569  m->arg[DYN_P] = m->p; // p
2570  m->arg[DYN_U] = m->u; // u
2571  m->res[DYN_ODE] = m->xdot; // ode
2572  m->res[DYN_ALG] = m->tmp1 + nx_; // alg
2573  m->res[DYN_QUAD] = nullptr; // quad
2574  m->res[DYN_ZERO] = m->e; // zero
2575  if (calc_function(m, "dae")) return 1;
2576  // Calculate de_dt using by forward mode AD applied to zero crossing function
2577  // Note: Currently ignoring dependency propagation via algebraic equations
2578  double dt_dt = 1;
2579  m->arg[DYN_NUM_IN + DYN_ODE] = m->xdot; // out:ode
2580  m->arg[DYN_NUM_IN + DYN_ALG] = m->tmp1 + nx_; // out:alg
2581  m->arg[DYN_NUM_IN + DYN_QUAD] = nullptr; // out:quad
2582  m->arg[DYN_NUM_IN + DYN_ZERO] = m->e; // out:zero
2583  m->arg[DYN_NUM_IN + DYN_NUM_OUT + DYN_T] = &dt_dt; // fwd:t
2584  m->arg[DYN_NUM_IN + DYN_NUM_OUT + DYN_X] = m->xdot; // fwd:x
2585  m->arg[DYN_NUM_IN + DYN_NUM_OUT + DYN_Z] = nullptr; // fwd:z
2586  m->arg[DYN_NUM_IN + DYN_NUM_OUT + DYN_P] = nullptr; // fwd:p
2587  m->arg[DYN_NUM_IN + DYN_NUM_OUT + DYN_U] = nullptr; // fwd:u
2588  m->res[DYN_ODE] = nullptr; // fwd:ode
2589  m->res[DYN_ALG] = nullptr; // fwd:alg
2590  m->res[DYN_QUAD] = nullptr; // fwd:quad
2591  m->res[DYN_ZERO] = m->edot; // fwd:zero
2592  if (calc_function(m, forward_name("dae", 1))) return 1;
2593  // Success
2594  return 0;
2595 }
2596 
2598  // Event time same as stopping time, by default
2599  double t_event = m->t_stop;
2600  casadi_int event_index = -1;
2601  // Calculate m->e and m->edot
2602  if (calc_edot(m)) return 1;
2603  // Save the values of the zero-crossing functions
2604  casadi_copy(m->e, ne_, m->old_e);
2605  // Find the next event, if any
2606  for (casadi_int i = 0; i < ne_; ++i) {
2607  if (!m->event_triggered[i]) {
2608  // Check if zero crossing function is positive and moving in the negative direction
2609  if (m->e[i] > 0 && m->edot[i] < 0) {
2610  // Projected zero-crossing time
2611  double t = m->t - m->e[i] / m->edot[i];
2612  // Save if earlier than current t_event
2613  if (t < t_event) {
2614  t_event = t;
2615  event_index = i;
2616  }
2617  }
2618  }
2619  }
2620  // Zero crossing projected
2621  if (event_index >= 0) {
2622  // Print progress
2623  if (verbose_) casadi_message("Projected zero crossing for index " + str(event_index)
2624  + " at t = " + str(t_event));
2625  // Update t_stop and t_next accordingly
2626  m->t_stop = t_event;
2627  m->t_next = std::min(m->t_next, t_event);
2628  }
2629  return 0;
2630 }
2631 
2632 int Integrator::trigger_event(IntegratorMemory* m, casadi_int* ind) const {
2633  // Throw an error if too many events are happening within a single control interval
2634  if (++m->num_events > max_events_) {
2635  casadi_error("At t = " + str(m->t) + ": Too many event iterations during interval "
2636  + str(m->k));
2637  }
2638  // Consistency checks
2639  if (*ind < 0 || m->event_triggered[*ind]) return 1;
2640  // Mark event as triggered
2641  m->event_triggered[*ind] = 1;
2642  // Print progress
2643  if (verbose_) casadi_message("Zero crossing for index " + str(*ind) + " at t = " + str(m->t));
2644  // The event time will be impacted by perturbations in x, z, u, p.
2645  // the perturbed time will be given by the following implicit function:
2646  // e[ind](t, x + (t - t_event) * xdot, z + (t - t_event) * zdot, u, p) = 0
2647  // The sensitivities of t as a functions of fwd_x, fwd_z, fwd_u and fwd_p
2648  // are given by the implicit function theorem:
2649  // de/dt(t, x, z, u, p) * fwd_t + de/dx * fwd_x + de/dz * fwd_z + de/du * fwd_u + de/dp * fwd_p
2650  // <=> fwd_t = -fwd_e(fwd_x, fwd_z, fwd_u, fwd_p) / edot
2651  if (nfwd_ > 0) {
2652  m->arg[DYN_NUM_IN + DYN_ODE] = m->xdot; // out:ode
2653  m->arg[DYN_NUM_IN + DYN_ALG] = nullptr; // out:alg
2654  m->arg[DYN_NUM_IN + DYN_QUAD] = nullptr; // out:quad
2655  m->arg[DYN_NUM_IN + DYN_ZERO] = m->e; // out:zero
2656  m->arg[DYN_NUM_IN + DYN_NUM_OUT + DYN_T] = nullptr; // fwd:t
2657  m->arg[DYN_NUM_IN + DYN_NUM_OUT + DYN_X] = m->x + nx1_; // fwd:x
2658  m->arg[DYN_NUM_IN + DYN_NUM_OUT + DYN_Z] = m->z + nz1_; // fwd:z
2659  m->arg[DYN_NUM_IN + DYN_NUM_OUT + DYN_P] = m->p + np1_; // fwd:p
2660  m->arg[DYN_NUM_IN + DYN_NUM_OUT + DYN_U] = m->u + nu1_; // fwd:u
2661  m->res[DYN_ODE] = nullptr; // fwd:ode
2662  m->res[DYN_ALG] = nullptr; // fwd:alg
2663  m->res[DYN_QUAD] = nullptr; // fwd:quad
2664  m->res[DYN_ZERO] = m->tmp1; // fwd:zero
2665  if (calc_function(m, forward_name("dae", nfwd_))) return 1;
2666  // Calculate sensitivity in t
2667  for (casadi_int i = 0; i < nfwd_; ++i) {
2668  m->tmp1[i] = -m->tmp1[*ind + ne_ * i] / m->edot[*ind];
2669  }
2670  // Propagate this sensitivity to the state vector
2671  for (casadi_int i = 0; i < nfwd_; ++i) {
2672  casadi_axpy(nx1_, m->tmp1[i], m->xdot, m->x + nx1_ * (1 + i));
2673  }
2674  }
2675  // Call event transition function, if any
2676  if (has_function("transition")) {
2677  // Evaluate to tmp2
2678  double index = *ind; // function expects floating point values
2679  m->arg[EVENT_INDEX] = &index; // index
2680  m->arg[EVENT_T] = &m->t; // t
2681  m->arg[EVENT_X] = m->x; // x
2682  m->arg[EVENT_Z] = m->z; // z
2683  m->arg[EVENT_P] = m->p; // p
2684  m->arg[EVENT_U] = m->u; // u
2685  m->res[EVENT_POST_X] = m->tmp2; // post_x
2686  m->res[EVENT_POST_Z] = m->tmp2 + nx_; // post_z
2687  if (calc_function(m, "transition")) return 1;
2688  // Propagate forward sensitivities
2689  if (nfwd_ > 0) {
2690  // Propagate sensitivities through event transition
2691  m->arg[EVENT_NUM_IN + EVENT_POST_X] = m->tmp2; // out:post_x
2692  m->arg[EVENT_NUM_IN + EVENT_POST_Z] = m->tmp2 + nx_; // out:post_z
2693  m->arg[EVENT_NUM_IN + EVENT_NUM_OUT + EVENT_INDEX] = nullptr; // fwd:index
2694  m->arg[EVENT_NUM_IN + EVENT_NUM_OUT + EVENT_T] = m->tmp1; // fwd:t
2695  m->arg[EVENT_NUM_IN + EVENT_NUM_OUT + EVENT_X] = m->x + nx1_; // fwd:x
2696  m->arg[EVENT_NUM_IN + EVENT_NUM_OUT + EVENT_Z] = m->z + nz1_; // fwd:z
2697  m->arg[EVENT_NUM_IN + EVENT_NUM_OUT + EVENT_P] = m->p + np1_; // fwd:p
2698  m->arg[EVENT_NUM_IN + EVENT_NUM_OUT + EVENT_U] = m->u + nu1_; // fwd:u
2699  m->res[EVENT_POST_X] = m->tmp2 + nx1_; // fwd:post_x
2700  m->res[EVENT_POST_Z] = m->tmp2 + nx_ + nz1_; // fwd:post_z
2701  calc_function(m, forward_name("transition", nfwd_));
2702  }
2703  }
2704  // Update x, z
2705  casadi_copy(m->tmp2, nx_ + nz_, m->x);
2706  // Calculate m->xdot and m->zdot
2707  if (calc_edot(m)) return 1;
2708  // Propagate this sensitivity to the state vector
2709  for (casadi_int i = 0; i < nfwd_; ++i) {
2710  casadi_axpy(nx1_, -m->tmp1[i], m->xdot, m->x + nx1_ * (1 + i));
2711  }
2712  // TODO(@jaeandersson): Check if other events need to be triggered
2713  *ind = -1; // for now, do not trigger other events
2714  return 0;
2715 }
2716 
2717 casadi_int Integrator::next_stopB(casadi_int k, const double* u) const {
2718  // Integrate till the beginning if no input signals
2719  if (nu_ == 0 || u == 0) return -1;
2720  // Find the next discontinuity, if any
2721  for (; k-- > 0; ) {
2722  // Next control value
2723  const double *u_next = u - nu_;
2724  // Check if there is any change in input from k to k + 1
2725  for (casadi_int i = 0; i < nu_; ++i) {
2726  // Step change detected: stop integration at k
2727  if (u[i] != u_next[i]) return k;
2728  }
2729  // Shift u
2730  u = u_next;
2731  }
2732  // No step changes detected
2733  return k;
2734 }
2735 
2736 bool Integrator::all_zero(const double* v, casadi_int n) {
2737  // Quick return if trivially zero
2738  if (v == 0 || n == 0) return true;
2739  // Loop over entries
2740  for (casadi_int i = 0; i < n; ++i) {
2741  if (v[i] != 0.) return false;
2742  }
2743  // All zero if reached here
2744  return true;
2745 }
2746 
2747 
2748 } // namespace casadi
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
~FixedStepIntegrator() override
Destructor.
std::vector< casadi_int > disc_
static const Options options_
Options.
void init(const Dict &opts) override
Initialize stage.
void stepB(FixedStepMemory *m, double t, double h, const double *x0, const double *xf, const double *vf, const double *adj_xf, const double *rv0, double *adj_x0, double *adj_p, double *adj_u) const
Take integrator step backward.
int init_mem(void *mem) const override
Initalize memory block.
void stepF(FixedStepMemory *m, double t, double h, const double *x0, const double *v0, double *xf, double *vf, double *qf) const
Take integrator step forward.
void impulseB(IntegratorMemory *mem, const double *adj_x, const double *adj_z, const double *adj_q) const override
Introduce an impulse into the backwards integration at the current time.
void retreat(IntegratorMemory *mem, const double *u, double *adj_x, double *adj_p, double *adj_u) const override
Retreat solution in time.
void reset(IntegratorMemory *mem, bool first_call) const override
Reset the forward solver at the start or after an event.
casadi_int nv_
Number of dependent variables in the discrete time integration.
int advance_noevent(IntegratorMemory *mem) const override
Advance solution in time.
FixedStepIntegrator(const std::string &name, const Function &dae, double t0, const std::vector< double > &tout)
Constructor.
void resetB(IntegratorMemory *mem) const override
Reset the backward problem and take time to tf.
Function create_advanced(const Dict &opts) override
virtual void setup_step()=0
Setup step functions.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const override
Set the (persistent) work vectors.
casadi_int size1_in(casadi_int ind) const
Input/output dimensions.
void alloc_iw(size_t sz_iw, bool persistent=false)
Ensure required length of iw field.
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.
static std::string forward_name(const std::string &fcn, casadi_int nfwd)
Helper function: Get name of forward derivative function.
casadi_int numel_out() const
Number of input/output elements.
const Sparsity & sparsity_in(casadi_int ind) const
Input/output sparsity.
virtual void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const
Set the (persistent) work vectors.
casadi_int numel_in() const
Number of input/output elements.
size_t n_in_
Number of inputs and outputs.
casadi_int size2_out(casadi_int ind) const
Input/output dimensions.
casadi_int size1_out(casadi_int ind) const
Input/output dimensions.
std::pair< casadi_int, casadi_int > size_out(casadi_int ind) const
Input/output dimensions.
void serialize_type(SerializingStream &s) const override
Serialize type information.
const Sparsity & sparsity_out(casadi_int ind) const
Input/output sparsity.
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
void setup(void *mem, const double **arg, double **res, casadi_int *iw, double *w) const
Set the (persistent and temporary) work vectors.
static std::string reverse_name(const std::string &fcn, casadi_int nadj)
Helper function: Get name of adjoint derivative function.
casadi_int size2_in(casadi_int ind) const
Input/output dimensions.
Function object.
Definition: function.hpp:60
casadi_int numel_in() const
Get number of input elements.
Definition: function.cpp:859
Function forward(casadi_int nfwd) const
Get a function that calculates nfwd forward derivatives.
Definition: function.cpp:1135
casadi_int nnz_out() const
Get number of output nonzeros.
Definition: function.cpp:855
const MX mx_in(casadi_int ind) const
Get symbolic primitives equivalent to the input expressions.
Definition: function.cpp:1584
const Sparsity & sparsity_out(casadi_int ind) const
Get sparsity of a given output.
Definition: function.cpp:1031
const std::string & name() const
Name of the function.
Definition: function.cpp:1307
casadi_int numel_out() const
Get number of output elements.
Definition: function.cpp:863
Function reverse(casadi_int nadj) const
Get a function that calculates nadj adjoint derivatives.
Definition: function.cpp:1143
static Function create(FunctionInternal *node)
Create from node.
Definition: function.cpp:336
std::vector< double > nominal_in(casadi_int ind) const
Get nominal input value.
Definition: function.cpp:1492
const Sparsity & sparsity_in(casadi_int ind) const
Get sparsity of a given input.
Definition: function.cpp:1015
casadi_int n_out() const
Get the number of function outputs.
Definition: function.cpp:823
casadi_int n_in() const
Get the number of function inputs.
Definition: function.cpp:819
std::vector< std::string > get_free() const
Get free variables as a string.
Definition: function.cpp:1184
bool is_a(const std::string &type, bool recursive=true) const
Check if the function is of a particular type.
Definition: function.cpp:1664
bool has_free() const
Does the function have free variables.
Definition: function.cpp:1697
std::pair< casadi_int, casadi_int > size_in(casadi_int ind) const
Get input dimension.
Definition: function.cpp:843
const std::vector< Sparsity > & jac_sparsity(bool compact=false) const
Get, if necessary generate, the sparsity of all Jacobian blocks.
Definition: function.cpp:940
static MX sym(const std::string &name, casadi_int nrow=1, casadi_int ncol=1)
Create an nrow-by-ncol symbolic primitive.
bool is_null() const
Is a null pointer?
~ImplicitFixedStepIntegrator() override
Destructor.
void init(const Dict &opts) override
Initialize stage.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
static const Options options_
Options.
ImplicitFixedStepIntegrator(const std::string &name, const Function &dae, double t0, const std::vector< double > &tout)
Constructor.
Internal storage for integrator related data.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
casadi_int nfwd_
Number of sensitivities.
void init(const Dict &opts) override
Initialize.
Definition: integrator.cpp:642
virtual void reset(IntegratorMemory *mem, bool first_call) const
Reset the forward solver at the start or after an event.
int eval(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
evaluate
Definition: integrator.cpp:354
static const Options options_
Options.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize into MX.
void set_z(IntegratorMemory *m, const double *z) const
virtual void resetB(IntegratorMemory *mem) const =0
Reset the backward problem.
void get_z(IntegratorMemory *m, double *z) const
~Integrator() override=0
Destructor.
Definition: integrator.cpp:281
void set_x(IntegratorMemory *m, const double *x) const
void serialize_type(SerializingStream &s) const override
Serialize type information.
casadi_int next_stopB(casadi_int k, const double *u) const
Find next stop time.
int advance(IntegratorMemory *m) const
Advance solution in time, with events handling.
Definition: integrator.cpp:532
Sparsity sp_jac_aug(const Sparsity &J, const Sparsity &J1) const
Helper function, get augmented system Jacobian.
static Function map2oracle(const std::string &name, const std::map< std::string, XType > &d)
Convert dictionary to Problem.
std::vector< double > nom_x_
Function rdae_
Backwards DAE function.
Integrator(const std::string &name, const Function &oracle, double t0, const std::vector< double > &tout)
Constructor.
Definition: integrator.cpp:264
Dict augmented_options_
Augmented user option.
Sparsity get_sparsity_in(casadi_int i) override
Sparsities of function inputs and outputs.
Definition: integrator.cpp:284
casadi_int nrx_
Number of states for the backward integration.
casadi_int max_events_
Maximum total number of events during the simulation.
Sparsity sp_jac_dae_
Sparsity pattern of the extended Jacobians.
void get_q(IntegratorMemory *m, double *q) const
int init_mem(void *mem) const override
Initalize memory block.
Definition: integrator.cpp:912
int predict_events(IntegratorMemory *m) const
Predict next event time.
casadi_int next_stop(casadi_int k, const double *u) const
Find next stop time.
int fdae_sp_reverse(SpReverseMem *m, bvec_t *x, bvec_t *p, bvec_t *u, bvec_t *ode, bvec_t *alg) const
Reverse sparsity pattern propagation through DAE, forward problem.
virtual MX algebraic_state_output(const MX &Z) const
int fquad_sp_forward(SpForwardMem *m, const bvec_t *x, const bvec_t *z, const bvec_t *p, const bvec_t *u, bvec_t *quad) const
Forward sparsity pattern propagation through quadratures, forward problem.
virtual void retreat(IntegratorMemory *mem, const double *u, double *adj_x, double *adj_p, double *adj_u) const =0
Retreat solution in time.
casadi_int np_
Number of forward and backward parameters.
casadi_int nt() const
Number of output times.
void set_u(IntegratorMemory *m, const double *u) const
bool print_stats_
Options.
casadi_int ntmp_
Length of the tmp1, tmp2 vectors.
virtual void impulseB(IntegratorMemory *mem, const double *adj_x, const double *adj_z, const double *adj_q) const =0
Introduce an impulse into the backwards integration at the current time.
int bquad_sp_reverse(SpReverseMem *m, bvec_t *x, bvec_t *z, bvec_t *p, bvec_t *u, bvec_t *adj_ode, bvec_t *adj_alg, bvec_t *adj_quad, bvec_t *adj_p, bvec_t *adj_u) const
Reverse sparsity pattern propagation through quadratures, backward problem.
std::vector< double > nom_z_
int sp_forward(const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const override
Propagate sparsity forward.
int bdae_sp_reverse(SpReverseMem *m, bvec_t *x, bvec_t *z, bvec_t *p, bvec_t *u, bvec_t *adj_ode, bvec_t *adj_quad, bvec_t *adj_x, bvec_t *adj_z) const
Reverse sparsity pattern propagation through DAE, backward problem.
static std::vector< std::string > quad_out()
IO conventions for continuous time dynamics.
static bool grid_out(casadi_int i)
Is an output repeated for each grid point?
Definition: integrator.cpp:324
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.
static bool grid_in(casadi_int i)
Is an input repeated for each grid point?
Definition: integrator.cpp:312
virtual MX algebraic_state_init(const MX &x0, const MX &z0) const
void get_x(IntegratorMemory *m, double *x) const
virtual void print_stats(IntegratorMemory *mem) const
Print solver statistics.
virtual Function create_advanced(const Dict &opts)
Definition: integrator.cpp:350
Sparsity get_sparsity_out(casadi_int i) override
Sparsities of function inputs and outputs.
Definition: integrator.cpp:298
static std::vector< std::string > bquad_out()
IO conventions for continuous time dynamics.
Function augmented_dae() const
Generate the augmented DAE system.
Definition: integrator.cpp:919
int trigger_event(IntegratorMemory *m, casadi_int *ind) const
Trigger an event.
Dict opts_
Copy of the options.
static std::map< std::string, Plugin > solvers_
Collection of solvers.
static std::vector< std::string > bdyn_in()
IO conventions for continuous time dynamics.
Definition: integrator.cpp:96
int bquad_sp_forward(SpForwardMem *m, const bvec_t *x, const bvec_t *z, const bvec_t *p, const bvec_t *u, const bvec_t *adj_ode, const bvec_t *adj_alg, const bvec_t *adj_quad, bvec_t *adj_p, bvec_t *adj_u) const
Forward sparsity pattern propagation through quadratures, backward problem.
static bool all_zero(const double *v, casadi_int n)
Helper function: Vector has only zeros?
void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const override
Set the (persistent) work vectors.
Definition: integrator.cpp:882
int fquad_sp_reverse(SpReverseMem *m, bvec_t *x, bvec_t *z, bvec_t *p, bvec_t *u, bvec_t *quad) const
Reverse sparsity pattern propagation through quadratures, forward problem.
std::vector< double > tout_
Output time grid.
double event_tol_
Termination tolerance for the event iteration.
void set_q(IntegratorMemory *m, const double *q) const
static std::vector< std::string > dae_out()
IO conventions for continuous time dynamics.
double t0_
Initial time.
int sp_reverse(bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w, void *mem) const override
Propagate sparsity backwards.
double event_acceptable_tol_
Acceptable tolerance for the event iteration.
virtual Dict getDerivativeOptions(bool fwd) const
Set solver specific options to generated augmented integrators.
virtual int advance_noevent(IntegratorMemory *mem) const =0
Advance solution in time, without events handling.
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.
Function transition_
Function to be called at state events.
static std::vector< std::string > bdae_out()
IO conventions for continuous time dynamics.
Sparsity sp_jac_rdae()
Create sparsity pattern of the extended Jacobian (backward problem)
casadi_int max_event_iter_
Maximum number of event iterations for a single event.
Function get_forward_dae(const std::string &name) const
Generate the augmented DAE system.
Definition: integrator.cpp:943
static const std::string infix_
Infix.
casadi_int nu_
Number of controls.
casadi_int nx_
Number of states for the forward integration.
Sparsity sp_jac_dae()
Create sparsity pattern of the extended Jacobian (forward problem)
int calc_edot(IntegratorMemory *m) const
Linearize the zero crossing function.
static std::vector< std::string > bdyn_out()
IO conventions for continuous time dynamics.
Definition: integrator.cpp:115
int fdae_sp_forward(SpForwardMem *m, const bvec_t *x, const bvec_t *p, const bvec_t *u, bvec_t *ode, bvec_t *alg) const
Forward sparsity pattern propagation through DAE, forward problem.
int bdae_sp_forward(SpForwardMem *m, const bvec_t *x, const bvec_t *z, const bvec_t *p, const bvec_t *u, const bvec_t *adj_ode, const bvec_t *adj_quad, bvec_t *adj_x, bvec_t *adj_z) const
Forward sparsity pattern propagation through DAE, backward problem.
casadi_int ne_
Number of of zero-crossing functions.
void set_p(IntegratorMemory *m, const double *p) const
static casadi_int adjmap_out(casadi_int i)
Which output is used to calculate a given input in adjoint sensitivity analysis.
Definition: integrator.cpp:336
MX - Matrix expression.
Definition: mx.hpp:92
Base class for functions that perform calculation with an oracle.
void set_function(const Function &fcn, const std::string &fname, bool jit=false)
Function oracle_
Oracle: Used to generate other functions.
int calc_sp_forward(const std::string &fcn, const bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w) const
Function create_function(const Function &oracle, const std::string &fname, const std::vector< std::string > &s_in, const std::vector< std::string > &s_out, const Function::AuxOut &aux=Function::AuxOut(), const Dict &opts=Dict())
void join_results(OracleMemory *m) const
Combine results from different threads.
void init(const Dict &opts) override
Function create_forward(const std::string &fname, casadi_int nfwd)
int init_mem(void *mem) const override
Initalize memory block.
int calc_function(OracleMemory *m, const std::string &fcn, const double *const *arg=nullptr, int thread_id=0) const
std::vector< std::string > get_function() const override
Get list of dependency functions.
bool has_function(const std::string &fname) const override
static const Options options_
Options.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
int calc_sp_reverse(const std::string &fcn, bvec_t **arg, bvec_t **res, casadi_int *iw, bvec_t *w) const
static bool has_plugin(const std::string &pname, bool verbose=false)
Check if a plugin is available or can be loaded.
void serialize_type(SerializingStream &s) const
Serialize type information.
static Plugin & getPlugin(const std::string &pname)
Load and get the creator function.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
virtual const char * plugin_name() const=0
static Plugin load_plugin(const std::string &pname, bool register_plugin=true, bool needs_lock=true)
Load a plugin dynamically.
Base class for FunctionInternal and LinsolInternal.
bool verbose_
Verbose printout.
void clear_mem()
Clear all memory (called from destructor)
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
bool is_vector() const
Check if the pattern is a row or column vector.
Definition: sparsity.cpp:289
casadi_int size1() const
Get the number of rows.
Definition: sparsity.cpp:124
static Sparsity diag(casadi_int nrow)
Create diagonal sparsity pattern *.
Definition: sparsity.hpp:190
static Sparsity dense(casadi_int nrow, casadi_int ncol=1)
Create a dense rectangular sparsity pattern *.
Definition: sparsity.cpp:1012
void spsolve(bvec_t *X, bvec_t *B, bool tr) const
Propagate sparsity through a linear solve.
Definition: sparsity.cpp:723
bool is_scalar(bool scalar_and_dense=false) const
Is scalar?
Definition: sparsity.cpp:269
casadi_int size2() const
Get the number of columns.
Definition: sparsity.cpp:128
std::pair< casadi_int, casadi_int > size() const
Get the shape.
Definition: sparsity.cpp:152
bool is_empty(bool both=false) const
Check if the sparsity is empty.
Definition: sparsity.cpp:144
bool is_singular() const
Check whether the sparsity-pattern indicates structural singularity.
Definition: sparsity.cpp:1299
bool is_dense() const
Is dense?
Definition: sparsity.cpp:273
std::vector< std::string > dyn_out()
Get output scheme of a DAE function.
Definition: integrator.cpp:236
std::vector< std::string > event_in()
Get input scheme of an event transition function.
Definition: integrator.cpp:256
bool has_integrator(const std::string &name)
Check if a particular plugin is available.
Definition: integrator.cpp:122
std::vector< std::string > dyn_in()
Get input scheme of a DAE function.
Definition: integrator.cpp:232
casadi_int integrator_n_out()
Get the number of integrator outputs.
Definition: integrator.cpp:228
casadi_int dyn_n_in()
Get the number of inputs for a DAE function.
Definition: integrator.cpp:248
std::vector< std::string > integrator_out()
Get integrator output scheme of integrators.
Definition: integrator.cpp:190
std::vector< std::string > event_out()
Get output scheme of an event transition functions.
Definition: integrator.cpp:260
void load_integrator(const std::string &name)
Explicitly load a plugin dynamically.
Definition: integrator.cpp:126
casadi_int integrator_n_in()
Get the number of integrator inputs.
Definition: integrator.cpp:224
std::vector< std::string > integrator_in()
Get input scheme of integrators.
Definition: integrator.cpp:184
Function integrator(const std::string &name, const std::string &solver, const SXDict &dae, const Dict &opts)
Definition: integrator.cpp:134
std::string doc_integrator(const std::string &name)
Get the documentation string for a plugin.
Definition: integrator.cpp:130
casadi_int dyn_n_out()
Get the number of outputs for a DAE function.
Definition: integrator.cpp:252
std::vector< std::string > rootfinder_options(const std::string &name)
Get all options for a plugin.
Definition: rootfinder.cpp:87
Function rootfinder(const std::string &name, const std::string &solver, const SXDict &rfp, const Dict &opts)
Definition: rootfinder.cpp:111
The casadi namespace.
Definition: archiver.cpp:28
std::map< std::string, MX > MXDict
Definition: mx.hpp:1009
@ STEP_H
Step size.
@ STEP_T
Current time.
@ STEP_U
Controls.
@ STEP_X0
State vector.
@ STEP_P
Parameter.
@ STEP_NUM_IN
Number of arguments.
@ STEP_V0
Dependent variables.
IntegratorOutput
Output arguments of an integrator.
Definition: integrator.hpp:243
@ INTEGRATOR_ADJ_U
Adjoint sensitivities corresponding to the control vector.
Definition: integrator.hpp:257
@ INTEGRATOR_ADJ_Z0
Adjoint sensitivities corresponding to the algebraic variable guess.
Definition: integrator.hpp:253
@ INTEGRATOR_QF
Quadrature state at all output times.
Definition: integrator.hpp:249
@ INTEGRATOR_ADJ_P
Adjoint sensitivities corresponding to the parameter vector.
Definition: integrator.hpp:255
@ INTEGRATOR_ZF
Algebraic variable at all output times.
Definition: integrator.hpp:247
@ INTEGRATOR_XF
Differential state at all output times.
Definition: integrator.hpp:245
@ INTEGRATOR_NUM_OUT
Number of output arguments of an integrator.
Definition: integrator.hpp:259
@ INTEGRATOR_ADJ_X0
Adjoint sensitivities corresponding to the initial state.
Definition: integrator.hpp:251
IntegratorInput
Input arguments of an integrator.
Definition: integrator.hpp:223
@ INTEGRATOR_U
Piecewise constant control, a new control interval starts at each output time.
Definition: integrator.hpp:231
@ INTEGRATOR_ADJ_QF
Adjoint seeds corresponding to the quadratures at the output times.
Definition: integrator.hpp:237
@ INTEGRATOR_ADJ_ZF
Adjoint seeds corresponding to the algebraic variables at the output times.
Definition: integrator.hpp:235
@ INTEGRATOR_P
Parameters.
Definition: integrator.hpp:229
@ INTEGRATOR_ADJ_XF
Adjoint seeds corresponding to the states at the output times.
Definition: integrator.hpp:233
@ INTEGRATOR_Z0
Initial guess for the algebraic variable at the initial time.
Definition: integrator.hpp:227
@ INTEGRATOR_NUM_IN
Number of input arguments of an integrator.
Definition: integrator.hpp:239
@ INTEGRATOR_X0
Differential state at the initial time.
Definition: integrator.hpp:225
unsigned long long bvec_t
@ STEP_XF
State vector at next time.
@ STEP_QF
Quadrature state contribution.
@ STEP_VF
Dependent variables at next time.
@ STEP_NUM_OUT
Number of arguments.
EventIn
Inputs of an event transition function.
Definition: integrator.hpp:207
@ EVENT_INDEX
Definition: integrator.hpp:208
@ EVENT_NUM_IN
Definition: integrator.hpp:214
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
DynIn
Inputs of the symbolic representation of the DAE.
Definition: integrator.hpp:190
@ DYN_NUM_IN
Definition: integrator.hpp:196
EventOut
Outputs of an event transition function.
Definition: integrator.hpp:217
@ EVENT_POST_Z
Definition: integrator.hpp:219
@ EVENT_POST_X
Definition: integrator.hpp:218
@ EVENT_NUM_OUT
Definition: integrator.hpp:220
void casadi_fill(T1 *x, casadi_int n, T1 alpha)
FILL: x <- alpha.
@ OT_DOUBLEVECTOR
std::map< std::string, SX > SXDict
Definition: sx_fwd.hpp:40
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
const double inf
infinity
Definition: calculus.hpp:50
DynOut
Outputs of the symbolic representation of the DAE.
Definition: integrator.hpp:199
@ DYN_NUM_OUT
Definition: integrator.hpp:204
void update_dict(Dict &target, const Dict &source, bool recurse)
Update the target dictionary in place with source elements.
std::string to_string(TypeFmi2 v)
void casadi_axpy(casadi_int n, T1 alpha, const T1 *x, T1 *y)
AXPY: y <- a*x + y.
void casadi_clear(T1 *x, casadi_int n)
CLEAR: x <- 0.
double simplify(double x)
Definition: calculus.hpp:271
Options metadata for a class.
Definition: options.hpp:40
Memory struct, forward sparsity pattern propagation.
Memory struct, backward sparsity pattern propagation.