Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Alexander R. Hankin
EE194_Manduca_Simulator
Commits
a08dc059
Commit
a08dc059
authored
May 02, 2018
by
David A.. Werner
Browse files
Initial version of Population.py
parent
b81d5baa
Changes
2
Hide whitespace changes
Inline
Side-by-side
manduca/Population.py
0 → 100644
View file @
a08dc059
import
numpy
as
np
import
copy
import
tqdm
from
collections
import
namedtuple
class
GenerationInfo
(
namedtuple
(
'GenerationInfo'
,
[
'generation_number'
,
'incoming_fitness'
,
'outgoing_fitness'
,
'surviving_ancestors'
,
'surviving_children'
,
'surviving_mutants'
,
'num_ancestors'
,
'num_matings'
,
'num_mutants'
,
'duplicate_population'
,
'duplicate_children'
,
'duplicate_mutants'
])):
@
property
def
max_fitness
(
self
):
return
max
(
self
.
outgoing_fitness
)
class
EvolutionParameters
(
object
):
def
__init__
(
self
,
max_population
,
num_matings
,
num_mutants
,
max_mutations
,
**
kwargs
):
self
.
max_population
=
max_population
self
.
num_matings
=
num_matings
self
.
num_mutants
=
num_mutants
self
.
max_mutations
=
max_mutations
self
.
num_fittest
=
kwargs
.
pop
(
'num_fittest'
,
int
(
self
.
max_population
/
2
))
self
.
num_random
=
kwargs
.
pop
(
'num_random'
,
int
(
self
.
max_population
/
5
))
def
update_parameters
(
self
,
history
):
"""Basic EvolutionParameters doesn't change as the simulation progresses"""
pass
class
EvolutionSimulator
(
object
):
default_evolution_parameters
=
EvolutionParameters
(
20
,
10
,
10
,
10
)
def
__init__
(
self
,
population
,
evolution_parameters
=
None
,
random_number_generator
=
None
,
random_seed
=
None
,
pool
=
None
):
"""Population can be array of manducas or tuple of (f, num_pop), where each call to f()
produces a member of the population"""
if
isinstance
(
population
,
tuple
):
self
.
population
=
[
population
[
0
]()
for
_
in
range
(
population
[
1
])]
else
:
self
.
population
=
population
self
.
_children
=
[]
self
.
_mutants
=
[]
self
.
history
=
[]
if
evolution_parameters
is
None
:
self
.
evolution_parameters
=
copy
.
copy
(
self
.
__class__
.
default_evolution_parameters
)
else
:
self
.
evolution_parameters
=
copy
.
copy
(
evolution_parameters
)
if
random_number_generator
is
None
:
self
.
random_number_generator
=
np
.
random
.
RandomState
()
else
:
self
.
random_number_generator
=
random_number_generator
if
random_seed
:
self
.
random_number_generator
.
seed
(
random_seed
)
self
.
pool
=
pool
def
next_generation
(
self
,
current_generation
):
incoming_fitness
=
sorted
([
m
.
fitness
for
m
in
self
.
population
],
reverse
=
True
)
# mate: create children of two random parents
self
.
mate
()
# mutate: create mutations of random individuals
self
.
mutate
()
# remove duplicates
num_before_dups
=
[
len
(
self
.
population
),
len
(
self
.
_children
),
len
(
self
.
_mutants
)]
# individuals in current population are unique
self
.
population
=
list
(
set
(
self
.
population
))
# remove children who are clones of others in the population
self
.
_children
=
[
c
for
c
in
self
.
_children
if
c
not
in
self
.
population
]
# remove mutants who are clones of others in the population or of a child
self
.
_mutants
=
[
m
for
m
in
self
.
_mutants
if
m
not
in
self
.
population
+
self
.
_children
]
num_after_dups
=
[
len
(
self
.
population
),
len
(
self
.
_children
),
len
(
self
.
_mutants
)]
duplicate_population
=
num_before_dups
[
0
]
-
num_after_dups
[
0
]
duplicate_children
=
num_before_dups
[
1
]
-
num_after_dups
[
1
]
duplicate_mutants
=
num_before_dups
[
2
]
-
num_after_dups
[
2
]
self
.
update_fitness
()
num_after_survival
=
self
.
survive
()
surviving_ancestors
,
surviving_children
,
surviving_mutants
=
num_after_survival
outgoing_fitness
=
sorted
([
m
.
fitness
for
m
in
self
.
population
],
reverse
=
True
)
num_ancestors
=
self
.
evolution_parameters
.
max_population
num_matings
=
self
.
evolution_parameters
.
num_matings
num_mutants
=
self
.
evolution_parameters
.
num_mutants
self
.
evolution_parameters
.
update_parameters
(
self
.
history
)
return
GenerationInfo
(
current_generation
,
incoming_fitness
,
outgoing_fitness
,
surviving_ancestors
,
surviving_children
,
surviving_mutants
,
num_ancestors
,
num_matings
,
num_mutants
,
duplicate_population
,
duplicate_children
,
duplicate_mutants
)
@
property
def
population_size
(
self
):
return
len
(
self
.
population
)
def
mate
(
self
):
self
.
_children
=
[]
rng
=
self
.
random_number_generator
for
_
in
range
(
self
.
evolution_parameters
.
num_matings
):
p1
=
self
.
random_number_generator
.
choice
(
self
.
population
)
p2
=
self
.
random_number_generator
.
choice
(
self
.
population
)
self
.
_children
.
append
(
p1
.
mate
(
p2
,
rng
=
rng
))
def
mutate
(
self
):
self
.
_mutants
=
[]
for
_
in
range
(
self
.
evolution_parameters
.
num_mutants
):
rng
=
self
.
random_number_generator
clone
=
rng
.
choice
(
self
.
population
).
clone
()
clone
.
mutate
(
max_mutations
=
self
.
evolution_parameters
.
max_mutations
,
rng
=
rng
)
self
.
_mutants
.
append
(
clone
)
def
survive
(
self
):
rng
=
self
.
random_number_generator
all_manducas
=
[(
m
,
0
)
for
m
in
self
.
population
]
+
\
[(
m
,
1
)
for
m
in
self
.
_children
]
+
\
[(
m
,
2
)
for
m
in
self
.
_mutants
]
all_manducas
.
sort
(
key
=
lambda
val
:
val
[
0
].
fitness
,
reverse
=
True
)
# Always keep the best 10 individuals
num_fittest
=
self
.
evolution_parameters
.
num_fittest
fittest_manducas
,
unfit_manducas
=
all_manducas
[:
num_fittest
],
all_manducas
[
num_fittest
:]
unfit_manducas
=
np
.
array
(
unfit_manducas
)
# Pick more completely randomly
num_random
=
self
.
evolution_parameters
.
num_random
if
num_random
>
0
:
idxs
=
rng
.
choice
(
len
(
unfit_manducas
),
num_random
,
replace
=
False
)
randomly_selected_manducas
=
list
(
unfit_manducas
[
idxs
])
else
:
randomly_selected_manducas
=
[]
# Pick the rest randomly, weighted by fitness
remaining_manducas
=
self
.
evolution_parameters
.
max_population
-
num_fittest
-
num_random
if
remaining_manducas
>
0
:
fitnesses
=
[
val
[
0
].
fitness
for
val
in
unfit_manducas
]
fitnesses
-=
min
(
fitnesses
)
for
idx
in
idxs
:
fitnesses
[
idx
]
=
0
# Make sure not to duplicate already selected individuals
probs
=
fitnesses
/
sum
(
fitnesses
)
idxs
=
rng
.
choice
(
len
(
unfit_manducas
),
remaining_manducas
,
p
=
probs
,
replace
=
False
)
remaining_selected_manducas
=
list
(
unfit_manducas
[
idxs
])
else
:
remaining_selected_manducas
=
[]
selected_manducas
=
fittest_manducas
+
randomly_selected_manducas
+
remaining_selected_manducas
self
.
population
=
[
val
[
0
]
for
val
in
selected_manducas
if
val
[
1
]
==
0
]
self
.
_children
=
[
val
[
0
]
for
val
in
selected_manducas
if
val
[
1
]
==
1
]
self
.
_mutants
=
[
val
[
0
]
for
val
in
selected_manducas
if
val
[
1
]
==
2
]
num_after_survival
=
[
len
(
self
.
population
),
len
(
self
.
_children
),
len
(
self
.
_mutants
)]
self
.
population
=
self
.
population
+
self
.
_children
+
self
.
_mutants
self
.
_children
=
self
.
_mutants
=
[]
return
num_after_survival
def
run_simulation
(
self
,
num_generations
,
history_interval
=
1
,
progress_bar
=
True
):
for
generation
in
tqdm
.
tqdm
(
range
(
num_generations
),
disable
=
not
(
progress_bar
)):
generation_info
=
self
.
next_generation
(
generation
)
if
generation
%
history_interval
==
0
or
generation
==
0
or
generation
==
num_generations
-
1
:
self
.
history
.
append
(
generation_info
)
@
property
def
max_fitness
(
self
):
all_manducas
=
self
.
population
+
self
.
_children
+
self
.
_mutants
return
max
([
manduca
.
fitness
for
manduca
in
all_manducas
])
def
update_fitness
(
self
):
all_manducas
=
self
.
population
+
self
.
_children
+
self
.
_mutants
[
manduca
.
fitness
for
manduca
in
all_manducas
]
manduca/__init__.py
View file @
a08dc059
from
.Manducas
import
Manduca
,
SimpleManduca
,
ManducaDeformityError
from
.Manducas
import
Manduca
,
SimpleManduca
,
ManducaDeformityError
,
ManducaBodyProperties
from
.Population
import
EvolutionParameters
,
EvolutionSimulator
,
GenerationInfo
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment