Selezionare un sub-set di funzioni "at runtime".

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
Avatar utente
epag00
Prode Principiante
Messaggi: 186
Iscrizione: sabato 29 dicembre 2007, 22:41

Selezionare un sub-set di funzioni "at runtime".

Messaggio da epag00 »

Ciao a tutti.

In un programma di calcolo per la soluzione di sistemi di equazioni non lineari, ho un insieme di equazioni (che descrivono dei processi fisici) sotto forma di funzioni. A tempo di esecuzione, devo essere in grado di fornire all'algoritmo risolutivo un sub-set di queste equazioni e relative incognite sotto forma di una funzione vettoriale funcv con argomento un vettore di incognite x. Le equazioni-funzioni e le incognite da scegliere sono ottenute da un input file. Sto cercando un modo per poter selezionare, a tempo di esecuzione, le funzioni da passare alla procedura di risoluzione.

Il linguaggio che sto usando è il Fortran 95, ma prima che i programmatori C scappino a gambe levate, faccio loro un appello a fornirmi una soluzione nel loro linguaggio visto che ci sono ormai poche differenze dal punto di vista delle capacità fra il Fortran 95+ e il C (cercherò poi di fare io una "traduzione").

Segue un esempio "statico" della funzione finale, ovvero un esempio (perfettamente funzionante) in cui passo all'algoritmo risolutivo un fissato set di incognite ed equazioni (è incluso in un modulo).

Codice: Seleziona tutto

MODULE equations
IMPLICIT NONE

REAL, PARAMETER	:: ONE = 1.

CONTAINS

!_______________________________________________________________________

FUNCTION funcv(x)
REAL(dp), DIMENSION(:), INTENT(IN)	:: x
REAL(dp), DIMENSION(SIZE(x))		:: funcv
REAL(dp), PARAMETER	:: mp = 1.5, pmec = 1445422., a = 0.746E5, b = 0.55E5
REAL(dp), PARAMETER	:: pmi = 963329., Ta = 288., pa = 1E5, eta_is_c = 0.8
REAL(dp), PARAMETER	:: k = 1.4, eta_m_t = 0.95 , eta_is_t = 0.85, Ts = 700.
REAL(dp), PARAMETER	:: eta_m_c = 0.95, rho = 9.
!
! x(1): l'v/lv		x(2): ps		x(3): pc		x(4): mu		x(5): Tc
!
funcv(1) = ONE + ONE / (rho-ONE) * ( ONE-( x(2)/x(3) )**(ONE/mp) ) - x(1)
funcv(2) = x(4) * x(1) * pmi + x(3) - x(2) - a - b*x(4)*x(1) - pmec
funcv(3) = SQRT( Ta / x(5) ) * x(3) / pa - x(4)
funcv(4) = Ta * ( ONE + ONE/eta_is_c * ( ( x(3)/pa )**( (k-ONE)/k ) - ONE ) ) - x(5)
funcv(5) = eta_m_t * eta_is_t * Ts * (ONE - ( pa/x(2) )**( (k-ONE)/k ) ) - ( x(5)-Ta )/eta_m_c

END FUNCTION funcv

END MODULE equations
Ora nella versione dinamica di questo modulo ci saranno tante procedure, insieme a funcv, per tutte le equazioni risolubili dal mio programma. L'input file indicherà il sub-set necessario durante ogni esecuzione. Quello che non so fare è il processo di selezione delle funzioni e delle incognite.

Per quello che riguarda la "selezione" delle incognite, ho pensato di condividere l'ambito di visibilità di tutti i parametri (i vari mp, pmec, a, b,... che nel caso statico sono all'interno della funcv) tra tutte le equazioni-funzione a disposizione e poi, in una procedura di "linking", usare un puntatore per collegare le x alle effettive grandezze fisiche che l'input file avrà indicato come incognite. Fin qui, almeno in teoria, potrebbe anche funzionare, ma non so come fare per le funzioni. Suggerimenti? C'è un modo più elegante per risolvere il problema? Come fanno i programmi di calcolo seri (ho cercato un po' nei sorgenti di Octave, ma mi ci sono perso in un niente)?

Come avrete intuito non sono un esperto di programmazione anche se ho una certa esperienza nella programmazione orientata al calcolo, per cui qualunque suggerimento per migliorare il processo è ben accetto.

Grazie per la pazienza di avermi letto fin qui!
If you shake my hand better count your fingers (D. Mustaine)
Ashura
Prode Principiante
Messaggi: 199
Iscrizione: venerdì 13 ottobre 2006, 9:55

Re: Selezionare un sub-set di funzioni "at runtime".

Messaggio da Ashura »

da quanto ho capito a te serve di poter risolvere una o piu' equazioni che non sono cablate a codice ma sono scritte in un file di testo... correggimi se sbaglio ma il tuo file di input sarebbe qualcosa del genere?

Codice: Seleziona tutto

EQ = x(4) * x(1) * pmi + x(3) - x(2) - a - b*x(4)*x(1) - pmec
EQ1 = SQRT( Ta / x(5) ) * x(3) / pa - x(4)
x = 5
pmi = 3
a = 1
b = 2
pmec = 12
Ta = 4
pa = 10
in questo caso quello che tu vuoi fare e' trasformare una stringa di testo ( l'equazione ) in una procedura matematica.
Non e' una cosa immensamente complessa ma neanche immediata.
A me e' capitato di fare qualcosa di simile ( piu' semplice pero' ) e ho prima trasformato l'equazione in notazione polacca inversa e poi ho scritto un piccolo interprete che calcola il valore di un'espressione in notazione RPN

ecco qualche riferimento:

http://it.wikipedia.org/wiki/Notazione_polacca_inversa
http://en.wikipedia.org/wiki/Reverse_Polish_notation
Avatar utente
epag00
Prode Principiante
Messaggi: 186
Iscrizione: sabato 29 dicembre 2007, 22:41

Re: Selezionare un sub-set di funzioni "at runtime".

Messaggio da epag00 »

Grazie per la risposta, Ashura.
Ashura ha scritto: da quanto ho capito a te serve di poter risolvere una o piu' equazioni che non sono cablate a codice ma sono scritte in un file di testo... correggimi se sbaglio ma il tuo file di input sarebbe qualcosa del genere?

Codice: Seleziona tutto

EQ = x(4) * x(1) * pmi + x(3) - x(2) - a - b*x(4)*x(1) - pmec
EQ1 = SQRT( Ta / x(5) ) * x(3) / pa - x(4)
x = 5
pmi = 3
a = 1
b = 2
pmec = 12
Ta = 4
pa = 10
No, nelle mie intenzioni il file di input dovrebbe contenere solo delle stringhe da me scelte che identificano le equazioni e le incognite che verranno riconosciute internamente dal programma. Le equazioni saranno già cablate a codice come module procedures nel modulo modificato indicato nel mio primo post. È qualcosa di un po' più semplice di quello che tu, più elegantemente, proponi. Ad esempio nel seguente input file definisco due equazioni e due incognite

Codice: Seleziona tutto

eq_pmec_compl
eq_sqrt
unk_pu
unk_ps
x = 5
pmi = 3
a = 1
b = 2
pmec = 12
Ta = 4
pa = 10
con un select case (ad esempio) faccio l'associazione tra la stringa e l'equazione o l'incognita e assegno i valori ai parametri (x, pmi, a, b, pmec, Ta, pa, nel nostro caso). Il problema che non so risolvere è come praticamente effettuare l'associazione con le funzioni corrispondenti (magari in modo da evitare un select case ad ogni chiamata della funcv di cui al primo messaggio).

La tua soluzione è molto più elegante e versatile, darò un'occhiata ai tuoi riferimenti, grazie! Tuttavia suppongo ci sia una maniera più semplice per risolvere il mio problema.
Ultima modifica di epag00 il martedì 23 marzo 2010, 20:15, modificato 1 volta in totale.
If you shake my hand better count your fingers (D. Mustaine)
Ashura
Prode Principiante
Messaggi: 199
Iscrizione: venerdì 13 ottobre 2006, 9:55

Re: Selezionare un sub-set di funzioni "at runtime".

Messaggio da Ashura »

epag00 ha scritto: Grazie per la risposta, Ashura.
Ashura ha scritto: da quanto ho capito a te serve di poter risolvere una o piu' equazioni che non sono cablate a codice ma sono scritte in un file di testo... correggimi se sbaglio ma il tuo file di input sarebbe qualcosa del genere?

Codice: Seleziona tutto

EQ = x(4) * x(1) * pmi + x(3) - x(2) - a - b*x(4)*x(1) - pmec
EQ1 = SQRT( Ta / x(5) ) * x(3) / pa - x(4)
x = 5
pmi = 3
a = 1
b = 2
pmec = 12
Ta = 4
pa = 10
No, nelle mie intenzioni il file di input dovrebbe contenere solo delle stringhe da me scelte che identificano le equazioni e le incognite che verranno riconosciute internamente dal programma. Le equazioni saranno già cablate a codice come module procedures nel modulo modificato indicato nel mio primo post. È qualcosa di un po' più semplice di quello che tu, più elegantemente, proponi. Ad esempio nel seguente input file definisco due equazioni e due incognite

Codice: Seleziona tutto

eq_pmec_compl
eq_sqrt
unk_pu
unk_ps
x = 5
pmi = 3
a = 1
b = 2
pmec = 12
Ta = 4
pa = 10
con un select case (ad esempio) faccio l'associazione tra la stringa e l'equazione o l'incognita e assegno i valori ai parametri (x, pmi, a, b, pmec, Ta, pa, nel nostro caso). Il problema che non so risolvere è come praticamente effettuare l'associazione con le funzioni corrispondenti (magari in modo da evitare un select case ad ogni chiamata della funcv di cui al primo messaggio).

La tua soluzione è molto più elegante e versatile, darò un'occhiata ai tuoi riferimenti, grazie! Tuttavia suppongo ci sia una maniera più semplice per risolvere il mio problema.
ah ho capito :)
beh non conosco il Fortran pero' puoi utilizzare un array associativo ( o dizionario, o mappa )
ovvero qualcosa che mappi una stringa ( quindi il nome della tua equazione ) al puntatore a funzione corrispondente
ecco un esempio in pseudo codice

Codice: Seleziona tutto


// Definizione delle procedure
result solve_eq_pmec_compl(params);
result solve_eq_sqrt(params);

// definisci l'array associativo 
var func_map<string, void(*pfunc)(params)>();
func_map["eq_pmec_compl"] = solve_eq_pmec_compl;
func_map["eq_sqrt"] = solve_eq_sqrt;

// leggi le funzioni da eseguire da file di input
var funcs = read_funcs_from_input_file();

// leggi i parametri dal file di input
var my_params = read_params_from_input_file();

// chiama le varie funzioni
foreach( func_name, funcs )
{
     func_map[func_name](my_params);
}
puo' esserti d'aiuto ?:) Non ho idea di come si dichiarino puntatori a funzione in Fortran, ma e' sicuramente possibile
Avatar utente
epag00
Prode Principiante
Messaggi: 186
Iscrizione: sabato 29 dicembre 2007, 22:41

Re: Selezionare un sub-set di funzioni "at runtime".

Messaggio da epag00 »

Ashura ha scritto: puo' esserti d'aiuto ?:) Non ho idea di come si dichiarino puntatori a funzione in Fortran, ma e' sicuramente possibile
Certo che mi sei stato di grande aiuto, Ashura! Grazie.

Mi sono assentato un po' per chiarirmi meglio le idee sui puntatori a procedure in Fortran. Effettivamente questa caratteristica è stata inclusa nello standard 2003 che gfortran (il compilatore GNU) non implementa ancora in maniera completa nell'ultima versione stabile. Quel che è peggio è che sembra (sto ancora investigando) che lo standard non preveda la definizione di vettori di puntatori a procedure; quel che serve al mio caso.

Il compilatore-fork g95 permette l'uso di procedure pointers, ma (come dicevo prima) non posso definire vettori di puntatori a funzione. Se includo in una struct il puntatore a procedura e poi ne creo un vettore, ho problemi nella fase di assegnazione del puntatore per altre limitazioni legate al linguaggio (nel caso posso dettagliare).

La mia curiosità è la seguente: nel C come si definisce un vettore di puntatori a funzione?

Grazie, ciao.
If you shake my hand better count your fingers (D. Mustaine)
Ashura
Prode Principiante
Messaggi: 199
Iscrizione: venerdì 13 ottobre 2006, 9:55

Re: Selezionare un sub-set di funzioni "at runtime".

Messaggio da Ashura »

in C un puntatore a funzione si definisce nel seguente modo

( esempio di un metodo che ritorna un intero e accetta un double )

typedef int(*MY_PROC_NAME) (double);

in questo modo utilizzando l'identificativo "MY_PROC_NAME" all'interno del mio programma indico un puntatore ad una funzione ( che accetta un double e restituisce un intero )

se voglio farne un vettore ( o array )

MY_PROC_NAME myArray[10];

in questo modo ho definito un array di 10 puntatori a funzione.
ovviamente in C tutti gli elementi di un array devono avere lo stesso tipo, quindi tutti i puntatori a funzione
devono avere lo stesso prototipo ( i.e. non posso mettere in un array C un puntatore a funzione che accetta un double e un puntatore a funzione che accetta un int )
Avatar utente
epag00
Prode Principiante
Messaggi: 186
Iscrizione: sabato 29 dicembre 2007, 22:41

Re: Selezionare un sub-set di funzioni "at runtime".

Messaggio da epag00 »

Ashura, grazie ancora.

In realtà anche nel Fortran 2003 si definisce in maniera molto simile un vettore di puntatori a funzione (con un tipo di variabile definita dal programmatore). Dopo tanto travagliare, alla fine ho capito che prima commettevo un errore sintattico. Mi riferisco a questa frase
epag00 ha scritto: Se includo in una struct il puntatore a procedura e poi ne creo un vettore, ho problemi nella fase di assegnazione del puntatore per altre limitazioni legate al linguaggio (nel caso posso dettagliare).
Almeno per quello che riguarda la compilazione, adesso funziona. Appena avrò un po' di tempo, devo ripulire un po' il codice, rifinirlo un attimo e lanciare un primo test drive. Magari faccio comunque sapere l'esito o propongo qualche altro dubbio.

Grazie di nuovo, per ora! (b2b)

(ot) che peccato sia così poco diffuso il Fortran...mi dovrò, prima o poi, decidere ad imparare seriamente il C.
If you shake my hand better count your fingers (D. Mustaine)
Avatar utente
epag00
Prode Principiante
Messaggi: 186
Iscrizione: sabato 29 dicembre 2007, 22:41

Re: Selezionare un sub-set di funzioni "at runtime".

Messaggio da epag00 »

Confermo che con il Fortran 2003 è possibile conseguire l'obiettivo. Un grande grazie ad Ashura per il supporto! (good)

Ci sono due opzioni per effettuare la selezione di equazioni e incognite a tempo di esecuzione, entrambe non prescindono dall'uso di puntatori a procedure che sono state incluse nello standard 2003. Le possibilità sono
  • un vettore di puntatori (alla funzione e/o alle incognite);
  • una lista collegata di puntatori (a funzione e/o alle incognite).
A livello prestazionale (almeno con g95) non sembrerebbero esserci differenze significative; per la "pulizia" e semplicità del codice sto propendendo per la prima ipotesi sia per le equazioni che per le incognite. Spero di fare la scelta giusta, visto che quando complicherò il programma mi peserebbe un po' dover tornare sui miei passi.

Eventuali suggerimenti sulla scelta fra le due possibilità sono sempre ben accetti (considerando che non uso delle librerie apposite per la gestione delle liste collegate)!

Ciao.
If you shake my hand better count your fingers (D. Mustaine)
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: 0 utenti iscritti e 4 ospiti