const ArrayXd inverseGaussianDist::variance(const ArrayXd& mu) const {return mu.cube();}
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; }