在 Fortran 中存储具有多维索引的变量

2023-12-12

Question

考虑以下代码:

program example

  implicit none

  integer, parameter :: n_coeffs = 1000
  integer, parameter :: n_indices = 5
  integer :: i
  real(8), dimension(n_coeffs) :: coeff
  integer, dimension(n_coeffs,n_indices) :: index

  do i = 1, n_coeffs
    coeff(i)   = real(i*3,8)
    index(i,:) = [2,4,8,16,32]*i
  end do

end

对于任何 5 维索引我需要获得相关系数,在不知道或计算的情况下 i。例如,给定[2,4,8,16,32]我需要获得3.0无需计算i.

是否有一个合理的解决方案,也许使用稀疏矩阵,适用于n_indices100 左右(尽管n_coeffs仍然是 1000 的数量级)?


一个糟糕的解决方案

一种解决方案是定义一个 5 维数组,如下所示

real(8), dimension(2000,4000,8000,16000,32000) :: coeff2

do i = 1, ncoeffs
    coeff2(index(i,1),index(i,2),index(i,3),index(i,4),index(i,5)) = coeff(i)
end do

然后,得到与相关的系数[2,4,8,16,32], call

coeff2(2,4,8,16,32)

然而,除了非常浪费内存之外,这个解决方案不允许n_indices考虑到数组的 7 维限制,要设置为大于 7 的数字。


OBS:这个问题是this one。我试图更准确地提出这个问题,但在第一次尝试中失败了,这一努力极大地受益于@Rodrigo_Rodrigues 的回答。


实际代码

如果它有帮助,这里是我试图解决的实际问题的代码。它是一种用于逼近函数的自适应稀疏网格方法。主要目标是使插值在 和 处尽可能快:

MODULE MOD_PARAMETERS

    IMPLICIT NONE
    SAVE

    INTEGER, PARAMETER :: d     = 2     ! number of dimensions
    INTEGER, PARAMETER :: L_0   = 4     ! after this adaptive grid kicks in, for L <= L_0 usual sparse grid
    INTEGER, PARAMETER :: L_max = 9    ! maximum level
    INTEGER, PARAMETER :: bound = 0     ! 0 -> for f = 0 at boundary
                                        ! 1 -> adding grid points at boundary
                                        ! 2 -> extrapolating close to boundary
    INTEGER, PARAMETER :: max_error = 1
    INTEGER, PARAMETER :: L2_error  = 1
    INTEGER, PARAMETER :: testing_sample = 1000000

    REAL(8), PARAMETER :: eps = 0.01D0   ! epsilon for adaptive grid

END MODULE MOD_PARAMETERS

PROGRAM MAIN

USE MOD_PARAMETERS
IMPLICIT NONE

INTEGER, DIMENSION(d,d)                :: ident
REAL(8), DIMENSION(d)                  :: xd
INTEGER, DIMENSION(2*d)                :: temp
INTEGER, DIMENSION(:,:),   ALLOCATABLE :: grid_index, temp_grid_index, grid_index_new, J_index
REAL(8), DIMENSION(:),     ALLOCATABLE :: coeff, temp_coeff, J_coeff

REAL(8) :: temp_min, temp_max, V, T, B, F, x1
INTEGER :: k, k_1, k_2, h, i, j, L, n, dd, L1, L2, dsize, count, first, repeated, add, ind

INTEGER :: time1, time2, clock_rate, clock_max

REAL(8), DIMENSION(L_max,L_max,2**(L_max),2**(L_max)) :: coeff_grid
INTEGER, DIMENSION(d) :: level, LL, ii

REAL(8), DIMENSION(testing_sample,d) :: x_rand
REAL(8), DIMENSION(testing_sample)   :: interp1, interp2

! ============================================================================
! EXECUTABLE
! ============================================================================

ident = 0
DO i = 1,d
    ident(i,i) = 1
ENDDO

! Initial grid point
dsize = 1
ALLOCATE(grid_index(dsize,2*d),grid_index_new(dsize,2*d))
grid_index(1,:) = 1
grid_index_new  = grid_index

ALLOCATE(coeff(dsize))
xd = (/ 0.5D0, 0.5D0 /)
CALL FF(xd,coeff(1))
CALL FF(xd,coeff_grid(1,1,1,1))

L = 1
n = SIZE(grid_index_new,1)
ALLOCATE(J_index(n*2*d,2*d))
ALLOCATE(J_coeff(n*2*d))

CALL SYSTEM_CLOCK (time1,clock_rate,clock_max)

DO WHILE (L .LT. L_max)

    L       = L+1
    n       = SIZE(grid_index_new,1)
    count   = 0
    first   = 1
    DEALLOCATE(J_index,J_coeff)
    ALLOCATE(J_index(n*2*d,2*d))
    ALLOCATE(J_coeff(n*2*d))
    J_index = 0
    J_coeff = 0.0D0
    DO k = 1,n
        DO i = 1,d
            DO j = 1,2
                IF ((bound .EQ. 0) .OR. (bound .EQ. 2)) THEN
                    temp = grid_index_new(k,:)+(/ident(i,:),ident(i,:)*(grid_index_new(k,d+i)-(-1)**j)/)
                ELSEIF (bound .EQ. 1) THEN
                    IF (grid_index_new(k,i) .EQ. 1) THEN
                        temp = grid_index_new(k,:)+(/ident(i,:),ident(i,:)*(-(-1)**j)/)
                    ELSE
                        temp = grid_index_new(k,:)+(/ident(i,:),ident(i,:)*(grid_index_new(k,d+i)-(-1)**j)/)
                    ENDIF
                ENDIF
                CALL XX(d,temp(1:d),temp(d+1:2*d),xd)
                temp_min = MINVAL(xd)
                temp_max = MAXVAL(xd)
                IF ((temp_min .GE. 0.0D0) .AND. (temp_max .LE. 1.0D0)) THEN
                    IF (first .EQ. 1) THEN
                        first = 0
                        count = count+1
                        J_index(count,:) = temp
                        V = 0.0D0
                        DO k_1 = 1,SIZE(grid_index,1)
                            T = 1.0D0
                            DO k_2 = 1,d
                                CALL XX(1,temp(k_2),temp(d+k_2),x1)
                                CALL BASE(x1,grid_index(k_1,k_2),grid_index(k_1,k_2+d),B)
                                T = T*B
                            ENDDO
                            V = V+coeff(k_1)*T
                        ENDDO
                        CALL FF(xd,F)
                        J_coeff(count) = F-V
                    ELSE
                        repeated = 0
                        DO h = 1,count
                            IF (SUM(ABS(J_index(h,:)-temp)) .EQ. 0) THEN
                                repeated = 1
                            ENDIF
                        ENDDO
                        IF (repeated .EQ. 0) THEN
                            count = count+1
                            J_index(count,:) = temp
                            V = 0.0D0
                            DO k_1 = 1,SIZE(grid_index,1)
                                T = 1.0D0
                                DO k_2 = 1,d
                                    CALL XX(1,temp(k_2),temp(d+k_2),x1)
                                    CALL BASE(x1,grid_index(k_1,k_2),grid_index(k_1,k_2+d),B)
                                    T = T*B
                                ENDDO
                                V = V+coeff(k_1)*T
                            ENDDO
                            CALL FF(xd,F)
                            J_coeff(count) = F-V
                        ENDIF
                    ENDIF
                ENDIF
            ENDDO
        ENDDO
    ENDDO

    ALLOCATE(temp_grid_index(dsize,2*d))
    ALLOCATE(temp_coeff(dsize))
    temp_grid_index = grid_index
    temp_coeff      = coeff
    DEALLOCATE(grid_index,coeff)
    ALLOCATE(grid_index(dsize+count,2*d))
    ALLOCATE(coeff(dsize+count))
    grid_index(1:dsize,:) = temp_grid_index
    coeff(1:dsize)        = temp_coeff
    DEALLOCATE(temp_grid_index,temp_coeff)
    grid_index(dsize+1:dsize+count,:) = J_index(1:count,:)
    coeff(dsize+1:dsize+count)        = J_coeff(1:count)
    dsize = dsize + count    

    DO i = 1,count
        coeff_grid(J_index(i,1),J_index(i,2),J_index(i,3),J_index(i,4)) = J_coeff(i)
    ENDDO

    IF (L .LE. L_0) THEN
        DEALLOCATE(grid_index_new)
        ALLOCATE(grid_index_new(count,2*d))
        grid_index_new = J_index(1:count,:)
    ELSE
        add = 0
        DO h = 1,count
            IF (ABS(J_coeff(h)) .GT. eps) THEN
                add = add + 1
                J_index(add,:) = J_index(h,:)
            ENDIF
        ENDDO
        DEALLOCATE(grid_index_new)
        ALLOCATE(grid_index_new(add,2*d))
        grid_index_new = J_index(1:add,:)
    ENDIF

ENDDO

CALL SYSTEM_CLOCK (time2,clock_rate,clock_max)
PRINT *, 'Elapsed real time1 = ', DBLE(time2-time1)/DBLE(clock_rate)
PRINT *, 'Grid Points        = ', SIZE(grid_index,1)

! ============================================================================
! Compute interpolated values:
! ============================================================================

CALL RANDOM_NUMBER(x_rand)
CALL SYSTEM_CLOCK (time1,clock_rate,clock_max)
DO i = 1,testing_sample
    V = 0.0D0
    DO L1=1,L_max
        DO L2=1,L_max
            IF (L1+L2 .LE. L_max+1) THEN
                level = (/L1,L2/)
                T = 1.0D0
                DO dd = 1,d
                    T = T*(1.0D0-ABS(x_rand(i,dd)/2.0D0**(-DBLE(level(dd)))-DBLE(2*FLOOR(x_rand(i,dd)*2.0D0**DBLE(level(dd)-1))+1)))
                ENDDO
                V = V + coeff_grid(L1,L2,2*FLOOR(x_rand(i,1)*2.0D0**DBLE(L1-1))+1,2*FLOOR(x_rand(i,2)*2.0D0**DBLE(L2-1))+1)*T
            ENDIF
        ENDDO
    ENDDO
    interp2(i) = V
ENDDO
CALL SYSTEM_CLOCK (time2,clock_rate,clock_max)
PRINT *, 'Elapsed real time2 = ', DBLE(time2-time1)/DBLE(clock_rate)

END PROGRAM

对于任何 5 维索引,我需要获取关联的 系数,在不知道或计算的情况下 i。例如,给定[2,4,8,16,32]我需要获得3.0无需计算i.

  function findloc_vector(matrix, vector) result(out)
    integer, intent(in) :: matrix(:, :)
    integer, intent(in) :: vector(size(matrix, dim=2))
    integer :: out, i

    do i = 1, size(matrix, dim=1)
      if (all(matrix(i, :) == vector)) then
        out = i
        return
      end if
    end do
    stop "No match for this vector"
  end

这就是你如何使用它:

print*, coeff(findloc_vector(index, [2,4,8,16,32])) ! outputs 3.0

我必须承认我不愿意发布这段代码,因为即使这样回答你的问题,老实说我认为这是not你真正想要/需要什么,但你没有提供足够的信息让我知道你真正想要什么do想要/需要。

Edit(在OP的实际代码之后):

如果我正确解密了您的代码(并考虑到您在上一个问题中所说的内容),您将声明:

REAL(8), DIMENSION(L_max,L_max,2**(L_max),2**(L_max)) :: coeff_grid

(where L_max = 9, so size(coeff_grid) = 21233664=~160MB),然后用以下内容填充:

DO i = 1,count
    coeff_grid(J_index(i,1),J_index(i,2),J_index(i,3),J_index(i,4)) = J_coeff(i)
ENDDO

(where count的数量级为 1000,即其元素的 0.005%),因此这样您可以使用数组表示法通过其 4 个索引来获取值。

请不要这样做。在这种情况下,您也不需要稀疏矩阵。您提出的新方法要好得多:将索引存储在较小数组的每一行中,并通过这些索引在其自己的数组中的相应位置获取系数数组。这更快(避免大量分配)并且内存效率更高。

PS:你必须坚持使用 Fortran 90 吗?它是标准的一个非常旧的版本,您使用的编译器很可能实现了更新的版本。您可以通过内在的方法大大提高代码质量move_alloc(对于较少的数组副本),内部模块中的类型常量iso_fortran_env(为了便携性),[], >, <, <=,...符号(为了可读性)...

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Fortran 中存储具有多维索引的变量 的相关文章

随机推荐

  • JSONDecodeError:额外数据:第 1 行第 228 列(字符 227)

    我正在使用 Ipython 进行一些数据分析 我无法加载 JSON 文件 请帮我在 IPython 中加载这个 JSON 文件 我还想跳过第一行中的相同单词以使其成为干净的格式 我希望每条记录如下所示 station id 72 num b
  • 字符串到字典字数统计

    所以我在家庭作业问题上遇到了麻烦 编写一个函数 word counter input str 它接受字符串 input str 并返回一个字典 将 input str 中的单词映射到其出现次数 所以到目前为止我的代码是 def word c
  • 如何在 Rails 中的 Chartkicks 中显示数据计数以及百分比

    Using chartkicks用于显示图表 它仅显示百分比 我想显示数量 金额以及百分比 Chartkickgem 是上面的包装Google Charts 通过使用库选项 您可以指定在legend并设置其他配置选项 所以像这样 有关更多配
  • 尝试更改 Google 云端硬盘中文件的所有者

    我尝试更改云端硬盘中文档的所有权 但收到以下错误 很抱歉 服务器发生错误 请稍等一下 然后重试 第 12 行 文件 代码 function transferFiles var files DriveApp getFiles while fi
  • JNA 与 Fortran 假定大小的数组

    我有一个 Fortran 子例程 采用假定大小的数组 subroutine sub arr implicit none double precision arr end subroutine 我使用 JNA 从 Java 进行了本机调用 F
  • Delphi:发生意外的内存泄漏

    在 Delphi 中 我已配置为报告内存泄漏 IFDEF Debug ReportMemoryLeaksOnShutdown true ENDIF After exiting the program I get the following
  • 在bash shell脚本中初始化动态变量(可变变量)

    我通过 bash shell 使用 PHP CLI 请检查在 shell 脚本中操作数组 由 php cli 打印 了解详情 在下面的 shell 代码中我能够回显key value我从 PHP 脚本中获得的对 IFS parse php
  • wp7水平滑动选择

    我正在寻找一个允许我滑动项目列表的控件 水平滑动将在下一个和上一个项目之间移动 该控件还将确保所选项目在不被操作时移动到中心 该控件仅占据页面的一半 我希望左侧和右侧的选项可见并环绕 Like so lt gt 所以我的问题是 这样的控件是
  • Google Play - 零支持的设备

    我知道这里有类似的问题 但似乎没有一个令人满意的答案 我正在尝试发布应用程序 但无论我尝试什么 开发人员控制台都会报告支持的设备数为零 这是我的完整清单
  • 如何获取R脚本出错时的行号?

    如果我从命令行运行一个很长的 R 脚本 R slave script R 那么我怎样才能让它在错误时给出行号呢 如果可能的话 我不想将调试命令添加到脚本中 我只是希望 R 表现得像大多数其他脚本语言一样 这不会给您行号 但它会告诉您调用堆栈
  • WPF 与 Windows 窗体

    我对 WPF 和 Windows 窗体非常困惑 WPF 相对于 Windows 窗体的用途是什么 WPF有什么用 WPF 是一个用于开发 Windows 和浏览器 应用程序的新平台 WPF不一定有replaceWindows 窗体 使用 W
  • Dojo 中的 DataGrid,包含来自 servlet 的 json 数据

    我第一次使用 JSON 并想用我的 JSON 数据填充我的数据网格 这是我的 JSON 数据 head vars s fname lname results bindings s type uri value http tn gov in
  • 按键对散列进行分组并对值求和

    我有一个哈希数组 Vegetable gt 10 Vegetable gt 5 Dry Goods gt 3 gt Dry Goods gt 2 我需要使用inject我想 但我真的一直在挣扎 我想要一个新的哈希值来反映前一个哈希值的重复键
  • 如何使用 PHP 解码以“\u”开头的内容

    如何使用 PHP 解码以 u 开头的内容 e g u4f60 u5df2 u7ecf u6dfb u52a0 u4e86 u6b64 u8bdd u9898 谢谢 对于 PHP 5 4 intl s u4f60 u5df2 u7ecf u6
  • 如何使用 PHP DOMDocument::saveHTML() 阻止 html 实体?

    由于自定义存储需求 为什么 在这里并不重要 谢谢 我必须保存 html a 特定格式的链接 例如 myDOMNode gt setAttribute href 123456 一切正常 直到我打电话saveHTML 在包含的 DOMDocum
  • AJAX POST 到 PHP(无需 JQuery)

    我有一个 PHP 作业 我决定尝试添加 AJAX 因为在我们的课堂上我们不会只学习 AJAX 而只会学习 PHP 我似乎无法得到工作的回应 然而 在 Fire Fox 控制台的网络部分中 我可以找到使用我在表单中输入的值发送的 POST 以
  • 多标签分类的特征选择 (scikit-learn)

    我正在尝试在 scikit learn 中通过卡方方法进行特征选择 sklearn feature selection SelectKBest 当我尝试将此应用于多标签问题时 我收到此警告 UserWarning Duplicate sco
  • 如何使用slf4j框架实现敏感数据的屏蔽?

    我想使用 slf4j 框架屏蔽敏感数据 例如用户名 密码 感谢您立即提供帮助 提前致谢 试试这个 1 首先 我们应该创建一个类来处理我们的日志 每行 public class PatternMaskingLayout extends Pat
  • 如何通过 JavaScript 将条目插入浏览历史记录

    如何在浏览历史记录中插入条目 以便后退按钮第一次单击时转到不同页面 第二次单击时转到原始页面 因此 如果您需要对我想要做什么进行详细解释 请访问 https secure exitjunction com howitworks jsp 我只
  • 在 Fortran 中存储具有多维索引的变量

    Question 考虑以下代码 program example implicit none integer parameter n coeffs 1000 integer parameter n indices 5 integer i re