Arrays 在这个Fortran算法中如何使用这些数组?

Arrays 在这个Fortran算法中如何使用这些数组?,arrays,algorithm,math,fortran,Arrays,Algorithm,Math,Fortran,我正在用Fortran90编写一些子程序来执行一些数值计算。但是,作为其中的一部分,我需要包含一些来自netlib模板库的代码,这些代码是用Fortran77编写的。我很难让它们工作——特别是理解数组的使用 例如,我需要使用一个名为GMRES的子程序。以下是论点: SUBROUTINE GMRES( N, B, X, RESTRT, WORK, LDW, WORK2, LDW2, $ ITER, RESID, MATVEC, PSOLVE, INFO )

我正在用Fortran90编写一些子程序来执行一些数值计算。但是,作为其中的一部分,我需要包含一些来自netlib模板库的代码,这些代码是用Fortran77编写的。我很难让它们工作——特别是理解数组的使用

例如,我需要使用一个名为GMRES的子程序。以下是论点:

  SUBROUTINE GMRES( N, B, X, RESTRT, WORK, LDW, WORK2, LDW2, 
 $                  ITER, RESID, MATVEC, PSOLVE, INFO )

*     .. Scalar Arguments ..
  INTEGER            N, RESTRT, LDW, LDW2, ITER, INFO
  DOUBLE PRECISION   RESID
*     ..
*     .. Array Arguments ..
  DOUBLE PRECISION   B( * ), X( * ), WORK( * ), WORK2( * )
*     ..
*     .. Function Arguments ..
*
  EXTERNAL           MATVEC, PSOLVE
*
*
*  Arguments
*  =========
*
*  N       (input) INTEGER. 
*          On entry, the dimension of the matrix.
*          Unchanged on exit.
* 
*  B       (input) DOUBLE PRECISION array, dimension N.
*          On entry, right hand side vector B.
*          Unchanged on exit.
*
*  X       (input/output) DOUBLE PRECISION array, dimension N.
*          On input, the initial guess; on exit, the iterated       solution.
*
*  RESTRT  (input) INTEGER
*          Restart parameter, <= N. This parameter controls the amount
*          of memory required for matrix WORK2.
*
*  WORK    (workspace) DOUBLE PRECISION array, dimension (LDW,5).
*          Note that if the initial guess is the zero vector, then 
*          storing the initial residual is not necessary.
*
*  LDW     (input) INTEGER
*          The leading dimension of the array WORK. LDW >= max(1,N).
*
*  WORK2   (workspace) DOUBLE PRECISION array, dimension     (LDW2,2*RESTRT+2).
*          This workspace is used for constructing and storing the
*          upper Hessenberg matrix. The two extra columns are used to
*          store the Givens rotation matrices.
*
*  LDW2    (input) INTEGER
*          The leading dimension of the array WORK2.
*          LDW2 >= max(1,RESTRT).
*
*  ITER    (input/output) INTEGER
*          On input, the maximum iterations to be performed.
*          On output, actual number of iterations performed.
*
*  RESID   (input/output) DOUBLE PRECISION
*          On input, the allowable error tolerance.
*          On ouput, the norm of the residual vector if solution
*          approximated to tolerance, otherwise reset to input
*          tolerance.
*
*  INFO    (output) INTEGER
*          =  0:  successful exit
*          =  1:  maximum number of iterations performed;
*                 convergence not achieved.
*
*  MATVEC  (external subroutine)
*          The user must provide a subroutine to perform the
*          matrix-vector product A*x = y.
*          Vector x must remain unchanged. The solution is
*          over-written on vector y.
*
*          The call is:
*
*             CALL MATVEC( X, Y )
那么,如果工作数组是二维的,上面的结果会不会导致秩不匹配呢?使用这样一个索引访问二维数组意味着什么?我应该将工作阵列定义为二维还是一维

编辑 GMRES例程需要提供matvec例程。在GMRES代码中,它被称为

CALL MATVEC(SCLR1, X, SCLR2, WORK(NDX2))
而且也喜欢

CALL MATVEC(SCLR1, WORK(NDX1), SCLR2, WORK(NDX2))
我试图提供的子程序MATVEC如下所示:

subroutine matvec(alpha, x, beta, y)

    real(dp), intent(in) :: alpha, beta
    real(dp), dimension(*), intent(in) :: x
    real(dp), dimension(*), intent(inout) :: y
    real(dp), dimension(*,*) :: A
    integer :: n

    call make_Jac(n,A)
    call dgemv('notranspose', n, n, alpha, A, n, x, 1, beta, y, 1)

end subroutine matvec
其中
make_Jac
返回我正在处理的问题的矩阵及其维数n。blas例程
dgemv
然后处理矩阵向量积。

WORK(*)
声明一个假定大小的数组,该数组可以是二维的。看

如果向子例程提供一维数组,编译器不会抱怨,但可能会发生奇怪的事情(包括分段错误)


更好地使用符合规范的阵列

相同的Fortran数组可以作为一维、二维等进行管理。在任何情况下,它都存储在连续内存中

假设你有

double precision x(3, 2)

call somefunc (x)
可以在somefunc中以y(6)的形式访问该函数

数组元素以“列主顺序”存储,这意味着

x(1, 1) is y(1)
x(2, 1) is y(2)
x(3, 1) is y(3)
x(1, 2) is y(4)
x(2, 2) is y(5)
x(3, 2) is y(6)
只要函数知道每个维度的限制,它就可以通过简单的算法计算线性访问。唉,这种“放松类型”也是常见的错误源。

更进一步,伪参数
work(*)
是一个排名1的假定大小数组。有这样一个阵列

有效参数和伪参数的等级和范围可能不同;伪参数仅假定有效参数的大小

这意味着对于这样的结构来说,它是完全可以接受的

double precision work(LDW,5)
call GMRES(..., work, ...)
! ...

end

subroutine GMRES(..., work, ...)
  double precision work(*)
  ! ...
end subroutine
实际上,将伪参数作为秩-1数组使用时,不允许将其作为秩-2数组引用。秩2假定大小的数组类似于

double precision work(LDW,*)
当然,在那里,
工作(ndx1)
是不好的

关于roygvib的评论,稍后在Netlib源代码中有一行

call GMRESREVCOM(..., work, ...)
其中该子例程具有伪参数

double precision work(LDW,*)
因此,可能有一种期望,即代码的用户最初会提供一个秩2的实际参数

所有这一切意味着,在
GMRES
中传递给
work
的实际参数的等级并不重要,只要它至少有
LDW*5
元素。不过,我会小心地将伪参数称为“任意长度”,因为引用
work(LDW*5+1)
(根据我的第一个示例)是错误的。虚拟数组的大小正好是传递的数组的大小

由于另一个原因,后面对
matvec
的调用并不麻烦。此子例程有四个参数,第一个和第三个是标量。第二个和第四个也是假定大小为秩1的数组。我们已经确定假定大小数组不关心有效/实际参数的秩,但是您可能想知道为什么可以将标量参数
work(ndx1)
传递给这个秩1数组

答案就是所谓的序列关联。这意味着,当实际参数是数组元素指示符且伪参数是数组伪参数时,则该伪参数是与实际参数中的元素序列关联的参数,从指定的元素开始

也就是说,在
matvec
中有一个类似于
[work(ndx1),work(ndx1+1),…]的秩1数组作为数组
x


只要您不试图引用超出实际参数范围的内容,这一切都很好。

这些数组实际上是作为
WORK(LDW,*)、WORK2(LDW2,*)从GMRES进一步传递到GMRESREVCOM的。
。如果在
GMRES
中将其更改为
WORK(LDW,*)、WORK2(LDW2,*)
,它仍然可以工作,但仅限于二维阵列。在您的Fortran教科书中查找序列关联。@VladimirF将GMRES()中的WORK和WORK2声明更改为2D假定大小声明是否有问题,因为它们已经在MATVEC()中使用,如上所述?(编译人员可能会抱怨。)是的,那会打破它,我错过了那一行。当然可以修改,但是没有理由这样做。我最初读到了你关于
WORK(NDX1)
的问题,而“仅仅一个索引”又是关于数组的秩。通过编辑,我现在认为您实际上对单个元素感到好奇,因此传递了一个标量。你能确认/澄清一下吗?在
matvec
中,你有
real(dp),维度(*,*)::A
。但是,
A
不是伪参数,因此此声明不合法:
A
不能是假定大小的数组;它不是命名常量,因此不能是隐含形状。你能检查一下你真的有这个吗?谢谢。但我发现自己遇到了一个新问题。GMRES例程需要一个名为MatVec的用户提供的例程。如果查看GMRES代码,它的调用类似于调用MatVec(scalar,Work(ndx1),scalar2,Work2(ndx2))
它要求MatVec函数为compute y=scalarAx+scalar2*y,其中y是一个向量。其他任何东西都会导致等级不匹配。然而,在代码中,MatVec是在非向量上被调用的。毫不奇怪,这会导致分割错误。在这一点上,我很想放弃,只是要求我的大学让我进入NAG图书馆
scalar1
scalar2
确实是标量,但是。。。虽然你可以这样做
double precision work(LDW,*)