Quali strategie di programmazione posso prendere per modificare facilmente i parametri dell'algoritmo?


17

Lo sviluppo di algoritmi scientifici è un processo altamente iterativo che comporta spesso la modifica di numerosi parametri che vorrò variare sia come parte del mio progetto sperimentale sia come parte delle modifiche dell'algoritmo. Quali strategie posso prendere per strutturare questi parametri in modo da poterli facilmente cambiare tra le iterazioni e in modo da poterne aggiungere facilmente di nuovi?

Risposte:


14

È ingombrante per l'utente specificare ogni aspetto di un algoritmo. Se l'algoritmo consente componenti nidificati, non sarebbe sufficiente un numero finito di opzioni. Pertanto, è fondamentale che le opzioni non si "appagino" al massimo livello, come nel caso di argomenti espliciti o parametri del modello. Questo è talvolta chiamato "problema di configurazione" nell'ingegneria del software. Credo che PETSc abbia un sistema straordinariamente potente per la gestione della configurazione. È simile al modello di Service Locator nel saggio di Martin Fowler sull'inversione del controllo .

Il sistema di configurazione di PETSc funziona attraverso una combinazione di configurazione specificata dall'utente gestita dagli oggetti del risolutore (con query get e set) e dal database delle opzioni. Qualsiasi componente della simulazione può dichiarare un'opzione di configurazione, un valore predefinito e un luogo in cui inserire il risultato. Gli oggetti nidificati hanno prefissi che possono essere composti, in modo tale che ogni oggetto che necessita di configurazione possa essere indirizzato in modo indipendente. Le opzioni stesse possono essere lette dalla riga di comando, dall'ambiente, dai file di configurazione o dal codice. Quando viene dichiarata un'opzione, vengono specificate una stringa di aiuto e una pagina man, in modo che l' -helpopzione sia comprensibile e che sia possibile scrivere una GUI correttamente collegata.

L'utente chiama un SetFromOptionsmetodo per configurare un oggetto in base alle opzioni della riga di comando. La chiamata a questa funzione è facoltativa e non può essere chiamata se l'utente (persona che scrive codice che chiama PETSc) sta esponendo le opzioni attraverso un'altra interfaccia. Raccomandiamo vivamente che l'utente esponga il database delle opzioni perché fornisce all'utente finale (persona che esegue l'applicazione) una grande potenza, ma non è necessario.

Una configurazione tipica, chiamata via

PetscObjectOptionsBegin(object); /* object has prefix and descriptive string */
PetscOptionsReal("-ts_atol",                                      /* options database key */
                 "Absolute tolerance for local truncation error", /* long description */
                 "TSSetTolerances",                               /* function and man page on topic */
                  ts->atol,                                       /* current/default value *?
                  &ts->atol,                                      /* place to store value */
                  &option_set);                                   /* TRUE if the option was set */
PetscOptionsList("-ts_type","Time stepping method","TSSetType",TSList,
                 defaultType,typeName,sizeof typeName,&option_set);
TSAdaptSetFromOptions(ts->adapt);                                 /* configures adaptive controller method */
/* ... many others */
/* ... the following is only called from implicit implementations */
SNESSetFromOptions(ts->snes);                                     /* configure nonlinear solver. */
PetscOptionsEnd();

Appunti:

  • PetscOptionsList()presenta all'utente una scelta da un elenco dinamico. Esiste un'architettura plug-in che le nuove implementazioni possono utilizzare per esporsi come chiamanti di prima classe. (Queste implementazioni possono essere inserite in librerie condivise e utilizzate come prima classe senza ricompilare i programmi.)
  • SNESSetFromOptions() configura in modo ricorsivo i solutori lineari, i precondizionatori e qualsiasi altro componente che necessita di configurazione.

11

Ho riscontrato questo problema diverse volte quando ho sviluppato da zero i miei codici di simulazione: quali parametri dovrebbero andare in un file di input, che dovrebbe essere preso dalla riga di comando, ecc. Dopo alcuni esperimenti, il risultato si è rivelato efficace. (Non è avanzato come PETSc.)

Invece di scrivere un "programma" di simulazione sperimentale, sono più propenso a scrivere un pacchetto Python che contenga tutte le funzioni e le classi necessarie per eseguire la simulazione. Il file di input tradizionale viene quindi sostituito da un piccolo script Python con da 5 a 10 righe di codice. Alcune righe sono in genere correlate al caricamento di file di dati e alla specifica dell'output. Altri sono istruzioni per il calcolo effettivo. Buoni valori predefiniti per argomenti opzionali nel pacchetto Python rendono possibile per i principianti l'uso della libreria per simulazioni semplici, mentre l'utente avanzato ha ancora accesso a tutte le campane e fischietti.

Alcuni esempi:


Questo è fantastico, ma penso che sia ortogonale al problema di configurazione. Se è necessario specificare un algoritmo gerarchico o nidificato, sono disponibili opzioni per specificare molti oggetti interni. Il codice che chiama quelli non dovrebbe nemmeno sapere della loro esistenza perché il numero di livelli e i tipi di annidamento possono cambiare. Questo è il problema di tutte quelle scelte "ribollenti". Con il tuo codice Python di alto livello, puoi rendere "facile" specificare tali opzioni, ma devi comunque specificarle nel codice. Penso che in genere non sia una buona cosa.
Jed Brown,

xmonad utilizza questo metodo per configurare il proprio window manager per X.
rcollyer,

2

Come primo punto, farei l'algoritmo E il software il più generali possibile. L'ho imparato nel modo più duro.

Diciamo che inizi con un semplice test case. Puoi farlo più velocemente. Ma poi, se hai reso il software troppo specifico (troppo pochi parametri) per questo caso iniziale, perderai sempre più tempo ad adattarlo ogni volta che aggiungi un nuovo grado di libertà. Quello che faccio ora è passare più tempo all'inizio a rendere la cosa piuttosto generale e ad aumentare la variazione dei parametri mentre mi muovo in avanti.

Ciò comporta più test dall'inizio poiché avrai più parametri dal punto di partenza, ma significherà che puoi giocare molto con l'algoritmo a zero oa un costo molto basso.

Esempio: l'algoritmo prevede il calcolo dell'integrale di superficie del prodotto punto di due funzioni vettoriali. Non dare per scontato dall'inizio la dimensione, la geometria e la discretizzazione della superficie se in futuro potresti volerlo cambiare. Fai una funzione punto-prodotto, rendi la superficie il più generale possibile, calcola l'integrale in un modo formale piacevole. Puoi testare ogni funzione che esegui separatamente.

All'inizio, puoi e iniziare a integrarti con geometrie semplici e dichiarare i parametri may come costanti. Col passare del tempo, se si desidera modificare la geometria, è possibile farlo facilmente. Se avessi fatto delle ipotesi all'inizio, dovresti cambiare l'intero codice ogni volta.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.