From 48fc9c073b516e3726a5988387bd30e50cc17de0 Mon Sep 17 00:00:00 2001 From: Alcides Fonseca Date: Sun, 3 Nov 2024 19:27:35 -0100 Subject: [PATCH] Converted Domino into benchmark --- examples/benchmarks/benchmark_suite.py | 4 +- examples/benchmarks/domino.py | 136 +++++++++++++++++++++ examples/domino.py | 147 ----------------------- examples/dominoRecursive.py | 156 ------------------------- run_examples.sh | 4 +- 5 files changed, 141 insertions(+), 306 deletions(-) create mode 100644 examples/benchmarks/domino.py delete mode 100644 examples/domino.py delete mode 100644 examples/dominoRecursive.py diff --git a/examples/benchmarks/benchmark_suite.py b/examples/benchmarks/benchmark_suite.py index 112c7559..ea72943e 100644 --- a/examples/benchmarks/benchmark_suite.py +++ b/examples/benchmarks/benchmark_suite.py @@ -1,6 +1,7 @@ from examples.benchmarks.classification import ClassificationBenchmark from examples.benchmarks.classification_lexicase import ClassificationLexicaseBenchmark from examples.benchmarks.datasets import get_banknote, get_game_of_life, get_vladislavleva +from examples.benchmarks.domino import DominoBenchmark, blacks, top_target, side_target from examples.benchmarks.game_of_life_vectorial import GameOfLifeVectorialBenchmark from examples.benchmarks.regression import RegressionBenchmark from examples.benchmarks.regression_lexicase import RegressionLexicaseBenchmark @@ -32,6 +33,7 @@ SantaFeBenchmark(map), StringMatchBenchmark(), VectorialGPBenchmark(dataset), + DominoBenchmark(blacks, top_target, side_target), ] @@ -62,5 +64,5 @@ bests = instance.search() best = bests[0] print( - f"Fitness of {best.get_fitness(problem)} by genotype: {best.genotype} with phenotype: {best.get_phenotype()}", + f"Fitness of {best.get_fitness(problem)} for {best.get_phenotype()}", ) diff --git a/examples/benchmarks/domino.py b/examples/benchmarks/domino.py new file mode 100644 index 00000000..90e4a551 --- /dev/null +++ b/examples/benchmarks/domino.py @@ -0,0 +1,136 @@ +from __future__ import annotations +from abc import ABC, abstractmethod +from dataclasses import dataclass +from typing import Annotated + +import numpy as np + + +from examples.benchmarks.benchmark import Benchmark, example_run +from geneticengine.grammar.grammar import extract_grammar +from geneticengine.grammar.grammar import Grammar +from geneticengine.grammar.metahandlers.ints import IntRange +from geneticengine.grammar.metahandlers.lists import ListSizeBetween +from geneticengine.problems import Problem +from geneticengine.problems import SingleObjectiveProblem + +blacks = [ + (0, 6), + (1, 0), + (3, 5), + (4, 1), + (6, 0), +] +top_target = [3, 2, 4, 10, 4, 3, 9] +side_target = [5, 5, 6, 5, 4, 4, 6] + + +class Domino(ABC): + value: int + posX: int + posY: int + + @abstractmethod + def processBoard(self, board: np.ndarray): + pass + + def __str__(self): + return "(" + str(self.posX) + " " + str(self.posY) + ")" + + +@dataclass +class DominoVertical(Domino): + value = 1 + posX: Annotated[int, IntRange(0, 6)] + posY: Annotated[int, IntRange(0, 5)] + + def processBoard(self, board: np.ndarray): + board[self.posY, self.posX] += 1 + board[self.posY + 1, self.posX] += 1 + + +@dataclass +class DominoHorizontal(Domino): + value = 2 + posX: Annotated[int, IntRange(1, 6)] + posY: Annotated[int, IntRange(0, 6)] + + def processBoard(self, board: np.ndarray): + board[self.posY, self.posX] += 1 + board[self.posY, self.posX - 1] += 1 + + +@dataclass +class Board: + + dominos: Annotated[list[Domino], ListSizeBetween(22, 22)] + + def __str__(self): + visited = np.zeros((7, 7), dtype=int) + for i in blacks: + visited[i[1], i[0]] = -10 + for i in self.dominos: + visited[i.posY, i.posX] += i.value + result = "\n" + for i in visited: + for j in i: + result += str(j) + " " + result += "\n" + return result + + +class DominoBenchmark(Benchmark): + def __init__(self, blacks, top_target, side_target): + self.setup_problem(blacks, top_target, side_target) + self.setup_grammar() + + def setup_problem(self, blacks, top_target, side_target): + + # Problem + def fitness_function(b: Board): + board = np.zeros((7, 7)) + temp_target = np.zeros((2, 7)) + # penalty for overlap + p_overlap = 1 + # penalty for overlap black squares + p_black = 10000 + # penalty for miss the target number + p_target = 1 + # penalty for not visited a empty squares + p_not_visited = 1 + for blackX, blackY in blacks: + board[blackY, blackX] = p_black + for i in b.dominos: + i.processBoard(board) + temp_target[0, i.posX] += i.value + temp_target[1, i.posY] += i.value + r_p_top_target = [ + p_target * ((2.0 - ((abs(temp_target[0, a] - top_target[a])) / top_target[a])) % 2) for a in range(7) + ] + r_p_side_target = [ + p_target * ((2.0 - ((abs(temp_target[1, a] - side_target[a])) / side_target[a])) % 2) for a in range(7) + ] + r_p_board = [ + ( + elem + if elem > p_black + else 0 if elem == p_black else p_not_visited if elem == 0 else (elem - 1) * p_overlap + ) + for elem in board.flatten() + ] + return sum(r_p_top_target) + sum(r_p_side_target) + sum(r_p_board) + + self.problem = SingleObjectiveProblem(minimize=True, fitness_function=fitness_function, target=0) + + def setup_grammar(self): + self.grammar = extract_grammar([DominoVertical, DominoHorizontal, Domino, Board], Board) + + def get_problem(self) -> Problem: + return self.problem + + def get_grammar(self) -> Grammar: + return self.grammar + + +if __name__ == "__main__": + example_run(DominoBenchmark(blacks, top_target, side_target)) diff --git a/examples/domino.py b/examples/domino.py deleted file mode 100644 index 98884be1..00000000 --- a/examples/domino.py +++ /dev/null @@ -1,147 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from dataclasses import dataclass -from typing import Annotated -import numpy as np - - -from geml.simplegp import SimpleGP -from geneticengine.grammar.grammar import extract_grammar -from geneticengine.grammar.grammar import Grammar -from geneticengine.grammar.metahandlers.ints import IntRange -from geneticengine.grammar.metahandlers.lists import ListSizeBetween - -blacks = [ - (0, 6), - (1, 0), - (3, 5), - (4, 1), - (6, 0), -] -top_target = [3,2,4,10,4,3,9] -side_target = [5,5,6,5,4,4,6] - - - -class Board(ABC): - pass - -class Domino(ABC): - value : int - posX : int - posY : int - - @abstractmethod - def processBoard(self, board:np.ndarray): - pass - - def __str__(self): - return "("+ str(self.posX) +" "+ str(self.posY) +")" - - -#------------------------------------------------------------ -@dataclass -class DominoVertical(Domino): - value = 1 - posX : Annotated[int, IntRange(0, 6)] - posY : Annotated[int, IntRange(0, 5)] - - def processBoard(self, board:np.ndarray): - board[self.posY, self.posX] +=1 - board[self.posY+1, self.posX] +=1 - - -@dataclass -class DominoHorizontal(Domino): - value = 2 - posX : Annotated[int, IntRange(1, 6)] - posY : Annotated[int, IntRange(0, 6)] - - def processBoard(self, board:np.ndarray): - board[self.posY, self.posX] +=1 - board[self.posY, self.posX-1] +=1 - - - -@dataclass -class GeneratedBoard(Board): - - dominos : Annotated[list[Domino], ListSizeBetween(22, 23)] - - def __str__(self): - return str(self.dominos) - -#------------------------------------------------------------------------------ - -def fitness_function(n:GeneratedBoard): - temp_target = np.zeros((2, 7)) - board = np.zeros((7, 7)) - #penalty for overlap - p_overlap = 1 - #penalty for overlap black squares - p_black = 10000 - #penalty for miss the target number - p_target = 1 - #penalty for not visited a empty squares - p_not_visited = 1 - for blackX, blackY in blacks: - board[blackY, blackX] = p_black - for i in n.dominos: - i.processBoard(board) - temp_target[0, i.posX] += i.value - temp_target[1, i.posY] += i.value - r_p_top_target = [p_target * ((2.0-((abs(temp_target[0, a] - top_target[a]))/top_target[a]))%2) for a in range(7)] - r_p_side_target = [p_target * ((2.0-((abs(temp_target[1, a] - side_target[a]))/side_target[a]))%2) for a in range(7)] - r_p_board =[ - elem if elem > p_black - else 0 if elem == p_black - else p_not_visited if elem == 0 - else (elem - 1) * p_overlap - for elem in board.flatten() - ] - return sum(r_p_top_target) + sum(r_p_side_target) + sum(r_p_board) - - -def toboard(board): - visited = np.zeros((7,7), dtype = int) - for i in blacks: - visited[i[1], i[0]] = -10 - for i in board.dominos: - visited[i.posY, i.posX] += i.value - result='\n' - for i in visited: - for j in i: - result += str(j)+" " - result += "\n" - return result - -class DominoMatchBenchmark: - - def get_grammar(self) -> Grammar: - return extract_grammar([GeneratedBoard, DominoHorizontal, DominoVertical], Board) - - def main(self, **args): - g = self.get_grammar() - - alg = SimpleGP( - grammar=g, - minimize=True, - fitness_function=fitness_function, - crossover_probability=0.75, - mutation_probability=0.01, - max_evaluations=10000, - max_depth=20, - max_time=60, - population_size=50, - selection_method=("tournament", 2), - elitism=5, - **args, - ) - best = alg.search() - print( - f"Fitness of {best.get_fitness(alg.get_problem())} by genotype: {toboard(best.genotype)} with phenotype: {toboard(best.get_phenotype())}", - ) - -if __name__ == "__main__": - DominoMatchBenchmark().main(seed=0) diff --git a/examples/dominoRecursive.py b/examples/dominoRecursive.py deleted file mode 100644 index b5d2bf1a..00000000 --- a/examples/dominoRecursive.py +++ /dev/null @@ -1,156 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from dataclasses import dataclass -from typing import Annotated -import numpy as np - - -from geml.simplegp import SimpleGP -from geneticengine.grammar.decorators import weight -from geneticengine.grammar.grammar import extract_grammar -from geneticengine.grammar.grammar import Grammar -from geneticengine.grammar.metahandlers.ints import IntRange - -blacks = [ - (0, 6), - (1, 0), - (3, 5), - (4, 1), - (6, 0), -] -top_target = [3,2,4,10,4,3,9] -side_target = [5,5,6,5,4,4,6] - -class Board(ABC): - pass - -class Domino(ABC): - value : int - posX : int - posY : int - - @abstractmethod - def processBoard(self, board:np.ndarray): - pass - - def __str__(self): - return "("+ str(self.posX) +", "+ str(self.posY) +")" - -@dataclass -class DominoVertical(Domino): - value = 1 - posX : Annotated[int, IntRange(0, 6)] - posY : Annotated[int, IntRange(0, 5)] - - def processBoard(self, board:np.ndarray): - board[self.posY, self.posX] +=1 - board[self.posY+1, self.posX] +=1 - - -@dataclass -class DominoHorizontal(Domino): - value = 2 - posX : Annotated[int, IntRange(1, 6)] - posY : Annotated[int, IntRange(0, 6)] - - def processBoard(self, board:np.ndarray): - board[self.posY, self.posX] +=1 - board[self.posY, self.posX-1] +=1 - -@weight(0.99) -@dataclass -class Add(Board): - current : Domino - next : Board - - def __str__(self): - return str(self.current) +", "+ str(self.next) - -@weight(0.01) -@dataclass -class Stop(Board): - current : Domino - - def __str__(self): - return str(self.current) - -def fitness_function(n:Board): - temp_target = np.zeros((2, 7)) - board = np.zeros((7, 7)) - #penalty for overlap - p_overlap = 5 - #penalty for overlap black squares - p_black = 100000 - #penalty for miss the target number - p_target = 1 - #penalty for not visited a empty squares - p_not_visited = 1 - obj = n - for blackX, blackY in blacks: - board[blackY, blackX] = p_black - while isinstance(obj, Add) or isinstance(obj, Stop): - i = obj.current - i.processBoard(board) - temp_target[0, i.posX] += i.value - temp_target[1, i.posY] += i.value - if isinstance(obj, Stop): - break - obj = obj.next - r_p_top_target = [p_target * ((2.0-((abs(temp_target[0, a] - top_target[a]))/top_target[a]))%2) for a in range(7)] - r_p_side_target = [p_target * ((2.0-((abs(temp_target[1, a] - side_target[a]))/side_target[a]))%2) for a in range(7)] - r_p_board =[ - elem if elem > p_black - else 0 if elem == p_black - else p_not_visited if elem == 0 - else (elem - 1) * p_overlap - for elem in board.flatten() - ] - return sum(r_p_top_target) + sum(r_p_side_target) + sum(r_p_board) - -def toboard(board): - visited = np.zeros((7,7), dtype = int) - for blackX, blackY in blacks: - visited[blackY, blackX] = -10 - obj = board - while True: - i=obj.current - visited[i.posY, i.posX] += i.value - if isinstance(obj, Stop): - break - obj = obj.next - result='\n' - for i in visited: - for j in i: - result += str(j)+" " - result += "\n" - return result - -class DominoMatchBenchmarkRecursive: - - def get_grammar(self) -> Grammar: - return extract_grammar([Add, Stop, DominoHorizontal, DominoVertical], Board) - - def main(self, **args): - g = self.get_grammar() - - alg = SimpleGP( - grammar=g, - minimize=True, - fitness_function=fitness_function, - crossover_probability=0.75, - mutation_probability=0.01, - max_depth=25, - max_evaluations=10000, - population_size=1000, - selection_method=("tournament", 2), - elitism=5, - **args, - ) - best = alg.search() - print( - f"Fitness of {best.get_fitness(alg.get_problem())} by genotype: {toboard(best.genotype)} with phenotype: {toboard(best.get_phenotype())}", - ) - -if __name__ == "__main__": - DominoMatchBenchmarkRecursive().main(seed=0) diff --git a/run_examples.sh b/run_examples.sh index cd4249c4..39134f0e 100755 --- a/run_examples.sh +++ b/run_examples.sh @@ -33,6 +33,7 @@ run_example examples/geml/regressor_example.py run_example examples/benchmarks/classification.py run_example examples/benchmarks/classification_lexicase.py +run_example examples/benchmarks/domino.py run_example examples/benchmarks/game_of_life_vectorial.py run_example examples/benchmarks/pymax.py run_example examples/benchmarks/regression.py @@ -40,8 +41,6 @@ run_example examples/benchmarks/regression_lexicase.py run_example examples/benchmarks/santafe.py run_example examples/benchmarks/string_match.py run_example examples/benchmarks/vectorialgp.py -run_example examples/domino.py -run_example examples/dominoRecursive.py run_example examples/progsys/Number_IO.py @@ -61,3 +60,4 @@ run_example examples/recurrence.py run_example examples/synthetic_grammar_example.py run_example examples/tutorial_example.py run_example examples/logging_example.py +run_example examples/dominoRecursive.py