/// <summary>
 /// Change signs of all values to opposite
 /// </summary>
 /// <param name="rightSide"></param>
 /// <returns></returns>
 public static KnuthSparseMatrix operator -(KnuthSparseMatrix rightSide)
 {
     if (rightSide == null)
     {
         throw new ArgumentNullException("rightSide");
     }
     KnuthSparseMatrix res = new KnuthSparseMatrix(rightSide);
     res.Negate();
     return res;
 }
        /// <summary>
        /// Multiply two sparse matrix
        /// </summary>
        /// <param name="mtx1">first matrix</param>
        /// <param name="mtx2">second matrix</param>
        /// <returns>result of multiplying this matrix</returns>
        public static KnuthSparseMatrix operator *(KnuthSparseMatrix mtx1, KnuthSparseMatrix mtx2)
        {
            if (mtx1.storage.Cols.Count != mtx2.storage.Rows.Count)
                throw new Exception("Wrong size of matrix to multiple");
            KnuthSparseMatrix Res = new KnuthSparseMatrix(mtx1.storage.Rows.Count, mtx2.storage.Cols.Count);
            double tmp;
            KnuthNode<double> Iter1, Iter2;
            for (int i = 0; i < mtx1.storage.Rows.Count; ++i)
            {
                for (int j = 0; j < mtx2.storage.Cols.Count; ++j)
                {
                    tmp = 0; //initalize mult of i-th row and j-th column
                    Iter1 = mtx1.storage.Rows[i].Left;
                    Iter2 = mtx2.storage.Cols[j].Up;
                    while (Iter1 != mtx1.storage.Rows[i] && Iter2 != mtx2.storage.Cols[j])
                    {
                        if (Iter1.Col == Iter2.Row)
                        {
                            tmp += Iter1.Val * Iter2.Val;
                            Iter1 = Iter1.Left;
                            Iter2 = Iter2.Up;
                        }
                        else if (Iter1.Col < Iter2.Row)
                        {
                            Iter2 = Iter2.Up;
                        }
                        else //(Iter2.Col < Iter1.Col)
                        {
                            Iter1 = Iter1.Left;
                        }
                    }
                    if (tmp != 0) // paste not 0 element
                    {
                        Res.At(i, j, tmp);
                    }

                }
            }
            return Res;
        }
 /// <summary>
 /// Adds two matrixes
 /// </summary>
 /// <param name="mtx1">first matrix</param>
 /// <param name="mtx2">second matrix</param>
 /// <returns>result of summing this matrixes</returns>
 public static KnuthSparseMatrix operator +(KnuthSparseMatrix mtx1, KnuthSparseMatrix mtx2)
 {
     if (mtx1.storage.Rows.Count != mtx2.storage.Rows.Count || mtx1.storage.Cols.Count != mtx2.storage.Cols.Count)
         throw new Exception("Wrong size of matrix to summ");
     KnuthSparseMatrix Res = new KnuthSparseMatrix(mtx1.storage.Rows.Count, mtx1.storage.Cols.Count);
     KnuthNode<double> Iter1, Iter2;
     for (int i = 0; i < mtx1.storage.Rows.Count; ++i)
     {
         Iter1 = mtx1.storage.Rows[i].Left;
         Iter2 = mtx2.storage.Rows[i].Left;
         while (Iter1 != mtx1.storage.Rows[i] || Iter2 != mtx2.storage.Rows[i])
         {
             if (Iter1 == mtx1.storage.Rows[i])
             {
                 Res.At(Iter2.Row, Iter2.Col, Iter2.Val);
                 Iter2 = Iter2.Left;
             }
             else if (Iter2 == mtx2.storage.Rows[i])
             {
                 Res.At(Iter1.Row, Iter1.Col, Iter1.Val);
                 Iter1 = Iter1.Left;
             }
             else if (Iter1.Col == Iter2.Col)
             {
                 Res.At(Iter1.Row, Iter1.Col, Iter1.Val + Iter2.Val);
                 Iter1 = Iter1.Left;
                 Iter2 = Iter2.Left;
             }
             else if (Iter1.Col < Iter2.Col)
             {
                 Res.At(Iter2.Row, Iter2.Col, Iter2.Val);
                 Iter2 = Iter2.Left;
             }
             else //(Iter2.Col < Iter1.Col)
             {
                 Res.At(Iter1.Row, Iter1.Col, Iter1.Val);
                 Iter1 = Iter1.Left;
             }
         }
     }
     return Res;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="KnuthSparseMatrix"/> class.
 /// </summary>
 /// <param name="_storage">
 /// Saved at KnuthSparseMatrixStorage matrix.
 /// </param>
 internal KnuthSparseMatrix(KnuthSparseMatrix mtx)
     : base(mtx.storage)
 {
 }