Matrix Multiply - 矩阵乘法


Matrix Multiply - 矩阵乘法
     两个矩阵 A,B:A 的列数等于 B 的行数,则A、B可以相乘。即,如果 A = (aij)是一个m * n的矩阵,B =(bjk)是一个 n * p 的矩阵,则它们的乘积 C = AB 是 m * p 矩阵 C = (cik)。
    学过计算机图形学,会发现,不管是二维图形的平移,旋转,缩放,三维图形的取景变换,投影变换等都是通过矩阵乘法来实现,例如,二维点P(x,y)平移(tx,ty)后得到 P’(x’,y’),可以通过矩阵计算:
                                                   
                                              
                                             
求矩阵相乘的通用公式为:
还有一个常见用法,求斐波那契数列:               
     所以当求 Fn 时可以用求幂来快速求出,而求幂也是建立在矩阵乘法的基础上:
                        
     矩阵相乘有两种方法,普通的矩阵乘法(Matrix Multiply)和Strassen算法。
最普通的矩阵乘法
Matrix operator * (Matrix a, Matrix b) {
    Matrix ret;
    ret.init(a.n, b.m);
    for (int i = 0; i < a.n; i++) {
        for (int k = 0; k < a.m; k++) if (a.mat[i][k]) {
            for (int j = 0; j < b.m; j++) if (b.mat[k][j]) {
                ret.mat[i][j] = ret.mat[i][j] + a.mat[i][k] * b.mat[k][j]; 
                if (ret.mat[i][j] >= mod) {
                    ret.mat[i][j] %= mod;
                }//if
            }//for(j)
        }//for(k)
    }//for(i)
    return ret;
}//乘法
矩阵加法只需简单的将两个矩阵的元素相加:
Matrix operator + (Matrix a, Matrix b) {
    Matrix ret;
    ret.init(a.n, a.m);
    for (int i = 0; i < a.n; i++) {
        for (int j = 0; j < a.m; j++) {
            ret.mat[i][j] = a.mat[i][j] + b.mat[i][j];
            if (ret.mat[i][j] >= mod) {
                ret.mat[i][j] %= mod;
            }
        }
    }
    return ret;
}//加法
矩阵求幂
Matrix operator ^ (Matrix a, int b) {
    Matrix ret = a,  tmp = a;
    ret.init_e();
    for ( ; b; b >>= 1) {
        if (b & 1) {
            ret = ret * tmp;
        }
        tmp = tmp * tmp;
    }
    return ret;
}//
幂求和,即求S = A + A2 + A3 +… + Ak  ,同样的二分思想,但是利用递归,可以很快求出:
//递归幂求和
//用二分法求矩阵和,递归实现 
Matrix Power_Sum1(Matrix a, int b) {
    Matrix ret = a;
    ret.init_e();
    if (b == 1) {
        return a;
    } else if (b & 1) {
        return (a ^ b) + Power_Sum1(a, b - 1);
    } else {
        return Power_Sum1(a, b >> 1) * ((a ^ (b >> 1)) + ret);
    }
}
//非递归幂求和
Matrix Power_Sum2(Matrix a, int b) {
    int k = 0 ,ss[32];
    Matrix tp1, tp2, ret;
    tp1 = tp2 = ret = a;
    ret.init_e();
    while (b) {
        ss[k++] = b & 1;
        b >>= 1;
    }
    for (int i = k - 2; i >= 0; i--) {
        tp1 = tp1 * (tp2 + ret);
        tp2 = tp2 * tp2;
        if (ss[i]) {
            tp2 = tp2 * a;
            tp1 = tp1 + tp2;
        }
    }
    return tp1;
}




二、Strassen算法
     Strassen算法核心思想是分治,是一种递归算法,运行时间为O(nlg7) = O(n2.81),当 n 很大时,优化很明显,在普通的矩阵乘法中,C = A * B,按照:
     每计算一个元素C[i,j],需要做 n 个乘法和 n – 1 次加法。因此,求出矩阵 C 的 n个元素所需的计算时间为0(n3)。Strassen算法的分治体现在:假设 n 是 2 的幂,将将矩阵A,B和C中每一矩阵都分块成为 4 个大小相等的子矩阵,每个子矩阵都是n / 2 × n / 2的方阵。由此可将方程C = AB重写为:
   由此可得
     可以看出,进行了8次乘法,4次加法,当子矩阵的阶大于2时,为求2个子矩阵的积,可以继续将子矩阵分块,直到子矩阵的阶降为2,利用这个简单的分治策略,最后可以得出:T(n) = 8T(n / 2) + O(n2),但是这个式子的解任然为T(n)= O(n3),和普通的方法效率一样,没有任何提高,原因是上边的四个式子并没有减少矩阵乘法的次数(乘法极其耗费时间,学过底层二进制计算的,必然了解,而加减操作非常轻松),所以改进算法的关键是,减少乘法次数。
     Strassen算法的高效之处,就在于,它成功的减少了乘法次数,将8次乘法,减少到7次。不要小看这减少的一次,每递归计算一次,效率就可以提高1 / 8,比如一个大的矩阵递归5次后,(7 / 8)5 = 0.5129,效率提升一倍。不过,这只是理论值,实际情况中,有隐含开销,并不是最常用算法,《算法导论》中给出四条理由:1)隐含的常数因子比简单的O(n3)方法中的常数因子要大。2)矩阵是稀疏矩阵时,为稀疏矩阵设计的方法更快。还有两点已经被缓解,可以不考虑。所以,稠密矩阵上的快速矩阵乘法实现一般采用Strassen算法。

M1 = (A0 + A3) × (B0 + B3)

M2 = (A2 + A3) × B0

M3 = A0 × (B1 – B3)

M4 = A3 × (B2 – B0)

M5 = (A0 + A1) × B3

M6 = (A2 – A0) × (B0 + B1)

M7 = (A1 – A3) × (B2 + B3)

C0 = M1 + M4 – M5 + M7

C1 = M3 + M5

C2 = M2 + M4

C3 = M1 – M2 + M3 + M6

      求解M1,……,M7总共7次乘法,其他都是加法和减法,比如将C0扩展开后,最后结果是,C0 = A0 * B0 + A1 * B2,《算法导论》里有一句奇怪的话:“现在我们还不清楚Strassen当时是如何找出算法正常运行的关键——子矩阵乘积”,一次乘法的消失过程真的这么吊诡?
Please read full article from Matrix Multiply - 矩阵乘法

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts