1 /*
2  *    This file is part of CasADi.
3  *
4  *    CasADi -- A symbolic framework for dynamic optimization.
5  *    Copyright (C) 2010-2014 Joel Andersson, Joris Gillis, Moritz Diehl,
6  *                            K.U. Leuven. All rights reserved.
7  *    Copyright (C) 2011-2014 Greg Horn
8  *
9  *    CasADi is free software; you can redistribute it and/or
10  *    modify it under the terms of the GNU Lesser General Public
11  *    License as published by the Free Software Foundation; either
12  *    version 3 of the License, or (at your option) any later version.
13  *
14  *    CasADi is distributed in the hope that it will be useful,
15  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *    Lesser General Public License for more details.
18  *
19  *    You should have received a copy of the GNU Lesser General Public
20  *    License along with CasADi; if not, write to the Free Software
21  *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24 
25 
26 #ifndef CASADI_FUNCTION_INTERNAL_HPP
27 #define CASADI_FUNCTION_INTERNAL_HPP
28 
29 #include "function.hpp"
30 #include <set>
31 #include <stack>
32 #include "code_generator.hpp"
33 #include "importer.hpp"
34 #include "sparse_storage.hpp"
35 #include "options.hpp"
36 #include "shared_object_internal.hpp"
37 #include "timing.hpp"
38 #ifdef CASADI_WITH_THREAD
39 #ifdef CASADI_WITH_THREAD_MINGW
40 #include <mingw.mutex.h>
41 #else // CASADI_WITH_THREAD_MINGW
42 #include <mutex>
43 #endif // CASADI_WITH_THREAD_MINGW
44 #endif //CASADI_WITH_THREAD
45 
46 // This macro is for documentation purposes
47 #define INPUTSCHEME(name)
48 
49 // This macro is for documentation purposes
50 #define OUTPUTSCHEME(name)
51 
52 /// \cond INTERNAL
53 
54 namespace casadi {
55   template<typename T>
zip(const std::vector<std::string> & id,const std::vector<T> & mat)56   std::vector<std::pair<std::string, T>> zip(const std::vector<std::string>& id,
57                                              const std::vector<T>& mat) {
58     casadi_assert_dev(id.size()==mat.size());
59     std::vector<std::pair<std::string, T>> r(id.size());
60     for (casadi_uint i=0; i<r.size(); ++i) r[i] = make_pair(id[i], mat[i]);
61     return r;
62   }
63 
64   /** \brief Function memory with temporary work vectors */
65   struct CASADI_EXPORT ProtoFunctionMemory {
66     // Function specific statistics
67     std::map<std::string, FStats> fstats;
68 
69     // Short-hand for "total" fstats
70     FStats* t_total;
71 
72     // Add a statistic
add_statcasadi::ProtoFunctionMemory73     void add_stat(const std::string& s) {
74       bool added = fstats.insert(std::make_pair(s, FStats())).second;
75       casadi_assert(added, "Duplicate stat: '" + s + "'");
76     }
77   };
78 
79   /** \brief Function memory with temporary work vectors */
80   struct CASADI_EXPORT FunctionMemory : public ProtoFunctionMemory {
81   };
82 
83   /** \brief Base class for FunctionInternal and LinsolInternal
84     \author Joel Andersson
85     \date 2017
86   */
87   class CASADI_EXPORT ProtoFunction : public SharedObjectInternal {
88   public:
89     /** \brief Constructor */
90     ProtoFunction(const std::string& name);
91 
92     /** \brief  Destructor */
93     ~ProtoFunction() override = 0;
94 
95     /** \brief Construct
96         Prepares the function for evaluation
97      */
98     void construct(const Dict& opts);
99 
100     ///@{
101     /** \brief Options */
102     static const Options options_;
get_options() const103     virtual const Options& get_options() const { return options_;}
104     ///@}
105 
106     /// Reconstruct options dict
107     virtual Dict generate_options(bool is_temp=false) const;
108 
109     /** \brief Initialize
110         Initialize and make the object ready for setting arguments and evaluation.
111         This method is typically called after setting options but before evaluating.
112         If passed to another class (in the constructor), this class should invoke
113         this function when initialized. */
114     virtual void init(const Dict& opts);
115 
116     /** \brief Finalize the object creation
117         This function, which visits the class hierarchy in reverse order is run after
118         init() has been completed.
119     */
120     virtual void finalize();
121 
122     /// Checkout a memory object
123     int checkout() const;
124 
125     /// Release a memory object
126     void release(int mem) const;
127 
128     /// Memory objects
129     void* memory(int ind) const;
130 
131     /** \brief Create memory block */
alloc_mem() const132     virtual void* alloc_mem() const { return new ProtoFunctionMemory(); }
133 
134     /** \brief Initalize memory block */
135     virtual int init_mem(void* mem) const;
136 
137     /** \brief Free memory block */
free_mem(void * mem) const138     virtual void free_mem(void *mem) const { delete static_cast<ProtoFunctionMemory*>(mem); }
139 
140     /// Get all statistics
141     virtual Dict get_stats(void* mem) const;
142 
143     /** \brief Clear all memory (called from destructor) */
144     void clear_mem();
145 
146     /** \brief C-style formatted printing during evaluation */
147     void print(const char* fmt, ...) const;
148 
149     /** \brief C-style formatted printing to string */
150     void sprint(char* buf, size_t buf_sz, const char* fmt, ...) const;
151 
152     /** \brief Format time in a fixed width 8 format */
153     void format_time(char* buffer, double time) const;
154 
155     /** \brief Print timing statistics */
156     void print_time(const std::map<std::string, FStats>& fstats) const;
157 
158     /** \brief Serialize an object */
159     void serialize(SerializingStream &s) const;
160 
161     /** \brief Serialize an object without type information */
162     virtual void serialize_body(SerializingStream &s) const;
163     /** \brief Serialize type information */
serialize_type(SerializingStream & s) const164     virtual void serialize_type(SerializingStream &s) const {}
165 
166     /** \brief String used to identify the immediate FunctionInternal subclass */
serialize_base_function() const167     virtual std::string serialize_base_function() const {
168       return class_name();
169     }
170 
171   protected:
172     /** \brief Deserializing constructor */
173     explicit ProtoFunction(DeserializingStream& s);
174 
175     /// Name
176     std::string name_;
177 
178     /// Verbose printout
179     bool verbose_;
180 
181     // Print timing statistics
182     bool print_time_;
183 
184     // Print timing statistics
185     bool record_time_;
186 
187 #ifdef CASADI_WITH_THREAD
188     /// Mutex for thread safety
189     mutable std::mutex mtx_;
190 #endif // CASADI_WITH_THREAD
191 
192   private:
193     /// Memory objects
194     mutable std::vector<void*> mem_;
195 
196     /// Unused memory objects
197     mutable std::stack<casadi_int> unused_;
198   };
199 
200   /** \brief Internal class for Function
201       \author Joel Andersson
202       \date 2010-2015
203   */
204   class CASADI_EXPORT FunctionInternal : public ProtoFunction {
205     friend class Function;
206   public:
207     /** \brief Constructor */
208     FunctionInternal(const std::string& name);
209 
210     /** \brief  Destructor */
211     ~FunctionInternal() override = 0;
212 
213     /** \brief  Obtain solver name from Adaptor */
getAdaptorSolverName() const214     virtual std::string getAdaptorSolverName() const { return ""; }
215 
216     ///@{
217     /** \brief Options */
218     static const Options options_;
get_options() const219     const Options& get_options() const override { return options_;}
220     ///@}
221 
222     /// Reconstruct options dict
223     Dict generate_options(bool is_temp=false) const override;
224 
225     /** \brief Initialize */
226     void init(const Dict& opts) override;
227 
228     /** \brief Finalize the object creation */
229     void finalize() override;
230 
231     /** \brief Get a public class instance */
self() const232     Function self() const { return shared_from_this<Function>();}
233 
234     // Factory
235     virtual Function factory(const std::string& name,
236                              const std::vector<std::string>& s_in,
237                              const std::vector<std::string>& s_out,
238                              const Function::AuxOut& aux,
239                              const Dict& opts) const;
240 
241     // Get list of dependency functions
242     virtual std::vector<std::string> get_function() const;
243 
244     // Get a dependency function
245     virtual const Function& get_function(const std::string &name) const;
246 
247     // Check if a particular dependency exists
has_function(const std::string & fname) const248     virtual bool has_function(const std::string& fname) const {return false;}
249 
250     /** \brief Which variables enter with some order
251     * \param[in] s_in Input name
252     * \param[in] s_out Output name(s)
253     * \param[in] order Only 1 (linear) and 2 (nonlinear) allowed
254     * \param[in] tr   Flip the relationship. Return which expressions contain the variables
255     */
256     virtual std::vector<bool> which_depends(const std::string& s_in,
257                                            const std::vector<std::string>& s_out,
258                                            casadi_int order, bool tr=false) const;
259 
260     ///@{
261     /** \brief  Is the class able to propagate seeds through the algorithm? */
has_spfwd() const262     virtual bool has_spfwd() const { return false;}
has_sprev() const263     virtual bool has_sprev() const { return false;}
264     ///@}
265 
266     ///@{
267     /** \brief  Evaluate numerically */
268     int eval_gen(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const;
269     virtual int eval(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const;
270     ///@}
271 
272     /** \brief  Evaluate with symbolic scalars */
273     virtual int eval_sx(const SXElem** arg, SXElem** res,
274       casadi_int* iw, SXElem* w, void* mem) const;
275 
276     /** \brief  Evaluate with symbolic matrices */
277     virtual void eval_mx(const MXVector& arg, MXVector& res,
278                          bool always_inline, bool never_inline) const;
279 
280     ///@{
281     /** \brief Evaluate with DM matrices */
282     virtual std::vector<DM> eval_dm(const std::vector<DM>& arg) const;
has_eval_dm() const283     virtual bool has_eval_dm() const { return false;}
284     ///@}
285 
286     ///@{
287     /** \brief Evaluate a function, overloaded */
eval_gen(const SXElem ** arg,SXElem ** res,casadi_int * iw,SXElem * w,void * mem) const288     int eval_gen(const SXElem** arg, SXElem** res, casadi_int* iw, SXElem* w, void* mem) const {
289       return eval_sx(arg, res, iw, w, mem);
290     }
eval_gen(const bvec_t ** arg,bvec_t ** res,casadi_int * iw,bvec_t * w,void * mem) const291     int eval_gen(const bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w, void* mem) const {
292       return sp_forward(arg, res, iw, w, mem);
293     }
294     ///@}
295 
296     ///@{
297     /** \brief Call a function, overloaded */
298     void call_gen(const MXVector& arg, MXVector& res, casadi_int npar,
299                   bool always_inline, bool never_inline) const;
300 
301     template<typename D>
302     void call_gen(const std::vector<Matrix<D> >& arg, std::vector<Matrix<D> >& res,
303                   casadi_int npar, bool always_inline, bool never_inline) const;
304     ///@}
305 
306     /** \brief Call a function, templated */
307     template<typename M>
308       void call(const std::vector<M>& arg, std::vector<M>& res,
309                bool always_inline, bool never_inline) const;
310 
311     ///@{
312     /** Helper function
313      *
314      * \param npar[in] normal usage: 1, disallow pararallel calls: -1
315      * \param npar[out] required number of parallel calls (or -1)
316      */
317     static bool check_mat(const Sparsity& arg, const Sparsity& inp, casadi_int& npar);
318     ///@}
319 
320     ///@{
321     /** \brief Check if input arguments have correct length and dimensions
322      *
323      * Raises errors.
324      *
325      * \param npar[in] normal usage: 1, disallow pararallel calls: -1
326      * \param[out] npar: max number of horizontal repetitions across all arguments (or -1)
327      */
328     template<typename M>
329     void check_arg(const std::vector<M>& arg, casadi_int& npar) const;
330     ///@}
331 
332     ///@{
333     /** \brief Check if output arguments have correct length and dimensions
334      *
335      * Raises errors.
336      *
337      * \param npar[in] normal usage: 1, disallow pararallel calls: -1
338      * \param[out] npar: max number of horizontal repetitions across all arguments  (or -1)
339      */
340     template<typename M>
341     void check_res(const std::vector<M>& res, casadi_int& npar) const;
342     ///@}
343 
344     /** \brief Check if input arguments that needs to be replaced
345      *
346      * Raises errors
347      *
348      * \param npar[in] normal usage: 1, disallow pararallel calls: -1
349      * \param[out] npar: max number of horizontal repetitions across all arguments  (or -1)
350      */
351     template<typename M> bool
352     matching_arg(const std::vector<M>& arg, casadi_int& npar) const;
353 
354     /** \brief Check if output arguments that needs to be replaced
355      *
356      * Raises errors
357      *
358      * \param npar[in] normal usage: 1, disallow pararallel calls: -1
359      * \param[out] npar: max number of horizontal repetitions across all arguments  (or -1)
360      */
361     template<typename M> bool
362     matching_res(const std::vector<M>& arg, casadi_int& npar) const;
363 
364     /** \brief Replace 0-by-0 inputs
365      */
366     template<typename M> std::vector<M>
367     replace_arg(const std::vector<M>& arg, casadi_int npar) const;
368 
369     /** \brief Project sparsities
370      * */
371     template<typename M> std::vector<M>
372     project_arg(const std::vector<M>& arg, casadi_int npar) const;
373 
374     /** \brief Project sparsities
375      * */
376     template<typename M> std::vector<M>
377     project_res(const std::vector<M>& arg, casadi_int npar) const;
378 
379     /** \brief Replace 0-by-0 outputs */
380     template<typename M> std::vector<M>
381     replace_res(const std::vector<M>& res, casadi_int npar) const;
382 
383     /** \brief Replace 0-by-0 forward seeds */
384     template<typename M> std::vector<std::vector<M>>
385     replace_fseed(const std::vector<std::vector<M>>& fseed, casadi_int npar) const;
386 
387     /** \brief Replace 0-by-0 reverse seeds */
388     template<typename M> std::vector<std::vector<M>>
389     replace_aseed(const std::vector<std::vector<M>>& aseed, casadi_int npar) const;
390 
391     /** \brief Convert from/to input/output lists/map  */
392     /// @{
393     template<typename M>
394     std::map<std::string, M> convert_arg(const std::vector<M>& arg) const;
395     template<typename M>
396     std::vector<M> convert_arg(const std::map<std::string, M>& arg) const;
397     template<typename M>
398     std::map<std::string, M> convert_res(const std::vector<M>& res) const;
399     template<typename M>
400     std::vector<M> convert_res(const std::map<std::string, M>& res) const;
401     /// @}
402 
403     /** \brief Convert from/to flat vector of input/output nonzeros */
404     /// @{
405     std::vector<double> nz_in(const std::vector<DM>& arg) const;
406     std::vector<double> nz_out(const std::vector<DM>& res) const;
407     std::vector<DM> nz_in(const std::vector<double>& arg) const;
408     std::vector<DM> nz_out(const std::vector<double>& res) const;
409     ///@}
410 
is_diff_out(casadi_int i)411     virtual bool is_diff_out(casadi_int i) { return true; }
is_diff_in(casadi_int i)412     virtual bool is_diff_in(casadi_int i) { return true; }
413 
414     ///@{
415     /** \brief Forward mode AD, virtual functions overloaded in derived classes */
416     virtual void call_forward(const std::vector<MX>& arg, const std::vector<MX>& res,
417                             const std::vector<std::vector<MX> >& fseed,
418                             std::vector<std::vector<MX> >& fsens,
419                             bool always_inline, bool never_inline) const;
420     virtual void call_forward(const std::vector<SX>& arg, const std::vector<SX>& res,
421                             const std::vector<std::vector<SX> >& fseed,
422                             std::vector<std::vector<SX> >& fsens,
423                             bool always_inline, bool never_inline) const;
424     ///@}
425 
426     ///@{
427     /** \brief Reverse mode, virtual functions overloaded in derived classes */
428     virtual void call_reverse(const std::vector<MX>& arg, const std::vector<MX>& res,
429                             const std::vector<std::vector<MX> >& aseed,
430                             std::vector<std::vector<MX> >& asens,
431                             bool always_inline, bool never_inline) const;
432     virtual void call_reverse(const std::vector<SX>& arg, const std::vector<SX>& res,
433                             const std::vector<std::vector<SX> >& aseed,
434                             std::vector<std::vector<SX> >& asens,
435                             bool always_inline, bool never_inline) const;
436     ///@}
437 
438     /** \brief Parallel evaluation */
439     std::vector<MX> mapsum_mx(const std::vector<MX > &arg, const std::string& parallelization);
440 
441     /** \brief Do the derivative functions need nondifferentiated outputs? */
uses_output() const442     virtual bool uses_output() const {return false;}
443 
444     ///@{
445     /** \brief Return Jacobian of all input elements with respect to all output elements */
446     Function jacobian() const;
has_jacobian() const447     virtual bool has_jacobian() const { return false;}
448     virtual Function get_jacobian(const std::string& name,
449                                   const std::vector<std::string>& inames,
450                                   const std::vector<std::string>& onames,
451                                   const Dict& opts) const;
452     ///@}
453 
454     ///@{
455     /** \brief Return Jacobian of all input elements with respect to all output elements */
456     Function jac() const;
has_jac() const457     virtual bool has_jac() const { return false;}
458     virtual Function get_jac(const std::string& name,
459                              const std::vector<std::string>& inames,
460                              const std::vector<std::string>& onames,
461                              const Dict& opts) const;
462     ///@}
463 
464     ///@{
465     /** \brief Return function that calculates forward derivatives
466      *    forward(nfwd) returns a cached instance if available,
467      *    and calls <tt>Function get_forward(casadi_int nfwd)</tt>
468      *    if no cached version is available.
469      */
470     Function forward(casadi_int nfwd) const;
has_forward(casadi_int nfwd) const471     virtual bool has_forward(casadi_int nfwd) const { return false;}
472     virtual Function get_forward(casadi_int nfwd, const std::string& name,
473                                  const std::vector<std::string>& inames,
474                                  const std::vector<std::string>& onames,
475                                  const Dict& opts) const;
476     ///@}
477 
478     ///@{
479     /** \brief Return function that calculates adjoint derivatives
480      *    reverse(nadj) returns a cached instance if available,
481      *    and calls <tt>Function get_reverse(casadi_int nadj)</tt>
482      *    if no cached version is available.
483      */
484     Function reverse(casadi_int nadj) const;
has_reverse(casadi_int nadj) const485     virtual bool has_reverse(casadi_int nadj) const { return false;}
486     virtual Function get_reverse(casadi_int nadj, const std::string& name,
487                                  const std::vector<std::string>& inames,
488                                  const std::vector<std::string>& onames,
489                                  const Dict& opts) const;
490     ///@}
491 
492     /** \brief returns a new function with a selection of inputs/outputs of the original */
493     virtual Function slice(const std::string& name, const std::vector<casadi_int>& order_in,
494                            const std::vector<casadi_int>& order_out, const Dict& opts) const;
495 
496     /** \brief Get oracle */
497     virtual const Function& oracle() const;
498 
499     /** \brief Can derivatives be calculated in any way? */
500     bool has_derivative() const;
501 
502     /** \brief  Weighting factor for chosing forward/reverse mode */
503     virtual double ad_weight() const;
504 
505     /** \brief  Weighting factor for chosing forward/reverse mode,
506         sparsity propagation */
507     virtual double sp_weight() const;
508 
509     ///@{
510     /** \brief Get Jacobian sparsity */
511     Sparsity jacobian_sparsity() const;
has_jacobian_sparsity() const512     virtual bool has_jacobian_sparsity() const { return false;}
get_jacobian_sparsity() const513     virtual Sparsity get_jacobian_sparsity() const { return Sparsity(); }
514     ///@}
515 
516     ///@{
517     /** \brief Get function input(s) and output(s)  */
518     virtual const SX sx_in(casadi_int ind) const;
519     virtual const SX sx_out(casadi_int ind) const;
520     virtual const std::vector<SX> sx_in() const;
521     virtual const std::vector<SX> sx_out() const;
522     virtual const MX mx_in(casadi_int ind) const;
523     virtual const MX mx_out(casadi_int ind) const;
524     virtual const std::vector<MX> mx_in() const;
525     virtual const std::vector<MX> mx_out() const;
526     const DM dm_in(casadi_int ind) const;
527     const DM dm_out(casadi_int ind) const;
528     const std::vector<DM> dm_in() const;
529     const std::vector<DM> dm_out() const;
530     ///@}
531 
532     /// Get free variables (MX)
533     virtual std::vector<MX> free_mx() const;
534 
535     /// Get free variables (SX)
536     virtual std::vector<SX> free_sx() const;
537 
538     /** \brief Does the function have free variables */
has_free() const539     virtual bool has_free() const { return false;}
540 
541     /** \brief Extract the functions needed for the Lifted Newton method */
542     virtual void generate_lifted(Function& vdef_fcn, Function& vinit_fcn) const;
543 
544     /** \brief Get the number of atomic operations */
545     virtual casadi_int n_instructions() const;
546 
547     /** \brief Get an atomic operation operator index */
548     virtual casadi_int instruction_id(casadi_int k) const;
549 
550     /** \brief Get the (integer) input arguments of an atomic operation */
551     virtual std::vector<casadi_int> instruction_input(casadi_int k) const;
552 
553     /** \brief Get the floating point output argument of an atomic operation */
554     virtual double instruction_constant(casadi_int k) const;
555 
556     /** \brief Get the (integer) output argument of an atomic operation */
557     virtual std::vector<casadi_int> instruction_output(casadi_int k) const;
558 
559     /** \brief Number of nodes in the algorithm */
560     virtual casadi_int n_nodes() const;
561 
562     /** *\brief get MX expression associated with instruction */
563     virtual MX instruction_MX(casadi_int k) const;
564 
565     /** *\brief get SX expression associated with instructions */
566     virtual SX instructions_sx() const;
567 
568     /** \brief Wrap in an Function instance consisting of only one MX call */
569     Function wrap() const;
570 
571     /** \brief Wrap in an Function instance consisting of only one MX call */
572     Function wrap_as_needed(const Dict& opts) const;
573 
574     /** \brief Get function in cache */
575     bool incache(const std::string& fname, Function& f, const std::string& suffix="") const;
576 
577     /** \brief Save function to cache */
578     void tocache(const Function& f, const std::string& suffix="") const;
579 
580     /** \brief Generate code the function */
581     void codegen(CodeGenerator& g, const std::string& fname) const;
582 
583     /** \brief Generate meta-information allowing a user to evaluate a generated function */
584     void codegen_meta(CodeGenerator& g) const;
585 
586     /** \brief Codegen sparsities */
587     void codegen_sparsities(CodeGenerator& g) const;
588 
589     /** \brief Get name in codegen */
590     virtual std::string codegen_name(const CodeGenerator& g, bool ns=true) const;
591 
592     /** \brief Get thread-local memory object */
593     std::string codegen_mem(CodeGenerator& g, const std::string& index="mem") const;
594 
595     /** \brief Codegen incref for dependencies */
codegen_incref(CodeGenerator & g) const596     virtual void codegen_incref(CodeGenerator& g) const {}
597 
598     /** \brief Codegen decref for dependencies */
codegen_decref(CodeGenerator & g) const599     virtual void codegen_decref(CodeGenerator& g) const {}
600 
601     /** \brief Codegen decref for alloc_mem */
602     virtual void codegen_alloc_mem(CodeGenerator& g) const;
603 
604     /** \brief Codegen decref for init_mem */
605     virtual void codegen_init_mem(CodeGenerator& g) const;
606 
607     /** \brief Codegen for free_mem */
codegen_free_mem(CodeGenerator & g) const608     virtual void codegen_free_mem(CodeGenerator& g) const {}
609 
610     /** \brief Code generate the function  */
611     std::string signature(const std::string& fname) const;
612 
613     /** \brief Generate code for the declarations of the C function */
614     virtual void codegen_declarations(CodeGenerator& g) const;
615 
616     /** \brief Generate code for the function body */
617     virtual void codegen_body(CodeGenerator& g) const;
618 
619     /** \brief Thread-local memory object type */
codegen_mem_type() const620     virtual std::string codegen_mem_type() const { return ""; }
621 
622     /** \brief Export / Generate C code for the dependency function */
623     virtual std::string generate_dependencies(const std::string& fname, const Dict& opts) const;
624 
625     /** \brief Is codegen supported? */
has_codegen() const626     virtual bool has_codegen() const { return false;}
627 
628     /** \brief Jit dependencies */
jit_dependencies(const std::string & fname)629     virtual void jit_dependencies(const std::string& fname) {}
630 
631     /** \brief Export function in a specific language */
632     virtual void export_code(const std::string& lang,
633       std::ostream &stream, const Dict& options) const;
634 
635     /** \brief Serialize type information */
636     void serialize_type(SerializingStream &s) const override;
637 
638     /** \brief Serialize an object without type information */
639     void serialize_body(SerializingStream &s) const override;
640 
641     /** \brief Display object */
642     void disp(std::ostream& stream, bool more) const override;
643 
644     /** \brief  Print more */
disp_more(std::ostream & stream) const645     virtual void disp_more(std::ostream& stream) const {}
646 
647     /** \brief Get function signature: name:(inputs)->(outputs) */
648     std::string definition() const;
649 
650     /** \brief Print dimensions of inputs and outputs */
651     void print_dimensions(std::ostream &stream) const;
652 
653     /** \brief Print list of options */
654     void print_options(std::ostream &stream) const;
655 
656     /** \brief Print all information there is to know about a certain option */
657     void print_option(const std::string &name, std::ostream &stream) const;
658 
659     /** \brief Print free variables */
660     virtual std::vector<std::string> get_free() const;
661 
662     /** \brief Get the unidirectional or bidirectional partition */
663     void get_partition(casadi_int iind, casadi_int oind, Sparsity& D1, Sparsity& D2,
664                       bool compact, bool symmetric,
665                       bool allow_forward, bool allow_reverse) const;
666 
667     ///@{
668     /** \brief Number of input/output nonzeros */
669     casadi_int nnz_in() const;
nnz_in(casadi_int ind) const670     casadi_int nnz_in(casadi_int ind) const { return sparsity_in(ind).nnz(); }
671     casadi_int nnz_out() const;
nnz_out(casadi_int ind) const672     casadi_int nnz_out(casadi_int ind) const { return sparsity_out(ind).nnz(); }
673     ///@}
674 
675     ///@{
676     /** \brief Number of input/output elements */
677     casadi_int numel_in() const;
numel_in(casadi_int ind) const678     casadi_int numel_in(casadi_int ind) const { return sparsity_in(ind).numel(); }
numel_out(casadi_int ind) const679     casadi_int numel_out(casadi_int ind) const { return sparsity_out(ind).numel(); }
680     casadi_int numel_out() const;
681     ///@}
682 
683     ///@{
684     /** \brief Input/output dimensions */
size1_in(casadi_int ind) const685     casadi_int size1_in(casadi_int ind) const { return sparsity_in(ind).size1(); }
size2_in(casadi_int ind) const686     casadi_int size2_in(casadi_int ind) const { return sparsity_in(ind).size2(); }
size1_out(casadi_int ind) const687     casadi_int size1_out(casadi_int ind) const { return sparsity_out(ind).size1(); }
size2_out(casadi_int ind) const688     casadi_int size2_out(casadi_int ind) const { return sparsity_out(ind).size2(); }
size_in(casadi_int ind) const689     std::pair<casadi_int, casadi_int> size_in(casadi_int ind) const {
690       return sparsity_in(ind).size();
691     }
size_out(casadi_int ind) const692     std::pair<casadi_int, casadi_int> size_out(casadi_int ind) const {
693       return sparsity_out(ind).size();
694     }
695     ///@}
696 
697     ///@{
698     /** \brief Input/output sparsity */
sparsity_in(casadi_int ind) const699     const Sparsity& sparsity_in(casadi_int ind) const { return sparsity_in_.at(ind); }
sparsity_out(casadi_int ind) const700     const Sparsity& sparsity_out(casadi_int ind) const { return sparsity_out_.at(ind); }
701     ///@}
702 
703     ///@{
704     /** \brief Are all inputs and outputs scalar */
705     bool all_scalar() const;
706 
707     /// Generate the sparsity of a Jacobian block
708     virtual Sparsity getJacSparsity(casadi_int iind, casadi_int oind, bool symmetric) const;
709 
710     /// Get the sparsity pattern, forward mode
711     template<bool fwd>
712     Sparsity getJacSparsityGen(casadi_int iind, casadi_int oind, bool symmetric,
713                                 casadi_int gr_i=1, casadi_int gr_o=1) const;
714 
715     /// A flavor of getJacSparsity that does hierarchical block structure recognition
716     Sparsity getJacSparsityHierarchical(casadi_int iind, casadi_int oind) const;
717 
718     /** A flavor of getJacSparsity that does hierarchical block
719     * structure recognition for symmetric Jacobians
720     */
721     Sparsity getJacSparsityHierarchicalSymm(casadi_int iind, casadi_int oind) const;
722 
723     /// Get, if necessary generate, the sparsity of a Jacobian block
724     Sparsity& sparsity_jac(casadi_int iind, casadi_int oind, bool compact, bool symmetric) const;
725 
726     /// Filter out nonzeros in the full sparsity jacobian according to is_diff_in/out
727     Sparsity jacobian_sparsity_filter(const Sparsity& sp) const;
728 
729     /// Get a vector of symbolic variables corresponding to the outputs
730     virtual std::vector<MX> symbolic_output(const std::vector<MX>& arg) const;
731 
732     ///@{
733     /** \brief Number of function inputs and outputs */
734     virtual size_t get_n_in();
735     virtual size_t get_n_out();
736     ///@}
737 
738 
739     ///@{
740     /** \brief Names of function input and outputs */
741     virtual std::string get_name_in(casadi_int i);
742     virtual std::string get_name_out(casadi_int i);
743     ///@}
744 
745     /** \brief Get default input value */
get_default_in(casadi_int ind) const746     virtual double get_default_in(casadi_int ind) const {
747       return 0;
748     }
749 
750     /** \brief Get largest input value */
get_max_in(casadi_int ind) const751     virtual double get_max_in(casadi_int ind) const {
752       return inf;
753     }
754 
755     /** \brief Get smallest input value */
get_min_in(casadi_int ind) const756     virtual double get_min_in(casadi_int ind) const {
757       return -inf;
758     }
759 
760     /** \brief Get relative tolerance */
get_reltol() const761     virtual double get_reltol() const {
762       return eps;
763     }
764 
765     /** \brief Get absolute tolerance */
get_abstol() const766     virtual double get_abstol() const {
767       return eps;
768     }
769 
770     /** \brief Get sparsity of a given input */
771     virtual Sparsity get_sparsity_in(casadi_int i);
772 
773     /** \brief Get sparsity of a given output */
774     virtual Sparsity get_sparsity_out(casadi_int i);
775 
776     /** \brief Get input scheme index by name */
index_in(const std::string & name) const777     casadi_int index_in(const std::string &name) const {
778       for (casadi_int i=0; i<name_in_.size(); ++i) {
779         if (name_in_[i]==name) return i;
780       }
781       casadi_error("FunctionInternal::index_in: could not find entry \""
782                    + name + "\". Available names are: " + str(name_in_) + ".");
783       return -1;
784     }
785 
786     /** \brief Get output scheme index by name */
index_out(const std::string & name) const787     casadi_int index_out(const std::string &name) const {
788       for (casadi_int i=0; i<name_out_.size(); ++i) {
789         if (name_out_[i]==name) return i;
790       }
791       casadi_error("FunctionInternal::index_out: could not find entry \""
792                    + name + "\". Available names are: " + str(name_out_) + ".");
793       return -1;
794     }
795 
796     /** \brief  Propagate sparsity forward */
797     virtual int sp_forward(const bvec_t** arg, bvec_t** res,
798                             casadi_int* iw, bvec_t* w, void* mem) const;
799 
800     /** \brief  Propagate sparsity backwards */
801     virtual int sp_reverse(bvec_t** arg, bvec_t** res, casadi_int* iw, bvec_t* w, void* mem) const;
802 
803     /** \brief Get number of temporary variables needed */
804     void sz_work(size_t& sz_arg, size_t& sz_res, size_t& sz_iw, size_t& sz_w) const;
805 
806     /** \brief Get required length of arg field */
sz_arg() const807     size_t sz_arg() const { return sz_arg_per_ + sz_arg_tmp_;}
808 
809     /** \brief Get required length of res field */
sz_res() const810     size_t sz_res() const { return sz_res_per_ + sz_res_tmp_;}
811 
812     /** \brief Get required length of iw field */
sz_iw() const813     size_t sz_iw() const { return sz_iw_per_ + sz_iw_tmp_;}
814 
815     /** \brief Get required length of w field */
sz_w() const816     size_t sz_w() const { return sz_w_per_ + sz_w_tmp_;}
817 
818     /** \brief Ensure required length of arg field */
819     void alloc_arg(size_t sz_arg, bool persistent=false);
820 
821     /** \brief Ensure required length of res field */
822     void alloc_res(size_t sz_res, bool persistent=false);
823 
824     /** \brief Ensure required length of iw field */
825     void alloc_iw(size_t sz_iw, bool persistent=false);
826 
827     /** \brief Ensure required length of w field */
828     void alloc_w(size_t sz_w, bool persistent=false);
829 
830     /** \brief Ensure work vectors long enough to evaluate function */
831     void alloc(const Function& f, bool persistent=false);
832 
833     /** \brief Set the (persistent) work vectors */
set_work(void * mem,const double ** & arg,double ** & res,casadi_int * & iw,double * & w) const834     virtual void set_work(void* mem, const double**& arg, double**& res,
835                           casadi_int*& iw, double*& w) const {}
836 
837     /** \brief Set the (temporary) work vectors */
set_temp(void * mem,const double ** arg,double ** res,casadi_int * iw,double * w) const838     virtual void set_temp(void* mem, const double** arg, double** res,
839                           casadi_int* iw, double* w) const {}
840 
841     /** \brief Set the (persistent and temporary) work vectors */
842     void setup(void* mem, const double** arg, double** res, casadi_int* iw, double* w) const;
843 
844     ///@{
845     /** \brief Calculate derivatives by multiplying the full Jacobian and multiplying */
846     virtual bool fwdViaJac(casadi_int nfwd) const;
847     virtual bool adjViaJac(casadi_int nadj) const;
848     ///@}
849 
850     /** Obtain information about function */
851     virtual Dict info() const;
852 
853     /** \brief Generate/retrieve cached serial map */
854     Function map(casadi_int n, const std::string& parallelization) const;
855 
856     /** \brief Export an input file that can be passed to generate C code with a main */
857     void generate_in(const std::string& fname, const double** arg) const;
858     void generate_out(const std::string& fname, double** res) const;
859 
860     bool always_inline_, never_inline_;
861 
862     /// Number of inputs and outputs
863     size_t n_in_, n_out_;
864 
865     /// Are inputs and outputs differentiable?
866     std::vector<bool> is_diff_in_, is_diff_out_;
867 
868     /// Input and output sparsity
869     std::vector<Sparsity> sparsity_in_, sparsity_out_;
870 
871     /// Input and output scheme
872     std::vector<std::string> name_in_, name_out_;
873 
874     /** \brief  Use just-in-time compiler */
875     bool jit_;
876 
877     /** \brief  Cleanup jit source file */
878     bool jit_cleanup_;
879 
880     /** \brief  Serialize behaviour */
881     std::string jit_serialize_;
882 
883     /** \brief  Name if jit source file */
884     std::string jit_name_;
885 
886     std::string jit_base_name_;
887 
888     /** \brief Use a temporary name */
889     bool jit_temp_suffix_;
890 
891     /** \brief Numerical evaluation redirected to a C function */
892     eval_t eval_;
893 
894     /** \brief Checkout redirected to a C function */
895     casadi_checkout_t checkout_;
896 
897    /** \brief Release redirected to a C function */
898     casadi_release_t release_;
899 
900     /** \brief Dict of statistics (resulting from evaluate) */
901     Dict stats_;
902 
903     /** \brief Reference counting in codegen? */
904     bool has_refcount_;
905 
906     /// Function cache
907     mutable std::map<std::string, WeakRef> cache_;
908 
909     /// Cache for full Jacobian
910     mutable WeakRef jacobian_;
911 
912     /// Cache for sparsities of the Jacobian blocks
913     mutable SparseStorage<Sparsity> jac_sparsity_, jac_sparsity_compact_;
914 
915     /// Cache for full Jacobian sparsity
916     mutable Sparsity jacobian_sparsity_;
917 
918     /// If the function is the derivative of another function
919     Function derivative_of_;
920 
921     /// User-set field
922     void* user_data_;
923 
924     /// Just-in-time compiler
925     std::string compiler_plugin_;
926     Importer compiler_;
927     Dict jit_options_;
928 
929     /// Penalty factor for using a complete Jacobian to calculate directional derivatives
930     double jac_penalty_;
931 
932     // Types of derivative calculation permitted
933     bool enable_forward_, enable_reverse_, enable_jacobian_, enable_fd_;
934     bool enable_forward_op_, enable_reverse_op_, enable_jacobian_op_, enable_fd_op_;
935 
936     /// Weighting factor for derivative calculation and sparsity pattern calculation
937     double ad_weight_, ad_weight_sp_;
938 
939     /// Maximum number of sensitivity directions
940     casadi_int max_num_dir_;
941 
942     /// Errors are thrown when NaN is produced
943     bool regularity_check_;
944 
945     /// Errors are thrown if numerical values of inputs look bad
946     bool inputs_check_;
947 
948     // Finite difference step
949     Dict fd_options_;
950 
951     // Finite difference step size
952     double fd_step_;
953 
954     // Finite difference method
955     std::string fd_method_;
956 
957     // Print input/output
958     bool print_in_;
959     bool print_out_;
960 
961     // Dump input/output
962     bool dump_in_, dump_out_, dump_;
963 
964     // Directory to dump to
965     std::string dump_dir_;
966 
967     // Format to dump with
968     std::string dump_format_;
969 
970     // Forward/reverse options
971     Dict forward_options_, reverse_options_;
972 
973     // Store a reference to a custom Jacobian
974     Function custom_jacobian_;
975 
976     // Counter for unique names for dumping inputs and output
977     mutable casadi_int dump_count_ = 0;
978 #ifdef CASADI_WITH_THREAD
979     mutable std::mutex dump_count_mtx_;
980 #endif // CASADI_WITH_THREAD
981 
982     /** \brief Check if the function is of a particular type */
983     virtual bool is_a(const std::string& type, bool recursive) const;
984 
985     /** \brief Can a derivative direction be skipped */
986     template<typename MatType>
987     static bool purgable(const std::vector<MatType>& seed);
988 
989     /** \brief Symbolic expressions for the forward seeds */
990     template<typename MatType>
991     std::vector<std::vector<MatType> >
992     fwd_seed(casadi_int nfwd) const;
993 
994     /** \brief Symbolic expressions for the adjoint seeds */
995     template<typename MatType>
996     std::vector<std::vector<MatType> >
997     symbolicAdjSeed(casadi_int nadj, const std::vector<MatType>& v) const;
998 
999     /** Unified return status for solvers */
1000     enum UnifiedReturnStatus {
1001         SOLVER_RET_UNKNOWN,
1002         SOLVER_RET_SUCCESS,
1003         SOLVER_RET_LIMITED, // Out of time
1004         SOLVER_RET_NAN
1005     };
1006 
1007     static std::string string_from_UnifiedReturnStatus(UnifiedReturnStatus status);
1008 
1009     /** \brief Deserializing constructor */
1010     explicit FunctionInternal(DeserializingStream& e);
1011 
1012     /** \brief Deserialize with type disambiguation */
1013     static Function deserialize(DeserializingStream& s);
1014 
1015     static std::map<std::string, ProtoFunction* (*)(DeserializingStream&)> deserialize_map;
1016 
1017   protected:
1018     /** \brief Populate jac_sparsity_ and jac_sparsity_compact_ during initialization */
1019     void set_jac_sparsity(const Sparsity& sp);
1020 
1021   private:
1022     // @{
1023     /// Dumping functionality
1024     casadi_int get_dump_id() const;
1025     void dump_in(casadi_int id, const double** arg) const;
1026     void dump_out(casadi_int id, double** res) const;
1027     void dump() const;
1028     // @}
1029 
1030     /** \brief Memory that is persistent during a call (but not between calls) */
1031     size_t sz_arg_per_, sz_res_per_, sz_iw_per_, sz_w_per_;
1032 
1033     /** \brief Temporary memory inside a function */
1034     size_t sz_arg_tmp_, sz_res_tmp_, sz_iw_tmp_, sz_w_tmp_;
1035   };
1036 
1037   // Template implementations
1038   template<typename MatType>
purgable(const std::vector<MatType> & v)1039   bool FunctionInternal::purgable(const std::vector<MatType>& v) {
1040     for (auto i=v.begin(); i!=v.end(); ++i) {
1041       if (!i->is_zero()) return false;
1042     }
1043     return true;
1044   }
1045 
1046   template<typename MatType>
1047   std::vector<std::vector<MatType> >
1048   FunctionInternal::
fwd_seed(casadi_int nfwd) const1049   fwd_seed(casadi_int nfwd) const {
1050     std::vector<std::vector<MatType>> fseed(nfwd);
1051     for (casadi_int dir=0; dir<nfwd; ++dir) {
1052       fseed[dir].resize(n_in_);
1053       for (casadi_int iind=0; iind<n_in_; ++iind) {
1054         std::string n = "f" + str(dir) + "_" +  name_in_[iind];
1055         Sparsity sp = is_diff_in_[iind] ? sparsity_in(iind) : Sparsity(size_in(iind));
1056         fseed[dir][iind] = MatType::sym(n, sp);
1057       }
1058     }
1059     return fseed;
1060   }
1061 
1062   template<typename MatType>
1063   std::vector<std::vector<MatType> >
1064   FunctionInternal::
symbolicAdjSeed(casadi_int nadj,const std::vector<MatType> & v) const1065   symbolicAdjSeed(casadi_int nadj, const std::vector<MatType>& v) const {
1066     std::vector<std::vector<MatType> > aseed(nadj, v);
1067     for (casadi_int dir=0; dir<nadj; ++dir) {
1068       // Replace symbolic inputs
1069       casadi_int oind=0;
1070       for (typename std::vector<MatType>::iterator i=aseed[dir].begin();
1071           i!=aseed[dir].end();
1072           ++i, ++oind) {
1073         // Name of the adjoint seed
1074         std::stringstream ss;
1075         ss << "a";
1076         if (nadj>1) ss << dir << "_";
1077         ss << oind;
1078 
1079         // Save to matrix
1080         *i = MatType::sym(ss.str(), is_diff_out_[oind] ? i->sparsity() : Sparsity(i->size()));
1081 
1082       }
1083     }
1084     return aseed;
1085   }
1086 
1087   template<typename M>
call(const std::vector<M> & arg,std::vector<M> & res,bool always_inline,bool never_inline) const1088   void FunctionInternal::call(const std::vector<M>& arg, std::vector<M>& res,
1089                               bool always_inline, bool never_inline) const {
1090     // If all inputs are scalar ...
1091     if (all_scalar()) {
1092       // ... and some arguments are matrix-valued with matching dimensions ...
1093       bool matrix_call = false;
1094       std::pair<casadi_int, casadi_int> sz;
1095       for (auto&& a : arg) {
1096         if (!a.is_scalar() && !a.is_empty()) {
1097           if (!matrix_call) {
1098             // Matrix call
1099             matrix_call = true;
1100             sz = a.size();
1101           } else if (a.size()!=sz) {
1102             // Not same dimensions
1103             matrix_call = false;
1104             break;
1105           }
1106         }
1107       }
1108 
1109       // ... then, call multiple times
1110       if (matrix_call) {
1111         // Start with zeros
1112         res.resize(n_out_);
1113         M z = M::zeros(sz);
1114         for (auto&& a : res) a = z;
1115         // Call multiple times
1116         std::vector<M> arg1 = arg, res1;
1117         for (casadi_int c=0; c<sz.second; ++c) {
1118           for (casadi_int r=0; r<sz.first; ++r) {
1119             // Get scalar arguments
1120             for (casadi_int i=0; i<arg.size(); ++i) {
1121               if (arg[i].size()==sz) arg1[i] = arg[i](r, c);
1122             }
1123             // Call recursively with scalar arguments
1124             call(arg1, res1, always_inline, never_inline);
1125             // Get results
1126             casadi_assert_dev(res.size() == res1.size());
1127             for (casadi_int i=0; i<res.size(); ++i) res[i](r, c) = res1[i];
1128           }
1129         }
1130         // All elements assigned
1131         return;
1132       }
1133     }
1134 
1135     // Check if inputs need to be replaced
1136     casadi_int npar = 1;
1137     if (!matching_arg(arg, npar)) {
1138       return call(replace_arg(arg, npar), res, always_inline, never_inline);
1139     }
1140 
1141     // Call the type-specific method
1142     call_gen(arg, res, npar, always_inline, never_inline);
1143   }
1144 
1145   template<typename M>
1146   std::vector<M> FunctionInternal::
project_arg(const std::vector<M> & arg,casadi_int npar) const1147   project_arg(const std::vector<M>& arg, casadi_int npar) const {
1148     casadi_assert_dev(arg.size()==n_in_);
1149 
1150     // Which arguments require mapped evaluation
1151     std::vector<bool> mapped(n_in_);
1152     for (casadi_int i=0; i<n_in_; ++i) {
1153       mapped[i] = arg[i].size2()!=size2_in(i);
1154     }
1155 
1156     // Check if matching input sparsity
1157     std::vector<bool> matching(n_in_);
1158     bool any_mismatch = false;
1159     for (casadi_int i=0; i<n_in_; ++i) {
1160       if (mapped[i]) {
1161         matching[i] = arg[i].sparsity().is_stacked(sparsity_in(i), npar);
1162       } else {
1163         matching[i] = arg[i].sparsity()==sparsity_in(i);
1164       }
1165       any_mismatch = any_mismatch || !matching[i];
1166     }
1167 
1168     // Correct input sparsity
1169     if (any_mismatch) {
1170       std::vector<M> arg2(arg);
1171       for (casadi_int i=0; i<n_in_; ++i) {
1172         if (!matching[i]) {
1173           if (mapped[i]) {
1174             arg2[i] = project(arg2[i], repmat(sparsity_in(i), 1, npar));
1175           } else {
1176             arg2[i] = project(arg2[i], sparsity_in(i));
1177           }
1178         }
1179       }
1180       return arg2;
1181     }
1182     return arg;
1183   }
1184 
1185   template<typename M>
1186     std::vector<M> FunctionInternal::
project_res(const std::vector<M> & arg,casadi_int npar) const1187     project_res(const std::vector<M>& arg, casadi_int npar) const {
1188       return arg;
1189   }
1190 
1191   template<typename D>
1192   void FunctionInternal::
call_gen(const std::vector<Matrix<D>> & arg,std::vector<Matrix<D>> & res,casadi_int npar,bool always_inline,bool never_inline) const1193   call_gen(const std::vector<Matrix<D> >& arg, std::vector<Matrix<D> >& res,
1194            casadi_int npar, bool always_inline, bool never_inline) const {
1195     casadi_assert(!never_inline, "Call-nodes only possible in MX expressions");
1196     std::vector< Matrix<D> > arg2 = project_arg(arg, npar);
1197 
1198     // Which arguments require mapped evaluation
1199     std::vector<bool> mapped(n_in_);
1200     for (casadi_int i=0; i<n_in_; ++i) {
1201       mapped[i] = arg[i].size2()!=size2_in(i);
1202     }
1203 
1204     // Allocate results
1205     res.resize(n_out_);
1206     for (casadi_int i=0; i<n_out_; ++i) {
1207       if (!res[i].sparsity().is_stacked(sparsity_out(i), npar)) {
1208         res[i] = Matrix<D>::zeros(repmat(sparsity_out(i), 1, npar));
1209       }
1210     }
1211 
1212     // Allocate temporary memory if needed
1213     std::vector<casadi_int> iw_tmp(sz_iw());
1214     std::vector<D> w_tmp(sz_w());
1215 
1216     // Get pointers to input arguments
1217     std::vector<const D*> argp(sz_arg());
1218     for (casadi_int i=0; i<n_in_; ++i) argp[i]=get_ptr(arg2[i]);
1219 
1220     // Get pointers to output arguments
1221     std::vector<D*> resp(sz_res());
1222     for (casadi_int i=0; i<n_out_; ++i) resp[i]=get_ptr(res[i]);
1223 
1224     // For all parallel calls
1225     for (casadi_int p=0; p<npar; ++p) {
1226       // Call memory-less
1227       if (eval_gen(get_ptr(argp), get_ptr(resp),
1228                    get_ptr(iw_tmp), get_ptr(w_tmp), memory(0))) {
1229         casadi_error("Evaluation failed");
1230       }
1231       // Update offsets
1232       if (p==npar-1) break;
1233       for (casadi_int i=0; i<n_in_; ++i) if (mapped[i]) argp[i] += nnz_in(i);
1234       for (casadi_int i=0; i<n_out_; ++i) resp[i] += nnz_out(i);
1235     }
1236   }
1237 
1238   template<typename M>
check_arg(const std::vector<M> & arg,casadi_int & npar) const1239   void FunctionInternal::check_arg(const std::vector<M>& arg, casadi_int& npar) const {
1240     casadi_assert(arg.size()==n_in_, "Incorrect number of inputs: Expected "
1241                           + str(n_in_) + ", got " + str(arg.size()));
1242     for (casadi_int i=0; i<n_in_; ++i) {
1243       if (!check_mat(arg[i].sparsity(), sparsity_in(i), npar)) {
1244         // Dimensions
1245         std::string d_arg = str(arg[i].size1()) + "-by-" + str(arg[i].size2());
1246         std::string d_in = str(size1_in(i)) + "-by-" + str(size2_in(i));
1247         std::string e = "Input " + str(i) + " (" + name_in_[i] + ") has mismatching shape. "
1248                      "Got " + d_arg + ". Allowed dimensions, in general, are:\n"
1249                      " - The input dimension N-by-M (here " + d_in + ")\n"
1250                      " - A scalar, i.e. 1-by-1\n"
1251                      " - M-by-N if N=1 or M=1 (i.e. a transposed vector)\n"
1252                      " - N-by-M1 if K*M1=M for some K (argument repeated horizontally)\n";
1253         if (npar!=-1) {
1254           e += " - N-by-P*M, indicating evaluation with multiple arguments (P must be a "
1255                      "multiple of " + str(npar) + " for consistency with previous inputs)";
1256         }
1257         casadi_error(e);
1258       }
1259     }
1260   }
1261 
1262   template<typename M>
check_res(const std::vector<M> & res,casadi_int & npar) const1263   void FunctionInternal::check_res(const std::vector<M>& res, casadi_int& npar) const {
1264     casadi_assert(res.size()==n_out_, "Incorrect number of outputs: Expected "
1265                           + str(n_out_) + ", got " + str(res.size()));
1266     for (casadi_int i=0; i<n_out_; ++i) {
1267       casadi_assert(check_mat(res[i].sparsity(), sparsity_out(i), npar),
1268                     "Output " + str(i) + " (" + name_out_[i] + ") has mismatching shape. "
1269                     "Expected " + str(size_out(i)) + ", got " + str(res[i].size()));
1270     }
1271   }
1272 
1273   template<typename M>
matching_arg(const std::vector<M> & arg,casadi_int & npar) const1274   bool FunctionInternal::matching_arg(const std::vector<M>& arg, casadi_int& npar) const {
1275     check_arg(arg, npar);
1276     for (casadi_int i=0; i<n_in_; ++i) {
1277       if (arg.at(i).size1()!=size1_in(i)) return false;
1278       if (arg.at(i).size2()!=size2_in(i) && arg.at(i).size2()!=npar*size2_in(i)) return false;
1279     }
1280     return true;
1281   }
1282 
1283   template<typename M>
matching_res(const std::vector<M> & res,casadi_int & npar) const1284   bool FunctionInternal::matching_res(const std::vector<M>& res, casadi_int& npar) const {
1285     check_res(res, npar);
1286     for (casadi_int i=0; i<n_out_; ++i) {
1287       if (res.at(i).size1()!=size1_out(i)) return false;
1288       if (res.at(i).size2()!=size2_out(i) && res.at(i).size2()!=npar*size2_out(i)) return false;
1289     }
1290     return true;
1291   }
1292 
1293   template<typename M>
replace_mat(const M & arg,const Sparsity & inp,casadi_int npar)1294   M replace_mat(const M& arg, const Sparsity& inp, casadi_int npar) {
1295     if (arg.size()==inp.size()) {
1296       // Matching dimensions already
1297       return arg;
1298     } else if (arg.is_empty()) {
1299       // Empty matrix means set zero
1300       return M(inp.size());
1301     } else if (arg.is_scalar()) {
1302       // Scalar assign means set all
1303       return M(inp, arg);
1304     } else if (arg.is_vector() && inp.size()==std::make_pair(arg.size2(), arg.size1())) {
1305       // Transpose vector
1306       return arg.T();
1307     } else if (arg.size1()==inp.size1() && arg.size2()>0 && inp.size2()>0
1308                && inp.size2()%arg.size2()==0) {
1309       // Horizontal repmat
1310       return repmat(arg, 1, inp.size2()/arg.size2());
1311     } else {
1312       casadi_assert_dev(npar!=-1);
1313       // Multiple evaluation
1314       return repmat(arg, 1, (npar*inp.size2())/arg.size2());
1315     }
1316   }
1317 
1318   template<typename M>
1319   std::vector<M> FunctionInternal::
replace_arg(const std::vector<M> & arg,casadi_int npar) const1320   replace_arg(const std::vector<M>& arg, casadi_int npar) const {
1321     std::vector<M> r(arg.size());
1322     for (casadi_int i=0; i<r.size(); ++i) r[i] = replace_mat(arg[i], sparsity_in(i), npar);
1323     return r;
1324   }
1325 
1326   template<typename M>
1327   std::vector<M> FunctionInternal::
replace_res(const std::vector<M> & res,casadi_int npar) const1328   replace_res(const std::vector<M>& res, casadi_int npar) const {
1329     std::vector<M> r(res.size());
1330     for (casadi_int i=0; i<r.size(); ++i) r[i] = replace_mat(res[i], sparsity_out(i), npar);
1331     return r;
1332   }
1333 
1334   template<typename M>
1335   std::vector<std::vector<M> > FunctionInternal::
replace_fseed(const std::vector<std::vector<M>> & fseed,casadi_int npar) const1336   replace_fseed(const std::vector<std::vector<M> >& fseed, casadi_int npar) const {
1337     std::vector<std::vector<M> > r(fseed.size());
1338     for (casadi_int d=0; d<r.size(); ++d) r[d] = replace_arg(fseed[d], npar);
1339     return r;
1340   }
1341 
1342   template<typename M>
1343   std::vector<std::vector<M> > FunctionInternal::
replace_aseed(const std::vector<std::vector<M>> & aseed,casadi_int npar) const1344   replace_aseed(const std::vector<std::vector<M> >& aseed, casadi_int npar) const {
1345     std::vector<std::vector<M> > r(aseed.size());
1346     for (casadi_int d=0; d<r.size(); ++d) r[d] = replace_res(aseed[d], npar);
1347     return r;
1348   }
1349 
1350   template<typename M>
1351   std::map<std::string, M> FunctionInternal::
convert_arg(const std::vector<M> & arg) const1352   convert_arg(const std::vector<M>& arg) const {
1353     casadi_assert(arg.size()==n_in_, "Incorrect number of inputs: Expected "
1354                       + str(n_in_) + ", got " + str(arg.size()));
1355     std::map<std::string, M> ret;
1356     for (casadi_int i=0;i<n_in_;++i) {
1357       ret[name_in_[i]] = arg[i];
1358     }
1359     return ret;
1360   }
1361 
1362   template<typename M>
1363   std::vector<M> FunctionInternal::
convert_arg(const std::map<std::string,M> & arg) const1364   convert_arg(const std::map<std::string, M>& arg) const {
1365     // Get default inputs
1366     std::vector<M> arg_v(n_in_);
1367     for (casadi_int i=0; i<arg_v.size(); ++i) {
1368       arg_v[i] = get_default_in(i);
1369     }
1370 
1371     // Assign provided inputs
1372     for (auto&& e : arg) {
1373       arg_v.at(index_in(e.first)) = e.second;
1374     }
1375 
1376     return arg_v;
1377   }
1378 
1379   template<typename M>
1380   std::map<std::string, M> FunctionInternal::
convert_res(const std::vector<M> & res) const1381   convert_res(const std::vector<M>& res) const {
1382     casadi_assert(res.size()==n_out_, "Incorrect number of outputs: Expected "
1383                       + str(n_out_) + ", got " + str(res.size()));
1384     std::map<std::string, M> ret;
1385     for (casadi_int i=0;i<n_out_;++i) {
1386       ret[name_out_[i]] = res[i];
1387     }
1388     return ret;
1389   }
1390 
1391   template<typename M>
1392   std::vector<M> FunctionInternal::
convert_res(const std::map<std::string,M> & res) const1393   convert_res(const std::map<std::string, M>& res) const {
1394     // Get default inputs
1395     std::vector<M> res_v(n_out_);
1396     for (casadi_int i=0; i<res_v.size(); ++i) {
1397       res_v[i] = std::numeric_limits<double>::quiet_NaN();
1398     }
1399 
1400     // Assign provided inputs
1401     for (auto&& e : res) {
1402       M a = e.second;
1403       res_v.at(index_out(e.first)) = a;
1404     }
1405     return res_v;
1406   }
1407 
1408 } // namespace casadi
1409 
1410 /// \endcond
1411 
1412 #endif // CASADI_FUNCTION_INTERNAL_HPP
1413