Ders 03 / 22
Planlayıcı ve Yürütücü Ayrımı
Karar veren ile çalıştıran yanın ayrılmasının kattığı ve ödettiği: 24 kurgu görevde tek döngü 0,9583 görev başarımı, 97 adım, 74 araç çağrısı ve 11978 belirteç veriyor; planlayıcı ve yürütücü ayrıldığında başarım 0,8750, adım 118, çağrı 71 ve belirteç 10345 oluyor. Başarım farkı bölünmüş düzenin kendi iki koşum farkına eşittir ve ölçülmemiş sayılır. Fazladan adım tam olarak görev başına bir planlama adımıdır. Belirteç iki koşumda da yüzde on üçten fazla düşüyor, çünkü yürütücü akıl yürütme izini değil planı taşıyor. Planın konumlarının 0,8868'i doğru ve yirmi dört planın on sekizi baştan sona doğru; yanlış bir konum körlemesine yürütüldüğü için düzeltme ancak plan tükendikten sonra başlıyor.
İçindekiler
Önceki ders tek bir döngünün derinlikle bozulduğunu ölçtü: dizinin dördüncü adımında doğru aracı seçme payı yarıya iniyordu. Bunun bir nedeni yapısaldır — aynı çağrı hem bütün işin planını hem de sıradaki tek eylemi taşıyor.
Akla gelen ilk düzenleme işi ikiye bölmektir. Bir yan işin planını tek seferde çıkarsın, öbür yan o planın adımlarını yürütsün ve kendi başına araç seçmesin. Bu ders bölmeyi kurar ve iki soruyu birlikte sorar: bölme başarımı yükseltiyor mu, ve neyi ödetiyor. Taban çizgisi düzeneksiz döngüdür — önceki dersin tek döngüsü.
- AM22. Ortam, araç kümesi, görev kümesi ve tek döngü önceki derslerdeki tanımın aynısıdır ve kurgudur. Tohum 20260218, ikinci koşum 20260219.
- AM23. Bölünmüş düzen iki parçadır: planlayıcı tek bir çağrıda bütün planı yazar, yürütücü planı sırayla çalıştırır ve kendi başına araç seçmez.
- AM24. Planlayıcı gözlem görmez. Bütün konumları aynı anda, aynı bilgiyle seçer; bu yüzden
derinlik cezası ona işlemez ve her konumu düz
gorme(1)payıyla seçer. - AM25. Planlama bir adımdır ve bütçeden düşer. İki kurulum da aynı sekiz adım bütçesiyle koşulur.
- AM26. Yürütücü planı körlemesine yürütür: yanlış bir konum da çalıştırılır.
- AM27. Plan bitip iş bitmediyse kalan konumlar tek döngünün kuralıyla denenir; düzeltme ancak plan tükendikten sonra başlar.
- AM28. Belirteç iki kurulumda ayrı sayılır. Tek döngünün adımı
60 + 22 x iz uzunluğu, planlayıcının çağrısı60 + 25 x plan uzunluğu, yürütücünün adımı40 + 10 x iz uzunluğu; her gözlem 30 belirteçtir. Yürütücü akıl yürütme izini değil planı taşır. - AM29. Plan uzunluğu görevin dizi uzunluğudur; planlayıcı diziyi bilmez, uzunluğunu bilir.
- AM30. Sayılan birimler başarım, adım, araç çağrısı, belirteç ve araç hatasıdır; iki koşum farkının altında kalan fark ölçülmemiş sayılır.
Bölme: Bir Plan, Bir Yürütme
Bölünmüş düzende karar bir kez verilir. Planlayıcı isteği okur ve sayac_oku -> tuketim -> tarife
gibi bir dizi yazar. Yürütücü o diziyi sırayla çalıştırır ve seçim yapmadığı için adımı ucuzdur:
akıl yürütme izini değil planı ve biriken durumu taşır. Bölmenin bedeli aynı cümlede yazılıdır —
plan gözlemden önce yazıldığı için, yanlış bir konum çalıştırılana kadar yanlış olduğu
anlaşılmaz.
# BENZETICI -- KURGUDUR. Gercek bir model ucu, arac sunucusu ya da calisma # zamani cagrilmaz; ortam da araclar da gorevler de kurgudur. TOHUM, M32 = 20260218, 0xFFFFFFFF def uretec(t): x = ((t ^ (t >> 16)) * 2246822507) & M32 x = ((x ^ (x >> 13)) * 3266489909) & M32 s = [(x ^ (x >> 16)) & M32] def sonraki(): s[0] = (s[0] * 1664525 + 1013904223) & M32 return s[0] / 4294967296 return sonraki def ayrik(u, w): t = 0.0 for i, x in enumerate(w): t += x if u < t: return i return len(w) - 1 def belirtecle(m): b = [] for s in str(m).lower().replace(",", " , ").split(): while len(s) > 5: b.append(s[:5]) s = s[5:] b.append(s) return b def izno(m): h = 2166136261 for c in str(m): h = ((h ^ ord(c)) * 16777619) & M32 return h # ---- KURGU ortam: olcum aginin kayitlari BOLGE = ["dogu", "bati", "kuzey", "guney", "merkez"] TIP = ["mesken", "isyeri"] ABONE = {} for i in range(60): r = uretec(TOHUM + 31 * i) onceki = 10000 + int(r() * 80000) ABONE[f"A{i + 1:03d}"] = {"bolge": BOLGE[int(r() * 5)], "tip": TIP[int(r() * 2)], "onceki": onceki, "simdiki": onceki + int(r() * 70)} BASAMAK, USTU = ((10, 4), (25, 7), (40, 11)), 16 ISYERI_KAT = 2 BELGE = {"TR01": "tarife basamaklari 10 25 40 metrekup ve ustu", "TR02": "isyeri abonesinde birim ucret iki katidir", "SY01": "endeks farki tuketimi verir sayac donusu 100000 eklenir", "AR01": "ariza kaydi acildiginda saha ekibi iki gun icinde gider", "KS01": "planli kesinti duyurusu bir hafta once yayimlanir"} CAGRI = [0] # arac cagri sayaci def _bedel(m3, tip): kalan, alt, top = m3, 0, 0 for ust, birim in BASAMAK: dilim = min(kalan, ust - alt) if dilim <= 0: break top += dilim * birim kalan -= dilim alt = ust top += kalan * USTU return top * (ISYERI_KAT if tip == "isyeri" else 1) def t_sayac_oku(abone=None, **_): a = ABONE.get(abone) if a is None: return {"hata": "abone yok"} return {"onceki": a["onceki"], "simdiki": a["simdiki"], "tip": a["tip"], "bolge": a["bolge"]} def t_tuketim(onceki=None, simdiki=None, **_): if onceki is None or simdiki is None: return {"hata": "eksik alan"} f = simdiki - onceki return {"m3": f + 100000 if f < 0 else f} def t_tarife(m3=None, tip="mesken", **_): if m3 is None: return {"hata": "eksik alan"} return {"tutar": _bedel(m3, tip)} def t_belge(anahtar=None, **_): if not anahtar: return {"hata": "eksik alan"} ab = set(belirtecle(anahtar)) en, kod = -1, None for k, m in BELGE.items(): o = len(ab & set(belirtecle(m))) if o > en: en, kod = o, k return {"kod": kod, "metin": BELGE[kod]} if en > 0 else {"hata": "bulunamadi"} def t_kayit(abone=None, sutun=None, deger=None, **_): if not (abone and sutun and deger is not None): return {"hata": "eksik alan"} return {"yazildi": True, "abone": abone, "sutun": sutun, "deger": deger} ARAC = { "sayac_oku": {"islev": t_sayac_oku, "alan": ("abone",), "yan_etki": False}, "tuketim": {"islev": t_tuketim, "alan": ("onceki", "simdiki"), "yan_etki": False}, "tarife": {"islev": t_tarife, "alan": ("m3", "tip"), "yan_etki": False}, "belge_ara": {"islev": t_belge, "alan": ("anahtar",), "yan_etki": False}, "kayit_yaz": {"islev": t_kayit, "alan": ("abone", "sutun", "deger"), "yan_etki": True}, } ARAC_ADI = list(ARAC) def cagir_arac(ad, durum): """Sema disindaki alanlar suzulur; eksik alan aracin kendi hatasidir.""" CAGRI[0] += 1 if ad not in ARAC: return {"hata": "arac yok"} kw = {a: durum[a] for a in ARAC[ad]["alan"] if a in durum} return ARAC[ad]["islev"](**kw) # ---- KURGU gorevler: her biri bilinen bir arac dizisiyle cozulur GOREV = [] for i in range(24): r = uretec(TOHUM + 9973 * i) ab = f"A{1 + int(r() * 60):03d}" t = ayrik(r(), [0.30, 0.22, 0.20, 0.28]) if t == 0: GOREV.append({"ad": f"G{i + 1:02d}", "tur": "bedel", "abone": ab, "istek": f"{ab} abonesinin bu donem bedeli nedir", "dizi": ("sayac_oku", "tuketim", "tarife")}) elif t == 1: GOREV.append({"ad": f"G{i + 1:02d}", "tur": "tuketim", "abone": ab, "istek": f"{ab} abonesinin bu donem tuketimi kac metrekup", "dizi": ("sayac_oku", "tuketim")}) elif t == 2: GOREV.append({"ad": f"G{i + 1:02d}", "tur": "belge", "abone": ab, "istek": "sayac donusunde endeks farki nasil hesaplanir", "dizi": ("belge_ara",)}) else: GOREV.append({"ad": f"G{i + 1:02d}", "tur": "kayit", "abone": ab, "istek": f"{ab} abonesinin bedelini hesapla ve kayda yaz", "dizi": ("sayac_oku", "tuketim", "tarife", "kayit_yaz")}) def dogru_yanit(g): a = ABONE[g["abone"]] f = a["simdiki"] - a["onceki"] m3 = f + 100000 if f < 0 else f if g["tur"] == "tuketim": return m3 if g["tur"] == "belge": return "SY01" return _bedel(m3, a["tip"]) # ---- KURGU ajan: her adimda bir arac secer ya da biter def gorme(d): return max(0.34, 0.80 - 0.09 * (d - 1)) # dogru araci secme payi, derinlikle duser def ajan(g, en_cok_adim=8, tohum=TOHUM, oz_elestiri=False, onay=False): """KURGU ajan dongusu. Gercek bir model cagrilmaz; arac secimi gorevin dizisine ve derinlige bagli tek bir cekilisten gelir.""" r = uretec(tohum ^ izno(g["ad"])) alan = {"abone": g["abone"], "anahtar": g["istek"], "sutun": "bedel"} iz, adim, bel, hata = [], 0, 0, 0 dizi, k = g["dizi"], 0 while adim < en_cok_adim: adim += 1 bel += 60 + 22 * len(iz) hedef = dizi[k] if k < len(dizi) else None if hedef is None: # is bitti , ajan durmali if r() < 0.88: return {"bitti": True, "adim": adim, "iz": iz, "belirtec": bel, "hata": hata, "yanit": alan.get("sonuc"), "onay": alan.get("onay", 0)} sec = ARAC_ADI[int(r() * len(ARAC_ADI))] else: sec = hedef if r() < gorme(k + 1) else ARAC_ADI[int(r() * len(ARAC_ADI))] if ARAC[sec]["yan_etki"] and onay: alan["onay"] = alan.get("onay", 0) + 1 if sec == "kayit_yaz": alan["deger"] = alan.get("sonuc") s = cagir_arac(sec, alan) iz.append((sec, "hata" in s)) bel += 30 if "hata" in s: hata += 1 if oz_elestiri: bel += 40 continue alan.update({kk: vv for kk, vv in s.items() if kk != "hata"}) if sec == "tuketim": alan["sonuc"] = s["m3"] if sec == "tarife": alan["sonuc"] = s["tutar"] if sec == "belge_ara": alan["sonuc"] = s["kod"] if sec == hedef: k += 1 return {"bitti": False, "adim": adim, "iz": iz, "belirtec": bel, "hata": hata, "yanit": alan.get("sonuc"), "onay": alan.get("onay", 0)} def planla_yurut(g, en_cok_adim=8, tohum=TOHUM): """BOLUNMUS duzen: PLANLAYICI tek cagrida butun plani yazar; gozlem gormedigi icin her konumu duz gorme(1) payiyla secer. YURUTUCU plani sirayla calistirir ve secim yapmaz; plan bitip is bitmediyse kalan konumlar tek dongunun kuraliyla denenir.""" r = uretec(tohum ^ izno("plan" + g["ad"])) dizi = g["dizi"] plan = [d if r() < gorme(1) else ARAC_ADI[int(r() * len(ARAC_ADI))] for d in dizi] alan = {"abone": g["abone"], "anahtar": g["istek"], "sutun": "bedel"} iz, adim, hata, k = [], 1, 0, 0 # planlama bir adimdir bel = 60 + 25 * len(plan) # planlayicinin cagrisi while adim < en_cok_adim: adim += 1 bel += 40 + 10 * len(iz) # yurutucu izi degil plani tasir hedef = dizi[k] if k < len(dizi) else None if hedef is None: if r() < 0.88: break sec = ARAC_ADI[int(r() * len(ARAC_ADI))] elif len(iz) < len(plan): sec = plan[len(iz)] # yurutucu planin sirasini izler else: sec = hedef if r() < gorme(k + 1) else ARAC_ADI[int(r() * len(ARAC_ADI))] if sec == "kayit_yaz": alan["deger"] = alan.get("sonuc") s = cagir_arac(sec, alan) iz.append((sec, "hata" in s)) bel += 30 if "hata" in s: hata += 1 continue alan.update({kk: vv for kk, vv in s.items() if kk != "hata"}) for a, b in (("tuketim", "m3"), ("tarife", "tutar"), ("belge_ara", "kod")): if sec == a: alan["sonuc"] = s[b] if sec == hedef: k += 1 return {"adim": adim, "iz": iz, "belirtec": bel, "hata": hata, "plan": plan, "yanit": alan.get("sonuc")} g = [x for x in GOREV if x["ad"] == "G05"][0] s = planla_yurut(g) print(f"{g['ad']} ({g['tur']}) dogru dizi :", " -> ".join(g["dizi"])) print(" plan :", " -> ".join(s["plan"])) print(" yurutulen :", " -> ".join(f"{a}{' [hata]' if h else ''}" for a, h in s["iz"])) print(f" adim {s['adim']} belirtec {s['belirtec']} arac hatasi {s['hata']}" f" yanit {s['yanit']} dogru {dogru_yanit(g)}")
G05 (bedel) dogru dizi : sayac_oku -> tuketim -> tarife plan : tarife -> tuketim -> tarife yurutulen : tarife [hata] -> tuketim [hata] -> tarife [hata] -> sayac_oku -> tuketim -> tarife adim 8 belirtec 805 arac hatasi 3 yanit 550 dogru 550
Planın ilk konumu yanlıştır ve bu tek yanlış bütün planı boşa çıkarıyor. tarife durumda m3
bulamadığı için hata veriyor, tuketim endeksler okunmadığı için hata veriyor, üçüncü konum yine
tarife ve yine hata. Yürütücü plana bağlı olduğundan üçünü de çalıştırmak zorunda; düzeltme ancak
plan tükendiğinde başlıyor. Doğru yanıt sonunda çıkıyor ama üç araç hatası ödendikten sonra.
Bölmenin Kattığı ve Ödettiği
Aynı yirmi dört görev iki kurulumda, iki tohumda ve aynı sekiz adım bütçesiyle koşturulur.
def olc(kur, tohum=TOHUM): CAGRI[0] = 0 bas = adim = bel = hata = 0 for x in GOREV: y = kur(x, tohum=tohum) adim, bel, hata = adim + y["adim"], bel + y["belirtec"], hata + y["hata"] bas += y["yanit"] == dogru_yanit(x) return bas / len(GOREV), adim, CAGRI[0], bel, hata print("kurulum kosum basarim adim cagri belirtec hata") for ad, kur in (("tek dongu", ajan), ("planlayici + yurutucu", planla_yurut)): for et, tohum in (("A", TOHUM), ("B", TOHUM + 1)): z = olc(kur, tohum) print(f"{ad:<22} {et:>5} {z[0]:>8.4f} {z[1]:>6} {z[2]:>6} {z[3]:>9} {z[4]:>5}") top = sum(len(x["dizi"]) for x in GOREV) for et, tohum in (("A", TOHUM), ("B", TOHUM + 1)): p = [planla_yurut(x, tohum=tohum)["plan"] for x in GOREV] kon = sum(a == b for pl, x in zip(p, GOREV) for a, b in zip(pl, x["dizi"])) tam = sum(list(pl) == list(x["dizi"]) for pl, x in zip(p, GOREV)) print(f"plan {et} : dogru konum {kon}/{top} = {kon / top:.4f} ;" f" tamami dogru plan {tam}/{len(GOREV)}")
kurulum kosum basarim adim cagri belirtec hata tek dongu A 0.9583 97 74 11978 8 tek dongu B 0.9583 98 74 11994 7 planlayici + yurutucu A 0.8750 118 71 10345 10 planlayici + yurutucu B 0.9583 116 70 10135 12 plan A : dogru konum 47/53 = 0.8868 ; tamami dogru plan 18/24 plan B : dogru konum 47/53 = 0.8868 ; tamami dogru plan 18/24
Başarım sütunu bulgu vermiyor. Tek döngü iki koşumda da 0,9583; bölünmüş düzen 0,8750 ve 0,9583. Bölünmüş düzenin kendi iki koşum farkı 0,0833’tür; iki kurulum arasındaki fark birinci koşumda tam olarak 0,0833, ikincisinde sıfırdır. Fark bandın içindedir ve bölmenin başarıma etkisi ölçülmemiş sayılır. Gözle görülen bir fark, ölçülmüş bir fark değildir.
Adım sütununun farkı ölçülmüştür ve nereden geldiği tam olarak hesaplanabilir. Bölünmüş düzen her göreve bir planlama adımı ekliyor, yani yirmi dört adım; 97 artı 24 121 eder, gerçekleşen 118’dir. Aradaki üç adımın karşılığı yandaki sütundadır: araç çağrısı 74’ten 71’e iniyor. Plan yürütücüyü bir miktar boşa çağrıdan koruyor, ama planlamanın kendisi bu kazancın sekiz katını geri alıyor.
Belirteç sütunu bölmenin kattığı yerdir: 11978 ve 11994 karşısında 10345 ve 10135, yani yüzde 13,6 ve yüzde 15,5 düşüş. İki kurulumun kendi bantları 16 ve 210 belirteçtir; fark bandın kat kat üstündedir ve ölçülmüştür. Nedeni tanımdadır — tek döngüde her adım büyüyen akıl yürütme izini yeniden taşır, yürütücüde ise adım sabit bir planı taşır.
Araç hatası ters yöne gidiyor: 8 ve 7 karşısında 10 ve 12. Yön iki koşumda da aynıdır ve mekanizması bellidir; körlemesine yürütülen yanlış konum, durumda alanı bulunmayan bir aracı çağırır. Ama bantlar 1 ve 2 iken fark birinci koşumda 2’dir: yönü mekanizmadan biliyoruz, büyüklüğünü bu ölçekte ölçemiyoruz.
Son iki satır bölmenin sınırını veriyor. Planın konumlarının 0,8868’i doğru, ama yirmi dört planın yalnız 18‘i baştan sona doğru. Plan uzadıkça tamamının doğru olma olasılığı düşer ve tek bir yanlış konum G05’teki gibi bütün planı boşa çıkarabilir. Bölmek kararı tek bir noktaya toplar; o noktadaki hatanın bedelini de tek bir noktada toplar.
Özet
- Bölünmüş düzende planlayıcı bütün planı gözlemden önce yazar, yürütücü onu sırayla ve körlemesine çalıştırır; düzeltme ancak plan tükendikten sonra başlar.
- Başarım tek döngüde 0,9583 ve 0,9583, bölünmüş düzende 0,8750 ve 0,9583; fark bölünmüş düzenin kendi iki koşum farkına eşittir ve ölçülmemiş sayılır.
- Bölmenin eklediği adım tam olarak görev başına bir planlama adımıdır: 97 adıma 24 eklenir, araç çağrısı 74’ten 71’e indiği için toplam 118’de kalır.
- Belirteç 11978’den 10345’e ve 11994’ten 10135’e iner; düşüş bandın kat kat üstündedir, çünkü yürütücü akıl yürütme izini değil planı taşır.
- Araç hatası bölünmüş düzende iki koşumda da yüksektir (10 ve 12 karşısında 8 ve 7); yönü mekanizmadan bellidir, büyüklüğü bu ölçekte ölçülemez.
- Planın konumlarının 0,8868’i doğrudur ama tamamı doğru plan yirmi dörtte on sekizdir; tek bir yanlış konum bütün planı boşa çıkarabilir.
Sonraki Adım
İki kurulum da aynı yerde tökezliyor ve o yer üç derstir hiç sorulmadı: döngü nerede duracak. Sekiz adım denildi ve sekiz adım yazıldı, ama bu sayı bir karardı ve gerekçesi yazılmadı. G05 plan tükendikten sonra düzelmek için üç adıma daha ihtiyaç duydu; bütçe altı olsaydı yanlış yanıt verecekti. Öte yandan işi biten bir ajan durmayı beceremezse elindeki doğru sonucu bozabilir. Sonraki ders adım bütçesini iki, dört, altı, sekiz ve on iki değerlerinde süpürür ve durdurma ölçütünü kursun kuralı olarak yazar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.