"""Onlooker Bees' class responsible for the exploitation phase of the
Artificial Bee Colony optimization.
"""
import sys
sys.path.append('...')
import time
import numpy as np
import pandas as pd
from .artificial_bee import ArtificialBee
from .food_source import FoodSource
from utils import Logger
[docs]class OnlookerBee(ArtificialBee):
'''Onlooker Bees, primarily responsible for the exploitation of \
the solution space. Onlookers search for neighboring food sources.
Attributes:
employee (:class:`~core.abc.employee_bee.EmployeeBee`): the assigned \
Employee Bee; stored to access greedy-selection
food_source (:class:`~core.abc.food_source.FoodSource`): the current \
food source (i.e neighbor)
id_tracker (int): the bee's ID for logging and tracking purposes
'''
def __init__(self):
'''Initializes an onlooker bee
'''
if not hasattr(OnlookerBee, 'id_tracker'):
OnlookerBee.id_tracker = 0
super(OnlookerBee, self).__init__(None, OnlookerBee.id_tracker)
OnlookerBee.id_tracker += 1
self.employee = None
[docs] def search(self, obj_interface):
'''
Exploit position (near a random :class:`~core.abc.employee_bee.EmployeeBee` \
chosen according to computed probability)
Args:
obj_interface (:class:`~core.objective_interface.ObjectiveInterface`): the \
objective interface used to sample/evaluate candidates
'''
self.food_source = self.get_random_neighbor(obj_interface)
[docs] def assign_employee(self, employee):
'''Assigns an EmployeeBee to the Onlooker for neighbor-search
Args:
employee (:class:`~core.abc.employee_bee.EmployeeBee`): the \
assigned employee bee
'''
self.employee = employee
self.food_source = FoodSource(self.employee.food_source.position)
[docs] def evaluate(self, obj_interface, itr):
'''
Evaluates sampled position and increments employee's trial counter
Args:
obj_interface (:class:`~core.objective_interface.ObjectiveInterface`): the objective interface \
used to sample/evaluate candidates
itr (int): current ABC iteration (for logging and result-saving purposes)
Returns:
:class:`pandas.Series`: a Pandas Series containing the evaluation's results (represents a \
row in the main results CSV file)
'''
Logger.evaluation_log('OnlookerBee', self.id, self.food_source.position)
t = time.time()
res = obj_interface.evaluate(self.food_source.position)
# unpack
self.food_source.fitness = res['fitness']
epochs = res['epochs']
weights_filename = res['filename']
params = res['params']
momentum = res['momentum']
momentum = sum([x[1] for _,x in momentum.items()]) / len(momentum) if len(momentum) else 0
self.food_source.time = time.time() - t
self.employee.trials += 1
self.employee.greedy_select(self.food_source, obj_interface.is_minimize)
series = pd.Series({
'bee_type': type(self).__name__,
'bee_id': self.id,
'bee_parent': self.employee.id,
'itr': itr,
'candidate': self.food_source.position,
'fitness': self.food_source.fitness,
'center_fitness': self.get_center_fs().fitness,
'momentum': momentum,
'epochs': epochs,
'momentum_epochs': 0,
'params': params,
'weights_filename': weights_filename,
'time': self.food_source.time
})
return series
[docs] def get_center_fs(self):
'''Returns the parent's center food_source
Returns:
:class:`~core.abc.food_source.FoodSource`: associated employee bee's \
center food source
'''
return self.employee.center_fs
def __str__(self):
'''For logging/debugging purposes
Returns:
str: the pretty-print contents of the OnlookerBee
'''
return 'OnlookerBee {} -> Parent Employee ({}) -- FS: {}'\
.format(self.id, self.employee.id, self.food_source)