/// <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);
        }
        public QsMatrix AppendLowerMatrix(QsMatrix matrix)
        {
            QsMatrix m = CopyMatrix(this);

            foreach (var vector in matrix)
            {
                m.AddVector(vector);
            }
            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>
        /// 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);
        }
        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>
        /// '>>' 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>
        /// 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);
        }
        /// <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);
        }