Ders 02 / 10
Sınıf Diyagramları
İlişki türü ve çokluk simgelerinin belirsizlikten aldığı pay: 20 simge 2048, 25 simge 64, 31 simge 1 sistem bırakıyor; ikili bir alanın simgesi tam bir bit alırken üç değerli bir alanınki 1,58 bit alıyor.
İçindekiler
Önceki ders tek bir sayı bıraktı: yirmi simgelik yapı gösterimi 2048 sistemi tek diyagrama düşürüyor. Sayı tek başına az şey söylüyor. Diyagrama simge eklemek onu düşürür, ama ne kadar düşürdüğü ölçülmedi — bir simge belirsizliği yarıya mı indiriyor, daha çoğunu mu alıyor, hiç almayanı var mı.
Sınıf gösterimi bu soruyu yanıtlamak için elverişli, çünkü ilişki simgelerinin her biri belirli bir olguyu yazıyor ve yazılmadığında o olgu düşüyor. Sınıfın, kalıtımın ve arayüzün ne olduğu Programlama Temelleri kursunda kuruldu; bu ders onları tanımlamıyor. Ölçtüğü tek şey şu: ilişki türü ve çokluk simgeleri, aynı gösterime düşen sistem sayısını kaç kat düşürüyor.
Simge Başına Bir Bit
Ortak tanım üç ayrıntı düzeyi tanımlıyor. Sıfırıncı düzeyde her bağın yalnız kaynağı, hedefi, yönü ve çokluğu yazılıyor. Birinci düzeyde yaşam alanı da yazılıyor: bağın bir yaşam döngüsü sahipliği taşıyıp taşımadığı. İkinci düzeyde topluluk taşıyan bağların sıralı ve benzersiz alanları da köşeli notlar olarak ekleniyor.
- YD8 — Üç düzey aynı sistem üzerinde ölçülür; değişen tek şey yazılan alan kümesidir.
- YD9 — Belirsizliğin bit karşılığı, aynı gösterime düşen sistem sayısının ikili logaritmasıdır. Tek sistem kalırsa bit sıfırdır ve gösterim geri çevrilebilir olmuştur.
"""M01/K06 ortak tanim (kesit): yapi gosterimi uc ayrinti duzeyinde ve her duzeyin ayni gosterime dusurdugu sistem sayisi. Sayim tam sayimdir.""" from itertools import product from math import log2 BAGLAR = [ {"ad": "b1", "kaynak": "IsEmri", "hedef": "Usta", "yon": "tek", "cokluk": "N:1", "yasam": "bagimsiz", "sirali": False, "benzersiz": True}, {"ad": "b2", "kaynak": "IsEmri", "hedef": "Kalem", "yon": "tek", "cokluk": "1:N", "yasam": "bagimli", "sirali": True, "benzersiz": False}, {"ad": "b3", "kaynak": "Kalem", "hedef": "Parca", "yon": "tek", "cokluk": "N:1", "yasam": "bagimsiz", "sirali": False, "benzersiz": True}, {"ad": "b4", "kaynak": "Usta", "hedef": "Tezgah", "yon": "cift", "cokluk": "N:M", "yasam": "bagimsiz", "sirali": False, "benzersiz": True}, {"ad": "b5", "kaynak": "IsEmri", "hedef": "Belge", "yon": "tek", "cokluk": "1:N", "yasam": "bagimli", "sirali": True, "benzersiz": True}, ] def gizli_alanlar(bag): alanlar = ["yasam"] if bag["cokluk"] in ("1:N", "N:M"): alanlar += ["sirali", "benzersiz"] return alanlar def yapi_gosterimi(baglar, ayrinti=0): simge = [] for b in baglar: s = {"kaynak": b["kaynak"], "hedef": b["hedef"], "yon": b["yon"], "cokluk": b["cokluk"]} if ayrinti >= 1: s["yasam"] = b["yasam"] if ayrinti >= 2: for a in gizli_alanlar(b): s[a] = b[a] simge.append(s) return simge def simge_sayisi(gosterim): return sum(len(s) for s in gosterim) def ayni_gosterime_dusen(baglar, ayrinti=0): secenek = {"yasam": ("bagimsiz", "bagimli"), "sirali": (False, True), "benzersiz": (False, True)} hedef = yapi_gosterimi(baglar, ayrinti) uzaylar = [] for b in baglar: alanlar = gizli_alanlar(b) uzaylar.append([dict(zip(alanlar, d)) for d in product(*[secenek[a] for a in alanlar])]) sayi = 0 for secim in product(*uzaylar): aday = [dict(b, **s) for b, s in zip(baglar, secim)] if yapi_gosterimi(aday, ayrinti) == hedef: sayi += 1 return sayi YAZILAN = {0: "kaynak/hedef/yon/cokluk", 1: "+ yasam", 2: "+ sirali , benzersiz"} olcum = [] print("ayrinti yazilan alan simge dusen sistem bit") for a in (0, 1, 2): g = yapi_gosterimi(BAGLAR, a) s, d = simge_sayisi(g), ayni_gosterime_dusen(BAGLAR, a) olcum.append((s, d)) print(f" {a:5d} {YAZILAN[a]:23s}{s:6d}{d:14d}{log2(d):7.2f}") print() print("gecis eklenen simge alinan bit simge basina bit") for (s0, d0), (s1, d1) in zip(olcum, olcum[1:]): print(f" {s0:2d} -> {s1:2d} simge{s1 - s0:12d}{log2(d0) - log2(d1):12.2f}" f"{(log2(d0) - log2(d1)) / (s1 - s0):18.2f}")
ayrinti yazilan alan simge dusen sistem bit
0 kaynak/hedef/yon/cokluk 20 2048 11.00
1 + yasam 25 64 6.00
2 + sirali , benzersiz 31 1 0.00
gecis eklenen simge alinan bit simge basina bit
20 -> 25 simge 5 5.00 1.00
25 -> 31 simge 6 6.00 1.00
Üç sayı yan yana. Sistem: beş bağ, 31 olgu. Gösterim: 20, 25 ya da 31 simge. Bedel: sırasıyla 2048, 64 ve 1 sistem.
Alt tablo dersin ana sonucunu veriyor: eklenen her simge tam olarak bir bit alıyor. Beş yaşam simgesi beş bit, altı sıralılık ve benzersizlik notu altı bit götürüyor; ne daha az ne daha çok. Son satırda belirsizlik sıfır bite iniyor, yani 31 simgelik gösterim geri çevrilebilir hâle geliyor — o gösterimi üreten tek bir sistem var ve okuyucu seçim yapmak zorunda kalmıyor.
Bu tam örtüşme bir rastlantı değil. Gizli alanların hepsi ikili: yaşam iki değer, sıralı iki değer, benzersiz iki değer. Bir ikili alanı yazmak seçenek uzayını tam yarıya indirir ve yarıya inen bir uzay tam bir bit kaybeder. Bir sonraki bölüm bu koşulun kalktığı durumu ölçecek.
Ölçünün kapsamı da burada sınırlanıyor. Model yalnız bağ satırlarını sayıyor; sınıf adları, öznitelikler ve işlemler modelin dışında ve dolayısıyla 2048 sayısı yalnız ilişki belirsizliğidir. Gerçek bir sınıf gösterimi bunlardan fazlasını taşır ve taşıdığı her yeni alan kendi gizli alanlarını da getirir; buradaki sayı bir alt sınırdır, bir toplam değildir.
Yaşam Döngüsü Sahipliği
Yaşam simgesinin aldığı bit, gösterimde iki ilişki türünü ayırıyor. Sıkı bileşim (composition) bir yaşam döngüsü sahipliği bildirir: sahip nesne silindiğinde parça nesne de silinir, çünkü parçanın sahibinden bağımsız bir varlığı yoktur. Gevşek bileşim (aggregation) sahiplik iddia etmez; parça, bütün silindikten sonra da durur. Bileşim kavramının kendisi Programlama Temelleri kursunda kuruldu; buradaki ek, iki türün ayrımının hangi olguyu taşıdığıdır.
Ayrım, gösterimde tek simge; örnek düzeyinde ise silinen nesne sayısı.
- YD10 — Örnek durum: bir iş emri, üç kalem, iki belge, bir usta, iki tezgâh, üç parça — toplam on iki nesne.
- YD11 — Silme kökten başlar ve yalnız bağımlı bağlar üzerinden geçişli yayılır. Bir bağın hedefi silinmediyse ve kaynağı silindiyse, hedef bağsız kalır.
- YD12 — Bir topluluğun geçerli içerik sayısı için dört parçalık bir katalog ve üç kalemlik bir iş emri alınır.
"""Yazilmayan alanlarin ornek duzeyindeki karsiligi. Yasam alani silme yayilimini , sirali ve benzersiz alanlari bir toplulugun gecerli icerik sayisini belirler. Ornek durum: 1 is emri , 3 kalem , 2 belge , 1 usta , 2 tezgah , 3 parca.""" from itertools import product NESNE = {"IsEmri": 1, "Kalem": 3, "Parca": 3, "Usta": 1, "Tezgah": 2, "Belge": 2} BAG = [("IsEmri", "Usta"), ("IsEmri", "Kalem"), ("Kalem", "Parca"), ("Usta", "Tezgah"), ("IsEmri", "Belge")] # ortak tanimin b1..b5 sirasi GERCEK = ("bagimsiz", "bagimli", "bagimsiz", "bagimsiz", "bagimli") def silme(yasamlar, kok="IsEmri"): """Siki bilesim yasam dongusu sahipligidir: sahip silinince parca da silinir.""" silinen, degisti = {kok}, True while degisti: degisti = False for (k, h), y in zip(BAG, yasamlar): if y == "bagimli" and k in silinen and h not in silinen: silinen.add(h) degisti = True bagsiz = {h for (k, h), y in zip(BAG, yasamlar) if y == "bagimsiz" and k in silinen and h not in silinen} return sum(NESNE[t] for t in silinen), sum(NESNE[t] for t in bagsiz), sorted(silinen) dagilim = {} for y in product(("bagimsiz", "bagimli"), repeat=5): n = silme(y)[0] dagilim[n] = dagilim.get(n, 0) + 1 print("toplam nesne:", sum(NESNE.values()), "| yasam secimi:", 2 ** 5, "| ayri silinen-nesne degeri:", len(dagilim)) print(" silinen nesne:", sorted(dagilim), "-> en az", min(dagilim), ", en cok", max(dagilim)) n, b, kume = silme(GERCEK) print("yasam yazildiginda tek deger:", n, "nesne siliniyor", kume, "|", b, "nesne bagsiz kaliyor") print() print("b2 (IsEmri -> Kalem , 1:N): 4 parcali katalog , 3 kalemlik is emri") print(" sirali benzersiz gecerli icerik sayisi") for sirali in (False, True): for benzersiz in (False, True): icerik = set() for d in product(range(4), repeat=3): if benzersiz and len(set(d)) != len(d): continue icerik.add(d if sirali else tuple(sorted(d))) print(f" {str(sirali):8s}{str(benzersiz):11s}{len(icerik):10d}")
toplam nesne: 12 | yasam secimi: 32 | ayri silinen-nesne degeri: 11 silinen nesne: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12] -> en az 1 , en cok 12 yasam yazildiginda tek deger: 6 nesne siliniyor ['Belge', 'IsEmri', 'Kalem'] | 4 nesne bagsiz kaliyor b2 (IsEmri -> Kalem , 1:N): 4 parcali katalog , 3 kalemlik is emri sirali benzersiz gecerli icerik sayisi False False 20 False True 4 True False 64 True True 24
Yirmi simgelik gösterime bakan biri, bir iş emri silindiğinde kaç nesnenin gideceğini bilemiyor. Otuz iki yaşam seçimi on bir ayrı silinen-nesne değeri üretiyor ve aralık 1 ile 12 arasında: bütün bağlar bağımsızsa yalnız iş emri siliniyor, hepsi bağımlıysa sistemdeki her nesne gidiyor. Diyagram bu on bir sonucun hepsiyle uyumlu.
Aralıkta bir boşluk var ve nedeni öğreticidir: on iki değerden yalnız 11 çıkmıyor. Nesneler tek tek değil kümeler hâlinde gidiyor — üç kalem birlikte, üç parça birlikte, iki belge birlikte — ve bu kümelerin hiçbir birleşimi tam on bir nesne etmiyor. Silme davranışı sürekli bir aralık değil, bağ yapısının izin verdiği ayrık bir değer kümesidir.
Yaşam simgeleri yazıldığında sonuç tek bir değere iniyor: 6 nesne siliniyor — iş emri, üç kalem, iki belge — ve 4 nesne bağsız kalıyor: kalemlerin işaret ettiği üç parça ile atanmış usta. Beş simgenin aldığı beş bit, örnek düzeyinde bir aralığı tek bir sayıya indiriyor. Bunun karşılığı somuttur: silme yordamını yazan kişi, gösterimde o simge yoksa kararı kendisi verir ve verdiği karar diyagramda yazmaz.
Bağsız kalan dört nesne ayrı bir kalemdir ve gevşek bileşimin bedelini gösterir. Parçalar silinmiyor, ama artık onlara işaret eden bir kalem yok; sistemde ulaşılamaz durur. Sıkı bileşim bu durumu ortadan kaldırır ve yerine başka bir şey koyar: sahibi silinen her nesne, başka bir yerden kullanılıyor olsa bile gider.
Çokluk simgesi de aynı biçimde eksik. Gösterim IsEmri ile Kalem arasında 1:N yazıyor ve
bunun anlamı “bir iş emrinin birden çok kalemi var” cümlesiyle sınırlı. Dört parçalık bir
katalogda üç kalemlik bir iş emrinin kaç ayrı geçerli içeriği olduğu ise yazılmayan iki alana
bağlı: sıralı ve tekrar kabul eden bir listede 64, sırasız ve benzersiz bir kümede 4.
Aradaki on altı katlık aralık gösterimde tek bir 1:N olarak duruyor.
Simge Her Zaman Bir Bit Almaz
Simge başına tam bir bit sonucu, gizli alanların ikili olmasından geliyordu. Ortak tanımın çözünürlük kuralı gereği bu koşul ikinci bir yapılandırmayla sınanır: yaşam alanı üç değer alsaydı ne olurdu.
- YD13 — Üç değerli yaşam alanı şunları ayırır: sahiplik iddia etmeyen düz bağ (association), parçayı paylaşan gevşek bileşim, parçayı yaşam döngüsüyle birlikte taşıyan sıkı bileşim. Yazılan simge sayısı değişmez; yalnız simgenin ayırabildiği değer sayısı artar.
"""Ikinci yapilandirma: yasam alani ikili degil uc degerli olsaydi. Uc deger: duz bag , gevsek bilesim , siki bilesim. Yazilan simge sayisi degismez ; degisen , bir simgenin aldigi bit sayisidir. Sayim yine tam sayimdir.""" from itertools import product from math import log2 COKLUKLAR = ["N:1", "1:N", "N:1", "N:M", "1:N"] # ortak tanimin bes bagi def gizli_alanlar(cokluk): return ["yasam", "sirali", "benzersiz"] if cokluk in ("1:N", "N:M") else ["yasam"] def tam_sayim(yasam_degeri, yasam_yazili): uzaylar = [] for c in COKLUKLAR: secenek = [range(1 if yasam_yazili else yasam_degeri) if a == "yasam" else range(2) for a in gizli_alanlar(c)] uzaylar.append(list(product(*secenek))) return sum(1 for _ in product(*uzaylar)) print("yasam degeri yasam yazili simge dusen sistem bit") for d in (2, 3): for yazili, simge in ((False, 20), (True, 25)): s = tam_sayim(d, yazili) print(f"{d:12d} {str(yazili):12s}{simge:7d}{s:14d}{log2(s):8.2f}") print() for d in (2, 3): alinan = log2(tam_sayim(d, False)) - log2(tam_sayim(d, True)) print(f"{d} degerli yasam alani: 5 simge {alinan:.2f} bit aliyor" f" , simge basina {alinan / 5:.2f}")
yasam degeri yasam yazili simge dusen sistem bit
2 False 20 2048 11.00
2 True 25 64 6.00
3 False 20 15552 13.92
3 True 25 64 6.00
2 degerli yasam alani: 5 simge 5.00 bit aliyor , simge basina 1.00
3 degerli yasam alani: 5 simge 7.92 bit aliyor , simge basina 1.58
Gösterim iki durumda da aynı: 20 simgeden 25 simgeye. Alınan bit ise 5,00’ten 7,92’ye çıkıyor, simge başına 1,58. Kural şu biçimde düzeltiliyor: bir simge, ayırdığı değer sayısının ikili logaritması kadar bit alır. İkili bir alanda bu tam bir bittir; üç değerli bir alanda 1,58, dört değerli bir alanda iki bit olur.
Sonucun ters okuması daha kullanışlı. Yaşam simgesi yazılmadığında kaybedilen bilgi, o simgenin kaç şeyi ayırabildiğine bağlıdır. Bağ ile gevşek bileşimi ayırmayan bir gösterimde yazılmayan simge 1,00 bit götürür; ikisini ayıran bir gösterimde aynı yazılmayan simge 1,58 bit götürür. Gösterimi zenginleştirmek, o gösterimin eksik bırakılmasını da pahalılaştırır — ve bu iki etki aynı tabloda görünmedikçe zenginleştirme bir kazanç sayılamaz.
Özet
- Ayrıntısız yapı gösterimi 20 simge ve 2048 sistem; yaşam simgeleri eklenince 25 simge ve 64 sistem; sıralılık ile benzersizlik notları da eklenince 31 simge ve tek sistem kalıyor.
- Bit cinsinden ölçüldüğünde eklenen her simge tam olarak bir bit alıyor: 5 simge 5,00 bit, 6 simge 6,00 bit. Otuz bir simgelik gösterimde belirsizlik sıfır bittir, yani gösterim geri çevrilebilir olmuştur.
- Sıkı bileşim yaşam döngüsü sahipliği bildirir, gevşek bileşim bildirmez. Yaşam simgeleri yazılmadığında bir iş emrinin silinmesi 12 nesnelik sistemde 11 ayrı sonuçla uyumludur (1 ile 12 arası); yazıldığında sonuç tek değere iner: 6 silinen, 4 bağsız kalan nesne.
- Çokluk simgesi topluluğun varlığını söyler, içeriğini söylemez: dört parçalık katalogda üç
kalemlik bir iş emrinin geçerli içerik sayısı sıralı ve tekrarlıysa 64, sırasız ve
benzersizse 4 — on altı katlık aralık gösterimde tek bir
1:Nolarak durur. - Simge başına bir bit yalnız ikili alanlar için geçerlidir. Yaşam alanı üç değerli olsaydı 20 simgelik gösterime düşen sistem 15552 olurdu ve aynı beş simge 7,92 bit, yani simge başına 1,58 bit alırdı.
Sonraki Adım
Bu derste sayılan her şey durağandı: hangi tür neye bağlı, kaç tane, kim kimin yaşam döngüsünü taşıyor. Sistemin çalışırken kaç ayrı parçaya bölündüğü hiç sorulmadı — beş bağın altı sınıfı tek bir birimde de koşabilir, altı ayrı birimde de, ve otuz bir simgelik gösterim bunların hiçbirini ayırt etmiyor.
Sonraki ders aynı sınıf kümesini çalışma zamanı birimlerine bölüyor ve bölüntüyü sayıyor: altı sınıf kaç ayrı bileşen bölüntüsüne düşüyor, bir bileşen gösterimi bunların kaçını aynı çizime indiriyor, ve bileşenler düğümlere yerleştirildiğinde hangi bağlar uzak bağ hâline geliyor.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.