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
import random
from copy import deepcopy
from math import cos, degrees, inf, log10, pi, radians, sin
from random import randrange, random, choice
from cmath import exp, phase
from math import log10, pi
from typing import List
from utils.pattern import compute_pattern
......@@ -9,13 +9,17 @@ from .base_algorithm import BaseAlgorithm
class Chromosome:
def __init__(self, N, bit_count):
self.gene = [Chromosome.new_gene(bit_count) for i in range(N)]
def __init__(self, n, bit_count):
self.gene = [Chromosome.new_gene(bit_count) for _ in range(n)]
self.fitness = float("nan")
self.needs_update = True
def get_score(self):
return -20 * log10(abs(self.fitness))
@staticmethod
def new_gene(bit_count):
return random.randrange(0, 2 ** bit_count)
return randrange(0, 2 ** bit_count)
class GeneticBucketAlgorithm(BaseAlgorithm):
......@@ -23,8 +27,10 @@ class GeneticBucketAlgorithm(BaseAlgorithm):
discrete values.
"""
chromosomes: List[Chromosome]
def __init__(self, options):
BaseAlgorithm.__init__(self, options)
super().__init__(self, options)
self.main_ang = options.main_ang
self.sample_size = options.sample_size
self.null_degrees = options.null_degrees
......@@ -32,6 +38,7 @@ class GeneticBucketAlgorithm(BaseAlgorithm):
self.bit_count = options.bit_count
self.bit_resolution = options.bit_resolution
self.mutation_factor = options.mutation_factor
self.chromosomes = []
self.buckets = [[]] * 8
self.check_parameters()
......@@ -41,43 +48,58 @@ class GeneticBucketAlgorithm(BaseAlgorithm):
assert len(self.null_degrees) == 1
def solve(self):
self.intialize_sample()
self.update_fitness()
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.initialize_sample()
self.organize_sample()
self.crossover(p1, p2, ii, ii + 1)
# self.mutate_sample()
self.update_fitness()
self.sort_fitness()
return self.make_weights(self.chromosomes[0])
def mutate_sample(self):
for chromosome in self.chromosomes[1:]: # for all except the best chromosome
for idx in range(self.N):
if random.random() <= self.mutation_factor:
chromosome.gene[idx] = Chromosome.new_gene(self.bit_count)
for generation in range(self.gen_to_repeat):
self.create_children()
self.mutate_sample()
self.organize_sample()
return (self.make_weights(self.chromosomes[0]), self.chromosomes[0].get_score())
def create_children(self):
for ii in range(self.sample_size // 2, self.sample_size - 1, 2):
bucket_idx = randrange(8)
p1 = choice(self.buckets[bucket_idx])
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
for chromosome in self.chromosomes:
chromosome.fitness = compute_pattern(
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
bucket_idx = int(((phase(chromosome.fitness) + pi) / (2 * pi)) * 8) % 8
self.buckets[bucket_idx].append(chromosome)
def sort_fitness(self):
self.chromosomes.sort(key=lambda x: -20 * log10(abs(x.fitness)), reverse=True)
def mutate_sample(self):
# 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):
weights = []
......@@ -88,7 +110,7 @@ class GeneticBucketAlgorithm(BaseAlgorithm):
* pi
/ (2 ** self.bit_resolution)
)
weights.append(cmath.exp(1j * angle))
weights.append(exp(1j * angle))
return weights
def crossover(self, p1, p2, c1, c2):
......@@ -98,7 +120,7 @@ class GeneticBucketAlgorithm(BaseAlgorithm):
self.chromosomes[c1].gene[ii] = (g1 + g2) // 2
self.chromosomes[c2].gene[ii] = (g1 + g2 + 1) // 2
def intialize_sample(self):
def initialize_sample(self):
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