bspline_impl.hpp
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 #ifndef CASADI_BSPLINE_IMPL_HPP
27 #define CASADI_BSPLINE_IMPL_HPP
28 
29 #include "bspline.hpp"
30 #include "interpolant_impl.hpp"
31 #include "casadi_low.hpp"
32 
33 namespace casadi {
34 
35  template<class M>
36  M BSplineCommon::derivative_coeff(casadi_int i,
37  const std::vector< std::vector<double> >& knots,
38  const std::vector<casadi_int>& degree,
39  const std::vector<casadi_int>& coeffs_dims, const M& coeffs,
40  std::vector< std::vector<double> >& new_knots,
41  std::vector<casadi_int>& new_degree) {
42  casadi_int n_knots = knots[i].size();
43  casadi_int n = n_knots-degree[i]-1;
44  DM K = knots[i];
45  DM delta_knots = K(range(1+degree[i], n_knots-1))
46  - K(range(1, n_knots-degree[i]-1));
47  DM d = degree[i]/delta_knots; // length n-1
48 
49  std::vector<casadi_int> coeffs_dims_new = coeffs_dims;
50  coeffs_dims_new[i+1] = n-1;
51 
52  // T = diag(-d) + upper_band(+d) is a scaled finite-difference operator.
53  // Apply via slice-subtract + broadcast-multiply — no T, no kron, no densify,
54  // no permutation mapping baked into generated code.
55  casadi_int L = 1, R = 1;
56  for (casadi_int k=0; k<=i; ++k) L *= coeffs_dims[k];
57  for (casadi_int k=i+2; k<(casadi_int)coeffs_dims.size(); ++k) R *= coeffs_dims[k];
58  casadi_int K_sz = coeffs_dims[i+1];
59  casadi_int Kp = n-1;
60 
61  M M_coeffs = reshape(coeffs, L*K_sz, R);
62  M top = M_coeffs(Slice(L, L*K_sz), Slice());
63  M bot = M_coeffs(Slice(0, L*(K_sz-1)), Slice());
64  M diffed = top - bot;
65 
66  std::vector<casadi_int> dims{L, Kp, R};
67  std::vector<casadi_int> a{-1, -2, -3};
68  std::vector<casadi_int> b{-2};
69  std::vector<casadi_int> c{-1, -2, -3};
70  M coeff_matrix = einstein(vec(diffed), M(d),
71  dims, std::vector<casadi_int>{Kp}, dims,
72  a, b, c);
73 
74  new_knots.clear();
75  new_degree.clear();
76  for (casadi_int k=0;k<degree.size();++k) {
77  if (i==k) {
78  new_knots.push_back(
79  std::vector<double>(knots[k].begin()+1, knots[k].end()-1));
80  new_degree.push_back(degree[k]-1);
81  } else {
82  new_knots.push_back(knots[k]);
83  new_degree.push_back(degree[k]);
84  }
85  }
86 
87  // Return the flat vector
88  return coeff_matrix;
89  }
90 
91  template<class T>
92  MX BSplineCommon::jac(const MX& x, const T& coeffs) const {
93  casadi_int n_dims = degree_.size();
94  std::vector<MX> parts;
95 
96  Dict opts;
97  std::vector<std::string> lookup_mode;
98  for (auto e : lookup_mode_) lookup_mode.push_back(Low::lookup_mode_from_enum(e));
99  opts["lookup_mode"] = lookup_mode;
100 
101  // Unflatten knots
102  std::vector< std::vector<double> > knots_unflat(n_dims);
103  for (casadi_int k=0;k<n_dims;++k) {
104  knots_unflat[k] = std::vector<double>(
105  get_ptr(knots_)+offset_[k], get_ptr(knots_)+offset_[k+1]);
106  }
107 
108  // Loop over dimensions
109  for (casadi_int k=0;k<n_dims;++k) {
110  std::vector< std::vector<double> > knots;
111  std::vector< casadi_int> degree;
112  T dC = derivative_coeff(k, knots_unflat, degree_, coeffs_dims_, coeffs, knots, degree);
113  MX d = MX::bspline(x, dC, knots, degree, m_, opts);
114  parts.push_back(d);
115  }
116 
117  return horzcat(parts);
118  }
119 
120 } // namespace casadi
121 
122 #endif // CASADI_BSPLINE_IMPL_HPP
friend MX bspline(const MX &x, const DM &coeffs, const std::vector< std::vector< double > > &knots, const std::vector< casadi_int > &degree, casadi_int m, const Dict &opts=Dict())
Definition: mx.hpp:903
The casadi namespace.
Definition: archiver.hpp:32
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
Matrix< double > DM
Definition: dm_fwd.hpp:33