İçeriğe geç
academia.sh

Ders 02 / 22

Ajan Döngüsü

Döngünün bir adımının algı, akıl yürütme, eylem ve gözlem olarak açılması ve doğru araç seçme payının adım derinliğine göre sayılması: 24 kurgu görevde derinlik 1'de pay 0,8000, derinlik 4'te 0,5000; ikinci koşumda 0,7742 ve 0,5000. Aradaki 0,3000'lik düşüş en geniş iki koşum bandının (0,0644) kat kat üstündedir ve ölçülmüştür, ama komşu derinlikler arasındaki 0,0917 ve 0,0160'lık farklar bandın içinde kalır ve ölçülmemiş sayılır. Derinlik arttıkça ölçümün kendisi de inceliyor: seçim sayısı 30'dan 6'ya iniyor. Dört görev türünde okunduğunda bir, iki ve üç adımlık görevlerin başarımı iki koşumda da 1,0000, dört adımlık yazma görevlerinde 0,6667; görev başına adım 2,86'dan 7,67'ye çıkıyor. Yanlış seçim yalnız adım harcamıyor, biriken sonucu da üzerine yazabiliyor.

İçindekiler

Önceki ders döngüyü bir kutu olarak ölçtü: giren yirmi dört görev, çıkan yanıtlar ve aradaki toplam bedel. Kutunun içi yalnız tek bir izde göründü, o izde iki yanlış araç seçimi vardı ve tür bazındaki son satır dört adımlık görevlerde başarımın düştüğünü söyledi. Düşüşün nereden geldiği ise açık kaldı.

Bu ders kutuyu açar. Önce bir adımın hangi evrelerden geçtiğini yazar, sonra tek bir sayıyı adım derinliğine göre sayar: ajan o adımda doğru aracı seçebildi mi. Bu dersin taban çizgisi düzeneksiz döngü değil, aynı döngünün birinci adımıdır; derinlik arttıkça aynı ölçünün ne olduğu sayılır.

  • AM13. Ortam, araç kümesi, görev kümesi ve döngü önceki dersteki tanımın aynısıdır ve kurgudur. Tohum 20260218, ikinci koşum 20260219.
  • AM14. Bir adım dört evredir: durumdaki alanların okunması (algı), sıradaki hedefin belirlenmesi (akıl yürütme), bir aracın çağrılması (eylem) ve dönen sonucun duruma yazılması (gözlem).
  • AM15. Derinlik, görevin dizisinde kaçıncı adımda olunduğudur — harcanan adım sayısı değil. Üç kez ıskalanan bir hedef üç adım tüketir ama derinliği değiştirmez.
  • AM16. Doğru araç seçme payı, o derinlikte yapılan seçimlerin kaçının hedef araç olduğudur. Yanlış seçim beş araçtan rastgele biri olduğu için hedefe rastlantıyla da düşebilir; mekanizmanın öngördüğü pay bu yüzden gorme(d) + (1 - gorme(d)) / 5 olur.
  • AM17. İş bittikten sonraki adımlar seçim sayılmaz; hedefleri yoktur.
  • AM18. Boşa çağrı, hedefi tutmayan seçimdir. Adım harcar, belirteç harcar ve duruma istenmeyen alan yazabilir.
  • AM19. Adım bütçesi bu derste sabit sekizdir; bütçe dördüncü dersin konusudur.
  • AM20. Derinlik arttıkça oraya ulaşan görev azalır; örneklem de incelir ve her satırda yazılır.
  • AM21. İki koşum farkının altında kalan fark ölçülmemiş sayılır.

Dört Evre ve Bir Görevin Dökümü

Döngünün her adımı aynı dört evreden geçer. Algı, durum sözlüğünde o an ne olduğudur: hangi alanlar dolu, hangi gözlemler birikmiş. Akıl yürütme, sıradaki hedefin ne olduğuna karar vermektir. Eylem, bir aracın çağrılmasıdır. Gözlem, aracın döndürdüğü alanların duruma yazılmasıdır — ya da bir araç hatasıdır, çünkü çağrı aracın bildirdiği alanları bulamamıştır.

Aşağıdaki kod tanımı kurar ve dört adımlık bir yazma görevinin dökümünü basar.

# 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 oku(g, tohum=TOHUM):
    """Izi gorevin dizisiyle yeniden okur: her adimda akil yurutmenin hedefi,
    eylem olarak secilen arac ve gozlemin ne getirdigi."""
    s = ajan(g, tohum=tohum)
    k, cift, satir = 0, [], []
    for i, (sec, hatali) in enumerate(s["iz"], 1):
        hedef = g["dizi"][k] if k < len(g["dizi"]) else "yok , durmali"
        if k < len(g["dizi"]):
            cift.append((k + 1, sec == hedef))
        satir.append(f"  {i}. derinlik {min(k + 1, len(g['dizi'])):<2}"
                     f" hedef {hedef:<14} eylem {sec:<10}"
                     f" gozlem {'arac hatasi' if hatali else 'alan geldi'}")
        if sec == hedef and not hatali:
            k += 1
    return s, cift, satir


g = [x for x in GOREV if x["ad"] == "G23"][0]
s, _, satir = oku(g)
print(f"{g['ad']} ({g['tur']}) : {g['istek']}")
print("\n".join(satir))
print(f"  adim {s['adim']}  yanit {s['yanit']}  dogru yanit {dogru_yanit(g)}")
G23 (kayit) : A006 abonesinin bedelini hesapla ve kayda yaz
  1. derinlik 1  hedef sayac_oku      eylem sayac_oku  gozlem alan geldi
  2. derinlik 2  hedef tuketim        eylem tuketim    gozlem alan geldi
  3. derinlik 3  hedef tarife         eylem belge_ara  gozlem alan geldi
  4. derinlik 3  hedef tarife         eylem tuketim    gozlem alan geldi
  5. derinlik 3  hedef tarife         eylem tarife     gozlem alan geldi
  6. derinlik 4  hedef kayit_yaz      eylem tarife     gozlem alan geldi
  7. derinlik 4  hedef kayit_yaz      eylem belge_ara  gozlem alan geldi
  8. derinlik 4  hedef kayit_yaz      eylem kayit_yaz  gozlem alan geldi
  adim 8  yanit TR01  dogru yanit 1132

Bu döküm yanlış seçimin iki ayrı bedelini gösteriyor. Üçüncü ve dördüncü adımdaki belge_ara ve tuketim çağrıları hedefi tutmuyor; ikisi de hata vermiyor, çünkü durumda bekledikleri alanlar var. Adım harcanıyor, derinlik ilerlemiyor. Yedinci adım daha ağırdır: belge_ara başarıyla dönüyor ve biriken sonucun üzerine yazıyor; durumda artık 1132 değil bir belge kodu duruyor. Sekizinci adımda ajan nihayet hedefi tutturuyor, fakat kayit_yaz o bozuk değeri kayda geçiriyor. Başarıyla dönen bir boşa çağrı adım harcamakla kalmıyor, durumu bozuyor.

Derinlik Arttıkça Doğru Araç Seçme Payı

Aynı sayı bütün görev kümesinde, derinlik derinlik toplanır. Mekanizmanın öngördüğü pay yanına yazılır, çünkü yanlış seçim rastgele bir araçtır ve hedefe rastlantıyla da düşebilir.

print("derinlik  beklenen   A: secim  dogru   pay    B: secim  dogru   pay")
for d in (1, 2, 3, 4):
    sat = [f"{d:>5} {gorme(d) + (1 - gorme(d)) / 5:>12.4f}"]
    for tohum in (TOHUM, TOHUM + 1):
        n = k = 0
        for x in GOREV:
            for dd, ok in oku(x, tohum)[1]:
                if dd == d:
                    n, k = n + 1, k + ok
        sat.append(f"{n:>10} {k:>6} {k / n:>6.4f}")
    print(" ".join(sat))

print()
print("tur      dizi  gorev   A: adim/gorev  bosa  hata  basarim"
      "    B: adim/gorev  bosa  hata  basarim")
for tur, boy in (("belge", 1), ("tuketim", 2), ("bedel", 3), ("kayit", 4)):
    alt = [x for x in GOREV if x["tur"] == tur]
    sat = [f"{tur:<8} {boy:>4} {len(alt):>6}"]
    for tohum in (TOHUM, TOHUM + 1):
        adim = bosa = hata = bas = 0
        for x in alt:
            y, c, _ = oku(x, tohum)
            adim, hata = adim + y["adim"], hata + y["hata"]
            bosa += sum(1 for _, ok in c if not ok)
            bas += y["yanit"] == dogru_yanit(x)
        sat.append(f"{adim / len(alt):>13.2f} {bosa:>5} {hata:>5} {bas / len(alt):>8.4f}")
    print(" ".join(sat))
derinlik  beklenen   A: secim  dogru   pay    B: secim  dogru   pay
    1       0.8400         30     24 0.8000         31     24 0.7742
    2       0.7680         24     17 0.7083         22     17 0.7727
    3       0.6960         13      9 0.6923         12      9 0.7500
    4       0.6240          6      3 0.5000          6      3 0.5000

tur      dizi  gorev   A: adim/gorev  bosa  hata  basarim    B: adim/gorev  bosa  hata  basarim
belge       1      7          2.86     5     5   1.0000          2.86     3     2   1.0000
tuketim     2      8          3.50     4     3   1.0000          3.62     5     1   1.0000
bedel       3      6          4.33     2     0   1.0000          5.00     6     3   1.0000
kayit       4      3          7.67     9     0   0.6667          6.33     4     1   0.6667

Birinci tablo iki şeyi birden söylüyor ve ikisi ayrı ayrı okunmalı. Uçtan uca fark ölçülmüştür: derinlik 1’de pay 0,8000, derinlik 4’te 0,5000; ikinci koşumda 0,7742 ve 0,5000. Düşüş 0,3000 ve 0,2742’dir. Aynı derinliğin iki koşum farkı en geniş yerde 0,0644’tür (derinlik 2), yani uçtan uca düşüş bandın dört katından fazladır. Plan uzadıkça seçim bozuluyor.

Komşu derinlikler arasındaki farklar ise başka bir hikaye anlatıyor. Birinci koşumda 1’den 2’ye düşüş 0,0917, 2’den 3’e 0,0160’tır; ikinci koşumda ilki 0,0015, ikincisi ise eksi 0,0227’dir. Bunların hepsi bandın içinde ya da sınırındadır ve ölçülmemiş sayılır. Yalnız 3’ten 4’e geçiş iki koşumda da bandı aşıyor: 0,1923 ve 0,2500. Tek tek adımların payını okumak isteyen bir ölçüm daha büyük bir görev kümesine ihtiyaç duyar.

Bunun nedeni sağdaki seçim sütunlarında yazılı. Derinlik 1’de 30 seçim var, derinlik 4’te yalnız 6. Dört adımlık diziye sahip görev sayısı üçtür ve oraya ulaşan koşum sayısı daha da azdır. Derinleştikçe ölçümün kendisi inceliyor: ajanın en zayıf olduğu yer, hakkında en az sayıya sahip olduğumuz yerdir.

Dört Görev Türünde Ayrı Okuma

İkinci tablo aynı düşüşü tür bazında gösteriyor. Görev başına adım dizi uzunluğuyla birlikte büyüyor: 2,86, 3,50, 4,33, 7,67. En az gereken adım sayısı sırasıyla 2, 3, 4 ve 5’tir — bir adım her zaman durmaya gider. Dört adımlık türde gerçekleşen adım en az gerekenin 1,53 katıdır ve bu oran ikinci koşumda 1,27’ye iner; ikisi arasındaki fark üç görevlik bir alt kümede ölçülemez.

Ölçülebilen şey başarımdır. Bir, iki ve üç adımlık türler iki koşumda da 1,0000, dört adımlık tür iki koşumda da 0,6667 veriyor. Aynı ajan, aynı araçlar, aynı bütçe; değişen tek şey dizinin uzunluğu. Araç hatası sütunu ise iki koşum arasında 5’ten 2’ye, 0’dan 3’e savruluyor: bu ölçekte hata sayımı gürültüdür.

Özet

  • Bir ajan adımı dört evredir: durumun okunması, hedefin belirlenmesi, aracın çağrılması ve dönen sonucun duruma yazılması.
  • Yanlış seçim iki bedel öder: harcanan adım ve duruma yazılan istenmeyen alan; başarılı bir yanlış çağrı biriken sonucun üzerine yazabilir.
  • Doğru araç seçme payı derinlik 1’de 0,8000, derinlik 4’te 0,5000; ikinci koşumda 0,7742 ve 0,5000. Uçtan uca düşüş en geniş iki koşum bandının dört katından fazladır ve ölçülmüştür.
  • Komşu derinlikler arasındaki 0,0917 ve 0,0160’lık farklar bandın içindedir ve ölçülmemiş sayılır; yalnız üçüncüden dördüncüye geçiş iki koşumda da bandı aşar.
  • Derinleştikçe örneklem incelir: seçim sayısı 30’dan 6’ya iner, yani ajanın en zayıf olduğu yer en az sayıya sahip olduğumuz yerdir.
  • Tür bazında görev başına adım 2,86’dan 7,67’ye çıkar; başarım üç kısa türde 1,0000, dört adımlık türde iki koşumda da 0,6667’dir.

Sonraki Adım

Bu derste tek bir döngü bütün işi kendi yaptı: hedefi de o belirledi, aracı da o çağırdı. Dizinin dördüncü adımında hedefi tutturma payının yarıya inmesi bu birleşimin bedelidir, çünkü aynı çağrı hem bütün planı hem de sıradaki eylemi taşımak zorunda. Akla gelen ilk çözüm işi bölmektir: bir yan planı çıkarsın, öbür yan yalnız o planın adımlarını yürütsün. Sonraki ders bu bölmeyi kurar ve iki soruyu birlikte sorar — bölme başarımı yükseltiyor mu, ve bölünen iş adım ile belirteç olarak ne kadar tutuyor.

İ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