Example #1
0
        /// <summary>
        /// This function solves simultaneous equations in matrix form.
        /// The equations are represented by the matrix equation:
        ///
        ///     aMatrix xVector = bVector
        ///
        /// The algorithm is from the book:
        /// "Mathematical Methods For Digital Computers" Volume 2
        /// Edited by Anthony Ralston and Herbert S. Wilf, 1967,
        /// John Wiley and Sons, pages 65-93.
        /// "The solution of ill-conditioned linear equations"
        /// by J. H. Wilkinson.
        /// </summary>
        /// <param name="numberOfEquations">The number of equations</param>
        /// <param name="aMatrix">A square matrix</param>
        /// <param name="bVector">A vector that contains the right hand side of the matrix equations shown below.</param>
        /// <param name="xVector">A vector to contain the solution of the matrix equations.</param>
        /// <returns>
        /// This function returns an enumerated value of type Status_T
        /// that is the value LinearEquationSolverStatus.Singular if the
        /// coefficient matrix is singular to working accuracy. A value of
        /// LinearEquationSolverStatus.IllConditioned is returned if the
        /// coefficient matrix is singular to working accuracy, i.e. the
        /// floating point arithmetic does not have enough precision to
        /// guarantee convergence to an accurate solution.
        /// The value LinearEquationSolverStatus.Success is returned
        /// if the solution vector was calculated successfully.
        /// </returns>
        public static LinearEquationSolverStatus Solve(int numberOfEquations,
                                                       Sparse2DMatrix <int, int, double> aMatrix,
                                                       SparseArray <int, double> bVector,
                                                       SparseArray <int, double> xVector)
        {
            //----------------------------------------------------------
            // Matrix a_matrix is copied into working matrix aMatrixCopy.
            //----------------------------------------------------------

            Sparse2DMatrix <int, int, double> aMatrixCopy = new Sparse2DMatrix <int, int, double>(aMatrix);

            //----------------------------------------------------------
            // The maximum value rowMaximumVector[i], i = 0 to n - 1
            // is stored
            //----------------------------------------------------------

            SparseArray <int, double> rowMaximumVector = new SparseArray <int, double>();

            int i;

            for (i = 0; i < numberOfEquations; i++)
            {
                double temp = 0.0;

                for (int j = 0; j < numberOfEquations; j++)
                {
                    double test = Math.Abs(aMatrix[i, j]);

                    if (test > temp)
                    {
                        temp = test;
                    }
                }

                rowMaximumVector[i] = temp;

                //----------------------------------------------------------
                // Test for singular matrix.
                //----------------------------------------------------------

                if (Math.Abs(temp) <= 0.0)
                {
                    return(LinearEquationSolverStatus.Singular);
                }
            }

            //----------------------------------------------------------
            // The r'th column of "l", the r'th pivotal position r', and
            // the r'th row of "u" are determined.
            //----------------------------------------------------------

            SparseArray <int, int> pivotRowArray = new SparseArray <int, int>();

            for (int r = 0; r < numberOfEquations; r++)
            {
                double maximumValue         = 0.0;
                int    rowMaximumValueIndex = r;

                //----------------------------------------------------------
                // The l[i][r], i = r to n - 1 are determined.
                // l[i][r] is a lower triangular matrix. It is calculated
                // using the variable temp and copied into matrix
                // "aMatrixCopy". The variable "maximumValue" contains
                // the largest Math.Abs(l[i][r] / pivotRowArray[i]) and
                // rowMaximumValueIndex stores the "i" which corresponds
                // to the value in variable maximumValue.
                //----------------------------------------------------------

                double temp;

                for (i = r; i < numberOfEquations; i++)
                {
                    temp = aMatrixCopy[i, r];

                    for (int j = 0; j < r; j++)
                    {
                        temp = temp - aMatrixCopy[i, j] * aMatrixCopy[j, r];
                    }

                    aMatrixCopy[i, r] = temp;

                    double test = Math.Abs(temp / rowMaximumVector[i]);

                    if (test > maximumValue)
                    {
                        maximumValue         = test;
                        rowMaximumValueIndex = i;
                    }
                }

                //----------------------------------------------------------
                // Test for matrix which is singular to working precision.
                //----------------------------------------------------------

                if (Math.Abs(maximumValue) <= 0.0)
                {
                    return(LinearEquationSolverStatus.IllConditioned);
                }

                //----------------------------------------------------------
                // "rowMaximumValueIndex" = r' and "pivotRowArray[r]"
                // is the pivotal row.
                //----------------------------------------------------------

                rowMaximumVector[rowMaximumValueIndex] = rowMaximumVector[r];
                pivotRowArray[r] = rowMaximumValueIndex;

                //----------------------------------------------------------
                // Rows "r" and "pivotRowArray[r]" are exchanged.
                //----------------------------------------------------------

                for (i = 0; i < numberOfEquations; i++)
                {
                    temp = aMatrixCopy[r, i];
                    aMatrixCopy[r, i] = aMatrixCopy[rowMaximumValueIndex, i];
                    aMatrixCopy[rowMaximumValueIndex, i] = temp;
                }

                //----------------------------------------------------------
                // The u[r][i], i = r + 1 to n - 1 are determined.
                // "u[r][i]" is an upper triangular matrix. It is copied
                // into aMatrixCopy.
                //----------------------------------------------------------

                for (i = r + 1; i < numberOfEquations; i++)
                {
                    temp = aMatrixCopy[r, i];

                    for (int j = 0; j < r; j++)
                    {
                        temp = temp - aMatrixCopy[r, j] * aMatrixCopy[j, i];
                    }

                    aMatrixCopy[r, i] = temp / aMatrixCopy[r, r];
                }
            }

            //----------------------------------------------------------
            // The first solution vector is set equal to the null vector
            // and the first residuals are set equal to the equation
            // constant vector.
            //----------------------------------------------------------

            SparseArray <int, double> residualVector = new SparseArray <int, double>();

            for (i = 0; i < numberOfEquations; i++)
            {
                xVector[i]        = 0.0;
                residualVector[i] = bVector[i];
            }

            //----------------------------------------------------------
            // The iteration counter is initialized.
            //----------------------------------------------------------

            int  iteration        = 0;
            bool notConvergedFlag = true;

            do
            {
                //----------------------------------------------------------
                // The forward substitution is performed and the solution
                // of l y = p r is calculated where p r is the current
                // residual after interchanges.
                //----------------------------------------------------------

                for (i = 0; i < numberOfEquations; i++)
                {
                    int    pivotRowIndex = pivotRowArray[i];
                    double temp          = residualVector[pivotRowIndex];
                    residualVector[pivotRowIndex] = residualVector[i];

                    for (int j = 0; j < i; j++)
                    {
                        temp = temp - aMatrixCopy[i, j] * residualVector[j];
                    }

                    residualVector[i] = temp / aMatrixCopy[i, i];
                }

                //----------------------------------------------------------
                // The back substitution is performed and the solution of
                // u e = y is calculated. The current correction is stored
                // in variable residualVector.
                //----------------------------------------------------------

                for (i = numberOfEquations - 1; i >= 0; i--)
                {
                    double temp = residualVector[i];

                    for (int j = i + 1; j < numberOfEquations; j++)
                    {
                        temp = temp - aMatrixCopy[i, j] * residualVector[j];
                    }

                    residualVector[i] = temp;
                }

                //----------------------------------------------------------
                // The norm of the error in the residuals and the norm of
                // the present solution vector are calculated.
                //----------------------------------------------------------

                double normOfX     = 0.0;
                double normOfError = 0.0;

                for (i = 0; i < numberOfEquations; i++)
                {
                    double test = Math.Abs(xVector[i]);

                    if (test > normOfX)
                    {
                        normOfX = test;
                    }

                    test = Math.Abs(residualVector[i]);

                    if (test > normOfError)
                    {
                        normOfError = test;
                    }
                }

                //----------------------------------------------------------
                // If iteration is zero then skip this section because
                // no correction exists on the first iteration.
                //----------------------------------------------------------

                if (iteration != 0)
                {
                    //------------------------------------------------------
                    // Test for matrix which is singular to working
                    // precision.
                    //------------------------------------------------------

                    if ((iteration == 1) && (normOfError / normOfX > 0.5))
                    {
                        return(LinearEquationSolverStatus.IllConditioned);
                    }

                    //------------------------------------------------------
                    // Check to see if "normOfError" / "normOfX" is greater
                    // than 2 ^ (1 - t), where "t" is the number of bits
                    // in the mantissa of a double precision number. If
                    // this is not true then the last correction is almost
                    // negligible and "notConvergedFlag" is set to false.
                    //------------------------------------------------------

                    notConvergedFlag = normOfError / normOfX >= SSmallFloatingPointValue;

#if DEBUGCODE
                    double normRatioForDebug = normOfError / normOfX;
#endif
                }

                //----------------------------------------------------------
                // The corrections (residuals) are added to the
                // solution vector.
                //----------------------------------------------------------

                for (i = 0; i < numberOfEquations; i++)
                {
                    xVector[i] = xVector[i] + residualVector[i];
                }

                //----------------------------------------------------------
                // The new residuals corresponding to the solution vector
                // are calculated.
                //----------------------------------------------------------

                for (i = 0; i < numberOfEquations; i++)
                {
                    double temp = bVector[i];

                    for (int j = 0; j < numberOfEquations; j++)
                    {
                        temp = temp - aMatrix[i, j] * xVector[j];
                    }

                    residualVector[i] = temp;
                }

                //----------------------------------------------------------
                // The iteration counter is incremented and the flag
                // "notConvergedFlag" is tested. If notConvergedFlag is false
                // then the solution vector has converged to sufficient
                // accuracy.
                //----------------------------------------------------------

                iteration++;
            }while (notConvergedFlag);

            return(LinearEquationSolverStatus.Success);
        }
Example #2
0
        /// <summary>
        /// This method gets a term in the simultaneous equation. The term
        /// can be a number, a variable, or a number and a variable. A term
        /// cannot be split between lines input to this method.
        /// </summary>
        /// <param name="inputLine">The input line to be parsed</param>
        /// <param name="positionIndex">The current parse position in the input string.</param>
        /// <param name="aMatrix">The A matrix for the simultaneous equations.
        /// This is updated as each line of input is parsed.
        /// </param>
        /// <param name="bVector">The B vector for the simultaneous equations.
        /// This is updated as each line of input is parsed.</param>
        /// <param name="variableNameIndexMap">A map that stores the integer
        /// index for a variable using the variable name as a key.</param>
        /// <returns>This method returns the value 'true' if and only if a term is found.
        /// </returns>
        private bool GetTerm(string inputLine,
                             ref int positionIndex,
                             Sparse2DMatrix <int, int, double> aMatrix,
                             SparseArray <int, double> bVector,
                             SparseArray <string, int> variableNameIndexMap)
        {
            //------------------------------------------------------------------
            // A term is one of the following three patterns.
            //
            // <Space> <Sign> Number <Space>
            // <Space> <Sign> Variable <Space>
            // <Space> <Sign> Number Variable <Space>
            //
            // Check for a plus or a minus sign at the start of a term.
            //------------------------------------------------------------------

            bool numberIsNegativeFlag = false;

            GetSign(inputLine,
                    ref positionIndex,
                    ref numberIsNegativeFlag);

            //------------------------------------------------------------------
            // Skip whitespace characters
            //------------------------------------------------------------------

            SkipSpaces(inputLine, ref positionIndex);

            //------------------------------------------------------------------
            // Check to see if this is a number or a variable.
            //------------------------------------------------------------------

            string numberString = "";

            bool haveNumberFlag = GetNumber(inputLine,
                                            ref positionIndex,
                                            ref numberString);

            //------------------------------------------------------------------
            // If an error occurred then abort.
            //------------------------------------------------------------------

            if (LastStatusValue != LinearEquationParserStatus.Success)
            {
                return(false);
            }

            //------------------------------------------------------------------
            // If there was a number encountered then test to see if the
            // number has an exponent.
            //------------------------------------------------------------------

            if (haveNumberFlag)
            {
                if (positionIndex < inputLine.Length)
                {
                    //----------------------------------------------------------
                    // Does the number have an exponent?
                    //----------------------------------------------------------

                    if (inputLine[positionIndex] == '^')
                    {
                        positionIndex++;

                        //------------------------------------------------------
                        // Does the exponent have a sign.
                        //------------------------------------------------------

                        bool negativeExponentFlag = false;

                        GetSign(inputLine,
                                ref positionIndex,
                                ref negativeExponentFlag);

                        //------------------------------------------------------
                        // Get the exponent digits.
                        //------------------------------------------------------

                        string exponentString = "";

                        if (GetNumber(inputLine,
                                      ref positionIndex,
                                      ref exponentString))
                        {
                            //--------------------------------------------------
                            // Is the exponent a valid exponent.
                            //--------------------------------------------------

                            var exponentLength = exponentString.Length;

                            if (exponentLength <= 2)
                            {
                                var exponent_error_flag = false;

                                for (var i = 0; i < exponentLength; ++i)
                                {
                                    if (!char.IsDigit(exponentString[i]))
                                    {
                                        exponent_error_flag = true;
                                    }
                                }

                                if (!exponent_error_flag)
                                {
                                    numberString += 'E';

                                    if (negativeExponentFlag)
                                    {
                                        numberString += '-';
                                    }

                                    numberString += exponentString;
                                }
                                else
                                {
                                    SetLastStatusValue(LinearEquationParserStatus.ErrorIllegalExponent,
                                                       positionIndex);
                                    return(false);
                                }
                            }
                            else
                            {
                                SetLastStatusValue(LinearEquationParserStatus.ErrorIllegalExponent,
                                                   positionIndex);
                                return(false);
                            }
                        }
                        else
                        {
                            SetLastStatusValue(LinearEquationParserStatus.ErrorMissingExponent,
                                               positionIndex);
                            return(false);
                        }
                    }
                }
            }

            //------------------------------------------------------------------
            // Skip whitespace characters
            //------------------------------------------------------------------

            SkipSpaces(inputLine, ref positionIndex);

            string variableName = "";

            bool haveVariableNameFlag = GetVariableName(inputLine,
                                                        ref positionIndex,
                                                        ref variableName);

            //------------------------------------------------------------------
            // Calculate the sign of the value. The sign is negated
            // if the equals sign has been encountered.
            //------------------------------------------------------------------

            bool negativeFlag =
                m_equalSignInEquationFlag ^ m_negativeOperatorFlag ^ numberIsNegativeFlag;

            double value = 0.0;

            if (haveNumberFlag)
            {
                value = Convert.ToDouble(numberString);

                if (negativeFlag)
                {
                    value = -value;
                }
            }
            else
            {
                value = 1.0;

                if (negativeFlag)
                {
                    value = -value;
                }
            }

            //------------------------------------------------------------------
            // If a variable was encountered then add to the aMatrix.
            //------------------------------------------------------------------

            var haveTermFlag = false;

            if (haveVariableNameFlag)
            {
                //--------------------------------------------------------------
                // If either a number or a variable is found then a term was
                // found.
                //--------------------------------------------------------------

                haveTermFlag = true;

                //--------------------------------------------------------------
                // Each equation must have at least one variable.
                // Record that a variable was encountered in this equation.
                //--------------------------------------------------------------

                m_atLeastOneVariableInEquationFlag = true;
                //--------------------------------------------------------------
                // If this variable has not been encountered before then add
                // the variable to the variableNameIndexMap.
                //--------------------------------------------------------------

                if (!variableNameIndexMap.TryGetValue(variableName, out int variableNameIndex))
                {
                    // This is a new variable. Add it to the map.
                    variableNameIndex = variableNameIndexMap.Count;
                    variableNameIndexMap[variableName] = variableNameIndex;
                }

                aMatrix[m_equationIndex, variableNameIndex] =
                    aMatrix[m_equationIndex, variableNameIndex] + value;
            }
            else if (haveNumberFlag)
            {
                //--------------------------------------------------------------
                // If either a number or a variable is found then a term was
                // found.
                //--------------------------------------------------------------

                haveTermFlag = true;

                //--------------------------------------------------------------
                // Put the value in the B vector.
                //--------------------------------------------------------------

                bVector[m_equationIndex] = bVector[m_equationIndex] - value;
            }
            else
            {
                haveTermFlag = false;
                SetLastStatusValue(LinearEquationParserStatus.ErrorNoTermEncountered,
                                   positionIndex);
                return(false);
            }

            //------------------------------------------------------------------
            // There must be at least one term on each side of the equal sign.
            //------------------------------------------------------------------

            if (m_equalSignInEquationFlag)
            {
                m_termAfterEqualSignExistsFlag = true;
            }
            else
            {
                m_termBeforeEqualSignExistsFlag = true;
            }

            //------------------------------------------------------------------
            // Skip whitespace characters
            //------------------------------------------------------------------

            SkipSpaces(inputLine, ref positionIndex);

            return(true);
        }
Example #3
0
 /// <summary>
 /// Copy constructor.
 /// </summary>
 /// <param name="sparseArray">The sparse array instance to be copied</param>
 public SparseArray(SparseArray <TKey, TValue> sparseArray)
 {
     _mDictionary = new Dictionary <TKey, TValue>();
     Initialize(sparseArray);
     DefaultValue = sparseArray.DefaultValue;
 }
Example #4
0
        /// <summary>
        /// This function parses line that contains all or part of a simple
        /// linear equation. The equation contains terms separated by operators.
        /// The term can be a number, a variable, or a number and a variable.
        /// A term cannot be split between lines input to the parser method.
        /// The operators are either the plus character '+', the minus
        /// character '-', or the equal sign character '='.  Numbers can have
        /// up to 15 digits, a decimal point, and an exponent of a power
        /// of 10 that follows the '^' character.
        /// </summary>
        /// <param name="inputLine">The input line of text to be parsed</param>
        /// <param name="aMatrix">The A matrix for the simultaneous equations.
        /// This is updated as each line of input is parsed.
        /// </param>
        /// <param name="bVector">The B vector for the simultaneous equations.
        /// This is updated as each line of input is parsed.</param>
        /// <param name="variableNameIndexMap">A map that stores the integer
        /// index for a variable using the variable name as a key.</param>
        /// <param name="numberOfEquations">A reference to an integer that
        /// will contain the  number of equations when this method exits.
        /// </param>
        /// <returns>An enum of type LinearEquationParserStatus</returns>
        public LinearEquationParserStatus Parse(string inputLine,
                                                Sparse2DMatrix <int, int, double> aMatrix,
                                                SparseArray <int, double> bVector,
                                                SparseArray <string, int> variableNameIndexMap,
                                                ref int numberOfEquations)
        {
            //------------------------------------------------------------------
            // Trim any space characters from the end of the line.
            //------------------------------------------------------------------

            inputLine.TrimEnd(null);

            //------------------------------------------------------------------
            // Assume success status.
            //------------------------------------------------------------------

            int positionIndex = 0;

            SetLastStatusValue(LinearEquationParserStatus.Success, positionIndex);

            //------------------------------------------------------------------
            // Skip whitespace characters
            //------------------------------------------------------------------

            SkipSpaces(inputLine, ref positionIndex);

            //------------------------------------------------------------------
            // Save the position of the first non-whitespace character. If
            // the first term is not found at this position then set the
            // error status to report that it is likely that the last
            // equation was not properly terminated.
            //------------------------------------------------------------------

            m_startPosition = positionIndex;

            //------------------------------------------------------------------
            // Separate the input string into tokens.
            //
            // Variables contains the letters A through Z and the underscore
            // '_' character.
            //
            // Operators include plus '+', minus '-', and times '*'.
            //
            // Delimiters include the equals sign '='.
            //
            // Numbers include the digits 0 through 9, the decimal point
            // (period character) '.', an optional exponent character which
            // is the letter '^', and up to two digits for the optional exponent.
            //
            // Check for sequences of terms and operators.
            //
            // Term:
            //   <Space> <Sign> Number <Space>
            //   <Space> <Sign> Variable <Space>
            //   <Space> <Sign> Number Variable <Space>
            //
            // Operator:
            //   <Space> Plus <Space>
            //   <Space> Minus <Space>
            //   <Space> Equals <Space>
            //
            //--------------------------------------------------------------

            bool operatorFoundLast = false;

            while (positionIndex < inputLine.Length)
            {
                if (m_parserState == LinearEquationParserState.ParseTerm)
                {
                    //------------------------------------------------------
                    // Skip whitespace characters
                    //------------------------------------------------------

                    SkipSpaces(inputLine, ref positionIndex);

                    if (positionIndex < inputLine.Length)
                    {
                        if (GetTerm(inputLine,
                                    ref positionIndex,
                                    aMatrix,
                                    bVector,
                                    variableNameIndexMap))
                        {
                            m_parserState     = LinearEquationParserState.ParseOperator;
                            operatorFoundLast = false;
                        }
                        else
                        {
                            if (LastStatusValue == LinearEquationParserStatus.Success)
                            {
                                SetLastStatusValue(LinearEquationParserStatus.ErrorIllegalEquation,
                                                   positionIndex);
                            }

                            break;
                        }
                    }
                    else
                    {
                        break;
                    }
                }
                else if (m_parserState == LinearEquationParserState.ParseOperator)
                {
                    //------------------------------------------------------
                    // Skip whitespace characters
                    //------------------------------------------------------

                    SkipSpaces(inputLine, ref positionIndex);

                    if (positionIndex < inputLine.Length)
                    {
                        //------------------------------------------------------
                        // Check for plus sign, minus sign, or an equal sign.
                        //------------------------------------------------------

                        if (GetOperator(inputLine, ref positionIndex))
                        {
                            m_parserState     = LinearEquationParserState.ParseTerm;
                            operatorFoundLast = true;
                        }
                        else
                        {
                            if (LastStatusValue != LinearEquationParserStatus.Success)
                            {
                                if (positionIndex == m_startPosition)
                                {
                                    SetLastStatusValue(LinearEquationParserStatus.ErrorIllegalEquation,
                                                       positionIndex);
                                }
                            }

                            break;
                        }
                    }
                }
            }

            // If an operator was found at
            if ((positionIndex >= inputLine.Length) && (positionIndex > 0) && (!operatorFoundLast))
            {
                ResetForNewEquation();
                numberOfEquations = m_equationIndex;
            }

            return(LastStatusValue);
        }