// DETERMINANT
        // first row expansion
        public IComplexNumber Determinant(IComplexMatrix matrix)
        {
            if (matrix.IsScalar())
            {
                return matrix.getElement(0, 0);
            }

            if (matrix.IsSquare())
            {
                IComplexNumber result = ComplexNumberFactory.GenerateZero();
                //IComplexNumber negative = ComplexNumberFactory.Operations.SignReversal(ComplexNumberFactory.generateIdentity());
                IComplexMatrix tempMatrix;
                IComplexNumber tempDeterminant;
                //IComplexNumber tempCoefficient;

                int count = matrix.getNumCols();
                for (int pos = 0; pos < count; pos++)
                {
                    tempMatrix = ComplexMatrixFactory.Operations.RemoveRowCol(matrix, 0, pos);
                    tempDeterminant = ComplexMatrixFactory.Operations.Determinant(tempMatrix);
                    //tempCoefficient = ComplexNumberFactory.Operations.Power(negative, pos);
                    if (pos % 2 == 0)
                    { result = ComplexNumberFactory.Operations.Add(result, tempDeterminant); }
                    else
                    { result = ComplexNumberFactory.Operations.Substract(result, tempDeterminant); }

                }

                return result;
            }

            throw new ExceptionMatrixDimension();
        }
        // CONJUGATE
        public IComplexMatrix Conjugate(IComplexMatrix matrix)
        {
            int maxRow = matrix.getNumRows();
            int maxCol = matrix.getNumCols();
            IComplexMatrix resultMatrix = ComplexMatrixFactory.GenerateComplexMatrix(maxRow, maxCol, false);
            IComplexNumber coefficient;

            for (int i = 0; i < maxRow; i++)
            {
                for (int j = 0; j < maxCol; j++)
                {
                    coefficient = ComplexNumberFactory.Operations.Conjugate(matrix.getElement(i, j));
                    resultMatrix.setElement(coefficient, i, j);
                }
            }

            return resultMatrix;
        }
        // ADDITION
        public IComplexMatrix Add(IComplexMatrix matrixA, IComplexMatrix matrixB)
        {
            int maxRow = System.Math.Min(matrixA.getNumRows(), matrixB.getNumRows());
            int maxCol = System.Math.Min(matrixA.getNumCols(), matrixB.getNumCols());
            //if (matrixA.getNumRows() != matrixB.getNumCols()) { throw new ExceptionMatrixDimension(); };

            IComplexMatrix resultMatrix = ComplexMatrixFactory.GenerateComplexMatrix(maxRow, maxCol, false);
            IComplexNumber coefficientA, coefficientB;
            IComplexNumber addition;
            for (int i = 0; i < maxRow; i++)
            {
                for (int j = 0; j < maxCol; j++)
                {
                    coefficientA = matrixA.getElement(i, j);
                    coefficientB = matrixB.getElement(i, j);
                    addition = ComplexNumberFactory.Operations.Add(coefficientA, coefficientB);
                    resultMatrix.setElement(addition, i, j);
                }
            }

            return resultMatrix;
        }
        // UTILITY PRODUCT
        public IComplexMatrix Multiplication(IComplexNumber number, IComplexMatrix matrix)
        {
            int maxRow = matrix.getNumRows();
            int maxCol = matrix.getNumCols();

            IComplexMatrix resultMatrix = FactoryComplexMatrix.generateComplexMatrix(maxRow, maxCol, false);
            IComplexNumber coefficient;

            for (int i = 0; i < maxRow; i++)
            {
                for (int j = 0; j < maxCol; j++)
                {
                    coefficient = FactoryComplexNumber.Operations.Multiplication(number, matrix.getElement(i, j));
                    resultMatrix.setElement(coefficient, i, j);
                }
            }

            return resultMatrix;
        }
        public IComplexMatrix Normalize(IComplexMatrix matrix)
        {
            double coeff = NormalizationCoefficient(matrix);

            IComplexNumber normalizationFactor = ComplexNumberFactory.GenerateComplexNumber(coeff, 0);
            return Multiplication(normalizationFactor, matrix);
        }
        // TENSOR PRODUCT
        public IComplexMatrix Tensor(IComplexMatrix matrixA, IComplexMatrix matrixB)
        {
            int maxRow = matrixA.getNumRows() * matrixB.getNumRows();
            int maxCol = matrixA.getNumCols() * matrixB.getNumCols();

            IComplexMatrix resultMatrix = ComplexMatrixFactory.GenerateComplexMatrix(maxRow, maxCol, false);
            IComplexNumber coefficient;

            for (int Ai = 0; Ai < matrixA.getNumRows(); Ai++)
            {
                for (int Aj = 0; Aj < matrixA.getNumCols(); Aj++)
                {
                    for (int Bi = 0; Bi < matrixB.getNumRows(); Bi++)
                    {
                        for (int Bj = 0; Bj < matrixB.getNumCols(); Bj++)
                        {
                            coefficient = ComplexNumberFactory.Operations.Multiplication(matrixA.getElement(Ai, Aj), matrixB.getElement(Bi, Bj));
                            resultMatrix.setElement(coefficient, Ai * matrixB.getNumRows() + Bi, Aj * matrixB.getNumCols() + Bj);
                        }
                    }
                }
            }

            return resultMatrix;
        }
        // TRACE
        public IComplexNumber Trace(IComplexMatrix matrix)
        {
            int vectorLength = System.Math.Min(matrix.getNumRows(), matrix.getNumCols());

            IComplexNumber addition;
            IComplexNumber element;

            addition = ComplexNumberFactory.GenerateZero();
            for (int k = 0; k < vectorLength; k++)
            {
                element = matrix.getElement(k, k);

                addition = ComplexNumberFactory.Operations.Add(addition, element);
            }

            return addition;
        }
 public double PoweredNormEuclidean(IComplexMatrix matrix)
 {
     double result = 0;
     for (int i = 0; i < matrix.getNumRows(); i++)
     {
         for (int j = 0; j < matrix.getNumCols(); j++)
         {
             result += ComplexNumberFactory.Operations.PoweredNormEuclidean(matrix.getElement(i, j));
         }
     }
     return result;
 }
        // REMOVEROWCOL
        public IComplexMatrix RemoveRowCol(IComplexMatrix matrix, int row, int col)
        {
            int maxRow = matrix.getNumRows() - 1;
            int maxCol = matrix.getNumCols() - 1;
            IComplexMatrix resultMatrix = ComplexMatrixFactory.GenerateComplexMatrix(maxCol, maxRow, false);
            IComplexNumber coefficient;

            int a, b;
            a = 0;
            for (int i = 0; i < maxRow; i++)
            {
                b = 0;
                for (int j = 0; j < maxCol; j++)
                {
                    if ((i != row) && (j != col))
                    {
                        coefficient = matrix.getElement(i, j);
                        resultMatrix.setElement(coefficient, a, b);
                    }
                    else
                    {
                        a--;
                        b--;
                    }
                    b++;
                }
                a++;
            }

            return resultMatrix;
        }
        public void setVectorInternal(IComplexMatrix vector)
        {
            int count = getNumLevels();

            if (count != vector.countTotalElements())
            { throw new ExceptionQuantumDebugger(); }

            for (int i = 0; i < count; i++)
            {
                setCoefficientInternal(vector.getElement(i, 0), i);
            }
        }
 // NORM
 public double PoweredNorm(IComplexMatrix matrix)
 {
     return PoweredNormEuclidean(matrix);
 }
        // NORMALIZE
        public double NormalizationCoefficient(IComplexMatrix matrix)
        {
            double poweredNorm = PoweredNorm(matrix);
            //int count = matrix.countTotalElements();

            double temp = 1.0 / poweredNorm;
            return System.Math.Sqrt(temp);

            //double coefBase = 1.0 / poweredNorm;
            //double coefExpo = 1.0 / (double)count;
            //return System.Math.Pow(coefBase, coefExpo);
        }
        //DATA COMPARISON
        public bool Equals(IComplexMatrix matrix)
        {
            bool result = true;

            for( int i=0; i < getNumRows(); i++)
            {
                for( int j=0; j < getNumCols(); j++ )
                {
                    result &= getElement(i,j).Equals(matrix.getElement(i,j));
                }
            }

            return result;
        }
        // INNER PRODUCT
        public IComplexMatrix Multiplication(IComplexMatrix matrixA, IComplexMatrix matrixB)
        {
            int maxRow = System.Math.Min(matrixA.getNumRows(), matrixB.getNumRows());
            int maxCol = System.Math.Min(matrixA.getNumCols(), matrixB.getNumCols());
            //if (matrixA.getNumRows() != matrixB.getNumCols()) { throw new ExceptionMatrixDimension(); };

            IComplexMatrix resultMatrix = ComplexMatrixFactory.GenerateComplexMatrix(maxRow, maxCol, false);
            IComplexMatrix vectorA, vectorB;
            IComplexNumber coefficient;
            for (int i = 0; i < maxRow; i++)
            {
                for (int j = 0; j < maxCol; j++)
                {
                    vectorA = matrixA.extractRowAsVector(i);
                    vectorB = matrixB.extractColAsVector(j);
                    coefficient = ComplexMatrixFactory.Operations.Dot(vectorA, vectorB);
                    resultMatrix.setElement(coefficient, i, j);
                }
            }

            return resultMatrix;
        }
        // INVERSE
        public IComplexMatrix Inverse(IComplexMatrix matrix)
        {
            IComplexMatrix tempMatrix ;
            IComplexNumber determinant;
            IComplexNumber coefficient;

            determinant = ComplexMatrixFactory.Operations.Determinant(matrix);
            coefficient = ComplexNumberFactory.Operations.Inverse(determinant);

            tempMatrix = matrix;
            tempMatrix = ComplexMatrixFactory.Operations.Transpose(tempMatrix);
            tempMatrix = ComplexMatrixFactory.Operations.Conjugate(tempMatrix);

            return ComplexMatrixFactory.Operations.Multiplication(coefficient, tempMatrix);
        }
        // DOT PRODUCT
        public IComplexNumber Dot(IComplexMatrix matrixA, IComplexMatrix matrixB)
        {
            int vectorLength = System.Math.Min(matrixA.getNumRows(), matrixB.getNumRows());

            IComplexNumber addition;
            IComplexNumber multiplication;
            IComplexNumber complexA, complexB;

            addition = ComplexNumberFactory.GenerateZero();
            for (int k = 0; k < vectorLength; k++)
            {
                complexA = matrixA.getElement(k, 0);
                complexB = matrixB.getElement(k, 0);

                multiplication = ComplexNumberFactory.Operations.Multiplication(complexA, complexB);

                addition = ComplexNumberFactory.Operations.Add(addition, multiplication);
            }

            return addition;
        }
 // CONSTRUCTOR
 public QuantumStateIsolated(int numLevels)
     : base(numLevels)
 {
     _matrix = ComplexMatrixFactory.GenerateComplexMatrix(numLevels, 1, false);
     _matrix.Randomize();
 }
        // TRANSPOSE
        public IComplexMatrix Transpose(IComplexMatrix matrix)
        {
            int maxRow = matrix.getNumRows();
            int maxCol = matrix.getNumCols();
            IComplexMatrix resultMatrix = FactoryComplexMatrix.generateComplexMatrix(maxCol, maxRow, false);
            IComplexNumber coefficient;

            for (int i = 0; i < maxRow; i++)
            {
                for (int j = 0; j < maxCol; j++)
                {
                    coefficient = FactoryComplexNumber.Operations.SignReversal(matrix.getElement(i, j));
                    resultMatrix.setElement(coefficient, j, i);
                }
            }

            return resultMatrix;
        }
 // Initialize and set values to a existing matix
 public virtual void Initialize(IComplexMatrix matrix)
 {
     for( int i=0; i < getNumRows(); i++ )
         for( int j=0; j < getNumCols(); j++ )
         {
             setElement(matrix.getElement(i,j),i,j);
         }
 }
 // CONSTRUCTOR
 public QuStateIsolated(int numLevels)
     : base(numLevels)
 {
     _matrix = FactoryComplexMatrix.generateComplexMatrix(numLevels, 1, false);
     _matrix.Randomize();
 }