linear_interpolant.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 "linear_interpolant.hpp"
27 
28 namespace casadi {
29 
30  extern "C"
31  int CASADI_INTERPOLANT_LINEAR_EXPORT
32  casadi_register_interpolant_linear(Interpolant::Plugin* plugin) {
33  plugin->creator = LinearInterpolant::creator;
34  plugin->name = "linear";
35  plugin->doc = LinearInterpolant::meta_doc.c_str();
36  plugin->version = CASADI_VERSION;
37  plugin->options = &LinearInterpolant::options_;
38  plugin->deserialize = &LinearInterpolant::deserialize;
39  plugin->exposed.do_inline = &LinearInterpolant::do_inline;
40  return 0;
41  }
42 
43  extern "C"
44  void CASADI_INTERPOLANT_LINEAR_EXPORT casadi_load_interpolant_linear() {
46  }
47 
48  const Options LinearInterpolant::options_
50  {{"lookup_mode",
52  "Sets, for each grid dimenion, the lookup algorithm used to find the correct index. "
53  "'linear' uses a for-loop + break; "
54  "'exact' uses floored division (only for uniform grids)."}}
55  }
56  };
57 
59  LinearInterpolant(const std::string& name,
60  const std::vector<double>& grid,
61  const std::vector<casadi_int>& offset,
62  const std::vector<double>& values,
63  casadi_int m)
64  : Interpolant(name, grid, offset, values, m) {
65  }
66 
68  clear_mem();
69  }
70 
72  clear_mem();
73  }
74 
75  void LinearInterpolant::init(const Dict& opts) {
76  // Call the base class initializer
77  Interpolant::init(opts);
78 
80 
81  // Needed by casadi_interpn
82  alloc_w(ndim_, true);
83  alloc_iw(2*ndim_, true);
84  }
85 
87  eval(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const {
88  setup(mem, arg, res, iw, w);
89  if (res[0]) {
90  const double* values = has_parametric_values() ? arg[arg_values()] : get_ptr(values_);
91  const double* grid = has_parametric_grid() ? arg[arg_grid()] : get_ptr(grid_);
92  casadi_interpn(res[0], ndim_, grid, get_ptr(offset_),
93  values, arg[0], get_ptr(lookup_mode_), m_, iw, w);
94  }
95  return 0;
96  }
97 
99  std::string values = has_parametric_values() ? g.arg(arg_values()) : g.constant(values_);
100  std::string grid = has_parametric_grid() ? g.arg(arg_grid()) : g.constant(grid_);
101  g << " if (res[0]) {\n"
102  << " " << g.interpn("res[0]", ndim_, grid, g.constant(offset_),
103  values, "arg[0]", g.constant(lookup_mode_), m_, "iw", "w") << "\n"
104  << " }\n";
105  }
106 
108  get_jacobian(const std::string& name,
109  const std::vector<std::string>& inames,
110  const std::vector<std::string>& onames,
111  const Dict& opts) const {
112  Function ret;
113  ret.own(new LinearInterpolantJac(name));
114  ret->construct(opts);
115  return ret;
116  }
117 
119  get_jacobian(const std::string& name,
120  const std::vector<std::string>& inames,
121  const std::vector<std::string>& onames,
122  const Dict& opts) const {
123  std::vector<MX> args = mx_in();
124  std::vector<MX> res(n_out_);
125  for (casadi_int i=0;i<n_out_;++i)
126  res[i] = DM(size1_out(i), size2_out(i));
127  Function f("f", args, res);
128 
129  return f->get_jacobian(name, inames, onames, Dict());
130  }
131 
132  void LinearInterpolantJac::init(const Dict& opts) {
133  // Call the base class initializer
135 
136  // Needed by casadi_interpn
138  alloc_w(2*m->ndim_ + m->m_, true);
139  alloc_iw(2*m->ndim_, true);
140  }
141 
143  eval(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const {
145 
146  const double* values = has_parametric_values() ? arg[m->arg_values()] : get_ptr(m->values_);
147  const double* grid = has_parametric_grid() ? arg[m->arg_grid()] : get_ptr(m->grid_);
148 
149  casadi_interpn_grad(res[0], m->ndim_, grid, get_ptr(m->offset_),
150  values, arg[0], get_ptr(m->lookup_mode_), m->m_, iw, w);
151  return 0;
152  }
153 
156  return m->has_parametric_values();
157  }
158 
161  return m->has_parametric_grid();
162  }
163 
165 
167  std::string values = has_parametric_values() ? g.arg(m->arg_values()) : g.constant(m->values_);
168  std::string grid = has_parametric_grid() ? g.arg(m->arg_grid()) : g.constant(m->grid_);
169 
170  g << " " << g.interpn_grad("res[0]", m->ndim_,
171  grid, g.constant(m->offset_), values,
172  "arg[0]", g.constant(m->lookup_mode_), m->m_, "iw", "w") << "\n";
173  }
174 
175 
177  s.unpack("LinearInterpolant::lookup_mode", lookup_mode_);
178  }
179 
181  s.version("LinearInterpolant", 1);
182  char type;
183  s.unpack("LinearInterpolant::type", type);
184  switch (type) {
185  case 'f': return new LinearInterpolant(s);
186  case 'j': return new LinearInterpolantJac(s);
187  default:
188  casadi_error("LinearInterpolant::deserialize error");
189  }
190  }
191 
194  s.pack("LinearInterpolant::lookup_mode", lookup_mode_);
195  }
196 
199  s.version("LinearInterpolant", 1);
200  s.pack("LinearInterpolant::type", 'f');
201  }
202 
206  m->PluginInterface<Interpolant>::serialize_type(s);
207  s.version("LinearInterpolant", 1);
208  s.pack("LinearInterpolant::type", 'j');
209  }
210 
211 
212  Function LinearInterpolant::do_inline(const std::string& name,
213  const std::vector<double>& grid,
214  const std::vector<casadi_int>& offset,
215  const std::vector<double>& values,
216  casadi_int m,
217  const Dict& opts) {
218 
219  // Number of grid points
220  casadi_int ndim = offset.size()-1;
221 
222  MX x = MX::sym("x", ndim);
223  MX g;
224  if (grid.empty()) {
225  g = MX::sym("g", offset.back());
226  } else {
227  g = MX(DM(grid));
228  }
229  MX c;
230  if (values.empty()) {
231  c = MX::sym("c", Interpolant::coeff_size(offset, m));
232  } else {
233  c = MX(DM(values));
234  }
235 
236  MX f = MX::interpn_linear(vertsplit(g, offset), c, vertsplit(x), opts);
237 
238  std::vector<MX> args = {x};
239  std::vector<std::string> arg_names = {"x"};
240  if (grid.empty()) {
241  args.push_back(g);
242  arg_names.push_back("g");
243  }
244  if (values.empty()) {
245  args.push_back(c);
246  arg_names.push_back("c");
247  }
248 
249  return Function(name, args, {f.T()}, arg_names, {"f"});
250  }
251 
252 } // namespace casadi
Helper class for C code generation.
std::string arg(casadi_int i) const
Refer to argument.
std::string constant(const std::vector< casadi_int > &v)
Represent an array constant; adding it when new.
std::string interpn(const std::string &res, casadi_int ndim, const std::string &grid, const std::string &offset, const std::string &values, const std::string &x, const std::string &lookup_mode, casadi_int m, const std::string &iw, const std::string &w)
Multilinear interpolation.
std::string interpn_grad(const std::string &grad, casadi_int ndim, const std::string &grid, const std::string &offset, const std::string &values, const std::string &x, const std::string &lookup_mode, casadi_int m, const std::string &iw, const std::string &w)
Multilinear interpolation - calculate gradient.
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
void alloc_iw(size_t sz_iw, bool persistent=false)
Ensure required length of iw field.
void init(const Dict &opts) override
Initialize.
virtual const std::vector< MX > mx_in() const
Get function input(s) and output(s)
casadi_int size2_out(casadi_int ind) const
Input/output dimensions.
casadi_int size1_out(casadi_int ind) const
Input/output dimensions.
void serialize_type(SerializingStream &s) const override
Serialize type information.
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
virtual Function get_jacobian(const std::string &name, const std::vector< std::string > &inames, const std::vector< std::string > &onames, const Dict &opts) const
Return Jacobian of all input elements with respect to all output elements.
void setup(void *mem, const double **arg, double **res, casadi_int *iw, double *w) const
Set the (persistent and temporary) work vectors.
Function derivative_of_
If the function is the derivative of another function.
Function object.
Definition: function.hpp:60
FunctionInternal * get() const
Definition: function.cpp:353
static MX sym(const std::string &name, casadi_int nrow=1, casadi_int ncol=1)
Create an nrow-by-ncol symbolic primitive.
void own(Internal *node)
std::vector< std::string > lookup_modes_
static const Options options_
Options.
casadi_int coeff_size() const
Size of the flattened coefficients vector.
void init(const Dict &opts) override
Initialize.
std::vector< casadi_int > offset_
std::vector< double > grid_
bool has_parametric_grid() const
Is parametric?
std::vector< double > values_
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
casadi_int arg_values() const
casadi_int arg_grid() const
bool has_parametric_values() const
Is parametric?
void serialize_type(SerializingStream &s) const override
Serialize type information.
static std::vector< casadi_int > interpret_lookup_mode(const std::vector< std::string > &modes, const std::vector< double > &grid, const std::vector< casadi_int > &offset, const std::vector< casadi_int > &margin_left=std::vector< casadi_int >(), const std::vector< casadi_int > &margin_right=std::vector< casadi_int >())
Convert from (optional) lookup modes labels to enum.
bool has_parametric_values() const
Is parametric?
void serialize_type(SerializingStream &s) const override
Serialize type information.
void init(const Dict &opts) override
Initialize.
int eval(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Evaluate numerically.
~LinearInterpolantJac() override
Destructor.
void codegen_body(CodeGenerator &g) const override
Generate code for the body of the C function.
Function get_jacobian(const std::string &name, const std::vector< std::string > &inames, const std::vector< std::string > &onames, const Dict &opts) const override
Full Jacobian.
'linear' plugin for Interpolant Implements a multilinear interpolant: For 1D, the interpolating polyn...
int eval(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Evaluate numerically.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
void serialize_type(SerializingStream &s) const override
Serialize type information.
static Interpolant * creator(const std::string &name, const std::vector< double > &grid, const std::vector< casadi_int > &offset, const std::vector< double > &values, casadi_int m)
Create a new Interpolant.
static const Options options_
Options.
std::vector< casadi_int > lookup_mode_
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
void init(const Dict &opts) override
Initialize.
void codegen_body(CodeGenerator &g) const override
Generate code for the body of the C function.
Function get_jacobian(const std::string &name, const std::vector< std::string > &inames, const std::vector< std::string > &onames, const Dict &opts) const override
Full Jacobian.
static Function do_inline(const std::string &name, const std::vector< double > &grid, const std::vector< casadi_int > &offset, const std::vector< double > &values, casadi_int m, const Dict &opts)
LinearInterpolant(const std::string &name, const std::vector< double > &grid, const std::vector< casadi_int > &offset, const std::vector< double > &values, casadi_int m)
static const std::string meta_doc
A documentation string.
MX - Matrix expression.
Definition: mx.hpp:92
MX T() const
Transpose the matrix.
Definition: mx.cpp:1029
static MX interpn_linear(const std::vector< MX > &x, const MX &v, const std::vector< MX > &xq, const Dict &opts=Dict())
Low-level access to inlined linear interpolation.
Definition: mx.cpp:2659
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
Base class for FunctionInternal and LinsolInternal.
void construct(const Dict &opts)
Construct.
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.
The casadi namespace.
Definition: archiver.cpp:28
T1 casadi_interpn(casadi_int ndim, const T1 *grid, const casadi_int *offset, const T1 *values, const T1 *x, casadi_int *iw, T1 *w)
int CASADI_INTERPOLANT_LINEAR_EXPORT casadi_register_interpolant_linear(Interpolant::Plugin *plugin)
void CASADI_INTERPOLANT_LINEAR_EXPORT casadi_load_interpolant_linear()
@ OT_STRINGVECTOR
void casadi_interpn_grad(T1 *grad, casadi_int ndim, const T1 *grid, const casadi_int *offset, const T1 *values, const T1 *x, casadi_int *iw, T1 *w)
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
Matrix< double > DM
Definition: dm_fwd.hpp:33