Diszkrét matematika 3. előadás mgyongyi@ms.sapientia.ro Sapientia Egyetem, Matematika-Informatika Tanszék Marosvásárhely, Románia 2018, őszi félév
Miről volt szó az elmúlt előadáson? számtartományok: természetes számok, egész számok Python alapfogalmak: utasítások (while), függvényhívások (rekurzió), a lista, a tuple típusú adatszerkezetek a faktoriális függvény - iteratív, rekurzív változatok a gyorshatványozás algoritmusa - iteratív, rekurzív változatok állománykezelés, bevezető fogalmak
Miről lesz szó? számtartományok: racionális számok racionális számok irreducibilis alakja legnagyobb közös osztó algoritmusa - iteratív, rekurzív változatok racionális számok sorozatba rendezése - két módszer lánctörtek: a racionális számok lánctört jegyei a Farey sorozat
Racionális számok halmazjelölés: Q = { a : a, b Z, b 0}, b egész számok rendezett párjaként is felfoghatóak, tulajdonságok: kommutatívitás, asszociatívítás, disztributívítás, a racionális számok halmaza zárt az összeadásra, kivonásra, szorzásra, osztásra nézve, összeadásra, szorzásra nézve minden elemnek lesz inverz eleme, sűrűn rendezett halmazt alkotnak: bármely két racionális szám között van egy harmadik, végtelen sok alakban feĺırhatóak irreducibilis tört, sorozatba rendezhetőek, tizedes tört alak: véges vagy végtelen szakaszos törtek.
Algoritmusok Pythonban 1. feladat Határozzuk meg egy adott racionális szám irreducibilis alakját. a x racionális számot az (x, y) értékpárral fogjuk jelölni, azaz tuple y típusú adatként kezeljük egy tört irreducibilis, ha a számláló és nevező legnagyobb közös osztója 1 meg kell határozni két szám legnagyobb közös osztóját: eukleidészi algoritmus (rekurzív változat) def ialak (a, b): l = lnko(a, b) return (a // l, b // l) # két szám legnagyobb közös osztója, eukleideszi algoritmus def lnko(a, b): temp = a % b if temp == 0: return b return lnko(b, temp)
Racionális számok A racionális számok halmaza megszámlálható: a racionális számok halmaza felsorolható, azaz létezik egy számsorozat, amelyet a racionális számok alkotnak : r 1, r 2,..., r n,..., bármelyik racionális szám feĺırható p/q alakba a racionális számok kigenerálásának egyik módszere, ha elindulunk a következő mátrix bal-felső sarkában található elemtől, majd a nyilakat követjük:
Algoritmusok Pythonban 2. feladat Az előző oldalon megadott bejárási sorrend szerint írassuk ki az első n sort, azaz az első n (n+1) racionális számot, ahol a racionális számokat tuple típusú adatként 2 kezeljük. def aracionalis (k): for j in range(1, k+1): if k % 2 == 1: print ((j, k+1-j), end = " ") else: print ((k+1-j, j), end = " ") print () def racionalis (n): for k in range(1, n+1): aracionalis (k) >>> racionalis (10) (1, 1) (2, 1) (1, 2) (1, 3) (2, 2) (3, 1) (4, 1) (3, 2) (2, 3) (1, 4) (1, 5) (2, 4) (3, 3) (4, 2) (5, 1)...
Algoritmusok Pythonban Az előző feladat segédfüggvény nélkül, egymásba ágyazott for ciklus-sal: def racionalis1 (n): for k in range(1, n+1): for j in range(1, k+1): print ((j, k+1-j), end = " ") print () elhagytuk az if feltételt, mert a sorrend az egyes sorokon belül nem számít, lesznek olyan racionális számok, amelyek többször is megjelennek a generált számok között!! ha egy számpárból képezhető racionális szám nem irreducibilis, akkor azt jelenti, hogy már egyszer ki volt generálva. Ennek a feltételnek a bevezetése házi feladat.
Algoritmusok Pythonban 3. feladat A korábban megadott módszerrel generáljuk ki lista adatszerkezetbe, az első n pozitív, racionális számot. def racionalisl(n): #az L listát üres listaként inicializáljuk: L = [] for k in range(1, n+1): for j in range(1, k+1): #az L lista végéhez hozzáfuzunk egy értékpárt: L = L + [(j, k+1-j)] n = n - 1 if n == 0: return L return L >>> racionalisl(7) [(1, 1), (1, 2), (2, 1), (1, 3), (2, 2), (3, 1), (1, 4)]
Algoritmusok Pythonban 4. feladat Írassuk ki az első n pozitív, racionális számot, alkalmazva a következő algoritmust: az első racionális szám 1, az x után következő racionális szám: 1 y 2 + 1 x reciproka, ahol alsó egész részt jelent (a kódsorban ezt az y x y értéket // művelettel határozzuk meg, azaz osztási egész részt fogunk számolni). pl: pl: 5 2 5 2 2 5 2 5 3 3 + 1 5 2 = 2 2 + 1 5 2 = 5 5 2 = 10 5 2 = 5 2 2 5 + 1 5 3 = 2 1 + 1 5 3 = 9 5 3 = 4 3 3 4 Ezzel a módszerrel a következő törteket kapjuk: 1 1, 1 2, 2 1, 1 3, 3 2, 2 3, 3 1, 1 4, 4 3, 3 5, 5 2, 2 5, 5 3, 3 4, 4 1, stb.
Algoritmusok Pythonban A feladat megoldásához a racionális számokat most is tuple típusú adatként fogjuk kezelni. Az első függvény amit megírunk az x y szám meghatározása: def nextrac (x, y): nrx = (2 * (x // y) + 1) * y - x nry = y g = lnko (nrx, nry) return (nry // g, nrx // g) racionális szám utáni racionális
Algoritmusok Pythonban Az első n racionális szám listába való kigenerálása: def racionalis2(n): if n < 1: return [] L = [(1, 1)] x, y = 1, 1 while n > 1: x, y = nextrac(x, y) L += [(x, y)] n = n - 1 return L >>> racionalis2(10) [(1, 1), (1, 2), (2, 1), (1, 3), (3, 2), (2, 3), (3, 1), (1, 4), (4, 3), (3, 5)]
Algoritmusok Pythonban A feladat megoldásához most a racionális számokat Fraction típusként fogjuk kezelni. A Python Fraction típusának a használatához szükséges importálni a fractions modult. from fractions import Fraction >>> rac1 = Fraction(2,3) >>> rac2 = Fraction(4,5) >>> rac1 + rac2 Fraction(22, 15) >>> rac1 * rac2 Fraction(8, 15) >>> rac1.denominator 3 >>> rac1.numerator 2
Algoritmusok Pythonban Az x y racionális szám utáni racionális szám meghatározása így a kövekező lesz: from fractions import Fraction def nextracfrac (r): x, y = r.numerator, r.denominator temp = 2 * (x // y) + 1 res = Fraction(temp, 1) - Fraction(x, y) return Fraction(res.denominator, res.numerator) >>> racnr = Fraction(4,3) >>> nextracfrac(racnr) Fraction(3, 5)
Lánctörtek (Continued fraction) A lánctört egy emeletes tört, amely kétféle alakban is megadható, ahol a két alak átalakítható egymásba: a 0 + a 1 + b 1 a 2 + b 2 b 3 a 3 + b4... d 0 + d 1 + 1 d 2 + 1 1 d 3 + 1... A második alakot egyszerű lánctörtnek, a [d 0, d 1, d 2, d 3,... ] számsorozatot, pedig a lánctört jegyeinek hívjuk. Ha a [d 0, d 1, d 2, d 3,... ] számsorozat véges számú elemet tartalmaz, akkor véges lánctörtről beszélünk. A racionális számok mindegyike feĺırható egyszerű, véges lánctört alakba.
Lánctörtek, példa Ha meg akarjuk határozni az x racionális szám lánctörtjét, akkor y meghatározzuk az x és y osztási egész részét (//), illetve osztási maradékát (%), felüĺırjuk az x és y értékeket, majd ismételjük a műveletsort, amíg az x és y osztási maradéka nem lesz 0. Az algoritmus tehát a legnagyobb közös osztó meghatározásának az algoritmusa kiegészítve egy plusz művelettel az osztási egész rész meghatározásával. Példa, 61 lánctört jegyeinek a meghatározása: 47 x y x//y x%y 61 47 1 14 47 14 3 5 14 5 2 4 5 4 1 1 4 1 4 0
Lánctörtek, példa 61 47 = 1 + 1 3 + 1 2 + 1 1 + 1 4 61 lánctört jegyei: [1, 3, 2, 1, 4], vagy 47 61 47 = 1 + 1 3 + 2 + 1 1 1 + 1 3 + 1 1 61 lánctört jegyei: [1, 3, 2, 1, 3, 1] 47 61 tizedes alakja: 1.(2978723404255319148936170212765957446808510638) 47 Ha a lánctört utolsó jegye nem 1, akkor ez az x érték helyettesíthető két további értékkel: x 1, 1. A két alak ekvivalens.
Lánctörtek, példa Alakítsuk át 41 -t lánctörtté, hat. meg a lánctört jegyeket, és a tizedes alakot: 11 41 11 = 3 + 1 41 1 11 = 3 + 1 1 1 + 2 + 1 1 + 1 1 + 1 2 + 1 + 1 2 41 lánctört jegyei: [3, 1, 2, 1, 2], vagy 11 1 + 1 1 41 lánctört jegyei: [3, 1, 2, 1, 1, 1] 11 41 tizedes alakja: 3.(72) 11
Algoritmusok Pythonban 5. feladat Határozzuk meg az x y def lanct(x, y): talak = x / y L = [] while True: temp = x // y L += [temp] r = x % y if r == 0: break x = y y = r return (talak, L) >>> lanct(41, 11) (3.727272727272727, [3, 1, 2, 1, 2]) racionális szám tizedes alakját és lánctört jegyeit. >>> lanct(89, 55) (1.6181818181818182, [1, 1, 1, 1, 1, 1, 1, 1, 2])
Algoritmusok Pythonban Az előző feladatban átírjuk a maradékos osztást!! def lanct1(x, y): talak = x / y L = [] while True: temp = x // y L += [temp] r = x - temp * y if r == 0: break x = y y = r return (talak, L) >>> lanct(61, 47) (1.297872340425532, [1, 3, 2, 1, 4])
Algoritmusok Pythonban Az előző feladatban érték-ellenőrző műveleteket vezetünk be. def lanct2(x, y): if not float(x).is_integer() or not float(y).is_integer(): print ( a bemenet nem egesz szam ) return L = [] while True: temp = x // y L += [temp] r = x - temp * y if r == 0: break x = y y = r return L >>> lanct2(41, 11.2) a bemenet nem egesz szam >>> lanct2(41, 11.0) [3, 1, 2, 1, 2]
A Farey sorozat 6. feladat Írjunk programot, mely, meghatározza adott n-re, az n-ed rendű Farey sorozatot, ahol n-ed rendű Farey sorozatnak nevezzük a h típusú törtek k halmazának, növekvő sorrendben feĺırt elemeit, ahol 0 h k n, és 0 lnko(h, k) = 1. A sorozat első eleme:, utolsó eleme: 1. 1 1 A feladatot több algoritmussal is meg lehet oldani, I. változat: Az n + 1-ed rendű sorozat előálĺıtható a n-ed rendű sorozat alapján: az n-ed rendű sorozat a 1 b 1 és a 2 b 2 elemei közé beszúrjuk az a 1+a 2 b 1 +b 2 törtet, abban az esetben ha a nevező egyenlő n-el. a negyed rendű Farey sorozat:, 1, 1, 1, 2, 3, 1 1 4 3 2 3 4 1 0 az ötöd rendű Farey sorozat:, 1, 1, 1, 2, 1, 3, 2, 3, 4, 1 1 5 4 3 5 2 5 3 4 5 1 0
A Farey sorozat A következő alfarey függvény az n-ed rendű Farey sorozat alapján, amelyet az L lista tárol, meghatározza az (n+1)-ed rendű Farey sorozatot, amelyet az ujl listába tesz. def ujelem (a1, b1, a2, b2): return ialak(a1 + a2, b1 + b2) #az ialak egy korábban bemutatott függvény, meghatározza a tört #irreducibilis alakját def alfarey(l, n): ujl = [] for i in range(1, len(l)): (a1, b1) = L[i-1] (a2, b2) = L[i] temp = ujelem (a1, b1, a2, b2) ujl += [L[i-1]] if temp[1] == n: ujl += [temp] ujl += [L[i]] return ujl
A Farey sorozat Ha konstansként megadjuk a 4-ed rendű Farey sorozatot, akkor a következőképpen tudjuk meghatározni az 5-öd rendű Farey sorozatot: >>> L = [(0, 1), (1, 4), (1, 3), (1, 2), (2, 3), (3, 4), (1, 1)] >>> alfarey(l, 5) [(0, 1), (1, 5), (1, 4), (1, 3), (2, 5), (1, 2), (3, 5), (2, 3), (3, 4), (4, 5), (1, 1)] Házi feladat: Írjuk egy farey függvényt, amely az L = [(0,1), (1,1)] bemeneti lista alapján meghatározza az n-ed rendű Farey sorozatot!
A Farey sorozat A Farey sorozat előálĺıtása, II. változat: 0 az n-ed rendű sorozat első két eleme mindig:, 1, 1 n az a 1 b 1, a 2 b 2 elemek után következő a 3 elemet képlettel is meghatározhatjuk: b 3 a 3 b 3 = a 2 k a 1 b 2 k b 1 n+b1 k = a 4-ed rendű Farey sorozat elemei: 0 1, 1 4 1 4, 1 3 1 3, 1 2 1 2, 2 3 2 3, 3 4 k=1 k=2 k=3 k=2 k=1 b 2 1 k 0 4 k 1 = 1 3 ahol k = 1 k 1 3 k 4 = 1 2 ahol k = 1 k 1 2 k 3 = 2 3 ahol k = 2 k 1 3 k 2 = 3 4 ahol k = 3 k 2 4 k 3 = 1 1 ahol k = 4+1 4 4+4 3 4+3 2 4+2 3 4+3 4 = 1 = 2 = 3 = 2 = 1
A Farey sorozat def farey_(n): a1, b1 = 0, 1 a2, b2 = 1, n print ((a1, b1), end = " ") print ((a2, b2), end = " ") while b2 > 1: k = (n + b1) // b2 a3, b3 = a2 * k - a1, b2 * k - b1 print ((a3, b3), end = " ") a1, b1 = a2, b2 a2, b2 = a3, b3 >>> farey_(5) (0,1) (1,5) (1,4) (1,3) (2,5) (1,2) (3,5) (2,3) (3,4) (4,5) (1,1)