Gene Expression Programming (GEP)
Gene Expression Programming (GEP), genetik programlama (GP) ve genetik algoritmalar (GA) arasında bir bağlantı kurmayı hedefleyen bir evrimsel algoritma türüdür. GEP, Portekizli bilim insanı Candida Ferreira tarafından 2001 yılında geliştirilmiştir.
GEP, genetik programlamada kullanılan ağaç temsili yerine, genetik algoritmalarda kullanılan lineer kromozom temsilini kullanır. Bu, GEP'nin genetik algoritmaların avantajlarından (örneğin, basit çaprazlama ve mutasyon işlemleri) yararlanmasını sağlar, aynı zamanda genetik programlamadaki karmaşık programları ifade edebilmesine olanak tanır.
Gene Expression Programming'in ana fikri, genler ve gen ifadesi kavramlarına dayanır. GEP'de, bir kromozom birden çok gen içerir ve her gen bir alt programı temsil eder. Genler, gen ifadesi süreci boyunca ağaç yapılarına dönüştürülür, böylece bir genin kodladığı alt programı ifade eder. Sonuçta, GEP, birden çok alt programın bir araya gelerek bir bütün programı oluşturduğu modüler bir programlama yaklaşımına sahip olur.
Genlerde yer alan işlemler ve parametreler, gen ifadesi sırasında, genetik algoritmalarda olduğu gibi genellikle rasgele seçilir. Bu, genlerin ağaç yapısına dönüştürülmesi sürecinde, hangi işlemlerin ne zaman ve nerede kullanılacağını belirler.
Bu algoritma, farklı problemler için çeşitli çözümler üretme kapasitesi, genellikle daha karmaşık genetik programlama tekniklerine kıyasla daha hızlı çalışma süresi ve genetik algoritmalardaki tüm evrimsel operatörlerin (seçilim, çaprazlama, mutasyon vb.) kullanılabilme özellikleri nedeniyle popülerdir.
Genel olarak, GEP, GA ve GP'nin birleşimini kullanarak genetik evrim algoritmalarının daha geniş bir uygulama alanına sahip olmasını sağlar. Bu tür bir yaklaşım, genetik programlamadaki ağaç tabanlı yapıların karmaşıklığını ve genetik algoritmalardaki basit genetik operatörlerin etkinliğini birleştirir. GEP, karmaşık programları üretebilme yeteneği ve genetik algoritmalardaki evrimsel operatörlerin etkinliği sayesinde genetik programlamada kullanılan diğer yöntemlere göre çeşitli avantajlara sahiptir.
import random import operator # Parametreler POPULATION_SIZE = 100 GENOME_LENGTH = 20 GENERATIONS = 50 OPERATORS = [operator.add, operator.sub, operator.mul, operator.truediv] TERMINALS = list(range(10)) # Birey sınıfı class Individual: def __init__(self, genome): self.genome = genome self.fitness = self.evaluate() def evaluate(self): # Gen ifadesi stack = [] for gene in self.genome: if isinstance(gene, int): stack.append(gene) else: if len(stack) < 2: return float('inf') # Geçersiz ifade a = stack.pop() b = stack.pop() try: result = gene(b, a) # Hedef işlemi gerçekleştir except ZeroDivisionError: result = float('inf') # Sıfıra bölme stack.append(result) return abs(42 - stack[0]) # Hedef: 42 # Popülasyonun başlangıcı population = [] for _ in range(POPULATION_SIZE): genome = [random.choice(OPERATORS + TERMINALS) for _ in range(GENOME_LENGTH)] individual = Individual(genome) population.append(individual) # Evrimsel döngü for generation in range(GENERATIONS): population.sort(key=lambda x: x.fitness) print(f"Generation {generation}, Best fitness: {population[0].fitness}") if population[0].fitness == 0: break # Optimal çözüme ulaşıldı next_population = population[:POPULATION_SIZE//10] # Elitizm for _ in range((POPULATION_SIZE - len(next_population)) // 2): parent1 = random.choice(population[:POPULATION_SIZE//2]) parent2 = random.choice(population[:POPULATION_SIZE//2]) crossover_point = random.randint(1, GENOME_LENGTH - 1) child1 = parent1.genome[:crossover_point] + parent2.genome[crossover_point:] child2 = parent2.genome[:crossover_point] + parent1.genome[crossover_point:] if random.random() < 0.1: # Mutasyon mutation_point = random.randint(0, GENOME_LENGTH - 1) child1[mutation_point] = random.choice(OPERATORS + TERMINALS) mutation_point = random.randint(0, GENOME_LENGTH - 1) child2[mutation_point] = random.choice(OPERATORS + TERMINALS) next_population += [Individual(child1), Individual(child2)] population = next_population
Bu örnek, gen ifadesini basit bir şekilde gerçekleştirir: her bir gen, bir operatör veya terminal sembolüdür ve genler, bir yığıt üzerinde işlem yapmak için kullanılır. Bu nedenle, bu örnek yalnızca basit aritmetik ifadeleri (örneğin, Reverse Polish notation) oluşturabilir ve daha karmaşık GEP uygulamaları için gen ifadesini ve genetik operatörleri daha fazla geliştirmeniz gerekebilir. Bu kod ayrıca, gen ifadesi sırasında geçersiz ifadelerin (örneğin, operatörler için yeterli sayıda terminal bulunmaması) oluşabileceği durumları da göz önünde bulundurur. Bu tür ifadelerin doğru bir şekilde ele alınması, GEP'nin uygulamalarında önemli bir zorluk olabilir. Bu, gen ifadesi sürecini daha karmaşık ve esnek hale getirerek çözülebilir. Örneğin, genler, operatörler ve operandlar için ayrı alanlara sahip karmaşık genler tanımlayabilirsiniz.
Bu Python kodu, Gene Expression Programming (GEP) algoritmasının temel bir uygulamasını temsil eder. İşte kodun ana bölümleri ve nasıl çalıştığına dair genel bir açıklama:
- Birey sınıfı Bu sınıf, bir gen ifadesini temsil eden bir "bireyi" tanımlar. Bireyin genleri, işlemleri (operatörler) veya parametreleri (terminaller) temsil eder. Bireyin uygunluk değeri, genlerin ifade ettiği işlem sonucunun belirli bir hedef değerden (bu örnekte 42) ne kadar uzak olduğu ile belirlenir.
- Popülasyonun başlangıcı: Başlangıçta, popülasyon rastgele genlere sahip bireylerle doldurulur. Bu genler operatörleri veya terminalleri temsil eder.
- Evrimsel döngü: Her nesilde, en uygun bireyler seçilir ve yeni bir popülasyon oluşturmak için çaprazlanır ve mutasyona uğrar. Çaprazlama, iki ebeveynin genlerini birleştirerek yeni "çocuk" bireyler oluşturur. Mutasyon, bir genin rastgele değiştirilmesiyle gerçekleşir. Bu süreç, genetik algoritmalarda doğal evrimin temel mekanizmalarını taklit eder.
Kodun çıktısı, her neslin en iyi uygunluk değerini yazar. Bu, algoritmanın zamanla daha iyi çözümler bulduğunu gösterir. Eğer bir bireyin uygunluk değeri 0'a ulaşırsa, bu optimal çözüme ulaşıldığı anlamına gelir ve döngü durur.
Bu örnekte, gen ifadesi işlemi basit bir yığıt mekanizması kullanılarak gerçekleştirilir ve genler basit aritmetik işlemleri temsil eder. Bu yüzden, oluşturulan ifadeler Reverse Polish notation formatında olacaktır.
Kodun son hali, genetik evrimin temel mekanizmalarını kullanarak bir işlemi (bu örnekte hedef sayıyı 42 yapmayı) optimize etmeye çalışan bir GEP algoritmasının basit bir uygulamasını sunar.
Bu, GEP'nin en basit formudur ve daha karmaşık problemleri çözebilmek için daha gelişmiş gen ifadesi ve genetik operatörlerin kullanılması gerekebilir. Ayrıca, uygunluk fonksiyonu da çözülmek istenen probleme bağlı olarak değiştirilebilir.
0 Comments
Recommended Comments
There are no comments to display.