Fortran 求所有可能的半正定整数,其加权和等于某个整数
我对fortran 90代码有问题。所以,我有Fortran 求所有可能的半正定整数,其加权和等于某个整数,fortran,integer-arithmetic,Fortran,Integer Arithmetic,我对fortran 90代码有问题。所以,我有n+1半正定整数k1,k2,k3千牛和千牛。现在,对于给定的n,我需要找到k1、k2、k3、千牛这样k1+2*k2+3*k3+…+n*kn=n。有人可能会考虑使用一个n级嵌套循环,每个循环从0运行到n,但实际上我将把这个代码放在一个子例程中,n(也就是说,k的数量)将作为这个子例程的输入。因此,如果我要使用嵌套循环,那么嵌套级别的数量应该是自动化的,我认为这在Fortran中很难做到(如果不是不可能的话)。有更好的方法解决这个问题吗?如果n非常小(比
n+1
半正定整数k1
,k2
,k3
<代码>千牛和<代码>千牛。现在,对于给定的n
,我需要找到k1
、k2
、k3
、<代码>千牛这样k1+2*k2+3*k3+…+n*kn=n
。有人可能会考虑使用一个n级嵌套循环,每个循环从0
运行到n
,但实际上我将把这个代码放在一个子例程中,n
(也就是说,k
的数量)将作为这个子例程的输入。因此,如果我要使用嵌套循环,那么嵌套级别的数量应该是自动化的,我认为这在Fortran中很难做到(如果不是不可能的话)。有更好的方法解决这个问题吗?如果n
非常小(比如,5),我认为编写多维循环以获得满足k1+k2*2+…+的所需k向量(k1,k2,…,kn)更简单kn*n=n。否则,可以选择使用递归。示例代码可能如下所示(请注意,我们需要recursive
关键字):
这里,我们可以看到,例如,对于n=4,kvec=[k1,k2,k3,k4]=[2,1,0,0]满足k1+k2*2+k3*3+k4*4=2+1*2+0+0=4
。使用这些k向量,我们可以计算f(g(x))的n阶导数(如OP所述,如下所示)
为了了解递归是如何工作的,插入大量代码通常很有用 打印语句并监控变量的变化。例如,代码的“详细”版本可能如下所示(为了简单起见,我删除了早期拒绝的内容): 请注意,数组
kvec
和kvelist
的值总是在递归调用进入和退出时保留。特别是,我们正在覆盖每个维度的kvec
元素,以获得可能模式的完整列表(因此本质上相当于多维循环)。我们还注意到,kvec
的值仅在最终递归级别(即,ind=n
)有效
另一种方法是将递归调用重写为特定
n
的等效非递归调用。例如,n=2的情况可以如下重写。这不依赖于递归,而是执行与上述代码相同的操作(对于n=2
)。如果我们设想将recur\u sub2
内联到recur\u sub
,很明显这些例程相当于k1
和k2
上的二维循环
!! routine specific for n = 2
subroutine recur_sub( n, ind, kvec, kveclist, nvec )
integer, intent(in) :: n, ind
integer, intent(inout) :: kvec(:), kveclist(:,:), nvec
integer k1
!! now ind == 1
do k1 = 0, n
kvec( ind ) = k1
call recur_sub2( n, ind + 1, kvec, kveclist, nvec ) !! go to next index
enddo
endsubroutine
!! routine specific for n = 2
subroutine recur_sub2( n, ind, kvec, kveclist, nvec )
integer, intent(in) :: n, ind
integer, intent(inout) :: kvec(:), kveclist(:,:), nvec
integer k2, ksum, t
!! now ind == n == 2
do k2 = 0, n
kvec( ind ) = k2
ksum = sum( [( kvec( t ) * t, t = 1, n )] )
if ( ksum == 2 ) then
nvec = nvec + 1
if ( nvec > nvecmax ) stop "nvecmax too small"
kveclist( :, nvec ) = kvec(:) !! save k-vectors
endif
enddo
endsubroutine
附录
下面是f(g(x))的第n阶导数的“漂亮打印”例程(在Julia中)(只是为了好玩)。如有必要,请使用Fortran编写相应的例程(但请注意大n!)
如果n
相当小(比如,5),我认为编写多维循环以获得满足k1+k2*2+…+的所需k向量(k1,k2,…,kn)更简单kn*n=n。否则,可以选择使用递归。示例代码可能如下所示(请注意,我们需要recursive
关键字):
这里,我们可以看到,例如,对于n=4,kvec=[k1,k2,k3,k4]=[2,1,0,0]
满足k1+k2*2+k3*3+k4*4=2+1*2+0+0=4
。使用这些k向量,我们可以计算f(g(x))的n阶导数(如OP所述,如下所示)
为了了解递归是如何工作的,插入大量代码通常很有用 打印语句并监控变量的变化。例如,代码的“详细”版本可能如下所示(为了简单起见,我删除了早期拒绝的内容): 请注意,数组
kvec
和kvelist
的值总是在递归调用进入和退出时保留。特别是,我们正在覆盖每个维度的kvec
元素,以获得可能模式的完整列表(因此本质上相当于多维循环)。我们还注意到,kvec
的值仅在最终递归级别(即,ind=n
)有效
另一种方法是将递归调用重写为特定
n
的等效非递归调用。例如,n=2的情况可以如下重写。这不依赖于递归,而是执行与上述代码相同的操作(对于n=2
)。如果我们设想将recur\u sub2
内联到recur\u sub
,很明显这些例程相当于k1
和k2
上的二维循环
!! routine specific for n = 2
subroutine recur_sub( n, ind, kvec, kveclist, nvec )
integer, intent(in) :: n, ind
integer, intent(inout) :: kvec(:), kveclist(:,:), nvec
integer k1
!! now ind == 1
do k1 = 0, n
kvec( ind ) = k1
call recur_sub2( n, ind + 1, kvec, kveclist, nvec ) !! go to next index
enddo
endsubroutine
!! routine specific for n = 2
subroutine recur_sub2( n, ind, kvec, kveclist, nvec )
integer, intent(in) :: n, ind
integer, intent(inout) :: kvec(:), kveclist(:,:), nvec
integer k2, ksum, t
!! now ind == n == 2
do k2 = 0, n
kvec( ind ) = k2
ksum = sum( [( kvec( t ) * t, t = 1, n )] )
if ( ksum == 2 ) then
nvec = nvec + 1
if ( nvec > nvecmax ) stop "nvecmax too small"
kveclist( :, nvec ) = kvec(:) !! save k-vectors
endif
enddo
endsubroutine
附录
下面是f(g(x))的第n阶导数的“漂亮打印”例程(在Julia中)(只是为了好玩)。如有必要,请使用Fortran编写相应的例程(但请注意大n!)
它也可以这样表述,但主要问题是让Fortran找到满足上述要求的所有可能的ki
组合。这要么是拖拉,要么是作业。如果不是,你能解释一下你想做什么以及为什么吗?这既不是拖拉也不是家庭作业。我实际上在用所谓的Faa-di-Bruno公式计算函数f(g(x))对x的任意阶导数。如果你看一下表中的等式(1),你就会明白为什么我需要做我在帖子中解释的事情。但是为什么-不是什么?不管怎样,如果你是认真的,那就看看哪种方法可能是正确的。对于我的研究来说。它也可以这样表述,但主要的问题是让Fortran找到满足上述要求的所有可能的ki
。这要么是trolling
recursive subroutine recur_sub( n, ind, kvec, kveclist, nvec )
integer, intent(in) :: n, ind
integer, intent(inout) :: kvec(:), kveclist(:,:), nvec
integer k, ksum, t, ind_next
print *, "Top of recur_sub: ind = ", ind
do k = 0, n
kvec( ind ) = k
print *, "ind = ", ind, " k = ", k, "kvec = ", kvec
if ( ind < n ) then
ind_next = ind + 1
print *, " > now going to the next level"
call recur_sub( n, ind_next, kvec, kveclist, nvec )
print *, " > returned to the current level"
endif
if ( ind == n ) then
ksum = sum( [( kvec( t ) * t, t = 1, n )] )
if ( ksum == n ) then
nvec = nvec + 1
if ( nvec > nvecmax ) stop "nvecmax too small"
kveclist( :, nvec ) = kvec(:)
endif
endif
enddo
print *, "Exiting recur_sub"
endsubroutine
Top of recur_sub: ind = 1
ind = 1 k = 0 kvec = 0 0
> now going to the next level
Top of recur_sub: ind = 2
ind = 2 k = 0 kvec = 0 0
ind = 2 k = 1 kvec = 0 1
ind = 2 k = 2 kvec = 0 2
Exiting recur_sub
> returned to the current level
ind = 1 k = 1 kvec = 1 2
> now going to the next level
Top of recur_sub: ind = 2
ind = 2 k = 0 kvec = 1 0
ind = 2 k = 1 kvec = 1 1
ind = 2 k = 2 kvec = 1 2
Exiting recur_sub
> returned to the current level
ind = 1 k = 2 kvec = 2 2
> now going to the next level
Top of recur_sub: ind = 2
ind = 2 k = 0 kvec = 2 0
ind = 2 k = 1 kvec = 2 1
ind = 2 k = 2 kvec = 2 2
Exiting recur_sub
> returned to the current level
Exiting recur_sub
For n = 2
kvec = 0 1
kvec = 2 0
!! routine specific for n = 2
subroutine recur_sub( n, ind, kvec, kveclist, nvec )
integer, intent(in) :: n, ind
integer, intent(inout) :: kvec(:), kveclist(:,:), nvec
integer k1
!! now ind == 1
do k1 = 0, n
kvec( ind ) = k1
call recur_sub2( n, ind + 1, kvec, kveclist, nvec ) !! go to next index
enddo
endsubroutine
!! routine specific for n = 2
subroutine recur_sub2( n, ind, kvec, kveclist, nvec )
integer, intent(in) :: n, ind
integer, intent(inout) :: kvec(:), kveclist(:,:), nvec
integer k2, ksum, t
!! now ind == n == 2
do k2 = 0, n
kvec( ind ) = k2
ksum = sum( [( kvec( t ) * t, t = 1, n )] )
if ( ksum == 2 ) then
nvec = nvec + 1
if ( nvec > nvecmax ) stop "nvecmax too small"
kveclist( :, nvec ) = kvec(:) !! save k-vectors
endif
enddo
endsubroutine
function recur_main( n )
kvec = zeros( Int, n ) # [k1,k2,...,kn] (work vector)
kveclist = Vector{Int}[] # list of k-vectors (output)
recur_sub( n, 1, kvec, kveclist ) # now entering recursion over {ki}...
return kveclist
end
function recur_sub( n, i, kvec, kveclist )
for ki = 0 : n
kvec[ i ] = ki
ksum = sum( kvec[ t ] * t for t = 1:i ) # k1 + k2*2 + ... + ki*i
ksum > n && continue # early rejection
if i < n
recur_sub( n, i + 1, kvec, kveclist ) # go to the next index
end
if i == n && ksum == n
push!( kveclist, copy( kvec ) ) # save k-vectors
end
end
end
function showderiv( n )
kveclist = recur_main( n )
println()
println( "(f(g))_$(n) = " )
fact( k ) = factorial( big(k) )
for (term, kvec) in enumerate( kveclist )
fac1 = div( fact( n ), prod( fact( kvec[ i ] ) for i = 1:n ) )
fac2 = prod( fact( i )^kvec[ i ] for i = 1:n )
coeff = div( fac1, fac2 )
term == 1 ? print( " " ) : print( " + " )
coeff == 1 ? print( " " ^ 15 ) : @printf( "%15i", coeff )
print( " (f$( sum( kvec ) ))" )
for i = 1 : length( kvec )
ki = kvec[ i ]
if ki > 0
print( "(g$( i ))" )
ki > 1 && print( "^$( ki )" )
end
end
println()
end
end
#--- test ---
if false
for n = 1 : 4
kveclist = recur_main( n )
println( "\nFor n = ", n )
for kvec in kveclist
println( "kvec = ", kvec )
end
end
end
showderiv( 1 )
showderiv( 2 )
showderiv( 3 )
showderiv( 4 )
showderiv( 5 )
showderiv( 8 )
showderiv( 10 )
(f(g))_1 =
(f1)(g1)
(f(g))_2 =
(f1)(g2)
+ (f2)(g1)^2
(f(g))_3 =
(f1)(g3)
+ 3 (f2)(g1)(g2)
+ (f3)(g1)^3
(f(g))_4 =
(f1)(g4)
+ 3 (f2)(g2)^2
+ 4 (f2)(g1)(g3)
+ 6 (f3)(g1)^2(g2)
+ (f4)(g1)^4
(f(g))_5 =
(f1)(g5)
+ 10 (f2)(g2)(g3)
+ 5 (f2)(g1)(g4)
+ 15 (f3)(g1)(g2)^2
+ 10 (f3)(g1)^2(g3)
+ 10 (f4)(g1)^3(g2)
+ (f5)(g1)^5
(f(g))_8 =
(f1)(g8)
+ 35 (f2)(g4)^2
+ 56 (f2)(g3)(g5)
+ 28 (f2)(g2)(g6)
+ 280 (f3)(g2)(g3)^2
+ 210 (f3)(g2)^2(g4)
+ 105 (f4)(g2)^4
+ 8 (f2)(g1)(g7)
+ 280 (f3)(g1)(g3)(g4)
+ 168 (f3)(g1)(g2)(g5)
+ 840 (f4)(g1)(g2)^2(g3)
+ 28 (f3)(g1)^2(g6)
+ 280 (f4)(g1)^2(g3)^2
+ 420 (f4)(g1)^2(g2)(g4)
+ 420 (f5)(g1)^2(g2)^3
+ 56 (f4)(g1)^3(g5)
+ 560 (f5)(g1)^3(g2)(g3)
+ 70 (f5)(g1)^4(g4)
+ 210 (f6)(g1)^4(g2)^2
+ 56 (f6)(g1)^5(g3)
+ 28 (f7)(g1)^6(g2)
+ (f8)(g1)^8
(f(g))_10 =
(f1)(g10)
+ 126 (f2)(g5)^2
+ 210 (f2)(g4)(g6)
+ 120 (f2)(g3)(g7)
+ 2100 (f3)(g3)^2(g4)
+ 45 (f2)(g2)(g8)
+ 1575 (f3)(g2)(g4)^2
+ 2520 (f3)(g2)(g3)(g5)
+ 630 (f3)(g2)^2(g6)
+ 6300 (f4)(g2)^2(g3)^2
+ 3150 (f4)(g2)^3(g4)
+ 945 (f5)(g2)^5
+ 10 (f2)(g1)(g9)
+ 1260 (f3)(g1)(g4)(g5)
+ 840 (f3)(g1)(g3)(g6)
+ 2800 (f4)(g1)(g3)^3
+ 360 (f3)(g1)(g2)(g7)
+ 12600 (f4)(g1)(g2)(g3)(g4)
+ 3780 (f4)(g1)(g2)^2(g5)
+ 12600 (f5)(g1)(g2)^3(g3)
+ 45 (f3)(g1)^2(g8)
+ 1575 (f4)(g1)^2(g4)^2
+ 2520 (f4)(g1)^2(g3)(g5)
+ 1260 (f4)(g1)^2(g2)(g6)
+ 12600 (f5)(g1)^2(g2)(g3)^2
+ 9450 (f5)(g1)^2(g2)^2(g4)
+ 4725 (f6)(g1)^2(g2)^4
+ 120 (f4)(g1)^3(g7)
+ 4200 (f5)(g1)^3(g3)(g4)
+ 2520 (f5)(g1)^3(g2)(g5)
+ 12600 (f6)(g1)^3(g2)^2(g3)
+ 210 (f5)(g1)^4(g6)
+ 2100 (f6)(g1)^4(g3)^2
+ 3150 (f6)(g1)^4(g2)(g4)
+ 3150 (f7)(g1)^4(g2)^3
+ 252 (f6)(g1)^5(g5)
+ 2520 (f7)(g1)^5(g2)(g3)
+ 210 (f7)(g1)^6(g4)
+ 630 (f8)(g1)^6(g2)^2
+ 120 (f8)(g1)^7(g3)
+ 45 (f9)(g1)^8(g2)
+ (f10)(g1)^10