/// <summary> /// Calculates the extended adjacency matrix index. /// An implementation of the algorithm published in <token>cdk-cite-HU96</token>. /// </summary> // @cdk.keyword EAID number public static double GetEAIDNumber(IAtomContainer atomContainer) { GIMatrix matrix = new GIMatrix(GetExtendedAdjacenyMatrix(atomContainer)); GIMatrix tempMatrix = matrix; GIMatrix fixedMatrix = matrix; for (int i = 2; i < atomContainer.Atoms.Count; i++) { tempMatrix = tempMatrix.Multiply(fixedMatrix); matrix = matrix.Add(tempMatrix); } for (int i = 0; i < atomContainer.Atoms.Count; i++) { matrix.SetValueAt(i, i, matrix.GetValueAt(i, i) + 1); } double eaid = matrix.Trace(); Debug.WriteLine("final matrix - the sum of the powers of EA matrix: "); DisplayMatrix(matrix.ArrayValue); Debug.WriteLine($"eaid number: {eaid}"); return(eaid); }
} // method Multiply(double) /// <summary> /// Returns the result of the matrix multiplication of this matrix by another one. The matrix passed /// as parameter <i>follows</i> this matrix in the multiplication, so for an example if the dimension of /// the actual matrix is mxn, the dimension of the second one should be nxp in order for the multiplication /// to be performed (otherwise an exception will be thrown) and the resulting matrix will have dimension mxp. /// </summary> /// <param name="matrix">the matrix following this one in the matrix multiplication</param> /// <returns>the resulting matrix of the matrix multiplication</returns> /// <exception cref="BadMatrixFormatException">if the matrix passed in arguments has wrong dimensions</exception> public GIMatrix Multiply(GIMatrix matrix) { if (Width != matrix.Height) { throw new BadMatrixFormatException(); // unsuitable dimensions } int p = matrix.Width; double[][] temp = Arrays.CreateJagged <double>(Height, p); double[][] multiplied = matrix.ArrayValue; for (int i = 0; i < Height; i++) { // line index of the first matrix for (int k = 0; k < p; k++) { // column index of the second matrix temp[i][k] = array[i][0] * multiplied[0][k]; // first multiplication for (int j = 1; j < Width; j++) { // sum of multiplications temp[i][k] = temp[i][k] + array[i][j] * multiplied[j][k]; } } } return(new GIMatrix(temp)); } // method Multiply(Matrix)
} // method IsInvertible() /// <summary> /// Returns the transpose of this matrix. The transpose of a matrix A = {a(i,j)} is the matrix B = {b(i,j)} /// such that b(i,j) = a(j,i) for every i,j i.e. it is the symmetrical reflection of the matrix along its /// diagonal. The matrix must be square to use this method, otherwise an exception will be thrown. /// </summary> /// <returns>the matrix's transpose as a Matrix object</returns> public GIMatrix Inverse() { try { if (!IsInvertible()) { throw new MatrixNotInvertibleException(); } } catch (BadMatrixFormatException) { throw new MatrixNotInvertibleException(); } GIMatrix I = CreateIdentity(Width); // Creates an identity matrix of same dimensions GIMatrix table; try { GIMatrix[][] temp = new[] { new[] { this, I } }; table = new GIMatrix(temp); } catch (BadMatrixFormatException) { return(null); } // never happens table = table.GaussJordan(); // linear reduction method applied double[][] inv = Arrays.CreateJagged <double>(Height, Width); for (int i = 0; i < Height; i++) { // extracts inverse matrix for (int j = Width; j < 2 * Width; j++) { try { inv[i][j - Width] = table.GetValueAt(i, j); } catch (IndexOutOfRangeException) { return(null); } // never happens } } try { return(new GIMatrix(inv)); } catch (BadMatrixFormatException) { return(null); } // never happens... } // method Inverse()
} // method SetLine(int,Matrix) /// <summary> /// Sets the column of the matrix at the specified index to a new value. /// </summary> /// <param name="j">the column number</param> /// <param name="column">the column to be placed at the specified index</param> /// <exception cref="ArgumentOutOfRangeException">if the given index is out of the matrix's range</exception> /// <exception cref="BadMatrixFormatException">in case the given Matrix is unproper to replace a column of this Matrix</exception> public void SetColumn(int j, GIMatrix column) { if ((j < 0) || (j >= Width)) { throw new ArgumentOutOfRangeException(nameof(j)); } if ((column.Height != Height) || (column.Width != 1)) { throw new BadMatrixFormatException(); } for (int k = 0; k < Height; k++) { array[k][j] = column.GetValueAt(k, 0); } } // method SetColumn(int,Matrix)
} // method GetColumn(int) /// <summary> /// Sets the line of the matrix at the specified index to a new value. /// </summary> /// <param name="i">the line number</param> /// <param name="line">the line to be placed at the specified index</param> /// <exception cref="ArgumentOutOfRangeException">if the given index is out of the matrix's range</exception> /// <exception cref="BadMatrixFormatException">in case the given Matrix is unproper to replace a line of this Matrix</exception> public void SetLine(int i, GIMatrix line) { if ((i < 0) || (i >= Height)) { throw new ArgumentOutOfRangeException(nameof(i)); } if ((line.Height != 1) || (line.Width != Width)) { throw new BadMatrixFormatException(); } for (int k = 0; k < Width; k++) { array[i][k] = line.GetValueAt(0, k); } } // method SetLine(int,Matrix)
} // method AddLine(int,int,double) /// <summary> /// Addition from two matrices. /// </summary> public GIMatrix Add(GIMatrix b) { if ((b == null) || (Height != b.Height) || (Width != b.Width)) { return(null); } int i, j; GIMatrix result = new GIMatrix(Height, Width); for (i = 0; i < Height; i++) { for (j = 0; j < Width; j++) { result.array[i][j] = array[i][j] + b.array[i][j]; } } return(result); }
} // method Zero(int,int) /// <summary> /// Verifies if two given matrix are equal or not. The matrix must be of the same size and dimensions, /// otherwise an exception will be thrown. /// </summary> /// <param name="matrix">the Matrix object to be compared to</param> /// <returns>true if both matrix are equal element to element</returns> /// <exception cref="BadMatrixFormatException">if the given matrix doesn't have the same dimensions as this one</exception> public bool Equals(GIMatrix matrix) { if ((Height != matrix.Height) || (Width != matrix.Width)) { throw new BadMatrixFormatException(); } double[][] temp = matrix.ArrayValue; for (int i = 0; i < Height; i++) { for (int j = 0; j < Width; j++) { if (!(array[i][j] == temp[i][j])) { return(false); } } } return(true); } // method Equals(Matrix)
} // constructor Matrix(Matrix) /// <summary> /// Class constructor. Creates a new Matrix object using a table of matrices (an array of Matrix objects). /// The given array should be properly instantiated i.e. it must contain a fixed number of lines and columns, /// otherwise an exception will be thrown. /// </summary> /// <param name="table">an array of matrices</param> /// <exception cref="BadMatrixFormatException">if the table is not properly instantiated</exception> public GIMatrix(GIMatrix[][] table) { VerifyTableFormat(table); Height = Width = 0; for (int i = 0; i < table.Length; i++) { Height += table[i][0].Height; } for (int j = 0; j < table[0].Length; j++) { Width += table[0][j].Width; } double[][] temp = Arrays.CreateJagged <double>(Height, Width); int k = 0; // counters for matrices for (int i = 0; i < Height; i++) { temp[i] = new double[Width]; // line by line ... if (i == table[k][0].Height) { k++; // last line of matrix reached } int h = 0; for (int j = 0; j < Width; j++) { if (j == table[k][h].Width) { h++; // last column of matrix reached } try { GIMatrix tempMatrix = table[k][h]; temp[i][j] = tempMatrix.GetValueAt(i - k * tempMatrix.Height, j - h * tempMatrix.Width); } catch (IndexOutOfRangeException) { } // never happens } } this.array = temp; } // constructor Matrix(Matrix)
} // constructor Matrix(int,int) /// <summary> /// Class constructor. Copies an already existing Matrix object in a new Matrix object. /// </summary> /// <param name="matrix">a Matrix object</param> public GIMatrix(GIMatrix matrix) { double[][] temp = new double[matrix.Height][]; for (int i = 0; i < matrix.Height; i++) { temp[i] = new double[matrix.Width]; // line by line ... for (int j = 0; j < matrix.Width; j++) { try { temp[i][j] = matrix.GetValueAt(i, j); } catch (IndexOutOfRangeException) { } // never happens } } this.array = temp; Height = array.Length; Width = array[0].Length; } // constructor Matrix(Matrix)
} // method Inverse() /// <summary> /// Gauss-Jordan algorithm. Returns the reduced-echeloned matrix of this matrix. The /// algorithm has not yet been optimised but since it is quite simple, it should not be /// a serious problem. /// </summary> /// <returns>the reduced matrix</returns> public GIMatrix GaussJordan() { GIMatrix tempMatrix = new GIMatrix(this); try { int i = 0; int j = 0; int k = 0; bool end = false; while ((i < Height) && (!end)) { bool allZero = true; // true if all elements under line i are null (zero) while (j < Width) { // determination of the pivot for (k = i; k < Height; k++) { if (!(tempMatrix.GetValueAt(k, j) == 0.0)) { // if an element != 0 allZero = false; break; } } if (allZero) { j++; } else { break; } } if (j == Width) { end = true; } else { if (k != i) { tempMatrix = tempMatrix.InvertLine(i, k); } if (!(tempMatrix.GetValueAt(i, j) == 1.0)) // if element != 1 { tempMatrix = // A = L(i)(1/a(i,j))(A) tempMatrix.MultiplyLine(i, 1 / tempMatrix.GetValueAt(i, j)); } for (int q = 0; q < Height; q++) { if (q != i) // A = L(q,i)(-a(q,j))(A) { tempMatrix = tempMatrix.AddLine(q, i, -tempMatrix.GetValueAt(q, j)); } } } i++; } // normally here, r = i-1 return(tempMatrix); } catch (IndexOutOfRangeException) { return(null); } // never happens... well I hope ;) // From: LEROUX, P. Algebre lineaire: une approche matricielle. Modulo Editeur, 1983. p. 75. (In French) } // method GaussJordan()