/// <summary>LU Decomposition</summary>
        /// <param name="A">  Rectangular matrix
        /// </param>
        /// <returns>     Structure to access L, U and piv.
        /// </returns>

        public LUDecomposition(GeneralMatrix A)
        {
            // Use a "left-looking", dot-product, Crout/Doolittle algorithm.

            LU  = A.ArrayCopy;
            m   = A.RowDimension;
            n   = A.ColumnDimension;
            piv = new int[m];
            for (int i = 0; i < m; i++)
            {
                piv[i] = i;
            }
            pivsign = 1;
            double[] LUrowi;
            double[] LUcolj = new double[m];

            // Outer loop.

            for (int j = 0; j < n; j++)
            {
                // Make a copy of the j-th column to localize references.

                for (int i = 0; i < m; i++)
                {
                    LUcolj[i] = LU[i][j];
                }

                // Apply previous transformations.

                for (int i = 0; i < m; i++)
                {
                    LUrowi = LU[i];

                    // Most of the time is spent in the following dot product.

                    int    kmax = System.Math.Min(i, j);
                    double s    = 0.0;
                    for (int k = 0; k < kmax; k++)
                    {
                        s += LUrowi[k] * LUcolj[k];
                    }

                    LUrowi[j] = LUcolj[i] -= s;
                }

                // Find pivot and exchange if necessary.

                int p = j;
                for (int i = j + 1; i < m; i++)
                {
                    if (System.Math.Abs(LUcolj[i]) > System.Math.Abs(LUcolj[p]))
                    {
                        p = i;
                    }
                }
                if (p != j)
                {
                    for (int k = 0; k < n; k++)
                    {
                        double t = LU[p][k]; LU[p][k] = LU[j][k]; LU[j][k] = t;
                    }
                    int k2 = piv[p]; piv[p] = piv[j]; piv[j] = k2;
                    pivsign = -pivsign;
                }

                // Compute multipliers.

                if (j < m & LU[j][j] != 0.0)
                {
                    for (int i = j + 1; i < m; i++)
                    {
                        LU[i][j] /= LU[j][j];
                    }
                }
            }
        }
        /// <summary>Solve X*A = B, which is also A'*X' = B'</summary>
        /// <param name="B">   right hand side
        /// </param>
        /// <returns>     solution if A is square, least squares solution otherwise.
        /// </returns>

        public virtual GeneralMatrix SolveTranspose(GeneralMatrix B)
        {
            return(Transpose().Solve(B.Transpose()));
        }
        /// <summary>Check for symmetry, then construct the eigenvalue decomposition</summary>
        /// <param name="Arg">   Square matrix
        /// </param>
        /// <returns>     Structure to access D and V.
        /// </returns>

        public EigenvalueDecomposition(GeneralMatrix Arg)
        {
            double[][] A = Arg.Array;
            n = Arg.ColumnDimension;
            V = new double[n][];
            for (int i = 0; i < n; i++)
            {
                V[i] = new double[n];
            }
            d = new double[n];
            e = new double[n];

            issymmetric = true;
            for (int j = 0; (j < n) & issymmetric; j++)
            {
                for (int i = 0; (i < n) & issymmetric; i++)
                {
                    issymmetric = (A[i][j] == A[j][i]);
                }
            }

            if (issymmetric)
            {
                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                    {
                        V[i][j] = A[i][j];
                    }
                }

                // Tridiagonalize.
                tred2();

                // Diagonalize.
                tql2();
            }
            else
            {
                H = new double[n][];
                for (int i2 = 0; i2 < n; i2++)
                {
                    H[i2] = new double[n];
                }
                ort = new double[n];

                for (int j = 0; j < n; j++)
                {
                    for (int i = 0; i < n; i++)
                    {
                        H[i][j] = A[i][j];
                    }
                }

                // Reduce to Hessenberg form.
                orthes();

                // Reduce Hessenberg to real Schur form.
                hqr2();
            }
        }
        /// <summary>Solve A*X = B</summary>
        /// <param name="B">   right hand side
        /// </param>
        /// <returns>     solution if A is square, least squares solution otherwise
        /// </returns>

        public virtual GeneralMatrix Solve(GeneralMatrix B)
        {
            return(m == n ? (new LUDecomposition(this)).Solve(B):(new QRDecomposition(this)).Solve(B));
        }