矩陣相乘的三種實現

對於兩個N階矩陣的乘法,可以使用蠻力法,三層循環即可實現,也可以使用分治法實現。

原數據結構:

    public class Matrix
    {
        public Matrix(int N)
        {
            this.n = N;
            m = new int[n, n];
            sx = 0;
            sy = 0;
            ex = N - 1;
            ey = N - 1;
        }
        public int[,] m;
        public int n;
        //position.start and end coordinate
        public int sx;
        public int sy;
        public int ex;
        public int ey;

        public void init()
        {
            Random r = new Random();
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    m[i, j] = r.Next(n);
                }
            }
            
        }
    }

三層循環:

        public static Matrix SquareMatrixMultiply(Matrix a, Matrix b)
        {
            int tmp = 0, n;
            n = a.n;
            Matrix c = new Matrix(n);
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    for (int k = 0; k < n; k++)
                    {
                        tmp += a.m[i,k] * b.m[k,j];
                    }
                    c.m[i,j] = tmp;
                    tmp = 0;
                }
            }

            return c;
        }

分治法:

        public static Matrix SquareMatrixMultiplyRecursive(Matrix a, Matrix b)
        {
            int n = a.n;
            Matrix c = new Matrix(n);
            if (n == 1)
            {
                //c.m[a.sx, b.sy] += a.m[a.sx, a.sy] * b.m[b.sx, b.sy];
                c.m[0, 0] = a.m[0, 0] * b.m[0, 0];
            }
            else
            {
                Matrix suba,subb;
                int[] ta1 = new int[4] { 0, 0, 2, 2 };
                int[] ta2 = new int[4] { 1, 1, 3, 3 };
                int[] tb1 = new int[4] { 0, 1, 0, 1 };
                int[] tb2 = new int[4] { 2, 3, 2, 3 };
                for (int i = 0; i < 4; i++)
                {
                    suba = partitionArray(ta1[i], a);
                    subb = partitionArray(tb1[i], b);

                    Matrix c1 = SquareMatrixMultiplyRecursive(suba, subb);
                    suba = partitionArray(ta2[i], a);
                    subb = partitionArray(tb2[i], b);
                    Matrix c2 = SquareMatrixMultiplyRecursive(suba, subb);
                    Plus(c, c1, c2, i);
                }

            }
            return c;
        }

Strassen

        public static Matrix SquareMatrixMultiplyStrassen(Matrix a, Matrix b)
        {
            int N = a.n;
            Matrix c = new Matrix(N);

            if (N <= 1)
            {
                c.m[a.sx, b.sy] = a.m[a.sx, a.sy] * b.m[b.sx, b.sy];
                //c.m[0, 0] = a.m[0, 0] * b.m[0, 0];
            }
            else
            {
                Dictionary<string, Matrix> ms = new Dictionary<string, Matrix>();
                //s1~s10
                string[] sa = { "S2", "S3", "S5", "S7", "S9" };
                string[] sb = { "S1", "S4", "S6", "S8", "S10" };
                int[] sa1 = { 0, 2, 0, 1, 0 };
                int[] sa2 = { 1, 3, 3, 3, 2 };
                bool[] sa3 = { true, true, true, false, false };

                int[] sb1 = { 1, 2, 0, 2, 0 };
                int[] sb2 = { 3, 0, 3, 3, 2 };
                bool[] sb3 = { false, false, true, true, true };
                Matrix tmp = null, sub1 = null, sub2 = null;
                for (int i = 0; i < 5; i++)
                {
                    sub1 = PartitionArrayByCalcuIndex(sa1[i], a);
                    sub2 = PartitionArrayByCalcuIndex(sa2[i], a);
                    tmp = AddMinus(sub1, sub2, sa3[i]);
                    ms.Add(sa[i], tmp);

                    sub1 = PartitionArrayByCalcuIndex(sb1[i], b);
                    sub2 = PartitionArrayByCalcuIndex(sb2[i], b);
                    tmp = AddMinus(sub1, sub2, sb3[i]);
                    ms.Add(sb[i], tmp);
                }
                string[] sp1 = { "A0", "S2", "S3", "A3", "S5", "S7", "S9" };
                string[] sp2 = { "S1", "B3", "B0", "S4", "S6", "S8", "S10" };

                for (int i = 0; i < sp1.Length; i++)
                {
                    string name = "P" + (i+1);
                    sub1 = getMBy(sp1[i], a, b, ms);
                    sub2 = getMBy(sp2[i], a, b, ms);
                    ms.Add(name, SquareMatrixMultiplyStrassen(sub1, sub2));
                }
                sub1 = ms["P5"].Add(ms["P4"]).Minus(ms["P2"]).Add(ms["P6"]);
                c.Add(sub1);
                sub1 = ms["P1"].Minus(ms["P2"]);
                c.Add(sub1);
                sub1 = ms["P3"].Add(ms["P4"]);
                c.Add(sub1);
                sub1 = ms["P5"].Add(ms["P1"]).Minus(ms["P3"]).Minus(ms["P7"]);
                c.Add(sub1);
            }
            return c;

主方法:

    class Program
    {
        static void Main(string[] args)
        {
            const int N = 8;
            //a
            Matrix a = new Matrix(N);
            a.init();
            
            Operation.ShowMatrix(a,"a");
            //b
            Matrix b = new Matrix(N);
            b.init();
            Operation.ShowMatrix(b, "b");
            //c
            Matrix c = Operation.SquareMatrixMultiply(a, b);
            Operation.ShowMatrix(c,"c brute-force method");
            //d
            Matrix d = Operation.SquareMatrixMultiplyRecursive(a, b);
            Operation.ShowMatrix(d,"d divide and conquer");
            //e
            Matrix e = Operation.SquareMatrixMultiplyStrassen(a, b);
            Operation.ShowMatrix(e, "e Strassen");
        }
    }

實現界面:

本次實現使用花費時間和空間較多的數組內容拷貝,並沒有實現索引計算。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章