Chained Matrix Multiplication(연쇄행렬곱셈)

2011. 1. 14. 22:03·Algorithms/Dynamic Programming

Basic Concept


Consider the multiplication of the following four maxtrices.

 

$$A \quad\times\quad  B \quad\times\quad C \quad\times\quad D$$

$$20\times 2 \qquad 2\times 30 \qquad 30\times 12 \qquad 12\times 8$$

 

There are five different orders in which we can multiply four matrices, each possibly resulting in a different number of elementary multiplications. The third order is the optimal order for multiplying the four matrices. Our goal is to develop an algorithm that determines the optimal order for multiplying n matrices. The optimal order depends only on the dimension of the matrices.

 

Example Five different orders in which we can multiply four matrices

A(B(CD))  (30×12×8) + ( 2×30× 8) + (20× 2× 8) =  3,680
(AB)(CD)  (20×2×30) + (30×12× 8) + (20×30× 8) =  8,880
A((BC)D)  (2×30×12) + ( 2×12× 8) + (20× 2× 8) =  1,232 // optimal order
((AB)C)D  (20×2×30) + (20×30×12) + (20×12× 8) = 10,320
(A(BC))D  (2×30×12) + (20× 2×12) + (20×12× 8) =  3,120

 

👉 연쇄적으로 행렬을 곱할 때, 어떤 행렬곱셈을 먼저 수행하느냐에 따라서 필요한 기본적인 곱셈의 횟수가 달라지게 된다. 이번 알고리즘의 목적은 n 개의 행렬을 연쇄적으로 곱할 때 최적의 순서를 찾는 것이다.
네 개의 행렬 A, B, C, D를 연쇄적으로 곱하는 경우,  총 다섯 가지 방법의 곱셈 순서가 존재한다. 이 중 세 번째 순서(A((BC)D))로 곱셈을 수행하는 것이 네 개의 행렬을 곱할 때의 최적의 순서이다.

 

 

Chained Matrix Multiplication Algorithm


Algorithm Design

We can obtain the following recursive property when multiplying n matrices. 
For 1 ≤ i ≤ j ≤ n

 

$$ \begin{align} M[i][j] = \quad& minimum_{(i \le k \le j-1)}(M[i][k] + M[k+1][j] + d_{i-1}d_kd_j), \text{ if } i < j \notag{}\\M[i][i] = \quad& 0 \notag{}\end{align}$$

 

Example Suppose we have the following six matrices:


$$ A_1 \quad \times \quad A_2 \quad \times \quad A_3 \quad \times \quad A_4 \quad \times \quad A_5 \quad \times \quad A_6 \\ (5 \ \times \ 2) \quad (2 \ \times \ 3) \quad (3 \ \times \ 4) \quad (4 \ \times \ 6) \quad (6 \ \times \ 7) \quad (7 \ \times \ 8) \\ (d_0 \times d_1) \quad (d_1\times d_2) \quad (d_2\times d_3) \quad (d_3\times d_4) \quad (d_4\times d_5) \quad (d_5\times d_6)$$

 

 

 

Compute Diagonal 1: M[1][2]는 두 개의 행렬을 곱할 때의 연산횟수를 계산한 값이다. M[2][3], M[3][4], M[4][5], M[5][6] 값들 역시 같은 방법으로 계산해준다.

M[1][2] = minimum(M[1][k] + M[k+1][2] + d0dkd2) // (1 ≤ k ≤ 1)
        = M[1][1] + M[2][2] + d0d1d2
        = 0 + 0 + 5 × 2 × 3 = 30.

 

Compute Diagonal 2: M[1][3]은 A1 부터 A3 까지의 행렬을 곱하는데 필요한 최소 횟수이다. 위에서 알 수 있듯이 세 개의 행렬을 곱하는 경우의 수는 두 가지(A1(A2A3), (A1A2)A3)이며, 이 중 더 적은 연산을 수행하는 값이 M[1][3]이 된다.

M[1][3] 값을 계산하기 위해 앞서 구한 M[1][2], M[2][3] 값들이 이용된다. M[2][4], M[3][5], M[4][6] 값들 역시 같은 방법으로 계산해준다.

M[1][3] = minimum(M[1][k] + M[k+1][3] + d0dkd3) // (1 ≤ k ≤ 2)
        = minimum(M[1][1] + M[2][3] + d0d1d3,   // ( A1(A2A3) )
                  M[1][2] + M[3][3] + d0d2d3)   // ( (A1A2)A3 )
        = minimum(0 + 24 + 5 × 2 × 4,
                  30 + 0 + 5 × 3 × 4) = 64.

 

Compute Diagonal 3: M[1][4]는 네 개의 행렬을 곱할 때의 연산횟수를 계산한 값이다. 앞서 구한 M[1][2], M[2][4], …, M[1][3] 등이 계산에 이용된다. 값을 재계산하지 않고 찾아서 재사용하는 것이 동적계획법의 특징이다. M[2][5] and M[3][6] 값들 역시 같은 방법으로 계산한다.

M[1][4] = minimum(M[1][k] + M[k+1][4] + d0dkd4) // (1 ≤ k ≤ 3)
        = minimum(M[1][1] + M[2][4] + d0d1d4,
                  M[1][2] + M[3][4] + d0d2d4,
                  M[1][3] + M[4][4] + d0d3d4)
        = minimum(0 + 72 + 5 × 2 × 6,
                  30 + 72 + 5 × 3 × 6,
                  64 + 0 + 5 × 4 × 6) = 132.

 

Compute Diagonal 4 and 5: diagonal 4와 5 둘다 위의 과정을 반복해주면 된다. 예제의 경우 diagonal 5의 계산이 끝나면 최소한의 연쇄행렬곱셈의 결과값 M[1][6] = 348 을 구할 수 있다. 

The Optimal Order is.. (A1((((A2A3)A4)A5)A6)) = 348.

 

Pseudo Code

  • Chained Matrix Multiplication from Godbole (1973)
int minmult(int n, const int d[ ], index p[ ][ ])
{
  index i, j, k , diagonal;
  int M[1...n][1...n];

  for (i = 1; i <= n; i++)
    M[i][i] = 0;

  for (diagonal = 1; diagonal <= n-1; diagonal++)
    for (i = 1; i <= n-diagonal; i++)
    {
      j = i + diagonal;
      M[i][j] = minimum(M[i][k] + M[k+1][j] + d[i-1]*d[k]*d[j]);
          i <= k <= j-1
      P[i][j] = a value of k that gave the minimum;
    }
  return M[1][n];
}

 

Source Code

  • minmult.h
// File: minmult.h
#ifndef CHAINED_MATRIX_MULTI_H
#define CHAINED_MATRIX_MULTI_H
#include <iostream>

namespace algorithms
{
  int minmult(int n, const int *d, int **P);
  // Problem: Determining the minimum number of elementary multiplications
  // needed to multiply n matrices and an order that produces that minimum
  // number.
  // Inputs: the number of matrices n, and an array of integers d, indexed
  // from 0 to n, where d[i-1] * d[i] is the dimension of the ith matrix.
  // Outputs: minmult, the minimum number of elementary multiplications
  // need to multiply the n matrices; a two-dimensional array P from which
  // the optimal order can be obtained. P has its rows indexed from 1
  // to n-1 and its columns indexed from 1 to n. P[i][j] is the point
  // where matrices i through j are split in an optimal order for
  // multiplying the matrices.

  void print_order(int i, int j, int **P);
  // Problem: Print the optimal order for multiplying n matrices.
  // Inputs: Positive integer n, and the array P produced by Algorithm 3.6.
  // P[i][j] is the point where matrices i through j are split in an optimal
  // order for multiplying those matrices.
  // Outputs: the optimal order for multiplying the matrices.

  template <typename Item>
  void print_matrix(Item **data, const int m, const int n);

  template <typename Item>
  Item **get_matrix_space(const int m, const int n)
  // Postcondition: Return the array containing m*n spaces
  {
    Item **a;
    a = new Item *[m];
    --a; // Offset the pointer to get row index from 1 to m
    for (int i = 1; i <= m; ++i)
    {
      a[i] = new Item[n];
      --a[i];
    }

    // Initialize the matrix
    for (int i = 1; i <= m; ++i)
      for (int j = 1; j <= n; ++j)
        a[i][j] = Item();

    return a;
  }

  template <typename Item>
  void release_matrix_space(Item **d, int n)
  {
    for (int i = 1; i <= n; ++i)
      delete[](d[i] + 1);
    delete (d + 1);
  }
} // namespace algorithms

#endif

 

  • minmult.cpp
// File: minmult.cpp
#include <iostream>
#include <climits> // Provides INT_MAX
#include <iomanip> // Provides setw
#include "minmult.h"
using namespace std;

namespace algorithms
{
  int minmult(int n, const int* d, int** P)
  {
    int i, j, k, diagonal;
    int** M = get_matrix_space<int>(n, n);

    for (i = 1; i <= n; ++i)
      M[i][i] = 0;

    for (diagonal = 1; diagonal <= n-1; ++diagonal)
    {
      for (i = 1; i <= n-diagonal; ++i)
      {
        j = i + diagonal;
        int minimum = INT_MAX;
        for (k = i; k <= j-1; ++k)
        {
          if ((M[i][k]+M[k+1][j] + d[i-1]*d[k]*d[j]) < minimum)
          {
            M[i][j] = M[i][k] + M[k+1][j] + d[i-1] * d[k] * d[j];
            minimum = M[i][k] + M[k+1][j] + d[i-1] * d[k] * d[j];
            P[i][j] = k; // a value of k that gave minimum
          }
        }
      }
    }

    print_matrix(M, n, n);
    return M[1][n];
  }

  void print_order(int i, int j, int** P)
  {
    int k;

    if (i == j)
      cout << "A" << i;
    else
    {
      k = P[i][j];
      cout << "(";
      print_order(i, k, P);
      print_order(k+1, j, P);
      cout << ")";
    }
  }

  template <typename Item>
    void print_matrix(Item **data, const int m, const int n)
    {
        // Print matrix's index
        cout << "index";
        for (int i = 1; i <= m; ++i)
            cout << setw(7) << i;
        cout << endl
            << "     ___________________________________________" << endl;
        // Print matrix's data
        for (int i = 1; i <= m; ++i)
        {
            cout << "  " << i << " |";
            for (int j = 1; j <= n; ++j)
                cout << setw(7) << data[i][j];
            cout << endl;
        }
        cout << endl;
    }
} // namespace algorithms

 

  • minmulttest.cpp
// File: minmulttest.cpp
#include <iostream>
#include "minmult.h"
using namespace std;
using namespace algorithms;

int main( )
{
  const int NUM_OF_MATRICES = 5; // A1, A2, A3, A4, A5, A6
  int* d;
  int** P;

  d = new int[NUM_OF_MATRICES]; // Do NOT need for offset
  d[0] = 10;
  d[1] = 4;
  d[2] = 5;
  d[3] = 20;
  d[4] = 2;
  d[5] = 50;

  P = get_matrix_space<int>(NUM_OF_MATRICES, NUM_OF_MATRICES);

  minmult(NUM_OF_MATRICES, d, P); // Minimum multiplications
  print_matrix(P, NUM_OF_MATRICES, NUM_OF_MATRICES);

  cout << "The Optimal Order is.. ";
  print_order(1, NUM_OF_MATRICES, P); // Print optimal order
  cout << endl;

  delete d;
  release_matrix_space(P, NUM_OF_MATRICES);
  return EXIT_SUCCESS;
}

 

Time Complexity Analysis


Basic operation

The instructions executed for each value of k.

 

Input size

n, the number of matrices to be multiplied.

 

Every-Case Time Complexity

$\displaystyle T(n) = \sum_{diagonal=1}^{n-1}[(n-diagonal) \times diagonal] = \frac{n(n-1)(n+1)}{6} \in \Theta(n^3)$

 

구분 수행 조건 수행 횟수
diagonal루프 수행 횟수 1 to n - 1 n - 1
i-루프 수행 횟수 1 to n - diagonal n - diagonal
j-루프 수행 횟수 i to j - 1 (j - 1) - i + 1 = (i + diagonal -1) -i + 1 = diagonal
※ j = i + diagonal

 

The bruth-force Time Complexity

n 개의 행렬을 곱하는 경우의 수는 $t_{n} \ge 2^{(n-2)}$ 이므로, 무작정 방법으로 연쇄행렬 곱셈의 최적의 순서를 찾는다면 그 시간복잡도는 exponential-time과 같다.

 

두 개의 행렬을 곱하는 경우의 수 = $t_{2}$ = 1.

AB

 

세 개의 행렬을 곱하는 경우의 수 = $t_{3}$ = 2.

 (AB)C, A(BC)

 

네 개의 행렬을 곱하는 경우의 수 = $t_{4}$ = 5.

((AB)C)D, (A(BC))D, A((BC)D), A(B(CD)), (AB)(CD)

 

n개의 행렬을 곱하는 경우의 수 = $t_{n} \ge 2^{(n-2)}$

 

Other Algorithms Time Complexity

Θ(n3) – Godbole (1973)

Θ(n2) – Yao (1982)

(n lg n) – Hu and Shing (1982, 1984)

 

 

Principle of Optimality


Chained Matrix Multiplication problem is an optimization problem. Therefore, the optimal solution to the instance contains optimal solutions to all subinstances, and the principle of optimality applies.

 

🔗 Dynamic Programming and Optimization Problems(동적계획법과 최적화 문제)

 

 

Exercises


Find the optimal order, and its cost, for evaluating the product A1 × A2 × A3 × A4 × A5, where

 

$$A_1  \quad\times\quad  A_2 \quad\times\quad  A_3 \quad\times\quad A_4  \quad\times\quad  A_5 \\(10 \times 4) \quad (4 \times 5) \quad (5 \times 20) \quad (20 \times 2) \quad (2 \times 50)$$

 

Show the final matrices M and P produced by our Minimum Multiplications algorithm.

 

My Answer

  • matrices M and P
/* matrix M */
index      1      2      3      4      5
     _____________________________________
  1 |      0    200   1200    320   1320
  2 |      0      0    400    240    640
  3 |      0      0      0    200    700
  4 |      0      0      0      0   2000
  5 |      0      0      0      0      0

/* matrix P */
index      1      2      3      4      5
     _____________________________________
  1 |      0      1      1      1      4
  2 |      0      0      2      2      4
  3 |      0      0      0      3      4
  4 |      0      0      0      0      4
  5 |      0      0      0      0      0

The Optimal Order is.. ((A1(A2(A3A4)))A5)

'Algorithms > Dynamic Programming' 카테고리의 다른 글

Optimal Binary Search Trees(최적이진탐색트리)  (4) 2011.01.14
Floyd's Algorithm for Shortest Paths(플로이드 알고리즘)  (0) 2011.01.12
Binomial Coefficient(이항계수)  (0) 2011.01.11
Dynamic Programming(동적계획법)  (0) 2011.01.10
'Algorithms/Dynamic Programming' 카테고리의 다른 글
  • Optimal Binary Search Trees(최적이진탐색트리)
  • Floyd's Algorithm for Shortest Paths(플로이드 알고리즘)
  • Binomial Coefficient(이항계수)
  • Dynamic Programming(동적계획법)
Zakarum
Zakarum
  • Zakarum
    Zakr. _archives
    Zakarum
  • 전체
    오늘
    어제
    • Zakarum
      • Cogito, ergo sum
      • Algorithms
        • Eff, Anal, and Order
        • Divide-and-Conquer
        • Dynamic Programming
        • The Greedy Approach
        • Backtracking
        • Branch-and-Bound
      • Et Cetera
        • Job-seeking
      • Not Public
        • MBA
        • Finance
        • 2.3. Civil•Commercial Law
        • 2.2. Credit Analysis (Basic..
        • 2.4. Foreign Exchange
        • 2.1. Accounting Principles ..
        • ITSM
        • Theory of NP
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 글쓰기
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    민상법기초1
    네트워크
    회계원리기초2
    동적계획법
    탐욕 알고리즘
    외국환
    미국여행
    p-np problem
    대만여행
    process management
    자바스크립트
    알고리즘
    SNU MBA
    백트래킹
    process scheduling
    ITIL
    재무회계
    분기한정법
    분할정복법
    금융IT 채용정보
    신용분석기초
    일본여행
    베트남여행
    민상법기초3
    이탈리아여행
    회계원리기초1
    소프트웨어공학
    0-1 배낭 문제
    os concept
    최소신장트리
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
Zakarum
Chained Matrix Multiplication(연쇄행렬곱셈)
상단으로

티스토리툴바