Esempio n. 1
0
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;
}