SparseMatrix BSplineBasis1D::reduceSupport(double lb, double ub) { // Check bounds if (lb < knots.front() || ub > knots.back()) throw Exception("BSplineBasis1D::reduceSupport: Cannot increase support!"); unsigned int k = degree + 1; int index_lower = indexSupportedBasisfunctions(lb).front(); int index_upper = indexSupportedBasisfunctions(ub).back(); // Check lower bound index if (k != knotMultiplicity(knots.at(index_lower))) { int suggested_index = index_lower - 1; if (0 <= suggested_index) { index_lower = suggested_index; } else { throw Exception("BSplineBasis1D::reduceSupport: Suggested index is negative!"); } } // Check upper bound index if (knotMultiplicity(ub) == k && knots.at(index_upper) == ub) { index_upper -= k; } // New knot vector std::vector<double> si; si.insert(si.begin(), knots.begin()+index_lower, knots.begin()+index_upper+k+1); // Construct selection matrix A int numOld = knots.size()-k; // Current number of basis functions int numNew = si.size()-k; // Number of basis functions after update if (numOld < numNew) throw Exception("BSplineBasis1D::reduceSupport: Number of basis functions is increased instead of reduced!"); DenseMatrix Ad = DenseMatrix::Zero(numOld, numNew); Ad.block(index_lower, 0, numNew, numNew) = DenseMatrix::Identity(numNew, numNew); SparseMatrix A = Ad.sparseView(); // Update knots knots = si; return A; }
SparseVector BSplineBasis1D::evaluate(double x) const { SparseVector basisvalues(numBasisFunctions()); supportHack(x); std::vector<int> indexSupported = indexSupportedBasisfunctions(x); basisvalues.reserve(indexSupported.size()); // Iterate through the nonzero basisfunctions and store functionvalues for(auto it = indexSupported.begin(); it != indexSupported.end(); it++) { basisvalues.insert(*it) = deBoorCox(x, *it, degree); } // Alternative evaluation using basis matrix // int knotIndex = indexHalfopenInterval(x); // knot index // SparseMatrix basisvalues2 = buildBsplineMatrix(x, knotIndex, 1); // for (int i = 2; i <= basisDegree; i++) // { // SparseMatrix Ri = buildBsplineMatrix(x, knotIndex, i); // basisvalues2 = basisvalues2*Ri; // } // basisvalues2.makeCompressed(); // assert(basisvalues2.rows() == 1); // assert(basisvalues2.cols() == basisDegree + 1); return basisvalues; }
// Old implementation of first derivative of basis functions DenseVector BSplineBasis1D::evaluateFirstDerivative(double x) const { DenseVector values; values.setZero(numBasisFunctions()); supportHack(x); std::vector<int> supportedBasisFunctions = indexSupportedBasisfunctions(x); for(int i : supportedBasisFunctions) { // Differentiate basis function // Equation 3.35 in Lyche & Moerken (2011) double b1 = deBoorCox(x, i, degree-1); double b2 = deBoorCox(x, i+1, degree-1); double t11 = knots.at(i); double t12 = knots.at(i+degree); double t21 = knots.at(i+1); double t22 = knots.at(i+degree+1); (t12 == t11) ? b1 = 0 : b1 = b1/(t12-t11); (t22 == t21) ? b2 = 0 : b2 = b2/(t22-t21); values(i) = degree*(b1 - b2); } return values; }
bool BSplineBasis1D::reduceSupport(double lb, double ub, SparseMatrix &A) { // Check bounds if(lb < knots.front() || ub > knots.back()) { return false; } unsigned int k = degree + 1; int index_lower = indexSupportedBasisfunctions(lb).front(); int index_upper = indexSupportedBasisfunctions(ub).back(); // Check lower bound index unsigned int count = knotMultiplicity(knots.at(index_lower)); bool is_p_regular = (k == count); if(!is_p_regular) { int suggested_index = index_lower - 1; if(0 <= suggested_index) { index_lower = suggested_index; } else { #ifndef NDEBUG std::cout << "\n\n----------------adjust_index_for_domain_reduction-----------------" << std::endl; std::cout << "Error: not enough knots to guarantee controlpoint convergence" << std::endl; std::cout << "----------------adjust_index_for_domain_reduction-----------------\n\n" << std::endl; #endif // NDEBUG return false; } } // Check upper bound index if(knotMultiplicity(ub) == k && knots.at(index_upper) == ub) { index_upper -= k; } // New knot vector std::vector<double> si; si.insert(si.begin(), knots.begin()+index_lower, knots.begin()+index_upper+k+1); // Construct selection matrix A int n_old = knots.size()-k; // Current number of basis functions int n_new = si.size()-k; // Number of basis functions after update if (n_old < n_new) return false; DenseMatrix Ad = DenseMatrix::Zero(n_old, n_new); Ad.block(index_lower, 0, n_new, n_new) = DenseMatrix::Identity(n_new, n_new); A = Ad.sparseView(); // Update knots knots = si; return true; }