currentSolution (macop.algorithms.Algorithm.Algorithm attribute)

getGlobalEvaluation() (macop.algorithms.Algorithm.Algorithm method)

increaseEvaluation() (macop.algorithms.Algorithm.Algorithm method)

IteratedLocalSearch (class in macop.algorithms.IteratedLocalSearch)

initalizer (macop.algorithms.IteratedLocalSearch.IteratedLocalSearch attribute)

evaluator (macop.algorithms.IteratedLocalSearch.IteratedLocalSearch attribute)

operators (macop.algorithms.IteratedLocalSearch.IteratedLocalSearch attribute)

policy (macop.algorithms.IteratedLocalSearch.IteratedLocalSearch attribute)

validator (macop.algorithms.IteratedLocalSearch.IteratedLocalSearch attribute)

maximise (macop.algorithms.IteratedLocalSearch.IteratedLocalSearch attribute)

checkpoint (macop.algorithms.IteratedLocalSearch.IteratedLocalSearch attribute)

run() (macop.algorithms.IteratedLocalSearch.IteratedLocalSearch method)

currentSolution (macop.algorithms.LocalSearch.LocalSearch attribute)

bestSolution (macop.algorithms.LocalSearch.LocalSearch attribute)

algo (macop.checkpoints.BasicCheckpoint.BasicCheckpoint attribute)

every (macop.checkpoints.BasicCheckpoint.BasicCheckpoint attribute)

filepath (macop.checkpoints.BasicCheckpoint.BasicCheckpoint attribute)

load() (macop.checkpoints.BasicCheckpoint.BasicCheckpoint method)

run() (macop.checkpoints.BasicCheckpoint.BasicCheckpoint method)

evaluatorExample() (in module macop.evaluators.EvaluatorExample)

RandomSplitCrossover (class in macop.operators.crossovers.RandomSplitCrossover)

SimpleCrossover (class in macop.operators.crossovers.SimpleCrossover)

kind (macop.operators.crossovers.SimpleCrossover.SimpleCrossover attribute)

apply() (macop.operators.crossovers.SimpleCrossover.SimpleCrossover method)

SimpleBinaryMutation (class in macop.operators.mutators.SimpleBinaryMutation)

SimpleMutation (class in macop.operators.mutators.SimpleMutation)

kind (macop.operators.mutators.SimpleMutation.SimpleMutation attribute)

apply() (macop.operators.mutators.SimpleMutation.SimpleMutation method)

operators (macop.operators.policies.RandomPolicy.RandomPolicy attribute)

select() (macop.operators.policies.RandomPolicy.RandomPolicy method)

operators (macop.operators.policies.UCBPolicy.UCBPolicy attribute)

rewards (macop.operators.policies.UCBPolicy.UCBPolicy attribute)

occurences (macop.operators.policies.UCBPolicy.UCBPolicy attribute)

CombinatoryIntegerSolution (class in macop.solutions.CombinatoryIntegerSolution)

data (macop.solutions.IntegerSolution.IntegerSolution attribute)

size (macop.solutions.IntegerSolution.IntegerSolution attribute)

score (macop.solutions.IntegerSolution.IntegerSolution attribute)

random() (macop.solutions.IntegerSolution.IntegerSolution method)

"""Abstract Algorithm class used as basic algorithm implementation with some specific initialization
"""

# main imports
import logging
from ..utils.color import macop_text, macop_line

# Generic algorithm class
class Algorithm():
    """Algorithm class used as basic algorithm

    Attributes:
        initalizer: {function} -- basic function strategy to initialize solution
        evaluator: {function} -- basic function in order to obtained fitness (mono or multiple objectives)
        operators: {[Operator]} -- list of operator to use when launching algorithm
        policy: {Policy} -- Policy class implementation strategy to select operators
        validator: {function} -- basic function to check if solution is valid or not under some constraints
        maximise: {bool} -- specify kind of optimization problem 
        currentSolution: {Solution} -- current solution managed for current evaluation
        bestSolution: {Solution} -- best solution found so far during running algorithm
        checkpoint: {Checkpoint} -- Checkpoint class implementation to keep track of algorithm and restart
        parent: {Algorithm} -- parent algorithm reference in case of inner Algorithm instance (optional)
    """
    def __init__(self,
                 _initalizer,
                 _evaluator,
                 _operators,
                 _policy,
                 _validator,
                 _maximise=True,
                 _parent=None):

        self.initializer = _initalizer
        self.evaluator = _evaluator
        self.operators = _operators
        self.policy = _policy
        self.validator = _validator
        self.checkpoint = None
        self.bestSolution = None

        # other parameters
        self.parent = _parent  # parent algorithm if it's sub algorithm
        #self.maxEvaluations = 0 # by default
        self.maximise = _maximise

        self.initRun()

    def addCheckpoint(self, _class, _every, _filepath):
        """Add checkpoint to algorithm specifying usefull parameters

        Args:
            _class: {class} -- Checkpoint class type
            _every: {int} -- checkpoint frequency based on evaluations
            _filepath: {str} -- file path where checkpoints will be saved
        """
        self.checkpoint = _class(self, _every, _filepath)

    def setCheckpoint(self, _checkpoint):
        """Set checkpoint instance directly

        Args:
            _checkpoint: {Checkpoint} -- checkpoint instance
        """
        self.checkpoint = _checkpoint

    def resume(self):
        """Resume algorithm using checkpoint instance

        Raises:
            ValueError: No checkpoint initialize (use `addCheckpoint` or `setCheckpoint` is you want to use this process)
        """
        if self.checkpoint is None:
            raise ValueError(
                "Need to `addCheckpoint` or `setCheckpoint` is you want to use this process"
            )
        else:
            print(macop_line())
            print(
                macop_text('Checkpoint found from `{}` file.'.format(
                    self.checkpoint.filepath)))
            self.checkpoint.load()

    def initRun(self):
        """
        Method which initialiazes or re-initializes the whole algorithm context: operators, current solution, best solution (by default current solution)
        """

        # track reference of algo into operator (keep an eye into best solution)
        for operator in self.operators:
            operator.setAlgo(self)

        # also track reference for policy
        self.policy.setAlgo(self)

        self.currentSolution = self.initializer()

        # evaluate current solution
        self.currentSolution.evaluate(self.evaluator)

        # reinitialize policy
        # if self.parent is not None:
        #     self.policy = globals()[type(self.policy).__name__]()

        # keep in memory best known solution (current solution)
        self.bestSolution = self.currentSolution

    def increaseEvaluation(self):
        """
        Increase number of evaluation once a solution is evaluated
        """
        self.numberOfEvaluations += 1

        if self.parent is not None:
            self.parent.numberOfEvaluations += 1

    def getGlobalEvaluation(self):
        """Get the global number of evaluation (if inner algorithm)

        Returns:
            {int} -- current global number of evaluation
        """

            return self.parent.numberOfEvaluations

        return self.numberOfEvaluations

    def stop(self):
        """
        Global stopping criteria (check for inner algorithm too)
        """
            return self.parent.numberOfEvaluations >= self.parent.maxEvaluations or self.numberOfEvaluations >= self.maxEvaluations

        return self.numberOfEvaluations >= self.maxEvaluations

    def evaluate(self, _solution):
        """
        Evaluate a solution using evaluator passed when intialize algorithm

        Args:
            solution: {Solution} -- solution to evaluate

        Returns: 
            fitness score of solution which is not already evaluated or changed

        Note: 
            if multi-objective problem this method can be updated using array of `evaluator`
        """
        return _solution.evaluate(self.evaluator)

    def update(self, _solution):
        """
        Apply update function to solution using specific `policy`
        Check if solution is valid after modification and returns it
        
        Args:
            solution: {Solution} -- solution to update using current policy

        Returns:
            {Solution} -- updated solution obtained by the selected operator
        """

        # two parameters are sent if specific crossover solution are wished
        sol = self.policy.apply(_solution)

        if (sol.isValid(self.validator)):
            return sol
        else:
            logging.info("-- New solution is not valid %s" % sol)
            return _solution

    def isBetter(self, _solution):
        """
        Check if solution is better than best found

        Args:
            solution: {Solution} -- solution to compare with best one

        Returns:
            {bool} -- `True` if better
        """
        # depending of problem to solve (maximizing or minimizing)
        if self.maximise:
            if _solution.fitness() > self.bestSolution.fitness():
                return True
        else:
            if _solution.fitness() < self.bestSolution.fitness():

        # by default
        return False

    def run(self, _evaluations):
        """
        Run the specific algorithm following number of evaluations to find optima
        """

        self.maxEvaluations = _evaluations

        # check if global evaluation is used or not
        if self.parent is not None and self.getGlobalEvaluation() != 0:

            # init number evaluations of inner algorithm depending of globalEvaluation
            # allows to restart from `checkpoint` last evaluation into inner algorithm
            rest = self.getGlobalEvaluation() % self.maxEvaluations
            self.numberOfEvaluations = rest

        else:
            self.numberOfEvaluations = 0

        logging.info("Run %s with %s evaluations" %
                     (self.__str__(), _evaluations))

    def progress(self):
        """
        Log progress and apply checkpoint if necessary
        """
        if self.checkpoint is not None:
            self.checkpoint.run()

        logging.info("-- %s evaluation %s of %s (%s%%) - BEST SCORE %s" %
                     (type(self).__name__, self.numberOfEvaluations,
                      self.maxEvaluations, "{0:.2f}".format(
                          (self.numberOfEvaluations) / self.maxEvaluations *
                          100.), self.bestSolution.fitness()))

    def end(self):
        """Display end message into `run` method
        """
        print(
            macop_text('({}) Found after {} evaluations => {}'.format(
                type(self).__name__, self.numberOfEvaluations,
                self.bestSolution)))
        print(macop_line())

    def information(self):
        logging.info("-- Best %s - SCORE %s" %
                     (self.bestSolution, self.bestSolution.fitness()))

    def __str__(self):
        return "%s using %s" % (type(self).__name__, type(
            self.bestSolution).__name__)

"""Iterated Local Search Algorithm implementation
"""

# module imports
from .Algorithm import Algorithm
from .LocalSearch import LocalSearch

class IteratedLocalSearch(Algorithm):
    """Iterated Local Search used to avoir local optima and increave EvE (Exploration vs Exploitation) compromise

    """
    def run(self, _evaluations, _ls_evaluations=100):
        """
        Run the iterated local search algorithm using local search (EvE compromise)

        Args:
            _evaluations: {int} -- number of global evaluations for ILS
            _ls_evaluations: {int} -- number of Local search evaluations (default: 100)

        Returns:
            {Solution} -- best solution found
        """

        # by default use of mother method to initialize variables
        super().run(_evaluations)

        # enable checkpoint for ILS
            self.resume()

        # passing global evaluation param from ILS
        ls = LocalSearch(self.initializer,
                         self.evaluator,
                         self.operators,
                         self.policy,
                         self.validator,
                         self.maximise,
                         _parent=self)

        # set same checkpoint if exists
            ls.setCheckpoint(self.checkpoint)

        # local search algorithm implementation
        while not self.stop():

            # create and search solution from local search
            newSolution = ls.run(_ls_evaluations)

            # if better solution than currently, replace it
            if self.isBetter(newSolution):
                self.bestSolution = newSolution

            # number of evaluatins increased from LocalSearch
            # increase number of evaluations and progress are then not necessary there
            #self.increaseEvaluation()
            #self.progress()

            self.information()

        logging.info("End of %s, best solution found %s" %
                     (type(self).__name__, self.bestSolution))

        self.end()
        return self.bestSolution

"""Local Search algorithm
"""

class LocalSearch(Algorithm):
    """Local Search used as exploitation optimization algorithm

    """
        """
        Run the local search algorithm

        Args:
            _evaluations: {int} -- number of Local search evaluations
            
        Returns:
        """

        solutionSize = self.bestSolution.size

            for _ in range(solutionSize):

                # update solution using policy
                newSolution = self.update(self.bestSolution)

                # if better solution than currently, replace it
                if self.isBetter(newSolution):
                    self.bestSolution = newSolution

                # increase number of evaluations
                self.increaseEvaluation()

                self.progress()
                logging.info("---- Current %s - SCORE %s" %
                             (newSolution, newSolution.fitness()))

                # stop algorithm if necessary
                if self.stop():
                    break

"""Basic Checkpoint class implementation
"""

import os
import numpy as np

from .Checkpoint import Checkpoint

class BasicCheckpoint(Checkpoint):
    """
    BasicCheckpoint is used for loading previous computations and start again after loading checkpoit

        algo: {Algorithm} -- main algorithm instance reference
        every: {int} -- checkpoint frequency used (based on number of evaluations)
        filepath: {str} -- file path where checkpoints will be saved
    """
    def __init__(self, _algo, _every, _filepath):
        self.algo = _algo
        self.every = _every
        self.filepath = _filepath

    def run(self):
        """
        Check if necessary to do backup based on `every` variable
        """
        # get current best solution
        solution = self.algo.bestSolution

        currentEvaluation = self.algo.getGlobalEvaluation()

        # backup if necessary
        if currentEvaluation % self.every == 0:

            logging.info("Checkpoint is done into " + self.filepath)

            solutionData = ""
            solutionSize = len(solution.data)

            for index, val in enumerate(solution.data):
                solutionData += str(val)

                if index < solutionSize - 1:
                    solutionData += ' '

            line = str(currentEvaluation) + ';' + solutionData + ';' + str(
                solution.fitness()) + ';\n'

            # check if file exists
            if not os.path.exists(self.filepath):
                with open(self.filepath, 'w') as f:
                    f.write(line)
            else:
                with open(self.filepath, 'a') as f:

    def load(self):
        """
        Load last backup line of solution and set algorithm state (best solution and evaluations) at this backup
        """
        if os.path.exists(self.filepath):

            logging.info('Load best solution from last checkpoint')
            with open(self.filepath) as f:

                # get last line and read data
                lastline = f.readlines()[-1]
                data = lastline.split(';')

                # get evaluation  information
                globalEvaluation = int(data[0])

                if self.algo.parent is not None:
                    self.algo.parent.numberOfEvaluations = globalEvaluation
                else:
                    self.algo.numberOfEvaluations = globalEvaluation

                # get best solution data information
                solutionData = list(map(int, data[1].split(' ')))

                self.algo.bestSolution.data = np.array(solutionData)
                self.algo.bestSolution.score = float(data[2])

            print(
                macop_text('Restart algorithm from evaluation {}.'.format(
                    self.algo.numberOfEvaluations)))

        else:
            print(
                macop_text(
                    'No backup found... Start running algorithm from evaluation 0.'
                ))
            logging.info(
                "Can't load backup... Backup filepath not valid in Checkpoint")

"""Abstract Checkpoint class
"""
import os

class Checkpoint():
    """
    Local Search used as exploitation optimization algorithm

    """

        # build path if not already exists
        head, _ = os.path.split(self.filepath)

        if not os.path.exists(head):
            os.makedirs(head)

        """
        """
        pass

        """
        Load last backup line of solution and set algorithm state at this backup
        """
        pass

"""Python evaluator function example
"""

# evaluator example
def evaluatorExample(_solution):
    """
    Evaluator's example of solution to compute fitness

    Args:
        _solution: {Solution} -- solution to evaluate

    Returns:
        {float} -- fitness score of solution
    """
    fitness = 0
    for index, elem in enumerate(_solution.data):
        fitness = fitness + (elem * index)

    return fitness

"""Abstract Operator class
"""
from enum import Enum

# enumeration which stores kind of operator
class KindOperator(Enum):
    """Enum in order to recognize kind of operators
    """
    MUTATOR = 1
    CROSSOVER = 2

class Operator():
    """Abstract Operator class which enables to update solution applying operator (computation)
    """
    def __init__(self):
        pass

    def apply(self, _solution):
        """Apply the current operator transformation

        Args:
            _solution: {Solution} -- Solution instance

        Raises:
            NotImplementedError: if method not implemented into child class
        """
        raise NotImplementedError

    def setAlgo(self, _algo):
        """Keep into operator reference of the whole algorithm
           The reason is to better manage operator instance

        Args:
            _algo: {Algorithm} -- the algorithm reference runned
        """

"""Abstract Crossover class
"""
from ..Operator import KindOperator, Operator

# main mutation class
class Crossover(Operator):
    """Abstract crossover extend from Operator

        kind: {KindOperator} -- specify the kind of operator
    """
        self.kind = KindOperator.CROSSOVER

    def apply(self, solution):

"""Crossover implementation which generated new solution by randomly splitting best solution and current solution
"""
import random
import sys
import pkgutil

from .Crossover import Crossover

# import all available solutions
for loader, module_name, is_pkg in pkgutil.walk_packages(
        path=['macop/solutions'], prefix='macop.solutions.'):
    _module = loader.find_module(module_name).load_module(module_name)
    globals()[module_name] = _module

class RandomSplitCrossover(Crossover):
    """Crossover implementation which generated new solution by randomly splitting best solution and current solution

    """
        """Create new solution based on best solution found and solution passed as parameter

        Args:
            _solution: {Solution} -- the solution to use for generating new solution

        Returns:
            {Solution} -- new generated solution
        """
        size = _solution.size

        # copy data of solution
        firstData = _solution.data.copy()
        # get best solution from current algorithm
        secondData = self.algo.bestSolution.data.copy()

        splitIndex = random.randint(0, len(secondData))

        if random.uniform(0, 1) > 0.5:
            firstData[splitIndex:(size - 1)] = firstData[splitIndex:(size - 1)]
            currentData = firstData
        else:
            secondData[splitIndex:(size - 1)] = firstData[splitIndex:(size -
                                                                      1)]
            currentData = secondData

        # create solution of same kind with new data
        class_name = type(_solution).__name__
        return getattr(globals()['macop.solutions.' + class_name],
                       class_name)(currentData, size)

"""Crossover implementation which generated new solution by splitting at mean size best solution and current solution
"""
import sys

class SimpleCrossover(Crossover):
    """Crossover implementation which generated new solution by splitting at mean size best solution and current solution

        kind: {Algorithm} -- specify the kind of operator
    """

        Args:

        Returns:
        """

        splitIndex = int(size / 2)

        else:
                                                                      1)]

"""Abstract Mutation class
"""

class Mutation(Operator):
    """Abstract Mutation extend from Operator

    """
        self.kind = KindOperator.MUTATOR

"""Mutation implementation for binary solution, swap bit randomly from solution
"""
import sys

from .Mutation import Mutation

class SimpleBinaryMutation(Mutation):
    """Mutation implementation for binary solution, swap bit randomly from solution

    """
        """Create new solution based on solution passed as parameter

        Args:

        Returns:
        """

        cell = random.randint(0, size - 1)

        currentData = _solution.data.copy()

        # swicth values
        if currentData[cell]:
            currentData[cell] = 0
        else:
            currentData[cell] = 1

"""Mutation implementation for binary solution, swap two bits randomly from solution
"""
import sys

class SimpleMutation(Mutation):
    """Mutation implementation for binary solution, swap two bits randomly from solution

    """

        Args:

        Returns:
        """

        firstCell = 0
        secondCell = 0

        while firstCell == secondCell:
            firstCell = random.randint(0, size - 1)
            secondCell = random.randint(0, size - 1)

        temp = currentData[firstCell]

        currentData[firstCell] = currentData[secondCell]
        currentData[secondCell] = temp

"""Abstract class which is used for applying strategy when selecting and applying operator 
"""

# define policy to choose `operator` function at current iteration
class Policy():
    """Abstract class which is used for applying strategy when selecting and applying operator 

        operators: {[Operator]} -- list of selected operators for the algorithm
    """
    def __init__(self, _operators):

    def select(self):
        """
        Select specific operator to solution and returns solution
        """

        """
        Apply specific operator chosen to create new solution, computes its fitness and returns solution
        
        Args:

        Returns:
        """

        operator = self.select()

        logging.info("---- Applying %s on %s" %
                     (type(operator).__name__, _solution))

        # apply operator on solution
        newSolution = operator.apply(_solution)

        # compute fitness of new solution
        newSolution.evaluate(self.algo.evaluator)

        logging.info("---- Obtaining %s" % (_solution))

        return newSolution

        """Keep into policy reference of the whole algorithm
           The reason is to better manage the operator choices (use of rewards as example)

        Args:
        """

"""Policy class implementation which is used for selecting operator randomly
"""

from .Policy import Policy

class RandomPolicy(Policy):
    """Policy class implementation which is used for select operator randomly

    """
        """Select randomly the next operator to use

        Returns:
            {Operator}: the selected operator
        """
        # choose operator randomly
        index = random.randint(0, len(self.operators) - 1)
        return self.operators[index]

"""Policy class implementation which is used for selecting operator using Upper Confidence Bound
"""
import math

class UCBPolicy(Policy):
    """UCB policy class which is used for applying UCB strategy when selecting and applying operator 

        C: {float} -- tradeoff between EvE parameter for UCB
        rewards: {[float]} -- list of summed rewards obtained for each operator
        occurences: {[int]} -- number of use (selected) of each operator
    """
    def __init__(self, _operators, _C=10.):
        self.rewards = [0. for o in self.operators]
        self.occurences = [0 for o in self.operators]
        self.C = _C

        Returns:
        """

        indices = [i for i, o in enumerate(self.occurences) if o == 0]

        # if operator have at least be used one time
        if len(indices) == 0:

            ucbValues = []
            nVisits = sum(self.occurences)

            for i in range(len(self.operators)):

                ucbValue = self.rewards[i] + self.C * math.sqrt(
                    math.log(nVisits) / self.occurences[i])
                ucbValues.append(ucbValue)

            return self.operators[ucbValues.index(max(ucbValues))]

        else:
            return self.operators[random.choice(indices)]

        """
        
        Args:

        Returns:
        """

        # compute reward
        difference = newSolution.fitness() - _solution.fitness()
        reward = difference if difference > 0 else 0.

        operator_index = self.operators.index(operator)
        self.rewards[operator_index] += reward
        self.occurences[operator_index] += 1

"""Binary solution class implementation
"""

# modules imports
from .Solution import Solution

# Solution which stores solution data as binary array
class BinarySolution(Solution):
    """
    Binary integer solution class

        data: {ndarray} --  array of binary values
        size: {int} -- size of binary array values
        score: {float} -- fitness score value
    """
    def __init__(self, _data, _size):
        """
        Initialize binary solution using specific data

        Args:
            data: {ndarray} --  array of binary values
            size: {int} -- size of binary array values
        """

        self.data = _data
        self.size = _size

    def random(self, _validator):
        """
        Intialize binary array with use of validator to generate valid random solution

        Args:
            _validator: {function} -- specific function which validates or not a solution

        Returns:
            {BinarySolution} -- new generated binary solution
        """

        self.data = np.random.randint(2, size=self.size)

        while not self.isValid(_validator):
            self.data = np.random.randint(2, size=self.size)

        return self

        return "Binary solution %s" % (self.data)

"""Combinatory integer solution class implementation
"""

# Solution which stores solution data as combinatory integer array
class CombinatoryIntegerSolution(Solution):
    """
    Combinatory integer solution class

    """
        """

        Args:
        """

        """
        Intialize combinatory integer array with use of validator to generate valid random solution

        Args:

        Returns:
            {CombinatoryIntegerSolution} -- new generated combinatory integer solution
        """

        self.data = np.random.shuffle(np.arange(self.size))

            self.data = np.random.shuffle(np.arange(self.size))

        return "Combinatory integer solution %s" % (self.data)

"""Integer solution class implementation
"""

# Solution which stores solution data as integer array
class IntegerSolution(Solution):
    """
    Integer solution class

    """
        """
        Initialize integer solution using specific data

        Args:
        """

        """
        Intialize integer array with use of validator to generate valid random solution

        Args:

        Returns:
            {IntegerSolution} -- new generated integer solution
        """

        self.data = np.random.randint(self.size, size=self.size)

            self.data = np.random.randint(self.size, size=self.size)

        return "Integer solution %s" % (self.data)