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>& degree, casadi_int &coeffs_size,
92 std::vector<casadi_int>& coeffs_dims, std::vector<casadi_int>& strides) {
94 casadi_int n_dims = degree.size();
96 coeffs_dims.resize(n_dims+1);
98 for (casadi_int i=0;i<n_dims;++i) coeffs_dims[i+1] =
offset[i+1]-
offset[i]-degree[i]-1;
101 strides.resize(n_dims);
103 for (casadi_int i=0;i<n_dims-1;++i) {
104 strides[i+1] = strides[i]*coeffs_dims[i+1];
110 s.
pack(
"BSpline::type",
'n');
115 s.
pack(
"BSpline::type",
'p');
123 s.
pack(
"BSplineCommon::m",
m_);
153 const std::vector<casadi_int>& offset,
154 const std::vector<double>& coeffs,
155 const std::vector<casadi_int>& degree,
157 const std::vector<casadi_int>& lookup_mode) :
158 BSplineCommon(knots, offset, degree, m, lookup_mode), coeffs_(coeffs) {
159 casadi_assert_dev(x.
numel()==degree.size());
166 const std::vector<double>& knots,
167 const std::vector<casadi_int>& offset,
168 const std::vector<casadi_int>& degree,
170 const std::vector<casadi_int>& lookup_mode) :
172 casadi_assert_dev(x.
size1()==degree.size());
177 void get_boor(
const MX& x,
const MX& knots, casadi_int degree, casadi_int lookup_mode,
178 MX& start,
MX& boor) {
179 MX knots_clipped = knots(
range(degree, knots.
size1()-degree));
183 MX L = low(knots_clipped, x, low_opts);
184 start = fmin(L, knots.
size1()-2*degree-2);
187 boor_init(
Slice(), degree) = 1;
188 std::vector<MX> boor_full = horzsplit(
MX(boor_init));
189 casadi_int n_knots = 2*degree+2;
194 std::vector<MX> knv = horzsplit(kn);
198 for (casadi_int d=1;d<degree+1;++d) {
199 for (casadi_int i=0;i<n_knots-d-1;++i) {
200 MX bottom = knv[i+d]-knv[i];
201 MX b =
if_else_zero(bottom, (xt-knv[i])*boor_full[i]/(bottom+1e-100));
202 bottom = knv[i+d+1]-knv[i + 1];
203 b +=
if_else_zero(bottom, (knv[i+d+1]-xt)*boor_full[i+1]/(bottom+1e-100));
208 boor = horzcat(std::vector<MX>(boor_full.begin(), boor_full.begin()+degree+1));
212 static casadi_int
knot_size(
const std::vector<double>& k) {
return k.size(); }
217 const std::vector<K>& knots,
220 const std::vector<casadi_int>& degree,
221 const std::vector<casadi_int>& lookup_mode) {
223 casadi_int batch_x = x.
size2();
226 casadi_int N = knots.size();
227 std::vector<MX> xs = vertsplit(x);
230 std::vector<MX> starts(N);
231 std::vector< std::vector<MX> > boors(N);
232 for (casadi_int i=0;i<N;++i) {
234 get_boor(xs[i], knots[i], degree[i], lookup_mode[i], starts[i], boor);
235 boors[i] = horzsplit(boor.
T());
239 std::vector<casadi_int> strides = {m};
240 for (casadi_int i=0;i<N-1;++i) {
241 strides.push_back(strides.back()*(
knot_size(knots[i])-degree[i]-1));
245 MX start = mtimes(
DM(strides).
T(), vertcat(starts));
249 for (casadi_int i=0;i<N;++i) {
250 casadi_int n = degree[i]+1;
251 core = vec(repmat(core, 1, n)+repmat(strides[i]*
DM(
range(n)).
T(), core.
size1(), 1));
256 for (casadi_int k=0;k<batch_x;++k) {
259 MX c = reshape(coeffs(start(k)+core), m, -1);
263 for (casadi_int i=0;i<N;++i) {
264 boor = vec(mtimes(boor, boors[i][k].
T()));
267 res.push_back(mtimes(c, boor));
274 const std::vector<double>& coeffs,
275 const std::vector<casadi_int>& degree,
279 casadi_assert(x.
is_vector(),
"x argument must be a vector, got " + x.
dim() +
" instead.");
280 casadi_assert(x.
numel()==knots.size(),
"x argument length (" +
str(x.
numel()) +
") must match "
281 "number knot list length (" +
str(knots.size()) +
").");
282 casadi_assert(degree.size()==knots.size(),
"Degree list length (" +
str(degree.size()) +
") "
283 "must match knot list length (" +
str(knots.size()) +
").");
285 bool do_inline_flag =
false;
286 std::vector<std::string> lookup_mode;
288 for (
auto&&
op : opts) {
289 if (
op.first==
"inline") {
290 do_inline_flag =
op.second;
291 }
else if (
op.first==
"lookup_mode") {
292 lookup_mode =
op.second;
296 std::vector<casadi_int>
offset;
297 std::vector<double> stacked;
300 std::vector<casadi_int> mode =
303 if (do_inline_flag) {
304 return do_inline(x, knots, coeffs, m, degree, mode);
312 const std::vector< std::vector<double> >& knots,
313 const std::vector<casadi_int>& degree,
317 casadi_assert(x.
is_vector(),
"x argument must be a vector, got " + x.
dim() +
" instead.");
318 casadi_assert(x.
numel()==knots.size(),
"x argument length (" +
str(x.
numel()) +
") must match "
319 "knot list length (" +
str(knots.size()) +
").");
320 casadi_assert(degree.size()==knots.size(),
"Degree list length (" +
str(degree.size()) +
") "
321 "must match knot list length (" +
str(knots.size()) +
").");
322 bool do_inline_flag =
false;
323 std::vector<std::string> lookup_mode;
325 for (
auto&&
op : opts) {
326 if (
op.first==
"inline") {
327 do_inline_flag =
op.second;
328 }
else if (
op.first==
"lookup_mode") {
329 lookup_mode =
op.second;
333 std::vector<casadi_int>
offset;
334 std::vector<double> stacked;
336 std::vector<casadi_int> mode =
339 if (do_inline_flag) {
340 return do_inline(x, knots, coeffs, m, degree, mode);
348 const std::vector<MX>& knots,
349 const std::vector<casadi_int>& degree,
353 casadi_assert(x.
is_vector(),
"x argument must be a vector, got " + x.
dim() +
" instead.");
354 casadi_assert(x.
numel()==knots.size(),
"x argument length (" +
str(x.
numel()) +
") must match "
355 "knot list length (" +
str(knots.size()) +
").");
356 casadi_assert(degree.size()==knots.size(),
"Degree list length (" +
str(degree.size()) +
") "
357 "must match knot list length (" +
str(knots.size()) +
").");
360 std::vector<std::string> lookup_mode;
361 for (
auto&&
op : opts) {
362 if (
op.first==
"lookup_mode") {
363 lookup_mode =
op.second;
368 std::vector<casadi_int>
offset(knots.size()+1);
370 for (casadi_int i=0; i<knots.size(); ++i) {
374 std::vector<casadi_int> mode =
378 return do_inline(x, knots, coeffs, m, degree, mode);
382 return "BSpline(" + arg.at(0) +
")";
386 return "BSplineParametric(" + arg.at(0) +
", " + arg.at(1) +
")";
390 const std::vector<bool>& unique)
const {
395 const std::vector<bool>& unique)
const {
400 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
402 std::lock_guard<std::mutex> lock(jac_cache_mtx_);
411 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
412 std::lock_guard<std::mutex> lock(jac_cache_mtx_);
421 std::vector<std::vector<MX> >& fsens)
const {
424 for (casadi_int d=0; d<fsens.size(); ++d) {
425 fsens[d][0] = mtimes(J, fseed[d][0]);
430 std::vector<std::vector<MX> >& asens)
const {
432 for (casadi_int d=0; d<aseed.size(); ++d) {
433 asens[d][0] += mtimes(JT, aseed[d][0]);
437 int BSpline::eval(
const double** arg,
double** res, casadi_int* iw,
double* w)
const {
438 if (!res[0])
return 0;
448 if (!res[0])
return 0;
458 const std::vector<casadi_int>& arg,
459 const std::vector<casadi_int>& res,
460 const std::vector<bool>& arg_is_ref,
461 std::vector<bool>& res_is_ref)
const {
462 casadi_int n_dims =
offset_.size()-1;
469 g <<
"CASADI_PREFIX(nd_boor_eval)(" << g.
work(res[0],
m_,
false) <<
"," << n_dims <<
","
476 const std::vector<casadi_int>& arg,
477 const std::vector<bool>& arg_is_ref)
const {
482 const std::vector<casadi_int>& arg,
483 const std::vector<bool>& arg_is_ref)
const {
484 return g.
work(arg[1],
dep(1).
nnz(), arg_is_ref[1]);
488 const std::vector< std::vector<double> >& knots,
489 const std::vector<casadi_int>& degree,
492 std::vector<casadi_int>
offset;
493 std::vector<double> stacked;
496 std::vector<std::string> lookup_mode;
497 auto it = opts.find(
"lookup_mode");
498 if (it!=opts.end()) lookup_mode = it->second;
499 std::vector<casadi_int> lookup_mode_int =
502 casadi_int n_dims = degree.size();
503 casadi_int N = x.size()/n_dims;
504 casadi_assert_dev(N*n_dims==x.size());
506 casadi_int coeffs_size;
507 std::vector<casadi_int> coeffs_dims, strides;
508 prepare(1,
offset, degree, coeffs_size, coeffs_dims, strides);
511 std::vector<double> contribution(coeffs_size);
512 std::vector<casadi_int> nz(coeffs_size);
514 std::vector<double> data;
515 std::vector<casadi_int> row, col;
517 std::vector<double> w(
n_w(degree));
518 std::vector<casadi_int> iw(
n_iw(degree));
520 for (casadi_int i=0;i<N;++i) {
521 std::fill(contribution.begin(), contribution.end(), 0.0);
526 data.insert(data.end(), contribution.begin(), contribution.begin()+
nnz);
527 col.insert(col.end(), nz.begin(), nz.begin()+
nnz);
528 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.
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.
bool is_empty(bool both=false) const
Check if the sparsity 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
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 given the nonzeros in sparse triplet form *.
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)