/// <summary> /// Matrix ^ scalar /// </summary> /// <param name="value"></param> /// <returns></returns> public QsMatrix PowerScalar(QsScalar value) { QsMatrix Total = (QsMatrix)this.Identity; //first get the identity matrix of this matrix. int count = Qs.IntegerFromQsValue(value); if (count > 0) { for (int i = 1; i <= count; i++) { Total = Total.MultiplyMatrix(this); } } else if (count == 0) { return(Total); //which id identity already } else { count = Math.Abs(count); for (int i = 1; i <= count; i++) { Total = Total.MultiplyMatrix(this.Inverse); //multiply the inverses many times } } return(Total); }
/// <summary> /// Matrix - Matrix /// </summary> /// <param name="matrix"></param> /// <returns></returns> private QsMatrix SubtractMatrix(QsMatrix matrix) { if (this.DimensionEquals(matrix)) { QsMatrix Total = new QsMatrix(); for (int IY = 0; IY < this.RowsCount; IY++) { List <QsScalar> row = new List <QsScalar>(ColumnsCount); for (int IX = 0; IX < this.ColumnsCount; IX++) { row.Add(this[IY, IX] - matrix[IY, IX]); } Total.AddRow(row.ToArray()); } return(Total); } else { throw new QsMatrixException("Matrix 1 [" + this.RowsCount.ToString(CultureInfo.InvariantCulture) + "x" + this.ColumnsCount.ToString(CultureInfo.InvariantCulture) + "] is not dimensional equal with Matrix 2 [" + matrix.RowsCount.ToString(CultureInfo.InvariantCulture) + "x" + matrix.ColumnsCount.ToString(CultureInfo.InvariantCulture) + "]"); } }
/// <summary> /// Normal multiplication. /// </summary> /// <param name="value"></param> /// <returns></returns> public override QsValue MultiplyOperation(QsValue vl) { QsValue value; if (vl is QsReference) { value = ((QsReference)vl).ContentValue; } else { value = vl; } if (value is QsScalar) { return(MultiplyScalar((QsScalar)value)); } else if (value is QsVector) { return(this.MultiplyVector((QsVector)value)); } else if (value is QsMatrix) { QsMatrix mvec = this.ToVectorMatrix().MultiplyMatrix((QsMatrix)value); // make it vector again. return(mvec[0]); } else { throw new NotSupportedException(); } }
/// <summary> /// /// </summary> /// <param name="value"></param> /// <returns></returns> public override QsValue DifferentiateOperation(QsValue vl) { QsValue value; if (vl is QsReference) { value = ((QsReference)vl).ContentValue; } else { value = vl; } if (value is QsScalar) { QsMatrix n = new QsMatrix(); foreach (var row in n.Rows) { n.AddRow(row.DifferentiateScalar((QsScalar)value).ToArray()); } return(n); } else { return(base.DifferentiateOperation(value)); } }
/// <summary> /// Gets a specific covector as a matrix object. /// </summary> /// <param name="columnIndex"></param> /// <returns></returns> public QsMatrix GetColumnVectorMatrix(int columnIndex) { QsMatrix mat = new QsMatrix(); mat.AddColumnVector(GetColumnVector(columnIndex)); return(mat); }
public QsMatrix AppendLowerMatrix(QsMatrix matrix) { QsMatrix m = CopyMatrix(this); foreach (var vector in matrix) { m.AddVector(vector); } return(m); }
/// <summary> /// Append the target matrix right to the matrix. /// </summary> /// <param name="matrix"></param> /// <returns></returns> public QsMatrix AppendRightMatrix(QsMatrix matrix) { QsMatrix m = CopyMatrix(this); foreach (var column in matrix.Columns) { m.AddColumnVector(column); } return(m); }
/// <summary> /// Copy the matrix into new matrix instance. /// </summary> /// <param name="matrix"></param> /// <returns></returns> public static QsMatrix CopyMatrix(QsMatrix matrix) { QsMatrix m = new QsMatrix(); foreach (QsVector v in matrix) { m.AddVector(QsVector.CopyVector(v)); } return(m); }
/// <summary> /// for the tensor product '(*)' operator /// </summary> /// <param name="value"></param> /// <returns></returns> public override QsValue TensorProductOperation(QsValue vl) { QsValue value; if (vl is QsReference) { value = ((QsReference)vl).ContentValue; } else { value = vl; } if (value is QsMatrix) { // Kronecker product var tm = (QsMatrix)value; QsMatrix result = new QsMatrix(); List <QsMatrix> lm = new List <QsMatrix>(); for (int i = 0; i < this.RowsCount; i++) { QsMatrix rowM = null; for (int j = 0; j < this.ColumnsCount; j++) { QsScalar element = this[i, j]; var imat = (QsMatrix)(tm * element); if (rowM == null) { rowM = imat; } else { rowM = rowM.AppendRightMatrix(imat); } } lm.Add(rowM); } // append vertically all matrices foreach (var rm in lm) { result = result.AppendLowerMatrix(rm); } return(result); } throw new NotImplementedException(); }
/// <summary> /// Transfer the columns of the matrix into rows. /// </summary> /// <returns></returns> public QsMatrix Transpose() { QsMatrix m = new QsMatrix(); for (int IX = 0; IX < ColumnsCount; IX++) { var vec = this.GetColumnVectorMatrix(IX); m.AddRow(vec.ToArray()); } return(m); }
/// <summary> /// Removes row at index /// </summary> /// <param name="rowIndex"></param> /// <returns></returns> public QsMatrix RemoveRow(int rowIndex) { QsMatrix m = new QsMatrix(); for (int iy = 0; iy < this.RowsCount; iy++) { if (iy != rowIndex) { m.AddVector(this[iy]); } } return(m); }
/// <summary> /// Removes column at index /// </summary> /// <param name="columnIndex"></param> /// <returns></returns> public QsMatrix RemoveColumn(int columnIndex) { QsMatrix m = new QsMatrix(); for (int ix = 0; ix < this.ColumnsCount; ix++) { if (ix != columnIndex) { m.AddColumnVector(this.GetColumnVector(ix)); } } return(m); }
public QsMatrix GetVectorMatrix(int rowIndex) { if (rowIndex > RowsCount) { throw new QsMatrixException("Index '" + rowIndex + "' Exceeds the rows limits '" + RowsCount + "'"); } QsMatrix mat = new QsMatrix(); mat.AddVector(QsVector.CopyVector(Rows[rowIndex])); return(mat); }
/// <summary> /// Makes n x n matrix with zeros. /// </summary> /// <param name="n"></param> /// <returns></returns> public static QsMatrix MakeEmptySquareMatrix(int n) { QsMatrix m = new QsMatrix(); for (int i = 0; i < n; i++) { QsVector v = new QsVector(n); for (int j = 0; j < n; j++) { v.AddComponent(QsScalar.Zero); } m.AddVector(v); } return(m); }
/// <summary> /// The function receive rows from vectors or matrices or may be tensors /// </summary> /// <param name="values">Vectors</param> /// <returns></returns> public static QsValue MatrixFromValues(params QsValue[] values) { if (values[0] is QsTensor) { if (values.Count() == 1) { return(values[0]); } // treat the case of tensors QsTensor tensor = new QsTensor(); foreach (var tn in values) { if (tn.GetType() != typeof(QsTensor)) { throw new QsException("Non Tensor in a matrix of tensors is not valid expression."); } else { tensor.AddInnerTensor((QsTensor)tn); } } return(tensor); } QsMatrix mat = new QsMatrix(); foreach (var val in values) { if (val is QsVector) { mat.AddVector((QsVector)val); } else if (val is QsMatrix) { foreach (var vc in ((QsMatrix)val)) { mat.AddVector((QsVector)vc); } } else { throw new QsInvalidOperationException("Value to be added is not a vector nor a matrix."); } } return(mat); }
/// <summary> /// Matrix elements ^. scalar /// </summary> /// <param name="scalarQuantity"></param> /// <returns></returns> public QsMatrix ElementsPowerScalar(QsScalar scalar) { QsMatrix Total = new QsMatrix(); for (int IY = 0; IY < this.RowsCount; IY++) { List <QsScalar> row = new List <QsScalar>(ColumnsCount); for (int IX = 0; IX < this.ColumnsCount; IX++) { row.Add(this[IY, IX].PowerScalar(scalar)); } Total.AddRow(row.ToArray()); } return(Total); }
/// <summary> /// Matrix + scalar /// </summary> /// <param name="scalar"></param> /// <returns></returns> private QsMatrix AddScalar(QsScalar scalar) { QsMatrix Total = new QsMatrix(); for (int IY = 0; IY < this.RowsCount; IY++) { List <QsScalar> row = new List <QsScalar>(ColumnsCount); for (int IX = 0; IX < this.ColumnsCount; IX++) { row.Add(this[IY, IX] + scalar); } Total.AddRow(row.ToArray()); } return(Total); }
/// <summary> /// Ordinary multiplicatinon of the matrix. /// Naive implementation :D and I am proud :P /// /// </summary> /// <param name="matrix"></param> /// <returns></returns> public QsMatrix MultiplyMatrix(QsMatrix matrix) { if (this.ColumnsCount == matrix.RowsCount) { QsMatrix Total = new QsMatrix(); //loop through my rows for (int iy = 0; iy < RowsCount; iy++) { var vec = this.Rows[iy]; QsScalar[] tvec = new QsScalar[matrix.ColumnsCount]; //the target row in the Total Matrix. //loop through all co vectors in the target matrix. for (int tix = 0; tix < matrix.ColumnsCount; tix++) { var covec = matrix.GetColumnVectorMatrix(tix).ToArray(); //multiply vec*covec and store it at the Total matrix at iy,ix QsScalar[] snum = new QsScalar[vec.Count]; for (int i = 0; i < vec.Count; i++) { snum[i] = vec[i].MultiplyScalar(covec[i]); } QsScalar tnum = snum[0]; for (int i = 1; i < snum.Length; i++) { tnum = tnum + snum[i]; } tvec[tix] = tnum; } Total.AddRow(tvec); } return(Total); } else { throw new QsMatrixException("Width of the first matrix [" + this.ColumnsCount + "] not equal to the height of the second matrix [" + matrix.RowsCount + "]"); } }
/// <summary> /// used to make sure that the two matrices are dimensionally equal /// have the same count of rows and columnss /// </summary> /// <param name="obj"></param> /// <returns></returns> public bool DimensionEquals(QsMatrix matrix) { if (matrix == null) { return(false); } else { if (this.RowsCount == matrix.RowsCount) { if (this.ColumnsCount == matrix.ColumnsCount) { return(true); //just for now. } } //dimensions not equal. return(false); } }
/// <summary> /// '>>' Right Shift Operator /// </summary> /// <param name="times"></param> /// <returns></returns> public override QsValue RightShiftOperation(QsValue vl) { QsValue times; if (vl is QsReference) { times = ((QsReference)vl).ContentValue; } else { times = vl; } QsMatrix ShiftedMatrix = new QsMatrix(); foreach (var vec in this) { ShiftedMatrix.AddVector((QsVector)vec.RightShiftOperation(times)); } return(ShiftedMatrix); }
/// <summary> /// Cross product for 3 components vector. /// </summary> /// <param name="v1"></param> /// <param name="v2"></param> /// <returns></returns> public QsVector VectorProduct(QsVector v2) { if (this.Count != v2.Count) { throw new QsException("Vectors are not equal"); } if (this.Count != 3) { throw new QsException("Cross product only happens with 3 component vector"); } // cross product as determinant of matrix. QsMatrix mat = new QsMatrix( new QsVector(QsScalar.One, QsScalar.One, QsScalar.One) , this , v2); return(mat.Determinant()); // problem now: what if we have more than 3 elements in the vector. // there is no cross product for more than 3 elements for vectors. }
/// <summary> /// Make identity matrix bases on dimension /// </summary> /// <param name="n">dimension or n * n matrix</param> /// <returns></returns> public static QsMatrix MakeIdentity(int n) { QsMatrix m = new QsMatrix(); for (int i = 0; i < n; i++) { QsVector v = new QsVector(n); for (int j = 0; j < n; j++) { if (j == i) { v.AddComponent(QsScalar.One); } else { v.AddComponent(QsScalar.Zero); } } m.AddVector(v); } return(m); }
public override QsValue Execute(Token expression) { string operation = expression.TokenValue; if (operation.Equals("Transpose()", StringComparison.OrdinalIgnoreCase)) { return(this.Transpose()); } if (operation.Equals("Identity", StringComparison.OrdinalIgnoreCase)) { return(this.Identity); } if (operation.Equals("Determinant", StringComparison.OrdinalIgnoreCase)) { return(QsMatrix.Determinant(this)); } if (operation.Equals("Cofactors", StringComparison.OrdinalIgnoreCase)) { return(this.Cofactors); } if (operation.Equals("Adjoint", StringComparison.OrdinalIgnoreCase)) { return(this.Adjoint); } if (operation.Equals("Inverse", StringComparison.OrdinalIgnoreCase)) { return(this.Inverse); } throw new QsException("Not implemented or Unknow method for the matrix type"); }
/// <summary> /// Create A matrix from a row values by aligning values to the left in /// </summary> /// <param name="values"></param> /// <returns></returns> public static QsValue MatrixRowFromValues(params QsValue[] values) { // what about [g g] and g is tensor // in this case return value should be tensor // from the higher degree of above g if (values[0] is QsTensor) { if (values.Count() == 1) { return(values[0]); } // in rare cases or event known cases by me Ahmed Sadek and because of parsing // sometimes I enclose tensor variable inside matrix [g g <|4 3|> ] // so in this case i will the return as it is. QsTensor tensor = new QsTensor(); foreach (var inTensor in values) { if (inTensor.GetType() != typeof(QsTensor)) { throw new QsException("Non Tensor in a matrix of tensors is not valid expression."); } else { tensor.AddInnerTensor((QsTensor)inTensor); } } return(tensor); } QsMatrix m = new QsMatrix(); foreach (var v in values) { if (v is QsScalar) { if (m.RowsCount == 0) { m.AddVector((QsVector)VectorFromValues(v)); } else { m.Rows[0].AddComponent((QsScalar)v); } } if (v is QsVector) { if (m.RowsCount == 0) { m.AddVector(((QsVector)v).Clone() as QsVector); } else if (m.RowsCount == 1) { m.Rows[0].AddComponents((QsVector)v); } else { throw new QsInvalidOperationException("Couldn't adding vector to multi row matrix"); } } if (v is QsMatrix) { if (m.RowsCount == 0) { m = null; m = QsMatrix.CopyMatrix((QsMatrix)v); } else if (m.RowsCount == ((QsMatrix)v).RowsCount) { foreach (var col in ((QsMatrix)v).Columns) { m.AddColumnVector(col); } } else { throw new QsInvalidOperationException("Couldn't adding different row matrices"); } } } return(m); }
// Contribution by Edward Popko, a well commented version: determinant.c for Microsoft C++ Visual Studio 6. // http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/determinant/determinant.c //============================================================================== // Recursive definition of determinate using expansion by minors. // // Notes: 1) arguments: // a (double **) pointer to a pointer of an arbitrary square matrix // n (int) dimension of the square matrix // // 2) Determinant is a recursive function, calling itself repeatedly // each time with a sub-matrix of the original till a terminal // 2X2 matrix is achieved and a simple determinat can be computed. // As the recursion works backwards, cumulative determinants are // found till untimately, the final determinate is returned to the // initial function caller. // // 3) m is a matrix (4X4 in example) and m13 is a minor of it. // A minor of m is a 3X3 in which a row and column of values // had been excluded. Another minor of the submartix is also // possible etc. // m a b c d m13 . . . . // e f g h e f . h row 1 column 3 is elminated // i j k l i j . l creating a 3 X 3 sub martix // m n o p m n . p // // 4) the following function finds the determinant of a matrix // by recursively minor-ing a row and column, each time reducing // the sub-matrix by one row/column. When a 2X2 matrix is // obtained, the determinat is a simple calculation and the // process of unstacking previous recursive calls begins. // // m n // o p determinant = m*p - n*o // // 5) this function uses dynamic memory allocation on each call to // build a m X m matrix this requires ** and * pointer variables // First memory allocation is ** and gets space for a list of other // pointers filled in by the second call to malloc. // // 6) C++ implements two dimensional arrays as an array of arrays // thus two dynamic malloc's are needed and have corresponsing // free() calles. // // 7) the final determinant value is the sum of sub determinants // //============================================================================== /* * double Determinant(double** a, int n) * { * int i, j, j1, j2; // general loop and matrix subscripts * double det = 0; // init determinant * double** m = NULL; // pointer to pointers to implement 2d * // square array * * if (n < 1) { } // error condition, should never get here * * else if (n == 1) * { // should not get here * det = a[0][0]; * } * * else if (n == 2) * { // basic 2X2 sub-matrix determinate * // definition. When n==2, this ends the * det = a[0][0] * a[1][1] - a[1][0] * a[0][1];// the recursion series * } * * * // recursion continues, solve next sub-matrix * else * { // solve the next minor by building a * // sub matrix * det = 0; // initialize determinant of sub-matrix * * // for each column in sub-matrix * for (j1 = 0; j1 < n; j1++) * { * // get space for the pointer list * m = (double**)malloc((n - 1) * sizeof(double*)); * * for (i = 0; i < n - 1; i++) * m[i] = (double*)malloc((n - 1) * sizeof(double)); * // i[0][1][2][3] first malloc * // m -> + + + + space for 4 pointers * // | | | | j second malloc * // | | | +-> _ _ _ [0] pointers to * // | | +----> _ _ _ [1] and memory for * // | +-------> _ a _ [2] 4 doubles * // +----------> _ _ _ [3] * // * // a[1][2] * // build sub-matrix with minor elements excluded * for (i = 1; i < n; i++) * { * j2 = 0; // start at first sum-matrix column position * // loop to copy source matrix less one column * for (j = 0; j < n; j++) * { * if (j == j1) continue; // don't copy the minor column element * * m[i - 1][j2] = a[i][j]; // copy source element into new sub-matrix * // i-1 because new sub-matrix is one row * // (and column) smaller with excluded minors * j2++; // move to next sub-matrix column position * } * } * * det += pow(-1.0, 1.0 + j1 + 1.0) * a[0][j1] * Determinant(m, n - 1); * // sum x raised to y power * // recursively get determinant of next * // sub-matrix which is now one * // row & column smaller * * for (i = 0; i < n - 1; i++) free(m[i]);// free the storage allocated to * // to this minor's set of pointers * free(m); // free the storage for the original * // pointer to pointer * } * } * return (det); * } */ // the code above is converted by me Ahmed Sadek to support determinant in Qs :) // I copied the code with the information about who made it to preserve the rights of the person // who made this effort. // Thank you public static QsScalar Determinant(QsMatrix a) { // code taken from: http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/determinant/ int n = a.RowsCount; QsScalar det = default(QsScalar); if (n < 1) { throw new QsException("Zero component matrix, are you crazy :)"); // error condition, should never get here } else if (n == 1) { // should not get here det = a[0][0]; } else if (n == 2) { // basic 2X2 sub-matrix determinate // definition. When n==2, this ends the det = a[0][0] * a[1][1] - a[1][0] * a[0][1];// the recursion series } // recursion continues, solve next sub-matrix else { // solve the next minor by building a // sub matrix int i, j, j1, j2; QsMatrix m = QsMatrix.MakeEmptySquareMatrix(n - 1); // for each column in sub-matrix for (j1 = 0; j1 < n; j1++) { // build sub-matrix with minor elements excluded for (i = 1; i < n; i++) { j2 = 0; // start at first sum-matrix column position // loop to copy source matrix less one column for (j = 0; j < n; j++) { if (j == j1) { continue; // don't copy the minor column element } m[i - 1][j2] = a[i][j]; // copy source element into new sub-matrix // i-1 because new sub-matrix is one row // (and column) smaller with excluded minors j2++; // move to next sub-matrix column position } } var fn = System.Math.Pow(-1.0, 1.0 + j1 + 1.0); var f = fn.ToQuantity().ToScalar(); var mr = Determinant(m); if (det == null) { det = f * (a[0][j1] * mr); } else { det += f * (a[0][j1] * mr); } // sum x raised to y power // recursively get determinant of next // sub-matrix which is now one // row & column smaller } } return(det); }
public override QsValue MultiplyOperation(QsValue vl) { QsValue value; if (vl is QsReference) { value = ((QsReference)vl).ContentValue; } else { value = vl; } if (value is QsScalar) { var scalar = (QsScalar)value; QsTensor NewTensor = new QsTensor(); if (this.Order > 3) { foreach (var iTensor in this.InnerTensors) { NewTensor.AddInnerTensor((QsTensor)iTensor.MultiplyOperation(value)); } } else { for (int il = 0; il < this.MatrixLayers.Count; il++) { QsMatrix ResultMatrix = (QsMatrix)this.MatrixLayers[il].MultiplyOperation(scalar); NewTensor.AddMatrix(ResultMatrix); } } return(NewTensor); } if (value is QsTensor) { var tensor = (QsTensor)value; if (this.Order == 1 && tensor.Order == 1) { var thisVec = this[0][0]; var thatVec = tensor[0][0]; var result = (QsMatrix)thisVec.TensorProductOperation(thatVec); return(new QsTensor(result)); } if (this.Order == 2 && tensor.Order <= 2) { //tenosrial product of two matrices will result in another matrix also. QsMatrix result = (QsMatrix)this.MatrixLayers[0].TensorProductOperation(tensor.MatrixLayers[0]); return(new QsTensor(result)); } else { throw new QsException("", new NotImplementedException()); } } throw new QsException("Tensor Multiplication Operation with " + value.GetType().Name + " Failed"); }
public override QsValue SubtractOperation(QsValue vl) { QsValue value; if (vl is QsReference) { value = ((QsReference)vl).ContentValue; } else { value = vl; } if (value is QsScalar) { var scalar = value as QsScalar; QsTensor NewTensor = new QsTensor(); if (this.Order > 3) { foreach (var iTensor in this.InnerTensors) { NewTensor.SubtractOperation((QsTensor)iTensor.AddOperation(value)); } } else { for (int il = 0; il < this.MatrixLayers.Count; il++) { QsMatrix ResultMatrix = (QsMatrix)this.MatrixLayers[il].SubtractOperation(scalar); NewTensor.AddMatrix(ResultMatrix); } } return(NewTensor); } if (value is QsTensor) { var tensor = value as QsTensor; if (this.Order != (tensor.Order)) { throw new QsException("Adding two different ranked tensors are not supported"); } if (this.Order > 3) { QsTensor NewTensor = new QsTensor(); for (int i = 0; i < this.InnerTensors.Count(); i++) { var iTensor = this.InnerTensors[i]; NewTensor.AddInnerTensor((QsTensor) iTensor.SubtractOperation(tensor.InnerTensors[i])); } return(NewTensor); } else { if (tensor.MatrixLayers.Count == this.MatrixLayers.Count) { // the operation will succeed if (tensor.FaceRowsCount == this.FaceRowsCount) { if (tensor.FaceColumnsCount == this.FaceColumnsCount) { QsTensor NewTensor = new QsTensor(); for (int il = 0; il < this.MatrixLayers.Count; il++) { QsMatrix ResultMatrix = (QsMatrix)this.MatrixLayers[il].SubtractOperation(tensor.MatrixLayers[il]); NewTensor.AddMatrix(ResultMatrix); } return(NewTensor); } } } } } throw new QsException("Tensor Subtract Operation with " + value.GetType().Name + " Failed"); }