Skip to content

Commit

Permalink
paper;game
Browse files Browse the repository at this point in the history
  • Loading branch information
Freakwill committed Dec 4, 2023
1 parent 068e4e2 commit 5dce1a0
Show file tree
Hide file tree
Showing 38 changed files with 2,201 additions and 1,846 deletions.
Binary file modified docs/build/.doctrees/environment.pickle
Binary file not shown.
Binary file modified docs/build/.doctrees/source/Customization.doctree
Binary file not shown.
Binary file modified docs/build/.doctrees/source/Examples.doctree
Binary file not shown.
Binary file modified docs/build/.doctrees/source/Helpers.doctree
Binary file not shown.
Binary file modified docs/build/.doctrees/source/Install.doctree
Binary file not shown.
Binary file modified docs/build/.doctrees/source/Misc.doctree
Binary file not shown.
Binary file modified docs/build/.doctrees/source/pyrimidine.benchmarks.doctree
Binary file not shown.
Binary file modified docs/build/.doctrees/source/pyrimidine.doctree
Binary file not shown.
Binary file modified docs/build/.doctrees/source/pyrimidine.local_search.doctree
Binary file not shown.
7 changes: 4 additions & 3 deletions docs/build/_sources/source/Customization.md.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ class _Particle(BaseParticle):
...

class MyParticleSwarm(ParticleSwarm, metaclass=MetaContainer):

element_class = _Particle
default_size = 20
...
```

In the standard definition, as an individual, a particle has two "chromosomes", one represents the current position, the other represents the current velocity. While, you can define three or more chromosomes, to include the acceleration. It also has an important attribute, `memory` as its clone, but stores the best position that the particle passed-by.
In the standard definition, as an individual, a particle has two "chromosomes", one represents the current position, the other represents the current velocity. While, you can define three or more chromosomes, to include the acceleration. It also has an important attribute, `memory` storing the best position that the particle passed-by.


## Simulated Annealing Algorithm
Expand All @@ -45,7 +46,7 @@ class SimulatedAnnealing(FitnessModel):
}

def init(self):
self.phantom = self.clone(fitness=None)
self.phantom = self.copy(fitness=None)

def transition(self, *args, **kwargs):
T = self.initT
Expand Down Expand Up @@ -145,7 +146,7 @@ class SimulatedAnnealing(PhantomIndividual):

def init(self):
# initialize phantom solution
self.phantom = self.clone(fitness=None)
self.phantom = self.copy(fitness=None)


def transit(self, *args, **kwargs):
Expand Down
233 changes: 211 additions & 22 deletions docs/build/_sources/source/Examples.md.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Examples and Comparison of Algorithm
# Examples and Comparison of Algorithms
[TOC]

## Examples
## Example 1

### A simple example --- Knapsack problem

One of the famous problem is the knapsack problem. It is a good example for GA.
One of the well-known problem is the knapsack problem. It is a good example for GA.

#### Codes

Expand All @@ -24,13 +24,13 @@ _evaluate = Knapsack.random(n_bags) # : 0-1 array -> float

# Define the individual class
class MyIndividual(MonoIndividual):
element_class = BinaryChromosome.set(default_size=n_bags)
element_class = BinaryChromosome // n_bags
def _fitness(self) -> float:
# To evaluate an individual!
return _evaluate(self.chromosome)

""" Equiv. to
MyIndividual = MonoIndividual[BinaryChromosome.set(default_size=n_bags)].set_fitness(_evaluate)
MyIndividual = MonoIndividual[BinaryChromosome//n_bags].set_fitness(_evaluate)
"""

# Define the population class
Expand All @@ -39,9 +39,9 @@ class MyPopulation(HOFPopulation):
default_size = 10

""" Equiv. to
MyPopulation = HOFPopulation[MyIndividual].set(default_size=10)
MyPopulation = HOFPopulation[MyIndividual] //10
or, as a population of chromosomes
MyPopulation = HOFPopulation[BinaryChromosome.set(default_size=n_bags).set_fitness(_evaluate)].set(default_size=10)
MyPopulation = HOFPopulation[(BinaryChromosome//n_bags).set_fitness(_evaluate)] //10
"""

pop = MyPopulation.random()
Expand Down Expand Up @@ -153,9 +153,9 @@ iteration & solution & Mean Fitness & Best Fitness & Standard Deviation of Fitne
```


## Create new algo.
## Example 2

In the following example, the binary chromosomes should be decoded to floats. We recommend `digit_converter`, created by the author for such purpose, to handle with it.
In the following example, the binary chromosomes should be decoded to floats. We recommend `digit_converter` to handle with it, created by the author for such purpose.

```python
#!/usr/bin/env python3
Expand All @@ -168,7 +168,7 @@ from digit_converter import *

ndim = 10
def evaluate(x):
return -rosenbrock(ndim)(x)
return -rosenbrock(x)


class _Chromosome(BinaryChromosome):
Expand All @@ -184,12 +184,12 @@ class uChromosome(BinaryChromosome):
def _fitness(i):
return evaluate(i.decode())

ExampleIndividual = MultiIndividual[_Chromosome].set_fitness(_fitness)
ExampleIndividual = MultiIndividual[_Chromosome].set_fitness(_fitness) // ndim

class MyIndividual(MixIndividual[(_Chromosome,)*ndim + (uChromosome,)].set_fitness(_fitness)):
"""my own individual class
class MyIndividual(MixedIndividual[(_Chromosome,)*ndim + (uChromosome,)].set_fitness(_fitness)):
"""My own individual class

Method `mate` is overriden.
The method `mate` is overriden.
"""
ranking = None
threshold = 0.25
Expand Down Expand Up @@ -217,12 +217,7 @@ class MyIndividual(MixIndividual[(_Chromosome,)*ndim + (uChromosome,)].set_fitne
else:
return super().mate(other)

class MyPopulation(StandardPopulation[MyIndividual]):

def transition(self, *args, **kwargs):
self.sort()
super().transition(*args, **kwargs)

MyPopulation = StandardPopulation[MyIndividual]
```


Expand All @@ -237,7 +232,7 @@ ax = fig.add_subplot(111)

_Population = StandardPopulation[ExampleIndividual]
pop = MyPopulation.random(n_individuals=20, sizes=[8]*ndim+[8])
cpy = pop.clone(_Population)
cpy = pop.copy(type_=_Population)
d = cpy.evolve(stat=stat, n_iter=100, history=True)
ax.plot(d.index, d['Mean Fitness'], d.index, d['Best Fitness'], '.-')

Expand All @@ -247,4 +242,198 @@ ax.legend(('Traditional mean','Traditional best', 'New mean', 'New best'))
plt.show()
```

![](comparison.png)
![](comparison.png)


## Example 3

### Quantum GA

It is based on quantum chromosomes. Let use have a look at the source code.

```python
class QuantumChromosome(CircleChromosome):

measure_result = None

def decode(self):
self.measure()
return self.measure_result

def measure(self):
# measure a QuantumChromosome to get a binary sequence
rs = np.random.random(size=(len(self),))
self.measure_result = np.cos(self) ** 2 > rs
self.measure_result.astype(np.int_)
```

```python
#!/usr/bin/env python3

from pyrimidine import *
from pyrimidine.benchmarks.optimization import *

from pyrimidine.deco import add_memory, fitness_cache

# generate a knapsack problem randomly
n_bags = 50
evaluate = Knapsack.random(n=n_bags)

@fitness_cache
class YourIndividual(BinaryChromosome // n_bags):

def _fitness(self):
return evaluate(self.decode())


YourPopulation = HOFPopulation[YourIndividual] // 20

@fitness_cache
@add_memory({'measure_result': None, 'fitness': None})
class MyIndividual(QuantumChromosome // n_bags):

def _fitness(self):
return evaluate(self.decode())

def backup(self, check=False):
f = self._fitness()
if not check or (self.memory['fitness'] is None or f > self.memory['fitness']):
self._memory = {
'measure_result': self.measure_result,
'fitness': f
}

class MyPopulation(HOFPopulation):

element_class = MyIndividual
default_size = 20

def init(self):
self.backup()
super().init()

def backup(self, check=True):
for i in self:
i.backup(check=check)

def update_hall_of_fame(self, *args, **kwargs):
"""
Update the `hall_of_fame` after each step of evolution
"""
self.backup()
super().update_hall_of_fame(*args, **kwargs)

```

### Visualization and comparison
```python
stat={'Mean Fitness': 'mean_fitness', 'Best Fitness': 'best_fitness'}
mypop = MyPopulation.random()

yourpop = YourPopulation([YourIndividual(i.decode()) for i in mypop])
mydata = mypop.evolve(n_iter=100, stat=stat, history=True)
yourdata = yourpop.evolve(n_iter=100, stat=stat, history=True)

import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
yourdata[['Mean Fitness', 'Best Fitness']].plot(ax=ax)
mydata[['Mean Fitness', 'Best Fitness']].plot(ax=ax)
ax.legend(('Mean Fitness', 'Best Fitness', 'Mean Fitness(Quantum)', 'Best Fitness(Quantum)'))
ax.set_xlabel('Generations')
ax.set_ylabel('Fitness')
ax.set_title(f'Demo of (Quantum)GA: {n_bags}-Knapsack Problem')
plt.show()

```

![](QGA.png)

## Game

```python
#!/usr/bin/env python


from random import random, randint

import numpy as np

from pyrimidine import BasePopulation


class Player:
"""
'scissors', 'paper', 'stone' = 0, 1, 2
"""

params = {'mutate_prob': 0.02}

def __init__(self, strategy=0, score=0):
self.strategy = strategy # 1,2
self.score = score

@classmethod
def random(cls):
return cls(strategy=randint(0, 2), score=0)

def clone(self, *args, **kwargs):
return self.__class__(self.strategy, self.score)

def mutate(self):
self.strategy = randint(0, 2)

def init(self):
pass

def __lt__(self, other):
return ((self.strategy, other.strategy) == (0, 1)
or (self.strategy, other.strategy) == (1, 2)
or (self.strategy, other.strategy) == (2, 0))


class Game(BasePopulation):

element_class = Player
default_size = 100

def transition(self, *args, **kwargs):
self.compete()
self.duplicate()
self.mutate()

def compete(self):
k = int(0.5 * self.default_size)
winner = []
for i, p in enumerate(self[:-1]):
for j, q in enumerate(self[:i]):
if random() < 0.5:
if p < q:
p.score += 1
q.score -= 1
elif q < p:
p.score -= 1
q.score += 1
winners = np.argsort([p.score for p in self])[-k:]
self.elements = [self.elements[k] for k in winners]

def duplicate(self):
self.extend(self.clone())


game = Game.random()
stat = {'scissors': lambda game: sum(p.strategy==0 for p in game),
'paper': lambda game: sum(p.strategy==1 for p in game),
'stone': lambda game: sum(p.strategy==2 for p in game)
}
data = game.evolve(stat=stat, history=True)

import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
data[['scissors', 'paper', 'stone']].plot(ax=ax)
ax.set_title("Have a zero-sum game")
plt.show()
```

![](game.png)
Loading

0 comments on commit 5dce1a0

Please sign in to comment.