536cd135cc
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
648 lines
22 KiB
C#
648 lines
22 KiB
C#
//-------------------------------------------------------------
|
||
// <copyright company=’Microsoft Corporation’>
|
||
// Copyright © Microsoft Corporation. All Rights Reserved.
|
||
// </copyright>
|
||
//-------------------------------------------------------------
|
||
// @owner=alexgor, deliant
|
||
//=================================================================
|
||
// File: TimeSeriesAndForecasting.cs
|
||
//
|
||
// Namespace: System.Web.UI.WebControls[Windows.Forms].Charting.Formulas
|
||
//
|
||
// Classes: TimeSeriesAndForecasting
|
||
//
|
||
// Purpose: This class is used for calculations of
|
||
// time series and forecasting
|
||
//
|
||
// Reviewed: GS - August 7, 2002
|
||
// AG - August 7, 2002
|
||
//
|
||
//===================================================================
|
||
|
||
using System;
|
||
using System.Globalization;
|
||
|
||
#if Microsoft_CONTROL
|
||
namespace System.Windows.Forms.DataVisualization.Charting.Formulas
|
||
#else
|
||
namespace System.Web.UI.DataVisualization.Charting.Formulas
|
||
#endif
|
||
{
|
||
/// <summary>
|
||
/// This class is used for calculations of
|
||
/// time series and forecasting
|
||
/// </summary>
|
||
internal class TimeSeriesAndForecasting : IFormula
|
||
{
|
||
#region Enumeration
|
||
|
||
/// <summary>
|
||
/// AxisName of regression
|
||
/// </summary>
|
||
internal enum RegressionType
|
||
{
|
||
/// <summary>
|
||
/// Polynomial trend
|
||
/// </summary>
|
||
Polynomial,
|
||
|
||
/// <summary>
|
||
/// IsLogarithmic trend
|
||
/// </summary>
|
||
Logarithmic,
|
||
|
||
/// <summary>
|
||
/// Power trend
|
||
/// </summary>
|
||
Power,
|
||
|
||
/// <summary>
|
||
/// Exponential trend
|
||
/// </summary>
|
||
Exponential
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Properties
|
||
|
||
/// <summary>
|
||
/// Formula Module name
|
||
/// </summary>
|
||
virtual public string Name { get { return SR.FormulaNameTimeSeriesAndForecasting; } }
|
||
|
||
#endregion
|
||
|
||
#region Methods
|
||
|
||
/// <summary>
|
||
/// Public constructor.
|
||
/// </summary>
|
||
public TimeSeriesAndForecasting()
|
||
{
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// The first method in the module, which converts a formula
|
||
/// name to the corresponding private method.
|
||
/// </summary>
|
||
/// <param name="formulaName">String which represent a formula name</param>
|
||
/// <param name="inputValues">Arrays of doubles - Input values</param>
|
||
/// <param name="outputValues">Arrays of doubles - Output values</param>
|
||
/// <param name="parameterList">Array of strings - Formula parameters</param>
|
||
/// <param name="extraParameterList">Array of strings - Extra Formula parameters from DataManipulator object</param>
|
||
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
|
||
virtual public void Formula( string formulaName, double [][] inputValues, out double [][] outputValues, string [] parameterList, string [] extraParameterList, out string [][] outLabels )
|
||
{
|
||
string name;
|
||
|
||
name = formulaName.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
|
||
|
||
// Not used for these formulas.
|
||
outLabels = null;
|
||
|
||
try
|
||
{
|
||
switch( name )
|
||
{
|
||
case "FORECASTING":
|
||
Forecasting( inputValues, out outputValues, parameterList );
|
||
break;
|
||
default:
|
||
outputValues = null;
|
||
break;
|
||
}
|
||
}
|
||
catch( IndexOutOfRangeException )
|
||
{
|
||
throw new InvalidOperationException( SR.ExceptionFormulaInvalidPeriod(name) );
|
||
}
|
||
catch( OverflowException )
|
||
{
|
||
throw new InvalidOperationException( SR.ExceptionFormulaNotEnoughDataPoints( name ) );
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Formulas
|
||
|
||
/// <summary>
|
||
/// Forecasting formula predicts future values of the time series variable.
|
||
/// Multiple regressions are used for this forecasting model. Any method
|
||
/// of fitting equations to data may be called regression. Such equations
|
||
/// are valuable for at least two purposes: making predictions and judging
|
||
/// the strength of relationships. Of the various methods of performing
|
||
/// regression, Last Square is the most widely used. This formula returns
|
||
/// two more series, which represents upper and lower bond of error. Error
|
||
/// is based on standard deviation and represents a linear combination of
|
||
/// approximation error and forecasting error.
|
||
/// ---------------------------------------------------------
|
||
/// Input:
|
||
/// - Y values.
|
||
/// Output:
|
||
/// - Forecasting
|
||
/// - upper bond error
|
||
/// - lower bond error
|
||
/// Parameters:
|
||
/// - Polynomial degree (Default: 2 - Linear regression )
|
||
/// - Forecasting period (Default: Half of the series length )
|
||
/// - Returns Approximation error (Default: true)
|
||
/// - Returns Forecasting error (Default: true)
|
||
/// </summary>
|
||
/// <param name="inputValues">Arrays of doubles - Input values</param>
|
||
/// <param name="outputValues">Arrays of doubles - Output values</param>
|
||
/// <param name="parameterList">Array of strings - Parameters</param>
|
||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
|
||
private void Forecasting(double[][] inputValues, out double[][] outputValues, string[] parameterList)
|
||
{
|
||
// Polynomial degree
|
||
int degree;
|
||
RegressionType regressionType = RegressionType.Polynomial;
|
||
|
||
if (String.Equals(parameterList[0],"Exponential", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
regressionType = RegressionType.Exponential;
|
||
degree = 2;
|
||
}
|
||
else if (String.Equals(parameterList[0],"Linear", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
regressionType = RegressionType.Polynomial;
|
||
degree = 2;
|
||
}
|
||
else if (String.Equals(parameterList[0],"IsLogarithmic", StringComparison.OrdinalIgnoreCase) ||
|
||
String.Equals(parameterList[0],"Logarithmic", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
regressionType = RegressionType.Logarithmic;
|
||
degree = 2;
|
||
}
|
||
else if (String.Equals(parameterList[0],"Power", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
regressionType = RegressionType.Power;
|
||
degree = 2;
|
||
}
|
||
else
|
||
{
|
||
if (parameterList.Length < 1 ||
|
||
!int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out degree))
|
||
{
|
||
degree = 2;
|
||
}
|
||
}
|
||
|
||
|
||
if (degree > 5 || degree < 1)
|
||
throw new InvalidOperationException(SR.ExceptionForecastingDegreeInvalid);
|
||
|
||
if (degree > inputValues[0].Length)
|
||
throw new InvalidOperationException(SR.ExceptionForecastingNotEnoughDataPoints(degree.ToString(System.Globalization.CultureInfo.InvariantCulture)));
|
||
|
||
// Forecasting period
|
||
int period;
|
||
if (parameterList.Length < 2 ||
|
||
!int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out period))
|
||
{
|
||
period = inputValues[0].Length / 2;
|
||
}
|
||
|
||
// Approximation error
|
||
bool approximationError;
|
||
if (parameterList.Length < 3 ||
|
||
!bool.TryParse(parameterList[2], out approximationError))
|
||
{
|
||
approximationError = true;
|
||
}
|
||
|
||
// Forecasting error
|
||
bool forecastingError;
|
||
if (parameterList.Length < 4 ||
|
||
!bool.TryParse(parameterList[3], out forecastingError))
|
||
{
|
||
forecastingError = true;
|
||
}
|
||
|
||
double[][] tempOut;
|
||
// Find regresion
|
||
Regression(regressionType, inputValues, out tempOut, degree, period);
|
||
|
||
// If error disabled get out from procedure
|
||
if (!forecastingError && !approximationError)
|
||
{
|
||
outputValues = tempOut;
|
||
return;
|
||
}
|
||
|
||
double[][] inputErrorEst = new double[2][];
|
||
double[][] outputErrorEst;
|
||
inputErrorEst[0] = new double[inputValues[0].Length / 2];
|
||
inputErrorEst[1] = new double[inputValues[0].Length / 2];
|
||
|
||
for (int index = 0; index < inputValues[0].Length / 2; index++)
|
||
{
|
||
inputErrorEst[0][index] = inputValues[0][index];
|
||
inputErrorEst[1][index] = inputValues[1][index];
|
||
}
|
||
|
||
Regression(regressionType, inputErrorEst, out outputErrorEst, degree, inputValues[0].Length / 2);
|
||
|
||
// Find the average for forecasting error
|
||
double error = 0;
|
||
for (int index = inputValues[0].Length / 2; index < outputErrorEst[1].Length; index++)
|
||
{
|
||
error += (outputErrorEst[1][index] - inputValues[1][index]) * (outputErrorEst[1][index] - inputValues[1][index]);
|
||
}
|
||
error /= inputValues[0].Length - inputValues[0].Length / 2;
|
||
error = Math.Sqrt(error);
|
||
error /= (inputValues[0].Length / 4);
|
||
|
||
// Find the standard deviation
|
||
double dev = 0;
|
||
for (int index = 0; index < inputValues[0].Length; index++)
|
||
{
|
||
dev += (tempOut[1][index] - inputValues[1][index]) * (tempOut[1][index] - inputValues[1][index]);
|
||
}
|
||
dev /= inputValues[0].Length;
|
||
dev = Math.Sqrt(dev);
|
||
|
||
outputValues = new double[4][];
|
||
outputValues[0] = tempOut[0];
|
||
outputValues[1] = tempOut[1];
|
||
outputValues[2] = new double[tempOut[0].Length];
|
||
outputValues[3] = new double[tempOut[0].Length];
|
||
|
||
if (!approximationError)
|
||
dev = 0;
|
||
|
||
if (!forecastingError)
|
||
error = 0;
|
||
|
||
for (int index = 0; index < inputValues[0].Length; index++)
|
||
{
|
||
outputValues[2][index] = tempOut[1][index] + 2 * dev;
|
||
outputValues[3][index] = tempOut[1][index] - 2 * dev;
|
||
}
|
||
double sumError = 0;
|
||
for (int index = inputValues[0].Length; index < tempOut[0].Length; index++)
|
||
{
|
||
sumError += error;
|
||
outputValues[2][index] = tempOut[1][index] + sumError + 2 * dev;
|
||
outputValues[3][index] = tempOut[1][index] - sumError - 2 * dev;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Any method of fitting equations to data may be called regression.
|
||
/// Such equations are valuable for at least two purposes: making
|
||
/// predictions and judging the strength of relationships. Of the
|
||
/// various methods of performing regression, Last Square is the
|
||
/// most widely used.
|
||
/// </summary>
|
||
/// <param name="regressionType">AxisName of regression Polynomial, exponential, etc.</param>
|
||
/// <param name="inputValues">Arrays of doubles - Input values</param>
|
||
/// <param name="outputValues">Arrays of doubles - Output values</param>
|
||
/// <param name="polynomialDegree">Polynomial degree (Default: 2 - Linear regression )</param>
|
||
/// <param name="forecastingPeriod">Forecasting period (Default: Half of the series length )</param>
|
||
private void Regression( RegressionType regressionType, double [][] inputValues, out double [][] outputValues, int polynomialDegree, int forecastingPeriod )
|
||
{
|
||
if( regressionType == RegressionType.Exponential )
|
||
{
|
||
double [] oldYValues = new double[ inputValues[1].Length ];
|
||
for( int index = 0; index < inputValues[1].Length; index++ )
|
||
{
|
||
oldYValues[ index ] = inputValues[1][index];
|
||
if( inputValues[1][index] <= 0 )
|
||
{
|
||
throw new InvalidOperationException(SR.ExceptionForecastingExponentialRegressionHasZeroYValues);
|
||
}
|
||
inputValues[1][index] = Math.Log( inputValues[1][index] );
|
||
}
|
||
|
||
|
||
|
||
PolynomialRegression( regressionType, inputValues, out outputValues, 2, forecastingPeriod, 0 );
|
||
|
||
inputValues[1] = oldYValues;
|
||
}
|
||
else if( regressionType == RegressionType.Logarithmic )
|
||
{
|
||
double interval;
|
||
double first = inputValues[0][0];
|
||
|
||
// Find Interval for X values
|
||
interval = Math.Abs( inputValues[0][0] - inputValues[0][inputValues[0].Length - 1] ) / ( inputValues[0].Length - 1 );
|
||
|
||
if( interval <= 0 )
|
||
interval = 1;
|
||
|
||
for( int index = 0; index < inputValues[0].Length; index++ )
|
||
{
|
||
inputValues[0][index] = Math.Log( inputValues[0][index] );
|
||
}
|
||
|
||
PolynomialRegression( regressionType, inputValues, out outputValues, 2, forecastingPeriod, interval );
|
||
|
||
// Create Y values based on approximation.
|
||
for( int i = 0; i < outputValues[0].Length; i++ )
|
||
{
|
||
// Set X value
|
||
outputValues[0][i] = first + i * interval;
|
||
}
|
||
}
|
||
else if( regressionType == RegressionType.Power )
|
||
{
|
||
double [] oldYValues = new double[ inputValues[1].Length ];
|
||
double interval;
|
||
double first = inputValues[0][0];
|
||
|
||
for( int index = 0; index < inputValues[1].Length; index++ )
|
||
{
|
||
oldYValues[ index ] = inputValues[1][index];
|
||
if( inputValues[1][index] <= 0 )
|
||
{
|
||
throw new InvalidOperationException(SR.ExceptionForecastingPowerRegressionHasZeroYValues);
|
||
}
|
||
}
|
||
|
||
// Find Interval for X values
|
||
interval = Math.Abs( inputValues[0][0] - inputValues[0][inputValues[0].Length - 1] ) / ( inputValues[0].Length - 1 );
|
||
|
||
if( interval <= 0 )
|
||
interval = 1;
|
||
|
||
PolynomialRegression( regressionType, inputValues, out outputValues, 2, forecastingPeriod, interval );
|
||
|
||
inputValues[1] = oldYValues;
|
||
|
||
// Create Y values based on approximation.
|
||
for( int i = 0; i < outputValues[0].Length; i++ )
|
||
{
|
||
// Set X value
|
||
outputValues[0][i] = first + i * interval;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
PolynomialRegression( regressionType, inputValues, out outputValues, polynomialDegree, forecastingPeriod, 0 );
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Any method of fitting equations to data may be called regression.
|
||
/// Such equations are valuable for at least two purposes: making
|
||
/// predictions and judging the strength of relationships. Of the
|
||
/// various methods of performing regression, Last Square is the
|
||
/// most widely used.
|
||
/// </summary>
|
||
/// <param name="regressionType">AxisName of regression Polynomial, exponential, etc.</param>
|
||
/// <param name="inputValues">Arrays of doubles - Input values</param>
|
||
/// <param name="outputValues">Arrays of doubles - Output values</param>
|
||
/// <param name="polynomialDegree">Polynomial degree (Default: 2 - Linear regression )</param>
|
||
/// <param name="forecastingPeriod">Forecasting period (Default: Half of the series length )</param>
|
||
/// <param name="logInterval">Interval for logarithmic scale</param>
|
||
private void PolynomialRegression( RegressionType regressionType, double [][] inputValues, out double [][] outputValues, int polynomialDegree, int forecastingPeriod, double logInterval )
|
||
{
|
||
double [] coefficients = new double [polynomialDegree];
|
||
int size = inputValues[0].Length;
|
||
double minimumX = double.MaxValue;
|
||
double interval = 1.0;
|
||
|
||
// Find Interval for X values
|
||
interval = Math.Abs( inputValues[0][0] - inputValues[0][inputValues[0].Length - 1] ) / ( inputValues[0].Length - 1 );
|
||
|
||
if( interval <= 0 )
|
||
interval = 1;
|
||
|
||
if( regressionType != RegressionType.Logarithmic )
|
||
{
|
||
// Avoid Rounding error because of big X values.
|
||
// Find Minimum X value
|
||
for( int xIndex = 0; xIndex < inputValues[0].Length; xIndex++ )
|
||
{
|
||
if( minimumX > inputValues[0][xIndex] )
|
||
minimumX = inputValues[0][xIndex];
|
||
}
|
||
|
||
// Change X values.
|
||
for( int xIndex = 0; xIndex < inputValues[0].Length; xIndex++ )
|
||
{
|
||
inputValues[0][xIndex] -= minimumX - 1;
|
||
}
|
||
}
|
||
|
||
if( regressionType == RegressionType.Power )
|
||
{
|
||
for( int index = 0; index < inputValues[0].Length; index++ )
|
||
{
|
||
inputValues[0][index] = Math.Log( inputValues[0][index] );
|
||
inputValues[1][index] = Math.Log( inputValues[1][index] );
|
||
}
|
||
}
|
||
|
||
double [][] mainDeterminant = new double [polynomialDegree][];
|
||
for(int arrayIndex = 0; arrayIndex < polynomialDegree; arrayIndex++)
|
||
{
|
||
mainDeterminant[arrayIndex] = new double [polynomialDegree];
|
||
}
|
||
|
||
// Main determinant
|
||
for( int k = 0; k < polynomialDegree; k++ )
|
||
{
|
||
for( int i = 0; i < polynomialDegree; i++ )
|
||
{
|
||
mainDeterminant[i][k] = 0;
|
||
for( int j = 0; j < inputValues[0].Length; j++ )
|
||
{
|
||
mainDeterminant[i][k] += (double)Math.Pow( inputValues[0][j], (i+k) );
|
||
}
|
||
}
|
||
}
|
||
double mainValue = Determinant(mainDeterminant);
|
||
|
||
// Coefficient determinant
|
||
for( int i = 0; i < polynomialDegree; i++ )
|
||
{
|
||
double [][] coeffDeterminant = CopyDeterminant(mainDeterminant);
|
||
for( int k = 0; k < polynomialDegree; k++ )
|
||
{
|
||
coeffDeterminant[i][k] = 0;
|
||
for( int j = 0; j < inputValues[0].Length; j++ )
|
||
{
|
||
coeffDeterminant[i][k] += (double)inputValues[1][j] * (double)Math.Pow( inputValues[0][j], k );
|
||
}
|
||
}
|
||
coefficients[i] = Determinant(coeffDeterminant) / mainValue;
|
||
}
|
||
|
||
// Create output arrays for approximation and forecasting
|
||
outputValues = new double[2][];
|
||
outputValues[0] = new double[size + forecastingPeriod];
|
||
outputValues[1] = new double[size + forecastingPeriod];
|
||
|
||
if( regressionType == RegressionType.Polynomial )
|
||
{
|
||
// Create Y values based on approximation.
|
||
for( int i = 0; i < size + forecastingPeriod; i++ )
|
||
{
|
||
// Set X value
|
||
outputValues[0][i] = inputValues[0][0] + i * interval;
|
||
|
||
outputValues[1][i] = 0;
|
||
for( int j = 0; j < polynomialDegree; j++ )
|
||
{
|
||
outputValues[1][i]+= (double)coefficients[j]*Math.Pow(outputValues[0][i],j);
|
||
}
|
||
}
|
||
}
|
||
else if( regressionType == RegressionType.Exponential )
|
||
{
|
||
// Create Y values based on approximation.
|
||
for( int i = 0; i < size + forecastingPeriod; i++ )
|
||
{
|
||
// Set X value
|
||
outputValues[0][i] = inputValues[0][0] + i * interval;
|
||
|
||
outputValues[1][i]= Math.Exp( coefficients[0] ) * Math.Exp( coefficients[1] * outputValues[0][i] );
|
||
}
|
||
}
|
||
else if( regressionType == RegressionType.Logarithmic )
|
||
{
|
||
// Create Y values based on approximation.
|
||
for( int i = 0; i < size + forecastingPeriod; i++ )
|
||
{
|
||
// Set X value
|
||
outputValues[0][i] = Math.Exp( inputValues[0][0] ) + i * logInterval;
|
||
|
||
outputValues[1][i]= coefficients[1] * Math.Log( outputValues[0][i] ) + coefficients[0];
|
||
}
|
||
}
|
||
else if( regressionType == RegressionType.Power )
|
||
{
|
||
// Create Y values based on approximation.
|
||
for( int i = 0; i < size + forecastingPeriod; i++ )
|
||
{
|
||
// Set X value
|
||
outputValues[0][i] = Math.Exp( inputValues[0][0] ) + i * logInterval;
|
||
|
||
outputValues[1][i]= Math.Exp( coefficients[0] ) * Math.Pow( outputValues[0][i], coefficients[1] );
|
||
}
|
||
}
|
||
|
||
if( regressionType != RegressionType.Logarithmic )
|
||
{
|
||
// Return X values.
|
||
for( int xIndex = 0; xIndex < size + forecastingPeriod; xIndex++ )
|
||
{
|
||
outputValues[0][xIndex] += minimumX - 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// This method recalculates determinant. This method is used for
|
||
/// recursive calls for sub determinants too.
|
||
/// </summary>
|
||
/// <param name="inputDeterminant">Input determinant</param>
|
||
/// <returns>Result of determinant</returns>
|
||
private double Determinant( double [][] inputDeterminant )
|
||
{
|
||
double sum = 0;
|
||
double sign = 1.0;
|
||
|
||
// Determinant is 2X2 - calculate value
|
||
if( inputDeterminant.Length == 2 )
|
||
{
|
||
return inputDeterminant[0][0]*inputDeterminant[1][1] - inputDeterminant[0][1]*inputDeterminant[1][0];
|
||
}
|
||
|
||
// Determinant is biger than 2X2. Go to recursive
|
||
// call of Determinant method
|
||
for( int column = 0; column < inputDeterminant.GetLength(0); column++ )
|
||
{
|
||
// Make sub determinant
|
||
double [][] newDeterminant = MakeSubDeterminant( inputDeterminant, column );
|
||
|
||
sum += sign * Determinant( newDeterminant ) * inputDeterminant[column][0];
|
||
sign *= -1.0;
|
||
}
|
||
return sum;
|
||
}
|
||
|
||
/// <summary>
|
||
/// This method will create a new determinant, which is
|
||
/// smaller by one rank (dimension). Specified column
|
||
/// and zero rows will be skipped.
|
||
/// </summary>
|
||
/// <param name="inputDeterminant">Input determinant</param>
|
||
/// <param name="columnPos">Position of column, which has to be skipped</param>
|
||
/// <returns>New determinant</returns>
|
||
private double [][] MakeSubDeterminant( double [][] inputDeterminant, int columnPos )
|
||
{
|
||
// Get Determinant Size
|
||
int size = inputDeterminant.GetLength(0);
|
||
|
||
// Prepare sub Determinant
|
||
double [][] newDeterminant = new double [size - 1][];
|
||
for(int arrayIndex = 0; arrayIndex < size - 1; arrayIndex++)
|
||
{
|
||
newDeterminant[arrayIndex] = new double [size - 1];
|
||
}
|
||
|
||
|
||
int newColumn = 0;
|
||
// Copy columns
|
||
for( int column = 0; column < size; column++ )
|
||
{
|
||
// Skeep this column
|
||
if( column == columnPos )
|
||
continue;
|
||
|
||
// Copy rows
|
||
for( int row = 1; row < size; row++ )
|
||
{
|
||
newDeterminant[newColumn][row-1] = inputDeterminant[column][row];
|
||
}
|
||
|
||
// Go to new column for new determinant
|
||
newColumn++;
|
||
}
|
||
|
||
// Return new determinant
|
||
return newDeterminant;
|
||
}
|
||
|
||
/// <summary>
|
||
/// This method will copy determinant
|
||
/// </summary>
|
||
/// <param name="inputDeterminant">Input determinant</param>
|
||
/// <returns>New determinant</returns>
|
||
private double [][] CopyDeterminant( double [][] inputDeterminant )
|
||
{
|
||
// Get Determinant Size
|
||
int size = inputDeterminant.GetLength(0);
|
||
|
||
// Prepare sub Determinant
|
||
double [][] newDeterminant = new double [size][];
|
||
for(int arrayIndex = 0; arrayIndex < size; arrayIndex++)
|
||
{
|
||
newDeterminant[arrayIndex] = new double [size];
|
||
}
|
||
|
||
// Copy columns
|
||
for( int column = 0; column < size; column++ )
|
||
{
|
||
// Copy rows
|
||
for( int row = 0; row < size; row++ )
|
||
{
|
||
newDeterminant[column][row] = inputDeterminant[column][row];
|
||
}
|
||
}
|
||
|
||
// Return new determinant
|
||
return newDeterminant;
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
}
|