Thread overview
AI ile FIFO
May 19
Erdem
May 17

Merhaba,

GPT-4o duyuralı bir kaç gün oldu ama ne zamandır küçük bir AI karşılaştırma testi için zaman kolluyordum; kısmet bugüneymiş! Biri önemli (capacity ile ilgili) olan ve nispeten çalışmasını etkileyemecek ekleme/çıkarmaları saymazsak son sürüm tam 12'den vurmuşa benziyor...

Prompt şu şekildeydi:

"Lütfen D dilinde bir FIFO stack yaz ama statik bir dizi ile yapmalısın, sınıf kurulurken kapasitesi ve türü belirlenecek ve her push() yapıldığında dizinin sıradaki boş elemanına veriyi kayıt etsin, sonra her pop() yapıldığında da ilk giren veriyi geri döndürsün ve tam o sırada kapasitesi 1 artsın. Yani new Stack!int(10) ile kurulduysa ve 10 defa push() sonras 1 defa pop() yapılarak dizin başından 1 eleman eksiltildiyse hala dizinin sonunda 1 eleman daha eklenebilmeli. Yani kaydırmalı bir buffer(önbellekleme) sistemine ihtiyaç var. Verimli olmalı çünkü her veri eklendiğinde kapasite dolmadan tekrar başından veri çekilebilmeli stack dolduğunda, yani 10 defa push() yapıldığında tekrar 1 defa daha push() yapılırsa program sonlanmadan "veri kayıt edilmedi, yığıt doldu" mesajı ekrana yazsın. Aynı şekilde henüz veri eklenmemiş (stack.empty == true) durumundaysa pop() yapılırsa "döndürülecek bir veri yok, yığıt boş" mesajı ekrana yazsın. Ayrıca clear() ve set() metodları da olmalı. Yani stack.clear() yapılarak sessizce yığıt boşaltılabilmeli ve stack.set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) yapılarak bir defada tüm yığıt uyarı mesajı vermeksizin doldurulabilmeli."

main() testi saymazsak çıkan sonuç 50 satırdan az olacak şekilde şöyle oldu:

import std.stdio;
//import std.array; "o ekledi, ben çıkardım!"

class Stack(T) {
    private T[] data;
    private size_t capacity;
    private size_t size;

    this(size_t capacity) {
        this.capacity = capacity;
        this.data = new T[capacity];
        //this.size = 0; "o ekledi, ben çıkardım!"
    }

    void push(T value) {
        if (size == capacity) {
            writeln("YIĞIT DOLDU: veri kayıt edilemez!");
            return;
        }
        data[size++] = value;
    }

    T pop() {
        if (size == 0) {
            writeln("YIĞIT BOŞ: döndürülecek bir veri yok!");
            return T.init;
        }
        T value = data[0];
        data = data[1 .. $] ~ T.init;
        size--;
        //capacity++; "o ekledi, ben çıkardım!"
        return value;
    }

    void clear() {
        data = new T[capacity];
        size = 0;
    }

    void set(T[] values) {
        if (values.length > capacity) {
            writeln("Verilen dizi kapasiteden büyük!");
            return; // "^--bunu istememiştim, akıllıca"
        }
        data = values ~ new T[capacity - values.length];
        size = values.length;
    }
    bool empty() => size == 0; // "tek satır yaptım"
}

Tam 12'den vurduğunu söylemiştim, belki diğer AI modellerine göre beni gönlümden vurmuş olabilir ama pop()'deki capacity++ satırını neden eklediğini anlayamadım! Açıkca bu bir bug ve mantığa aykırı olduğu için 10 üzerinden not verirsek skoru 9'a düşürdüm, şimdilik! Testleri şu kısmen değişmiş devam koduyla yapabilirsiniz:

void main()
{
    auto stack = new Stack!int(10);

    //writeln(stack.pop()); // YIĞIT BOŞ: döndürülecek bir veri yok!
    stack.push(0); // "ben ekledim"
    stack.push(1);
    stack.push(2);
    stack.push(3);

    writeln(stack.pop()); // 0
    stack.set([4, 5, 6, 7, 8, 9]); /* "ben ekledim"
    stack.push(4);
    stack.push(5);
    stack.push(6);
    stack.push(7);
    stack.push(8);
    stack.push(9);//*/
    stack.push(10); // YIĞIT DOLDU: veri kayıt edilemez!
    stack.size.writefln!"size = %s"; // 3 "ben ekledim, ismi index olabilirdi!"
    stack.push(11); /* "ben ekledim"
    with(stack) while(!empty)
        pop.write(" ");
    writeln;//*/
    stack.data.writeln; // "ben ekledim"

    stack.clear();
    assert(stack.empty); // "ben ekledim"

    stack.set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    writeln(stack.pop()); // 0

}

Ayrıca gereksiz eklediği satırlar ve benim 0'dan başlayarak ekleme yapmasını belirttiğim halde eklememesi ekstra bir not kırımını gerektiriyor. Çünkü biraz başına buyruk (korkmayın henüz The Terminator'lük bir durum yok) kod yazıyor! Bilerek "statik bir dizi" ifadesini kullandım, bakalım ne yapacak diye ama D'nin dilimleme be GC olanaklarından faydalanmayı tercih ettiğini görüyoruz.

Belki new Stack!(int, 10) şeklinde bir kurulum yapmasını gerektiğini söyleseydim kırdığım notu geri almam gerekebilirdir ne dersiniz? Gerçi set() ederken eklenen dizinin boyutunu belirtmediğim halde kontrol etmesi akıllıca. Ama yinede hala 10 puanı hak etmiyor :)

SDB@79

May 18

On Friday, 17 May 2024 at 04:58:20 UTC, Salih Dincer wrote:

>

Merhaba,

ne zamandır küçük bir AI karşılaştırma testi ...

Küçük dediysek burada bitmez hani, çünkü çok model var peki, önceki GPT-4 sürümüne sorsaydık ne elde edermişiz bakalım:

import std.stdio;
import std.conv;

class Stack(T) {
    private T[] buffer;
    private int front;
    private int rear;
    private int capacity;

    this(int size) {
        buffer = new T[size];
        front = 0;
        rear = 0;
        capacity = size;
    }

    void push(T value) {
        if ((rear + 1) % capacity == front) {
            writeln("veri kayıt edilmedi, yığıt doldu");
        } else {
            buffer[rear] = value;
            rear = (rear + 1) % capacity;
            if (front == rear) { // Buffer is full
                front = (front + 1) % capacity; // Increase capacity
            }
        }
    }

    T pop() {
        if (isEmpty()) {
            writeln("döndürülecek bir veri yok, yığıt boş");
            throw new Exception("Stack is empty");
        } else {
            T value = buffer[front];
            front = (front + 1) % capacity;
            return value;
        }
    }

    void clear() {
        front = rear;
    }

    void set(T[] values) {
        foreach (value; values) {
            push(value);
        }
    }

    bool isEmpty() {
        return front == rear;
    }

    bool isFull() {
        return (rear + 1) % capacity == front;
    }
}

void main() {
    Stack!int myStack = new Stack!int(10);
    // Örnek kullanım:
    myStack.push(1);
    myStack.push(2);
    writeln("Pop: ", myStack.pop()); // 1'i döndürür
    myStack.clear(); // Yığıtı boşaltır
    myStack.set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); // Yığıtı doldurur
}

Evet, istediğim noktaya gelmiş görünüyor. Yani çift indeks kullandığını görüyorum. Ama bu sefer, virgülüne bile dokunmadan hiçbir değerlendirme yapmayacağım çünkü çalıştırmadım!

Bir de öğrencilerin bile hayatını değiştiren (sanırım 1 sene oldu?) GPT sürüm 3.5 ile sormak istiyorum. Belki farklı bir sonuç elde ederiz ha! Aslında hedeflediğim zor olanı yaptırmak; RotativeStack. Benzerlerini önceden defalarca yaptım ve asıl verimini GC'yi kullanmayan bir ortam görebilirsiniz.

İyi hafta sonları...

SDB@79

May 18

On Saturday, 18 May 2024 at 05:06:13 UTC, Salih Dincer wrote:

>

değerlendirme yapmayacağım çünkü çalıştırmadım!

Küçük bir öğle arası verdim ve denemeye vakit bulabildim, evet...

Kod çalışıyor!

Ama insan dokunmadan edemiyor, malum yapay zeka üretimi! Başta "front" üyesi D'nin aralık kavramı ile çakışıyordu ve calculatePos() ile kod daha düzenli bir hale geldi. Çakışmayı düzeltmek için ilk posizyon bilgisini tutan değişkene "head" ismini verdim. Ufak 1-2 düzenleme (magictouch dedikleri) ile bence mükemmel, itirazı olan?

import std.range,
       std.stdio;

enum limit = 10;

void main() {
  with(new Stack!limit) {
    assert(empty); // stack is empty

    push = 41;
    assert(buffer[0] == 41); // first buffer cell

    assert(!empty); // stack contains data
    pop.writeln;

    assert(empty); // stack is empty

    push = 42;
    assert(buffer[1] == 42); // next buffer cell

    pop.writeln;

    try pop(); catch(Exception e)
    {
      e.msg.writeln; // "Stack is empty"
    }

    enum len = 100;
    foreach(n; iota(10, len, 10)) push = n;
    assert(buffer == [41, 42, 10, 20, 30, 40, 50, 60, 70, 80, 90]);

    push(len);
    assert(buffer[0] == len); // overwrites the first cell
    assert(isFull); // buffer[1] isn't used!

    try push(42); catch(Exception e)
    {
      e.msg.writeln; // "Stack is full!"
    }
    clear();
    push(len);

    assert(buffer[1] == len); // buffer[1] isn't used!
    assert(!isFull); // stack isn't full

    foreach(n; 1..10) push(len + n);

    assert(isFull); // stack is full but
    assert(buffer[0] == 0);  // buffer[0] isn't used!

    buffer.writeln;
  }
}

class Stack(size_t size, T = int) {
  private T[size + 1] buffer;
  private size_t head, rear;
  size_t capacity;

  this() { capacity = buffer.length; }

  void push(T value) {
    if (isFull) throw new Exception("Stack is full!");
    else {
      buffer[rear] = value;
      rear = calculatePos(rear);
      if (empty) head = calculatePos(head);
    }
  }

  auto pop() {
    if (empty) throw new Exception("Stack is empty!");
    scope(exit) head = calculatePos(head);
    return buffer[head];
  }

  void clear() {
    buffer[] = 0;
    head = rear;
  }

  auto set(T[] values) { foreach (value; values) push(value); }

  bool isFull() => calculatePos(rear) == head;
  auto length() => (rear - head + capacity) % capacity;
  auto calculatePos(size_t pos) => (pos + 1) % capacity;

  bool empty() => head == rear;
  auto front() => buffer[head];
  auto popFront() => head = calculatePos(head);
}

Şimdi dikkatimi çekti, yığıt bir referans türü (class Stack) olduğu için sondaki InputRange işlevlerine bir de son pozisyonları ve buffer[] içindeki verinin yedeğini alan save() üyesini de eklersek sanırım daha mükemmel olacak:

  auto save() {
    auto backup = new Stack!size;
    backup.buffer = this.buffer;
    backup.head = this.head;
    backup.rear = this.rear;
    return backup;
  }

SDB@79

May 19

Yığıt herhalde son giren ilk çıkar mantığı ile çalışıyordu.

Vala örneğini D'ye çevirdik.

import std.stdio;
import std.array;
import std.string;
import std.conv;

class Yığıt (T)
{
    Düğüm!T ilk;
    int elemanAdedi;

    class Düğüm (T)
    {
        T eleman;
        Düğüm!T sonraki;
    }

public:

    this()
    {
        ilk = null;
        elemanAdedi = 0;
    }

    void ekle (T eleman)
    {
        Düğüm!T eskiİlk = ilk;
        ilk = new Düğüm!T();
        ilk.eleman = eleman;
        ilk.sonraki = eskiİlk;
        ++elemanAdedi;
    }

    T çıkar()
    {
        T çıkarılan = ilk.eleman;
        ilk = ilk.sonraki;
        --elemanAdedi;
        return çıkarılan;
    }

    bool boşMu()
    {
        return ilk is null;
    }

    int elemanSayısı()
    {
        return elemanAdedi;
    }
}

int main()
{
    auto yığıt = new Yığıt!string();

    foreach (satır; stdin.byLine())
    {
        if (!satır.empty)
        {
            auto kelimeler = satır.split(" ");
            foreach (kelime; kelimeler)
                if (kelime == "-")
                    writeln(yığıt.çıkar() ~ " ");
                else
                    yığıt.ekle(to!string(kelime));
        }
    }

    return 0;
}

Örnek bir giriş kütüğü mani.txt olabilir.

kaçar bilmeyen mâni - mâni açar mâniyi - - - - - söyleşelim gel - mâni - -

Uygulama ./yığıt < mani.txt şeklinde kullanılabilir.