2013-03-07 8 views
5

Sto scrivendo del codice in Fortran 2003 che esegue molta algebra lineare con matrici sparse. Sto cercando di sfruttare alcune delle caratteristiche più astratte del nuovo standard, quindi ho programmi più semplici senza troppo codice ripetuto.polimorfismo di run-time in fortran 2003

Ho una procedura solver che contiene una matrice, alcuni vettori, la tolleranza per il metodo iterativo utilizzato ecc. Sto passando un puntatore a una procedura denominata matvec; matvec è la subroutine che usiamo per le moltiplicazioni del vettore matrice.

Il problema è che a volte matvec è una procedura che accetta argomenti aggiuntivi colorlist, color1, color2 superiori a quelli usuali inviati a questa procedura. Posso pensare a diversi modi di affrontare questo.

Prima idea: definire due diverse interfacce astratte matvec1, matvec2 e due diversi risolutori. Funziona ma significa duplicare del codice, che è proprio quello che sto cercando di evitare.

Un'altra idea: mantenere la stessa interfaccia astratta matvec, e rendere gli argomenti extra , color1, color2 opzionale. Ciò significa renderli opzionali in ogni routine MATVEC, anche quelli per i quali non sono realmente opzionali, e per le routine in cui non vengono neppure utilizzati. Abbastanza sicuro andrò all'inferno se lo faccio.

Posso pensare a molte altre soluzioni meno che ottimali. Mi piacerebbe un po 'di input su questo - Sono sicuro che c'è un modo elegante per farlo, non sono sicuro di cosa sia.

risposta

5

La domanda è in realtà, se gli argomenti aggiuntivi devono essere passati ogni volta che viene richiamata la procedura (perché cambiano tra due invocazioni), oppure possono essere inizializzati in qualche punto e quindi utilizzati solo nella funzione. Nel caso successivo è possibile creare una classe con un'interfaccia astratta, che definisce la subroutine matvec con gli argomenti essenziali. È quindi possibile estendere tale classe con quelle più specializzate, che possono contenere le opzioni aggiuntive necessarie. Devono ancora definire la stessa interfaccia matvec come classe genitore (con lo stesso elenco di argomenti), ma possono utilizzare i valori aggiuntivi memorizzati in essi quando viene chiamata la loro procedura matvec.

Si trova un esempio dettagliato in this answer per un caso simile (cercare il secondo esempio che mostra module rechercheRacine).

2

Invece di passare il puntatore del procedimento come argomento esplicito, si potrebbe mettere i vari matvec routine dietro un'interfaccia generica:

interface matvec 
    module procedure matvec1, matvec2 
end interface 

Allora la vostra solver routine può semplicemente utilizzare il nome generico con o senza gli argomenti extra . Lo stesso approccio può naturalmente anche essere posta nell'uso approccio suggerito di Bálint di definire un solver come un tipo derivato con procedure di tipo-bound:

type :: solver 
    real, allocatable :: matrix(:,:), v1(:), v2(:) 
contains 
    procedure, pass :: matvec1 
    procedure, pass :: matvec2 
    generic :: matvec => matvec1, matvec2 
end type 

La differenza principale è che questo non usa polimorfismo per determinare la corretta procedura invocare, ma piuttosto le caratteristiche degli argomenti fittizi.

Non sono sicuro delle vostre intenzioni per il puntatore della procedura; se desideri cambiare il suo obiettivo in fase di esecuzione (o forse assegnare un significato speciale al suo stato 'indefinito'), allora i puntatori sono l'unico modo e tutti gli obiettivi devono corrispondere alla stessa interfaccia astratta.Se invece è sufficiente selezionare una delle varie procedure in base ai loro argomenti, è possibile sfruttare l'interfacciamento (il mio esempio) o il sovraccarico (l'esempio di Bálint). Ogni estensione di un tipo può estendere un binding ereditato generic con nuove procedure o sovraccaricare un binding specifico ereditato.