Commit e904adb7 authored by Cihan Ates's avatar Cihan Ates
Browse files

Lecture notes, codes and additional materials are added for L4-L12.

parent 25d96832
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# -*- coding: utf-8 -*-
"""
Created on Thu Jul 8 15:28:46 2021
@author: cihan
"""
import datetime
import random
import genetic
'''
Problem Definition:
operate on numbers to reach a lucky number; say 35.
allowed operations:
* basics: +, -, *
* others: ^
'''
# Measure of fitness:
def get_fitness(genes, expectedTotal, fnEvaluate):
result = fnEvaluate(genes)
if result != expectedTotal:
fitness = expectedTotal - abs(result - expectedTotal)
else:
fitness = 1000 - len(genes)
return fitness
##############################################################################
##############################################################################
def create(numbers, operations, minNumber, maxNumber):
genes = [random.choice(numbers)]
count = random.randint(minNumber, maxNumber+1)
while count > 1:
count -=1
genes.append(random.choice(operations))
genes.append(random.choice(numbers))
return genes
##############################################################################
##############################################################################
def mutate(genes, numbers, operations, minNumbers, maxNumbers, fnGetFitness):
count = random.randint(1, 10)
initialFitness = fnGetFitness(genes)
while count > 0:
count -= 1
if fnGetFitness(genes) > initialFitness:
return
numberCount = (1 + len(genes)) / 2
appending = numberCount < maxNumbers and \
random.randint(0, 100) == 0
if appending:
genes.append(random.choice(operations))
genes.append(random.choice(numbers))
continue
removing = numberCount > minNumbers and \
random.randint(0, 20) == 0
if removing:
index = random.randrange(0, len(genes) - 1)
del genes[index]
del genes[index]
continue
index = random.randrange(0, len(genes))
genes[index] = random.choice(operations) \
if (index & 1) == 1 else random.choice(numbers)
##############################################################################
##############################################################################
# Evaluating the equation:
def evaluate(genes, prioritizedOperations):
equation = genes[:]
for operationSet in prioritizedOperations:
iOffset = 0
for i in range(1, len(equation), 2):
i += iOffset
opToken = equation[i]
if opToken in operationSet:
leftOperand = equation[i - 1]
rightOperand = equation[i + 1]
equation[i - 1] = operationSet[opToken](leftOperand, rightOperand)
del equation[i + 1]
del equation[i]
iOffset += -2
return equation[0]
##############################################################################
##############################################################################
# Helpers:
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def multiply(a, b):
return a * b
def display(candidate, startTime):
timeDiff = datetime.datetime.now() - startTime
print("{0}\t{1}\t{2}".format(
(' '.join(map(str, [i for i in candidate.Genes]))),
candidate.Fitness,
timeDiff))
##############################################################################
##############################################################################
# Equation generator class:
def EquationGenerator():
operations = ['^', '+', '-', '*']
prioritizedOperations = [{'^': lambda a, b: a ** b},
{'*': multiply},
{'+': add,
'-': subtract}]
optimalLengthSolution = [6, '^', 2, '-', 1]
solve(operations, prioritizedOperations, optimalLengthSolution)
def solve(operations, prioritizedOperations, optimalLengthSolution):
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
expectedTotal = evaluate(optimalLengthSolution, prioritizedOperations)
minNumbers = (1 + len(optimalLengthSolution)) / 2
maxNumbers = 6 * minNumbers
startTime = datetime.datetime.now()
def fnDisplay(candidate):
display(candidate, startTime)
def fnEvaluate(genes):
return evaluate(genes, prioritizedOperations)
def fnGetFitness(genes):
return get_fitness(genes, expectedTotal, fnEvaluate)
def fnCreate():
return create(numbers, operations, minNumbers, maxNumbers)
def fnMutate(child):
mutate(child, numbers, operations, minNumbers, maxNumbers, fnGetFitness)
optimalFitness = fnGetFitness(optimalLengthSolution)
genetic.get_best(fnGetFitness, None, optimalFitness, None,
fnDisplay, fnMutate, fnCreate, maxAge=50)
Case = EquationGenerator()
\ No newline at end of file
# This file is part of DEAP.
#
# DEAP is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# DEAP is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with DEAP. If not, see <http://www.gnu.org/licenses/>.
"""
This example is from "John R. Koza. Genetic Programming: On the Programming
of Computers by Natural Selection. MIT Press, Cambridge, MA, USA, 1992.".
The problem is called The Artificial Ant Problem.
<http://www.cs.ucl.ac.uk/staff/w.langdon/bloat_csrp-97-29/node2.html>
The goal of this example is to show how to use DEAP and its GP framework with
with complex system of functions and object.
Given an AntSimulator ant, this solution should get the 89 pieces of food
within 543 moves.
ant.routine = ant.if_food_ahead(ant.move_forward, prog3(ant.turn_left,
prog2(ant.if_food_ahead(ant.move_forward, ant.turn_right),
prog2(ant.turn_right, prog2(ant.turn_left, ant.turn_right))),
prog2(ant.if_food_ahead(ant.move_forward, ant.turn_left), ant.move_forward)))
Best solution found with DEAP:
prog3(prog3(move_forward,
turn_right,
if_food_ahead(if_food_ahead(prog3(move_forward,
move_forward,
move_forward),
prog2(turn_left,
turn_right)),
turn_left)),
if_food_ahead(turn_left,
turn_left),
if_food_ahead(move_forward,
turn_right))
fitness = (89,)
"""
import copy
import random
import numpy
from functools import partial
from deap import algorithms
from deap import base
from deap import creator
from deap import tools
from deap import gp
def progn(*args):
for arg in args:
arg()
def prog2(out1, out2):
return partial(progn,out1,out2)
def prog3(out1, out2, out3):
return partial(progn,out1,out2,out3)
def if_then_else(condition, out1, out2):
out1() if condition() else out2()
class AntSimulator(object):
direction = ["north","east","south","west"]
dir_row = [1, 0, -1, 0]
dir_col = [0, 1, 0, -1]
def __init__(self, max_moves):
self.max_moves = max_moves
self.moves = 0
self.eaten = 0
self.routine = None
def _reset(self):
self.row = self.row_start
self.col = self.col_start
self.dir = 1
self.moves = 0
self.eaten = 0
self.matrix_exc = copy.deepcopy(self.matrix)
@property
def position(self):
return (self.row, self.col, self.direction[self.dir])
def turn_left(self):
if self.moves < self.max_moves:
self.moves += 1
self.dir = (self.dir - 1) % 4
def turn_right(self):
if self.moves < self.max_moves:
self.moves += 1
self.dir = (self.dir + 1) % 4
def move_forward(self):
if self.moves < self.max_moves:
self.moves += 1
self.row = (self.row + self.dir_row[self.dir]) % self.matrix_row
self.col = (self.col + self.dir_col[self.dir]) % self.matrix_col
if self.matrix_exc[self.row][self.col] == "food":
self.eaten += 1
self.matrix_exc[self.row][self.col] = "passed"
def sense_food(self):
ahead_row = (self.row + self.dir_row[self.dir]) % self.matrix_row
ahead_col = (self.col + self.dir_col[self.dir]) % self.matrix_col
return self.matrix_exc[ahead_row][ahead_col] == "food"
def if_food_ahead(self, out1, out2):
return partial(if_then_else, self.sense_food, out1, out2)
def run(self,routine):
self._reset()
while self.moves < self.max_moves:
routine()
def parse_matrix(self, matrix):
self.matrix = list()
for i, line in enumerate(matrix):
self.matrix.append(list())
for j, col in enumerate(line):
if col == "#":
self.matrix[-1].append("food")
elif col == ".":
self.matrix[-1].append("empty")
elif col == "S":
self.matrix[-1].append("empty")
self.row_start = self.row = i
self.col_start = self.col = j
self.dir = 1
self.matrix_row = len(self.matrix)
self.matrix_col = len(self.matrix[0])
self.matrix_exc = copy.deepcopy(self.matrix)
ant = AntSimulator(600)
pset = gp.PrimitiveSet("MAIN", 0)
pset.addPrimitive(ant.if_food_ahead, 2)
pset.addPrimitive(prog2, 2)
pset.addPrimitive(prog3, 3)
pset.addTerminal(ant.move_forward)
pset.addTerminal(ant.turn_left)
pset.addTerminal(ant.turn_right)
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
creator.create("Individual", gp.PrimitiveTree, fitness=creator.FitnessMax)
toolbox = base.Toolbox()
# Attribute generator
toolbox.register("expr_init", gp.genFull, pset=pset, min_=1, max_=2)
# Structure initializers
toolbox.register("individual", tools.initIterate, creator.Individual, toolbox.expr_init)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
def evalArtificialAnt(individual):
# Transform the tree expression to functionnal Python code
routine = gp.compile(individual, pset)
# Run the generated routine
ant.run(routine)
return ant.eaten,
toolbox.register("evaluate", evalArtificialAnt)
toolbox.register("select", tools.selTournament, tournsize=7)
toolbox.register("mate", gp.cxOnePoint)
toolbox.register("expr_mut", gp.genFull, min_=0, max_=2)
toolbox.register("mutate", gp.mutUniform, expr=toolbox.expr_mut, pset=pset)
def main():
random.seed(69)
with open("ant/santafe_trail.txt") as trail_file:
ant.parse_matrix(trail_file)
pop = toolbox.population(n=300)
hof = tools.HallOfFame(1)
stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("avg", numpy.mean)
stats.register("std", numpy.std)
stats.register("min", numpy.min)
stats.register("max", numpy.max)
algorithms.eaSimple(pop, toolbox, 0.5, 0.2, 40, stats, halloffame=hof)
return pop, hof, stats
if __name__ == "__main__":
main()
# -*- coding: utf-8 -*-
"""
Created on Mon Jul 5 08:37:20 2021
@author: C. Ates
Exercise for genetic programing
"""
#Libs
import datetime
import random
import statistics
import time
import sys
from bisect import bisect_left
from math import exp
from enum import Enum
def _generate_parent(length, geneSet, get_fitness):
genes = []
while len(genes) < length:
sampleSize = min(length - len(genes), len(geneSet))
genes.extend(random.sample(geneSet, sampleSize))
fitness = get_fitness(genes)
return Chromosome(genes, fitness, Strategies.Create)
def _mutate(parent, geneSet, get_fitness):
childGenes = parent.Genes[:]
index = random.randrange(0, len(parent.Genes))
newGene, alternate = random.sample(geneSet, 2)
childGenes[index] = alternate \
if newGene == childGenes[index] \
else newGene
fitness = get_fitness(childGenes)
return Chromosome(childGenes, fitness, Strategies.Mutate)
def _mutate_custom(parent, custom_mutate, get_fitness):
childGenes = parent.Genes[:]
custom_mutate(childGenes)
fitness = get_fitness(childGenes)
return Chromosome(childGenes, fitness, Strategies.Mutate)
def _crossover(parentGenes, index, parents, get_fitness, crossover, mutate,
generate_parent):
donorIndex = random.randrange(0, len(parents))
if donorIndex == index:
donorIndex = (donorIndex + 1) % len(parents)
childGenes = crossover(parentGenes, parents[donorIndex].Genes)
if childGenes is None:
# parent and donor are indistinguishable
parents[donorIndex] = generate_parent()
return mutate(parents[index])
fitness = get_fitness(childGenes)
return Chromosome(childGenes, fitness, Strategies.Crossover)
def get_best(get_fitness, targetLen, optimalFitness, geneSet,
display, custom_mutate=None, custom_create=None,
maxAge=None, poolSize=1, crossover=None,
maxSeconds=None):
if custom_mutate is None:
def fnMutate(parent):
return _mutate(parent, geneSet, get_fitness)
else:
def fnMutate(parent):
return _mutate_custom(parent, custom_mutate, get_fitness)
if custom_create is None:
def fnGenerateParent():
return _generate_parent(targetLen, geneSet, get_fitness)
else:
def fnGenerateParent():
genes = custom_create()
return Chromosome(genes, get_fitness(genes), Strategies.Create)
strategyLookup = {
Strategies.Create: lambda p, i, o: fnGenerateParent(),
Strategies.Mutate: lambda p, i, o: fnMutate(p),
Strategies.Crossover: lambda p, i, o: _crossover(p.Genes, i, o, get_fitness,
crossover, fnMutate, fnGenerateParent)}
usedStrategies = [strategyLookup[Strategies.Mutate]]
if crossover is not None:
usedStrategies.append(strategyLookup[Strategies.Crossover])
def fnNewChild(parent, index, parents):
return random.choice(usedStrategies)(parent, index, parents)
else:
def fnNewChild(parent, index, parents):
return fnMutate(parent)
for timedOut, improvement in _get_improvement(fnNewChild, fnGenerateParent, maxAge,
poolSize, maxSeconds):
if timedOut:
return improvement
display(improvement)
f = strategyLookup[improvement.Strategy]
usedStrategies.append(f)
if not optimalFitness > improvement.Fitness:
return improvement
def _get_improvement(new_child, generate_parent, maxAge, poolSize, maxSeconds):
startTime = time.time()
bestParent = generate_parent()
yield maxSeconds is not None and time.time() - startTime > maxSeconds, bestParent
parents = [bestParent]
historicalFitnesses = [bestParent.Fitness]
for _ in range(poolSize - 1):
parent = generate_parent()
if maxSeconds is not None and time.time() - startTime > maxSeconds:
yield True, parent
if parent.Fitness > bestParent.Fitness:
yield False, parent
bestParent = parent
historicalFitnesses.append(parent.Fitness)
parents.append(parent)
lastParentIndex = poolSize - 1
pindex = 1
while True:
if maxSeconds is not None and time.time() - startTime > maxSeconds:
yield True, bestParent
pindex = pindex - 1 if pindex > 0 else lastParentIndex
parent = parents[pindex]
child = new_child(parent, pindex, parents)
if parent.Fitness > child.Fitness:
if maxAge is None:
continue
parent.Age += 1
if maxAge > parent.Age:
continue
index = bisect_left(historicalFitnesses, child.Fitness, 0,
len(historicalFitnesses))
difference = len(historicalFitnesses) - index
proportionSimilar = difference / len(historicalFitnesses)
if random.random() < exp(-proportionSimilar):
parents[pindex] = child
continue
parents[pindex] = bestParent
parent.Age = 0
continue
if not child.Fitness > parent.Fitness:
# same fitness
child.Age = parent.Age + 1
parents[pindex] = child
continue
parents[pindex] = child
parent.Age = 0
if child.Fitness > bestParent.Fitness:
yield False, child
bestParent = child
historicalFitnesses.append(child.Fitness)
class Chromosome:
Genes = None
Fitness = None
Age = 0
Strategy = None
def __init__(self, genes, fitness, strategy):
self.Genes = genes
self.Fitness = fitness
self.Strategy = strategy
class Strategies(Enum):
Create = 0,
Mutate = 1,
Crossover = 2
\ No newline at end of file
This diff is collapsed.
PID controller:
https://www.youtube.com/watch?v=S5C_z1nVaSg
Curious about control? See:
https://www.youtube.com/watch?v=Pi7l8mMjYVE&list=PLMrJAkhIeNNR20Mz-VpzgfQs5zrYi085m
https://www.youtube.com/watch?v=oulLR06lj_E&list=PLMrJAkhIeNNQkv98vuPjO2X2qJO_UPeWR
......@@ -26,15 +26,6 @@
"# Active Session 3: Dynamic Mode Decomposition: PyDMD exercise"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "SGDnRis4GSYs"
},
"source": [
"[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/cihan-ates/data-driven-engineering/blob/master/DDE_II_Advanced_Topics/Lecture%204/Lecture_4.ipynb)\n"
]
},
{
"cell_type": "markdown",
"metadata": {
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people