【问题标题】:How to reference sub-matrices within a matrix如何引用矩阵中的子矩阵
【发布时间】:2010-12-06 14:42:52
【问题描述】:

我有一个 nxn 矩阵 A,其中 n 是 2 的幂。矩阵 A 分为 4 个大小相等的子矩阵。如何在 java 中引用子矩阵 A11、A12、A21 和 A22 的矩阵?我正在尝试分而治之的矩阵乘法算法 (Strassen)

            A11 | A12
   A -->    ---------
            A21 | A22

编辑:矩阵存储为整数数组:int[][]。

【问题讨论】:

  • 你的矩阵是如何存储的?多维数组,还是某个专门的类?
  • 不知道它是如何存储的,我们帮不了你。
  • 请在此处查看我的答案 - stackoverflow.com/questions/4358591/…

标签: java


【解决方案1】:

好吧,如果 ij 是您的索引,那么在 i = 0..(n/2)-1, j = 0..(n/2)-1 时获得 A11。 然后,A12 是 i = 0..(n/2)-1 和 j = n/2..n-1 等等。

要“引用”它们,您只需要一个“i_min, i_max, j_min, j_max”,而不是从 0 到 n-1 运行索引,而是从 min 到 max 运行它们。

【讨论】:

  • 如何将子矩阵的引用传递给方法。在 C++ 中,我可以分配正确的地址并将其存储在指向数组的指针中。我可以将此指针传递给方法。
  • 由于数组是通过引用传递的,您可以将矩阵本身与定义元素边界的 4 个整数一起传递。或者您使用一些允许“切片”的高级矩阵库。
【解决方案2】:

这是Strassen algorithm for matrix multiplication的一个实现

import java.io.*;

public class MatrixMultiplication {

    public static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    public MatrixMultiplication() throws IOException {
        int n;
        int[][] a, b;

        System.out.print("Enter the number for rows/colums: ");
        n = Integer.parseInt(br.readLine());

        a = new int[n][n];
        b = new int[n][n];  

        System.out.print("\n\n\nEnter the values for the first matrix:\n\n");
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                System.out.print("Enter the value for cell("+(i+1)+","+(j+1)+"): ");
                a[i][j] = Integer.parseInt(br.readLine());
            }
        }
        System.out.print("\n\n\nEnter the values for the second matrix:\n");
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                System.out.print("Enter the value for cell ("+(i+1)+","+(j+1)+"): ");
                b[i][j] = Integer.parseInt(br.readLine());
            }
        }

        System.out.print("\n\nMatrix multiplication using standard method:\n");
        print(multiplyWithStandard(a, b));  

        System.out.print("\n\nMatrix multiplication using Strassen method:\n");
        print(multiplyWithStandard(a, b));  
    }

    public int[][] multiplyWithStandard(int[][] a, int[][] b) {
        int n = a.length;
        int[][] c = new int[n][n];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                for (int k = 0; k < n; k++) {
                    c[i][j] += a[i][k] * b[k][j];
                } 
            }
        }
        return c;
    }

    public int[][] multiplyWithStrassen(int [][] A, int [][] B) {
        int n = A.length;
        int [][] result = new int[n][n];

        if (n == 1) {
            result[0][0] = A[0][0] * B[0][0];
        } else if ((n%2 != 0 ) && (n != 1)) {
            int[][] a1, b1, c1;
            int n1 = n+1;
            a1 = new int[n1][n1];
            b1 = new int[n1][n1];
            c1 = new int[n1][n1];

            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    a1[i][j] = A[i][j];
                    b1[i][j] = B[i][j];
                }
            } 
            c1 = multiplyWithStrassen(a1, b1);   
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    result[i][j] = c1[i][j];
                }
            }   
        } else {
            int [][] A11 = new int[n/2][n/2];
            int [][] A12 = new int[n/2][n/2];
            int [][] A21 = new int[n/2][n/2];
            int [][] A22 = new int[n/2][n/2];

            int [][] B11 = new int[n/2][n/2];
            int [][] B12 = new int[n/2][n/2];
            int [][] B21 = new int[n/2][n/2];
            int [][] B22 = new int[n/2][n/2];

            divideArray(A, A11, 0 , 0);
            divideArray(A, A12, 0 , n/2);
            divideArray(A, A21, n/2, 0);
            divideArray(A, A22, n/2, n/2);

            divideArray(B, B11, 0 , 0);
            divideArray(B, B12, 0 , n/2);
            divideArray(B, B21, n/2, 0);
            divideArray(B, B22, n/2, n/2);

            int [][] M1 = multiplyWithStrassen(add(A11, A22), add(B11, B22));
            int [][] M2 = multiplyWithStrassen(add(A21, A22), B11);
            int [][] M3 = multiplyWithStrassen(A11, subtract(B12, B22));
            int [][] M4 = multiplyWithStrassen(A22, subtract(B21, B11));
            int [][] M5 = multiplyWithStrassen(add(A11, A12), B22);
            int [][] M6 = multiplyWithStrassen(subtract(A21, A11), add(B11, B12));
            int [][] M7 = multiplyWithStrassen(subtract(A12, A22), add(B21, B22));

            int [][] C11 = add(subtract(add(M1, M4), M5), M7);
            int [][] C12 = add(M3, M5);
            int [][] C21 = add(M2, M4);
            int [][] C22 = add(subtract(add(M1, M3), M2), M6);

            copyArray(C11, result, 0 , 0);
            copyArray(C12, result, 0 , n/2);
            copyArray(C21, result, n/2, 0);
            copyArray(C22, result, n/2, n/2);
        }
        return result;
    }

    public int[][] add(int [][] A, int [][] B) {
        int n = A.length;  
        int [][] result = new int[n][n]; 

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++)
                result[i][j] = A[i][j] + B[i][j];
            }   
        return result;
    }

    public int[][] subtract(int [][] A, int [][] B) {
        int n = A.length;
        int [][] result = new int[n][n];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                result[i][j] = A[i][j] - B[i][j];
            }  
        }    
        return result;
    }

    private void divideArray(int[][] parent, int[][] child, int iB, int jB) {
        for (int i1 = 0, i2 = iB; i1 < child.length; i1++, i2++) {
            for (int j1 = 0, j2 = jB; j1 < child.length; j1++, j2++) {
                child[i1][j1] = parent[i2][j2];
            }
        }
    }

    private void copyArray(int[][] child, int[][] parent, int iB, int jB) {
        for(int i1 = 0, i2 = iB; i1 < child.length; i1++, i2++) {
            for(int j1 = 0, j2 = jB; j1 < child.length; j1++, j2++) {
                parent[i2][j2] = child[i1][j1];
            }
        }
    }

    public void print(int [][] array) {
        int n = array.length;  

        System.out.println();  
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                System.out.print(array[i][j] + "\t");
            }
            System.out.println();
        }
        System.out.println();
    }

    public static void main(String[] args) throws IOException {
        new MatrixMultiplication();
    }
} 

【讨论】:

    【解决方案3】:

    我认为您必须决定是每次复制每个子矩阵的内容还是对寻址进行算术运算。您的问题意味着您的子矩阵是连续的而不是拆分的(如在计算带有次要和辅因子的决定因素时 - http://mathworld.wolfram.com/Determinant.html)。由于您没有说明为什么要这样做,您已经遇到了哪些性能问题,以及是否存在对较小矩阵的递归,我认为只有您才能决定复制的简单性或复杂性之间的平衡递归寻址。但我希望已经有图书馆,我会检查http://commons.apache.org/math/

    【讨论】:

      猜你喜欢
      • 2018-05-12
      • 2015-05-17
      • 1970-01-01
      • 2016-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-20
      • 1970-01-01
      相关资源
      最近更新 更多