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 const std::vector< std::vector<double> >& knots,
215 const std::vector<casadi_int>& degree,
216 const std::vector<casadi_int>& lookup_mode) {
218 casadi_int batch_x = x.
size2();
221 casadi_int N = knots.size();
222 std::vector<MX> xs = vertsplit(x);
225 std::vector<MX> starts(N);
226 std::vector< std::vector<MX> > boors(N);
227 for (casadi_int i=0;i<N;++i) {
229 get_boor(xs[i], knots[i], degree[i], lookup_mode[i], starts[i], boor);
230 boors[i] = horzsplit(boor.
T());
234 std::vector<casadi_int> strides = {m};
235 for (casadi_int i=0;i<N-1;++i) {
236 strides.push_back(strides.back()*(knots[i].size()-degree[i]-1));
240 MX start = mtimes(
DM(strides).
T(), vertcat(starts));
244 for (casadi_int i=0;i<N;++i) {
245 casadi_int n = degree[i]+1;
246 core = vec(repmat(core, 1, n)+repmat(strides[i]*
DM(
range(n)).
T(), core.
size1(), 1));
251 for (casadi_int k=0;k<batch_x;++k) {
254 MX c = reshape(coeffs(start(k)+core), m, -1);
258 for (casadi_int i=0;i<N;++i) {
259 boor = vec(mtimes(boor, boors[i][k].
T()));
262 res.push_back(mtimes(c, boor));
269 const std::vector<double>& coeffs,
270 const std::vector<casadi_int>& degree,
274 casadi_assert(x.
is_vector(),
"x argument must be a vector, got " + x.
dim() +
" instead.");
275 casadi_assert(x.
numel()==knots.size(),
"x argument length (" +
str(x.
numel()) +
") must match "
276 "number knot list length (" +
str(knots.size()) +
").");
277 casadi_assert(degree.size()==knots.size(),
"Degree list length (" +
str(degree.size()) +
") "
278 "must match knot list length (" +
str(knots.size()) +
").");
280 bool do_inline_flag =
false;
281 std::vector<std::string> lookup_mode;
283 for (
auto&&
op : opts) {
284 if (
op.first==
"inline") {
285 do_inline_flag =
op.second;
286 }
else if (
op.first==
"lookup_mode") {
287 lookup_mode =
op.second;
291 std::vector<casadi_int>
offset;
292 std::vector<double> stacked;
295 std::vector<casadi_int> mode =
298 if (do_inline_flag) {
299 return do_inline(x, knots, coeffs, m, degree, mode);
307 const std::vector< std::vector<double> >& knots,
308 const std::vector<casadi_int>& degree,
312 casadi_assert(x.
is_vector(),
"x argument must be a vector, got " + x.
dim() +
" instead.");
313 casadi_assert(x.
numel()==knots.size(),
"x argument length (" +
str(x.
numel()) +
") must match "
314 "knot list length (" +
str(knots.size()) +
").");
315 casadi_assert(degree.size()==knots.size(),
"Degree list length (" +
str(degree.size()) +
") "
316 "must match knot list length (" +
str(knots.size()) +
").");
317 bool do_inline_flag =
false;
318 std::vector<std::string> lookup_mode;
320 for (
auto&&
op : opts) {
321 if (
op.first==
"inline") {
322 do_inline_flag =
op.second;
323 }
else if (
op.first==
"lookup_mode") {
324 lookup_mode =
op.second;
328 std::vector<casadi_int>
offset;
329 std::vector<double> stacked;
331 std::vector<casadi_int> mode =
334 if (do_inline_flag) {
335 return do_inline(x, knots, coeffs, m, degree, mode);
342 return "BSpline(" + arg.at(0) +
")";
346 return "BSplineParametric(" + arg.at(0) +
", " + arg.at(1) +
")";
358 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
360 std::lock_guard<std::mutex> lock(jac_cache_mtx_);
369 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
370 std::lock_guard<std::mutex> lock(jac_cache_mtx_);
379 std::vector<std::vector<MX> >& fsens)
const {
382 for (casadi_int d=0; d<fsens.size(); ++d) {
383 fsens[d][0] = mtimes(J, fseed[d][0]);
388 std::vector<std::vector<MX> >& asens)
const {
390 for (casadi_int d=0; d<aseed.size(); ++d) {
391 asens[d][0] += mtimes(JT, aseed[d][0]);
395 int BSpline::eval(
const double** arg,
double** res, casadi_int* iw,
double* w)
const {
396 if (!res[0])
return 0;
406 if (!res[0])
return 0;
416 const std::vector<casadi_int>& arg,
417 const std::vector<casadi_int>& res,
418 const std::vector<bool>& arg_is_ref,
419 std::vector<bool>& res_is_ref)
const {
420 casadi_int n_dims =
offset_.size()-1;
427 g <<
"CASADI_PREFIX(nd_boor_eval)(" << g.
work(res[0],
m_,
false) <<
"," << n_dims <<
","
434 const std::vector<casadi_int>& arg,
435 const std::vector<bool>& arg_is_ref)
const {
440 const std::vector<casadi_int>& arg,
441 const std::vector<bool>& arg_is_ref)
const {
442 return g.
work(arg[1],
dep(1).
nnz(), arg_is_ref[1]);
446 const std::vector< std::vector<double> >& knots,
447 const std::vector<casadi_int>& degree,
450 std::vector<casadi_int>
offset;
451 std::vector<double> stacked;
454 std::vector<std::string> lookup_mode;
455 auto it = opts.find(
"lookup_mode");
456 if (it!=opts.end()) lookup_mode = it->second;
457 std::vector<casadi_int> lookup_mode_int =
460 casadi_int n_dims = degree.size();
461 casadi_int N = x.size()/n_dims;
462 casadi_assert_dev(N*n_dims==x.size());
464 casadi_int coeffs_size;
465 std::vector<casadi_int> coeffs_dims, strides;
466 prepare(1,
offset, degree, coeffs_size, coeffs_dims, strides);
469 std::vector<double> contribution(coeffs_size);
470 std::vector<casadi_int> nz(coeffs_size);
472 std::vector<double> data;
473 std::vector<casadi_int> row, col;
475 std::vector<double> w(
n_w(degree));
476 std::vector<casadi_int> iw(
n_iw(degree));
478 for (casadi_int i=0;i<N;++i) {
479 std::fill(contribution.begin(), contribution.end(), 0.0);
484 data.insert(data.end(), contribution.begin(), contribution.begin()+
nnz);
485 col.insert(col.end(), nz.begin(), nz.begin()+
nnz);
486 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.
void eval_mx(const std::vector< MX > &arg, std::vector< MX > &res) const override
Evaluate symbolically (MX)
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.
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 serialize_type(SerializingStream &s) const override
Serialize type information.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
void eval_mx(const std::vector< MX > &arg, std::vector< MX > &res) const override
Evaluate symbolically (MX)
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.
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.
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.
MX do_inline(const MX &x, const std::vector< std::vector< double > > &knots, const MX &coeffs, casadi_int m, const std::vector< casadi_int > °ree, const std::vector< casadi_int > &lookup_mode)
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)