/// <summary> /// Creates an instance specifying the value of eps. /// </summary> /// <param name="eps"> the step size used to approximate the derivative </param> public MatrixFieldFirstOrderDifferentiator(double eps) { ArgChecker.isTrue(eps > 1e-15, "eps of {} is below machine tolerance of 1e-15. Please choose a higher value", eps); this.eps = eps; this.twoEps = 2 * eps; this.oneOverTwpEps = 1.0 / twoEps; }
/// <summary> /// Calculates polynomials and derivative. </summary> /// <param name="n"> the n value </param> /// <param name="alpha"> the alpha value </param> /// <param name="beta"> the beta value </param> /// <returns> the result </returns> public virtual Pair <DoubleFunction1D, DoubleFunction1D>[] getPolynomialsAndFirstDerivative(int n, double alpha, double beta) { ArgChecker.isTrue(n >= 0); //JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @SuppressWarnings("unchecked") com.opengamma.strata.collect.tuple.Pair<com.opengamma.strata.math.impl.function.DoubleFunction1D, com.opengamma.strata.math.impl.function.DoubleFunction1D>[] polynomials = new com.opengamma.strata.collect.tuple.Pair[n + 1]; Pair <DoubleFunction1D, DoubleFunction1D>[] polynomials = new Pair[n + 1]; DoubleFunction1D p, dp, p1, p2; for (int i = 0; i <= n; i++) { if (i == 0) { polynomials[i] = Pair.of(One, Zero); } else if (i == 1) { double a1 = (alpha + beta + 2) / 2; polynomials[i] = Pair.of((DoubleFunction1D) new RealPolynomialFunction1D(new double[] { (alpha - beta) / 2, a1 }), (DoubleFunction1D) new RealPolynomialFunction1D(new double[] { a1 })); } else { int j = i - 1; p1 = polynomials[j].First; p2 = polynomials[j - 1].First; DoubleFunction1D temp1 = p1.multiply(getB(alpha, beta, j)); DoubleFunction1D temp2 = p1.multiply(X).multiply(getC(alpha, beta, j)); DoubleFunction1D temp3 = p2.multiply(getD(alpha, beta, j)); p = (temp1.add(temp2).add(temp3)).divide(getA(alpha, beta, j)); dp = p.derivative(); polynomials[i] = Pair.of(p, dp); } } return(polynomials); }
/// <summary> /// Compute $A^T A$, where A is a matrix. </summary> /// <param name="a"> The matrix </param> /// <returns> The result of $A^T A$ </returns> public virtual DoubleMatrix matrixTransposeMultiplyMatrix(DoubleMatrix a) { ArgChecker.notNull(a, "a"); int n = a.rowCount(); int m = a.columnCount(); //JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java: //ORIGINAL LINE: double[][] data = new double[m][m]; double[][] data = RectangularArrays.ReturnRectangularDoubleArray(m, m); for (int i = 0; i < m; i++) { double sum = 0d; for (int k = 0; k < n; k++) { sum += a.get(k, i) * a.get(k, i); } data[i][i] = sum; for (int j = i + 1; j < m; j++) { sum = 0d; for (int k = 0; k < n; k++) { sum += a.get(k, i) * a.get(k, j); } data[i][j] = sum; data[j][i] = sum; } } return(DoubleMatrix.ofUnsafe(data)); }
/// <summary> /// Adds two matrices. This operation can only be performed if the matrices are of the same type and dimensions. </summary> /// <param name="m1"> The first matrix, not null </param> /// <param name="m2"> The second matrix, not null </param> /// <returns> The sum of the two matrices </returns> /// <exception cref="IllegalArgumentException"> If the matrices are not of the same type, if the matrices are not the same shape. </exception> public virtual Matrix add(Matrix m1, Matrix m2) { ArgChecker.notNull(m1, "m1"); ArgChecker.notNull(m2, "m2"); if (m1 is DoubleArray) { if (m2 is DoubleArray) { DoubleArray array1 = (DoubleArray)m1; DoubleArray array2 = (DoubleArray)m2; return(array1.plus(array2)); } throw new System.ArgumentException("Tried to add a " + m1.GetType() + " and " + m2.GetType()); } else if (m1 is DoubleMatrix) { if (m2 is DoubleMatrix) { DoubleMatrix matrix1 = (DoubleMatrix)m1; DoubleMatrix matrix2 = (DoubleMatrix)m2; return(matrix1.plus(matrix2)); } throw new System.ArgumentException("Tried to add a " + m1.GetType() + " and " + m2.GetType()); } throw new System.NotSupportedException(); }
/// <summary> /// Creates an instance. /// </summary> /// <param name="a"> the value </param> public IncompleteGammaFunction(double a) { ArgChecker.notNegativeOrZero(a, "a"); _maxIter = 100000; _eps = 1e-12; _a = a; }
public override Pair <DoubleFunction1D, DoubleFunction1D>[] getPolynomialsAndFirstDerivative(int n) { ArgChecker.isTrue(n >= 0); //JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @SuppressWarnings("unchecked") com.opengamma.strata.collect.tuple.Pair<com.opengamma.strata.math.impl.function.DoubleFunction1D, com.opengamma.strata.math.impl.function.DoubleFunction1D>[] polynomials = new com.opengamma.strata.collect.tuple.Pair[n + 1]; Pair <DoubleFunction1D, DoubleFunction1D>[] polynomials = new Pair[n + 1]; DoubleFunction1D p, dp; for (int i = 0; i <= n; i++) { if (i == 0) { polynomials[i] = Pair.of(One, Zero); } else if (i == 1) { polynomials[i] = Pair.of(X, One); } else { p = (polynomials[i - 1].First.multiply(X).multiply(2 * i - 1).subtract(polynomials[i - 2].First.multiply(i - 1))).multiply(1.0 / i); dp = p.derivative(); polynomials[i] = Pair.of(p, dp); } } return(polynomials); }
//------------------------------------------------------------------------- public virtual System.Func <DoubleArray, DoubleMatrix[]> differentiate(System.Func <DoubleArray, DoubleArray> function, System.Func <DoubleArray, bool> domain) { ArgChecker.notNull(function, "function"); System.Func <DoubleArray, DoubleMatrix> jacFunc = vectorFieldDiff.differentiate(function, domain); System.Func <DoubleArray, DoubleMatrix[]> hFunc = maxtrixFieldDiff.differentiate(jacFunc, domain); return(new FuncAnonymousInnerClass2(this, hFunc)); }
/// <summary> /// Creates an instance with a sampled (parameterised) curve. /// </summary> /// <param name="samplePoints"> the points where we sample the curve </param> /// <param name="curve"> a parameterised curve </param> public ParameterizedCurveVectorFunction(double[] samplePoints, ParameterizedCurve curve) { ArgChecker.notEmpty(samplePoints, "samplePoints"); ArgChecker.notNull(curve, "curve"); _samplePoints = Arrays.copyOf(samplePoints, samplePoints.Length); _curve = curve; }
/// <summary> /// Creates an instance. /// <para> /// If the size of the domain is very small or very large, consider re-scaling first. /// If this value is too small, the result will most likely be dominated by noise. /// Use around 10<sup>-5</sup> times the domain size. /// /// </para> /// </summary> /// <param name="differenceType"> the differencing type to be used in calculating the gradient function </param> /// <param name="eps"> the step size used to approximate the derivative </param> public VectorFieldFirstOrderDifferentiator(FiniteDifferenceType differenceType, double eps) { ArgChecker.notNull(differenceType, "differenceType"); this.differenceType = differenceType; this.eps = eps; this.twoEps = 2 * eps; }
protected internal override QuantileResult expectedShortfall(double level, DoubleArray sample) { ArgChecker.isTrue(level > 0, "Quantile should be above 0."); ArgChecker.isTrue(level < 1, "Quantile should be below 1."); int sampleSize = sampleCorrection(sample.size()); double[] order = createIndexArray(sample.size()); double[] s = sample.toArray(); DoubleArrayMath.sortPairs(s, order); double fractionalIndex = level * sampleSize; int index = (int)checkIndex(this.index(fractionalIndex), sample.size(), true); int[] indices = new int[index]; double[] weights = new double[index]; double interval = 1d / (double)sampleSize; double losses = s[0] * interval *indexShift(); for (int i = 0; i < index - 1; i++) { losses += s[i] * interval; indices[i] = (int)order[i]; weights[i] = interval; } losses += s[index - 1] * (fractionalIndex - index + 1 - indexShift()) * interval; indices[index - 1] = (int)order[index - 1]; weights[0] += interval * indexShift(); weights[index - 1] = (fractionalIndex - index + 1 - indexShift()) * interval; return(QuantileResult.of(losses / level, indices, DoubleArray.ofUnsafe(weights).dividedBy(level))); }
/// <summary> /// Creates an instance. /// </summary> /// <param name="x1"> the lower edge </param> /// <param name="x2"> the upper edge, must be greater than x1 </param> /// <param name="y"> the height </param> public TopHatFunction(double x1, double x2, double y) { ArgChecker.isTrue(x1 < x2, "x1 must be less than x2"); _x1 = x1; _x2 = x2; _y = y; }
/// <summary> /// Gets the polynomials and derivative. /// </summary> /// <param name="n"> the n value </param> /// <param name="alpha"> the alpha value </param> /// <returns> the result </returns> public virtual Pair <DoubleFunction1D, DoubleFunction1D>[] getPolynomialsAndFirstDerivative(int n, double alpha) { ArgChecker.isTrue(n >= 0); //JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @SuppressWarnings("unchecked") com.opengamma.strata.collect.tuple.Pair<com.opengamma.strata.math.impl.function.DoubleFunction1D, com.opengamma.strata.math.impl.function.DoubleFunction1D>[] polynomials = new com.opengamma.strata.collect.tuple.Pair[n + 1]; Pair <DoubleFunction1D, DoubleFunction1D>[] polynomials = new Pair[n + 1]; DoubleFunction1D p, dp, p1, p2; for (int i = 0; i <= n; i++) { if (i == 0) { polynomials[i] = Pair.of(One, Zero); } else if (i == 1) { polynomials[i] = Pair.of(F1, DF1); } else { p1 = polynomials[i - 1].First; p2 = polynomials[i - 2].First; p = (p1.multiply(2.0 * i + alpha - 1).subtract(p1.multiply(X)).subtract(p2.multiply((i - 1.0 + alpha))).divide(i)); dp = (p.multiply(i).subtract(p1.multiply(i + alpha))).divide(X); polynomials[i] = Pair.of(p, dp); } } return(polynomials); }
public override DoubleMatrix apply(TridiagonalMatrix x) { ArgChecker.notNull(x, "x"); double[] a = x.DiagonalData; double[] b = x.UpperSubDiagonalData; double[] c = x.LowerSubDiagonalData; int n = a.Length; int i, j, k; double[] theta = new double[n + 1]; double[] phi = new double[n]; theta[0] = 1.0; theta[1] = a[0]; for (i = 2; i <= n; i++) { theta[i] = a[i - 1] * theta[i - 1] - b[i - 2] * c[i - 2] * theta[i - 2]; } if (theta[n] == 0.0) { throw new MathException("Zero determinant. Cannot invert the matrix"); } phi[n - 1] = 1.0; phi[n - 2] = a[n - 1]; for (i = n - 3; i >= 0; i--) { phi[i] = a[i + 1] * phi[i + 1] - b[i + 1] * c[i + 1] * phi[i + 2]; } double product; //JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java: //ORIGINAL LINE: double[][] res = new double[n][n]; double[][] res = RectangularArrays.ReturnRectangularDoubleArray(n, n); for (j = 0; j < n; j++) { for (i = 0; i <= j; i++) { product = 1.0; for (k = i; k < j; k++) { product *= b[k]; } res[i][j] = ((i + j) % 2 == 0 ? 1 : -1) * product * theta[i] * phi[j] / theta[n]; } for (i = j + 1; i < n; i++) { product = 1.0; for (k = j; k < i; k++) { product *= c[k]; } res[i][j] = ((i + j) % 2 == 0 ? 1 : -1) * product * theta[j] * phi[i] / theta[n]; } } return(DoubleMatrix.copyOf(res)); }
/// <summary> /// Gamma is in the form gamma^i_{j,k} =\partial^2y_j/\partial x_i \partial x_k, where i is the /// index of the matrix in the stack (3rd index of the tensor), and j,k are the individual /// matrix indices. We would like it in the form H^i_{j,k} =\partial^2y_i/\partial x_j \partial x_k, /// so that each matrix is a Hessian (for the dependent variable y_i), hence the reshaping below. /// </summary> /// <param name="gamma"> the rank 3 tensor </param> /// <returns> the reshaped rank 3 tensor </returns> private DoubleMatrix[] reshapeTensor(DoubleMatrix[] gamma) { int m = gamma.Length; int n = gamma[0].rowCount(); ArgChecker.isTrue(gamma[0].columnCount() == m, "tenor wrong size. Seond index is {}, should be {}", gamma[0].columnCount(), m); DoubleMatrix[] res = new DoubleMatrix[n]; for (int i = 0; i < n; i++) { //JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java: //ORIGINAL LINE: double[][] temp = new double[m][m]; double[][] temp = RectangularArrays.ReturnRectangularDoubleArray(m, m); for (int j = 0; j < m; j++) { DoubleMatrix gammaJ = gamma[j]; for (int k = j; k < m; k++) { temp[j][k] = gammaJ.get(i, k); } } for (int j = 0; j < m; j++) { for (int k = 0; k < j; k++) { temp[j][k] = temp[k][j]; } } res[i] = DoubleMatrix.copyOf(temp); } return(res); }
public static int[] fromTensorIndex(int index, int[] dimensions) { ArgChecker.notNull(dimensions, "dimensions"); int dim = dimensions.Length; int[] res = new int[dim]; int product = 1; int[] products = new int[dim - 1]; for (int i = 0; i < dim - 1; i++) { product *= dimensions[i]; products[i] = product; } int a = index; for (int i = dim - 1; i > 0; i--) { res[i] = a / products[i - 1]; a -= res[i] * products[i - 1]; } res[0] = a; return(res); }
public virtual double?[] getRoots(RealPolynomialFunction1D function) { ArgChecker.notNull(function, "function"); double[] coeffs = function.Coefficients; int l = coeffs.Length - 1; //JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java: //ORIGINAL LINE: double[][] hessianDeref = new double[l][l]; double[][] hessianDeref = RectangularArrays.ReturnRectangularDoubleArray(l, l); for (int i = 0; i < l; i++) { hessianDeref[0][i] = -coeffs[l - i - 1] / coeffs[l]; for (int j = 1; j < l; j++) { hessianDeref[j][i] = 0; if (i != l - 1) { hessianDeref[i + 1][i] = 1; } } } RealMatrix hessian = new Array2DRowRealMatrix(hessianDeref); double[] d = (new EigenDecomposition(hessian)).RealEigenvalues; double?[] result = new double?[d.Length]; for (int i = 0; i < d.Length; i++) { result[i] = d[i]; } return(result); }
/// <summary> /// Finds the node sensitivity. /// </summary> /// <param name="pp"> the <seealso cref="PiecewisePolynomialResultsWithSensitivity"/> </param> /// <param name="xKey"> the key </param> /// <returns> Node sensitivity value at x=xKey </returns> public virtual DoubleArray nodeSensitivity(PiecewisePolynomialResultsWithSensitivity pp, double xKey) { ArgChecker.notNull(pp, "null pp"); ArgChecker.isFalse(double.IsNaN(xKey), "xKey containing NaN"); ArgChecker.isFalse(double.IsInfinity(xKey), "xKey containing Infinity"); if (pp.Dimensions > 1) { throw new System.NotSupportedException(); } DoubleArray knots = pp.Knots; int nKnots = knots.size(); int interval = FunctionUtils.getLowerBoundIndex(knots, xKey); if (interval == nKnots - 1) { interval--; // there is 1 less interval that knots } double s = xKey - knots.get(interval); DoubleMatrix a = pp.getCoefficientSensitivity(interval); int nCoefs = a.rowCount(); DoubleArray res = a.row(0); for (int i = 1; i < nCoefs; i++) { res = (DoubleArray)MA.scale(res, s); res = (DoubleArray)MA.add(res, a.row(i)); } return(res); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the price sensitivity of the bond future option product based on curves. /// <para> /// The price sensitivity of the product is the sensitivity of the price to the underlying curves. /// The volatility is unchanged for a fixed strike in the sensitivity computation, hence the "StickyStrike" name. /// </para> /// <para> /// This calculates the underlying future price using the future pricer. /// /// </para> /// </summary> /// <param name="futureOption"> the option product </param> /// <param name="discountingProvider"> the discounting provider </param> /// <param name="volatilities"> the volatilities </param> /// <returns> the price curve sensitivity of the product </returns> public PointSensitivities priceSensitivityRatesStickyStrike(ResolvedBondFutureOption futureOption, LegalEntityDiscountingProvider discountingProvider, BlackBondFutureVolatilities volatilities) { ArgChecker.isTrue(futureOption.PremiumStyle.Equals(FutureOptionPremiumStyle.DAILY_MARGIN), "Premium style should be DAILY_MARGIN"); double futurePrice = this.futurePrice(futureOption, discountingProvider); return(priceSensitivityRatesStickyStrike(futureOption, discountingProvider, volatilities, futurePrice)); }
/// <summary> /// Solves the system Ax = y for the unknown vector x, where A is a tridiagonal matrix and y is a vector. /// This takes order n operations where n is the size of the system /// (number of linear equations), as opposed to order n^3 for the general problem. </summary> /// <param name="aM"> tridiagonal matrix </param> /// <param name="b"> known vector (must be same length as rows/columns of matrix) </param> /// <returns> vector (as an array of doubles) with same length as y </returns> public static double[] solvTriDag(TridiagonalMatrix aM, double[] b) { ArgChecker.notNull(aM, "null matrix"); ArgChecker.notNull(b, "null vector"); double[] d = aM.Diagonal; //b is modified, so get copy of diagonal int n = d.Length; ArgChecker.isTrue(n == b.Length, "vector y wrong length for matrix"); double[] y = Arrays.copyOf(b, n); double[] l = aM.LowerSubDiagonalData; double[] u = aM.UpperSubDiagonalData; double[] x = new double[n]; for (int i = 1; i < n; i++) { double m = l[i - 1] / d[i - 1]; d[i] = d[i] - m * u[i - 1]; y[i] = y[i] - m * y[i - 1]; } x[n - 1] = y[n - 1] / d[n - 1]; for (int i = n - 2; i >= 0; i--) { x[i] = (y[i] - u[i] * x[i + 1]) / d[i]; } return(x); }
public virtual double pvbp(RatePaymentPeriod paymentPeriod, RatesProvider provider) { ArgChecker.isTrue(!paymentPeriod.FxReset.Present, "FX reset is not supported"); int accPeriodCount = paymentPeriod.AccrualPeriods.size(); ArgChecker.isTrue(accPeriodCount == 1 || paymentPeriod.CompoundingMethod.Equals(CompoundingMethod.FLAT), "Only one accrued period or Flat compounding supported"); // no compounding if (accPeriodCount == 1) { RateAccrualPeriod accrualPeriod = paymentPeriod.AccrualPeriods.get(0); double df = provider.discountFactor(paymentPeriod.Currency, paymentPeriod.PaymentDate); return(df * accrualPeriod.YearFraction * paymentPeriod.Notional); } else { // Flat compounding switch (paymentPeriod.CompoundingMethod) { case FLAT: return(pvbpCompoundedFlat(paymentPeriod, provider)); default: throw new System.NotSupportedException("PVBP not implemented yet for non FLAT compounding"); } } }
/// <summary> /// Uses the parameters to create a function. /// </summary> /// <param name="x"> the value at which the function is to be evaluated, not null </param> /// <returns> a function that is always evaluated at <i>x</i> for different values of the parameters </returns> public virtual System.Func <T, U> asFunctionOfParameters(S x) { ArgChecker.notNull(x, "x"); return((T @params) => { return ParameterizedFunction.this.evaluate(x, @params); }); }
/// <summary> /// Constructor. </summary> /// <param name="ch"> The result of the Cholesky decomposition. </param> public CholeskyDecompositionCommonsResult(CholeskyDecomposition ch) { ArgChecker.notNull(ch, "Cholesky decomposition"); _determinant = ch.Determinant; _l = CommonsMathWrapper.unwrap(ch.L); _lt = CommonsMathWrapper.unwrap(ch.LT); _solver = ch.Solver; }
protected internal virtual void checkInputs(System.Func <double, double> f, double xLower, double xUpper) { ArgChecker.notNull(f, "function"); if (DoubleMath.fuzzyEquals(xLower, xUpper, ZERO)) { throw new System.ArgumentException("Lower and upper values were not distinct"); } }
/// <summary> /// {@inheritDoc} /// </summary> public virtual double?integrate(System.Func <double, double> function, double?lower, double?upper) { ArgChecker.notNull(function, "function"); ArgChecker.notNull(lower, "lower"); ArgChecker.notNull(upper, "upper"); System.Func <double, double> integral = getIntegralFunction(function, lower, upper); return(integrateFromPolyFunc(integral)); }
/// <summary> /// Creates an instance. /// </summary> /// <param name="n"> The number of sample points to be used in the integration, not negative or zero </param> /// <param name="generator"> The generator of weights and abscissas </param> public GaussianQuadratureIntegrator1D(int n, QuadratureWeightAndAbscissaFunction generator) { ArgChecker.isTrue(n > 0, "number of intervals must be > 0"); ArgChecker.notNull(generator, "generating function"); this.size = n; this.generator = generator; this.quadrature = generator.generate(size); }
/// <param name="abscissas"> An array containing the abscissas, not null </param> /// <param name="weights"> An array containing the weights, not null, must be the same length as the abscissa array </param> public GaussianQuadratureData(double[] abscissas, double[] weights) { ArgChecker.notNull(abscissas, "abscissas"); ArgChecker.notNull(weights, "weights"); ArgChecker.isTrue(abscissas.Length == weights.Length, "Abscissa and weight arrays must be the same length"); _weights = weights; _abscissas = abscissas; }
public virtual LUDecompositionResult apply(DoubleMatrix x) { ArgChecker.notNull(x, "x"); RealMatrix temp = CommonsMathWrapper.wrap(x); LUDecomposition lu = new LUDecomposition(temp); return(new LUDecompositionCommonsResult(lu)); }
/// <summary> /// Uses the parameters to create a function. /// </summary> /// <param name="params"> the parameters for which the function is to be evaluated, not null </param> /// <returns> a function that can be evaluated at different <i>x</i> with the input parameters </returns> public virtual System.Func <S, U> asFunctionOfArguments(T @params) { ArgChecker.notNull(@params, "params"); return((S x) => { return ParameterizedFunction.this.evaluate(x, @params); }); }
//------------------------------------------------------------------------- /// <summary> /// Calculates the price sensitivity of the Ibor future option product based on curves. /// <para> /// The price sensitivity of the product is the sensitivity of the price to the underlying curves. /// The volatility is unchanged for a fixed strike in the sensitivity computation, hence the "StickyStrike" name. /// </para> /// <para> /// This calculates the underlying future price using the future pricer. /// /// </para> /// </summary> /// <param name="futureOption"> the option product </param> /// <param name="ratesProvider"> the rates provider </param> /// <param name="volatilities"> the volatilities </param> /// <returns> the price curve sensitivity of the product </returns> public virtual PointSensitivities priceSensitivityRatesStickyStrike(ResolvedIborFutureOption futureOption, RatesProvider ratesProvider, NormalIborFutureOptionVolatilities volatilities) { ArgChecker.isTrue(futureOption.PremiumStyle.Equals(FutureOptionPremiumStyle.DAILY_MARGIN), "Premium style should be DAILY_MARGIN"); double futurePrice = this.futurePrice(futureOption, ratesProvider); return(priceSensitivityRatesStickyStrike(futureOption, ratesProvider, volatilities, futurePrice)); }
public override double?apply(double[] x) { ArgChecker.notNull(x, "x"); int n = x.Length; ArgChecker.isTrue(n >= 2, "Need at least two points to calculate the population variance"); return(_variance.apply(x) * (n - 1) / n); }