İçeriğe geç
academia.sh

Ders 06 / 22

Çoklu Ajan Düzenleri

Aynı görev kümesinde tek ajan ile iki ajanın yan yana ölçülmesi: sekiz adımlık bütçe ikiye bölünüp iş bir okuyucu ile bir hesapçıya dağıtıldığında toplam başarım iki koşumda da 23/24'te kalıyor, ama adım 97'den 140'a çıkıyor ve devredilen bağlam 363 belirteç götürüyor. Bölme, dört araçlık kayıt görevlerini 2/3'ten 3/3'e çıkarırken iki araçlık tüketim görevlerini 8/8'den 7/8'e düşürüyor. Devir paketi ucuzlatıldığında 178 belirteç kazanılıyor, karşılığında 68 alan kayboluyor ve başarım 23/24'ten 18/24'e iniyor; kaybolan alan abone tipi olduğu için işyeri abonelerinin bedeli tam yarısı çıkıyor. Dört adımlık bütçe ikiye bölündüğünde düzen 21/24'ten 19/24'e ve 20/24'ten 16/24'e düşüyor.

İçindekiler

Önceki ders denetleyen gözü döngünün içinde bıraktı: ajan kendi izine kendi baktı ve iz temiz göründüğünde hiçbir şey göremedi. Gözü dışarı çıkarmanın en doğrudan yolu işi bölmektir.

Bölme bedava değildir. Tek bir döngüde biriken durum ortak bir sözlükte durur; iki ajan aynı belleği paylaşmaz ve aradaki her şey açıkça devredilmek zorundadır. Devredilen şey bir metindir, yani belirteçle ölçülür. Bölme burada araç kümesine göredir; planlayıcı–yürütücü ayrımı değildir, iki ajan da yürütür.

  • AM47. Kurulum ortaktır: ölçüm ağının kurgu abone kayıtları, kurgu belge dağarcığı, beş kurgu araç, yirmi dört kurgu görev ve ders içinde yazılmış bir ajan benzeticisi. Gerçek bir model ucu ya da araç sunucusu çağrılmaz.
  • AM48. Taban çizgisi düzeneksiz döngüdür: tek ajan, aynı küme, aynı toplam bütçe.
  • AM49. Düzen iki roldür. Okuyucu yalnız sayac_oku, tuketim ve belge_ara, hesapçı yalnız tarife ve kayit_yaz araçlarını görür; rol döngüsü ortak döngünün aynısıdır.
  • AM50. Toplam adım bütçesi ikiye bölünür ve devir bir adım sayılır.
  • AM51. Devir paketi bir metindir: taşınacak alanlar ad=deger biçiminde yazılır, bedeli o metnin belirteç sayısıdır ve taşınmayan her alan kaybolur. Tam devir sekiz alanı taşır, özet devir yalnız abone, sutun, m3 ve sonuc alanlarını.
  • AM52. İkinci koşum tohum 20260219; iki koşum farkı bu kümede bir görevdir (0,0417) ve altındaki her fark ölçülmemiş sayılır.

Devirde Kaybolan Alan

Önce tek bir görevde iki paket biçimi yan yana konur. G23 bir kayıt görevidir, abonesi işyeri.

# ORTAK KURGU KURULUM -- olcum aginin 60 kurgu abonesi, 5 kurgu belge,
# 5 kurgu arac, 24 kurgu gorev ve ders icinde yazilmis ajan benzeticisi.
# Gercek bir model ucu, arac sunucusu ya da calisma zamani cagrilmaz.
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)}



# ---- Bu derste eklenen parca: iki ajanli duzen ve devir paketi

ROL = {"okuyucu": ("sayac_oku", "tuketim", "belge_ara"),
       "hesapci": ("tarife", "kayit_yaz")}
DEVIR_ALAN = ("abone", "sutun", "onceki", "simdiki", "tip", "bolge", "m3", "sonuc")
OZET_ALAN = ("abone", "sutun", "m3", "sonuc")


def rol_ajani(g, rol, alan, en_cok_adim, tohum):
    """Ortak dongunun aynisi; arac kumesi ve baslangic durumu disaridan verilir."""
    r = uretec(tohum ^ izno(rol + "|" + g["ad"]))
    adlar = ROL[rol]
    dizi = [a for a in g["dizi"] if a in adlar]
    iz, adim, bel, k = [], 0, 0, 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:
            if r() < 0.88:
                break
            sec = adlar[int(r() * len(adlar))]
        else:
            sec = hedef if r() < gorme(k + 1) else adlar[int(r() * len(adlar))]
        if sec == "kayit_yaz":
            alan["deger"] = alan.get("sonuc")
        s = cagir_arac(sec, alan)
        iz.append(sec)
        bel += 30
        if "hata" in s:
            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 alan, adim, bel


def devir_paketi(alan, tasinan):
    """Devredilen baglam bir metindir; bedeli belirtecle olculur."""
    p = " ".join(f"{a}={alan[a]}" for a in tasinan if a in alan)
    kayip = [a for a in DEVIR_ALAN if a in alan and a not in tasinan]
    return p, len(belirtecle(p)), kayip


def paketi_ac(p):
    d = {}
    for parca in p.split():
        a, _, v = parca.partition("=")
        d[a] = int(v) if v.lstrip("-").isdigit() else v
    return d


g = GOREV[22]
alan = {"abone": g["abone"], "anahtar": g["istek"], "sutun": "bedel"}
alan, adim, bel = rol_ajani(g, "okuyucu", alan, 4, TOHUM)
print(g["ad"], g["tur"], "-- okuyucu bitti, adim", adim, "belirtec", bel)
for ad, tasinan in (("tam  ", DEVIR_ALAN), ("ozet ", OZET_ALAN)):
    p, bl, kayip = devir_paketi(alan, tasinan)
    b2, a2, e2 = rol_ajani(g, "hesapci", paketi_ac(p), 4, TOHUM)
    print(f"{ad} paket {bl:>2} belirtec, kayip {len(kayip)} {kayip}"
          f" -- yanit {b2.get('sonuc')}, dogrusu {dogru_yanit(g)}")
G23 kayit -- okuyucu bitti, adim 3 belirtec 306
tam   paket 18 belirtec, kayip 0 [] -- yanit 1132, dogrusu 1132
ozet  paket  8 belirtec, kayip 4 ['onceki', 'simdiki', 'tip', 'bolge'] -- yanit 566, dogrusu 1132

Fark on belirteçtir ve karşılığı tam bir yanlış yanıttır. Özet paket tip alanını taşımadığı için tarife aracı kendi varsayılanına düşüyor ve bedeli mesken tarifesiyle hesaplıyor; sonuç tam yarısı çıkıyor. Araç hata vermiyor ve o değer kayda yazılıyor. Kaybolan alan, araç hatası olarak değil, yanlış ama geçerli bir sonuç olarak görünür.

İkinci Ajanın Kattığı ve Ödettiği

Şimdi bütün küme koşturulur; tür kırılımı da tabloda durur. Belge görevleri her düzende 7/7 çıktığı için tabloda yer almaz.

TUR = ("belge", "tuketim", "bedel", "kayit")


def kosum(tohum, butce, tasinan=None):
    """tasinan None ise tek ajan. Degilse butce ikiye bolunur: okuyucu kendi
    isini bitirir, devir paketini yazar, hesapci paketle baslar."""
    CAGRI[0] = 0
    d = {"dogru": 0, "adim": 0, "bel": 0, "devir": 0, "kayip": 0,
         "tur": {t: [0, 0] for t in TUR}}
    for g in GOREV:
        if tasinan is None:
            s = ajan(g, en_cok_adim=butce, tohum=tohum)
            yanit, d["adim"], d["bel"] = (s["yanit"], d["adim"] + s["adim"],
                                          d["bel"] + s["belirtec"])
        else:
            alan = {"abone": g["abone"], "anahtar": g["istek"], "sutun": "bedel"}
            alan, a1, b1 = rol_ajani(g, "okuyucu", alan, butce // 2, tohum)
            paket, pb, kayip = devir_paketi(alan, tasinan)
            son, a2, b2 = rol_ajani(g, "hesapci", paketi_ac(paket),
                                    butce // 2, tohum)
            d["adim"] += a1 + 1 + a2
            d["bel"] += b1 + pb + b2
            d["devir"] += pb
            d["kayip"] += len(kayip)
            yanit = son.get("sonuc", alan.get("sonuc"))
        d["tur"][g["tur"]][1] += 1
        d["tur"][g["tur"]][0] += yanit == dogru_yanit(g)
        d["dogru"] += yanit == dogru_yanit(g)
    d["cagri"] = CAGRI[0]
    return d


for t in (TOHUM, TOHUM + 1):
    print(f"\ntohum {t}")
    print("butce duzen           tuket bedel kayit toplam  adim cagri"
          "  belirt devir kayip")
    for butce in (4, 8):
        for ad, tas in (("tek ajan", None), ("iki ajan, tam", DEVIR_ALAN),
                        ("iki ajan, ozet", OZET_ALAN)):
            d = kosum(t, butce, tas)
            p = "".join(f"{d['tur'][x][0]}/{d['tur'][x][1]:<5}" for x in TUR[1:])
            print(f"{butce:>5} {ad:<15}{p}{d['dogru']:>2}/24{d['adim']:>6}"
                  f"{d['cagri']:>6}{d['bel']:>8}{d['devir']:>6}{d['kayip']:>6}")
tohum 20260218
butce duzen           tuket bedel kayit toplam  adim cagri  belirt devir kayip
    4 tek ajan       8/8    5/6    1/3    21/24    84    64    9402     0     0
    4 iki ajan, tam  6/8    4/6    2/3    19/24   109    63    8162   358     0
    4 iki ajan, ozet 6/8    1/6    1/3    15/24   109    63    7984   180    68
    8 tek ajan       8/8    6/6    2/3    23/24    97    74   11978     0     0
    8 iki ajan, tam  7/8    6/6    3/3    23/24   140    69   11703   363     0
    8 iki ajan, ozet 7/8    2/6    2/3    18/24   140    69   11525   185    68

tohum 20260219
butce duzen           tuket bedel kayit toplam  adim cagri  belirt devir kayip
    4 tek ajan       8/8    4/6    1/3    20/24    83    67    9366     0     0
    4 iki ajan, tam  6/8    1/6    2/3    16/24   108    63    8083   361     0
    4 iki ajan, ozet 6/8    0/6    1/3    14/24   108    63    7895   173    72
    8 tek ajan       8/8    6/6    2/3    23/24    98    74   11994     0     0
    8 iki ajan, tam  8/8    5/6    3/3    23/24   143    75   12358   372     0
    8 iki ajan, ozet 8/8    2/6    2/3    19/24   143    75   12170   184    72

Sekiz adımlık bütçede toplam başarım iki düzende de 23/24 ve iki koşumda da aynı: ikinci ajan toplama hiçbir şey katmıyor. Bedeli açık — adım 97’den 140‘a, devredilen bağlam 363 belirteç. Çağrı ise 74’ten 69’a düşüyor, çünkü hesapçının işi olmayan on beş görevde ajan bir adım harcayıp hiçbir araç çağırmadan çıkıyor. İletişim maliyeti bir çağrı kalemi değildir.

Kırılım toplamın gizlediğini gösteriyor. Dört araçlık kayıt görevleri iki koşumda da 2/3’ten 3/3‘e çıkıyor: bölme derinliği her ajan için sıfırdan başlatıyor ve yanlış seçim beş araç yerine iki ya da üç araç arasından geliyor. Aynı mekanizma kısa dizide ters çalışıyor — tüketim görevleri birinci koşumda 8/8’den 7/8’e, bedel görevleri ikincide 6/6’dan 5/6’ya iniyor. Kayıt alt kümesi üç görevliktir; yön aynı, büyüklüğü ölçülmemiş sayılır.

Özet devir satırı ikinci bedeli yazıyor. Paketi ucuzlatmak 363 belirteci 185‘e indiriyor; karşılığı 68 kaybolan alan ve 23/24’ten 18/24‘e düşen başarımdır. Kayıp bedel görevlerinde toplanıyor: 6/6’dan 2/6’ya. Belirteçle ölçülen bir tasarruf, görevle ödeniyor.

Dört adımlık bütçe satırlarında düzen tek ajanın altında kalıyor: 19/24 ve 16/24. Her ajana kalan pay dizisini bitirmeye yetmiyor. Bir işi bölmek, bölünecek kadar bütçe varsa bir düzendir.

Özet

  • İki ajan ortak bellek paylaşmaz; aralarındaki her alan açıkça devredilir ve bedeli belirteçle ölçülür.
  • Eşit toplam bütçede ikinci ajan başarıma iki koşumda da hiçbir şey katmıyor (23/24 → 23/24); adım 97’den 140’a çıkıyor, devredilen bağlam 363 belirteç tutuyor. Çağrı ise 74’ten 69’a düşüyor: iletişim maliyeti adım kalemindedir.
  • Kırılım toplamın gizlediğini açıyor: kayıt görevleri 2/3’ten 3/3’e çıkarken tüketim ve bedel görevleri birer görev kaybediyor.
  • Devir paketini ucuzlatmak 178 belirteç kazandırıp 68 alan kaybettiriyor ve başarımı 18/24’e indiriyor; kaybolan alan yanlış ama geçerli bir sonuç olarak görünüyor.
  • Dört adımlık bütçe ikiye bölündüğünde düzen tek ajanın altına düşüyor (19/24 ve 16/24).

Sonraki Adım

İki derste denetim önce döngünün içine, sonra ikinci bir ajana verildi; ikisinde de karar düzeneğin kendisinde kaldı. G23 görevinde yanlış değer bir kayda yazıldı ve bunu durduran hiçbir şey yoktu, çünkü kayit_yaz yan etkili tek araçtır ve öbür araçlarla aynı muameleyi gördü. Sonraki ders o aracın önüne bir onay noktası koyar: onay açıkken ve kapalıyken kaç kayıt yazılıyor, onay kaç yanlış yazımı durduruyor ve bunun için insana kaç kez soruluyor.

İ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