/// <summary>
        /// rv = lhs * rhs
        /// 自分自身(lhs,rhs)を変更しない。
        /// </summary>
        /// <returns>乗算結果。</returns>
        public static MatrixGF2 Mul(MatrixGF2 lhs, MatrixGF2 rhs)
        {
            if (lhs.Column != rhs.Row)
            {
                throw new ArgumentException("lhs.Column != rhs.Row");
            }

            int loopCount = lhs.Column;

            var rv = new MatrixGF2(lhs.Row, rhs.Column);

            Parallel.For(0, rv.Row, r => {
                for (int c = 0; c < rv.Column; ++c)
                {
                    GF2 v = GF2.Zero;
                    for (int i = 0; i < loopCount; ++i)
                    {
                        v = GF2.Add(v, GF2.Mul(lhs.At(r, i), rhs.At(i, c)));
                    }
                    rv.Set(r, c, v);
                }
            });

            return(rv);
        }
        /// <summary>
        /// 他の行列aと同じかどうか。
        /// </summary>
        /// <returns>同じなら0。異なるときは0以外。</returns>
        public int CompareTo(MatrixGF2 a)
        {
            if (mRow != a.mRow || mCol != a.mCol)
            {
                // 異なる。
                return(1);
            }

            int acc = 0;

            for (int r = 0; r < mRow; ++r)
            {
                for (int c = 0; c < mCol; ++c)
                {
                    acc += At(r, c).Add(a.At(r, c)).Val;
                }
            }

            return(acc);
        }
        /// <summary>
        /// 自分自身を変更しない
        /// </summary>
        /// <returns>逆行列</returns>
        public MatrixGF2 Inverse()
        {
            if (mRow != mCol)
            {
                throw new NotImplementedException();
            }
            int n = mRow;

            // org := this
            var org = new MatrixGF2(n, n, m);

            // inv := 単位行列
            var inv = new MatrixGF2(n, n);

            inv.SetIdentity();

            // ピボットの候補
            var pivotList = new List <int>();

            for (int i = 0; i < n; ++i)
            {
                pivotList.Add(i);
            }

            for (int c = 0; c < n; ++c)
            {
                // c列の値が1の行を1つだけにする。

                // c列が値1の行を探す。
                int pivRow = -1;
                foreach (var r in pivotList)
                {
                    if (GF2.One == org.At(r, c))
                    {
                        pivRow = r;
                        break;
                    }
                }
                if (pivRow < 0)
                {
                    // 逆行列が存在しない。
                    return(null);
                }
                pivotList.Remove(pivRow);

                // pivot以外の行のc列の値を0にする。
                for (int r = 0; r < n; ++r)
                {
                    if (r == pivRow)
                    {
                        continue;
                    }

                    if (org.At(r, c) == GF2.One)
                    {
                        org.AddRow(pivRow, r);
                        inv.AddRow(pivRow, r);
                    }
                }
            }

            // 各々の列は値1が1度だけ現れる。

            // sが正方行列になるように行を入れ替える。
            for (int c = 0; c < n; ++c)
            {
                // c列の値が1の行を探す。
                int oneRow = -1;
                for (int r = 0; r < n; ++r)
                {
                    if (org.At(r, c) == GF2.One)
                    {
                        oneRow = r;
                        break;
                    }
                }

                if (oneRow == c)
                {
                    // 既にc列c行が1である。
                    continue;
                }

                // c行とoneRow行を入れ替えてc列c行を1にする。
                org.SwapRow(oneRow, c);
                inv.SwapRow(oneRow, c);
            }

            return(inv);
        }