Correttezza del programma, le specifiche


17

Da Wikipedia: Nell'informatica teorica si afferma la correttezza di un algoritmo quando si dice che l'algoritmo è corretto rispetto a una specifica.

Ma il problema è che ottenere la specifica "appropriata" non è un compito banale e non esiste un metodo corretto al 100% (per quanto ne so) per ottenere quello giusto, è solo una stima, quindi se vogliamo prendere un predicato come una specifica solo perché "sembra" come "quello", perché non prendere il programma come giusto solo perché "sembra" corretto?


2
Perché si spera che la specifica sia meno complicata del programma, quindi avrà meno errori del programma.
user253751

1
Si noti che un sistema di tipi è una forma di specifica: possiamo usarlo per dimostrare alcune proprietà non banali dei programmi. Più ricco è il sistema di tipi, più forti sono le proprietà che siamo in grado di dimostrare.
gardenhead

@immibis ma se ha un solo errore, tutto è sbagliato
Maykel Jakson,

@MaykelJakson Vero ... Una volta ho messo una contraddizione in un assioma in Rodin per errore (quello che stavo cercando di fare era corretto ma la sintassi era sbagliata). Mi ci è voluto un po 'di "hmm il pro-prover sembra funzionare insolitamente bene in questo momento" prima che me ne accorgessi.
user253751

Risposte:


30

Prima di tutto, hai assolutamente ragione: hai una vera preoccupazione. La verifica formale trasferisce il problema della fiducia nella correttezza del programma al problema della fiducia nella correttezza delle specifiche, quindi non è un proiettile d'argento.

Tuttavia, ci sono diversi motivi per cui questo processo può essere ancora utile.

  1. Le specifiche sono spesso più semplici del codice stesso. Ad esempio, considera il problema dell'ordinamento di un array di numeri interi. Esistono algoritmi di ordinamento abbastanza sofisticati che fanno cose intelligenti per migliorare le prestazioni. Ma la specifica è abbastanza semplice da affermare: l'output deve essere in ordine crescente e deve essere una permutazione dell'ingresso. Pertanto, è probabilmente più facile acquisire fiducia nella correttezza delle specifiche piuttosto che nella correttezza del codice stesso.

  2. Non esiste un singolo punto di errore. Supponiamo che una persona scriva una specifica e un'altra persona scriva il codice sorgente, quindi verifica formalmente che il codice soddisfi la specifica. Quindi qualsiasi difetto non rilevato dovrebbe essere presente sia nella specifica che nel codice. In alcuni casi, per alcuni tipi di difetti, questo sembra meno probabile: è meno probabile che si trascuri il difetto quando si ispezionano le specifiche e si trascuri il difetto quando si ispeziona il codice sorgente. Non tutti, ma alcuni.

  3. Le specifiche parziali possono essere notevolmente più semplici del codice. Ad esempio, considerare il requisito che il programma sia privo di vulnerabilità di sovraccarico del buffer. Oppure, il requisito che non vi siano errori fuori limite dell'indice di array. Questa è una semplice specifica che è ovviamente una cosa buona e utile da dimostrare. Ora puoi provare a utilizzare metodi formali per dimostrare che l'intero programma soddisfa questa specifica. Potrebbe essere un compito abbastanza complicato, ma se hai successo, acquisisci maggiore fiducia nel programma.

  4. Le specifiche potrebbero cambiare meno frequentemente del codice. Senza metodi formali, ogni volta che aggiorniamo il codice sorgente, dobbiamo verificare manualmente che l'aggiornamento non introduca alcun bug o difetto. I metodi formali possono potenzialmente ridurre questo onere: supponiamo che le specifiche non cambino, in modo che gli aggiornamenti del software comportino solo modifiche al codice e non modifiche alle specifiche. Quindi per ogni aggiornamento, sei sollevato dall'onere di verificare se la specifica è ancora corretta (non è cambiata, quindi non vi è alcun rischio che siano stati introdotti nuovi bug nelle specifiche) e dell'onere di verificare se il codice è ancora corretto (il verificatore del programma lo controlla per te). Devi ancora verificare che le specifiche originali siano corrette, ma non devi continuare a controllarle ogni volta che uno sviluppatore commette una nuova patch / aggiornamento / modifica.

Infine, ricorda che le specifiche in genere sono dichiarative e non possono necessariamente essere eseguite né compilate direttamente in codice. Ad esempio, considera di nuovo l'ordinamento: la specifica dice che l'output è in aumento ed è una permutazione dell'input, ma non esiste un modo ovvio per "eseguire" direttamente questa specifica e nessun modo ovvio per un compilatore di compilarlo automaticamente in codice. Quindi, prendere le specifiche come corrette ed eseguirle spesso non è un'opzione.

Tuttavia, la linea di fondo rimane la stessa: i metodi formali non sono una panacea. Trasferiscono semplicemente il problema (molto difficile) della fiducia nella correttezza del codice al problema (semplicemente difficile) della fiducia nella correttezza delle specifiche. I bug nelle specifiche sono un rischio reale, sono comuni e non possono essere trascurati. In effetti, la comunità dei metodi formali talvolta separa il problema in due parti: la verifica riguarda la garanzia che il codice soddisfi le specifiche; la convalida consiste nel garantire che le specifiche siano corrette (soddisfa le nostre esigenze).

Potresti anche goderti la verifica formale del programma in pratica e perché non stiamo ricercando di più verso garanzie di compilazione? per più prospettive con qualche influenza su questo.


A parte questo, quando una specifica diventa più dettagliata, aumenta la probabilità che possa essere scritta come pseudocodice. Usando il tuo esempio di ordinamento, una versione più dettagliata di "l'output deve essere in ordine crescente" sarebbe "ogni numero intero nell'output, dopo il primo, deve essere maggiore del numero precedente". Questo, a sua volta, può essere facilmente scritto come qualcosa come for each integer I<sub> N</sub> in set S (where N > 1) { assert I<sub> N</sub> > I<sub> N - 1</sub> }. Non sicuro al 100% della notazione.
Justin Time - Ripristina Monica il

Quindi, una buona specifica può anche aiutare a creare il codice, non solo a verificarlo.
Justin Time - Ripristina Monica il

1
Il modo ovvio per eseguire le specifiche di ordinamento è enumerare tutte le permutazioni dell'input e scegliere quella ordinata. Il problema con questo , tuttavia, dovrebbe essere chiaro ...
Derek Elkins lasciò SE il

19

La risposta di DW è ottima , ma vorrei espandermi su un punto. Una specifica non è solo un riferimento rispetto al quale viene verificato il codice. Uno dei motivi per avere una specifica formale è convalidarlo dimostrando alcune proprietà fondamentali. Naturalmente, la specifica non può essere completamente convalidata: la convalida sarebbe complessa come la specifica stessa, quindi sarebbe un processo senza fine. Ma la convalida ci consente di ottenere una garanzia più forte su alcune proprietà critiche.

Ad esempio, supponiamo che stai progettando un pilota automatico per auto. Questa è una cosa piuttosto complessa che coinvolge molti parametri. Le proprietà di correttezza dell'autopilota includono cose come "l'auto non si schianterà contro un muro" e "l'auto guiderà dove gli viene detto di andare". Una proprietà come "l'auto non si schianterà contro un muro" è davvero molto importante, quindi vorremmo dimostrarlo. Poiché il sistema funziona nel mondo fisico, dovrai aggiungere alcuni vincoli fisici; la proprietà effettiva del sistema computazionale sarà qualcosa del tipo "in base a questi presupposti riguardanti la scienza dei materiali e questi presupposti riguardanti la percezione degli ostacoli da parte dei sensori dell'auto, l'auto non si schianterà contro un muro". Ma anche così, il risultato è una proprietà relativamente semplice che è chiaramente desiderabile.

Potresti provare questa proprietà dal codice? In definitiva, è quello che sta succedendo, se stai seguendo un approccio completamente formale¹. Ma il codice ha molte parti diverse; i freni, le telecamere, il motore, ecc. sono tutti controllati autonomamente. Una proprietà di correttezza dei freni sarebbe qualcosa del tipo "se il segnale" applica freni "è attivo, allora i freni vengono applicati". Una proprietà di correttezza del motore sarebbe "se il segnale della frizione è spento, allora il motore non sta guidando le ruote". Ci vuole una visione di altissimo livello per metterli tutti insieme. Una specifica crea uno strato intermedio in cui i diversi componenti del sistema possono essere articolati insieme.

In effetti, un sistema così complesso come un pilota automatico per auto avrebbe diversi livelli di specifiche con quantità variabili di perfezionamenti. Nel progetto viene spesso utilizzato un approccio di perfezionamento: iniziare con alcune proprietà di alto livello come "l'auto non si schianterà contro un muro", quindi capire che ciò richiede sensori e freni e elaborare alcuni requisiti di base per i sensori, i freni e il software pilota, quindi perfezionare nuovamente quei requisiti di base in un progetto del componente (per il sensore, avrò bisogno di un radar, un DSP, una libreria di elaborazione delle immagini, ...), ecc. In un processo di sviluppo formale, ogni livello di specifica ha dimostrato di soddisfare i requisiti stabiliti dal livello sopra di esso, dalle proprietà di livello più alto fino al codice.

È impossibile essere sicuri che le specifiche siano corrette. Ad esempio, se hai sbagliato la fisica, i freni potrebbero non essere efficaci anche se la matematica che collega il codice freno ai requisiti formali è corretta. Non serve dimostrare che le rotture sono efficaci con 500 kg di carico se si hanno effettivamente 5000 kg. Ma è più facile vedere che 500 kg sono sbagliati che vedere all'interno del codice dei freni che non saranno abbastanza buoni per i parametri fisici della macchina.

¹ Il contrario di un approccio completamente formale è "Immagino che funzioni, ma non posso esserne sicuro". Quando ci scommetti la vita, non sembra così bello.


È possibile dimostrare solo una proprietà del mio codice e assicurarmi che sia sempre corretta, ad esempio voglio solo dimostrare che l'indice di un array non è mai al di fuori del limite dell'array e non mi interessa l'altra roba?
Maykel Jakson,

5
@MaykelJakson Sure! Lo usi solo come tua specifica. Probabilmente è una specifica debole, ma nulla ti impedisce di usarlo e usa metodi formali per dimostrarlo.
chi
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.