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,tuketimvebelge_ara, hesapçı yalnıztarifevekayit_yazaraç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=degerbiç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ızabone,sutun,m3vesonucalanları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.