Quellcode durchsuchen

Update of operators

Jérôme BUISINE vor 4 Jahren
Ursprung
Commit
0dff1b3cc8

+ 1 - 1
README.md

@@ -9,7 +9,7 @@ Optimisation generic framework built for optimization problem during thesis
 - **algorithms:** generic and implemented OR algorithms
 - **evaluator:** example of an evaluation function to use (you have to implement your own evaluation function)
 - **solutions:** solutions used to represent problem data
-- **updators:** mutators, crossovers update of solution. This folder also had `policies` folder to manage the way of update and use solution.
+- **operators:** mutators, crossovers update of solution. This folder also had `policies` folder to manage the way of update and use solution.
   
 **Note:** you can pass a custom `validator` function to the algorithm in order to check is solution is always correct for your needs after an update.
 

+ 5 - 4
algorithms/Algorithm.py

@@ -4,14 +4,14 @@ import logging
 # Generic algorithm class
 class Algorithm():
 
-    def __init__(self, _initalizer, _evaluator, _updators, _policy, _validator, _maximise=True):
+    def __init__(self, _initalizer, _evaluator, _operators, _policy, _validator, _maximise=True):
         """
         Initialize all usefull parameters for problem to solve
         """
 
         self.initializer = _initalizer
         self.evaluator = _evaluator
-        self.updators = _updators
+        self.operators = _operators
         self.validator = _validator
         self.policy = _policy
 
@@ -49,7 +49,7 @@ class Algorithm():
         return solution.evaluate(self.evaluator)
 
 
-    def update(self, solution):
+    def update(self, solution, secondSolution=None):
         """
         Apply update function to solution using specific `policy`
 
@@ -59,7 +59,8 @@ class Algorithm():
             updated solution
         """
 
-        sol = self.policy.apply(solution)
+        # two parameters are sent if specific crossover solution are wished
+        sol = self.policy.apply(solution, secondSolution)
 
         if(sol.isValid(self.validator)):
             return sol

+ 1 - 1
algorithms/IteratedLocalSearch.py

@@ -12,7 +12,7 @@ class IteratedLocalSearch(Algorithm):
         # by default use of mother method to initialize variables
         super().run(_evaluations)
 
-        ls = LocalSearch(self.initializer, self.evaluator, self.updators, self.policy, self.validator, self.maximise)
+        ls = LocalSearch(self.initializer, self.evaluator, self.operators, self.policy, self.validator, self.maximise)
 
         # local search algorithm implementation
         while self.numberOfEvaluations < self.maxEvalutations:

+ 3 - 2
algorithms/LocalSearch.py

@@ -19,7 +19,8 @@ class LocalSearch(Algorithm):
             for _ in range(solutionSize):
 
                 # update solution using policy
-                newSolution = self.update(self.bestSolution)
+                # send random solution as second parameter for mutation
+                newSolution = self.update(self.bestSolution, self.initializer())
 
                 # if better solution than currently, replace it
                 if self.isBetter(newSolution):
@@ -29,7 +30,7 @@ class LocalSearch(Algorithm):
                 self.numberOfEvaluations += 1
 
                 self.progress()
-                logging.info("-- Found solution %s with score of %s" % (newSolution, newSolution.fitness()))
+                logging.info("-- Found %s with score of %s" % (newSolution, newSolution.fitness()))
 
                 # stop algorithm if necessary
                 if self.numberOfEvaluations >= self.maxEvalutations:

+ 8 - 5
mainExample.py

@@ -10,8 +10,11 @@ from optimization.algorithms.IteratedLocalSearch import IteratedLocalSearch as I
 from optimization.solutions.BinarySolution import BinarySolution
 from optimization.evaluators.EvaluatorExample import evaluatorExample
 
-from optimization.updators.mutators.SimpleMutation import SimpleMutation, SimpleBinaryMutation
-from optimization.updators.policies.RandomPolicy import RandomPolicy
+from optimization.operators.mutators.SimpleMutation import SimpleMutation
+from optimization.operators.mutators.SimpleBinaryMutation import SimpleBinaryMutation
+from optimization.operators.crossovers.SimpleCrossover import SimpleCrossover
+
+from optimization.operators.policies.RandomPolicy import RandomPolicy
 
 # logging configuration
 logging.basicConfig(format='%(asctime)s %(message)s', filename='example.log', level=logging.DEBUG)
@@ -26,10 +29,10 @@ def init():
 
 def main():
 
-    updators = [SimpleBinaryMutation, SimpleMutation]
-    policy = RandomPolicy(updators)
+    operators = [SimpleBinaryMutation(), SimpleMutation(), SimpleCrossover()]
+    policy = RandomPolicy(operators)
 
-    algo = ILS(init, evaluatorExample, updators, policy, validator, True)
+    algo = ILS(init, evaluatorExample, operators, policy, validator, True)
 
     bestSol = algo.run(100000)
 

+ 7 - 0
operators/Operator.py

@@ -0,0 +1,7 @@
+# main imports
+from enum import Enum
+
+# enumeration which stores kind of operator
+class Operator(Enum):
+    MUTATOR = 1
+    CROSSOVER = 2

updators/__init__.py → operators/__init__.py


+ 11 - 0
operators/crossovers/Crossover.py

@@ -0,0 +1,11 @@
+# module imports
+from ..Operator import Operator
+
+# main mutation class
+class Crossover():
+
+    def __init__(self):
+        self.kind = Operator.CROSSOVER
+
+    def apply(self, solution, secondSolution=None):
+        raise NotImplementedError

+ 31 - 0
operators/crossovers/SimpleCrossover.py

@@ -0,0 +1,31 @@
+# main imports
+import random
+import sys
+
+# module imports
+from .Crossover import Crossover
+
+from ...solutions.BinarySolution import BinarySolution
+from ...solutions.Solution import Solution
+
+
+class SimpleCrossover(Crossover):
+
+    def apply(self, solution, secondSolution=None):
+        size = solution.size
+
+        # copy data of solution
+        firstData = solution.data.copy()
+        secondData = secondSolution.data.copy()
+
+        splitIndex = int(size / 2)
+        
+        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
+        return globals()[type(solution).__name__](currentData, size)

updators/crossovers/__init__.py → operators/crossovers/__init__.py


+ 11 - 0
operators/mutators/Mutation.py

@@ -0,0 +1,11 @@
+# module imports
+from ..Operator import Operator
+
+# main mutation class
+class Mutation():
+
+    def __init__(self):
+        self.kind = Operator.MUTATOR
+
+    def apply(self, solution):
+        raise NotImplementedError

+ 28 - 0
operators/mutators/SimpleBinaryMutation.py

@@ -0,0 +1,28 @@
+# main imports
+import random
+import sys
+
+# module imports
+from .Mutation import Mutation
+
+from ...solutions.BinarySolution import BinarySolution
+from ...solutions.Solution import Solution
+
+class SimpleBinaryMutation(Mutation):
+
+    def apply(self, solution):
+        size = solution.size
+
+        cell = random.randint(0, size - 1)
+
+        # copy data of solution
+        currentData = solution.data.copy()
+
+        # swicth values
+        if currentData[cell]:
+            currentData[cell] = 0
+        else:
+            currentData[cell] = 1
+
+        # create solution of same kind with new data
+        return globals()[type(solution).__name__](currentData, size)

+ 35 - 0
operators/mutators/SimpleMutation.py

@@ -0,0 +1,35 @@
+# main imports
+import random
+import sys
+
+# module imports
+from .Mutation import Mutation
+
+from ...solutions.BinarySolution import BinarySolution
+from ...solutions.Solution import Solution
+
+
+class SimpleMutation(Mutation):
+
+    def apply(self, solution):
+        size = solution.size
+
+        firstCell = 0
+        secondCell = 0
+
+        # copy data of solution
+        currentData = solution.data.copy()
+
+        while firstCell == secondCell:
+            firstCell = random.randint(0, size - 1) 
+            secondCell = random.randint(0, size - 1)
+
+        temp = currentData[firstCell]
+
+        # swicth values
+        currentData[firstCell] = currentData[secondCell]
+        currentData[secondCell] = temp
+        
+        # create solution of same kind with new data
+        return globals()[type(solution).__name__](currentData, size)
+

updators/mutators/__init__.py → operators/mutators/__init__.py


+ 13 - 0
operators/policies/Policy.py

@@ -0,0 +1,13 @@
+# define policy to choose `operator` function at current iteration
+class Policy():
+
+    # here you can define your statistical variables for choosing next operator to apply
+
+    def __init__(self, _operators):
+        self.operators = _operators
+
+    def apply(self, solution):
+        """
+        Apply specific operator to solution and returns solution
+        """
+        raise NotImplementedError

+ 24 - 0
operators/policies/RandomPolicy.py

@@ -0,0 +1,24 @@
+# main imports
+import random
+
+# module imports
+from ..Operator import Operator
+from .Policy import Policy
+
+class RandomPolicy(Policy):
+
+    def apply(self, solution, secondSolution=None):  
+
+        # choose operator randomly
+        index = random.randint(0, len(self.operators) - 1)
+        operator = self.operators[index]
+
+        # check kind of operator
+        if operator.kind == Operator.CROSSOVER:
+            return operator.apply(solution, secondSolution)
+        
+        if operator.kind == Operator.MUTATOR:
+            return operator.apply(solution)
+
+        # by default
+        return operator.apply(solution)

updators/policies/__init__.py → operators/policies/__init__.py


+ 1 - 8
solutions/Solution.py

@@ -10,14 +10,7 @@ class Solution():
         self.data = _data
         self.size = _size
         self.score = None
-    
-
-    def apply(self, _updator):
-        """
-        Apply custom modification of solution and return the transformed solution
-        """
-        return _updator(self)
-
+        
 
     def isValid(self, _validator):
         """

+ 0 - 49
updators/mutators/SimpleMutation.py

@@ -1,49 +0,0 @@
-# main imports
-import random
-import sys
-
-# module imports
-from ...solutions.BinarySolution import BinarySolution
-from ...solutions.Solution import Solution
-
-def SimpleBinaryMutation(solution):
-    size = solution.size
-
-    cell = random.randint(0, size - 1)
-
-    # copy data of solution
-    currentData = solution.data.copy()
-
-    # swicth values
-    if currentData[cell]:
-        currentData[cell] = 0
-    else:
-        currentData[cell] = 1
-
-    # create solution of same kind with new data
-    return globals()[type(solution).__name__](currentData, size)
-
-
-def SimpleMutation(solution):
-
-    size = solution.size
-
-    firstCell = 0
-    secondCell = 0
-
-    # copy data of solution
-    currentData = solution.data.copy()
-
-    while firstCell == secondCell:
-        firstCell = random.randint(0, size - 1) 
-        secondCell = random.randint(0, size - 1)
-
-    temp = currentData[firstCell]
-
-    # swicth values
-    currentData[firstCell] = currentData[secondCell]
-    currentData[secondCell] = temp
-    
-    # create solution of same kind with new data
-    return globals()[type(solution).__name__](currentData, size)
-

+ 0 - 13
updators/policies/Policy.py

@@ -1,13 +0,0 @@
-# define policy to choose `updator` function at current iteration
-class Policy():
-
-    # here you can define your statistical variables for choosing next operator to apply
-
-    def __init__(self, _updators):
-        self.updators = _updators
-
-    def apply(self, solution):
-        """
-        Apply specific updator to solution and returns solution
-        """
-        raise NotImplementedError

+ 0 - 17
updators/policies/RandomPolicy.py

@@ -1,17 +0,0 @@
-# main imports
-import random
-
-# module imports
-from .Policy import Policy
-
-class RandomPolicy(Policy):
-
-    def apply(self, solution):  
-
-        # TODO : implement for mutator (need two parameters)
-
-        # choose updator randomly
-        index = random.randint(0, len(self.updators) - 1)
-        updator = self.updators[index]
-        
-        return solution.apply(updator)