Skip to content

Commit

Permalink
added the new internal representation for individuals
Browse files Browse the repository at this point in the history
  • Loading branch information
Oskar Taubert committed Nov 7, 2023
1 parent 96d078e commit bff313e
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 7 deletions.
64 changes: 59 additions & 5 deletions propulate/population.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from decimal import Decimal
from typing import Union

import numpy as np

Expand All @@ -10,8 +11,9 @@ class Individual:

def __init__(
self,
position: np.ndarray = None,
position: Union[dict, np.ndarray] = None,
velocity: np.ndarray = None,
limits: dict = None,
generation: int = -1,
rank: int = -1,
) -> None:
Expand All @@ -25,10 +27,30 @@ def __init__(
rank: int
rank (-1 if unset)
"""
super(Individual, self).__init__(list())

self.limits = limits
self.types = {key: type(limits[key][0]) for key in limits}
offset = 0
self.offsets = {}
for key in limits:
self.offsets[key] = offset
if isinstance(limits[key][0], str):
offset += len(limits[key])
else:
offset += 1

if isinstance(position, np.ndarray):
self.position = position
else:
self.position = np.zeros(offset)
for key in position:
self[key] = position[key]

self.velocity = velocity
self.generation = generation # Equals each worker's iteration for continuous population in Propulate.
self.rank = rank
self.loss = None # Set to None instead of inf since there are no comparisons

self.active = True
self.island = -1 # island of origin
self.current = -1 # current responsible worker
Expand All @@ -38,10 +60,38 @@ def __init__(
self.evalperiod = None # evaluation duration
if velocity is not None:
if not position.shape == velocity.shape:
raise ValueError()
raise ValueError("position and velocity shape mismatch")

def __getitem__(self, key):
if self.types[key] == float:
return self.position[self.offsets[key]].item()
elif self.types[key] == int:
return np.rint(self.position[self.offsets[key]]).item()
elif self.types[key] == str:
offset = self.offsets[key]
upper = self.offsets[key] + len(self.limits[key])
return self.limits[key][np.argmax(self.position[offset:upper]).item()]
else:
raise ValueError("Unknown type")

def __setitem__(self, key, newvalue):
if self.types[key] == float:
assert isinstance(newvalue, float)
self.position[self.offsets[key]] = newvalue
elif self.types[key] == int:
assert isinstance(newvalue, int)
self.position[self.offsets[key]] = float(newvalue)
elif self.types[key] == str:
assert newvalue in self.limits[key]
offset = self.offsets[key]
upper = len(self.limits[key])
self.position[offset:upper] = np.array([0])
self.position[offset + self.limits[key].index(newvalue)] = 1.0
else:
raise ValueError("Unknown type")

self.position = position
self.velocity = velocity
def __len__(self):
return len(self.limits)

def __repr__(self) -> str:
"""
Expand All @@ -61,6 +111,10 @@ def __repr__(self) -> str:
loss_str = f"{Decimal(float(self.loss)):.2E}"
return f"[{rep}, loss {loss_str}, island {self.island}, worker {self.rank}, generation {self.generation}]"

def __iter__(self):
for key in self.limits:
yield key

def __eq__(self, other) -> bool:
"""
Define equality operator ``==`` for class ``Individual``.
Expand Down
21 changes: 19 additions & 2 deletions tests/test_population.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@

@pytest.mark.mpi_skip
def test_individual():
limits = {
"float1": (0.0, 1.0),
"float2": (-1.0, 1.0),
"int1": (0, 5),
"int2": (1, 8),
"cat1": ("a", "b", "c", "d", "e"),
"cat2": ("f", "g", "h"),
}
ind_map = {
"float1": 0.1,
"float2": 0.2,
Expand All @@ -14,8 +22,17 @@ def test_individual():
"cat2": "f",
}

ind = Individual(ind_map)
print(ind)
ind = Individual(ind_map, limits=limits)
assert len(ind) == 6
assert ind.position.shape[0] == 12

for key in ind:
print(ind[key])
assert ind["cat1"] == "e"
assert ind["cat2"] == "f"

ind["cat1"] = "b"
assert ind.position[5] == 1.


@pytest.mark.mpi_skip
Expand Down

0 comments on commit bff313e

Please sign in to comment.