Appendix 9. Hög-Prestanda Fortran

A 9.0 Inledning

Mycket viktigt vid införandet av en ny programspråksstandard är numera att språket skall klara effektiv kompilering och exekvering, inte bara på konventionella datorer utan även på parallella och massivt parallella system. Något förenklat kan man säga att Fortran 90 effektivt klarar konventionella datorer och vektorprocessorer, men är mindre effektivt på parallella processorer. Anledningen till detta är att inga kommandon för uppdelning i parallella processer finns i Fortran 90, förutom de som direkt följer ur fältbegreppet och tillhörande operationer och funktioner.

En grupp med säte i Houston, High Performance Fortran Forum, har därför utarbetat ett förslag i form av ett tillägg till Fortran 90. Syftet med detta projekt High Performance Fortran eller HPF är att erbjuda ett flyttbart (portabelt) språk som ger ett effektivt utnyttjande av olika parallella system. Projektet har avgett ett slutligt genomarbetat förslag i maj 1993, se litteraturlistan, och syftar mot en de facto standard, dvs ej en formell standard fastlagd av ANSI eller ISO. För att få en snabbare spridning av HPF finns även ett "HPF Subset", baserat på Fortran 77 utvidgad med en mindre del ur Fortran 90. Ett flertal tillverkare medarbetade i gruppen, som förväntas få ett snabbt genomslag av sina förslag. Eftersom gruppen med sina 45 aktiva medlemmar har arbetat mycket öppet, bland annat med en omfattande elektronisk distribution av sina arbetspapper till mer än 500 personer, så har många synpunkter från utomstående experter och framtida användare kommit in. Dessutom skedde en rejäl remissomgång av utkasten daterade november 1992 och januari 1993. De delar av förslaget som man ej har lyckats ena sig om, oftast på grund av tidsbrist, har förts till ett separat dokument kallat "Journal of Development".

Förslaget innebär ett Fortran-baserat språk för att kontrollera fördelningen av fält på parallella system med fördelat minne (eng. to control distribution of arrays onto distributed memory parallel computers) och innefattar tillägg för

Fullständig HPF är baserat på Fortran 90 och inkluderar Subset HPF är i stället baserat på Fortran 77 (för att kunna realiseras redan under 1993) och inkluderar Direktiven har getts den utformningen att de i en senare version av Fortran kan övergå till att bli vanliga kommandon. De skrives tills vidare som kommentarer, dvs
CHPF$ direktiv          ! Fortran 77 och fix form Fortran 90
!HPF$ direktiv          ! Fortran 90 (både fix och fri form)
Redan nu har bland andra Digital Equipment ett nästan fullständigt HPF system. Dessutom har Portland-gruppen en HPF Fortran 90 kompilator för flera olika system.

Senaste versionerna av rapporterna kan erhållas i PostScript eller hypertext-form (HTML). De kan även erhållas från Wien.

Den aktuella listan över tillgängliga och planerade implementationer är enligt HPFF protokoll från september 1995:

Fortsatt utveckling

Gruppen High Performance Fortran Forum har fortsatt att utveckla HPF språket och siktar mot att publicera en ny version mot slutet av 1996. Nya egenskaper är asynkron in/utmatning, parallella processer (tasking), mer allmänna fördelningar, gränssnitt till ANSI C, reduceringsoperationer med mera. Det är troligt att själva kärnan till språket inte kommer att utvidgas särskilt mycket, men att den nya specifikationen kommer att definiera vissa standardiserade men frivilliga tillägg.

A 9.1 Datalagring

HPF innehåller direktiv om hur data bör lagras. Dessa direktiv påverkar ej beräkningsresultatet men väl beräkningshastigheten. Anledningar till att direktiven för datalagring införes är: Med datalagringsdirektiv kan vi fördela data över de olika processorerna. Ibland är det lämpligt att rikta (göra rak, ställa upp i rät linje, eng. align) ett fält gentemot en mall (schablon, mönster, formbräde, eng. template) som sedan fördelas (kringsprides, utbredes, eng. distributed) på processorer. Ett första exempel kan förklara avsikten bättre än många ord.
        REAL A(1000), B(1000), C(1000), X(500), Y(0:501)
        INTEGER INX(1000)
!HPF$     PROCESSORS PROCS(10)
!HPF$     DISTRIBUTE A(BLOCK) ONTO PROCS
!HPF$     DISTRIBUTE B(BLOCK) ONTO PROCS
!HPF$     DISTRIBUTE INX(BLOCK) ONTO PROCS
!HPF$     DISTRIBUTE C(CYCLIC) ONTO PROCS
!HPF$     ALIGN X(I) WITH Y(I-1)

        A(I) = B(I)                     ! (1)
        X(I) = Y(I-1)                   ! (2)
        A(I) = C(I)                     ! (3)
        A(I) = A(I-1) + A(I) + A(I+1)   ! (4)
        C(I) = C(I-1) + C(I) + C(I+1)   ! (5)
        X(I) = Y(I)                     ! (6)
        A(I) = A(INX(I)) + B(INX(I))    ! (7)
Vi arbetar här med 10 processorer, och har fördelat flyttalsvektorerna A och B samt heltalsvektorn INX blockvis över dessa, dvs de hundra första elementen från var och en av dem på den första processorn, de 100 följande på nästa processor, osv. Vektorn C har däremot fördelats cykliskt, så att elementen nr 1, 11, 21 osv finns på den första processorn, elementen nr 2, 12, 22 osv på den andra, osv. Utan att mer exakt ange hur vektorerna X och Y skall fördelas har vi dessutom föreskrivet att element nr I av X-vektorn skall finnas på samma processor som element nr I-1 av Y-vektorn.

Tilldelningarna i fallen (1) och (2) ovan kan därför ske utan kommunikation mellan processorerna, eftersom alla data hela tiden finns på rätt processor. Tilldelningen i fall (3) kommer normalt att ske mellan olika processorer, endast i undantagsfall finns data på samma. Tvärtom kommer det i fall (4) att endast vara i undantagsfall (vid blockgränsen) som alla tre data inte är på samma processor.

Fall (5) ser ut som fall (4), men i detta fall ligger data alltid på tre olika processorer.

För fall (6) vet vi bara att X(I) och Y(I-1) ligger på samma processor, men detta säger inget om hur X(I) och Y(I) är lagrade. Vid blockvis lagring av båda ligger de normalt på samma, vid cyklisk lagring av båda ligger de däremot alltid på olika (om man har samma cykel på båda). Vi har således ingen egentlig information om hur dessa är lagrade.

Inte heller i fall (7) vet vi så mycket. Man inser dock att A(INX(I)) och B(INX(I)) alltid är på samma processor, samt att A(I) och INX(I) likaså är det (men ej nödvändigtvis på samma som de båda tidigare nämnda elementen).

Även de formella argumenten i en funktion eller subrutin kan lagras på olika sätt med hjälp av direktiv. Antag att vi har en subrutin med två argument, som båda är flyttalsvektorer.

	SUBROUTINE CAROLUS (KARL, CHARLES)
	REAL, DIMENSION (:) :: KARL, CHARLES
!HPF$   INHERIT :: KARL
!HPF$   ALIGN WITH KARL :: CHARLES
!       ...
        END SUBROUTINE CAROLUS
och att denna anropas med
        PROGRAM APP83B
	REAL, DIMENSION (1718) :: GUSTAV, ADOLF
        INTERFACE
          SUBROUTINE CAROLUS (KARL, CHARLES)
  	  REAL, DIMENSION (:) :: KARL, CHARLES
          END SUBROUTINE CAROLUS
        END INTERFACE
!       ..
	CALL CAROLUS (GUSTAV, ADOLF)
        END PROGRAM APP83B
Detta innebär att det första formella argumentet KARL fördelas över processorerna likadant som det verkliga argumentet, nämligen som GUSTAV. Det andra formella argumentet CHARLES fördelas däremot över processorer likadant som det första formella argumentet, dvs även det i verkligheten som GUSTAV, och ej som det andra verkliga argumentet ADOLF.

Ett annat exempel är när man behöver de fyra hörn-delfälten av storlek N*N från ett större fält av storlek (N+1)*(N+1). I detta fall anges det stora fältet kallat EARTH enbart som TEMPLATE, dvs formbräde, mall, mönster eller schablon. Det lagras aldrig i verkligheten, eftersom det egentligen aldrig användes!

!HPF$     TEMPLATE, DISTRIBUTE (BLOCK,BLOCK) :: EARTH (N+1,N=!)
          REAL, DIMENSION (N,N) :: NW, NE, SW, SE
!HPF$     ALIGN NW(I,J) WITH EARTH(I,J)
!HPF$     ALIGN NE(I,J) WITH EARTH(I,J+1)
!HPF$     ALIGN SW(I,J) WITH EARTH(I+1,J)
!HPF$     ALIGN SE(I,J) WITH EARTH(I+1,J+1)
Eftersom TEMPLATE inte representerar något verkligt lagringsutrymme kan det inte heller ingå i COMMON. Riktningsindex (eng. alignment subscript) får bara vara aningen mer komplicerat än index i Fortran 66, dvs av typen m*i+n, endast en variabel i får förekomma och då endast en gång, parametrarna m och n svarar mot konstanter.

Ett något mer komplicerat direktiv är

!HPF$     ALIGN A(:) WITH D(:,*)
vilket innebär att en kopia av vektorn A samordnas med varje kolumn av matrisen D. Ett exempel på detta följer. Av detta framgår dessutom att syntaxen tillåter väldigt många varianter för att skriva samma sak.
!HPF$     TEMPLATE, D1(N), D2(N,N)
          REAL, DIMENSION (N,N) :: X, A, B, C, AR1, AR2, P, Q, R, S
!HPF$     ALIGN X(:,*) WITH D1(:)
!HPF$     ALIGN (:,*) WITH D1 :: A, B, C, AR1, AR2
!HPF$     ALIGN WITH D2, DYNAMIC :: P, Q, R, S
Följande är ett mer fullständigt exempel där först en inbyggd funktion känner av det aktuella antalet processorer, vilket sedan utnyttjas vid fördelningen av fälten. Dessutom användes här en funktion.

!HPF$   TEMPLATE, D1(N), D2(N, N)
	REAL, DIMENSION (N, N) :: X, A, B, C, AR1, AR2, &
                                  P, Q, R, S
!HPF$   ALIGN X(:,*) WITH D1(:)
!HPF$   ALIGN (:,*) WITH D1 :: A, B, C, AR1, AR2
!HPF$   ALIGN WITH D2, DYNAMIC :: P, Q, R, S
The following is a more complete example, where an intrinsic function finds the present number of processors, which is used at the distribution of the arrays. In addition a usual (external) function is being used.
        PROGRAM APP83C
        IMPLICIT NONE

        INTERFACE
           FUNCTION F(X)
           REAL                :: F
           REAL, DIMENSION (:) :: X
           END FUNCTION F
        END INTERFACE 

        REAL, DIMENSION (1000)  :: X, Y, Z
        REAL, DIMENSION (5000)  :: V, W
        REAL :: TEMP
        REAL, DIMENSION (10,1000) :: A

!HPF$   PROCESSORS MPP(NUMBER_OF_PROCESSORS())

!HPF$   TEMPLATE T(1000), S(5000)
!HPF$   DISTRIBUTE T(BLOCK) ONTO MPP    ! Blockstorlek
!HPF$   DISTRIBUTE S(CYCLIC) ONTO MPP   ! kan specificeras
!HPF$   ALIGN WITH T :: X, Y, Z
!HPF$   ALIGN WITH S :: V, W

!HPF$   ALIGN A(*,:) WITH T(:)          ! Vektor av kolumner

!	...
        TEMP = F(V)
!	...
        END PROGRAM APP83C

	REAL FUNCTION F(X)
        IMPLICIT NONE
	REAL, DIMENSION (:) :: X
!HPF$	INHERIT :: X            ! Fördela formellt argument
                                ! X som verkligt argument V
	REAL, DIMENSION (SIZE(X)) :: S
!HPF$	ALIGN WITH X :: S       ! Fördela lokalt argument S som
                                ! formellt argument X, dvs som 
                                ! verkligt argument V
!	...
        F = SUM(S)              ! Bara enkelt exempel
	RETURN
	END FUNCTION F
Man kan specificera olika fördelningar för de olika dimensionerna i ett fält. Följande deklarationer
        REAL A(100,100), B(100,100), C(200)
!HPF$   DISTRIBUTE A(BLOCK,*), B(*,CYCLIC), C(BLOCK(5))
medför att den första processorn vid en fyra processors-maskin lagrar följande fältsektioner
        A(1:25, 1:100)
        B(1:100, 1:97:4)
        C(1:5), C(21:25), C(41:45), C(61,65), C(81:85),
        C(101:105), C(121:125), C(141:145), C(161,165),
        C(181:185),
Det är likaså möjligt att fördela flera dimensioner på ett oberoende sätt
        REAL D(8,100,100)
!HPF$   DISTRIBUTE D(*,BLOCK,CYCLIC)
medför att den första processorn vid en fyra processors-maskin konfigurerad som en 2*2 matris lagrar följande fältsektioner
        D(1:8, 1:50, 1:99:2)
Förutom ovanstående statiska direktiv finns även de båda dynamiska direktiven REDISTRIBUTE och REALIGN, vilka tillåter fält att ändra sin fördelning inom en subrutin. Vid användning av en subrutin kan tre olika möjligheter finnas för de formella argumenten: Vid utgången från en subrutin måste en eventuell omfördelning återtas!

A 9.2 Exekvering

En ny sats FORALL införes för att till skillnad från en DO-slinga kunna utföras i godtycklig ordning (och därmed parallellt om den fysiska möjligheten finns). Samtidigt införes regler för att undvika sido-effekter (snarare att undvika olika resultat beroende på i vilken ordning beräkningen utföres). Ett par enkla exempel på FORALL-satser följer
        FORALL (I = 1:N, J = 1:N) H(I,J) = 1.0/REAL(I+J-1)
        FORALL (I = 1:N, J = 1:N, Y(I,J) .NE. 0.0) &
                        X(I,J) = 1.0/Y(I,J)
        FORALL (I = 1:N) A(I,I+1:N) = 3.141592654 
Den första av dessa definierar Hilbertmatrisen av ordning N, den andra inverterar elementen i en matris med undvikande av eventuella nollor. I den tredje tilldelas alla element över huvuddiagonalen i matrisen A ett approximativt värde på pi.

I dessa satser kan FORALL sägas vara en dubbelslinga som kan utföras i godtycklig ordning. Det allmänna utseendet är

        FORALL ( v1 = l1:u1:s1, ... , vn = ln:un:sn, mask ) &
                a(e1, ... , em) = right_hand_side
och beräknas enligt väl definierade regler, i princip beräknas alla index först.

Dessutom finns en FORALL-konstruktion. Denna skall tolkas som om de ingående satserna i stället vore skrivna som FORALL-satser i samma ordning. Denna restriktion är väsentlig för att få ett entydigt beräkningsresultat. I en FORALL-konstruktion är anrop av funktioner och subrutiner tillåtna om dessa är rena (eng. pure). Med direktivet PURE kan man ange att så är fallet. Först ett enkelt exempel på en FORALL-konstruktion.

        REAL, DIMENSION(N,N) :: A, B
        ...
        FORALL (I = 2:N-1, J = 2:N-1)
           A(I,J) = 0.25*(A(I,J-1)+A(I,J+1)+A(I-1,J)+A(I+1,J))
           B(I,J) = A(I,J)
        END FORALL
Efter dessa satser har A och B exakt samma värden i alla inre punkter, medan B har kvar sina eventuella gamla värden på ränderna.

Dessutom införes ett direktiv om oberoende inom slingor av de båda typerna DO och FORALL. Detta direktiv, som helt enkelt heter !HPF$ INDEPENDENT placeras direkt efter den DO-sats eller FORALL konstruktion (dvs direkt efter inledande FORALL) och gäller fram till och med motsvarande END DO respektive END FORALL. Direktivet försäkrar kompilatorn att motsvarande del av programmet kan exekveras oberoende, dvs i godtycklig ordning eller parallellt, utan att medföra någon ändring i resultatet (ingen semantisk ändring).

I nedanstående exempel försäkras således att heltalsvektorn P inte har några upprepade värden (vilket skulle innebära att "sista vinner" tilldelningen skulle kunna bli en annan vid exekvering i annan ordning, och en konflikt vid rent parallell exekvering), samt att alla värdena P(I) ligger inom gränserna 1 och 200.

        REAL, DIMENSION(200)    :: A
        REAL, DIMENSION(100)    :: B
        INTEGER, DIMENSION(100) :: P
        ...
!HPF$   INDEPENDENT
        DO I = 1, 100
           A(P(I)) = B(I)
        END DO
Man kan även ange vilka delar av en multipelslinga som skall betraktas som oberoende. I nedanstående exempel så är den innersta slingan inte oberoende eftersom ett visst element i A tilldelas ett upprepat antal gånger.
	REAL, DIMENSION(:, :, :), ALLOCATABLE :: A, B, C
        ...
        ALLOCATE (A(N,N,N))
        ALLOCATE (B(N,N,N))
        ALLOCATE (C(N,N,N))
        ...
!HPF$   INDEPENDENT (I1, I2, I3)
        DO I1 = 1, N1
          DO I2 = 1, N2
            DO I3 = 1, N3
              DO I4 = 1, N4 ! The innermost loop is NOT
                            ! independent !
                 A(I1, I2, I3) = A(I1, I2, I3) &
                   + B(I1, I2, I4) * C(I2, I3, I4)
              END DO
            END DO
          END DO
        END DO
En DO-slinga och en FORALL-konstruktion med samma innehåll är ekvivalenta om de båda har getts ett INDEPENDENT direktiv.

A 9.3 Inbyggda funktioner

Förutom alla de i Fortran 90 inbyggda funktionerna tillkommer ett antal nya, samt har två funktioner modifierats.

A 9.3.1 Lokaliseringsfunktioner:

Lokaliseringsfunktionerna MAXLOC och MINLOC har kompletterats med en valfri parameter DIM, som om den är med anger längs vilken dimension man skall arbeta. Ett exempel illustrerar hur detta påverkar MAXLOC, motsvarande gäller naturligtvis för MINLOC. Den stora skillnaden är att utan den valfria parametern returneras läget för det största elementet, om den valfria parametern är med så returneras i stället radnumret vid DIM = 1 och kolumnnumret vid DIM = 2 där de största värdena för respektive kolumn eller rad befinner sig. Dessa nya egenskaper svarar mot de som redan i Fortran 90 finns för MAXVAL och MINVAL.
                0 -5     8  -3
        A =     3  4    -1   2
                1  5     6  -4
ger följande värden
        MAXLOC(A)       = (/ 1, 3 /)
        MAXLOC(A, DIM = 1)    = (/ 2, 3, 1, 2 /)
        MAXLOC(A, DIM = 2)    = (/ 3, 2, 3 /)
Följande helt nya funktioner tillkommer. Avsikten är att förfrågningsfunktionerna blir verkliga inbyggda funktioner, medan de övriga eventuellt i stället kommer att finnas i ett bibliotek (som externa funktioner).

A 9.3.2 Förfrågningsfunktioner:

A 9.3.3 Bitmanipuleringsfunktioner:

Dessa tre är ett komplement till de i Fortran 90 och även dessa använder modellen i sektion 13.5.7 i Fortran 90 standarden. Observera att resultaten är maskinberoende, eftersom de beror på antalet bitar i ett heltal. Detta senare antal kan erhållas med Fortran 90 bitförfrågningsfunktionen BIT_SIZE.

A 9.3.4 Övriga funktioner:

ILEN är en heltalsfunktion på heltal som returnerar antalet bitar som behövs för att lagra ett heltal (med tecken) i form av ett 2-komplement. Exempel på dess användning är att 2**ILEN(N-1) avrundar ett godtyckligt heltal N > 0 uppåt till den närmaste 2-potensen, och att däremot 2**(ILEN(N)-1) avrundar nedåt.

De följande funktionerna är ej inbyggda utan finns i ett normalt bibliotek och kräver därför en USE-sats före användning. Jag har här valt att inte ge en detaljerad beskrivning, utan räknar bara upp dessa. För definitioner hänvisar jag till standarden.

Reduceringsfunktionerna IALL, IANY, IPARITY och PARITY finns och de svarar mot de i Fortran 90 inbyggda logiska funktionerna IAND, IOR, IEOR och operatorn .NEQV. Ett stort antal funktioner finns för att kombinera ihop och sprida ut data, de har namn av formen XXX_SCATTER, där XXX kan vara någon av SUM, COUNT, PRODUCT, MAXVAL, MINVAL, IALL, IANY, IPARITY, ALL, ANY och PARITY. För parallella operationer finns funktioner med namnen XXX_PREFIX och XXX_SUFFIX, där XXX har samma möjligheter som för XXX_SCATTER. Exempel: SUM_PREFIX summerar successivt talen i fältet, det första blir oförändrat, det andra blir summan av de två första, osv, medan SUM_SUFFIX gör det baklänges.

Det finns dessutom två sorteringsfunktioner, GRADE_UP och GRADE_DOWN. Däremot finns det för närvarande inga operationer i HPF för parallell in- eller utmatning (förutom i Journal of Development).

A 9.4 Lagringsregler

För Fortran 90 gäller vissa regler för lagring av variabler, dels för fält som måste lagras i en väl specificerad ordning, där första index varierar snabbast, dels för sådana storheter som placerats i COMMON och/eller EQUIVALENCE. Dessa regler om sekventiell lagring kan komma i konflikt med den fördelning över processorer som kan föreskrivas i HPF med ALIGN, REALIGN, DISTRIBUTE och REDISTRIBUTE direktiven. Den modell som Fortran arbetar med när det gäller lagring är som bekant rent linjär, med ett visst utrymmesbehov för heltal och flyttal, och dubbelt för tal i dubbel precision.

Man talar i Fortran om lagringsassociering (eng. storage association) och ordningsassociering (eng. sequence association). Fortranstandarden säger i (14.6.3.1) att lagringsassociering är den associering av två eller flera dataobjekt som förekommer när två eller flera följder av data delar en eller flera lagringsenheter, och i (12.4.1.4) att ordningsassociering avser den ordning för fältelement som Fortran kräver då ett fältuttryck associeras med ett formellt argument: Rang och mönster hos det verkliga argumentet behöver inte överensstämma med rang och mönster hos det formella argumentet.

Notera att HPF klarar det fall att fält, använda som argument, är fördelade över processorer, i det fall att verkligt argument och formellt argument båda har samma rang och mönster. Det är det (relativt vanliga) fallet att man tricksar i Fortran (dvs. utnyttjar de möjligheter som finns och är tillåtna) som ställer till problem i HPF. Om man har en subrutin som innehåller deklarationerna

        SUBROUTINE HEMMA(X)
        DIMENSION X(20,10)
så kan denna anropas med CALL HEMMA(Y(2,1)) endast om fältet X är deklarerat sekventiellt i subrutinen HEMMA och samtidigt fältet Y är deklarerat sekventiellt i den anropande rutinen. Det alternativa anropet CALL HEMMA(Y) är tillåtet om antingen X och Y båda är sekventiella eller om de båda är dimensionerade exakt lika.

Ett direktiv SEQUENCE har införts för att explicit tala om för systemet att en variabel eller ett COMMON-block skall betraktas som att vara rent sekventiell. Under HPF gäller normalt att alla COMMON-block behandlas som icke-sekventiella, medan variabler (utom i ett par specificerade undantagsfall, som när variabeln ingår i ett sekventiellt COMMON-block eller är ett fält med antagen dimension) likaså normalt är icke-sekventiella.

För att få alla "gamla" program att ge samma resultat under HPF som under Fortran rekommenderas följande att ingå i implementationer av HPF.

A 9.5 HPF Subset

Följande nyheter i Fortran 90 ingår i HPF Subset:

Vanliga begrepp

Fält-begrepp

Övriga begrepp från Fortran 90

Dessutom ingår i HPF Subset

Det militära tillägget MIL-STD-1753 till Fortran 77. Detta innefattar förutom DO WHILE, END DO, IMPLICIT NONE och INCLUDE även bitmanipuleringsfunktionerna BTEST, IAND, IBCLR, IBITS, IBSET, IEOR, IOR, ISHFT, ISHFTC och NOT samt bitkopieringsrutinen MVBITS och binära, oktala och hexadecimala konstanter.

Följande från fullständig HPF är däremot inte med i HPF Subset:

Dessutom gäller vissa inskränkningar vad gäller tillåtna värden på argumentet DIM till MAXLOC och MINLOC, samt saknas definition av yttre procedurer (rutiner ej skrivna i HPF, eng. extrinsic) samt saknas naturligtvis bindning till Fortran 90.

A 9.6 HPF 2.0

HPF Forum har annonserat tillgängligheten av The High Performance Fortran Language Specification, version 2.0. HPF 2.0 innehåller HPF 2.0 språket innehåller begrepp som förväntas införas av varje HPF implementation inom ett år. Dessa inkluderar: De tillåtna utvidgningarna inkluderar avancerade egenskaper som motsvarar verkliga behov, men som troligen ej kommer att stödjas i alla implementationer från början. Dessa utvidgningar inkluderar: Specifikationen är tillgänglig på flera sätt: