In de context van programmaverificatie is het niet voldoende om alleen de juistheid van de eindresultaten van een programma te garanderen. Het is even belangrijk om te zorgen voor de algehele correctheid van het programma, wat niet alleen betrekking heeft op de juistheid van de uitvoer, maar ook op de uitvoering zelf en de beëindiging van een programma. Dit concept wordt de "volledige correctheid" genoemd. Het combineren van partiële correctheid en terminatie leidt tot een formalisatie die volledig deugdelijk is. De weak precondition calculus is één manier om deze volledige correctheid te waarborgen, door zowel de voorwaardelijke juistheid van programma's als hun correcte beëindiging in overweging te nemen.
In Figuur 8.7 wordt een uitbreiding van de weakest precondition calculus gepresenteerd die volledige correctheid waarborgt. Deze uitbreiding is nodig om de terminatie van een programma te garanderen. De weakest precondition calculus biedt een formeel kader om de voorwaardelijke juistheid van een programma te analyseren, gegeven een vooraf gedefinieerde preconditie en postconditie . Voor opdrachten zoals toewijzingen en conditionele structuren is deze uitbreiding eenvoudig: we moeten de goedgedefinieerdheidsformule van de geëvalueerde termen toevoegen aan de preconditie.
Echter, wanneer we te maken hebben met luscommando’s, wordt het ingewikkelder. Hier moeten we naast de standaard weakest precondition-formule een universeel gekwantificeerde voorwaarde toevoegen die verzekert dat de lusvoorwaarde altijd goed gedefinieerd blijft en dat de terminatiemaat niet-negatief is voor elke iteratie. Bovendien is het noodzakelijk om te verifiëren dat de invariant tijdens elke iteratie van de lus behouden blijft, terwijl steeds afneemt. Dit wordt vastgelegd in de formule waarin de waarde van de terminatiemaat in de vorige toestand van de lusiteratie vertegenwoordigt.
Wanneer we de volledige juistheid van een Hoare-tripel willen verifiëren, is het voldoende om de geldigheid van de formule te bevestigen, zoals gesteld in Propositie 8.9. Dit betekent dat we met de weakest precondition calculus kunnen aantonen dat, als een programma in een staat start die voldoet aan , het normaal zal eindigen in een staat die voldoet aan de postconditie .
Echter, het gebruik van strongest postcondition of commando’s als relaties in plaats van weakest preconditions kan problemen opleveren. In gevallen waarbij een programma niet normaal beëindigt, zouden de weakest preconditions een onverenigbare voorwaarde (bijvoorbeeld “false”) opleveren, wat impliceert dat de volledige correctheid van de Hoare-tripel niet kan worden afgeleid. Aan de andere kant zouden sterke postcondities in zulke gevallen een triviaal waarneembare postconditie opleveren, wat programma’s die niet eindigen normaal, onterecht gelijkstelt aan programma’s die wel eindigen maar geen specifieke overgangsvoorwaarden hebben. Dit is een onbruikbare oplossing voor het verifiëren van volledige correctheid.
Daarom wordt een nieuwe calculus geïntroduceerd, die specifiek is ontworpen om de normale beëindiging van een commando te verifiëren, onafhankelijk van de partiële juistheid. Twee varianten van deze calculus zijn voorgesteld: één met de uitspraak en één met de uitspraak . Beide wijzen erop dat een programma , wanneer het start in een toestand die voldoet aan preconditie , normaal zal eindigen, zonder dat we de partiële correctheid hoeven te verifiëren. Dit is van groot belang voor het verifiëren van programma’s die lussen bevatten, omdat het ons in staat stelt te controleren of een lus al dan niet beëindigt.
De calculus voor is gericht op het controleren of een gegeven preconditie voldoende sterk is om de normale beëindiging van te waarborgen. Dit is nuttig wanneer we willen bevestigen dat een gegeven programma eindigt onder bepaalde voorwaarden. De calculus voor daarentegen is ontworpen om een voldoende sterke preconditie te construeren die de beëindiging van het programma garandeert. Dit is handig wanneer we willen bepalen welke voorwaarden moeten worden voldaan om te zorgen dat een programma daadwerkelijk eindigt.
Wat hierbij belangrijk is, is dat beide calculus-systemen fundamenteel met elkaar verbonden zijn. De calculus voor is een natuurlijke aanvulling op de strongest postcondition calculus, terwijl de calculus voor een aanvulling is op de weakest precondition calculus. Beide calculi helpen bij het verifiëren van de volledige correctheid van een Hoare-tripel , maar de manier waarop ze de preconditie behandelen, verschilt. In de regel voor luscommando’s levert de calculus voor de lusinvariant op, die aangeeft dat moet worden gehandhaafd in de preconditie van de lus. De overige vereisten voor de invariant en de terminatie moeten worden gecontroleerd in de veronderstellingen van de regel, als afzonderlijke verificatievoorwaarden.
Wat hier cruciaal is om te begrijpen, is dat de juiste ontwikkeling van lusinvarianten en terminatiematen essentieel is voor het succes van deze verificaties. In de praktijk is het ontwikkelen van geschikte lussenvarianten vaak de grootste uitdaging. De keuze van een geschikte invariant kan het verschil maken tussen een programma dat succesvol geverifieerd kan worden en een programma dat niet voldoet aan de noodzakelijke voorwaarden voor terminatie.
De praktijk van computervaardige verificatie is intussen al in staat om veel concrete programma’s te verifiëren, maar de concepten van loop invariants en terminatiematen blijven centraal in het verificatieproces. Gezien de complexiteit van deze verifiëring, vooral bij programma’s met lussen, is het gebruik van deze calculi onmisbaar.
Hoe de Taal van de Logica Werkt: Een Basisbegrip van Formules en Termen
In de taal van de logica zijn er twee hoofdsoorten van syntactische zinnen: termen en formules. Deze termen en formules zijn de bouwstenen van logische redeneringen en helpen bij het uitdrukken van waarheden over objecten binnen een gegeven domein. We zullen eerst de informele interpretatie van termen en formules verkennen, gevolgd door hoe we deze structuren kunnen toepassen in formele logische beweringen.
Een term wordt geïnterpreteerd als een object of waarde binnen een specifiek domein. In de informele logica kan een term een variabele, constante of een functieaanroep zijn. Bijvoorbeeld, de waarde van een variabele V hangt af van de context waarin het wordt geëvalueerd, die meestal wordt ingesteld door een kwantificeerder die de variabele introduceert. Een constante CS verwijst naar een vaste waarde, zoals het getal 0 in een numeriek systeem. Wanneer een functie wordt toegepast, zoals de functie + in de term x + 1, betekent dit dat we de waarden van de termen x en 1 gebruiken om een nieuw resultaat te berekenen, namelijk de som van de twee getallen. Daarnaast komt de let term in het spel, zoals let V = T1 in T2, wat aangeeft dat de waarde van T2 wordt berekend met de waarde van V gelijk aan T1. De voorwaarde if F then T1 else T2 gaat verder door de waarde van T1 te geven wanneer de formule F waar is, en de waarde van T2 wanneer F onwaar is.
In de natuurlijke taal worden deze termen gerepresenteerd door zelfstandige naamwoorden en naamwoordgroepen. Bijvoorbeeld, de naam "Mary" komt overeen met de constante Mary, de uitdrukking "de moeder van Mary" komt overeen met de toepassing mother(Mary) van de uniaire functie mother, en de zin "als zij minstens 18 jaar is, dan zijzelf, anders haar moeder" kan worden uitgedrukt als de voorwaardelijke term if age(she) ≥ 18 then she else mother(she).
Een formule, aan de andere kant, vertegenwoordigt een uitspraak over objecten en hun relaties die waar of onwaar kan zijn. De formuleringen van formules volgen bepaalde logische structuren, zoals waar en onwaar als logische constanten, of predikaten die de waarheidswaarde van een uitspraak aangeven. Een voorbeeld is de formule T1 = T2, die waar is als en alleen als de termen T1 en T2 dezelfde waarde aanduiden. Negatie (¬F) betekent dat de formule F alleen waar is als F onwaar is. Een conjunctie (F1 ∧ F2) is waar als zowel F1 als F2 waar zijn, terwijl een disjunctie (F1 ∨ F2) waar is als ten minste één van de formules waar is. Een implicatie (F1 ⇒ F2) is alleen onwaar als F1 waar is en F2 onwaar is.
De verschillende soorten formules kunnen ook worden gekwantificeerd. Een universele kwantificatie ∀V. F betekent dat de formule F waar is voor elke mogelijke waarde van de variabele V. Een existentiële kwantificatie ∃V. F betekent dat er ten minste één waarde van V is waarvoor de formule F waar is. De voorwaardelijke structuur if F then F1 else F2 geeft de waarheidswaarde van F1 als F waar is, en de waarheidswaarde van F2 als F onwaar is.
In de natuurlijke taal kunnen we zinnen vormen die de formules representeren. De zin “Voor alle paren van personen is het waar dat als de eerste persoon de zus is van de tweede, de tweede persoon de broer of zus is van de eerste” komt overeen met de formule ∀x ∀y. isSister(x, y) ⇒ isSister(y, x) ∨ isBrother(y, x). Deze vertaling van natuurlijke taal naar formele logica maakt het mogelijk om complexe redeneringen te structureren en te analyseren met behulp van abstracte symbolen en regels.
Het is van belang te realiseren dat de betekenis van een implicatie, bijvoorbeeld F1 ⇒ F2, in de logica iets anders is dan in de alledaagse taal. In de logica is een implicatie alleen onwaar wanneer de eerste bewering waar is en de tweede onwaar. Dus, een uitspraak als "Als het regent, blijf ik thuis" is niet noodzakelijk onwaar als het niet regent, zelfs als de consequentie van de uitspraak ("ik blijf thuis") niet waar is.
Deze informele interpretaties van termen en formules zijn essentieel om de werking van logica in de praktijk te begrijpen. Ze bieden een brug tussen formele systemen en de manier waarop we in het dagelijks leven redeneren over waarheden en relaties. Het is cruciaal om te begrijpen dat formules niet alleen symbolen zijn; ze vertegenwoordigen waarheden die kunnen worden getest tegen de werkelijkheid.
Hoe Zorgen We Voor de Termination van Programma's in Relationele Semantiek?
In de context van programma-analyse is het van essentieel belang om te begrijpen hoe de execution van een programma verloopt en wat de voorwaarden zijn voor het voorkomen van abortus of voor het verzekeren van de beëindiging van een programma. Dit heeft direct te maken met het concept van "relational semantics" die de manier beschrijft waarop een programma of een commando uitgevoerd wordt zonder onverwachte onderbrekingen of eindeloze lussen. Een cruciaal punt hierbij is het begrijpen van de vertaling van programma's en commando's naar statussen en condities die de uitvoering ervan bepalen.
Wanneer we bijvoorbeeld het programma [ 𝑃 ]✓ ⟨vs⟩ beschouwen, waarbij 𝑃 een programma is en ⟨vs⟩ een reeks van parameters, kunnen we zeggen dat dit programma altijd zal eindigen zonder te aborteren. Dit geldt bijvoorbeeld voor een programma waarin de uitvoering zonder uitzonderingen plaatsvindt, zoals een programma waarin elke stap goed gedefinieerd en geëvalueerd wordt. In tegenstelling tot een programma als 'mayabort', waarin de mogelijkheid bestaat dat het programma kan stoppen afhankelijk van de uitvoeringscondities, garandeert de relational semantics van een programma als [ 𝑃 ]✓ ⟨vs⟩ de voorspelbare uitvoering zonder onverwachte stops.
Het concept van loops in programma's wordt een stuk ingewikkelder, vooral als het gaat om het verzekeren van hun beëindiging. Een belangrijk aspect hierbij is het loopmechanisme, zoals geïllustreerd in de definitie van "State Sequence of a Loop". Dit concept legt uit dat een lus met een bepaalde voorwaarde (zoals de "while"-lus) meerdere staten doorloopt totdat de voorwaarde niet meer waar is. Als de lus bijvoorbeeld altijd blijft draaien omdat de voorwaarde nooit onwaar wordt, is de verwachting van de relational semantics dat er een eindeloze staatsequentie zou kunnen optreden, wat uiteindelijk leidt tot een non-terminerende situatie.
Een bekend voorbeeld hiervan is het programma 'mayloop(x:Nat)', waarin een lus met de voorwaarde 'x = 0' eindeloos kan blijven draaien als de lokale variabele altijd wordt hersteld naar de waarde 0. In dit geval beschrijft de relationele semantiek alleen het aspect van het programma dat het mogelijk is dat het zich eindeloos herhaalt, maar het maakt geen specifieke uitspraak over de mogelijkheid dat het programma daadwerkelijk eindigt. Dit maakt 'mayloop' moeilijk te onderscheiden van een programma zoals 'choose(x:Nat)', dat altijd een eindresultaat produceert, ongeacht de omstandigheden.
Om dit probleem van niet-termineren te adresseren, wordt de conceptuele benadering van de "State Sequence of a Loop" geïntroduceerd. Deze benadering helpt bij het bepalen of een lus daadwerkelijk eindigt of niet door de sequentie van staten die zich tijdens de uitvoeringen van de lus voordoen te volgen. Dit stelt ons in staat om te bepalen of een lus kan eindigen, en zo ja, onder welke omstandigheden. De kern van dit mechanisme is het idee dat er een eindige staatsequentie moet zijn die leidt tot een eindresultaat, zonder dat er sprake is van een eindeloze herhaling van stappen.
In de formele semantiek van programma's worden verschillende voorwaarden en vertalingen gedefinieerd om de beëindiging van commando's en programma's te garanderen. Bijvoorbeeld, de vertaling van een commando als ⟨⟨𝐶⟩⟩ ⟨𝑠⟩ maakt gebruik van de definitie dat er altijd een eindtoestand 𝑠′ moet zijn, die wordt bereikt na de uitvoering van het commando 𝐶, en dit moet gelden voor elke mogelijke begintoestand 𝑠. Dit principe wordt verder versterkt door de "Termination" voorwaarden die precies aangeven onder welke omstandigheden een commando of programma daadwerkelijk beëindigt.
Er zijn echter nog meer nuances die de lezer moet begrijpen bij het werken met dergelijke formele systemen. Het is belangrijk om in gedachten te houden dat de relatie tussen commando's en hun uitvoeringscondities vaak impliciete veronderstellingen bevat over de beschikbaarheid van benodigde staten en waarden. Deze veronderstellingen moeten correct worden geïdentificeerd en begrepen om te voorkomen dat een programma onverwachte gedragingen vertoont of vastloopt in een loop zonder terminatie.
Bovendien is het essentieel om de invloed van variabele toewijzingen en de mogelijke interacties tussen verschillende commando's en lussen te begrijpen. De toewijzing van een waarde aan een variabele kan de status van een programma significant veranderen, vooral als die variabele later wordt gebruikt in een lus of conditionele structuur. Het is noodzakelijk om te begrijpen hoe deze dynamische interacties de uitvoering van een programma kunnen beïnvloeden, en hoe de formele vertalingen helpen om deze effecten in de staatsequenties vast te leggen.
In veel gevallen helpt een formele semantiek om de betrouwbaarheid en voorspelbaarheid van programma's te waarborgen, maar het vereist zorgvuldige aandacht voor detail en begrip van de onderliggende wiskundige modellen die de uitvoering van programma's beschrijven. Dit biedt een solide basis voor het ontwerpen van robuuste programma's die gegarandeerd correct functioneren zonder onbedoelde abortus of eindeloze loops.
Hoe kan nanotechnologie bijdragen aan duurzame milieuremediatie?
Hoe slimme irrigatiesystemen bijdragen aan duurzame landbouw via IoT en machine learning
Hoe functioneren de kerncomponenten van On-Board Data Handling in satellieten?
Regeling voor de verstrekking van maaltijden aan leerlingen van Openbare Middelbare School Nr. 2 in de stad Makarjev, district Makarjev, regio Kostroma
Bevel d.d. "31" januari 2015 nr. 54/v Goedkeuring van de regeling voor het afnemen van examens in de Russische taal, de geschiedenis van Rusland en de basiswetgeving van de Russische Federatie
Lesrooster voor Chemie: Overzicht van de Belangrijkste Concepten en Wetenschappen
Fasen van het werk aan het project

Deutsch
Francais
Nederlands
Svenska
Norsk
Dansk
Suomi
Espanol
Italiano
Portugues
Magyar
Polski
Cestina
Русский