Skip to content
Snippets Groups Projects
Commit 8477b8d6 authored by Sepehr Madani's avatar Sepehr Madani
Browse files

Add new mutation method and refactor methods

parent f63ce154
No related branches found
No related tags found
No related merge requests found
import cmath from random import randrange, random, choice
import random from cmath import exp, phase
from copy import deepcopy from math import log10, pi
from math import cos, degrees, inf, log10, pi, radians, sin from typing import List
from utils.pattern import compute_pattern from utils.pattern import compute_pattern
...@@ -9,13 +9,17 @@ from .base_algorithm import BaseAlgorithm ...@@ -9,13 +9,17 @@ from .base_algorithm import BaseAlgorithm
class Chromosome: class Chromosome:
def __init__(self, N, bit_count): def __init__(self, n, bit_count):
self.gene = [Chromosome.new_gene(bit_count) for i in range(N)] self.gene = [Chromosome.new_gene(bit_count) for _ in range(n)]
self.fitness = float("nan") self.fitness = float("nan")
self.needs_update = True
def get_score(self):
return -20 * log10(abs(self.fitness))
@staticmethod @staticmethod
def new_gene(bit_count): def new_gene(bit_count):
return random.randrange(0, 2 ** bit_count) return randrange(0, 2 ** bit_count)
class GeneticBucketAlgorithm(BaseAlgorithm): class GeneticBucketAlgorithm(BaseAlgorithm):
...@@ -23,8 +27,10 @@ class GeneticBucketAlgorithm(BaseAlgorithm): ...@@ -23,8 +27,10 @@ class GeneticBucketAlgorithm(BaseAlgorithm):
discrete values. discrete values.
""" """
chromosomes: List[Chromosome]
def __init__(self, options): def __init__(self, options):
BaseAlgorithm.__init__(self, options) super().__init__(self, options)
self.main_ang = options.main_ang self.main_ang = options.main_ang
self.sample_size = options.sample_size self.sample_size = options.sample_size
self.null_degrees = options.null_degrees self.null_degrees = options.null_degrees
...@@ -32,6 +38,7 @@ class GeneticBucketAlgorithm(BaseAlgorithm): ...@@ -32,6 +38,7 @@ class GeneticBucketAlgorithm(BaseAlgorithm):
self.bit_count = options.bit_count self.bit_count = options.bit_count
self.bit_resolution = options.bit_resolution self.bit_resolution = options.bit_resolution
self.mutation_factor = options.mutation_factor self.mutation_factor = options.mutation_factor
self.chromosomes = []
self.buckets = [[]] * 8 self.buckets = [[]] * 8
self.check_parameters() self.check_parameters()
...@@ -41,43 +48,58 @@ class GeneticBucketAlgorithm(BaseAlgorithm): ...@@ -41,43 +48,58 @@ class GeneticBucketAlgorithm(BaseAlgorithm):
assert len(self.null_degrees) == 1 assert len(self.null_degrees) == 1
def solve(self): def solve(self):
self.intialize_sample() self.initialize_sample()
self.update_fitness() self.organize_sample()
self.sort_fitness()
for generation in range(self.gen_to_repeat):
for ii in range(self.sample_size // 2, self.sample_size - 1, 2):
bucket_idx = random.randrange(4)
p1 = random.choice(self.buckets[bucket_idx])
p2 = random.choice(self.buckets[bucket_idx + 4])
self.crossover(p1, p2, ii, ii + 1) for generation in range(self.gen_to_repeat):
# self.mutate_sample() self.create_children()
self.update_fitness() self.mutate_sample()
self.sort_fitness() self.organize_sample()
return self.make_weights(self.chromosomes[0]) return (self.make_weights(self.chromosomes[0]), self.chromosomes[0].get_score())
def mutate_sample(self): def create_children(self):
for chromosome in self.chromosomes[1:]: # for all except the best chromosome for ii in range(self.sample_size // 2, self.sample_size - 1, 2):
for idx in range(self.N): bucket_idx = randrange(8)
if random.random() <= self.mutation_factor: p1 = choice(self.buckets[bucket_idx])
chromosome.gene[idx] = Chromosome.new_gene(self.bit_count) p2 = min(
self.buckets[7 - bucket_idx], key=lambda x: abs(x.fitness + p1.fitness)
)
self.crossover(p1, p2, ii, ii + 1)
def update_fitness(self, use_exact_angle=True): def organize_sample(self):
# Update fitness
for chromosome in self.chromosomes:
if chromosome.needs_update:
chromosome.fitness = compute_pattern(
N=self.N,
k=self.k,
weights=self.make_weights(chromosome),
degrees=self.null_degrees,
use_absolute_value=False,
)[0]
chromosome.needs_update = False
# Sort sample by fitness
self.chromosomes.sort(key=lambda x: x.get_score(), reverse=True)
# Allocate chromosomes to their respective buckets
self.buckets = [[]] * 8 self.buckets = [[]] * 8
for chromosome in self.chromosomes: for chromosome in self.chromosomes:
chromosome.fitness = compute_pattern( bucket_idx = int(((phase(chromosome.fitness) + pi) / (2 * pi)) * 8) % 8
N=self.N,
k=self.k,
weights=self.make_weights(chromosome),
degrees=self.null_degrees,
use_absolute_value=False,
)[0]
bucket_idx = int(((cmath.phase(chromosome.fitness) + pi) / (2 * pi)) * 8) % 8
self.buckets[bucket_idx].append(chromosome) self.buckets[bucket_idx].append(chromosome)
def sort_fitness(self): def mutate_sample(self):
self.chromosomes.sort(key=lambda x: -20 * log10(abs(x.fitness)), reverse=True) # For all except the best chromosome
for original in range(1, self.sample_size):
mutated = original + self.sample_size - 1
self.chromosomes[mutated].needs_update = True
for ii in range(self.N):
if random() <= self.mutation_factor:
self.chromosomes[mutated].gene[ii] = Chromosome.new_gene(self.bit_count)
else:
self.chromosomes[mutated].gene[ii] = self.chromosomes[original].gene[ii]
def make_weights(self, chromosome): def make_weights(self, chromosome):
weights = [] weights = []
...@@ -88,7 +110,7 @@ class GeneticBucketAlgorithm(BaseAlgorithm): ...@@ -88,7 +110,7 @@ class GeneticBucketAlgorithm(BaseAlgorithm):
* pi * pi
/ (2 ** self.bit_resolution) / (2 ** self.bit_resolution)
) )
weights.append(cmath.exp(1j * angle)) weights.append(exp(1j * angle))
return weights return weights
def crossover(self, p1, p2, c1, c2): def crossover(self, p1, p2, c1, c2):
...@@ -98,7 +120,7 @@ class GeneticBucketAlgorithm(BaseAlgorithm): ...@@ -98,7 +120,7 @@ class GeneticBucketAlgorithm(BaseAlgorithm):
self.chromosomes[c1].gene[ii] = (g1 + g2) // 2 self.chromosomes[c1].gene[ii] = (g1 + g2) // 2
self.chromosomes[c2].gene[ii] = (g1 + g2 + 1) // 2 self.chromosomes[c2].gene[ii] = (g1 + g2 + 1) // 2
def intialize_sample(self): def initialize_sample(self):
self.chromosomes = [ self.chromosomes = [
Chromosome(self.N, self.bit_count) for i in range(self.sample_size) Chromosome(self.N, self.bit_count) for _ in range(self.sample_size * 2 - 1)
] ]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment