26 #include "bspline_impl.hpp"
32 s.
unpack(
"BSpline::type", t);
39 casadi_error(
"Unknown BSpline type");
45 const std::vector<casadi_int>& offset,
46 const std::vector<casadi_int>& degree,
48 const std::vector<casadi_int>& lookup_mode) :
49 knots_(knots), offset_(offset), degree_(degree),
50 m_(m), lookup_mode_(lookup_mode) {
63 casadi_int n_dims = degree.size();
73 casadi_int n_dims = degree.size();
75 for (casadi_int k=0;k<n_dims-1;++k) {
78 sz += 2*degree[n_dims-1]+1;
84 const std::vector<casadi_int>& degree) {
86 for (casadi_int i=0;i<degree.size();++i) ret*=
offset[i+1]-
offset[i]-degree[i]-1;
91 const std::vector<casadi_int>& offset,
const std::vector<casadi_int>& degree) {
93 casadi_assert(n==expected,
94 "Expected " +
str(expected) +
" coefficients, but got " +
str(n) +
".");
98 const std::vector<casadi_int>& degree, casadi_int &coeffs_size,
99 std::vector<casadi_int>& coeffs_dims, std::vector<casadi_int>& strides) {
101 casadi_int n_dims = degree.size();
103 coeffs_dims.resize(n_dims+1);
105 for (casadi_int i=0;i<n_dims;++i) coeffs_dims[i+1] =
offset[i+1]-
offset[i]-degree[i]-1;
108 strides.resize(n_dims);
110 for (casadi_int i=0;i<n_dims-1;++i) {
111 strides[i+1] = strides[i]*coeffs_dims[i+1];
117 s.
pack(
"BSpline::type",
'n');
122 s.
pack(
"BSpline::type",
'p');
130 s.
pack(
"BSplineCommon::m",
m_);
160 const std::vector<casadi_int>& offset,
161 const std::vector<double>& coeffs,
162 const std::vector<casadi_int>& degree,
164 const std::vector<casadi_int>& lookup_mode) :
165 BSplineCommon(knots, offset, degree, m, lookup_mode), coeffs_(coeffs) {
166 casadi_assert_dev(x.
numel()==degree.size());
173 const std::vector<double>& knots,
174 const std::vector<casadi_int>& offset,
175 const std::vector<casadi_int>& degree,
177 const std::vector<casadi_int>& lookup_mode) :
179 casadi_assert_dev(x.
size1()==degree.size());
184 void get_boor(
const MX& x,
const MX& knots, casadi_int degree, casadi_int lookup_mode,
185 MX& start,
MX& boor) {
186 MX knots_clipped = knots(
range(degree, knots.
size1()-degree));
190 MX L = low(knots_clipped, x, low_opts);
191 start = fmin(L, knots.
size1()-2*degree-2);
194 boor_init(
Slice(), degree) = 1;
195 std::vector<MX> boor_full = horzsplit(
MX(boor_init));
196 casadi_int n_knots = 2*degree+2;
201 std::vector<MX> knv = horzsplit(kn);
205 for (casadi_int d=1;d<degree+1;++d) {
206 for (casadi_int i=0;i<n_knots-d-1;++i) {
207 MX bottom = knv[i+d]-knv[i];
208 MX b =
if_else_zero(bottom, (xt-knv[i])*boor_full[i]/(bottom+1e-100));
209 bottom = knv[i+d+1]-knv[i + 1];
210 b +=
if_else_zero(bottom, (knv[i+d+1]-xt)*boor_full[i+1]/(bottom+1e-100));
215 boor = horzcat(std::vector<MX>(boor_full.begin(), boor_full.begin()+degree+1));
219 static casadi_int
knot_size(
const std::vector<double>& k) {
return k.size(); }
224 const std::vector<K>& knots,
227 const std::vector<casadi_int>& degree,
228 const std::vector<casadi_int>& lookup_mode) {
230 casadi_int batch_x = x.
size2();
233 casadi_int N = knots.size();
234 std::vector<MX> xs = vertsplit(x);
237 std::vector<MX> starts(N);
238 std::vector< std::vector<MX> > boors(N);
239 for (casadi_int i=0;i<N;++i) {
241 get_boor(xs[i], knots[i], degree[i], lookup_mode[i], starts[i], boor);
242 boors[i] = horzsplit(boor.
T());
246 std::vector<casadi_int> strides = {m};
247 for (casadi_int i=0;i<N-1;++i) {
248 strides.push_back(strides.back()*(
knot_size(knots[i])-degree[i]-1));
252 MX start = mtimes(
DM(strides).
T(), vertcat(starts));
256 for (casadi_int i=0;i<N;++i) {
257 casadi_int n = degree[i]+1;
258 core = vec(repmat(core, 1, n)+repmat(strides[i]*
DM(
range(n)).
T(), core.
size1(), 1));
263 for (casadi_int k=0;k<batch_x;++k) {
266 MX c = reshape(coeffs(start(k)+core), m, -1);
270 for (casadi_int i=0;i<N;++i) {
271 boor = vec(mtimes(boor, boors[i][k].
T()));
274 res.push_back(mtimes(c, boor));
281 const std::vector<double>& coeffs,
282 const std::vector<casadi_int>& degree,
286 casadi_assert(x.
is_vector(),
"x argument must be a vector, got " + x.
dim() +
" instead.");
287 casadi_assert(x.
numel()==knots.size(),
"x argument length (" +
str(x.
numel()) +
") must match "
288 "number knot list length (" +
str(knots.size()) +
").");
289 casadi_assert(degree.size()==knots.size(),
"Degree list length (" +
str(degree.size()) +
") "
290 "must match knot list length (" +
str(knots.size()) +
").");
292 bool do_inline_flag =
false;
293 std::vector<std::string> lookup_mode;
295 for (
auto&&
op : opts) {
296 if (
op.first==
"inline") {
297 do_inline_flag =
op.second;
298 }
else if (
op.first==
"lookup_mode") {
299 lookup_mode =
op.second;
301 casadi_error(
"Unknown option '" +
op.first +
"'.");
305 std::vector<casadi_int>
offset;
306 std::vector<double> stacked;
310 std::vector<casadi_int> mode =
313 if (do_inline_flag) {
314 return do_inline(x, knots, coeffs, m, degree, mode);
322 const std::vector< std::vector<double> >& knots,
323 const std::vector<casadi_int>& degree,
327 casadi_assert(x.
is_vector(),
"x argument must be a vector, got " + x.
dim() +
" instead.");
328 casadi_assert(x.
numel()==knots.size(),
"x argument length (" +
str(x.
numel()) +
") must match "
329 "knot list length (" +
str(knots.size()) +
").");
330 casadi_assert(degree.size()==knots.size(),
"Degree list length (" +
str(degree.size()) +
") "
331 "must match knot list length (" +
str(knots.size()) +
").");
332 bool do_inline_flag =
false;
333 std::vector<std::string> lookup_mode;
335 for (
auto&&
op : opts) {
336 if (
op.first==
"inline") {
337 do_inline_flag =
op.second;
338 }
else if (
op.first==
"lookup_mode") {
339 lookup_mode =
op.second;
341 casadi_error(
"Unknown option '" +
op.first +
"'.");
345 std::vector<casadi_int>
offset;
346 std::vector<double> stacked;
349 std::vector<casadi_int> mode =
352 if (do_inline_flag) {
353 return do_inline(x, knots, coeffs, m, degree, mode);
361 const std::vector<MX>& knots,
362 const std::vector<casadi_int>& degree,
366 casadi_assert(x.
is_vector(),
"x argument must be a vector, got " + x.
dim() +
" instead.");
367 casadi_assert(x.
numel()==knots.size(),
"x argument length (" +
str(x.
numel()) +
") must match "
368 "knot list length (" +
str(knots.size()) +
").");
369 casadi_assert(degree.size()==knots.size(),
"Degree list length (" +
str(degree.size()) +
") "
370 "must match knot list length (" +
str(knots.size()) +
").");
373 std::vector<std::string> lookup_mode;
374 for (
auto&&
op : opts) {
375 if (
op.first==
"lookup_mode") {
376 lookup_mode =
op.second;
377 }
else if (
op.first!=
"inline") {
378 casadi_error(
"Unknown option '" +
op.first +
"'.");
383 std::vector<casadi_int>
offset(knots.size()+1);
385 for (casadi_int i=0; i<knots.size(); ++i) {
390 std::vector<casadi_int> mode =
394 return do_inline(x, knots, coeffs, m, degree, mode);
398 return "BSpline(" + arg.at(0) +
")";
402 return "BSplineParametric(" + arg.at(0) +
", " + arg.at(1) +
")";
406 const std::vector<bool>& unique)
const {
411 const std::vector<bool>& unique)
const {
416 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
418 std::lock_guard<std::mutex> lock(jac_cache_mtx_);
427 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
428 std::lock_guard<std::mutex> lock(jac_cache_mtx_);
437 std::vector<std::vector<MX> >& fsens)
const {
440 for (casadi_int d=0; d<fsens.size(); ++d) {
441 fsens[d][0] = mtimes(J, fseed[d][0]);
446 std::vector<std::vector<MX> >& asens)
const {
448 for (casadi_int d=0; d<aseed.size(); ++d) {
449 asens[d][0] += mtimes(JT, aseed[d][0]);
453 int BSpline::eval(
const double** arg,
double** res, casadi_int* iw,
double* w)
const {
454 if (!res[0])
return 0;
464 if (!res[0])
return 0;
474 const std::vector<casadi_int>& arg,
475 const std::vector<casadi_int>& res,
476 const std::vector<bool>& arg_is_ref,
477 std::vector<bool>& res_is_ref)
const {
478 casadi_int n_dims =
offset_.size()-1;
485 g <<
"CASADI_PREFIX(nd_boor_eval)(" << g.
work(res[0],
m_,
false) <<
"," << n_dims <<
","
492 const std::vector<casadi_int>& arg,
493 const std::vector<bool>& arg_is_ref)
const {
498 const std::vector<casadi_int>& arg,
499 const std::vector<bool>& arg_is_ref)
const {
500 return g.
work(arg[1],
dep(1).
nnz(), arg_is_ref[1]);
504 const std::vector< std::vector<double> >& knots,
505 const std::vector<casadi_int>& degree,
508 std::vector<casadi_int>
offset;
509 std::vector<double> stacked;
512 std::vector<std::string> lookup_mode;
513 auto it = opts.find(
"lookup_mode");
514 if (it!=opts.end()) lookup_mode = it->second;
515 std::vector<casadi_int> lookup_mode_int =
518 casadi_int n_dims = degree.size();
519 casadi_int N = x.size()/n_dims;
520 casadi_assert(N*n_dims==x.size(),
"Number of point coordinates (" +
str(x.size()) +
") "
521 "must be a multiple of the number of dimensions (" +
str(n_dims) +
").");
523 casadi_int coeffs_size;
524 std::vector<casadi_int> coeffs_dims, strides;
525 prepare(1,
offset, degree, coeffs_size, coeffs_dims, strides);
528 std::vector<double> contribution(coeffs_size);
529 std::vector<casadi_int> nz(coeffs_size);
531 std::vector<double> data;
532 std::vector<casadi_int> row, col;
534 std::vector<double> w(
n_w(degree));
535 std::vector<casadi_int> iw(
n_iw(degree));
537 for (casadi_int i=0;i<N;++i) {
538 std::fill(contribution.begin(), contribution.end(), 0.0);
543 data.insert(data.end(), contribution.begin(), contribution.begin()+
nnz);
544 col.insert(col.end(), nz.begin(), nz.begin()+
nnz);
545 row.insert(row.end(),
nnz, i);
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
std::vector< casadi_int > lookup_mode_
void ad_forward(const std::vector< std::vector< MX > > &fseed, std::vector< std::vector< MX > > &fsens) const override
Calculate forward mode directional derivatives.
std::vector< double > knots_
static casadi_int get_coeff_size(casadi_int m, const std::vector< casadi_int > &offset, const std::vector< casadi_int > °ree)
static size_t n_w(const std::vector< casadi_int > °ree)
Get required length of w field.
BSplineCommon(const std::vector< double > &knots, const std::vector< casadi_int > &offset, const std::vector< casadi_int > °ree, casadi_int m, const std::vector< casadi_int > &lookup_mode)
Constructor.
std::vector< casadi_int > degree_
size_t sz_w() const override
Get required length of w field.
std::vector< casadi_int > offset_
std::vector< casadi_int > coeffs_dims_
void generate(CodeGenerator &g, const std::vector< casadi_int > &arg, const std::vector< casadi_int > &res, const std::vector< bool > &arg_is_ref, std::vector< bool > &res_is_ref) const override
Generate code for the operation.
static void prepare(casadi_int m, const std::vector< casadi_int > &offset, const std::vector< casadi_int > °ree, casadi_int &coeffs_size, std::vector< casadi_int > &coeffs_dims, std::vector< casadi_int > &strides)
void ad_reverse(const std::vector< std::vector< MX > > &aseed, std::vector< std::vector< MX > > &asens) const override
Calculate reverse mode directional derivatives.
std::vector< casadi_int > strides_
size_t sz_iw() const override
Get required length of iw field.
static size_t n_iw(const std::vector< casadi_int > °ree)
Get required length of iw field.
static void check_coeffs(casadi_int n, casadi_int m, const std::vector< casadi_int > &offset, const std::vector< casadi_int > °ree)
virtual MX jac_cached() const =0
casadi_int op() const override
Get the operation.
static MXNode * deserialize(DeserializingStream &s)
Deserialize without type information.
MX jac(const MX &x, const T &coeffs) const
void serialize_type(SerializingStream &s) const override
Serialize type information.
std::string disp(const std::vector< std::string > &arg) const override
Print expression.
BSplineParametric(const MX &x, const MX &coeffs, const std::vector< double > &knots, const std::vector< casadi_int > &offset, const std::vector< casadi_int > °ree, casadi_int m, const std::vector< casadi_int > &lookup_mode)
Constructor.
std::string generate(CodeGenerator &g, const std::vector< casadi_int > &arg, const std::vector< bool > &arg_is_ref) const override
Generate code for the operation.
MX jac_cached() const override
int eval(const double **arg, double **res, casadi_int *iw, double *w) const override
Evaluate the function numerically.
void eval_mx(const std::vector< MX > &arg, std::vector< MX > &res, const std::vector< bool > &unique={}) const override
Evaluate symbolically (MX)
static MX create(const MX &x, const MX &coeffs, const std::vector< std::vector< double > > &knots, const std::vector< casadi_int > °ree, casadi_int m, const Dict &opts)
std::string generate(CodeGenerator &g, const std::vector< casadi_int > &arg, const std::vector< bool > &arg_is_ref) const override
Generate code for the operation.
static MX create(const MX &x, const std::vector< std::vector< double > > &knots, const std::vector< double > &coeffs, const std::vector< casadi_int > °ree, casadi_int m, const Dict &opts)
std::vector< double > coeffs_
MX jac_cached() const override
int eval(const double **arg, double **res, casadi_int *iw, double *w) const override
Evaluate the function numerically.
static DM dual(const std::vector< double > &x, const std::vector< std::vector< double > > &knots, const std::vector< casadi_int > °ree, const Dict &opts)
BSpline(const MX &x, const std::vector< double > &knots, const std::vector< casadi_int > &offset, const std::vector< double > &coeffs, const std::vector< casadi_int > °ree, casadi_int m, const std::vector< casadi_int > &lookup_mode)
Constructor.
std::string disp(const std::vector< std::string > &arg) const override
Print expression.
void eval_mx(const std::vector< MX > &arg, std::vector< MX > &res, const std::vector< bool > &unique={}) const override
Evaluate symbolically (MX)
void serialize_type(SerializingStream &s) const override
Serialize type information.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Helper class for C code generation.
std::string work(casadi_int n, casadi_int sz, bool is_ref) const
std::string constant(const std::vector< casadi_int > &v)
Represent an array constant; adding it when new.
std::string clear(const std::string &res, std::size_t n)
Create a fill operation.
void add_auxiliary(Auxiliary f, const std::vector< std::string > &inst={"casadi_real"})
Add a built-in auxiliary function.
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
casadi_int numel() const
Get the number of elements, size1()*size2()
bool is_empty(bool both=false) const
Check if the matrix is empty, i.e. if one of the dimensions is zero.
bool is_vector() const
Check if the matrix is a row or column vector.
casadi_int size2() const
Get the second dimension (i.e. number of columns)
casadi_int size1() const
Get the first dimension (i.e. number of rows)
std::string dim(bool with_nz=false) const
Get string representation of dimensions.
static MatType zeros(casadi_int nrow=1, casadi_int ncol=1)
Create a dense matrix or a matrix with specified sparsity with all entries zero.
static void stack_grid(const std::vector< std::vector< double > > &grid, std::vector< casadi_int > &offset, std::vector< double > &stacked)
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.
static std::string lookup_mode_from_enum(casadi_int lookup_mode)
Node class for MX objects.
virtual void serialize_type(SerializingStream &s) const
Serialize type information.
virtual casadi_int offset() const
MX get_bspline(const std::vector< double > &knots, const std::vector< casadi_int > &offset, const std::vector< double > &coeffs, const std::vector< casadi_int > °ree, casadi_int m, const std::vector< casadi_int > &lookup_mode) const
BSpline.
casadi_int nnz(casadi_int i=0) const
const MX & dep(casadi_int ind=0) const
dependencies - functions that have to be evaluated before this one
virtual void serialize_body(SerializingStream &s) const
Serialize an object without type information.
void set_sparsity(const Sparsity &sparsity)
Set the sparsity.
void set_dep(const MX &dep)
Set unary dependency.
MX T() const
Transpose the matrix.
void get_nz(MX &m, bool ind1, const Slice &kk) const
Get a set of nonzeros (what x.nz[k] does)
Matrix< Scalar > T() const
Transpose the matrix.
Helper class for Serialization.
void pack(const Sparsity &e)
Serializes an object to the output stream.
Class representing a Slice.
static Sparsity dense(casadi_int nrow, casadi_int ncol=1)
Create a dense rectangular sparsity pattern.
static Sparsity triplet(casadi_int nrow, casadi_int ncol, const std::vector< casadi_int > &row, const std::vector< casadi_int > &col, std::vector< casadi_int > &mapping, bool invert_mapping)
Create a sparsity pattern from the (row, col) index of every nonzero.
std::vector< casadi_int > range(casadi_int start, casadi_int stop, casadi_int step, casadi_int len)
Range function.
double if_else_zero(double x, double y)
Conditional assignment.
static casadi_int knot_size(const std::vector< double > &k)
std::string str(const T &v)
String representation, any type.
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.
MX do_inline(const MX &x, const std::vector< K > &knots, const MX &coeffs, casadi_int m, const std::vector< casadi_int > °ree, const std::vector< casadi_int > &lookup_mode)
void get_boor(const MX &x, const MX &knots, casadi_int degree, casadi_int lookup_mode, MX &start, MX &boor)
void casadi_clear(T1 *x, casadi_int n)
CLEAR: x <- 0.
void casadi_nd_boor_eval(T1 *ret, casadi_int n_dims, const T1 *knots, const casadi_int *offset, const casadi_int *degree, const casadi_int *strides, const T1 *c, casadi_int m, const T1 *x, const casadi_int *lookup_mode, casadi_int *iw, T1 *w)