Wiedeńska metoda rozwoju - Vienna Development Method
Metoda Development Wiedeń ( VDM ) jest jednym z najdłużej ustalonych metod formalnych dotyczących rozwoju systemów komputerowych. Wywodzi się z prac wykonanych w IBM Laboratory w Wiedniu w latach 70. XX wieku, a następnie rozrósł się do grupy technik i narzędzi opartych na formalnym języku specyfikacji — języku specyfikacji VDM (VDM-SL). Posiada rozszerzoną formę VDM++, która wspiera modelowanie systemów obiektowych i współbieżnych. Wsparcie dla VDM obejmuje komercyjne i akademickie narzędzia do analizy modeli, w tym wsparcie dla testowania i udowadniania właściwości modeli oraz generowania kodu programu ze zwalidowanych modeli VDM. Istnieje historia przemysłowego wykorzystania VDM i jego narzędzi, a rosnąca liczba badań nad formalizmem doprowadziła do znaczącego wkładu w inżynierię systemów krytycznych, kompilatorów , systemów współbieżnych oraz logiki dla informatyki .
Filozofia
Systemy obliczeniowe mogą być modelowane w VDM-SL na wyższym poziomie abstrakcji niż jest to osiągalne przy użyciu języków programowania, co pozwala na analizę projektów i identyfikację kluczowych cech, w tym defektów, na wczesnym etapie rozwoju systemu. Zweryfikowane modele można przekształcić w szczegółowe projekty systemu w procesie udoskonalania. Język ma semantykę formalną, umożliwiającą udowodnienie właściwości modeli na wysokim poziomie pewności. Zawiera również podzbiór wykonywalny, dzięki czemu modele mogą być analizowane przez testowanie i mogą być wykonywane za pomocą graficznych interfejsów użytkownika, dzięki czemu modele mogą być oceniane przez ekspertów, którzy niekoniecznie są zaznajomieni z samym językiem modelowania.
Historia
Początki VDM SL leżą w IBM laboratorium w Wiedeń , gdzie pierwsza wersja język zwany był V ienna D EFINICJA L anguage (VDL). VDL był zasadniczo używany do podawania operacyjnych opisów semantycznych w przeciwieństwie do VDM – Meta-IV, który zapewniał semantykę denotacyjną
„Pod koniec 1972 roku grupa wiedeńska ponownie zwróciła uwagę na problem systematycznego rozwijania kompilatora z definicji języka. Ogólne przyjęte podejście zostało nazwane „metodą rozwoju wiedeńskiego”. dokument norm napisany jako abstrakcyjny tłumacz") w BEKIČ 74.»
Nie ma żadnego związku między Meta-IV a językiem Meta-II Schorre'a lub jego następcą Tree Meta ; były to raczej systemy kompilator-kompilator niż nadające się do formalnych opisów problemów.
Tak więc Meta-IV była „używana do definiowania głównych części” języka programowania PL/I . Inne języki programowania opisane retrospektywnie lub częściowo opisane przy użyciu Meta-IV i VDM-SL obejmują język programowania BASIC , FORTRAN , język programowania APL , ALGOL 60, język programowania Ada i język programowania Pascal . Meta-IV przekształciła się w kilka wariantów, ogólnie określanych jako szkoły duńska, angielska i irlandzka.
„Szkoła języka angielskiego” wywodzi się z prac Cliffa Jonesa dotyczących aspektów VDM niezwiązanych konkretnie z definicją języka i projektowaniem kompilatorów (Jones 1980, 1990). Podkreśla modelowanie stanu trwałego poprzez wykorzystanie typów danych zbudowanych z bogatej kolekcji typów bazowych. Funkcjonalność jest zwykle opisana za pomocą operacji, które mogą mieć skutki uboczne na stanie i które są w większości określane niejawnie za pomocą warunku wstępnego i końcowego. „Szkoła Duńska” ( Bjørner et al. 1982) ma tendencję do podkreślania konstruktywnego podejścia, w którym w większym stopniu stosowana jest jawna specyfikacja operacyjna. Praca w duńskiej szkole doprowadziła do powstania pierwszego zatwierdzonego w Europie kompilatora Ady .
ISO Standard języka ukazał się w 1996 (ISO 1996).
Funkcje VDM
Składnia i semantyka VDM-SL i VDM++ są szczegółowo opisane w podręcznikach języka VDMTools oraz w dostępnych tekstach. Norma ISO zawiera formalną definicję semantyki języka. W pozostałej części tego artykułu używana jest składnia wymiany zdefiniowanej przez ISO (ASCII). Niektóre teksty wolą bardziej zwięzłą składnię matematyczną .
Model VDM-SL to opis systemu podany pod kątem funkcjonalności wykonywanej na danych. Składa się z szeregu definicji typów danych oraz funkcji lub operacji na nich wykonywanych.
Podstawowe typy: numeryczne, znakowe, tokenowe i cudzysłowowe
VDM-SL zawiera podstawowe typy modelujące liczby i znaki w następujący sposób:
bool |
Typ danych logicznych | fałsz PRAWDA |
nat |
liczby naturalne (w tym zero) | 0, 1, 2, 3, 4, 5... |
nat1 |
liczby naturalne (bez zera) | 1, 2, 3, 4, 5, ... |
int |
liczby całkowite | ..., -3, -2, -1, 0, 1, 2, 3, ... |
rat |
liczby wymierne | a/b , gdzie a i b są liczbami całkowitymi, b nie jest 0 |
real |
liczby rzeczywiste | ... |
char |
postacie | A, B, C, ... |
token |
tokeny bezstrukturalne | ... |
<A> |
typ cytatu zawierający wartość <A>
|
... |
Typy danych są zdefiniowane w celu reprezentowania głównych danych modelowanego systemu. Każda definicja typu wprowadza nową nazwę typu i przedstawia reprezentację pod względem typów podstawowych lub pod względem typów już wprowadzonych. Na przykład identyfikatory użytkownika modelujące typ dla systemu zarządzania logowaniem mogą być zdefiniowane w następujący sposób:
types UserId = nat
Aby manipulować wartościami należącymi do typów danych, operatory są definiowane na wartościach. W ten sposób zapewnione jest dodawanie, odejmowanie itp. liczb naturalnych, podobnie jak operatory logiczne, takie jak równość i nierówność. Język nie ustala maksymalnej lub minimalnej reprezentowanej liczby ani precyzji dla liczb rzeczywistych. Takie ograniczenia są definiowane tam, gdzie są wymagane w każdym modelu, za pomocą niezmienników typu danych — wyrażeń logicznych oznaczających warunki, które muszą być przestrzegane przez wszystkie elementy zdefiniowanego typu. Na przykład wymaganie, aby identyfikatory użytkowników nie mogły być większe niż 9999, można wyrazić w następujący sposób (gdzie <=
jest operatorem logicznym „mniejszy lub równy” na liczbach naturalnych):
UserId = nat inv uid == uid <= 9999
Ponieważ niezmienniki mogą być dowolnie złożonymi wyrażeniami logicznymi, a członkostwo w zdefiniowanym typie jest ograniczone tylko do wartości spełniających niezmiennik, poprawność typu w VDM-SL nie jest automatycznie rozstrzygana we wszystkich sytuacjach.
Inne podstawowe typy to char dla znaków. W niektórych przypadkach reprezentacja typu nie ma znaczenia dla celu modelu i tylko zwiększa złożoność. W takich przypadkach członkowie typu mogą być reprezentowani jako tokeny bez struktury. Wartości typów tokenów można porównywać tylko pod kątem równości – nie są na nich zdefiniowane żadne inne operatory. Tam, gdzie wymagane są konkretne nazwane wartości, są one wprowadzane jako typy cytatów. Każdy typ cudzysłowu składa się z jednej nazwanej wartości o tej samej nazwie co sam typ. Wartości typów cudzysłowów (znanych jako literały cudzysłowów) mogą być porównywane tylko pod kątem równości.
Na przykład w modelowaniu sterownika sygnalizacji świetlnej może być wygodne zdefiniowanie wartości reprezentujących kolory sygnalizacji świetlnej jako typy cytatów:
<Red>, <Amber>, <FlashingAmber>, <Green>
Konstruktory typów: typy uniowe, produktowe i złożone
Same podstawowe typy mają ograniczoną wartość. Nowe, bardziej ustrukturyzowane typy danych są budowane przy użyciu konstruktorów typów.
T1 | T2 | ... | Tn |
Unia typów T1,...,Tn
|
T1*T2*...*Tn |
Iloczyn kartezjański typów T1,...,Tn
|
T :: f1:T1 ... fn:Tn |
Typ kompozytowy (rekordowy) |
Najbardziej podstawowy konstruktor typu tworzy unię dwóch wstępnie zdefiniowanych typów. Typ (A|B)
zawiera wszystkie elementy typu A i wszystkie typu B
. W przykładzie sterownika sygnalizacji świetlnej typ modelujący kolor sygnalizacji świetlnej można zdefiniować w następujący sposób:
SignalColour = <Red> | <Amber> | <FlashingAmber> | <Green>
Typy wyliczone w VDM-SL są zdefiniowane jak pokazano powyżej jako związki w typach cytatów.
W VDM-SL można również zdefiniować kartezjańskie typy produktów. Typ (A1*…*An)
to typ złożony ze wszystkich krotek wartości, z których pierwszy element pochodzi z typu, A1
a drugi z typu A2
i tak dalej. Typ złożony lub rekord to iloczyn kartezjański z etykietami dla pól. Typ
T :: f1:A1 f2:A2 ... fn:An
jest iloczynem kartezjańskim z polami oznaczonymi f1,…,fn
. Element typu T
może być złożony z części składowych przez konstruktora napisane mk_T
. I odwrotnie, biorąc pod uwagę element typu T
, nazwy pól mogą służyć do wybierania nazwanego komponentu. Na przykład typ
Date :: day:nat1 month:nat1 year:nat inv mk_Date(d,m,y) == d <=31 and m<=12
modeluje prosty typ daty. Wartość mk_Date(1,4,2001)
odpowiada 1 kwietnia 2001 r. W przypadku daty d
wyrażenie d.month
jest liczbą naturalną reprezentującą miesiąc. W razie potrzeby do niezmiennika można włączyć ograniczenia dotyczące dni w miesiącu i lat przestępnych. Łącząc te:
mk_Date(1,4,2001).month = 4
Kolekcje
Typy kolekcji modelują grupy wartości. Zestawy to skończone nieuporządkowane kolekcje, w których duplikowanie między wartościami jest pomijane. Sekwencje to skończone uporządkowane kolekcje (listy), w których może wystąpić duplikacja, a mapowania reprezentują skończone zależności między dwoma zestawami wartości.
Zestawy
Konstruktor typu set (zapisany set of T
gdzie T
jest typem predefiniowanym) konstruuje typ złożony ze wszystkich skończonych zestawów wartości wylosowanych z typu T
. Na przykład definicja typu
UGroup = set of UserId
definiuje typ UGroup
złożony ze wszystkich skończonych zbiorów UserId
wartości. Różne operatory są zdefiniowane na zbiorach do konstruowania ich sumy, przecięcia, określania poprawnych i nieścisłych relacji podzbiorów itp.
{a, b, c} |
Wyliczenie zbioru: zbiór elementów a , b orazc
|
{x | x:T & P(x)} |
Zbiór ze zrozumieniem: zbiór x od typu T taki, żeP(x)
|
{i, ..., j} |
Zbiór liczb całkowitych z zakresu i doj
|
e in set s |
e jest elementem zestawu s
|
e not in set s |
e nie jest elementem zestawu s
|
s1 union s2 |
Unia zbiorów s1 is2
|
s1 inter s2 |
Przecięcie zbiorów s1 is2
|
s1 \ s2 |
Ustaw różnicę zestawów s1 is2
|
dunion s |
Rozproszony związek zbioru zestawów s
|
s1 psubset s2 |
s1 jest (właściwym) podzbiorem s2
|
s1 subset s2 |
s1 jest (słabym) podzbiorem s2
|
card s |
Kardynalność zbioru s
|
Sekwencje
Konstruktor typu skończonej sekwencji (zapisany seq of T
gdzie T
jest predefiniowanym typem) konstruuje typ złożony ze wszystkich skończonych list wartości wylosowanych z typu T
. Na przykład definicja typu
String = seq of char
Definiuje typ String
złożony ze wszystkich skończonych ciągów znaków. Różne operatory są zdefiniowane na sekwencjach do konstruowania konkatenacji, selekcji elementów i podciągów itp. Wiele z tych operatorów jest częściowych w tym sensie, że nie są zdefiniowane dla pewnych zastosowań. Na przykład wybranie piątego elementu sekwencji, która zawiera tylko trzy elementy, jest niezdefiniowane.
Kolejność i powtarzalność elementów w sekwencji jest istotna, więc [a, b]
nie jest równa [b, a]
i [a]
nie jest równa [a, a]
.
[a, b, c] |
Wyliczanie sekwencji: sekwencja elementów a , b ic
|
[f(x) | x:T & P(x)] |
Zrozumienie sekwencji: sekwencja wyrażeń f(x) dla każdego x typu (numerycznego) T taka, że P(x) zawiera ( x wartości brane w kolejności numerycznej)
|
hd s |
Głowa (pierwszy element) s
|
tl s |
Ogon (pozostała sekwencja po usunięciu głowy) z s
|
len s |
Długość s
|
elems s |
Zbiór elementów s
|
s(i) |
i Th elements
|
inds s |
zbiór indeksów dla ciągu s
|
s1^s2 |
ciąg utworzony przez łączenie ciągów s1 is2
|
Mapy
Skończone mapowanie to zgodność między dwoma zestawami, domeną i zakresem, z elementami indeksującymi domenę z zakresu. Jest więc podobny do funkcji skończonej. Konstruktor typu mapowania w VDM-SL (zapisany map T1 to T2
gdzie T1
i T2
są typami predefiniowanymi) konstruuje typ złożony ze wszystkich skończonych mapowań z zestawów T1
wartości na zestawy T2
wartości. Na przykład definicja typu
Birthdays = map String to Date
Definiuje typ, Birthdays
który mapuje ciągi znaków na Date
. Ponownie, operatory są definiowane w mapowaniach do indeksowania w mapowaniu, mapowania scalającego, nadpisywania wyodrębniania podmapowań.
{a |-> r, b |-> s} |
Wyliczenie mapowania: a maps to r , b maps tos
|
{x |-> f(x) | x:T & P(x)} |
Zrozumienie mapowania: x mapuje do f(x) for all x dla typu T takiego, żeP(x)
|
dom m |
Domena m
|
rng m |
Zakres m
|
m(x) |
m stosowane do x
|
m1 munion m2 |
Unia mapowań m1 i m2 ( m1 , m2 muszą być spójne tam, gdzie się nakładają)
|
m1 ++ m2 |
m1 nadpisany przez m2
|
Strukturyzacja
Główną różnicą między notacjami VDM-SL i VDM++ jest sposób, w jaki zajmuje się strukturacją. W VDM-SL istnieje konwencjonalne rozszerzenie modułowe, podczas gdy VDM++ ma tradycyjny mechanizm strukturyzacji obiektowej z klasami i dziedziczeniem.
Strukturyzacja w VDM-SL
W normie ISO dla VDM-SL znajduje się załącznik informacyjny, który zawiera różne zasady strukturyzowania. Wszystkie one są zgodne z tradycyjnymi zasadami ukrywania informacji za pomocą modułów i można je wyjaśnić jako:
-
Nazewnictwo modułów : każdy moduł jest uruchamiany składniowo słowem kluczowym,
module
po którym następuje nazwa modułu. Na końcu modułuend
zapisywane jest słowo kluczowe, a po nim ponownie nazwa modułu. -
Importowanie : możliwe jest importowanie definicji, które zostały wyeksportowane z innych modułów. Odbywa się to w sekcji importów, która zaczyna się od słowa kluczowego,
imports
po którym następuje sekwencja importów z różnych modułów. Każdy z tych importów modułów jest rozpoczynany od słowa kluczowego,from
po którym następuje nazwa modułu i sygnatura modułu. Podpis moduł może być albo po prostu słowo kluczoweall
wskazaniem import wszystkich definicjach eksportowanych z tego modułu, lub może to być sekwencja podpisów importowych. Sygnatury importu są specyficzne dla typów, wartości, funkcji i operacji, a każda z nich rozpoczyna się od odpowiedniego słowa kluczowego. Ponadto te sygnatury importu określają konstrukcje, do których istnieje chęć uzyskania dostępu. Dodatkowo może być obecna opcjonalna informacja o typie i wreszcie możliwa jest zmiana nazwy każdego z konstruktów podczas importu. W przypadku typów należy również użyć słowa kluczowego,struct
jeśli chcemy uzyskać dostęp do wewnętrznej struktury danego typu. -
Eksportowanie : Definicje z modułu, do którego inne moduły mają mieć dostęp, są eksportowane przy użyciu słowa kluczowego,
exports
po którym następuje podpis modułu eksportu. Podpis moduł eksportu może albo po prostu składa się z słów kluczowychall
lub jako sekwencję podpisów eksportowych. Takie sygnatury eksportu są specyficzne dla typów, wartości, funkcji i operacji, a każdy z nich rozpoczyna się od odpowiedniego słowa kluczowego. W przypadku chęci wyeksportowania wewnętrznej struktury typustruct
należy użyć słowa kluczowego . - Bardziej egzotyczne funkcje : We wcześniejszych wersjach narzędzi VDM-SL istniała również obsługa modułów parametryzowanych i ich instancji. Jednak te funkcje zostały usunięte z VDMTools około 2000 r., ponieważ prawie nigdy nie były używane w zastosowaniach przemysłowych, a z tymi funkcjami istniała znaczna liczba wyzwań związanych z narzędziami.
Strukturyzacja w VDM++
W VDM++ strukturyzacja odbywa się za pomocą klas i wielokrotnego dziedziczenia. Kluczowe pojęcia to:
-
Klasa : Każda klasa jest składniowo rozpoczynana od słowa kluczowego,
class
po którym następuje nazwa klasy. Na końcu klasyend
zapisywane jest słowo kluczowe, a po nim ponownie nazwa klasy. -
Dziedziczenie : W przypadku, gdy klasa dziedziczy konstrukcje z innych klas, po nazwie klasy w nagłówku klasy mogą występować słowa kluczowe,
is subclass of
po których następuje oddzielona przecinkami lista nazw nadklas. -
Modyfikatory dostępu : ukrywanie informacji w VDM++ odbywa się w taki sam sposób, jak w większości języków obiektowych przy użyciu modyfikatorów dostępu. W VDM++ definicje są domyślnie prywatne, ale przed wszystkimi definicjami można użyć jednego ze słów kluczowych modyfikujących dostęp:
private
,public
iprotected
.
Funkcjonalność modelowania
Modelowanie funkcjonalne
W VDM-SL funkcje są definiowane na podstawie typów danych zdefiniowanych w modelu. Obsługa abstrakcji wymaga, aby możliwe było scharakteryzowanie wyniku, który funkcja powinna obliczyć, bez konieczności określania, w jaki sposób powinna być obliczana. Głównym mechanizmem służącym do tego jest niejawna definicja funkcji, w której zamiast formuły obliczającej wynik, predykat logiczny nad zmiennymi wejściowymi i wynikowymi, zwany warunkiem końcowym , podaje właściwości wyniku. Na przykład funkcję SQRT
obliczania pierwiastka kwadratowego z liczby naturalnej można zdefiniować w następujący sposób:
SQRT(x:nat)r:real post r*r = x
W tym przypadku warunek końcowy nie definiuje metody obliczania wyniku, r
ale określa, jakie właściwości można założyć, że go posiadają. Zauważ, że definiuje to funkcję, która zwraca poprawny pierwiastek kwadratowy; nie ma wymogu, aby był to pierwiastek dodatni lub ujemny. Powyższa specyfikacja zostałaby spełniona na przykład przez funkcję, która zwróciła ujemny pierwiastek z 4, ale dodatni pierwiastek wszystkich innych prawidłowych danych wejściowych. Należy zauważyć, że funkcje w VDM-SL muszą być deterministyczne, aby funkcja spełniająca powyższą przykładową specyfikację zawsze zwracała ten sam wynik dla tych samych danych wejściowych.
Bardziej ograniczoną specyfikację funkcji uzyskuje się poprzez wzmocnienie warunku końcowego. Na przykład poniższa definicja ogranicza funkcję do zwracania dodatniego pierwiastka.
SQRT(x:nat)r:real post r*r = x and r>=0
Wszystkie specyfikacje funkcji mogą być ograniczone przez warunki wstępne, które są logicznymi predykatami tylko nad zmiennymi wejściowymi i które opisują ograniczenia, które zakłada się, że są spełnione podczas wykonywania funkcji. Na przykład funkcja obliczania pierwiastka kwadratowego, która działa tylko na dodatnich liczbach rzeczywistych, może być określona w następujący sposób:
SQRTP(x:real)r:real pre x >=0 post r*r = x and r>=0
Warunek wstępny i warunek końcowy tworzą razem umowę, którą musi spełnić każdy program, który twierdzi, że realizuje funkcję. Warunek wstępny rejestruje założenia, zgodnie z którymi funkcja gwarantuje zwrócenie wyniku spełniającego warunek końcowy. Jeśli funkcja jest wywoływana na danych wejściowych, które nie spełniają jej warunku wstępnego, wynik jest niezdefiniowany (w rzeczywistości zakończenie nie jest nawet gwarantowane).
VDM-SL obsługuje również definicję funkcji wykonywalnych na sposób funkcjonalnego języka programowania. W jawnej definicji funkcji wynik jest definiowany za pomocą wyrażenia na danych wejściowych. Na przykład funkcja tworząca listę kwadratów listy liczb może być zdefiniowana w następujący sposób:
SqList: seq of nat -> seq of nat SqList(s) == if s = [] then [] else [(hd s)**2] ^ SqList(tl s)
Ta rekurencyjna definicja składa się z sygnatury funkcji podającej typy danych wejściowych i wyników oraz treści funkcji. Niejawna definicja tej samej funkcji może mieć następującą postać:
SqListImp(s:seq of nat)r:seq of nat post len r = len s and forall i in set inds s & r(i) = s(i)**2
Wyraźna definicja jest w prostym sensie implementacją niejawnie określonej funkcji. Poprawność jawnej definicji funkcji w odniesieniu do niejawnej specyfikacji można zdefiniować w następujący sposób.
Biorąc pod uwagę niejawną specyfikację:
f(p:T_p)r:T_r pre pre-f(p) post post-f(p, r)
oraz funkcja jawna:
f:T_p -> T_r
mówimy, że spełnia specyfikację iff :
forall p in set T_p & pre-f(p) => f(p):T_r and post-f(p, f(p))
Tak więc " f
jest poprawną implementacją" należy interpretować jako " f
spełnia specyfikację".
Modelowanie oparte na stanach
W VDM-SL funkcje nie mają skutków ubocznych, takich jak zmiana stanu trwałej zmiennej globalnej. Jest to przydatna umiejętność w wielu językach programowania, więc istnieje podobna koncepcja; zamiast funkcji do zmiany zmiennych stanu używane są operacje (znane również jako globals ).
Na przykład, jeśli mamy stan składający się z jednej zmiennej someStateRegister : nat
, możemy to zdefiniować w VDM-SL jako:
state Register of someStateRegister : nat end
W VDM++ byłoby to zamiast tego zdefiniowane jako:
instance variables someStateRegister : nat
Operacja ładowania wartości do tej zmiennej może być określona jako:
LOAD(i:nat) ext wr someStateRegister:nat post someStateRegister = i
Pozory punkt ( ext
) określa, które elementy stanu mogą być dostępne przez działanie; rd
wskazujący dostęp tylko do wr
odczytu i będący dostępem do odczytu/zapisu.
Czasami ważne jest, aby odwołać się do wartości stanu przed jego modyfikacją; na przykład operacja dodania wartości do zmiennej może być określona jako:
ADD(i:nat) ext wr someStateRegister : nat post someStateRegister = someStateRegister~ + i
Gdzie ~
symbol na zmiennej stanu w warunku końcowym wskazuje wartość zmiennej stanu przed wykonaniem operacji.
Przykłady
Maks funkcja
To jest przykład niejawnej definicji funkcji. Funkcja zwraca największy element ze zbioru dodatnich liczb całkowitych:
max(s:set of nat)r:nat pre card s > 0 post r in set s and forall r' in set s & r' <= r
Warunek końcowy charakteryzuje wynik, a nie definiuje algorytm jego uzyskania. Warunek wstępny jest potrzebny, ponieważ żadna funkcja nie może zwrócić r w zbiorze s, gdy zbiór jest pusty.
Mnożenie liczb naturalnych
multp(i,j:nat)r:nat pre true post r = i*j
Stosowanie obowiązku dowodu forall p:T_p & pre-f(p) => f(p):T_r and post-f(p, f(p))
do wyraźnej definicji multp
:
multp(i,j) == if i=0 then 0 else if is-even(i) then 2*multp(i/2,j) else j+multp(i-1,j)
Wówczas obowiązek dowodu staje się:
forall i, j : nat & multp(i,j):nat and multp(i, j) = i*j
Można to wykazać prawidłowo przez:
- Udowodnienie, że rekurencja się kończy (to z kolei wymaga udowodnienia, że liczby zmniejszają się z każdym krokiem)
- Indukcja matematyczna
Abstrakcyjny typ danych kolejki
Jest to klasyczny przykład ilustrujący zastosowanie niejawnej specyfikacji operacji w modelu stanowym znanej struktury danych. Kolejka modelowana jest jako sekwencja złożona z elementów typu Qelt
. Reprezentacja jest Qelt
nieistotna i dlatego jest definiowana jako typ tokenu.
types
Qelt = token; Queue = seq of Qelt;
state TheQueue of q : Queue end
operations
ENQUEUE(e:Qelt) ext wr q:Queue post q = q~ ^ [e];
DEQUEUE()e:Qelt ext wr q:Queue pre q <> [] post q~ = [e]^q;
IS-EMPTY()r:bool ext rd q:Queue post r <=> (len q = 0)
Przykład systemu bankowego
Jako bardzo prosty przykład modelu VDM-SL rozważ system do utrzymywania szczegółów konta bankowego klienta. Klienci są modelowani według numerów klientów ( CustNum ), konta są modelowane według numerów kont ( AccNum ). Przedstawienia numerów klientów są uważane za nieistotne i dlatego są modelowane przez typ tokena. Salda i kredyty w rachunku bieżącym są modelowane według typów liczbowych.
AccNum = token; CustNum = token; Balance = int; Overdraft = nat;
AccData :: owner : CustNum balance : Balance
state Bank of accountMap : map AccNum to AccData overdraftMap : map CustNum to Overdraft inv mk_Bank(accountMap,overdraftMap) == for all a in set rng accountMap & a.owner in set dom overdraftMap and a.balance >= -overdraftMap(a.owner)
Z operacjami: NEWC przydziela nowy numer klienta:
operations NEWC(od : Overdraft)r : CustNum ext wr overdraftMap : map CustNum to Overdraft post r not in set dom ~overdraftMap and overdraftMap = ~overdraftMap ++ { r |-> od};
NEWAC przydziela nowy numer rachunku i ustawia saldo na zero:
NEWAC(cu : CustNum)r : AccNum ext wr accountMap : map AccNum to AccData rd overdraftMap map CustNum to Overdraft pre cu in set dom overdraftMap post r not in set dom accountMap~ and accountMap = accountMap~ ++ {r|-> mk_AccData(cu,0)}
ACINF zwraca wszystkie salda wszystkich rachunków klienta w postaci mapy numeru rachunku do salda:
ACINF(cu : CustNum)r : map AccNum to Balance ext rd accountMap : map AccNum to AccData post r = {an |-> accountMap(an).balance | an in set dom accountMap & accountMap(an).owner = cu}
Wsparcie narzędziowe
Wiele różnych narzędzi obsługuje VDM:
- VDMTools to wiodące komercyjne narzędzia dla VDM i VDM++, będące własnością, sprzedawane, utrzymywane i rozwijane przez CSK Systems , oparte na wcześniejszych wersjach opracowanych przez duńską firmę IFAD. Dostępne są podręczniki i praktyczny samouczek . Wszystkie licencje są dostępne bezpłatnie dla pełnej wersji narzędzia. Pełna wersja zawiera automatyczne generowanie kodu dla Javy i C++, bibliotekę dołączaną dynamicznie oraz obsługę CORBA.
- Overture to oparta na społeczności inicjatywa open source, której celem jest zapewnienie bezpłatnie dostępnego wsparcia narzędziowego dla VDM++ na platformie Eclipse. Jego celem jest opracowanie ram dla interoperacyjnych narzędzi, które będą przydatne do zastosowań przemysłowych, badań i edukacji.
- vdm-mode to zbiór pakietów Emacsa do pisania specyfikacji VDM przy użyciu VDM-SL, VDM++ i VDM-RT. Obsługuje podświetlanie i edycję składni, sprawdzanie składni w locie, uzupełnianie szablonów i obsługę interpretera.
- SpecBox : firmy Adelard zapewnia sprawdzanie składni, proste sprawdzanie semantyczne oraz generowanie pliku LaTeX umożliwiającego drukowanie specyfikacji w notacji matematycznej. To narzędzie jest dostępne bezpłatnie, ale nie jest dalej utrzymywane.
- Makra LaTeX i LaTeX2e są dostępne do obsługi prezentacji modeli VDM w składni matematycznej języka standardowego ISO. Zostały opracowane i są utrzymywane przez National Physical Laboratory w Wielkiej Brytanii. Dokumentacja i makra są dostępne online.
Doświadczenie przemysłowe
VDM jest szeroko stosowany w różnych dziedzinach aplikacji. Najbardziej znane z tych aplikacji to:
- Kompilatory Ada i CHILL : Pierwszy kompilator Ada zwalidowany w Europie został opracowany przez Dansk Datamatik Center przy użyciu VDM. Podobnie semantyka CHILL i Modula-2 została opisana w ich standardach przy użyciu VDM.
- ConForm: Eksperyment w British Aerospace porównujący konwencjonalny rozwój zaufanej bramy z rozwojem przy użyciu VDM.
- Dust-Expert: Projekt realizowany przez Adelard w Wielkiej Brytanii dla aplikacji związanej z bezpieczeństwem, określający, czy bezpieczeństwo jest odpowiednie w rozplanowaniu zakładów przemysłowych.
- Rozwój VDMTools: Większość komponentów pakietu narzędzi VDMTools jest sama opracowywana przy użyciu VDM. Ten rozwój został dokonany w IFAD w Danii i CSK w Japonii .
- TradeOne: Niektóre kluczowe elementy systemu back-office TradeOne opracowanego przez systemy CSK dla japońskiej giełdy zostały opracowane przy użyciu VDM. Istnieją pomiary porównawcze wydajności programistów i gęstości defektów komponentów opracowanych w VDM w porównaniu z konwencjonalnie opracowanym kodem.
- Firma FeliCa Networks poinformowała o opracowaniu systemu operacyjnego dla układu scalonego do zastosowań telefonii komórkowej .
Udoskonalenie
Korzystanie z VDM zaczyna się od bardzo abstrakcyjnego modelu i rozwija go w implementację. Każdy krok obejmuje rewizję danych , a następnie dekompozycję operacji .
Reifikacja danych rozwija abstrakcyjne typy danych w bardziej konkretne struktury danych , podczas gdy dekompozycja operacji rozwija (abstrakcyjną) niejawną specyfikację operacji i funkcji w algorytmy, które mogą być bezpośrednio zaimplementowane w wybranym języku komputerowym.
Reifikacja danych
Reifikacja danych (udokładnianie krokowe) polega na znalezieniu bardziej konkretnej reprezentacji abstrakcyjnych typów danych używanych w specyfikacji. Może być kilka kroków przed osiągnięciem implementacji. Każdy krok reifikacji abstrakcyjnej reprezentacji danych ABS_REP
wiąże się z zaproponowaniem nowej reprezentacji NEW_REP
. Aby pokazać, że nowa reprezentacja jest dokładna, zdefiniowana jest funkcja wyszukiwania, która odnosi się NEW_REP
do ABS_REP
, tj retr : NEW_REP -> ABS_REP
. . Poprawność reifikacji danych zależy od wykazania adekwatności , tj
forall a:ABS_REP & exists r:NEW_REP & a = retr(r)
Ponieważ reprezentacja danych uległa zmianie, konieczne jest zaktualizowanie operacji i funkcji tak, aby działały na NEW_REP
. Należy pokazać nowe operacje i funkcje, aby zachować wszelkie niezmienniki typu danych w nowej reprezentacji. Aby udowodnić, że nowe operacje i funkcje modelują te, które znalazły się w pierwotnej specyfikacji, konieczne jest spełnienie dwóch obowiązków dowodowych:
- Reguła domeny:
forall r: NEW_REP & pre-OPA(retr(r)) => pre-OPR(r)
- Zasada modelowania:
forall ~r,r:NEW_REP & pre-OPA(retr(~r)) and post-OPR(~r,r) => post-OPA(retr(~r,), retr(r))
Przykładowa reifikacja danych
W firmowym systemie bezpieczeństwa pracownicy otrzymują identyfikatory; są one podawane do czytników kart przy wejściu i wyjściu z fabryki. Wymagane operacje:
-
INIT()
inicjuje system, zakłada, że fabryka jest pusta -
ENTER(p : Person)
rejestruje, że pracownik wchodzi do fabryki; dane pracowników są odczytywane z dowodu osobistego) -
EXIT(p : Person)
odnotowuje, że pracownik opuszcza fabrykę -
IS-PRESENT(p : Person) r : bool
sprawdza, czy określony pracownik jest w fabryce, czy nie
Formalnie byłoby to:
types
Person = token; Workers = set of Person;
state AWCCS of pres: Workers end
operations
INIT() ext wr pres: Workers post pres = {};
ENTER(p : Person) ext wr pres : Workers pre p not in set pres post pres = pres~ union {p};
EXIT(p : Person) ext wr pres : Workers pre p in set pres post pres = pres~\{p};
IS-PRESENT(p : Person) r : bool ext rd pres : Workers post r <=> p in set pres~
Ponieważ większość języków programowania ma koncepcję porównywalną do zestawu (często w postaci tablicy), pierwszym krokiem od specyfikacji jest przedstawienie danych w postaci sekwencji. Te sekwencje nie mogą umożliwiać powtórzeń, ponieważ nie chcemy, aby ten sam pracownik pojawiał się dwa razy, więc musimy dodać niezmiennik do nowego typu danych. W tym przypadku kolejność nie jest ważna, więc [a,b]
jest taka sama jak [b,a]
.
Vienna Development Method jest cenna dla systemów opartych na modelach. Nie jest właściwe, jeśli system jest oparty na czasie. W takich przypadkach bardziej przydatny jest rachunek systemów komunikacji (CCS).
Zobacz też
- Metody formalne
- Formalna specyfikacja
- Kod pidgin
- Logika predykatów
- Rachunek zdań
- Język specyfikacji Z , główna alternatywa dla VDM-SL (porównaj)
- COMPASS Modeling Language (CML), połączenie VDM-SL z CSP , oparty na ujednoliconych teoriach programowania , opracowany do modelowania systemów systemów (SoS)
Dalsza lektura
- Bjørner, Dines; Cliff B. Jones (1978). Wiedeńska metoda rozwoju: metajęzyk, notatki do wykładów z informatyki 61 . Berlin, Heidelberg, Nowy Jork: Springer. Numer ISBN 978-0-387-08766-5.
- O'Regan, Gerard (2006). Matematyczne podejścia do jakości oprogramowania . Londyn: Springer. Numer ISBN 978-1-84628-242-3.
- Cliff B. Jones, wyd. (1984). Języki programowania i ich definicja — H. Bekič (1936-1982) . Notatki z wykładów z informatyki . 177 . Berlin, Heidelberg, Nowy Jork, Tokio: Springer-Verlag. doi : 10.1007/BFb0048933 . Numer ISBN 978-3-540-13378-0.
- Fitzgerald, JS i Larsen, PG, Systemy modelowania: praktyczne narzędzia i techniki w inżynierii oprogramowania . Cambridge University Press , 1998 ISBN 0-521-62348-0 (wydanie japońskie, Iwanami Shoten 2003 ISBN 4-00-005609-3 ).
- Fitzgerald, JS , Larsen, PG, Mukherjee, P., Plat, N. i Verhoef, M., Zatwierdzone projekty systemów zorientowanych obiektowo . Springer Verlag 2005. ISBN 1-85233-881-4 . Pomocnicza strona internetowa [1] zawiera przykłady i bezpłatne wsparcie narzędzi.
- Jones, CB , Systematyczne tworzenie oprogramowania przy użyciu VDM , Prentice Hall 1990. ISBN 0-13-880733-7 . Dostępne również online i bezpłatnie: http://www.csr.ncl.ac.uk/vdm/ssdvdm.pdf.zip
- Bjørner, D. i Jones, CB , Specyfikacja formalna i rozwój oprogramowania Prentice Hall International, 1982. ISBN 0-13-880733-7
- J. Dawes, The VDM-SL Reference Guide , Pitman 1991. ISBN 0-273-03151-1
- Międzynarodowa Organizacja Normalizacyjna , Technologia informacyjna – Języki programowania, ich środowiska i interfejsy oprogramowania systemowego – Wiedeńska metoda rozwoju – Język specyfikacji – Część 1: Język podstawowy Norma międzynarodowa ISO/IEC 13817-1, grudzień 1996.
- Jones, CB , Rozwój oprogramowania: rygorystyczne podejście , Prentice Hall International, 1980. ISBN 0-13-821884-6
- Jones, CB and Shaw, RC (red.), Studia przypadków w systematycznym rozwoju oprogramowania , Prentice Hall International, 1990. ISBN 0-13-880733-7
- Bicarregui, JC, Fitzgerald, JS , Lindsay, PA, Moore, R. i Ritchie, B., Proof in VDM: a Practitioner's Guide . Springer Verlag Formalne podejścia do informatyki i technologii informacyjnej (FACIT), 1994. ISBN 3-540-19813-X .
Bibliografia
Zewnętrzne linki