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>
37  const std::vector<double>& knots,
38  const std::vector<casadi_int>& offset,
39  const std::vector<casadi_int>& degree,
40  const std::vector<casadi_int>& coeffs_dims, const M& coeffs,
41  std::vector< std::vector<double> >& new_knots,
42  std::vector<casadi_int>& new_degree) {
43  casadi_int n_dims = degree.size();
44 
45  casadi_int n_knots = offset[i+1]-offset[i];
46  casadi_int n = n_knots-degree[i]-1;
47  DM K = std::vector<double>(get_ptr(knots)+offset[i], get_ptr(knots)+offset[i+1]);
48  DM delta_knots = K(range(1+degree[i], n_knots-1))
49  - K(range(1, n_knots-degree[i]-1));
50  Sparsity sp_diag = vertsplit(Sparsity::diag(n), {0, n-1, n})[0];
51  Sparsity sp_band = vertsplit(Sparsity::band(n, -1), {0, n-1, n})[0];
52  DM delta_knots_inv = 1/delta_knots;
53  DM T = DM(sp_diag, -delta_knots_inv) + DM(sp_band, delta_knots_inv);
54  T*= degree[i];
55 
56  std::vector<casadi_int> coeffs_dims_new = coeffs_dims;
57  coeffs_dims_new[i+1] = T.size1();
58 
59  // Apply transformation T on axis i
60 
61  // Bring axis i to the back
62  std::vector<casadi_int> order = range(n_dims+1);
63  std::swap(order.back(), order[i+1]);
64  std::vector<casadi_int> mapping = tensor_permute_mapping(coeffs_dims, order);
65  M coeff_matrix = coeffs.nz(mapping); // NOLINT(cppcoreguidelines-slicing)
66 
67  // Cast as matrix
68  coeff_matrix = reshape(coeff_matrix, -1, T.size2());
69 
70  // Apply the transformation matrix from the right
71  coeff_matrix = mtimes(coeff_matrix, T.T());
72 
73  // Bring axis i back to the original place
74  mapping = tensor_permute_mapping(permute(coeffs_dims_new, order), order);
75  coeff_matrix = coeff_matrix.nz(mapping); // NOLINT(cppcoreguidelines-slicing)
76 
77  new_knots.clear();
78  new_degree.clear();
79  for (casadi_int k=0;k<degree.size();++k) {
80  if (i==k) {
81  new_knots.push_back(
82  std::vector<double>(get_ptr(knots)+offset[k]+1, get_ptr(knots)+offset[k+1]-1));
83  new_degree.push_back(degree[k]-1);
84  } else {
85  new_knots.push_back(
86  std::vector<double>(get_ptr(knots)+offset[k], get_ptr(knots)+offset[k+1]));
87  new_degree.push_back(degree[k]);
88  }
89  }
90 
91  // Return the flat vector
92  return coeff_matrix;
93  }
94 
95  template<class T>
96  MX BSplineCommon::jac(const MX& x, const T& coeffs) const {
97  casadi_int n_dims = degree_.size();
98  std::vector<MX> parts;
99 
100  Dict opts;
101  std::vector<std::string> lookup_mode;
102  for (auto e : lookup_mode_) lookup_mode.push_back(Low::lookup_mode_from_enum(e));
103  opts["lookup_mode"] = lookup_mode;
104 
105  // Loop over dimensions
106  for (casadi_int k=0;k<n_dims;++k) {
107  std::vector< std::vector<double> > knots;
108  std::vector< casadi_int> degree;
109  T dC = derivative_coeff(k, knots_, offset_, degree_, coeffs_dims_, coeffs, knots, degree);
110  MX d = MX::bspline(x, dC, knots, degree, m_, opts);
111  parts.push_back(d);
112  }
113 
114  return horzcat(parts);
115  }
116 
117 } // namespace casadi
118 
119 #endif // CASADI_BSPLINE_IMPL_HPP
std::vector< casadi_int > lookup_mode_
Definition: bspline.hpp:76
std::vector< double > knots_
Definition: bspline.hpp:72
std::vector< casadi_int > degree_
Definition: bspline.hpp:74
std::vector< casadi_int > offset_
Definition: bspline.hpp:73
std::vector< casadi_int > coeffs_dims_
Definition: bspline.hpp:80
static M derivative_coeff(casadi_int i, const std::vector< double > &knots, const std::vector< casadi_int > &offset, const std::vector< casadi_int > &degree, const std::vector< casadi_int > &coeffs_dims, const M &coeffs, std::vector< std::vector< double > > &new_knots, std::vector< casadi_int > &new_degree)
MX jac(const MX &x, const T &coeffs) const
static std::string lookup_mode_from_enum(casadi_int lookup_mode)
Definition: casadi_low.cpp:48
virtual casadi_int offset() const
Definition: mx_node.cpp:218
virtual Matrix< casadi_int > mapping() const
Get an IM representation of a GetNonzeros or SetNonzeros node.
Definition: mx_node.cpp:973
MX - Matrix expression.
Definition: mx.hpp:92
static 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.cpp:2116
General sparsity class.
Definition: sparsity.hpp:106
static Sparsity diag(casadi_int nrow)
Create diagonal sparsity pattern *.
Definition: sparsity.hpp:190
static Sparsity band(casadi_int n, casadi_int p)
Create a single band in a square sparsity pattern.
Definition: sparsity.cpp:1070
The casadi namespace.
Definition: archiver.cpp:28
std::vector< casadi_int > range(casadi_int start, casadi_int stop, casadi_int step, casadi_int len)
Range function.
std::vector< casadi_int > tensor_permute_mapping(const std::vector< casadi_int > &dims, const std::vector< casadi_int > &order)
Computes a mapping for a (dense) tensor permutation.
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
std::vector< T > permute(const std::vector< T > &a, const std::vector< casadi_int > &order)
permute a list