* Function for generating second order finite-difference matrix, which is used for penalizing the * (approximate) second derivative in control point calculation for P-splines. */
| 214 | * (approximate) second derivative in control point calculation for P-splines. |
| 215 | */ |
| 216 | SparseMatrix BSpline::Builder::getSecondOrderFiniteDifferenceMatrix(const BSpline &bspline) const |
| 217 | { |
| 218 | unsigned int numVariables = bspline.getNumVariables(); |
| 219 | |
| 220 | // Number of (total) basis functions - defines the number of columns in D |
| 221 | unsigned int numCols = bspline.getNumBasisFunctions(); |
| 222 | std::vector<unsigned int> numBasisFunctions = bspline.getNumBasisFunctionsPerVariable(); |
| 223 | |
| 224 | // Number of basis functions (and coefficients) in each variable |
| 225 | std::vector<unsigned int> dims; |
| 226 | for (unsigned int i = 0; i < numVariables; i++) |
| 227 | dims.push_back(numBasisFunctions.at(i)); |
| 228 | |
| 229 | std::reverse(dims.begin(), dims.end()); |
| 230 | |
| 231 | for (unsigned int i=0; i < numVariables; ++i) |
| 232 | if (numBasisFunctions.at(i) < 3) |
| 233 | throw Exception("BSpline::Builder::getSecondOrderDifferenceMatrix: Need at least three coefficients/basis function per variable."); |
| 234 | |
| 235 | // Number of rows in D and in each block |
| 236 | int numRows = 0; |
| 237 | std::vector< int > numBlkRows; |
| 238 | for (unsigned int i = 0; i < numVariables; i++) |
| 239 | { |
| 240 | int prod = 1; |
| 241 | for (unsigned int j = 0; j < numVariables; j++) |
| 242 | { |
| 243 | if (i == j) |
| 244 | prod *= (dims[j] - 2); |
| 245 | else |
| 246 | prod *= dims[j]; |
| 247 | } |
| 248 | numRows += prod; |
| 249 | numBlkRows.push_back(prod); |
| 250 | } |
| 251 | |
| 252 | // Resize and initialize D |
| 253 | SparseMatrix D(numRows, numCols); |
| 254 | D.reserve(DenseVector::Constant(numCols,2*numVariables)); // D has no more than two elems per col per dim |
| 255 | |
| 256 | int i = 0; // Row index |
| 257 | // Loop though each dimension (each dimension has its own block) |
| 258 | for (unsigned int d = 0; d < numVariables; d++) |
| 259 | { |
| 260 | // Calculate left and right products |
| 261 | int leftProd = 1; |
| 262 | int rightProd = 1; |
| 263 | for (unsigned int k = 0; k < d; k++) |
| 264 | { |
| 265 | leftProd *= dims[k]; |
| 266 | } |
| 267 | for (unsigned int k = d+1; k < numVariables; k++) |
| 268 | { |
| 269 | rightProd *= dims[k]; |
| 270 | } |
| 271 | |
| 272 | // Loop through subblocks on the block diagonal |
| 273 | for (int j = 0; j < rightProd; j++) |
nothing calls this directly
no test coverage detected