İçeriğe geç
academia.sh

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.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat