/* * Author: Syed Mehroz Alam * Email: smehrozalam@yahoo.com * URL: Programming Home "http://www.geocities.com/smehrozalam/" * Date: 6/20/2004 * Time: 4:46 PM * */ using System; namespace Mehroz { /// /// Classes Contained: /// MatrixApplication /// Matrix (version 1.1) /// MatrixException /// Fraction (Version 2.0) /// FractionException /// /// /// class name: Application /// The class demonstrates the Matrix class /// public class MatrixApplication { public static void Main() { try { Console.WriteLine("Press 'm' for Matrix demo, 'e' for Equation Solver demo"); if ( Console.ReadLine().ToLower()=="e" ) EquationSolver(); else MatrixDemo(); Console.WriteLine("\n\nPress any key to exit"); } //end try catch (MatrixException exp) { Console.WriteLine("\nInternal Matrix Error: " + exp.Message); } catch (FractionException exp) { Console.WriteLine("\nInternal Fraction Error: " + exp.Message); } catch (Exception exp) { Console.WriteLine("\nSystem Error: " + exp);//.Message); } Console.ReadLine(); } public static void MatrixDemo() { Console.WriteLine("Enter no. of Rows: "); int iRows=Convert.ToInt32(Console.ReadLine()); Console.WriteLine("Enter no. of Cols: "); int iCols=Convert.ToInt32(Console.ReadLine()); Matrix m1=new Matrix(iRows,iCols); Matrix m2=new Matrix(iRows,iCols); System.Random rnd=new System.Random(); for ( int i=0;i0 && nn0 && j public class Matrix { /// /// Class attributes/members /// int m_iRows; int m_iCols; Fraction[,] m_iElement; /// /// Constructors /// public Matrix(Fraction[,] elements) { m_iElement=elements; m_iRows=elements.GetLength(0); m_iCols=elements.GetLength(1); } public Matrix(int[,] elements) { m_iRows=elements.GetLength(0); m_iCols=elements.GetLength(1);; m_iElement=new Fraction[m_iRows,m_iCols]; for(int i=0;i /// Properites /// public int Rows { get { return m_iRows; } } public int Cols { get { return m_iCols; } } /// /// Indexer /// public Fraction this[int iRow, int iCol] // matrix's index starts at 0,0 { get { return GetElement(iRow,iCol); } set { SetElement(iRow,iCol,value); } } /// /// Internal functions for getting/setting values /// private Fraction GetElement(int iRow, int iCol) { if ( iRow<0 || iRow>Rows-1 || iCol<0 || iCol>Cols-1 ) throw new MatrixException("Invalid index specified"); return m_iElement[iRow,iCol]; } private void SetElement(int iRow, int iCol, Fraction value) { if ( iRow<0 || iRow>Rows-1 || iCol<0 || iCol>Cols-1 ) throw new MatrixException("Invalid index specified"); m_iElement[iRow,iCol]=value.Duplicate(); } /// /// The function returns the current Matrix object as a string /// public override string ToString() { string str=""; for (int i=0;i /// The function return the Minor of element[Row,Col] of a Matrix object /// public static Matrix Minor(Matrix matrix, int iRow, int iCol) { Matrix minor=new Matrix(matrix.Rows-1, matrix.Cols-1); int m=0,n=0; for (int i=0;i /// The function multiplies the given row of the current matrix object by a Fraction /// public void MultiplyRow(int iRow, Fraction frac) { for (int j=0;j /// The function multiplies the given row of the current matrix object by an integer /// public void MultiplyRow(int iRow, int iNo) { this.MultiplyRow(iRow, new Fraction(iNo)); } /// /// The function multiplies the given row of the current matrix object by a double /// public void MultiplyRow(int iRow, double dbl) { this.MultiplyRow(iRow, Fraction.ToFraction(dbl)); } /// /// The function adds two rows for current matrix object /// It performs the following calculation: /// iTargetRow = iTargetRow + iMultiple*iSecondRow /// public void AddRow(int iTargetRow, int iSecondRow, Fraction iMultiple) { for (int j=0;j /// The function interchanges two rows of the current matrix object /// public void InterchangeRow(int iRow1, int iRow2) { for (int j=0;j /// The function concatenates the two given matrices column-wise /// it can be helpful in a equation solver class where the augmented matrix is obtained by concatenation /// public static Matrix Concatenate(Matrix matrix1, Matrix matrix2) { if (matrix1.Rows!=matrix2.Rows) throw new MatrixException("Concatenation not possible"); Matrix matrix=new Matrix(matrix1.Rows, matrix1.Cols+matrix2.Cols ); for (int i=0;i /// The function returns the determinent of the current Matrix object as Fraction /// It computes the determinent by reducing the matrix to reduced echelon form using row operations /// The function is very fast and efficient but may raise overflow exceptions in some cases. /// In such cases use the Determinent() function which computes determinent in the traditional /// manner(by using minors) /// public Fraction DeterminentFast() { if (this.Rows!=this.Cols) throw new MatrixException("Determinent of a non-square matrix doesn't exist"); Fraction det=new Fraction(1); try { Matrix ReducedEchelonMatrix=this.Duplicate(); for (int i=0;i=0;j--) { ReducedEchelonMatrix.AddRow( j, i, -ReducedEchelonMatrix[j,i]); } } return det; } catch(Exception) { throw new MatrixException("Determinent of the given matrix could not be calculated"); } } /// /// The function returns the determinent of the current Matrix object as Fraction /// It computes the determinent in the traditional way (i.e. using minors) /// It can be much slower(due to recursion) if the given matrix has order greater than 6 /// Try using DeterminentFast() function if the order of matrix is greater than 6 /// public Fraction Determinent() { return Determinent(this); } /// /// The helper function for the above Determinent() method /// it calls itself recursively and computes determinent using minors /// private Fraction Determinent(Matrix matrix) { Fraction det=new Fraction(0); if (matrix.Rows!=matrix.Cols) throw new MatrixException("Determinent of a non-square matrix doesn't exist"); if (matrix.Rows==1) return matrix[0,0]; for (int j=0;j /// The function returns the Echelon form of the current matrix /// public Matrix EchelonForm() { try { Matrix EchelonMatrix=this.Duplicate(); for (int i=0;i /// The function returns the reduced echelon form of the current matrix /// public Matrix ReducedEchelonForm() { try { Matrix ReducedEchelonMatrix=this.Duplicate(); for (int i=0;i=0;j--) ReducedEchelonMatrix.AddRow( j, i, -ReducedEchelonMatrix[j,i]); } return ReducedEchelonMatrix; } catch(Exception) { throw new MatrixException("Matrix can not be reduced to Echelon form"); } } /// /// The function returns the inverse of the current matrix using Reduced Echelon Form method /// The function is very fast and efficient but may raise overflow exceptions in some cases. /// In such cases use the Inverse() method which computes inverse in the traditional way(using adjoint). /// public Matrix InverseFast() { if ( this.DeterminentFast()==0 ) throw new MatrixException("Inverse of a singular matrix is not possible"); try { Matrix IdentityMatrix=Matrix.IdentityMatrix(this.Rows, this.Cols); Matrix ReducedEchelonMatrix=this.Duplicate(); for (int i=0;i=0;j--) { IdentityMatrix.AddRow( j, i, -ReducedEchelonMatrix[j,i]); ReducedEchelonMatrix.AddRow( j, i, -ReducedEchelonMatrix[j,i]); } } return IdentityMatrix; } catch(Exception) { throw new MatrixException("Inverse of the given matrix could not be calculated"); } } /// /// The function returns the inverse of the current matrix in the traditional way(by adjoint method) /// It can be much slower if the given matrix has order greater than 6 /// Try using InverseFast() function if the order of matrix is greater than 6 /// public Matrix Inverse() { if ( this.Determinent()==0 ) throw new MatrixException("Inverse of a singular matrix is not possible"); return ( this.Adjoint()/this.Determinent() ); } /// /// The function returns the adjoint of the current matrix /// public Matrix Adjoint() { if (this.Rows!=this.Cols) throw new MatrixException("Adjoint of a non-square matrix does not exists"); Matrix AdjointMatrix=new Matrix(this.Rows, this.Cols); for (int i=0;i /// The function returns the transpose of the current matrix /// public Matrix Transpose() { Matrix TransposeMatrix=new Matrix(this.Cols, this.Rows); for (int i=0;i /// The function duplicates the current Matrix object /// public Matrix Duplicate() { Matrix matrix=new Matrix(Rows,Cols); for (int i=0;i /// The function returns a Scalar Matrix of dimension ( Row x Col ) and scalar K /// public static Matrix ScalarMatrix(int iRows, int iCols, int K) { Fraction zero=new Fraction(0); Fraction scalar=new Fraction(K); Matrix matrix=new Matrix(iRows,iCols); for (int i=0;i /// The function returns an identity matrix of dimensions ( Row x Col ) /// public static Matrix IdentityMatrix(int iRows, int iCols) { return ScalarMatrix(iRows, iCols, 1); } /// /// The function returns a Unit Matrix of dimension ( Row x Col ) /// public static Matrix UnitMatrix(int iRows, int iCols) { Fraction temp=new Fraction(1); Matrix matrix=new Matrix(iRows,iCols); for (int i=0;i /// The function returns a Null Matrix of dimension ( Row x Col ) /// public static Matrix NullMatrix(int iRows, int iCols) { Fraction temp=new Fraction(0); Matrix matrix=new Matrix(iRows,iCols); for (int i=0;i /// Operators for the Matrix object /// includes -(unary), and binary opertors such as +,-,*,/ /// public static Matrix operator -(Matrix matrix) { return Matrix.Negate(matrix); } public static Matrix operator +(Matrix matrix1, Matrix matrix2) { return Matrix.Add(matrix1, matrix2); } public static Matrix operator -(Matrix matrix1, Matrix matrix2) { return Matrix.Add(matrix1, -matrix2); } public static Matrix operator *(Matrix matrix1, Matrix matrix2) { return Matrix.Multiply(matrix1, matrix2); } public static Matrix operator *(Matrix matrix1, int iNo) { return Matrix.Multiply(matrix1, iNo); } public static Matrix operator *(Matrix matrix1, double dbl) { return Matrix.Multiply(matrix1, Fraction.ToFraction(dbl)); } public static Matrix operator *(Matrix matrix1, Fraction frac) { return Matrix.Multiply(matrix1, frac); } public static Matrix operator *(int iNo, Matrix matrix1) { return Matrix.Multiply(matrix1, iNo); } public static Matrix operator *(double dbl, Matrix matrix1) { return Matrix.Multiply(matrix1, Fraction.ToFraction(dbl)); } public static Matrix operator *(Fraction frac, Matrix matrix1) { return Matrix.Multiply(matrix1, frac); } public static Matrix operator /(Matrix matrix1, int iNo) { return Matrix.Multiply(matrix1, Fraction.Inverse(new Fraction(iNo))); } public static Matrix operator /(Matrix matrix1, double dbl) { return Matrix.Multiply(matrix1, Fraction.Inverse(Fraction.ToFraction(dbl))); } public static Matrix operator /(Matrix matrix1, Fraction frac) { return Matrix.Multiply(matrix1, Fraction.Inverse(frac)); } /// /// Internal Fucntions for the above operators /// private static Matrix Negate(Matrix matrix) { return Matrix.Multiply(matrix,-1); } private static Matrix Add(Matrix matrix1, Matrix matrix2) { if (matrix1.Rows!=matrix2.Rows || matrix1.Cols!=matrix2.Cols) throw new MatrixException("Operation not possible"); Matrix result=new Matrix(matrix1.Rows, matrix1.Cols); for (int i=0;i /// Exception class for Matrix class, derived from System.Exception /// public class MatrixException : Exception { public MatrixException() : base() {} public MatrixException(string Message) : base(Message) {} public MatrixException(string Message, Exception InnerException) : base(Message, InnerException) {} } // end class MatrixException /// /// Class name: Fraction /// Developed by: Syed Mehroz Alam /// Email: smehrozalam@yahoo.com /// URL: Programming Home "http://www.geocities.com/smehrozalam/" /// Version: 2.0 /// /// What's new in version 2.0: /// * Changed Numerator and Denominator from Int32(integer) to Int64(long) for increased range /// * renamed ConvertToString() to (overloaded) ToString() /// * added the capability of detecting/raising overflow exceptions /// * Fixed the bug that very small numbers e.g. 0.00000001 could not be converted to fraction /// * Other minor bugs fixed /// /// Properties: /// Numerator: Set/Get value for Numerator /// Denominator: Set/Get value for Numerator /// Value: Set an integer value for the fraction /// /// Constructors: /// no arguments: initializes fraction as 0/1 /// (Numerator, Denominator): initializes fraction with the given numerator and denominator values /// (integer): initializes fraction with the given integer value /// (long): initializes fraction with the given long value /// (double): initializes fraction with the given double value /// (string): initializes fraction with the given string value /// the string can be an in the form of and integer, double or fraction. /// e.g it can be like "123" or "123.321" or "123/456" /// /// Public Methods (Description is given with respective methods' definitions) /// (override) string ToString(Fraction) /// Fraction ToFraction(string) /// Fraction ToFraction(double) /// double ToDouble(Fraction) /// Fraction Duplicate() /// Fraction Inverse(integer) /// Fraction Inverse(Fraction) /// ReduceFraction(Fraction) /// Equals(object) /// GetHashCode() /// /// Private Methods (Description is given with respective methods' definitions) /// Initialize(Numerator, Denominator) /// Fraction Negate(Fraction) /// Fraction Add(Fraction1, Fraction2) /// /// Overloaded Operators (overloaded for Fractions, Integers and Doubles) /// Unary: - /// Binary: +,-,*,/ /// Relational and Logical Operators: ==,!=,<,>,<=,>= /// /// Overloaded user-defined conversions /// Implicit: From double/long/string to Fraction /// Explicit: From Fraction to double/string /// public class Fraction { /// /// Class attributes/members /// long m_iNumerator; long m_iDenominator; /// /// Constructors /// public Fraction() { Initialize(0,1); } public Fraction(long iWholeNumber) { Initialize(iWholeNumber, 1); } public Fraction(double dDecimalValue) { Fraction temp=ToFraction(dDecimalValue); Initialize(temp.Numerator, temp.Denominator); } public Fraction(string strValue) { Fraction temp=ToFraction(strValue); Initialize(temp.Numerator, temp.Denominator); } public Fraction(long iNumerator, long iDenominator) { Initialize(iNumerator, iDenominator); } /// /// Internal function for constructors /// private void Initialize(long iNumerator, long iDenominator) { Numerator=iNumerator; Denominator=iDenominator; ReduceFraction(this); } /// /// Properites /// public long Denominator { get { return m_iDenominator; } set { if (value!=0) m_iDenominator=value; else throw new FractionException("Denominator cannot be assigned a ZERO Value"); } } public long Numerator { get { return m_iNumerator; } set { m_iNumerator=value; } } public long Value { set { m_iNumerator=value; m_iDenominator=1; } } /// /// The function takes a Fraction object and returns its value as double /// public static double ToDouble(Fraction frac) { return ( (double)frac.Numerator/frac.Denominator ); } /// /// The function returns the current Fraction object as double /// public double ToDouble() { return ( (double)this.Numerator/this.Denominator ); } /// /// The function returns the current Fraction object as a string /// public override string ToString() { string str; if ( this.Denominator==1 ) str=this.Numerator.ToString(); else str=this.Numerator + "/" + this.Denominator; return str; } /// /// The function takes an string as an argument and returns its corresponding reduced fraction /// the string can be an in the form of and integer, double or fraction. /// e.g it can be like "123" or "123.321" or "123/456" /// public static Fraction ToFraction(string strValue) { int i; for (i=0;i /// The function takes a floating point number as an argument /// and returns its corresponding reduced fraction /// public static Fraction ToFraction(double dValue) { try { checked { Fraction frac; if (dValue%1==0) // if whole number { frac=new Fraction( (long) dValue ); } else { double dTemp=dValue; long iMultiple=1; string strTemp=dValue.ToString(); while ( strTemp.IndexOf("E")>0 ) // if in the form like 12E-9 { dTemp*=10; iMultiple*=10; strTemp=dTemp.ToString(); } int i=0; while ( strTemp[i]!='.' ) i++; int iDigitsAfterDecimal=strTemp.Length-i-1; while ( iDigitsAfterDecimal>0 ) { dTemp*=10; iMultiple*=10; iDigitsAfterDecimal--; } frac=new Fraction( (int)Math.Round(dTemp) , iMultiple ); } return frac; } } catch(OverflowException) { throw new FractionException("Conversion not possible due to overflow"); } catch(Exception) { throw new FractionException("Conversion not possible"); } } /// /// The function replicates current Fraction object /// public Fraction Duplicate() { Fraction frac=new Fraction(); frac.Numerator=Numerator; frac.Denominator=Denominator; return frac; } /// /// The function returns the inverse of a Fraction object /// public static Fraction Inverse(Fraction frac1) { if (frac1.Numerator==0) throw new FractionException("Operation not possible (Denominator cannot be assigned a ZERO Value)"); long iNumerator=frac1.Denominator; long iDenominator=frac1.Numerator; return ( new Fraction(iNumerator, iDenominator)); } /// /// Operators for the Fraction object /// includes -(unary), and binary opertors such as +,-,*,/ /// also includes relational and logical operators such as ==,!=,<,>,<=,>= /// public static Fraction operator -(Fraction frac1) { return ( Negate(frac1) ); } public static Fraction operator +(Fraction frac1, Fraction frac2) { return ( Add(frac1 , frac2) ); } public static Fraction operator +(int iNo, Fraction frac1) { return ( Add(frac1 , new Fraction(iNo) ) ); } public static Fraction operator +(Fraction frac1, int iNo) { return ( Add(frac1 , new Fraction(iNo) ) ); } public static Fraction operator +(double dbl, Fraction frac1) { return ( Add(frac1 , Fraction.ToFraction(dbl) ) ); } public static Fraction operator +(Fraction frac1, double dbl) { return ( Add(frac1 , Fraction.ToFraction(dbl) ) ); } public static Fraction operator -(Fraction frac1, Fraction frac2) { return ( Add(frac1 , -frac2) ); } public static Fraction operator -(int iNo, Fraction frac1) { return ( Add(-frac1 , new Fraction(iNo) ) ); } public static Fraction operator -(Fraction frac1, int iNo) { return ( Add(frac1 , -(new Fraction(iNo)) ) ); } public static Fraction operator -(double dbl, Fraction frac1) { return ( Add(-frac1 , Fraction.ToFraction(dbl) ) ); } public static Fraction operator -(Fraction frac1, double dbl) { return ( Add(frac1 , -Fraction.ToFraction(dbl) ) ); } public static Fraction operator *(Fraction frac1, Fraction frac2) { return ( Multiply(frac1 , frac2) ); } public static Fraction operator *(int iNo, Fraction frac1) { return ( Multiply(frac1 , new Fraction(iNo) ) ); } public static Fraction operator *(Fraction frac1, int iNo) { return ( Multiply(frac1 , new Fraction(iNo) ) ); } public static Fraction operator *(double dbl, Fraction frac1) { return ( Multiply(frac1 , Fraction.ToFraction(dbl) ) ); } public static Fraction operator *(Fraction frac1, double dbl) { return ( Multiply(frac1 , Fraction.ToFraction(dbl) ) ); } public static Fraction operator /(Fraction frac1, Fraction frac2) { return ( Multiply( frac1 , Inverse(frac2) ) ); } public static Fraction operator /(int iNo, Fraction frac1) { return ( Multiply( Inverse(frac1) , new Fraction(iNo) ) ); } public static Fraction operator /(Fraction frac1, int iNo) { return ( Multiply( frac1 , Inverse(new Fraction(iNo)) ) ); } public static Fraction operator /(double dbl, Fraction frac1) { return ( Multiply( Inverse(frac1) , Fraction.ToFraction(dbl) ) ); } public static Fraction operator /(Fraction frac1, double dbl) { return ( Multiply( frac1 , Fraction.Inverse( Fraction.ToFraction(dbl) ) ) ); } public static bool operator ==(Fraction frac1, Fraction frac2) { return frac1.Equals(frac2); } public static bool operator !=(Fraction frac1, Fraction frac2) { return ( !frac1.Equals(frac2) ); } public static bool operator ==(Fraction frac1, int iNo) { return frac1.Equals( new Fraction(iNo)); } public static bool operator !=(Fraction frac1, int iNo) { return ( !frac1.Equals( new Fraction(iNo)) ); } public static bool operator ==(Fraction frac1, double dbl) { return frac1.Equals( new Fraction(dbl)); } public static bool operator !=(Fraction frac1, double dbl) { return ( !frac1.Equals( new Fraction(dbl)) ); } public static bool operator<(Fraction frac1, Fraction frac2) { return frac1.Numerator * frac2.Denominator < frac2.Numerator * frac1.Denominator; } public static bool operator>(Fraction frac1, Fraction frac2) { return frac1.Numerator * frac2.Denominator > frac2.Numerator * frac1.Denominator; } public static bool operator<=(Fraction frac1, Fraction frac2) { return frac1.Numerator * frac2.Denominator <= frac2.Numerator * frac1.Denominator; } public static bool operator>=(Fraction frac1, Fraction frac2) { return frac1.Numerator * frac2.Denominator >= frac2.Numerator * frac1.Denominator; } /// /// checks whether two fractions are equal /// public override bool Equals(object obj) { Fraction frac=(Fraction)obj; return ( Numerator==frac.Numerator && Denominator==frac.Denominator); } /// /// returns a hash code for this fraction /// public override int GetHashCode() { return ( Convert.ToInt32((Numerator ^ Denominator) & 0xFFFFFFFF) ) ; } /// /// internal function for negation /// private static Fraction Negate(Fraction frac1) { long iNumerator=-frac1.Numerator; long iDenominator=frac1.Denominator; return ( new Fraction(iNumerator, iDenominator) ); } /// /// internal functions for binary operations /// private static Fraction Add(Fraction frac1, Fraction frac2) { try { checked { long iNumerator=frac1.Numerator*frac2.Denominator + frac2.Numerator*frac1.Denominator; long iDenominator=frac1.Denominator*frac2.Denominator; return ( new Fraction(iNumerator, iDenominator) ); } } catch(OverflowException) { throw new FractionException("Overflow occurred while performing arithemetic operation"); } catch(Exception) { throw new FractionException("An error occurred while performing arithemetic operation"); } } private static Fraction Multiply(Fraction frac1, Fraction frac2) { try { checked { long iNumerator=frac1.Numerator*frac2.Numerator; long iDenominator=frac1.Denominator*frac2.Denominator; return ( new Fraction(iNumerator, iDenominator) ); } } catch(OverflowException) { throw new FractionException("Overflow occurred while performing arithemetic operation"); } catch(Exception) { throw new FractionException("An error occurred while performing arithemetic operation"); } } /// /// The function returns GCD of two numbers (used for reducing a Fraction) /// private static long GCD(long iNo1, long iNo2) { // take absolute values if (iNo1 < 0) iNo1 = -iNo1; if (iNo2 < 0) iNo2 = -iNo2; do { if (iNo1 < iNo2) { long tmp = iNo1; // swap the two operands iNo1 = iNo2; iNo2 = tmp; } iNo1 = iNo1 % iNo2; } while (iNo1 != 0); return iNo2; } /// /// The function reduces(simplifies) a Fraction object by dividing both its numerator /// and denominator by their GCD /// public static void ReduceFraction(Fraction frac) { try { if (frac.Numerator==0) { frac.Denominator=1; return; } long iGCD=GCD(frac.Numerator, frac.Denominator); frac.Numerator/=iGCD; frac.Denominator/=iGCD; if ( frac.Denominator<0 ) // if -ve sign in denominator { //pass -ve sign to numerator frac.Numerator*=-1; frac.Denominator*=-1; } } // end try catch(Exception exp) { throw new FractionException("Cannot reduce Fraction: " + exp.Message); } } } //end class Fraction /// /// Exception class for Fraction, derived from System.Exception /// public class FractionException : Exception { public FractionException() : base() {} public FractionException(string Message) : base(Message) {} public FractionException(string Message, Exception InnerException) : base(Message, InnerException) {} } //end class FractionException } //end namespace Mehroz