finite_differences.hpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 
26 #ifndef CASADI_FINITE_DIFFERENCES_HPP
27 #define CASADI_FINITE_DIFFERENCES_HPP
28 
29 #include "function_internal.hpp"
30 
32 
33 namespace casadi {
34 
36 enum class FdMode {FORWARD, BACKWARD, CENTRAL, SMOOTHING, NUMEL};
37 
39 CASADI_EXPORT std::string to_string(FdMode v);
40 
42 CASADI_EXPORT casadi_int n_fd_points(FdMode v);
43 
45 CASADI_EXPORT casadi_int fd_offset(FdMode v);
46 
48 template<typename T1>
49 CASADI_EXPORT void finite_diff(FdMode v, const T1** yk, T1* J, T1 h, casadi_int n_y,
50  T1 smoothing) {
51  switch (v) {
52  case FdMode::FORWARD:
53  case FdMode::BACKWARD:
54  return casadi_forward_diff(yk, J, h, n_y);
55  case FdMode::CENTRAL:
56  return casadi_central_diff(yk, J, h, n_y);
57  case FdMode::SMOOTHING:
58  return casadi_smoothing_diff(yk, J, h, n_y, eps);
59  default:
60  casadi_error("FD mode " + to_string(v) + " not implemented");
61  }
62 }
63 
68 class CASADI_EXPORT FiniteDiff : public FunctionInternal {
69 public:
70  // Constructor (protected, use create function)
71  FiniteDiff(const std::string& name, casadi_int n);
72 
76  ~FiniteDiff() override;
77 
79 
82  static const Options options_;
83  const Options& get_options() const override { return options_;}
85 
87 
90  Sparsity get_sparsity_in(casadi_int i) override;
91  Sparsity get_sparsity_out(casadi_int i) override;
93 
97  double get_default_in(casadi_int ind) const override;
98 
100 
103  size_t get_n_in() override;
104  size_t get_n_out() override;
106 
108 
111  std::string get_name_in(casadi_int i) override;
112  std::string get_name_out(casadi_int i) override;
114 
118  void init(const Dict& opts) override;
119 
120  // Evaluate numerically
121  int eval(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const override;
122 
126  bool uses_output() const override {return true;}
127 
131  bool has_codegen() const override { return true;}
132 
136  void codegen_declarations(CodeGenerator& g) const override;
137 
141  void codegen_body(CodeGenerator& g) const override;
142 
143 protected:
144  // Number of function evaluations needed
145  virtual casadi_int n_pert() const = 0;
146 
147  // Get perturbation expression
148  virtual std::string pert(const std::string& k) const = 0;
149 
150  // Get perturbation expression
151  virtual double pert(casadi_int k, double h) const = 0;
152 
153  // Calculate finite difference approximation
154  virtual double calc_fd(double** yk, double* y0, double* J, double h) const = 0;
155 
156  // Codegen finite difference approximation
157  virtual std::string calc_fd() const = 0;
158 
159  // Is an error estimate available?
160  virtual casadi_int has_err() const = 0;
161 
162  // Calculate step size from absolute tolerance
163  virtual double calc_stepsize(double abstol) const = 0;
164 
165  // Number of directional derivatives
166  casadi_int n_;
167 
168  // Iterations to improve h
169  casadi_int h_iter_;
170 
171  // Perturbation
172  double h_;
173 
174  // Dimensions
175  casadi_int n_z_, n_y_;
176 
177  // Target ratio of truncation error to roundoff error
178  double u_aim_;
179 
180  // Allowed step size range
181  double h_min_, h_max_;
182 
183  // Memory object
185 };
186 
191 class CASADI_EXPORT ForwardDiff : public FiniteDiff {
192 public:
193  // Constructor
194  ForwardDiff(const std::string& name, casadi_int n) : FiniteDiff(name, n) {}
195 
199  ~ForwardDiff() override {}
200 
204  std::string class_name() const override {return "ForwardDiff";}
205 
206  // Number of function evaluations needed
207  casadi_int n_pert() const override {return 1;};
208 
209  // Get perturbation expression
210  std::string pert(const std::string& k) const override {
211  return str(h_);
212  }
213 
214  // Get perturbation expression
215  double pert(casadi_int k, double h) const override {
216  return h;
217  }
218 
219  // Calculate finite difference approximation
220  double calc_fd(double** yk, double* y0, double* J, double h) const override;
221 
222  // Codegen finite difference approximation
223  std::string calc_fd() const override {return "casadi_forward_diff_old";}
224 
225  // Is an error estimate available?
226  casadi_int has_err() const override {return false;}
227 
228  // Calculate step size from absolute tolerance
229  double calc_stepsize(double abstol) const override { return sqrt(abstol);}
230 
234  double get_abstol() const override { return h_;}
235 
237 
240  bool has_forward(casadi_int nfwd) const override { return true;}
241  Function get_forward(casadi_int nfwd, const std::string& name,
242  const std::vector<std::string>& inames,
243  const std::vector<std::string>& onames,
244  const Dict& opts) const override;
246 };
247 
252 class CASADI_EXPORT BackwardDiff : public ForwardDiff {
253 public:
254  // Constructor
255  BackwardDiff(const std::string& name, casadi_int n) : ForwardDiff(name, n) {}
256 
260  ~BackwardDiff() override {}
261 
265  std::string class_name() const override {return "BackwardDiff";}
266 
267  // Calculate step size from absolute tolerance
268  double calc_stepsize(double abstol) const override {
269  return -ForwardDiff::calc_stepsize(abstol);
270  }
271 };
272 
277 class CASADI_EXPORT CentralDiff : public FiniteDiff {
278 public:
279  // Constructor
280  CentralDiff(const std::string& name, casadi_int n) : FiniteDiff(name, n) {}
281 
285  ~CentralDiff() override {}
286 
290  std::string class_name() const override {return "CentralDiff";}
291 
292  // Number of function evaluations needed
293  casadi_int n_pert() const override {return 2;};
294 
295  // Get perturbation expression
296  std::string pert(const std::string& k) const override {
297  return "(2*" + k + "-1)*" + str(h_);
298  }
299 
300  // Get perturbation expression
301  double pert(casadi_int k, double h) const override {
302  return (2*static_cast<double>(k)-1)*h;
303  }
304 
305  // Calculate finite difference approximation
306  double calc_fd(double** yk, double* y0, double* J, double h) const override;
307 
308  // Codegen finite difference approximation
309  std::string calc_fd() const override {return "casadi_central_diff_old";}
310 
311  // Is an error estimate available?
312  casadi_int has_err() const override {return true;}
313 
314  // Calculate step size from absolute tolerance
315  double calc_stepsize(double abstol) const override { return pow(abstol, 1./3);}
316 
320  double get_abstol() const override { return h_*h_;}
321 
323 
326  bool has_forward(casadi_int nfwd) const override { return true;}
327  Function get_forward(casadi_int nfwd, const std::string& name,
328  const std::vector<std::string>& inames,
329  const std::vector<std::string>& onames,
330  const Dict& opts) const override;
332 };
333 
338 class CASADI_EXPORT Smoothing : public FiniteDiff {
339 public:
340  // Constructor
341  Smoothing(const std::string& name, casadi_int n) : FiniteDiff(name, n) {}
342 
346  ~Smoothing() override {}
347 
351  std::string class_name() const override {return "Smoothing";}
352 
353  // Number of function evaluations needed
354  casadi_int n_pert() const override {return 4;};
355 
356  // Get perturbation expression
357  std::string pert(const std::string& k) const override;
358 
359  // Get perturbation expression
360  double pert(casadi_int k, double h) const override;
361 
362  // Calculate finite difference approximation
363  double calc_fd(double** yk, double* y0, double* J, double h) const override;
364 
365  // Codegen finite difference approximation
366  std::string calc_fd() const override {return "casadi_smoothing_diff_old";}
367 
368  // Is an error estimate available?
369  casadi_int has_err() const override {return true;}
370 
371  // Calculate step size from absolute tolerance
372  double calc_stepsize(double abstol) const override { return pow(abstol, 1./3);}
373 
377  double get_abstol() const override { return h_*h_;}
378 
380 
383  bool has_forward(casadi_int nfwd) const override { return true;}
384  Function get_forward(casadi_int nfwd, const std::string& name,
385  const std::vector<std::string>& inames,
386  const std::vector<std::string>& onames,
387  const Dict& opts) const override;
389 };
390 
391 
392 } // namespace casadi
394 
395 #endif // CASADI_FINITE_DIFFERENCES_HPP
The casadi namespace.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.