Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
For loop 减少多个do循环计算和的计算时间_For Loop_Fortran - Fatal编程技术网

For loop 减少多个do循环计算和的计算时间

For loop 减少多个do循环计算和的计算时间,for-loop,fortran,For Loop,Fortran,我想用Fortran90计算以下总和: \sum{i,j,l,t}l{a,i,j}l{a,l,t}\sum{k\alpha{k a{i,k}a{j,k}a{l,k}a{t,k} 对于最后一个和,我想使用Fortran的函数和来获得张量T_{I,j,l,k}。 然而,我不知道如何减少剩余总和的计算时间。 这里是我在这个阶段忽略索引a的循环版本 tot=0 do i=1,n do j=1,n do l=1,n do t=

我想用Fortran90计算以下总和:

\sum{i,j,l,t}l{a,i,j}l{a,l,t}\sum{k\alpha{k a{i,k}a{j,k}a{l,k}a{t,k}

对于最后一个和,我想使用Fortran的函数和来获得张量T_{I,j,l,k}。 然而,我不知道如何减少剩余总和的计算时间。 这里是我在这个阶段忽略索引a的循环版本

    tot=0
    do i=1,n
        do j=1,n
           do l=1,n
             do t=1,n
                C1(i,j,l,t)=L(i,j)*L(l,t)*T(i,j,l,t)
                tot=tot+L(i,j)*L(l,t)*T(i,j,l,t)
             end 
          end
        end
     end

提前感谢您的帮助。

如果我正确理解了您的数学,请确认!通过识别,你可以用矩阵乘法和轨迹来重写它,并且完全避免4D张量,你可以使它更快。我将尝试在这里解释如何,但由于某些愚蠢的原因,stackoverflow似乎不支持MathJax,这可能不是很清楚。。。无论如何,给定4D张量的计算值必须至少在^4上,这里它实际上在^5上,矩阵乘法在^3上。如果你能使用它,后者一定是更好的方法

书写

S=\sum_{i,j,l,t} L_{i,j}L_{l,t} \sum_k \alpha_k A_{i,k} A_{j,k} A_{l,k} A_{t,k}
将k和取在外,并将i,j和中的项和l,k和中的项分别分组,得到

S=\sum_k \alpha_k [\sum_{i}A_{i,k}\sum_{j}L_{i,j}A_{j,k}][\sum_{l}A_{l,k}\sum_{t}L_{l,t}A_{t,k}]
方括号中的术语是相同的,只是总和指数发生了变化。这样写

C_{k}=\sum_{l}A_{l,k}\sum_{t}L_{l,t}A_{t,k}
S=\sum_k \alpha_k C_{k}*C_{k}
检查C的形式,我们可以把t上的和写成矩阵乘法

B=L*A
C_{k}=\sum_{l}A_{l,k}B_{l,k}
因此,我们的食谱是

Matmul L,A提交的表格B 生成Ck 形成最终的总和 代码也简单得多:

ian@eris:~/work/stack$ cat tense.f90
Program tense
  
  Use, Intrinsic :: iso_fortran_env, Only : wp => real64, li => int64

  Implicit None

  Integer, Parameter :: n = 100

  Real( wp ), Dimension( 1:n, 1:n ) :: a, l

  Real( wp ), Dimension( 1:n, 1:n, 1:n, 1:n ) :: t

  Real( wp ), Dimension( 1:n, 1:n ) :: b

  Real( wp ), Dimension( 1:n ) :: c
  Real( wp ), Dimension( 1:n ) :: alpha

  Real( wp ) :: s
  
  Integer( li ) :: start, finish, rate

  Integer :: i, j, k, p, q

  ! Give A, L values
  Call Random_number( a )
  Call Random_number( l )
  ! Try to avoid huge range of numbers
  a = a - 0.5_wp
  l = l - 0.5_wp

  ! Set alpha all to unity so can compare easily
  alpha = 1.0_wp
  
  ! Method in original post
  Call system_clock( start, rate )
  ! Set up T
  t = 0.0_wp
  Do k = 1, n
     Do q = 1, n
        Do p = 1, n
           Do j = 1, n
              Do i = 1, n
                 t( i, j, p, q ) = t( i, j, p, q ) + &
                      a( i, k ) * a( j, k ) * a( p, k ) * a( q, k )
              End Do
           End Do
        End Do
     End Do
  End Do
  ! Sum
  s = 0.0_wp
  Do q = 1, n
     Do p = 1, n
        Do j = 1, n
           Do i = 1, n
              s = s + L( i, j ) * L( p, q ) * t( i, j, p, q ) 
           End Do
        End Do
     End Do
  End Do
  Call system_clock( finish, rate )
  Write( *, * ) 'Tensor method       : Sum, time ', s, Real( finish - start, wp ) / rate

  ! Matrix factorisation method
  Call system_clock( start, rate )
  b = Matmul( l, a )
  Do k = 1, n
     c( k ) = Sum( a( :, k ) * b( :, k ) )
  End Do
  s = Sum( alpha * c * c )
  Call system_clock( finish, rate )
  Write( *, * ) 'Factorisation method: Sum, time ', s, Real( finish - start, wp ) / rate
  
End Program tense
编译和运行:

ian@eris:~/work/stack$ gfortran --version
GNU Fortran (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ian@eris:~/work/stack$ gfortran -O3 -std=f2008 -Wall -Wextra tense.f90
ian@eris:~/work/stack$ ./a.out
 Tensor method       : Sum, time    544.08976066804723        14.874410230000001     
 Factorisation method: Sum, time    544.08976066799494        2.4018499999999999E-004

所以我把n=100的时间缩短了60000,这个差值会随着n的增加而增加。仔细考虑最好的算法总是胜过实现上的调整

如果我正确理解你的数学,请确认!通过识别,你可以用矩阵乘法和轨迹来重写它,并且完全避免4D张量,你可以使它更快。我将尝试在这里解释如何,但由于某些愚蠢的原因,stackoverflow似乎不支持MathJax,这可能不是很清楚。。。无论如何,给定4D张量的计算值必须至少在^4上,这里它实际上在^5上,矩阵乘法在^3上。如果你能使用它,后者一定是更好的方法

书写

S=\sum_{i,j,l,t} L_{i,j}L_{l,t} \sum_k \alpha_k A_{i,k} A_{j,k} A_{l,k} A_{t,k}
将k和取在外,并将i,j和中的项和l,k和中的项分别分组,得到

S=\sum_k \alpha_k [\sum_{i}A_{i,k}\sum_{j}L_{i,j}A_{j,k}][\sum_{l}A_{l,k}\sum_{t}L_{l,t}A_{t,k}]
方括号中的术语是相同的,只是总和指数发生了变化。这样写

C_{k}=\sum_{l}A_{l,k}\sum_{t}L_{l,t}A_{t,k}
S=\sum_k \alpha_k C_{k}*C_{k}
检查C的形式,我们可以把t上的和写成矩阵乘法

B=L*A
C_{k}=\sum_{l}A_{l,k}B_{l,k}
因此,我们的食谱是

Matmul L,A提交的表格B 生成Ck 形成最终的总和 代码也简单得多:

ian@eris:~/work/stack$ cat tense.f90
Program tense
  
  Use, Intrinsic :: iso_fortran_env, Only : wp => real64, li => int64

  Implicit None

  Integer, Parameter :: n = 100

  Real( wp ), Dimension( 1:n, 1:n ) :: a, l

  Real( wp ), Dimension( 1:n, 1:n, 1:n, 1:n ) :: t

  Real( wp ), Dimension( 1:n, 1:n ) :: b

  Real( wp ), Dimension( 1:n ) :: c
  Real( wp ), Dimension( 1:n ) :: alpha

  Real( wp ) :: s
  
  Integer( li ) :: start, finish, rate

  Integer :: i, j, k, p, q

  ! Give A, L values
  Call Random_number( a )
  Call Random_number( l )
  ! Try to avoid huge range of numbers
  a = a - 0.5_wp
  l = l - 0.5_wp

  ! Set alpha all to unity so can compare easily
  alpha = 1.0_wp
  
  ! Method in original post
  Call system_clock( start, rate )
  ! Set up T
  t = 0.0_wp
  Do k = 1, n
     Do q = 1, n
        Do p = 1, n
           Do j = 1, n
              Do i = 1, n
                 t( i, j, p, q ) = t( i, j, p, q ) + &
                      a( i, k ) * a( j, k ) * a( p, k ) * a( q, k )
              End Do
           End Do
        End Do
     End Do
  End Do
  ! Sum
  s = 0.0_wp
  Do q = 1, n
     Do p = 1, n
        Do j = 1, n
           Do i = 1, n
              s = s + L( i, j ) * L( p, q ) * t( i, j, p, q ) 
           End Do
        End Do
     End Do
  End Do
  Call system_clock( finish, rate )
  Write( *, * ) 'Tensor method       : Sum, time ', s, Real( finish - start, wp ) / rate

  ! Matrix factorisation method
  Call system_clock( start, rate )
  b = Matmul( l, a )
  Do k = 1, n
     c( k ) = Sum( a( :, k ) * b( :, k ) )
  End Do
  s = Sum( alpha * c * c )
  Call system_clock( finish, rate )
  Write( *, * ) 'Factorisation method: Sum, time ', s, Real( finish - start, wp ) / rate
  
End Program tense
编译和运行:

ian@eris:~/work/stack$ gfortran --version
GNU Fortran (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ian@eris:~/work/stack$ gfortran -O3 -std=f2008 -Wall -Wextra tense.f90
ian@eris:~/work/stack$ ./a.out
 Tensor method       : Sum, time    544.08976066804723        14.874410230000001     
 Factorisation method: Sum, time    544.08976066799494        2.4018499999999999E-004

所以我把n=100的时间缩短了60000,这个差值会随着n的增加而增加。仔细考虑最好的算法总是胜过实现上的调整

关于Fortran是column major这一事实,我是否遗漏了一句话?没有想过,但问题中提出的解决方法有更重要的问题要解决。我甚至没有提到大量但不必要的内存使用,我会将其排在列主索引之前-如果程序占用太多内存,则无法完全解决问题,如果速度慢,则只需等待更长的时间。这是肯定的,但OP使用了行主索引,可能是因为她不知道Fortran是主列,所以我的注释也是在解决方案中使用的主列顺序。看起来L和T是数组。看起来l和t是索引变量。这可能会散文一些问题,尽管情况是上下??在数学上是的,是的,这不是最好的选择,我可能会回去解决它。在代码中,没有-我使用I,j,k,p和q作为索引,因此没有问题-我遗漏了一点关于Fortran是column major这一事实的注释吗?没有-考虑过这一点,但问题中提出的解决方法有更重要的问题要解决。我甚至没有提到大量但不必要的内存使用,我会将其排在列主索引之前-如果程序占用太多内存,则无法完全解决问题,如果速度慢,则只需等待更长的时间。这是肯定的,但OP使用了行主索引,可能是因为她不知道Fortran是主列,所以我的注释也是在解决方案中使用的主列顺序。看起来L和T是数组。看起来l和t是索引变量。这可能会散文一些问题,尽管情况是上下??在数学上是的,是的,这不是最好的选择,我可能会回去解决它。在代码中,no-I使用I、j、k、p和q作为索引,因此没有问题