26 #include "finite_differences.hpp"
73 {{
"second_order_stepsize",
75 "Second order perturbation size [default: 1e-3]"}},
78 "Step size [default: computed from abstol]"}},
81 "Maximum step size [default 0]"}},
84 "Minimum step size [default inf]"}},
87 "Smoothing regularization [default: machine precision]"}},
90 "Accuracy of function inputs [default: query object]"}},
93 "Accuracy of function outputs [default: query object]"}},
96 "Target ratio of roundoff error to truncation error [default: 100.]"}},
99 "Number of iterations to improve on the step-size "
100 "[default: 1 if error estimate available, otherwise 0]"}},
119 for (
auto&& op : opts) {
122 }
else if (op.first==
"h_min") {
124 }
else if (op.first==
"h_max") {
126 }
else if (op.first==
"reltol") {
128 }
else if (op.first==
"abstol") {
130 }
else if (op.first==
"smoothing") {
132 }
else if (op.first==
"u_aim") {
134 }
else if (op.first==
"h_iter") {
141 casadi_error(
"Perturbation size refinement requires an error estimate, "
142 "which is not available for the class '" +
class_name() +
"'. "
143 "Choose a different differencing scheme.");
155 casadi_message(
"Finite differences (" +
class_name() +
") with "
157 +
" outputs and " +
str(
n_) +
" directional derivatives.");
169 }
else if (i<n_in+n_out) {
202 }
else if (i<n_in+n_out) {
214 const std::vector<std::string>& inames,
215 const std::vector<std::string>& onames,
216 const Dict& opts)
const {
222 std::string f_name =
"fd_" + name;
226 f_opts[
"derivative_of"] = f;
233 casadi_int* iw,
double* w,
void* mem)
const {
234 setup(mem, arg, res, iw, w);
240 const double** x0 = arg;
245 for (casadi_int j=0; j<n_out; ++j) {
252 const double** seed = arg;
266 for (casadi_int j=0; j<
n_pert; ++j) {
267 yk[j] = w, w +=
n_y_;
272 for (casadi_int j=0; j<n_in; ++j) {
279 for (casadi_int j=0; j<n_out; ++j) {
285 for (casadi_int i=0; i<
n_; ++i) {
289 for (casadi_int iter=0; iter<1+
h_iter_; ++iter) {
291 for (casadi_int k=0; k<
n_pert; ++k) {
294 for (casadi_int j=0; j<n_in; ++j) {
306 double u =
calc_fd(yk, y0, J, h);
315 h *= sqrt(
u_aim_ / fmax(1., u));
323 for (casadi_int j=0; j<n_out; ++j) {
325 if (sens[j])
casadi_copy(J + off, nnz, sens[j] + i*nnz);
333 return casadi_forward_diff_old(yk, y0, J, h,
n_y_, &
m_);
337 return casadi_central_diff_old(yk, y0, J, h,
n_y_, &
m_);
350 g.
comment(
"Non-differentiated input");
351 g.
local(
"x0",
"const casadi_real",
"**");
352 g <<
"x0 = arg, arg += " << n_in <<
";\n";
354 g.
comment(
"Non-differentiated output");
355 g.
local(
"y0",
"casadi_real",
"*");
357 for (casadi_int j=0; j<n_out; ++j) {
359 g << g.
copy(
"*arg++", nnz,
"w") <<
" w += " << nnz <<
";\n";
363 g.
local(
"seed",
"const casadi_real",
"**");
364 g <<
"seed = arg, arg += " << n_in <<
";\n";
366 g.
comment(
"Forward sensitivities");
367 g.
local(
"sens",
"casadi_real",
"**");
368 g <<
"sens = res, res += " << n_out <<
";\n";
370 g.
comment(
"Finite difference approximation");
371 g.
local(
"J",
"casadi_real",
"*");
372 g <<
"J = w, w += " <<
n_y_ <<
";\n";
374 g.
comment(
"Perturbed function value");
375 g.
local(
"yk",
"casadi_real",
"**");
376 g <<
"yk = res, res += " <<
n_pert <<
";\n";
377 g.
local(
"j",
"casadi_int");
378 g <<
"for (j=0; j<" <<
n_pert <<
"; ++j) yk[j] = w, w += " <<
n_y_ <<
";\n";
380 g.
comment(
"Setup arg and z for evaluation");
381 g.
local(
"z",
"casadi_real",
"*");
383 for (casadi_int j=0; j<n_in; ++j) {
387 g.
comment(
"Setup res and y for evaluation");
388 g.
local(
"y",
"casadi_real",
"*");
390 for (casadi_int j=0; j<n_out; ++j) {
394 g.
comment(
"For all sensitivity directions");
395 g.
local(
"i",
"casadi_int");
396 g <<
"for (i=0; i<" <<
n_ <<
"; ++i) {\n";
399 g.
local(
"h",
"casadi_real");
400 g <<
"h = " <<
h_ <<
";\n";
402 g.
comment(
"Perform finite difference algorithm with different step sizes");
403 g.
local(
"iter",
"casadi_int");
404 g <<
"for (iter=0; iter<" << 1+
h_iter_ <<
"; ++iter) {\n";
406 g.
comment(
"Calculate perturbed function values");
407 g.
local(
"k",
"casadi_int");
408 g <<
"for (k=0; k<" <<
n_pert <<
"; ++k) {\n";
412 for (casadi_int j=0; j<n_in; ++j) {
414 std::string s =
"seed[" +
str(j) +
"]";
415 g << g.
copy(
"x0[" +
str(j) +
"]", nnz,
"z+" +
str(off)) <<
"\n"
416 <<
"if ("+s+
") " << g.
axpy(nnz,
pert(
"k"),
417 s+
"+i*"+
str(nnz),
"z+" +
str(off)) <<
"\n";
422 g <<
"if (" << g(
derivative_of_,
"arg",
"res",
"iw",
"w") <<
") return 1;\n";
425 g << g.
copy(
"y",
n_y_,
"yk[k]") <<
"\n";
429 g.
comment(
"Finite difference calculation with error estimate");
430 g.
local(
"u",
"casadi_real");
431 g.
local(
"m",
"const struct casadi_finite_diff_mem");
435 g <<
"u = " <<
calc_fd() <<
"(yk, y0, J, h, " <<
n_y_ <<
", &m);\n";
436 g <<
"if (iter==" <<
h_iter_ <<
") break;\n";
439 g <<
"if (u < 0) {\n";
441 g <<
"h /= " <<
u_aim_ <<
";\n";
444 g <<
"h *= sqrt(" <<
u_aim_ <<
" / fmax(1., u));\n";
451 g <<
"h = " << h <<
";\n";
456 g.
comment(
"Gather sensitivities");
458 for (casadi_int j=0; j<n_out; ++j) {
460 std::string s =
"sens[" +
str(j) +
"]";
461 g <<
"if (" << s <<
") " << g.
copy(
"J+" +
str(off), nnz, s +
"+i*" +
str(nnz)) <<
"\n";
468 std::string
sign =
"(2*(" + k +
"/2)-1)";
469 std::string len =
"(" + k +
"%%2+1)";
474 casadi_int
sign = 2*(k/2)-1;
475 casadi_int len = k%2+1;
476 return static_cast<double>(len*
sign)*h;
480 return casadi_smoothing_diff_old(yk, y0, J, h,
n_y_, &
m_);
484 const std::vector<std::string>& inames,
485 const std::vector<std::string>& onames,
486 const Dict& opts)
const {
491 const std::vector<std::string>& inames,
492 const std::vector<std::string>& onames,
493 const Dict& opts)
const {
CentralDiff(const std::string &name, casadi_int n)
std::string calc_fd() const override
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
Second order derivatives.
Helper class for C code generation.
std::string axpy(casadi_int n, const std::string &a, const std::string &x, const std::string &y)
Codegen axpy: y += a*x.
std::string add_dependency(const Function &f)
Add a function dependency.
std::string arg(casadi_int i) const
Refer to argument.
std::string copy(const std::string &arg, std::size_t n, const std::string &res)
Create a copy operation.
void comment(const std::string &s)
Write a comment line (ignored if not verbose)
void local(const std::string &name, const std::string &type, const std::string &ref="")
Declare a local variable.
std::string res(casadi_int i) const
Refer to resuly.
void init_local(const std::string &name, const std::string &def)
Specify the default value for a local variable.
void add_auxiliary(Auxiliary f, const std::vector< std::string > &inst={"casadi_real"})
Add a built-in auxiliary function.
size_t get_n_in() override
Number of function inputs and outputs.
int eval(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Evaluate numerically.
virtual casadi_int n_pert() const =0
void codegen_declarations(CodeGenerator &g) const override
Generate code for the declarations of the C function.
virtual double calc_stepsize(double abstol) const =0
void init(const Dict &opts) override
Initialize.
void codegen_body(CodeGenerator &g) const override
Generate code for the body of the C function.
Sparsity get_sparsity_in(casadi_int i) override
Sparsities of function inputs and outputs.
virtual std::string pert(const std::string &k) const =0
std::string get_name_in(casadi_int i) override
Names of function input and outputs.
double get_default_in(casadi_int ind) const override
Get default input value.
~FiniteDiff() override
Destructor.
virtual casadi_int has_err() const =0
std::string get_name_out(casadi_int i) override
Names of function input and outputs.
virtual std::string calc_fd() const =0
static const Options options_
Options.
size_t get_n_out() override
Number of function inputs and outputs.
Sparsity get_sparsity_out(casadi_int i) override
Sparsities of function inputs and outputs.
casadi_finite_diff_mem< double > m_
FiniteDiff(const std::string &name, casadi_int n)
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
Second order derivatives.
std::string calc_fd() const override
ForwardDiff(const std::string &name, casadi_int n)
Internal class for Function.
void init(const Dict &opts) override
Initialize.
void alloc_res(size_t sz_res, bool persistent=false)
Ensure required length of res field.
static const Options options_
Options.
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.
virtual double get_abstol() const
Get absolute tolerance.
void alloc(const Function &f, bool persistent=false, int num_threads=1)
Ensure work vectors long enough to evaluate function.
virtual double get_reltol() const
Get relative tolerance.
Function derivative_of_
If the function is the derivative of another function.
casadi_int nnz_out() const
Get number of output nonzeros.
const Sparsity & sparsity_out(casadi_int ind) const
Get sparsity of a given output.
const std::vector< std::string > & name_in() const
Get input scheme.
static Function create(FunctionInternal *node)
Create from node.
const Sparsity & sparsity_in(casadi_int ind) const
Get sparsity of a given input.
casadi_int n_out() const
Get the number of function outputs.
casadi_int n_in() const
Get the number of function inputs.
casadi_int nnz_in() const
Get number of input nonzeros.
const std::vector< std::string > & name_out() const
Get output scheme.
double default_in(casadi_int ind) const
Get default input value.
bool verbose_
Verbose printout.
void clear_mem()
Clear all memory (called from destructor)
virtual std::string class_name() const =0
Readable name of the internal class.
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
Second order derivatives.
std::string pert(const std::string &k) const override
std::string calc_fd() const override
Smoothing(const std::string &name, casadi_int n)
const double eps
Machine epsilon.
casadi_int n_fd_points(FdMode v)
Length of FD stencil, including unperturbed input.
casadi_int fd_offset(FdMode v)
Offset for FD stencil, i.e. index of unperturbed input.
double sign(double x)
Sign function, note that sign(nan) == nan.
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
std::string to_string(TypeFmi2 v)
void casadi_axpy(casadi_int n, T1 alpha, const T1 *x, T1 *y)
AXPY: y <- a*x + y.
Options metadata for a class.