【问题标题】:Finding n'th term in a (linear) recurrence relation using matrix exponentiation使用矩阵求幂查找(线性)递归关系中的第 n 项
【发布时间】:2021-06-30 00:51:12
【问题描述】:

我正在尝试编写(我认为是一段漂亮的代码)一个 Java 程序,该程序将通过以下方式通过有效的矩阵求幂找到递归定义序列的 n'th 项:

Given 是一个线性递归关系:

f(n) = c_1 * f(n-1) + c_2 * f(n-2)+ ... + c_k * f(n-k) = sum_{i=1}^k c_i * f(n-i)

已知整数系数C_k = c_{1<=i<=k} 和已知整数基本情况B_k = b_{1<=i<=k}

为了演示符号,对于众所周知的斐波那契数列,这变为C_2 = {1,1} 和基本情况B_2 = {1,1}f(n) = f(n-1) + f(n-2)

Java 方法将所需的术语索引n、mod m(因为术语增长得非常快)、系数数组C_k 和基本情况数组B_k 作为参数。该方法返回值f(n) mod m

类如下所示:

public class test2 {

public static void main(String[] args) 
{
    long n = 13;
    long m = 100000000L;
    long [] baseCases = {1,1};
    long [] coefficients = {1,1};
    long v = f(n , m , coefficients , baseCases);
    
    System.out.println(v);
}

public static long f (long n , long m , long [] coefficients , long [] baseCases) //main method, taking arguments of nth term, mod m , coefficients and base cases
{
    // generate the transformation matrix {c1, c2 , c3} , {1,0,0...} , {0,1,0,0...} , {0,0,1,0....}........
    int k = coefficients.length;
    long [][] M = new long [k][k];
    
    for (int i = 0 ; i < k ; i++)
        M[0][i] = coefficients[i];
    
    for (int i = 1 ; i < k ; i++)
    {
        for (int j = 0 ; j < k ; j++)
            M[i][j] = 0;
        M[i][i - 1] = 1;
    }
    
    // generate the "bases" matrix
    long [][] B = new long [baseCases.length][baseCases.length];
    for (int i = 0 ; i < baseCases.length ; i++)
        B[0][i] = baseCases[i];
    for (int i = 1 ; i < B.length ; i++)
        for (int j = 0 ; j < B[0].length ; j ++)
            B[i][j] = 0;
                
    long v = ME(B , M , n - k + 1 , m); //the matrix raised to the n-k+1 power would yield the nth term. for fibonacci, k = 2 , so n-1 exponentioation
    
    return v;
}

public static void mult (long M1 [][] , long M2 [][] , long m) //method to multiply 2 matrices
{
    int r = Math.max(M1.length, M2.length);
    int c = Math.max(M1[0].length, M2[0].length);
    int mulTemp[][] = new int[r][c]; //temporary matrix to store values
    
    for (int i = 0 ; i < r ; i++)
    {
        for (int j = 0 ; j < c ; j++)
        {
            mulTemp[i][j] = 0;
            for (int k = 0 ; k < r ; k++)
                mulTemp[i][j] += M1[i][k] * M2[k][j] % m;
        }
    }
    
    //transferring the values back to M1
    for (int i = 0 ; i < M1.length ; i++) 
        for (int j = 0 ; j < M1[0].length ; j++)
            M1[i][j] = mulTemp[i][j]; 
}
  
public static long ME (long B[][] , long M[][] , long n , long m) //method for fast matrix exponentiation 
{ 
    if (n == 1)
    {
        long s = 0;
        for (int i = 0 ; i < B[0].length ; i++)
            s += B[0][i];
        
        return s;
    }
  
    ME(B , M , n / 2 , m);
  
    mult(M  , M , m);
  
    if ((n & 1) != 0)
        mult(B , M , m);

    long s = 0;
    for (int i = 0 ; i < B[0].length ; i++)
        s += B[0][i];
    
    return s;
}

}

代码相对简洁明了,并根据需要进行了注释,但并没有达到预期的效果。例如,正如当前在 main 方法中编写的那样,我正在尝试用它生成斐波那契数列。斐波那契数确实生成了,但不是用各自的n 生成的(对于n=13,它给出5,它应该给出233,对于n=10,它给出89 而不是55)。

我认为我对矩阵方法的处理不当,而且我没有正确使用基本情况,我不确切知道如何在代码中使用它们。我认为我转换基本情况的方式有问题将cases数组放入B矩阵中。如果我正确理解理论,则转换矩阵的形式为:

c1 , c2 , c3 , c4....

 1  , 0  , 0  , 0 ....

 0  , 1  , 0  , 0 ....

 0  , 0  , 1  , 0 ....

......................

............... 1  , 0 

从那里开始,这是一个矩阵求幂的问题,使用中间的基本情况矩阵。

我想知道如何更改此代码以能够处理任何线性递推关系,使用我提到的已知给定(整数)参数,而不仅仅是斐波那契数列(我只在帖子,因为它是最容易理解和实施的)。我可以轻松查找 Fibonacci 矩阵求幂算法,但它并没有让我深入了解如何在算法中推广这个想法,尽管我认为数学很清楚。

我真正要问的是如何在代码中实现这个理论。

【问题讨论】:

    标签: java algorithm recursion matrix matrix-multiplication


    【解决方案1】:

    您的矩阵构造看起来不错。

    不过,我不知道您要如何处理基本情况。基本情况是一个向量。根本不应该有基本案例矩阵。

    矩阵 M 将连续样本的向量向前变换一步,因此 M*[f(n), f(n-1)...] = [f(n+1), f(n).. .]。基本情况向量就是 B=[f(k),f(k-1)...f(1)]

    要找到 f(n),其中 n>k,你只需得到 (M^(n-k)*B)[0]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-01
      • 2013-01-24
      • 2019-11-13
      • 2018-10-28
      相关资源
      最近更新 更多