計算方法(三)C#矩陣類庫


    測量平差以及工科中常常用到矩陣的相關運算,因此自己寫了一個,同時考慮到了類庫的可用性,這次又重載了比較勻運算符,修正了一些問題

using System;
using System.Collections.Generic;

namespace CMath
{
    [Serializable]
    public class Matrix
    {
        public double[] element;
        private int rows = 0;
        private int cols = 0;
        /// <summary>
        /// 獲取矩陣行數
        /// </summary>
        public int Rows
        {
            get
            {
                return rows;
            }
        }
        /// <summary>
        /// 獲取矩陣列數
        /// </summary>
        public int Cols
        {
            get
            {
                return cols;
            }
        }
        /// <summary>
        /// 獲取或設置第i行第j列的元素值
        /// </summary>
        /// <param name="i">第i行</param>
        /// <param name="j">第j列</param>
        /// <returns>返回第i行第j列的元素值</returns>
        public double this[int i, int j]
        {
            get
            {
                if (i < Rows && j < Cols)
                {
                    return element[i * cols + j];
                }
                else
                {
                    throw new Exception("索引越界");
                }
            }
            set
            {
                element[i * cols + j] = value;
            }
        }
        /// <summary>
        /// 用二維數組初始化Matrix
        /// </summary>
        /// <param name="m">二維數組</param>
        public Matrix(double[][] m)
        {
            this.rows = m.GetLength(0);
            this.cols = m.GetLength(1);
            int count = 0;
            this.element=new double[Rows*Cols];
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    element[count++] = m[i][j];
                }
            }
        }
        public Matrix(double[,] m)
        {
            this.rows = m.GetLength(0);
            this.cols = m.GetLength(1);
            this.element = new double[this.rows * this.cols];
            int count = 0;
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    element[count++] = m[i, j];
                }
            }
        }
        public Matrix(List<List<double>> m)
        {
            this.rows = m.Count;
            this.cols = m[0].Count;
            this.element = new double[Rows * Cols];
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    this[i, j] = m[i][j];
                }
            }
        }
        #region 矩陣數學運算
        public static Matrix MAbs(Matrix a)
        {
            Matrix _thisCopy = a.DeepCopy();
            for (int i = 0; i < a.Rows; i++)
            {
                for (int j = 0; j < a.Cols; j++)
                {
                    _thisCopy[i, j] = Math.Abs(a[i, j]);
                }
            }
            return _thisCopy;
        }
        /// <summary>
        /// 矩陣相加
        /// </summary>
        /// <param name="a">第一個矩陣,和b矩陣必須同等大小</param>
        /// <param name="b">第二個矩陣</param>
        /// <returns>返回矩陣相加后的結果</returns>
        public static Matrix operator +(Matrix a, Matrix b)
        {
            if (a.cols == b.cols && a.rows == b.rows)
            {
                double[,] res = new double[a.rows, a.cols];
                for (int i = 0; i < a.Rows; i++)
                {
                    for (int j = 0; j < a.Cols; j++)
                    {
                        res[i, j] = a[i, j] + b[i, j];
                    }
                }
                return new Matrix(res);
            }
            else
            {
                throw new Exception("兩個矩陣行列不相等");
            }
        }
        /// <summary>
        /// 矩陣相減
        /// </summary>
        /// <param name="a">第一個矩陣,和b矩陣必須同等大小</param>
        /// <param name="b">第二個矩陣</param>
        /// <returns>返回矩陣相減后的結果</returns>
        public static Matrix operator -(Matrix a, Matrix b)
        {
            if (a.cols == b.cols && a.rows == b.rows)
            {
                double[,] res = new double[a.rows, a.cols];
                for (int i = 0; i < a.Rows; i++)
                {
                    for (int j = 0; j < a.Cols; j++)
                    {
                        res[i, j] = a[i, j] - b[i, j];
                    }
                }
                return new Matrix(res);
            }
            else
            {
                throw new Exception("兩個矩陣行列不相等");
            }
        }
        /// <summary>
        /// 對矩陣每個元素取相反數
        /// </summary>
        /// <param name="a">二維矩陣</param>
        /// <returns>得到矩陣的相反數</returns>
        public static Matrix operator -(Matrix a)
        {
            Matrix res = a;
            for (int i = 0; i < a.rows; i++)
            {
                for (int j = 0; j < a.cols; j++)
                {
                    res.element[i * a.cols + j] = -res.element[i * a.cols + j];
                }
            }
            return res;
        }
        /// <summary>
        /// 矩陣相乘
        /// </summary>
        /// <param name="a">第一個矩陣</param>
        /// <param name="b">第二個矩陣,這個矩陣的行要與第一個矩陣的列相等</param>
        /// <returns>返回相乘后的一個新的矩陣</returns>
        public static Matrix operator *(Matrix a, Matrix b)
        {
            if (a.cols == b.rows)
            {
                double[,] res = new double[a.rows, b.cols];
                for (int i = 0; i < a.rows; i++)
                {
                    for (int j = 0; j < b.cols; j++)
                    {
                        for (int k = 0; k < a.cols; k++)
                        {
                            res[i, j] += a[i, k] * b[k, j];
                        }
                    }
                }
                return new Matrix(res);
            }
            else
            {
                throw new Exception("兩個矩陣行和列不等");
            }
        }
        /// <summary>
        /// 矩陣與數相乘
        /// </summary>
        /// <param name="a">第一個矩陣</param>
        /// <param name="num">一個實數</param>
        /// <returns>返回相乘后的新的矩陣</returns>
        public static Matrix operator *(Matrix a, double num)
        {
            Matrix res = a;
            for (int i = 0; i < a.rows; i++)
            {
                for (int j = 0; j < a.cols; j++)
                {
                    res.element[i * a.cols + j] *= num;
                }
            }
            return res;
        }
        /// <summary>
        /// 矩陣轉置
        /// </summary>
        /// <returns>返回當前矩陣轉置后的新矩陣</returns>
        public Matrix Transpose()
        {
            double[,] res = new double[cols, rows];
            {
                for (int i = 0; i < cols; i++)
                {
                    for (int j = 0; j < rows; j++)
                    {
                        res[i, j] = this[j, i];
                    }
                }
            }
            return new Matrix(res);
        }
        /// <summary>
        /// 矩陣求逆
        /// </summary>
        /// <returns>返回求逆后的新的矩陣</returns>
        public Matrix Inverse()
        {
            //最后原始矩陣並不變,所以需要深拷貝一份
            Matrix _thisCopy = this.DeepCopy();
            if (cols == rows && this.Determinant() != 0)
            {
                //初始化一個同等大小的單位陣
                Matrix res = _thisCopy.EMatrix();
                for (int i = 0; i < rows; i++)
                {
                    //首先找到第i列的絕對值最大的數,並將該行和第i行互換
                    int rowMax = i;
                    double max = Math.Abs(_thisCopy[i, i]);
                    for (int j = i; j < rows; j++)
                    {
                        if (Math.Abs(_thisCopy[j, i]) > max)
                        {
                            rowMax = j;
                            max = Math.Abs(_thisCopy[j, i]);
                        }
                    }
                    //將第i行和找到最大數那一行rowMax交換
                    if (rowMax != i)
                    {
                        _thisCopy.Exchange(i, rowMax);
                        res.Exchange(i, rowMax);

                    }
                    //將第i行做初等行變換,將第一個非0元素化為1
                    double r = 1.0 / _thisCopy[i, i];
                    _thisCopy.Exchange(i, -1, r);
                    res.Exchange(i, -1, r);
                    //消元
                    for (int j = 0; j < rows; j++)
                    {
                        //到本行后跳過
                        if (j == i)
                            continue;
                        else
                        {
                            r = -_thisCopy[j, i];
                            _thisCopy.Exchange(i, j, r);
                            res.Exchange(i, j, r);
                        }
                    }
                }
                return res;
            }
            else
            {
                throw new Exception("矩陣不是方陣無法求逆");
            }
        }
        #region 重載比較運算符
        public static bool operator <(Matrix a, Matrix b)
        {
            bool issmall = true;
            for (int i = 0; i < a.Rows; i++)
            {
                for (int j = 0; j < a.Cols; j++)
                {
                    if (a[i, j] >= b[i, j]) issmall = false;
                }
            }
                return issmall;
        }
        public static bool operator >(Matrix a, Matrix b)
        {
            bool issmall = true;
            for (int i = 0; i < a.Rows; i++)
            {
                for (int j = 0; j < a.Cols; j++)
                {
                    if (a[i, j] <= b[i, j]) issmall = false;
                }
            }
            return issmall;
        }
        public static bool operator <=(Matrix a, Matrix b)
        {
            bool issmall = true;
            for (int i = 0; i < a.Rows; i++)
            {
                for (int j = 0; j < a.Cols; j++)
                {
                    if (a[i, j] > b[i, j]) issmall = false;
                }
            }
            return issmall;
        }
        public static bool operator >=(Matrix a, Matrix b)
        {
            bool issmall = true;
            for (int i = 0; i < a.Rows; i++)
            {
                for (int j = 0; j < a.Cols; j++)
                {
                    if (a[i, j] < b[i, j]) issmall = false;
                }
            }
            return issmall;
        }
        public static bool operator !=(Matrix a, Matrix b)
        {
            bool issmall = true;
            issmall = ReferenceEquals(a, b);
            if (issmall) return issmall;
            for (int i = 0; i < a.Rows; i++)
            {
                for (int j = 0; j < a.Cols; j++)
                {
                    if (a[i, j] == b[i, j]) issmall = false;
                }
            }
            return issmall;
        }
        public static bool operator ==(Matrix a, Matrix b)
        {
            bool issmall = true;
            issmall = ReferenceEquals(a, b);
            if (issmall) return issmall;
            for (int i = 0; i < a.Rows; i++)
            {
                for (int j = 0; j < a.Cols; j++)
                {
                    if (a[i, j] != b[i, j]) issmall = false;
                }
            }
            return issmall;
        }
        public override bool Equals(object obj)
        {
            Matrix b = obj as Matrix;
            return this == b;
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
#endregion
        public double Determinant()
        {
            if (cols == rows)
            {
                Matrix _thisCopy = this.DeepCopy();
                //行列式每次交換行,都需要乘以-1
                double res = 1;
                for (int i = 0; i < rows; i++)
                {
                    //首先找到第i列的絕對值最大的數
                    int rowMax = i;
                    double max = Math.Abs(_thisCopy[i, i]);
                    for (int j = i; j < rows; j++)
                    {
                        if (Math.Abs(_thisCopy[j, i]) > max)
                        {
                            rowMax = j;
                            max = Math.Abs(_thisCopy[j, i]);
                        }
                    }
                    //將第i行和找到最大數那一行rowMax交換,同時將單位陣做相同初等變換
                    if (rowMax != i)
                    {
                        _thisCopy.Exchange(i, rowMax);
                        res *= -1;
                    }
                    //消元
                    for (int j = i + 1; j < rows; j++)
                    {
                        double r = -_thisCopy[j, i] / _thisCopy[i, i];
                        _thisCopy.Exchange(i, j, r);
                    }
                }
                //計算對角線乘積
                for (int i = 0; i < rows; i++)
                {
                    res *= _thisCopy[i, i];
                }
                return res;
            }
            else
            {
                throw new Exception("不是行列式");
            }
        }
        #endregion
        #region 初等變換
        /// <summary>
        /// 初等變換:交換第r1和第r2行
        /// </summary>
        /// <param name="r1">第r1行</param>
        /// <param name="r2">第r2行</param>
        /// <returns>返回交換兩行后的新的矩陣</returns>
        public Matrix Exchange(int r1, int r2)
        {
            if (Math.Min(r2, r1) >= 0 && Math.Max(r1, r2) < rows)
            {
                for (int j = 0; j < cols; j++)
                {
                    double temp = this[r1, j];
                    this[r1, j] = this[r2, j];
                    this[r2, j] = temp;
                }
                return this;
            }
            else
            {
                throw new Exception("超出索引");
            }
        }
        /// <summary>
        /// 初等變換:將r1行乘以某個數加到r2行
        /// </summary>
        /// <param name="r1">第r1行乘以num</param>
        /// <param name="r2">加到第r2行,若第r2行為負,則直接將r1乘以num並返回</param>
        /// <param name="num">某行放大的倍數</param>
        /// <returns></returns>
        public Matrix Exchange(int r1, int r2, double num)
        {
            if (Math.Min(r2, r1) >= 0 && Math.Max(r1, r2) < rows)
            {
                for (int j = 0; j < cols; j++)
                {
                    this[r2, j] += this[r1, j] * num;
                }
                return this;
            }
            else if (r2 < 0)
            {
                for (int j = 0; j < cols; j++)
                {
                    this[r1, j] *= num;
                }
                return this;
            }
            else
            {
                throw new Exception("超出索引");
            }
        }
        /// <summary>
        /// 得到一個同等大小的單位矩陣
        /// </summary>
        /// <returns>返回一個同等大小的單位矩陣</returns>
        public Matrix EMatrix()
        {
            if (rows == cols)
            {
                double[,] res = new double[rows, cols];
                for (int i = 0; i < rows; i++)
                {
                    for (int j = 0; j < cols; j++)
                    {
                        if (i == j)
                            res[i, j] = 1;
                        else
                            res[i, j] = 0;
                    }
                }
                return new Matrix(res);
            }
            else
                throw new Exception("不是方陣,無法得到單位矩陣");
        }
        #endregion
        /// <summary>
        /// 深拷貝,僅僅將值拷貝給一個新的對象
        /// </summary>
        /// <returns>返回深拷貝后的新對象</returns>
        public Matrix DeepCopy()
        {
            double[,] ele = new double[rows, cols];
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    ele[i, j] = this[i, j];
                }
            }
            return new Matrix(ele);
        }

        public override string ToString()
        {
            string str = "";
            for (int i = 0; i < Rows; i++)
            {
                for (int j = 0; j < Cols; j++)
                {
                    str += this[i, j].ToString();
                    if (j != Cols - 1)
                        str += " ";
                    else if (i != Rows - 1)
                        str += Environment.NewLine;
                }
            }
            return str;
        }
    }
}

 

 矩陣的求秩過幾天補上。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM