resueltos programas programación problemas guia funciones ejemplos fortran operator-overloading sparse-matrix matrix-multiplication derived-types

programas - Función Fortran para sobrecargar la multiplicación entre tipos derivados con componentes asignados



guia fortran (1)

Prefacio

Para almacenar matrices en bandas cuyas contrapartes completas puedan tener filas y columnas indexadas de índices distintos a 1 , definí un tipo de datos derivado como

TYPE CDS REAL, DIMENSION(:,:), ALLOCATABLE :: matrix INTEGER, DIMENSION(2) :: lb, ub INTEGER :: ld, ud END TYPE CDS

donde CDS significa almacenamiento diagonal comprimido. Dada la declaración TYPE(CDS) :: A ,

  1. Se supone que la matrix componentes de rango 2 contiene, como columnas, las diagonales de la matriz completa real (como aquí , excepto que almaceno las diagonales como columnas y no como filas).
  2. Se supone que los componentes ld y ud deben contener el número de diagonales inferior y superior, respectivamente, que es -lbound(A%matrix,2) y +ubound(A%matrix,2) .
  3. Se supone que los componentes de 2 elementos lb y ub contienen los límites inferiores y los límites superiores de la matriz completa real a lo largo de las dos dimensiones. En particular, lb(1) y ub(1) deberían ser iguales a lbound(A%matrix,1) y lbound(A%matrix,2) .

Como puede ver en los puntos 2 y 3., el tipo derivado contiene información redundante, pero no me importa, ya que son solo 3 parejas de números enteros. Además, en el código que estoy escribiendo, la información sobre los límites y la banda de la matriz completa real se conoce antes de que se pueda completar la matriz. Así que primero asigno los valores a los componentes ld , ud , lb y ub , y luego usé estos componentes para ALLOCATE el componente de la matrix (luego puedo llenarlo correctamente).

El problema

Tengo que realizar una multiplicación de matrices entre matrices tan dispersas, así que escribí una FUNCTION para ejecutar dicho producto y lo utilicé para sobrecargar el * operador.

Por el momento, la función es la siguiente,

FUNCTION CDS_mat_x_CDS_mat(A, B) IMPLICIT NONE TYPE(CDS), INTENT(IN) :: A, B TYPE(CDS) :: cds_mat_x_cds_mat ! determine the lower and upper bounds and band of the result based on those of the operands CDS_mat_x_CDS_mat%lb(1) = A%lb(1) CDS_mat_x_CDS_mat%ub(1) = A%ub(1) CDS_mat_x_CDS_mat%lb(2) = B%lb(2) CDS_mat_x_CDS_mat%ub(2) = B%ub(2) CDS_mat_x_CDS_mat%ld = A%ld + B%ld CDS_mat_x_CDS_mat%ud = A%ud + B%ud ! allocate the matrix component ALLOCATE(CDS_mat_x_CDS_mat%matrix(CDS_mat_x_CDS_mat%lb(1):CDS_mat_x_CDS_mat%ub(1),& & -CDS_mat_x_CDS_mat%ld:+CDS_mat_x_CDS_mat%ud)) ! perform the product : : END FUNCTION

Esto significa que, si tengo que hacer el producto varias veces, la asignación se realiza varias veces dentro de la función. Creo que esto no es bueno desde el punto de vista del rendimiento.

Pido sugerencias sobre cómo llevar a cabo la tarea de matrices dispersas en bandas por matriz dispersa con bandas. Me gustaría usar el tipo que definí porque necesito que sea tan general, en términos de límites, como lo es en este momento. Pero podría cambiar el procedimiento para realizar el producto (de FUNCTION a SUBROUTINE , si es necesario).

Ideas

Podría volver a escribir el procedimiento como una SUBROUTINE para declarar CDS_mat_x_CDS_mat con CDS_mat_x_CDS_mat INTENT(INOUT) hacer la asignación de componentes distintos de la matrix , así como la asignación, fuera de la SUBROUTINE . El inconveniente sería que no podría sobrecargar el * operador.

Noté que la función intrínseca MATMUL puede operar en cualquier operando de rango 2, cualquiera que sea el límite superior e inferior a lo largo de las dos dimensiones. Esto significa que la asignación se realiza dentro de la función. Supongo que es eficiente (ya que es intrínseco). La diferencia con respecto a mi función es que acepta matrices de rango 2 de cualquier forma, mientras que las mías aceptan objetos de tipos de datos derivados con un componente de arreglo de rango 2 de cualquier forma.


La función intrínseca MATMUL tiene el equivalente de un resultado automático (F2008 5.2.2) - la forma del resultado se expresa de tal manera que se convierte en una característica de la función (F2008 12.3.3) - la forma del resultado de la función se determina en la parte de especificación de la función y (en términos de implementación), el compilador, por lo tanto, sabe cómo calcular la forma del resultado de la función antes de ejecutar realmente la función propiamente dicha.

Como consecuencia, no hay variables ASLOCATABLE en el lenguaje Fortran asociadas con el equivalente del resultado intrínseco de la función MATMUL. Esto no es lo mismo que "no hay asignación de memoria", es posible que el compilador necesite asignar memoria detrás de la escena para sus propios fines, para cosas como expresiones temporales y similares.

(Digo "equivalente a" arriba, porque los procedimientos intrínsecos son inherentemente especiales, pero pretendo por un momento que MATMUL era solo una función de usuario).

El equivalente de ese tipo de resultado automático para su caso se puede lograr mediante el uso de parámetros de tipo de longitud. Esta es la función Fortran 2003, el mismo estándar de lenguaje base que introdujo componentes asignables, pero no es una que haya sido implementada por todos los compiladores mantenidos activamente.

MODULE xyz IMPLICIT NONE TYPE CDS(lb1, ub1, ld, ud) INTEGER, LEN :: lb1, ub1, ld, ud REAL :: matrix(lb1:ub1, ld:ud) INTEGER :: lb2, ub2 END TYPE CDS INTERFACE OPERATOR(*) MODULE PROCEDURE CDS_mat_x_CDS_mat END INTERFACE OPERATOR(*) CONTAINS FUNCTION CDS_mat_x_CDS_mat(A, B) RESULT(C) TYPE(CDS(*,*,*,*)), INTENT(IN) :: A, B TYPE(CDS(A%lb1, A%ub1, A%ld+B%ld, A%ud+B%ud)) :: C C%lb2 = B%lb2 C%ub2 = B%ub2 ! perform the product. ! : END FUNCTION CDS_mat_x_CDS_mat END MODULE xyz

Teóricamente, esto le da al compilador más oportunidades para la optimización, porque tiene más información antes de la llamada a la función para el almacenamiento requerido para el resultado de la función. Si esto realmente da como resultado un mejor rendimiento en el mundo real depende de la implementación del compilador y la naturaleza de las referencias a funciones.