Integer :: NBE,ierr,RN,i,j
Real(kind=8), allocatable :: AA1(:,:),AA2(:,:)

NBE=40 
RN=3*NBE-2
Allocate(AA1(3*NBE,3*NBE),AA2(3*NBE,RN),stat=ierr)

If (ierr .ne. 0) Then
    print *, 'allocate steps failed 1'
    pause
End If

Do i=1,3*NBE
  Do j=1,3*NBE
     AA1(i,j)=1
  End Do
End Do

Quiero eliminar las columnas 97 y 113 de la matriz AA1 y luego esta matriz se convierte en AA2. Solo quiero saber si algún comando de Fortran puede realizar esta operación.

3
Jeremy_Tamu 21 ene. 2018 a las 07:06

3 respuestas

La mejor respuesta

La respuesta de Alexander Vogt da el concepto de utilizar un <índice> subíndice vectorial para seleccionar los elementos de la matriz para inclusión. Esa respuesta construye la matriz de subíndices vectoriales usando

[(i,i=1,96),(i=98,112),(i=114,3*NBE)]

Algunos pueden considerar

AA2 = AA1(:,[(i,i=1,96),(i=98,112),(i=114,3*NBE)])

Ser menos que claro en la lectura. Se podría usar un vector índice "temporal"

integer selected_columns(RN)
selected_columns = [(i,i=1,96),(i=98,112),(i=114,3*NBE)]
AA2 = AA1(:,selected_columns)

Pero eso no soluciona que el constructor de matrices no sea agradable, especialmente en casos más complicados. En cambio, podemos crear una máscara y usar nuestras técnicas comunes:

logical column_wanted(3*NBE)
integer, allocatable :: selected_columns(:)

! Create a mask of whether a column is wanted
column_wanted = .TRUE.
column_wanted([97,113]) = .FALSE.

! Create a list of indexes of wanted columns
selected_columns = PACK([(i,i=1,3*NBE)],column_wanted)
AA2 = AA1(:,selected_columns)
5
francescalus 24 ene. 2018 a las 06:08

No tengo un compilador fortran aquí en casa, así que no puedo probarlo. Pero haría algo en línea con esto:

i = 0
DO j = 1, 3*NBE
    IF (j == 97 .OR. j == 113) CYCLE
    i = i + 1
    AA2(:, i) = AA1(:, j)
END DO

El comando CYCLE significa que el resto del bucle ya no debería ejecutarse y la próxima iteración debería comenzar. Por lo tanto, i no se incrementará, así que cuando j=96, luego i=96, cuando j=98 luego i=97, y cuando j=114 y luego {{ X7}}.

Unas pocas palabras más: debido al diseño de memoria de Fortran, desea desplazarse por el primer índice el más rápido, y así sucesivamente. Por lo tanto, su código se ejecutará más rápido si lo cambia a:

Do j=1,3*NBE    ! Outer loop over second index
  Do i=1,3*NBE  ! Inner loop over first index
    AA1(i,j)=1
  End Do
End Do

(Por supuesto, una inicialización tan fácil se puede hacer aún más fácil con solo AA1(:,:) = 1 de solo AA1 = 1.

1
chw21 21 ene. 2018 a las 07:48

Aquí hay un simple revestimiento:

AA2 = AA1(:,[(i,i=1,96),(i=98,112),(i=114,3*NBE)])

Explicación:

  1. (Parte interna) Construya una matriz temporal para los índices [1,...,96,98,...,112,114,...,3*NBE]

  2. (Parte externa) Copie la matriz y solo considere las columnas en la matriz de índice


OK, cedo ante @IanBush ... Aún más simple sería hacer tres tareas dedicadas:

AA2(:,1:96)   = AA1(:,1:96)
AA2(:,97:111) = AA1(:,98:112)
AA2(:,112:)   = AA1(:,114:)
5
Alexander Vogt 21 ene. 2018 a las 11:29