Utolsó óra összefoglaló

Hasonló dokumentumok
Neurális Hálók. és a Funkcionális Programozás. Berényi Dániel Wigner GPU Labor

A verem (stack) A verem egy olyan struktúra, aminek a tetejéről kivehetünk egy (vagy sorban több) elemet. A verem felhasználása

Rekurzió. Működése, programtranszformációk. Programozás II. előadás. Szénási Sándor.

A szemantikus elemzés elmélete. Szemantikus elemzés (attribútum fordítási grammatikák) A szemantikus elemzés elmélete. A szemantikus elemzés elmélete

Wavelet transzformáció

Programozás. (GKxB_INTM021) Dr. Hatwágner F. Miklós március 3. Széchenyi István Egyetem, Gy r

Programozás alapjai. (GKxB_INTM023) Dr. Hatwágner F. Miklós október 11. Széchenyi István Egyetem, Gy r

Műveletek mátrixokkal. Kalkulus. 2018/2019 ősz

6. Függvények. Legyen függvény és nem üreshalmaz. A függvényt az f K-ra való kiterjesztésének

Matematika (mesterképzés)

Algoritmusok és adatszerkezetek gyakorlat 03 Oszd meg és uralkodj. Nagy

KOVÁCS BÉLA, MATEMATIKA I.

Oktatási segédlet 2014

S0-02 Típusmodellek (Programozás elmélet)

Adatszerkezetek 7a. Dr. IványiPéter

9. Előadás. Megyesi László: Lineáris algebra, oldal. 9. előadás Mátrix inverze, mátrixegyenlet

illetve, mivel előjelét a elnyeli, a szinuszból pedig kiemelhető: = " 3. = + " 2 = " 2 % &' + +

Algoritmuselmélet 2. előadás

Programozás II. 2. Dr. Iványi Péter

Gregorics Tibor Modularizált programok C++ nyelvi elemei 1

1. Generátorrendszer. Házi feladat (fizikából tudjuk) Ha v és w nem párhuzamos síkvektorok, akkor generátorrendszert alkotnak a sík vektorainak

Rekurzió. (Horváth Gyula és Szlávi Péter előadásai felhasználásával)

Bonyolultságelmélet. Monday 26 th September, 2016, 18:27. Bonyolultságelmélet

Adatszerkezetek Tömb, sor, verem. Dr. Iványi Péter

Rekurzív algoritmusok

Adatszerkezetek 1. Dr. Iványi Péter

Bonyolultságelmélet. Monday 26 th September, 2016, 18:28

Dinamikus modellek szerkezete, SDG modellek

FFT. Második nekifutás. Czirbusz Sándor ELTE IK, Komputeralgebra Tanszék október 2.

Matematika szigorlat június 17. Neptun kód:

1. Determinánsok. Oldjuk meg az alábbi kétismeretlenes, két egyenletet tartalmaz lineáris egyenletrendszert:

Komplex számok. Komplex számok és alakjaik, számolás komplex számokkal.

Lin.Alg.Zh.1 feladatok

Diszkrét matematika 1. estis képzés

Absztrakt adatstruktúrák A bináris fák

A programozás alapjai 1 Rekurzió

Rekurzió. Dr. Iványi Péter

Miért fontos számunkra az előző gyakorlaton tárgyalt lineáris algebrai ismeretek

Programozás alapjai gyakorlat. 2. gyakorlat C alapok

van neve lehetnek bemeneti paraméterei (argumentumai) lehet visszatérési értéke a függvényt úgy használjuk, hogy meghívjuk

Algoritmuselmélet. 2-3 fák. Katona Gyula Y. Számítástudományi és Információelméleti Tanszék Budapesti Műszaki és Gazdaságtudományi Egyetem. 8.

Adatszerkezetek I. 7. előadás. (Horváth Gyula anyagai felhasználásával)

3. Fuzzy aritmetika. Gépi intelligencia I. Fodor János NIMGI1MIEM BMF NIK IMRI

1. A polinom fogalma. Számolás formális kifejezésekkel. Feladat Oldjuk meg az x2 + x + 1 x + 1. = x egyenletet.

2012. október 2 és 4. Dr. Vincze Szilvia

A függvény kód szekvenciáját kapcsos zárójelek közt definiáljuk, a { } -ek közti részt a Bash héj kód blokknak (code block) nevezi.

Gauss elimináció, LU felbontás

Bevezetés a programozásba I 10. gyakorlat. C++: alprogramok deklarációja és paraméterátadása

DISZKRÉT MATEMATIKA: STRUKTÚRÁK Előadáson mutatott példa: Bércesné Novák Ágnes

Lin.Alg.Zh.1 feladatok

4. Laplace transzformáció és alkalmazása

3. Előadás. Megyesi László: Lineáris algebra, oldal. 3. előadás Lineáris egyenletrendszerek

LINEÁRIS ALGEBRA. matematika alapszak. Euklideszi terek. SZTE Bolyai Intézet, őszi félév. Euklideszi terek LINEÁRIS ALGEBRA 1 / 40

Adaptív dinamikus szegmentálás idősorok indexeléséhez

Ellenőrző kérdések. 36. Ha t szintű indexet használunk, mennyi a keresési költség blokkműveletek számában mérve? (1 pont) log 2 (B(I (t) )) + t

A számítástudomány alapjai. Katona Gyula Y. Számítástudományi és Információelméleti Tanszék Budapesti Műszaki és Gazdaságtudományi Egyetem

sallang avagy Fordítótervezés dióhéjban Sallai Gyula

Egyenletek, egyenlőtlenségek V.

2018, Funkcionális programozás

Nagy Gábor compalg.inf.elte.hu/ nagy ősz

A 2017/2018 tanévi Országos Középiskolai Tanulmányi Verseny első fordulójának feladatai. INFORMATIKA II. (programozás) kategória

Programozás I. zárthelyi dolgozat

GPU Lab. 4. fejezet. Fordítók felépítése. Grafikus Processzorok Tudományos Célú Programozása. Berényi Dániel Nagy-Egri Máté Ferenc

1/1. Házi feladat. 1. Legyen p és q igaz vagy hamis matematikai kifejezés. Mutassuk meg, hogy

Logika es sz am ıt aselm elet I. r esz Logika 1/36

Függvények július 13. f(x) = 1 x+x 2 f() = 1 ()+() 2 f(f(x)) = 1 (1 x+x 2 )+(1 x+x 2 ) 2 Rendezés után kapjuk, hogy:

C programozás. 6 óra Függvények, függvényszerű makrók, globális és

1. Template (sablon) 1.1. Függvénysablon Függvénysablon példányosítás Osztálysablon

1. Interpoláció. Egyértelműség Ha f és g ilyen polinomok, akkor n helyen megegyeznek, így a polinomok azonossági tétele miatt egyenlők.

Rendezések. Összehasonlító rendezések

Logika es sz am ıt aselm elet I. r esz Logika Harmadik el oad as 1/33

2018, Diszkrét matematika

Programozás alapjai C nyelv 8. gyakorlat. Mutatók és címek (ism.) Indirekció (ism)

Fourier transzformáció

Nagy Gábor compalg.inf.elte.hu/ nagy ősz

Logika es sz am ıt aselm elet I. r esz Logika Negyedik el oad as 1/26

Nagy Gábor compalg.inf.elte.hu/ nagy ősz

2010. október 12. Dr. Vincze Szilvia

LNM folytonos Az interpoláció Lagrange interpoláció. Lineáris algebra numerikus módszerei

A programozás alapjai előadás. Amiről szólesz: A tárgy címe: A programozás alapjai

Algoritmusok és adatszerkezetek gyakorlat 06 Adatszerkezetek

9.fejezet: Függvények és külső eljárások

Paraméter átadás regisztereken keresztül

3. Osztályok II. Programozás II

Matematika szigorlat, Mérnök informatikus szak I máj. 12. Név: Nept. kód: Idő: 1. f. 2. f. 3. f. 4. f. 5. f. 6. f. Össz.: Oszt.

Nagy Gábor compalg.inf.elte.hu/ nagy ősz

BASH script programozás II. Vezérlési szerkezetek

Formális nyelvek és automaták

Mutatók és címek (ism.) Programozás alapjai C nyelv 8. gyakorlat. Indirekció (ism) Néhány dolog érthetőbb (ism.) Változók a memóriában

Bevezetés a programozásba I 3. gyakorlat. PLanG: Programozási tételek. Programozási tételek Algoritmusok

LINEÁRIS PROGRAMOZÁSI FELADATOK MEGOLDÁSA SZIMPLEX MÓDSZERREL

Programozási nyelvek (ADA)

Programozási nyelvek II. JAVA

Matematika A1a Analízis

Számsorozatok (1) First Prev Next Last Go Back Full Screen Close Quit

Programozás alapjai. 7. előadás

Diszkrét matematika II., 8. előadás. Vektorterek

5. Rekurzió és iteráció (Rekurzív programok átírása nemrekurzívvá)

Gráfok 1. Tárolási módok, bejárások. Szoftvertervezés és -fejlesztés II. előadás. Szénási Sándor

9. Előadás. Megyesi László: Lineáris algebra, oldal. 9. előadás Mátrix inverze, Leontyev-modell

Átírás:

Utolsó óra összefoglaló

Fourier Transzformáció A bázistranszformációk általában a következő alakúak: N f(x) = a k Φ k (x) k=0 Ahol: f a kifejtendő függvény, a az újbázisbeli együtthatók, Φ-k a (legtöbbször ortonormált) bázisfüggvények. Megj.: fordított irányban is hasonló formulát írhatunk fel, tehát f és a szerepe (melyik az eredeti, melyik a transzformált) csupán nézőpont kérdése. A legegyszerűbb bázis a Fourier-bázis, ahol: Φ k x = e ikx A bázisokhoz tartoznak kitüntetett pontok (kollokációs pontok, ezek a bázishoz tartozó kvadratúra kiértékelési helyei), amik általában a bázisok zérus helyei, vagy szélsőértékei. Fourier esetben általában: x l = 2πl -t használunk. N Ezekkel a Fourier transzformáció: f x l = f l = σ N k=0 a k e ik2πl N Berényi D. - Nagy-Egri M. F. 2

Gyors Fourier Transzformáció Az ötlet az, hogy a szumma átzárójelezhető, és közös faktorok emelhetőek ki, pl. N=8 esetén: a k = f 0 + f 1 e 2iπk 8 1 + f 2 e 2iπk 8 2 + f 3 e 2iπk 8 3 + f 4 e 2iπk 8 4 + f 5 e 2iπk 8 5 + f 6 e 2iπk 8 6 + f 7 e 2iπk 8 7 = f 0 + f 2 e 2iπk 8 2 + f 4 e 2iπk 8 4 + f 6 e 2iπk 8 6 + e 2iπk 8 1 f 1 + f 3 e 2iπk 8 2 + f 5 e 2iπk 8 4 + f 7 e 2iπk 8 6 = f 0 + f 4 e 2iπk 8 4 + e 2iπk 8 2 f 2 + f 6 e 2iπk 8 4 + e 2iπk 8 1 f 1 + f 5 e 2iπk 8 4 + e 2iπk 8 2 f 3 + f 7 e 2iπk 8 4 Ekkor: A fenti zárójelek faktorai különbözően periodikusak (ahogy k fut 0-tól 7-ig): Legbelül 2 a periódus, ezért k=0, 2, 4, 6-ra pontosan ugyanazt a szummát kell kiszámolni, sőt k=1, 3, 5, 7-re is, csak akkor egy mínusz előjellel. A []-k között 4 a periódus, ezért k={0, 4}, {1, 5}, {2, 6}, {3, 7} csoportokra ugyan az a szumma, de a szorzó faktorok: 1, -1, -i, i. A ()-között 8 a periódus, tehát csak a -1 szorzás marad meg. Ezek kihasználásával lényegesen csökkenthető az elvégzendő szorzások (és exp számolások) száma. Berényi D. - Nagy-Egri M. F. 3

Gyors Fourier Transzformáció A műveletek átrendezése viszont fontos, de elég fura alakú. Ha a bemenő tömb sorban van elhelyezve a memóriában, akkor az indexek: [0, 1, 2, 3, 4, 5, 6, 7] Az első lépésben a jelölt párokon kell dolgozni: [[0, 4], [1, 5], [2, 6], [3, 7]] Majd a másodikban: [[0, 2], [4, 6], [1, 3], [6, 7]] Végül: [[0, 1], [2, 3], [4, 5], [6, 7]] A párokon végrehajtandó művelet (pillangó): (x, y) (x + f y, x f y), ahol f faktor az éppen aktuális exponenciális faktor az előző oldalról. Viszont ekkor a kimenő tömb sorrendje valójában [0, 4, 2, 6, 1, 5, 3, 7] lesz. Berényi D. - Nagy-Egri M. F. 4

Gyors Fourier Transzformáció A műveletek átrendezése viszont fontos, de elég fura alakú. Ha a bemenő tömb sorban van elhelyezve a memóriában, akkor az indexek: [0, 1, 2, 3, 4, 5, 6, 7] Az első lépésben a jelölt párokon kell dolgozni: [[0, 4], [1, 5], [2, 6], [3, 7]] Majd a másodikban: [[0, 2], [4, 6], [1, 3], [6, 7]] Végül: [[0, 1], [2, 3], [4, 5], [6, 7]] A műveleti párok képzehetőek a következő képpen: félbevágjuk a tömböt, majd a két felet elemenként párokba rendezzük. Ekkor végrehajtható a pillangó. A következő lépésben a párok tömbjét deflatten-elni kell, azaz a párstruktúrát eltávolítjuk. Ezek után újra képezhetjük a műveleti párokat a pillangóhoz. Az eljárás végén át kell indexelni a tömböt, hogy jó sorrendben legyen a kimenet, amihez az indexek bináris inverzét kell kiszámolni. Berényi D. - Nagy-Egri M. F. 5

Gyors Fourier Transzformáció Linkek: http://www.librow.com/articles/article-10 Bit reversal: http://www.katjaas.nl/bitreversal/bitreversal.html Berényi D. - Nagy-Egri M. F. 6

Foldokkal listákon ki tudjuk számolni egy bináris művelet ismételt alkalmazását, és egyetlen elemre redukálni a kollekciót. Egyszerűen véggondolható, hogy ez bináris fákra is működik, pl.: a szorzás művelettel: 24 3 8 1 3 2 4 1 3 2 4 Ekkor tehát az eredmény 24. Berényi D. - Nagy-Egri M. F. 7

De, mi van akkor, ha több féle műveletet szeretnénk végrehajtani a fa különböző helyein, pl. mert egy műveleti fát kell kiértékelnünk? / 0.5 + * 4 8 1 3 2 4 1 3 2 4 Berényi D. - Nagy-Egri M. F. 8

Ha több lehetséges elágazás, és/vagy csúcs fajta van a fában, akkor azok egy sumtype-ot alkotnak. Sumtype-t csak a match-al tudunk eliminálni, ezért a fa alulról felfelé feldolgozása során minden ponton egy match-et kell végrehajtani. Nyilván minden esethez meg kell adni a megfelelő kezelő függvényt. / 0.5 + * 4 8 1 3 2 4 1 3 2 4 Berényi D. - Nagy-Egri M. F. 9

Ha pl. a fában a következő dolgok lehetnek: Konstans, + művelet, * művelet, / művelet Akkor a fa algebrai alakja vázlatosan: Tree = Constant Add Mul Div / + * 1 3 2 4 Azonban, mit tárol egy Add? Tárolhat konstanst, alfát (subtree)... Ahelyett, hogy egy rekurzív definíciót adnánk (amit általában nem támogatnak a típusrendszerek) : Tree = Constant Int Add Tree Tree Mul Tree Tree Div Tree Tree Kénytelenek vagyunk egy nem-rekurzív, de parametrikus definíciót adni, amit majd később teszünk rekurzívvá Berényi D. - Nagy-Egri M. F. 10

Ha pl. a fában a következő dolgok lehetnek: Konstans (egész szám), + művelet, * művelet, / művelet / + * Egy nemrekurzív, de parametrikus definíciót adunk, amit majd később teszünk rekurzívvá: Tree a = Constant Int Add a a Mul a a Div a a ahol a egy típus paraméter (template arguentum). A rekurzív fa típust a Fixpont kombinátorral hozzuk létre, mint a korábbi Faktoriális példánál láttuk: ExprTree = Fix Tree 1 3 2 4 Itt Tree a-ban az a helyére maga a Tree helyettesítődik be. A rekurzió nem végtelen: minden értelmes fa előbb utóbb egy Constantban végződik, aminek nincs a paramétere, ezért nem folytatható a rekurzió. Berényi D. - Nagy-Egri M. F. 11

Mivel a Tree egy sumtype, a kiértékelő függvénynek is egy sumtypenak kell lennie, hogy matchelni lehessen. Ahhoz, hogy ezek a függvények tetszőlegesen kombinálhatóak legyenek, a visszatérési értéküknek ugyan annak kell lenniük. / + * 1 3 2 4 Pl.: Evaluator = Constant Int Int Int Int Int Int Int Int Int Int Berényi D. - Nagy-Egri M. F. 12

Ezt a konstrukciót Kategória Elméletben F-algebrák néven ismerik. A fa egy Functor: F a, amit egy nemrekurzív parametrikus típus fixálásából kaptnk. / + * 1 3 2 4 A kiértékelő az Algebra, amely egy függvény kollekció, amelynek az eredendő szignatúrája: F a -> a A függvény, ami a rekurzív bejárást megcsinálja a katamorfizmus (catamorphism): cata alg tree = (alg. fmap cata alg. unfix) tree Berényi D. - Nagy-Egri M. F. 13

cata alg tree = (alg. map cata alg. unfix) tree Ezt a következő képpen kell olvasni: bejön egy tree Erre hattatódik egy unfix, ami felfedi az egy szinttel mélyebben fekvő típust, esetünkben: Fix tree -> tree (Fix tree), hiszen a fa elemei is fák. / + * 1 3 2 4 Az eredményre hattatódik egy map, aminek a függvénye maga a katamorfizmus és az algebra (azaz már csak egy tree-t vár, amire hatni fog). A tree kötelezően Functor, tehát a map létezik rá, és az implementációja annyi, hogy minden parametrikus (tehát pl. a Constant-ra nem!) elemére hattatja a kapott függvényt, ami persze újra a felfedett altree-kre fogja meghívni a map-et egy unfix után stb A lefelé lépkedés addig megy, amíg minden ágon el nem érjük a nemrekurzív végelemet (Constant), erre ugyanis nem hat a map! Amikor a map visszatér, akkor kerül a vezérlés az algebrához. Berényi D. - Nagy-Egri M. F. 14

/ + * cata alg tree = (alg. map cata alg. unfix) tree 1 3 2 4 Alulról, amikor a Constant-hoz ér a bejárás, akkor a map nem csinál semmit, a Constant egyenesen megy az algebrába. Matchelődik rá az első függvény, ami mondjuk Int-et csinál belőle (csak kiveszi a tárolt értéket) Az eggyel feljebbi szinten ez a visszaadott Int kerül a fában a korábbi alfa helyére, és ezzel tér vissza a map. Ezen a szinten az algebra már egy sumtype-ot kap, aminek minden rekurzív alága már ki lett értékelve, és csak az adott szinten levő műveletet kell elvégeznie. A következőkben ezt lépésenként leírjuk: Berényi D. - Nagy-Egri M. F. 15

cata alg tree = (alg. map cata alg. unfix) tree alg :: tree Int -> Int Belépés: + Unfix, map: ekkor itt a típus még: tree (Fix tree) 1 3 Berényi D. - Nagy-Egri M. F. 16

cata alg tree = (alg. map cata alg. unfix) tree alg :: tree Int -> Int Belépés: + Unfix, map: ekkor itt a típus még: tree (Fix tree) 1 3 Unfix, map: ekkor itt a típus is még: tree (Fix tree) Berényi D. - Nagy-Egri M. F. 17

cata alg tree = (alg. map cata alg. unfix) tree alg :: tree Int -> Int Belépés: + Unfix, map: ekkor itt a típus még: tree (Fix tree) 1 3 Itt a map nem hat, mert a Constant nem parametrikus, ezért a típus még mindig tree (Fix tree) Berényi D. - Nagy-Egri M. F. 18

cata alg tree = (alg. map cata alg. unfix) tree alg :: tree Int -> Int Belépés: + Unfix, map: ekkor itt a típus még: tree (Fix tree) 1 3 Hattatódik az algebra, ami a Constant Int-ből visszaadja az Int-et. Ez mindkét ágon megtörténik egymástól függetlenül. Berényi D. - Nagy-Egri M. F. 19

cata alg tree = (alg. map cata alg. unfix) tree alg :: tree Int -> Int Belépés: + Unfix, map: ekkor itt a típus még: tree (Fix tree) 1 3 A belső cata visszatér az egyik ágon 1-el, a másik ágon 3-al. Berényi D. - Nagy-Egri M. F. 20

cata alg tree = (alg. map cata alg. unfix) tree alg :: tree Int -> Int Belépés: + 1 3 Itt a map megkapja a visszatérési értékeket, amiket visszacsomagol a Functor struktúrába, ekkor ezen a szinten a típus tree Int lesz! Berényi D. - Nagy-Egri M. F. 21

cata alg tree = (alg. map cata alg. unfix) tree alg :: tree Int -> Int Belépés: 4 Végül ezen a szinten is meghívódik az algebra a tree Int el, de mivel ez most a + ág, ezért az ennek megfelelő függvény fog a match-be kerülni, és elvégződik az összeadás, aminek az eredménye Int. Berényi D. - Nagy-Egri M. F. 22

cata alg tree = (alg. map cata alg. unfix) tree alg :: tree Int -> Int Visszatérés: A legkülső cata hívás visszatér Int 4-el. 4 Berényi D. - Nagy-Egri M. F. 23

cata alg tree = (alg. map cata alg. unfix) tree alg :: tree a -> a Katamorfizmusokkal tetszőleges fákon tetszőleges alulról felfelé bejárást / kiértékelést leírhatunk, segítségükkel kiabsztrahálható a mélységi bejárás. A catamorfizmusok a fold általánosításai, amikoris a lista struktúra helyett tetszőleges fixált rekurzív functor sumtype van, és egyetlen függvény helyett pedig ennek megfelelő számú. Olvasnivalók, amik részletesebben elmagyarázzák az elméletet és az implementációt: http://bartoszmilewski.com/2013/06/10/understanding-f-algebras/ http://ericniebler.com/2013/07/16/f-algebras-and-c/ Berényi D. - Nagy-Egri M. F. 24

Anamorfizmusok Az unfoldok megfelelő általánosításai az anamorfizmusok: ana coalg seed = (fix. map ana coalg. coalg) seed coalg :: a -> tree a Ezek felülről lefelé bejárást valósítanak meg, minden lépésben a tree struktúrába csomagolva a kapott eredményeket, és az új értékeket használva seednek a következő lépésben. Berényi D. - Nagy-Egri M. F. 25

Megjegyzések a példakódhoz A sumtype-okat általában úgy szokás implementálni, hogy fordítás időben ismert, hogy milyen lehetőségeket tárolhat, és az aktuális választás a futásidejű érték. Ez lefordítva a fák nyelvére azt jelenti, hogy a fa lehetséges ágtípusai ismertek, de a konkrét aktuális struktúrája (hogy hol milyen művelet van kijelölve) nem. Pl. beolvasunk egy műveleti fát egy fileból. A numerikus gyakorlatban azonban az ember tudja, hogy milyen műveleti fát akar lekódolni, és mindent fordításidőben akar leírni, hogy a fordító mindent ki tudjon optimalizálni. Ekkor, ha template nyelven implementáljuk a katamorfizmusokat, akkora fix és unfix nem csinál semmit, hiszen nincs típusa a típus szintű értékeknek. Azonban, ha továbbra is egyetlen implementációt akarunk használni érték és típus szinten, akkor egyetlen alakot kell adnunk a catanak, ezért van kiírva a példában a fix, unfix. Berényi D. - Nagy-Egri M. F. 26

Megjegyzések a példakódhoz Az órai második példa egy λ kalkulust implementál. A példában az algebra visszatérési értéke nem egy jóldefiniált típus, csupán az a közös bennük, hogy minegyik egy olyan függvény (lambda), amely egy meghatározott struktúrájú argumentumlistát vár. Az argumentumlista a változók szimbólumait és a függvényhívásokban rögzített értékeit tárolja (Ctx), last in, first out sorrendben. A variadikus listából a get függvény keresi ki az adott változó aktuális értékét. A példa tömbökkel és map-el kiegészített λ kalkulust implementál, és kiértékeléskor minden elemre a ap-ben új szálat indít. A példa lényege, hogy pontosan ugyan ez a kód lesz majd futtatható a C++14 template részét támogató GPU-s API-kban (amikor végre elkészülnek), és ekkor várhatóan CSAK az algebra map részének implementációját kell átírni (l. arr_map2 fv.). Berényi D. - Nagy-Egri M. F. 27