Ejemplo n.º 1
0
 const ArrayXd  inverseGaussianDist::variance(const ArrayXd& mu) const {return mu.cube();}
Ejemplo n.º 2
0
ArrayXd Functions::cubicSplineInterpolation(RefArrayXd const observedAbscissa, RefArrayXd const observedOrdinate, 
                                            RefArrayXd const interpolatedAbscissaUntruncated)
{
    // Number of data points
    
    int size = observedAbscissa.size();           
   

    // Number of interpolation grid points.
    
    int interpolatedSize = interpolatedAbscissaUntruncated.size();
    
   
    // Since the formula requires at least 2 data points, check if array size is not below 2,
    // if the interpolated grid has at least one point, and if input abscissa and ordinate 
    // have same number of elements.
    
    assert(size >= 2);
    assert(interpolatedSize >= 1);
    assert(observedOrdinate.size() == size);


    // Check if lower bound set by observed abscissa is respected by interpolated abscissa
   
    assert(observedAbscissa(0) <= interpolatedAbscissaUntruncated(0));
    

    // Compare upper bound of observed and interpolated abscissas and truncate the latter if it exceeds the observed upper limit

    double largestObservedAbscissa = observedAbscissa(size-1);
    double largestInterpolatedAbscissa = interpolatedAbscissaUntruncated(interpolatedSize-1);
    ArrayXd interpolatedAbscissa;

    if (largestObservedAbscissa < largestInterpolatedAbscissa)
    {
        // Since upper bound of observed abscissa is lower, and the routine is not doing any extrapolation, truncate the array of
        // interpolated abscissa at this upper bound.

        int extraSize = Functions::countArrayIndicesWithinBoundaries(interpolatedAbscissaUntruncated, largestObservedAbscissa, largestInterpolatedAbscissa);
        interpolatedSize = interpolatedSize - extraSize;
        interpolatedAbscissa = interpolatedAbscissaUntruncated.segment(0,interpolatedSize);
    }
    else
        interpolatedAbscissa = interpolatedAbscissaUntruncated;


    // Define some array differences

    ArrayXd differenceOrdinate = observedOrdinate.segment(1,size-1) - observedOrdinate.segment(0,size-1);
    ArrayXd differenceAbscissa = observedAbscissa.segment(1,size-1) - observedAbscissa.segment(0,size-1);
    ArrayXd differenceAbscissa2 = observedAbscissa.segment(2,size-2) - observedAbscissa.segment(0,size-2);


    // Lower bound condition for natural spline 

    vector<double> secondDerivatives(size);
    vector<double> partialSolution(size-1);
    secondDerivatives[0] = 0.0;
    partialSolution[0] = 0.0;
    
    
    // Do tridiagonal decomposition for computing second derivatives of observed ordinate
    
    ArrayXd sigma = differenceAbscissa.segment(0,size-2)/differenceAbscissa2.segment(0,size-2);
    double beta;

    
    // Forward computation of partial solutions in tridiagonal system

    for (int i = 1; i < size-1; ++i)
    {
        beta = sigma(i-1) * secondDerivatives[i-1] + 2.0;
        secondDerivatives[i] = (sigma(i-1) - 1.0)/beta;
        partialSolution[i] = differenceOrdinate(i)/differenceAbscissa(i) - differenceOrdinate(i-1)/differenceAbscissa(i-1);
        partialSolution[i] = (6.0*partialSolution[i]/differenceAbscissa2(i-1)-sigma(i-1)*partialSolution[i-1])/beta;
    }

    
    // Upper bound condition for natural spline
    
    secondDerivatives[size-1] = 0.0;


    // Backward substitution

    for (int k = (size-2); k >= 0; --k)
    {
        secondDerivatives[k] = secondDerivatives[k]*secondDerivatives[k+1]+partialSolution[k];
    }


    // Initialize arrays of differences in both ordinate and abscissa
    
    ArrayXd interpolatedOrdinate = ArrayXd::Zero(interpolatedSize);
    ArrayXd remainingInterpolatedAbscissa = interpolatedAbscissa;       // The remaining part of the array of interpolated abscissa
    int cumulatedBinSize = 0;                                           // The cumulated number of interpolated points from the beginning
    int i = 0;                                                          // Bin counter

    while ((i < size-1) && (cumulatedBinSize < interpolatedSize))
    {
        // Find which values of interpolatedAbscissa are containined within the selected bin of observedAbscissa.
        // Since elements in interpolatedAbscissa are monotonically increasing, we cut the input array each time
        // we identify the elements of the current bin. This allows to speed up the process.

        double lowerAbscissa = observedAbscissa(i);
        double upperAbscissa = observedAbscissa(i+1);


        // Find total number of interpolated points falling in the current bin

        int binSize = Functions::countArrayIndicesWithinBoundaries(remainingInterpolatedAbscissa, lowerAbscissa, upperAbscissa);
      

        // Do interpolation only if interpolated points are found within the bin

        if (binSize > 0)
        {
            double lowerOrdinate = observedOrdinate(i);
            double upperOrdinate = observedOrdinate(i+1);
            double denominator = differenceAbscissa(i);
            double upperSecondDerivative = secondDerivatives[i+1];
            double lowerSecondDerivative = secondDerivatives[i];
            ArrayXd interpolatedAbscissaInCurrentBin = remainingInterpolatedAbscissa.segment(0, binSize);
            ArrayXd interpolatedOrdinateInCurrentBin = ArrayXd::Zero(binSize);


            // Compute coefficients for cubic spline interpolation function

            ArrayXd a = (upperAbscissa - interpolatedAbscissaInCurrentBin) / denominator;
            ArrayXd b = 1.0 - a;
            ArrayXd c = (1.0/6.0) * (a.cube() - a)*denominator*denominator;
            ArrayXd d = (1.0/6.0) * (b.cube() - b)*denominator*denominator;
            interpolatedOrdinateInCurrentBin = a*lowerOrdinate + b*upperOrdinate + c*lowerSecondDerivative + d*upperSecondDerivative;

                
            // Merge bin ordinate into total array of ordinate
        
            interpolatedOrdinate.segment(cumulatedBinSize, binSize) = interpolatedOrdinateInCurrentBin;


            // Reduce size of array remainingInterpolatedAbscissa by binSize elements and initialize the array
            // with remaining part of interpolatedAbscissa
        
            int currentRemainingSize = interpolatedSize - cumulatedBinSize;
            remainingInterpolatedAbscissa.resize(currentRemainingSize - binSize);
            cumulatedBinSize += binSize;
            remainingInterpolatedAbscissa = interpolatedAbscissa.segment(cumulatedBinSize, interpolatedSize-cumulatedBinSize);
        }  


        // Move to next bin

        ++i;
    }

    return interpolatedOrdinate;
}