gt:             for(int j = 0; j < theMatrix.numColumns; j++)
context: package qcfcs_math;
  
  /**
   * This class implements a matrix of complex numbers.
   * Created by reesede on 1/4/2017.
   * @author David E. Reese
   * @version 2.7.1
   * @since 2.1.1
   */
  
  // Copyright 2017 David E. Reese
  //
  // This file is part of QCfCS_java.
  //
  // QCfCS_java is free software: you can redistribute it and/or modify
  // it under the terms of the GNU General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // QCfCS_java is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with QCfCS_java.  If not, see <http://www.gnu.org/licenses/>.
  //
  // History:
  //      20170118    D.E. Reese          Creation (Programming Drill 2.1.1).
  //      20170119    D.E. Reese          Added set () (Programming Drill 2.1.1).
  //      20170121    D.E. Reese          Added static get(), set(), and clone() methods (Programming Drill 2.1.1).
  //      20170122    D.E. Reese          Added add(), subtract() (Programming Drill 2.1.1).
  //      20170131    D.E. Reese          Added multiply() for two ComplexMatrices (Programming Drill 2.2.2).
  //      20170201    D.E. Reese          Added code to stub multiply() of two matrices and added instance multiply().
  //      20170202    D.E. Reese          Corrected bug in multiply() of two complex matrices where test for matrix2
  //                                      being null tested matrix1 (resulted in NullPointerException instead of
  //                                      IllegalArgumentException).
  //                                      Added is1By1() and convert1By1ToScalar().
  //      20170205    D.E. Reese          Added transpose(), transposeConjugate(), isSquare().
  //      20170209    D.E. Reese          Added trace().
  //      20170210    D.E. Reese          Added innerProduct(). Finalized method parameters.
  //      20170213    D.E. Reese          Added equals(), isHermitian().
  //      20170215    D.E. Reese          Added identityMatrix(), isIdentity().
  //      20170216    D.E. Reese          Added isUnitary().
  //      20170217    D.E. Reese          Added tensorProduct().
  //      20170218    D.E. Reese          Fixed bug in tensorProduct() to get the correct indices.
  //
  
  public class ComplexMatrix implements Cloneable
  {
      /**
       * Number of rows in the matrix.
       */
      private int numRows;
  
      /**
       * Number of columns in the matrix.
       */
      private int numColumns;
  
      /**
       * Array of data contained in the matrix.
       */
      private Complex theData[][];
  
      /**
       * Constructor to create a matrix of complex numbers. All entries in the array will be set to 0.
       * @param rows  Number of rows in matrx.
       * @param columns   Number of columns in matrix.
       * @throws IllegalArgumentException Thrown if rows <= 0 or columns <= 0.
       */
      public ComplexMatrix(final int rows, final int columns) throws IllegalArgumentException
      {
          // Verify that the rows and columns are valid.
  
          if (rows <= 0) throw new IllegalArgumentException("rows <= 0.");
          if (columns <= 0) throw new IllegalArgumentException("columns <= 0.");
  
          // Set the local numbers of rows and columns.
  
          numRows = rows;
          numColumns = columns;
  
          // Create the matrix objects.
  
          theData = new Complex[rows][columns];
          for(int i = 0; i < numRows; i++)
              for(int j = 0; j < numColumns; j++)
                  theData[i][j] = new Complex();
      }
  
      /**
       * Constructor to create a matrix of complex numbers of the same dimensions and elements of another
       * complex matrix. This makes a shallow copy of the matrix (i.e., the elements of the original and
       * new matrix will be the same, not copies).
       * @param theMatrix Matrix of complex numbers to be copied to the new matrix.
       * @throws IllegalArgumentException Thrown if theMatrix is null or has internal data inconsistencies.
       */
      public ComplexMatrix(final ComplexMatrix theMatrix) throws IllegalArgumentException
      {
          // Verify that theMatrix is correct.
          if (theMatrix == null) throw new IllegalArgumentException("theMatrix is null.");
          if (theMatrix.numRows <= 0) throw new IllegalArgumentException("theMatrix.numRows <= 0.");
          if (theMatrix.numColumns <= 0) throw new IllegalArgumentException("theMatrix.theColumns <= 0.");
          if (theMatrix.theData == null) throw new IllegalArgumentException("theMatrix.theData is null.");
  
          numRows = theMatrix.numRows;
          numColumns = theMatrix.numColumns;
  
          theData = new Complex[numRows][numColumns];
          for(int i = 0; i < numRows; i++)
              for(int j = 0; j < numColumns; j++)
                  theData[i][j] = new Complex(theMatrix.theData[i][j]);
      }
  
      /**
       * This method returns an element of a ComplexMatrix at a specified row and column.
       * @param theMatrix Matrix whose element is to be returned.
       * @param row   Row of desired element. Note that this is 0-based.
       * @param column    Column of desired element. Note that this is 0-based.
       * @return  Element in theMatrix at [row][column]
       * @throws IllegalArgumentException Thrown if theMatrix is null.
       * @throws IndexOutOfBoundsException    Thrown if row or column are out of bounds.
       */
      public static Complex get (final ComplexMatrix theMatrix, final int row, final int column) throws IllegalArgumentException, IndexOutOfBoundsException
      {
          if (theMatrix == null) throw new IllegalArgumentException("theMatrix is null.");
          if ((row < 0) || (row >= theMatrix.numRows)) throw new IndexOutOfBoundsException("row < 0 or row >= theMatrix.numRows");
          if ((column < 0) || (column >= theMatrix.numColumns)) throw new IndexOutOfBoundsException("column < 0 or column >= theMatrix.numColumns");
  
          return theMatrix.theData[row][column];
      }
  
      /**
       * This method sets an element in a complex matrix to a new complex number.
       * @param theMatrix Matrix whose element is to be set.
       * @param row   Row of the element to be set. Note that this is 0-based.
       * @param column    Column of the element to be set. Note that this is 0-based.
       * @param element   New value of the specified element.
       * @return  Previous value of the element.
       * @throws IndexOutOfBoundsException    Thrown if row or column are out of bounds.
       * @throws IllegalArgumentException     Thrown if element is null.
       */
      public static Complex set(ComplexMatrix theMatrix, int row, int column, Complex element) throws IllegalArgumentException, IndexOutOfBoundsException
      {
          if (theMatrix == null) throw new IllegalArgumentException("theMatrix is null.");
          if ((row < 0) || (row >= theMatrix.numRows)) throw new IndexOutOfBoundsException("row < 0 or row >= theMatrix.numRows.");
          if ((column < 0) || (column >= theMatrix.numColumns)) throw new IndexOutOfBoundsException("column < 0 or column >= theMatrix.numColumns.");
          if (element == null) throw new IllegalArgumentException("element is null.");
  
          Complex currentValue = theMatrix.theData[row][column];
          theMatrix.theData[row][column] = element;
          return currentValue;
      }
  
      /**
       * This method adds two complex matrices and returns the sum. The corresponding elements of each matrix are added.
       * @param matrix1   First matrix to add.
       * @param matrix2   Second matrix to add.
       * @return  New matrix with element [i][j] the sum of matrix1[i][j] + matrix2[i][j].
       * @throws IllegalArgumentException Thrown if matrix1 is null, matrix2 is null, or matrix1 and matrix2 are not the same size.
       */
      public static ComplexMatrix add(final ComplexMatrix matrix1, final ComplexMatrix matrix2) throws IllegalArgumentException
      {
          if (matrix1 == null) throw new IllegalArgumentException("matrix1 is null.");
          if (matrix2 == null) throw new IllegalArgumentException("matrix2 is null.");
          if (matrix1.numRows != matrix2.numRows) throw new IllegalArgumentException("matrix1 not the same size as matrix2");
          if (matrix1.numColumns != matrix2.numColumns) throw new IllegalArgumentException("matrix1 not the same size as matrix2");
  
          ComplexMatrix newMatrix = new ComplexMatrix(matrix1.numRows, matrix1.numColumns);
          for(int i = 0; i < matrix1.numRows; i++)
              for(int j = 0; j < matrix1.numColumns; j++)
                  newMatrix.theData[i][j] = new Complex(Complex.add(matrix1.get(i,j), matrix2.get(i,j)));
          return newMatrix;
      }
  
      /**
       * This method subtracts two complex matrices and returns the sum. The corresponding elements of each matrix are subtracted.
       * @param matrix1   First matrix from which matrix2 is to be subtracted.
       * @param matrix2   Second matrix to subtract from matrix1.
       * @return  New matrix with element [i][j] the sum of matrix1[i][j] - matrix2[i][j].
       * @throws IllegalArgumentException Thrown if matrix1 is null, matrix2 is null, or matrix1 and matrix2 are not the same size.
       */
      public static ComplexMatrix subtract(final ComplexMatrix matrix1, final ComplexMatrix matrix2) throws IllegalArgumentException
      {
          if (matrix1 == null) throw new IllegalArgumentException("matrix1 is null.");
          if (matrix2 == null) throw new IllegalArgumentException("matrix2 is null.");
          if (matrix1.numRows != matrix2.numRows) throw new IllegalArgumentException("matrix1 not the same size as matrix2");
          if (matrix1.numColumns != matrix2.numColumns) throw new IllegalArgumentException("matrix1 not the same size as matrix2");
  
          ComplexMatrix newMatrix = new ComplexMatrix(matrix1.numRows, matrix1.numColumns);
          for(int i = 0; i < matrix1.numRows; i++)
              for(int j = 0; j < matrix1.numColumns; j++)
                  newMatrix.theData[i][j] = new Complex(Complex.subtract(matrix1.get(i,j), matrix2.get(i,j)));
          return newMatrix;
      }
  
      /**
       * This method performs scalar multiplication on a complex matrix, i.e., multiplying each element by a scalar.
       * @param theMatrix Matrix to be multiplier by multiplier.
       * @param multiplier    Complex scalar by which to multiply each element of theMatrix.
       * @return  New matrix whose elements are the elements of theMatrix multiplied by multiplier.
       * @throws IllegalArgumentException Thrown if theMatrix is null or multiplier is null.
       */
      public static ComplexMatrix multiply(final ComplexMatrix theMatrix, final Complex multiplier) throws IllegalArgumentException
      {
          if (theMatrix == null) throw new IllegalArgumentException("theMatrix is null.");
          if (multiplier == null) throw new IllegalArgumentException("multiplier is null.");
  
          ComplexMatrix newMatrix = new ComplexMatrix(theMatrix.numRows, theMatrix.numColumns);
          for(int i = 0; i < theMatrix.numRows; i++)
              for(int j = 0; j < theMatrix.numColumns; j++)
                  newMatrix.theData[i][j] = theMatrix.theData[i][j].multiply(multiplier);
          return newMatrix;
      }
  
      /**
       * This method performs scalar multiplication on a complex matrix, i.e., multiplying each element by a scalar.
       * @param theMatrix Matrix to be multiplier by multiplier.
       * @param multiplier    Double scalar by which to multiply each element of theMatrix.
       * @return  New matrix whose elements are the elements of theMatrix multiplied by multiplier.
       * @throws IllegalArgumentException Thrown if theMatrix is null.
       */
      public static ComplexMatrix multiply(final ComplexMatrix theMatrix, final double multiplier) throws IllegalArgumentException
      {
          if (theMatrix == null) throw new IllegalArgumentException("theMatrix is null.");
  
          ComplexMatrix newMatrix = new ComplexMatrix(theMatrix.numRows, theMatrix.numColumns);
          for(int i = 0; i < theMatrix.numRows; i++)
              for(int j = 0; j < theMatrix.numColumns; j++)
                  newMatrix.theData[i][j] = theMatrix.theData[i][j].multiply(multiplier);
          return newMatrix;
      }
  
      /**
       * This method performs scalar multiplication on a complex matrix, i.e., multiplying each element by a scalar.
       * @param theMatrix Matrix to be multiplier by multiplier.
       * @param multiplier    Float scalar by which to multiply each element of theMatrix.
       * @return  New matrix whose elements are the elements of theMatrix multiplied by multiplier.
       * @throws IllegalArgumentException Thrown if theMatrix is null.
       */
      public static ComplexMatrix multiply(final ComplexMatrix theMatrix, final float multiplier) throws IllegalArgumentException
      {
          if (theMatrix == null) throw new IllegalArgumentException("theMatrix is null.");
  
          ComplexMatrix newMatrix = new ComplexMatrix(theMatrix.numRows, theMatrix.numColumns);
          for(int i = 0; i < theMatrix.numRows; i++)
              for(int j = 0; j < theMatrix.numColumns; j++)
                  newMatrix.theData[i][j] = theMatrix.theData[i][j].multiply(multiplier);
          return newMatrix;
      }
  
      /**
       * This method performs scalar multiplication on a complex matrix, i.e., multiplying each element by a scalar.
       * @param theMatrix Matrix to be multiplier by multiplier.
       * @param multiplier    Int scalar by which to multiply each element of theMatrix.
       * @return  New matrix whose elements are the elements of theMatrix multiplied by multiplier.
       * @throws IllegalArgumentException Thrown if theMatrix is null.
       */
      public static ComplexMatrix multiply(final ComplexMatrix theMatrix, final int multiplier) throws IllegalArgumentException
      {
          if (theMatrix == null) throw new IllegalArgumentException("theMatrix is null.");
  
          ComplexMatrix newMatrix = new ComplexMatrix(theMatrix.numRows, theMatrix.numColumns);
          for(int i = 0; i < theMatrix.numRows; i++)
              for(int j = 0; j < theMatrix.numColumns; j++)
                  newMatrix.theData[i][j] = theMatrix.theData[i][j].multiply(multiplier);
          return newMatrix;
      }
  
      /**
       * This method multiplies two complex matrices.
       * @param matrix1   First matrix to multiply.
       * @param matrix2   Second matrix to multiply.
       * @return  The product of matrix1 * matrix2.
       * @throws IllegalArgumentException Thrown if matrix1 is null, matrix2 is null, or the dimensions of the matrices do not allow matrix multiplication.
       */
      public static ComplexMatrix multiply(final ComplexMatrix matrix1, final ComplexMatrix matrix2) throws IllegalArgumentException
      {
          if (matrix1 == null) throw new IllegalArgumentException("matrix1 is null.");
          if (matrix2 == null) throw new IllegalArgumentException("matrix2 is null.");
          if (matrix1.numColumns != matrix2.numRows) throw new IllegalArgumentException("matrix1.numColumns != matrix2.numRows.");
  
          ComplexMatrix result = new ComplexMatrix(matrix1.numRows, matrix2.numColumns);
  
          for (int i = 0; i < result.numRows; i++)
              for (int j = 0; j < result.numColumns; j++)
              {
                  Complex theElement = new Complex();
                  for (int l = 0; l < matrix1.numColumns; l++)
                  {
                      theElement = theElement.add(matrix1.get(i, l).multiply(matrix2.get(l, j)));
                  }
                  result.set(i, j, theElement);
              }
          return result;
      }
  
      /**
       * This method negates a complex matrix, i.e., multiplies each element by -1.
       * @param theMatrix Matrix to be negated.
       * @return  The arithmetic inverse of the matrix, i.e., each element multiplied by -1.
       * @throws IllegalArgumentException Thrown if theMatrix is null.
       */
      public static ComplexMatrix negate(final ComplexMatrix theMatrix) throws IllegalArgumentException
      {
          if (theMatrix == null) throw new IllegalArgumentException("theMatrix is null.");
  
          ComplexMatrix newMatrix = new ComplexMatrix(theMatrix.numRows, theMatrix.numColumns);
          for(int i = 0; i < theMatrix.numRows; i++)
              for(int j = 0; j < theMatrix.numColumns; j++)
                  newMatrix.theData[i][j] = theMatrix.theData[i][j].negate();
          return newMatrix;
      }
  
      /**
       * This method returns the number of rows in a complex matrix.
       * @param theMatrix Matrix whose number of rows is to be returned.
       * @return  Number of rows in the matrix.
       * @throws IllegalArgumentException Thrown if theMatrix is null.
       */
      public static int getNumRows(final ComplexMatrix theMatrix) throws IllegalArgumentException
      {
          if (theMatrix == null) throw new IllegalArgumentException("theMatrix is null.");
          return theMatrix.numRows;
      }
  
      /**
       * This method returns the number of columns in a complex matrix.
       * @param theMatrix Matrix whose number of columns is to be returned.
       * @return  Number of rows in the matrix.
       * @throws IllegalArgumentException Thrown if theMatrix is null.
       */
      public static int getNumColumns(final ComplexMatrix theMatrix) throws IllegalArgumentException
      {
          if (theMatrix == null) throw new IllegalArgumentException("theMatrix is null.");
          return theMatrix.numColumns;
      }
  
      /**
       * This method determines if a ComplexMatrix is a 1x1 matrix (i.e., it's really a scalar).
       * @param theMatrix Matrix to test.
       * @return  true if theMatrix has 1 row and 1 column; false otherwise.
       * @throws IllegalArgumentException Thrown if theMatrix is null.
       */
      public static boolean is1By1(final ComplexMatrix theMatrix) throws IllegalArgumentException
      {
          if (theMatrix == null) throw new IllegalArgumentException("theMatrix is null.");
  
          if ((theMatrix.numRows == 1) && (theMatrix.numColumns == 1))
              return true;
          return false;
      }
  
      /**
       * This method converts a 1x1 ComplexMatrix into a scalar.
       * @param theMatrix Matrix to be converted into a scalar.
       * @return  Complex number set to the value of the only element in the matrix.
       * @throws IllegalArgumentException Thrown if theMatrix is null, theMatrix is not 1x1.
       */
      public static Complex convert1By1ToScalar(final ComplexMatrix theMatrix) throws IllegalArgumentException
      {
          if (theMatrix == null) throw new IllegalArgumentException("theMatrix is null.");
          if ((theMatrix.numRows != 1) || (theMatrix.numColumns != 1))
              throw new IllegalArgumentException("theMatrix is not 1x1.");
          return new Complex(theMatrix.theData[0][0]);
      }
  
      /**
       * This method returns the transpose of a matrix, i.e., the result matrix is result[j,i] = theMatrix[i,j]. Note
       * that this is a deep copy, i.e., each element of the result is a copy of the source element.
       * @param theMatrix Matrix whose transpose is to be found.
       * @return  Transpose of the matrix.
       * @throws IllegalArgumentException Thrown if theMatrix is null.
       */
      public static ComplexMatrix transpose(final ComplexMatrix theMatrix) throws IllegalArgumentException
      {
          if (theMatrix == null) throw new IllegalArgumentException("theMatrix is null.");
  
          ComplexMatrix theResult = new ComplexMatrix(theMatrix.numColumns, theMatrix.numRows);
          for(int i = 0; i < theMatrix.numRows; i++)
              for(int j = 0; j < theMatrix.numColumns; j++)
                  theResult.theData[j][i] = new Complex(theMatrix.theData[i][j]);
          return theResult;
      }
  
      /**
       * This method returns the transpose conjugate of a matrix, i.e., the result matrix is result[j,i] = theMatrix[i,j]*.
       * Note that this is a deep copy, i.e., each element of the result is a copy of the source element.
       * @param theMatrix Matrix whose transpose conjugate is to be found.
       * @return  Transpose conjugate of the matrix.
       * @throws IllegalArgumentException Thrown if theMatrix is null.
       */
      public static ComplexMatrix transposeConjugate(final ComplexMatrix theMatrix) throws IllegalArgumentException
      {
          if (theMatrix == null) throw new IllegalArgumentException("theMatrix is null.");
  
          ComplexMatrix theResult = new ComplexMatrix(theMatrix.numColumns, theMatrix.numRows);
          for(int i = 0; i < theMatrix.numRows; i++)
  