  PROGRAM Diagonali1
! SCOPO: Calcolo della somma di tutte le diagonali e antidiagonali di una
!   matrice
! ALGORITMO: le diagonali vengono sommate in sequenza.
! DATI: file di testo che contiene le dimensioni nel primo(i) record
!   e gli elementi in ordine di riga nei record successivi.
! RISULTATI: le somme sono riportate lungo i bordi della matrice, allineate
!   con le diagonali.
!--------------------------------------------------------------------------
!-- Dichiarazioni globali
  IMPLICIT NONE
  INTEGER,ALLOCATABLE:: mat(:,:) ! Matrice
!   Attributo ALLOCATABLE: allocazione dinamica,
!   va dichiarato il "rango", non la "forma"
  INTEGER:: n, m                 ! dimensioni della matrice
  INTEGER:: i, j, k              ! k: lunghezza della diagonale
  CHARACTER(LEN=20):: file       ! nome del file di ingresso

  WRITE(*,*) "File di input? "
  READ(*,*) file
  OPEN(1,FILE=file,STATUS='OLD')
  READ(1,*) n, m
  ALLOCATE( mat(1:n+1,0:m+1))         ! Matrice bordata a ds, sn e in basso
!   Istruzione per allocare la matrice: la "forma" è dichiarata qui
  READ(1,*) (mat(i,1:m), i=1,n)       ! Carica i dati per righe

!-- Somma le diagonali
  DO j=1,m+1                 ! Diagonali che terminano sul lato basso
    k = MIN( j-1, n)
    mat(n+1,j) = SUM( Diag( mat(n+1-k:n, j-k:j-1)))
!     Funzione intrinseca vettoriale SUM: con un solo argomento, somma
!       tutti gli elementi dell'array
!     NOTA: per j=1, mat(n+1:n,1:0) ha "ampiezza nulla" e cosi' pure Diag,
!       la cui somma fa 0.
  END DO
  DO i=1,n                   ! Diagonali che terminano sul lato destro
    k = MIN( i-1, m)
    mat(i,m+1) = SUM( Diag( mat(i-k:i-1, m-k+1:m)))
!     NOTA: per i=1, mat(1:0,m+1:m) ha "ampiezza nulla".
  END DO
  WRITE(*,*)   &
    "Matrice bordata (in basso e a ds.) dalle somme delle diagonali"
  WRITE(*,*)
  CALL Scrivi(mat(1:n+1,1:m+1))

!-- Somma le antidiagonali
  DO j=0,m                   ! Diagonali che terminano sul lato basso
    k = MIN( m-j, n)
    mat(n+1,j) = SUM( Antidiag( mat(n+1-k:n, j+1:j+k)))
!     NOTA: per j=m, mat(n+1:n,m+1:m) ha "ampiezza nulla"
  END DO
  DO i=1,n+1                 ! Diagonali che terminano sul lato sinistro
    k = MIN( i-1, m)
    mat(i,0) = SUM( Antidiag( mat(i-k:i-1, 1:k)))
!     NOTA: per i=1, mat(1:0,1:0) ha "ampiezza nulla".
  END DO
  WRITE(*,*)
  WRITE(*,*)  &
    "Matrice bordata (a sn. e in basso) dalle somme delle antidiagonali"
  WRITE(*,*)
  CALL Scrivi(mat(1:n+1,0:m))
  STOP

CONTAINS
!--------------------------------------------------------------------------
  FUNCTION Diag(mat)
! Estrae la diagonale principale da una matrice quadrata
!--------------------------------------------------------------------------
  INTEGER,DIMENSION(:,:),INTENT(IN):: mat      ! Va dichiarato prima!
!   Argomento di "forma presunta" (assumed shape): dichiarato solo il rango
  INTEGER,DIMENSION(SIZE(mat,1))   :: Diag     ! Funzione vettoriale
!   La funzione intrinseca SIZE, in questa forma, restituisce l'estenzione
!     dell'indice richiesto (qui il primo).
!     SIZE(mat) restiruisce l'ampiezza (n. di elementi) di "mat".
!   NOTA: la forma (ma non il rango!) del risultato di una funzione
!     può essere funzione degli argomenti.
!     Nel caso di subroutine, la forma di un argomento può essere funzione
!     di argomenti in ingresso.
  INTEGER :: i
!   Costrutto FORALL
  FORALL (i=1:SIZE(mat,1))
    Diag(i)= mat(i,i)
  END FORALL
  RETURN
END FUNCTION Diag

!--------------------------------------------------------------------------
  FUNCTION Antidiag(mat)
! Estrae l'antidiagonale principale da una matrice quadrata
!--------------------------------------------------------------------------
  INTEGER,DIMENSION(:,:),INTENT(IN):: mat(:,:)
  INTEGER,DIMENSION(SIZE(mat,1))   :: Antidiag  ! Funzione vettoriale
  INTEGER:: i, n
  n = SIZE(mat,1)
!   Istruzione FORALL
  FORALL (i=1:n)    Antidiag(i) = mat(i,n-i+1)
  RETURN
END FUNCTION Antidiag

!--------------------------------------------------------------------
  SUBROUTINE Scrivi(mat)
! Scrive la matrice per righe
!--------------------------------------------------------------------
  INTEGER,INTENT(IN):: mat(:,:)
  INTEGER:: i
  DO i=1,SIZE(mat,1)
    WRITE(*,*) mat(i,:)
  END DO
  RETURN
END SUBROUTINE Scrivi
END PROGRAM Diagonali1
