How to select parent using roulette wheel? - python

I'm trying to implement a genetic algorithm for solving the Travelling Salesman Problem (TSP).
I have 2 classes, which are City and Fitness.
I have done the code for initialization.
class City:
def __init__(self, x, y):
self.x = x
self.y = y
def distance(self, city):
xDis = abs(self.x - city.x)
yDis = abs(self.y - city.y)
distance = np.sqrt((xDis ** 2) + (yDis ** 2))
return distance
def __repr__(self):
return "(" + str(self.x) + "," + str(self.y) + ")"
class Fitness:
def __init__(self, route):
self.route = route
self.distance = None
self.fitness = None
def routeDistance(self):
if self.distance == None:
pathDistance = 0.0
for i in range(0, len(self.route)):
fromCity = self.route[i]
toCity = None
if i+1 < len(self.route):
toCity = self.route[i+1]
else:
toCity = self.route[0]
pathDistance += fromCity.distance(toCity)
self.distance = pathDistance
return self.distance
def routeFitness(self):
if self.fitness == None:
self.fitness = 1 / float(self.routeDistance())
return self.fitness
def selection(population, size=None):
if size== None:
size= len(population)
matingPool = []
fitnessResults = {}
for i in range(0, size):
fitnessResults[i] = Fitness(population[i]).routeFitness()
matingPool.append(random.choice(population))
return matingPool
The code above just randomly selects a parent in the selection method.
My question is: How to code to select a parent using roulette wheels?

You could try this [1, 2]:
from numpy.random import choice
def selection(population, size=None):
if size== None:
size= len(population)
fitnessResults = []
for i in range(0, size):
fitnessResults.append(Fitness(population[i]).routeFitness())
sum_fitness = sum(fitnessResults)
probability_lst = [f/sum_fitness for f in fitnessResults]
matingPool = choice(population, size=size, p=probability_lst)
return matingPool

Read this
So basically, the higher a fitness value, the higher are its chances to be chosen. But that is when high fitness value means a high fitness. But in TSP a lower value of fitness is better so to implement this, we need to implement the concept where probability is indirectly proportional to the fitness value.
Here is something I had implemented in python with some changes
def choose_parent_using_RWS(genes, S):
P = random.uniform(0, S)
for x in genes:
P += get_fitness_value(x)
if P > S:
return x
return genes[-1]
where S is the sum of the inverse of the fitness values of the current population (i.e, 1/f1 + 1/f2 + 1/f3 + ...)
and
get_fitness_value(x) returns the inverse of the distance, just like your routeFitness() function
TeeHee

Related

Is there a way to have a object type of your choice (i.e. LinkedEdge) hash as part of a 'union.set()' processing?

I have the following code and it works until it gets to the 'union.set()' part. It says, "unhashable type: 'LinkedEdge' " . I am not sure why this is the case since I have looked at other sources on the web and in reference books to know that the 'g.addVertex()' method and the 'g.addEdge()' method as well as the arguments being passed should lead correctly to an output like this:
5 Vertices: A C B E D
5 Edges: A>B:3 A>C:2 B>D:1 C>D:1 D>E:2
class LinkedEdge(object):
def __init__(self, fromVertex, toVertex, weight = None):
self._vertex1 = fromVertex
self._vertex2 = toVertex
self._weight = weight
self._mark = False
def clearMark(self):
self._mark = False
def __eq__(self, other):
if self is other: return True
if type(self) != type(other):
return False
return self._vertex1 == other._vertex1 and self._vertex2 == other._vertex2
def getOtherVertex(self, thisVertex):
if thisVertex == None or thisVertex == self._vertex2:
return self._vertex1
else:
return self._vertex2
def getToVertex(self):
return self._vertex2
def getWeight(self):
return self._weight
def isMarked(self):
return self._mark
def setMark(self):
self._mark = True
def setWeight(self, weight):
self._weight = weight
def __str__(self):
return str(self._vertex1) + ">" + str(self._vertex2) + ":" + str(self._weight)
class LinkedVertex(object):
def __init__(self, label):
self._label = label
self._edgeList = []
self._mark = False
def clearMark(self):
self._mark = False;
def getLabel(self):
return self._label
def isMarked(self):
return self._mark
def setLabel(self, label, g):
g._vertices.pop(self._label, None)
g._vertices[label] = self
self._label = label
def setMark(self):
self._mark = True
def __str__(self):
return str(self._label)
def addEdgeTo(self, toVertex, weight):
edge = LinkedEdge(self, toVertex, weight)
self._edgeList.append(edge)
def getEdgeTo(self, toVertex):
edge = LinkedEdge(self, toVertex)
try:
return self._edgeList[self._edgeList.index(edge)]
except:
return None
def incidentEdges(self):
return iter(self._edgeList)
def neighboringVertices(self):
vertices = []
for edge in self._edgeList:
vertices.append(edge.getOtherVertex(self))
return iter(vertices)
def removeEdgeTo(self, toVertex):
edge = LinkedEdge(self, toVertex)
if edge in self._edgeList:
self._edgeList.remove(edge)
return True
else:
return False
class LinkedDirectedGraph(object):
def __init__(self, collection = None):
self._vertexCount = 0
self._edgeCount = 0
self._vertices = {}
if collection != None:
for label in collection:
self.addVertex(label)
# Methods for clearing, marks, sizes, string rep
def clear(self):
self._vertexCount = 0
self._edgeCount = 0
self._vertices = {}
def clearEdgeMarks(self):
for edge in self.edges():
edge.clearMark()
def clearVertexMarks(self):
for vertex in self.vertices():
vertex.clearMark()
def isEmpty(self):
return self._vertexCount == 0;
def sizeEdges(self):
return self._edgeCount
def sizeVertices(self):
return self._vertexCount
def __str__(self):
result = str(self.sizeVertices()) + " Vertices: "
for vertex in self._vertices:
result += " " + str(vertex)
result += "\n";
result += str(self.sizeEdges()) + " Edges: "
for edge in self.edges():
result += " " + str(edge)
return result
def addVertex(self, label):
self._vertices[label] = LinkedVertex(label)
self._vertexCount += 1
def containsVertex (self, label):
return label in self._vertices
def getVertex(self, label):
return self._vertices[label]
def removeVertex(self, label):
removedVertex = self._vertices.pop(label, None)
if removedVertex is None:
return False
# Examine all vertices
for vertex in self.vertices():
if vertex.removeEdgeTo(removedVertex):
self._edgeCount -= 1
self._vertexCount -= 1
return True
def addEdge(self, fromLabel, toLabel, weight):
fromVertex = self.getVertex(fromLabel)
toVertex = self.getVertex(toLabel)
fromVertex.addEdgeTo(toVertex, weight)
self._edgeCount += 1
def containsEdge(self, fromLabel, toLabel):
return self.getEdge(fromLabel, toLabel) != None
def getEdge(self, fromLabel, toLabel):
fromVertex = self._vertices[fromLabel]
toVertex = self._vertices[toLabel]
return fromVertex.getEdgeTo(toVertex)
def removeEdge (self, fromLabel, toLabel):
fromVertex = self.getVertex(fromLabel)
toVertex = self.getVertex(toLabel)
edgeRemovedFlg = fromVertex.removeEdgeTo(toVertex)
if edgeRemovedFlg:
self._edgeCount -= 1
return edgeRemovedFlg
# Iterators
def edges(self):
result = set()
for vertex in self.vertices():
edges = vertex.incidentEdges()
result = result.union(set(edges))
return iter(result)
def vertices(self):
return iter(self._vertices.values())
def incidentEdges(self, label):
return self._vertices[label].incidentEdges()
def neighboringVertices(self, label):
return self._vertices[label].neighboringVertices
g = LinkedDirectedGraph()
# Insert vertices
g.addVertex("John")
g.addVertex("Sam")
g.addVertex("Megan")
g.addVertex("Jennifer")
g.addVertex("Rick")
# Insert weighted edges
g.addEdge("John", "Sam", 3)
g.addEdge("John", "Megan", 2)
g.addEdge("Sam", "Jennifer", 1)
g.addEdge("Megan", "Jennifer", 1)
g.addEdge("Jennifer", "Rick", 2)
print(g)
If you override __eq__, then Python intentionally makes your class unhashable, since there is no longer a guarantee that the default hashing algorithm (based on the object's location in memory) is compatible with your __eq__ algorithm. "Compatible" here just means that equal objects must have equal hashes. By default, nothing is equal, so when you make some things equal using an __eq__ method, you impose a requirement on what a proper hash function must do.
If you want a custom class with a custom __eq__ method to be hashable, you must implement a __hash__ method yourself.
It could be as simple as being based on the hash of the corresponding tuple:
def __hash__(self):
return hash((type(self), self._vertex1, self._vertex2))
The Python docs explain this here.

Errors in a class when trying to call it

I have this code consisting of a class and a subclass. The class is Euler forward, while the second one is Eulers midpoint method. These are for solving an ODE (x'=x(1/2-x)). Now it doesn't seem to work because when I am to call the function, by typing:
Euler=H.solve(6)
where the 6 is the amount of steps, I get attributeerror.
AttributeError: 'int' object has no attribute 'size'
Could anyone help me make my code more robust and working so I could plot the values later on, really don't see whats wrong. My code below:
import numpy as np
class H:
def __init__(self, f):
self._f = f
def initial(self, u0):
self._u0 = u0
def solve(self, time_points):
n = time_points.size
self._t = time_points
self._u = np.zeros(n)
self._u[0] = self._u0
for k in range(n-1):
self._k = k
self._u[k+1] = self.advance()
return self._u, self._t
class F(H):
def ad(self):
u = self._u; t = self._t; f = self._f; k = self._k
dt = t[k+1] - t[k]
u_k12 = u[k] + dt/2 * f(u[k], t[k])
return u[k] + dt * f(u_k12, (t[k] + dt/2) )
I think what's wrong is the way you use the class. Initial value is set with initial method (u0), then you give solve method the list of points. You can use np.linscape to generate midpoint.
np.linspace(0, 3, 31) # 30 points evenly spaced between 0 and 3
So it's like this:
def func(x, y):
return x * y
midpoint = np.linspace(0, 3, 31)
F_ = F(func)
F_.initial(6)
F_.solve(midpoint)
Code:
class H:
def __init__(self, f):
self._f = f
def initial(self, u0):
self._u0 = u0
def solve(self, time_points):
n = time_points.size
self._t = time_points
self._u = np.zeros(n)
self._u[0] = self._u0
for k in range(n-1):
self._u[k+1] = self.advance(k)
return self._u, self._t
def advance(self, k):
....
class F(H):
def advance(self, k):
dt = self._t[k+1] + self._t[k]
u_k12 = self._u[k] + dt/2 * self._f(self._u[k], self._t[k])
return self._u[k] + dt * self._f(u_k12, (self._t[k] + dt/2))

Subtraction with metric prefixes as objects

Im trying to subtract with prefixes as objects.
Here is my code
class Prefix:
def __init__(self, m=0, cm=0):
self.m = m
self.cm = cm
def __sub__(self, other):
centim = self.cm - other.cm
meter = (self.m - other.m) - abs(centim/100)
if meter < 1:
centim = m*100
meter = 0
return Prefix(meter, cm)
Im trying to subtract in a way which creates a negative centimeter value and take 1m from the meter object such that this is fulfilled
Prefix(2, 20) - Prefix(1, 30) == Prefix(0, 90)
First, keep in mind that for a given length, everything to the right of the hundreds place goes into cm, and everything at it or to its left gets divided by 100, and then goes into m.
Given this, we can recast the problem as converting both Prefix objects into their full lengths, performing calculations there, and then creating a new Prefix from the result:
class Prefix:
def __init__(self, m=0, cm=0):
self.m = m
self.cm = cm
def __sub__(self, other):
self_length = self.m * 100 + self.cm
other_length = other.m * 100 + other.cm
result_length = self_length - other_length
result_m, result_cm = divmod(result_length, 100)
return Prefix(result_m, result_cm)
result = Prefix(2, 20) - Prefix(1, 30)
print(result.m, result.cm)
Output:
0 90
Since we've come this far, we might as well store a "length" and overload __repr__ to make the result prettier:
class Prefix:
def __init__(self, length):
self.length = length
def __sub__(self, other):
result_length = self.length - other.length
return Prefix(result_length)
def __repr__(self):
result_m, result_cm = self.split_up(self.length)
if result_m > 0:
return f'{result_m}m {result_cm}cm'
else:
return f'{result_cm}cm'
#staticmethod
def split_up(length):
return divmod(length, 100)
Prefix(220) - Prefix(130)
Output:
90cm

Python genetic algorithm is slow

I made a genetic algorithm that writes the target phrase, but i'm feeling that it takes too long on each iteration, so I'd like to know if you have any idea on how to speed it up.
Thanks
from random import randint, random
from time import time
def rescale(X,A,B,C,D,force_float=False):
retval = ((float(X - A) / (B - A)) * (D - C)) + C
if not force_float and all(map(lambda x: type(x) == int, [X,A,B,C,D])):
return int(round(retval))
return retval
Here i create a list of random characters that form the phrase
class DNA:
def __init__(self,num):
self.genes=[]
for i in range(num):
self.genes.append((chr(randint(32,126))))
Transform the genes in a string
def getPhrase(self):
return(''.join(self.genes))
Calculating the fitness(similarity to the target)
def fitness(self,target):
score=0
for i in range(len(self.genes)):
if (self.genes[i] == target[i]):
score+=1
return score*score/(len(target)*len(target))
Mixing two genes (getting some character from one and some from another)
def crossover(self,partner):
child = DNA(len(self.genes))
midpoint = randint(0,len(self.genes))
for i in range(len(self.genes)):
if (i > midpoint):
child.genes[i] = self.genes[i]
else:
child.genes[i] = partner.genes[i]
return child
Mutating a gene(adding some random characters)
def mutate(self,mutationRate):
for i in range(len(self.genes)):
if (random() < mutationRate):
self.genes[i] = chr(randint(32,126))
A list of DNA objects
class Population:
def __init__(self,target,mutationRate,num):
self.population=[]
for i in range(num):
self.population.append(DNA(len(target)))
self.mutationRate=mutationRate
self.calcFitness(target)
self.generations=0
Making a list with the fitness of each gene
def calcFitness(self,target):
self.fitness=[]
for i in range(len(self.population)):
self.fitness.append(self.population[i].fitness(target))
Making a list to the crossover function, with entries proportional to the fitness
def naturalSelection(self):
global index, x
self.matingPool=[]
self.maxFitness = 0
for i in range(len(self.population)):
if (self.fitness[i] > self.maxFitness):
self.maxFitness = self.fitness[i]
index=i
print(DNA.getPhrase(population.population[index]),' generation: ',self.generations)
if (DNA.getPhrase(population.population[index]))==target:
x=False
for i in range(len(self.population)):
fitness = rescale(self.fitness[i],0,float(self.maxFitness),0,1)
n = (fitness * 100)
for j in range(int(n)):
self.matingPool.append(population.population[i])
Updating the population
def generate(self):
for i in range(len(self.population)):
a = randint(0,len(self.matingPool)-1)
b = randint(0,len(self.matingPool)-1)
partnerA = self.matingPool[a]
partnerB = self.matingPool[b]
child = partnerA.crossover(partnerB)
child.mutate(self.mutationRate)
population.population[i] = child
self.generations+=1
start=time()
target= input("Target: ")
population = Population(target, 0.05,300)
x=True
while x==True:
population.naturalSelection()
population.generate()
population.calcFitness(target)
end=time()
print(end-start)

Which data structure to use when implementing graph representation using adjacency list

I have a graph that is very big about 1,000,000 nodes and many edges. This is what i wanted to know which is the best suited data structure when implementing an adjacency list. Here are the objects that i keep track of
Edge list
Node to node connection list
I am coding with python so I used a set(because according to this it has a o(1) average insertion time) for edge list and a dictionary to node to node connection list(by making it completely hashable according to How to make an object properly hashable?). Here is my code
class node:
def __init__(self, name = ""):
self.__name = name
def getName(self):
return self.__name
def __str__(self):
return self.__name
def __hash__(self):
return hash(self.__name)
def __lt__(self, other):
if(type(self) != type(other)):
return NotImplemented
return self.__name.__lt__(other.__name)
def __eq__(self, other):
if(type(self)) != type(other):
return NotImplemented
return self.__name == other.__name
class Edge:
def __init__(self, name = "", node1 = None, node2 = None, weight = 0):
self.__name = name
self.__firstNode = node1
self.__secondNode = node2
self.__weight = weight
def getName(self):
return self.__name
def getFirstNode(self):
return self.__firstNode
def getSecondNode(self):
return self.__secondNode
def getWeight(self):
return self.__weight
def __lt__(self, other):
if(type(self) != type(other)):
return NotImplemented
return self.__name.__lt__(other.__name) and self.__firstNode.__lt__(other.__firstNode) and self.__secondNode.__lt__(other.__secondNode) and self.__weight.__lt__(other.__weight)
def __eq__(self, other):
if(type(self) != type(other)):
return NotImplemented
return self.__name == other.__name and self.__firstNode == other.__firstNode and self.__secondNode == other.__secondNode and self.__weight == other.__weight
def __str__(self):
return self.__name + " " + str(self.__firstNode) + " " + str(self.__secondNode) + " " + str(self.__weight)
def __hash__(self):
return hash(hash(self.__name) + hash(self.__firstNode) + hash(self.__secondNode) + hash(self.__weight))
class graph:
def __init__(self):
self.__nodeToNode = {}
self.__edgeList = set()
def addEdge(self, edge):
if(type(edge) != type(Edge())):
return False
self.__edgeList.add(edge)
if(not edge.getFirstNode() in self.__nodeToNode):
self.__nodeToNode[edge.getFirstNode()] = set()
self.__nodeToNode[edge.getFirstNode()].add(edge.getSecondNode())
if(not edge.getSecondNode() in self.__nodeToNode):
self.__nodeToNode[edge.getSecondNode()] = set()
self.__nodeToNode[edge.getSecondNode()].add(edge.getSecondNode())
return True
def getNodes(self):
return dict(self.__nodeToNode)
def getEdges(self):
return set(self.__edgeList)
import string
import random
import time
grp = graph()
nodes = [None] * 20000
for i in range(20000):
st = ''.join(random.SystemRandom().choice(string.ascii_letters) for i in range(10))
node1 = node(st)
nodes[i] = node1
current = time.time()
for i in range(3000000):
rdm = random.randint(0, 199)
rdm2 = random.randint(0, 199)
st = ''.join(random.SystemRandom().choice(string.ascii_letters) for i in range(10))
eg = Edge(st, nodes[rdm], nodes[rdm2])
grp.addEdge(eg)
last = time.time()
print((last - current))
nodes = grp.getNodes()
edges = grp.getEdges()
but this code runs very slowly can i make it faster? If so by using what data structure?
Let me introduce you a way to create an adjacency list:
Suppose you have the input like this:
4 4
1 2
3 2
4 3
1 4
The first line contains 2 numbers V and E, the next E lines defines an edge between two vertices.
You can either create a .txt file and read the input or directly type in via sys.stdin.read():
input = sys.stdin.read()
data = list(map(int, input.split()))
n, m = data[0:2]
data = data[2:]
edges = list(zip(data[0:(2 * m):2], data[1:(2 * m):2]))
x, y = data[2 * m:]
adj = [[] for _ in range(n)]
x, y = x - 1, y - 1
for (a, b) in edges:
adj[a - 1].append(b - 1)
adj[b - 1].append(a - 1)
Let's output the adjacency list adj:
>>> print(adj)
[[1, 3], [0, 2], [1, 3], [2, 0]]
adj[0] have two adj nodes: 1 and 3. Meaning the node 1 have two adj nodes: 2 and 4.
And now, if you want a directed, weighted graph, you just need to modify the input like this:
4 4
1 2 3 # edge(1, 2) has the weight of 3
3 2 1
4 3 1
1 4 2
input = sys.stdin.read()
data = list(map(int, input.split()))
n, m = data[0:2]
data = data[2:]
edges = list(zip(zip(data[0:(3 * m):3], data[1:(3 * m):3]), data[2:(3 * m):3]))
data = data[3 * m:]
adj = [[] for _ in range(n)]
cost = [[] for _ in range(n)]
for ((a, b), w) in edges:
adj[a - 1].append(b - 1)
cost[a - 1].append(w)
You store the weight in cost, and for example, cost[0][1] = 3, cost[0][3] = 2.
Hope this helped!

Categories