diff --git a/GameModel.py b/GameModel.py index b36070f..78630a7 100644 --- a/GameModel.py +++ b/GameModel.py @@ -18,8 +18,10 @@ from data.Order import Order from data.enum.ItemType import ItemType from decision.Action import Action from decision.ActionType import ActionType +from genetic_order.GeneticOrder import GeneticOrder from imageClasification.Classificator import image_classification from pathfinding.PathfinderOnStates import PathFinderOnStates, PathFinderState +from tree.DecisionTree import DecisionTree from util.PathByEnum import PathByEnum from util.PathDefinitions import GridLocation, GridWithWeights @@ -179,8 +181,26 @@ class GameModel(Model): self.recognised_items.append(recognised) if self.phase == Phase.CLIENT_SORTING: - # TODO GENERICS SORTING - sorted(self.orderList, key=lambda x: len(x.items)) + orders: [Order] = self.orderList + tree: DecisionTree = DecisionTree() + + # CLIENT RECOGNITION + orders_with_prio = tree.get_data_good(orders) + + # print("before:" ) + # for i in range(len(orders_with_prio)): + # print("ORDER {}, PRIO: {}".format(orders_with_prio[i].id, orders_with_prio[i].priority)) + + # GENERICS SORTING + genericOrder: GeneticOrder = GeneticOrder(orders_with_prio) + new_orders = genericOrder.get_orders_sorted(orders) + + # print("after:" ) + # for i in range(len(new_orders)): + # print("ORDER {}, PRIO: {}".format(new_orders[i].id, new_orders[i].priority)) + + self.orderList = new_orders + print("FINISHED CLIENT ORDER SORTING") self.phase = Phase.EXECUTION diff --git a/InitialStateFactory.py b/InitialStateFactory.py index a1b61f2..1289f0c 100644 --- a/InitialStateFactory.py +++ b/InitialStateFactory.py @@ -3,6 +3,7 @@ import random from data.Item import Item from data.Order import Order from data.enum.ItemType import ItemType +from data.enum.Priority import Priority from util.ClientParamsFactory import ClientParamsFactory @@ -24,6 +25,38 @@ class InitialStateFactory: return order_list + @staticmethod + def generate_order_list_XD(output_order_list_size: int): + order_list: [Order] = [] + for i in range(output_order_list_size): + order_list.append(InitialStateFactory.__generate_order_XD()) + + return order_list + + @staticmethod + def __generate_order_XD() -> Order: + order_size = random.randint(1, 4) + + items: [Item] = [] + for i in range(order_size): + items.append(InitialStateFactory.__generate_item()) + + time_base = random.randint(8, 20) + final_time = time_base * order_size + + client_params = ClientParamsFactory.get_client_params() + + x = random.randint(0, 3) + type = Priority.LOW + if x == 0: + type = Priority.MEDIUM + elif x == 1: + type = Priority.HIGH + + x = random.randint(20, 300) + + return Order(final_time, items, type, x, client_params) + @staticmethod def __generate_order() -> Order: order_size = random.randint(1, 4) @@ -37,7 +70,7 @@ class InitialStateFactory: client_params = ClientParamsFactory.get_client_params() - return Order(final_time, items, None, client_params) + return Order(final_time, items, Priority.LOW, 0, client_params) @staticmethod def generate_input_sequence(self, input_sequence_size): diff --git a/data/GameConstants.py b/data/GameConstants.py index 81397d2..42bb980 100644 --- a/data/GameConstants.py +++ b/data/GameConstants.py @@ -1,5 +1,7 @@ from typing import Dict +from data.Item import Item +from data.Order import Order from data.enum.ItemType import ItemType from util.PathDefinitions import GridLocation @@ -9,16 +11,10 @@ class GameConstants: self, grid_width: int, grid_height: int, - # delivery_pos: GridLocation, - # order_pos: GridLocation, - # special_positions: Dict[ItemType, GridLocation], walls: [GridLocation], diffTerrain: [GridLocation] ): self.grid_width = grid_width self.grid_height = grid_height - # self.delivery_pos = delivery_pos - # self.order_pos = order_pos - # self.special_positions = special_positions self.walls = walls self.diffTerrain = diffTerrain diff --git a/data/Order.py b/data/Order.py index 7fd9c88..1ed3763 100644 --- a/data/Order.py +++ b/data/Order.py @@ -9,12 +9,18 @@ from data.enum.Priority import Priority class Order: id_counter = count(start=0) - def __init__(self, time: int, items: [Item], priority: Priority, client_params: ClientParams): + def __init__(self, time: int, items: [Item], priority: Priority, sum: int, client_params: ClientParams): self.id = next(self.id_counter) self.time = time self.items: List[Item] = items self.client_params = client_params self.priority = priority + self.sum = sum + + # def sum_items(self, items: [Item]): + # result = 0 + # for i in range(len(items)): + # result += items[i] def __repr__(self) -> str: return "items: {} priority: {}".format(self.items, self.priority) diff --git a/data/enum/GeneticMutationType.py b/data/enum/GeneticMutationType.py new file mode 100644 index 0000000..a34ac2e --- /dev/null +++ b/data/enum/GeneticMutationType.py @@ -0,0 +1,7 @@ +from enum import Enum + + +class GeneticMutationType(Enum): + MUTATION = 1 + CROSS = 2 + REVERSE = 3 diff --git a/decision/State.py b/decision/State.py index 3cd6be8..4f6f65c 100644 --- a/decision/State.py +++ b/decision/State.py @@ -1,6 +1,7 @@ from data.enum.Direction import Direction from data.Item import Item from data.Order import Order +from data.enum.Priority import Priority from decision.ActionType import ActionType from util.PathDefinitions import GridLocation @@ -10,7 +11,7 @@ class State: action_taken: ActionType, forklift_position: GridLocation, forklift_rotation: Direction, - pending_orders: [Order], + pending_orders: [Priority, [Order]], filled_orders: [Order], input_items: [Item] ): diff --git a/decision/test/ForkliftActions.py b/decision/test/ForkliftActions.py new file mode 100644 index 0000000..5c4c883 --- /dev/null +++ b/decision/test/ForkliftActions.py @@ -0,0 +1,9 @@ +from data.GameConstants import GameConstants + + +class ForkliftActions: + + def __init__(self, game: GameConstants, + ) -> None: + self.game = game + diff --git a/genetic_order/GeneticOrder.py b/genetic_order/GeneticOrder.py new file mode 100644 index 0000000..7037a9a --- /dev/null +++ b/genetic_order/GeneticOrder.py @@ -0,0 +1,218 @@ +import itertools +import random + +from data.Order import Order +from data.enum.GeneticMutationType import GeneticMutationType +from data.enum.Priority import Priority + + +class GeneticOrder: + mutation_chance = 10 + reverse_chance = 60 + cross_chance = 5 + + best_fit_special = 50 + best_fit_super_special = 20 + + population_size = 200 + number_of_populations = 1000 + + punish_low = 500 + punish_med = 300 + + punish_sum = 50 + + def __init__(self, orders: [Order]) -> None: + self.orders = orders + + def get_mutation_type(self) -> GeneticMutationType: + x = random.randint(0, self.mutation_chance + self.cross_chance + self.reverse_chance) + + if x < self.mutation_chance: + return GeneticMutationType.MUTATION + + if x > self.mutation_chance + self.cross_chance: + return GeneticMutationType.REVERSE + + return GeneticMutationType.CROSS + + def mutation(self, population: [int]) -> [int]: + x = random.randint(0, len(population) - 1) + y = random.randint(0, len(population) - 1) + while x == y: + y = random.randint(0, len(population) - 1) + + result = population + + pom = population[x] + result[x] = population[y] + result[y] = pom + + if (result[x] == result[y]): + print("PIZDA I CHUJ") + + return result + + def cross(self, population: [int]) -> [int]: + x = random.randint(1, len(population) - 1) + + result = [] + + for i in range(len(population)): + result.append(population[(i + x) % len(population)]) + + return result + + def reverse(self, population: [int]) -> [int]: + x = random.randint(0, len(population)) + y = random.randint(0, len(population) - 1) + while y - x > 2 or x >= y: + x = random.randint(0, len(population)) + y = random.randint(0, len(population) - 1) + + result = [] + # print("X: ", x, " y: ", y) + + for i in range(len(population)): + if x <= i <= y: + new_i = i - x + # print("len:", len(population), " new_i: ", new_i) + result.append(population[y - new_i]) + else: + result.append(population[i]) + + return result + + def generate_first_population(self, k: int) -> [[int]]: + result = [] + + s = range(len(self.orders)) + p = itertools.permutations(s) + while len(result) < k: + n = p.__next__() + if n not in result: + result.append(n) + + return [list(x) for x in result] + + # result = itertools.permutations(range(len(self.orders))) + # + # return [list(x) for x in result] + + def correct_sum(self, last_prio: Priority, last_sum: float, o: Order) -> bool: + if o.priority == last_prio: + return last_sum > o.sum / o.time + return True + + def sum_wrong(self, member: [int]) -> int: + last_high = 0 + last_med = 0 + last_prio = Priority.HIGH + last_sum = 0 + counter = 0 + + for i in range(len(member)): + o: Order = self.orders[member[i]] + if o.priority == Priority.HIGH: + last_high = i + elif o.priority == Priority.MEDIUM: + last_med = i + + if not self.correct_sum(last_prio, last_sum, o): + counter += int(last_sum - (o.sum / o.time)) + last_prio = o.priority + last_sum = o.sum / o.time + + for i in range(last_high): + o: Order = self.orders[member[i]] + if o.priority == Priority.MEDIUM: + counter += self.punish_med + elif o.priority == Priority.LOW: + counter += self.punish_low + + for i in range(last_med): + o: Order = self.orders[member[i]] + if o.priority == Priority.LOW: + counter += self.punish_low + + return counter + + def evaluate(self, member: [int]) -> int: + # result = 0 + # for i in range(len(self.orders) - 1): + # x: Order = self.orders[member[i]] + # y: Order = self.orders[member[i + 1]] + # + # if ((x.priority == Priority.MEDIUM or x.priority == Priority.LOW) and y.priority == Priority.HIGH) or (x.priority == Priority.LOW and y.priority == Priority.MEDIUM): + # result += 30 + # + # if x.sum / x.time < y.sum / y.time: + # result += int(y.sum / y.time) + + # return result + + return self.sum_wrong(member) + + def mutate_population(self, order_population: [[int]]) -> [[int]]: + result = [] + + for i in range(len(order_population)): + member: [int] = order_population[i] + operation: GeneticMutationType = self.get_mutation_type() + + if operation == GeneticMutationType.MUTATION: + member = self.mutation(member) + elif operation == GeneticMutationType.REVERSE: + member = self.reverse(member) + else: + member = self.cross(member) + + result.append(member) + + return result + + def get_next_population(self, population: [[int]]) -> [[int]]: + result = [] + + for i in range(len(population) - self.best_fit_special - self.best_fit_super_special): + result.append(population[i]) + + for i in range(self.best_fit_special): + x = random.randint(0, self.best_fit_special) + result.append(population[x]) + + for i in range(self.best_fit_super_special): + x = random.randint(0, self.best_fit_super_special) + result.append(population[x]) + + return result + + def get_orders_sorted(self, orders: [Order]) -> [Order]: + self.orders = orders + + population: [[int]] = self.generate_first_population(self.population_size) + # print(population) + + population.sort(key=self.evaluate) + best_fit: [int] = population[0] + + for i in range(self.number_of_populations): + # print("population: ", i) + population = self.mutate_population(population) + population.sort(key=self.evaluate) + + if self.evaluate(best_fit) > self.evaluate(population[0]): + best_fit = population[0] + + # population = self.get_next_population(population).sort(key=self.evaluate) + + if self.evaluate(best_fit) < self.evaluate(population[0]): + population[0] = best_fit + + best: [int] = population[0] + result: [Order] = [] + + for i in range(len(best)): + result.append(self.orders[best[i]]) + + return result diff --git a/main.py b/main.py index c72ea9e..c6e2056 100644 --- a/main.py +++ b/main.py @@ -1,3 +1,4 @@ +import math import random from mesa.visualization.ModularVisualization import ModularServer @@ -5,11 +6,16 @@ from mesa.visualization.modules import CanvasGrid from ForkliftAgent import ForkliftAgent from GameModel import GameModel +from InitialStateFactory import InitialStateFactory from PatchAgent import PatchAgent from PatchType import PatchType from PictureVisualizationAgent import PictureVisualizationAgent +from data.Order import Order from data.enum.Direction import Direction from tensorflow import keras + +from data.enum.Priority import Priority +from genetic_order.GeneticOrder import GeneticOrder from util.PathDefinitions import GridWithWeights from visualization.DisplayAttributeElement import DisplayAttributeElement from visualization.DisplayItemListAttribute import DisplayItemListAttributeElement @@ -94,7 +100,69 @@ if __name__ == '__main__': [grid, readyText, provided_itesm, recognised_items, ordersText, fulfilled_orders], "Automatyczny Wózek Widłowy", - dict(width=gridHeight, height=gridWidth, graph=diagram, items=50, orders=3, classificator=model)) + dict(width=gridHeight, height=gridWidth, graph=diagram, items=50, orders=20, classificator=model)) + + # def order_rule(order: Order): + # return order.id + # + # + # punish_low = 500 + # punish_med = 300 + # def sum_wrong(member: [Order]) -> int: + # last_high = 0 + # last_med = 0 + # + # sum_high = 0 + # sum_med = 0 + # sum_low = 0 + # + # counter = 0 + # + # for i in range(len(member)): + # o: Order = member[i] + # if o.priority == Priority.HIGH : + # sum_high += 1 + # last_high = i + # elif o.priority == Priority.MEDIUM: + # sum_med += 1 + # last_med = i + # else: + # sum_low += 1 + # + # for i in range(last_high): + # o: Order = member[i] + # if o.priority == Priority.MEDIUM: + # counter += punish_med + # elif o.priority == Priority.LOW: + # counter += punish_low + # + # for i in range(last_med): + # o: Order = member[i] + # if o.priority == Priority.LOW: + # counter += punish_low + # + # print("sum: high:", sum_high, "med:", sum_med, "low:", sum_low) + # print("last_high:", last_high, "last_med:", last_med, "sum:", counter) + # return counter + # + # orders = InitialStateFactory.generate_order_list_XD(20) + # test: GeneticOrder = GeneticOrder(orders) + # punish_low = test.punish_low + # punish_med = test.punish_med + # + # print("SIEMA before: ") + # sum_wrong(orders) + # for i in orders: + # print("id:", i.id, "priority:", i.priority, "sum/time:", i.sum/i.time) + # # print("id:", i.id, "priority:", i.priority) + # + # newOrders = test.get_orders_sorted(orders) + # + # print("NAURA after:") + # sum_wrong(newOrders) + # for i in newOrders: + # print("id:", i.id, "priority:", i.priority, "sum/time:", i.sum/i.time) + # # print("id:", i.id, "priority:", i.priority) server.port = 8888 server.launch() diff --git a/tree/DecisionTree.py b/tree/DecisionTree.py index bdb6cb7..968aec3 100644 --- a/tree/DecisionTree.py +++ b/tree/DecisionTree.py @@ -1,11 +1,17 @@ import csv +import numpy as np import pandas import sklearn from sklearn import metrics, preprocessing from sklearn.model_selection import train_test_split from sklearn.tree import DecisionTreeClassifier +from InitialStateFactory import InitialStateFactory +from data.ClientParams import ClientParams +from data.Order import Order +from data.enum.CompanySize import CompanySize +from data.enum.Priority import Priority from util.ClientParamsFactory import ClientParamsFactory @@ -58,6 +64,63 @@ class DecisionTree: print("\nDecisionTrees's Accuracy: ", metrics.accuracy_score(y, prediction)) + def get_data_good(self, orders: [Order]) -> [Order]: + + n_array_input = [] + for i in range(len(orders)): + o:Order = orders[i] + cp: ClientParams = o.client_params + pom = [] + + pom.append(cp.payment_delay) + pom.append(cp.payed) + pom.append(cp.net_worth) + pom.append(cp.infuence_rate) + pom.append(cp.is_skarbowka) + pom.append(cp.membership) + pom.append(cp.is_hat) + + size: CompanySize = cp.company_size + if(size == CompanySize.NO): + pom.append(0) + if (size == CompanySize.SMALL): + pom.append(1) + if (size == CompanySize.NORMAL): + pom.append(2) + if (size == CompanySize.BIG): + pom.append(3) + if (size == CompanySize.HUGE): + pom.append(4) + if (size == CompanySize.GIGANTISHE): + pom.append(5) + + + + n_array_input.append(pom) + + n_array = np.array(n_array_input) + # print(n_array) + + # print(n_array[0]) + tree = self.get_decision_tree() + priority = tree.predict(n_array) + + + for i in range(len(orders)): + print(orders[i].priority) + orders[i].priority = priority[i] + + if priority[i] == "LOW": + orders[i].priority = Priority.LOW + if priority[i] == "MEDIUM": + orders[i].priority = Priority.MEDIUM + if priority[i] == "HIGH": + orders[i].priority = Priority.HIGH + + print(orders[i].priority) + + + return orders def get_decision_tree(self) -> DecisionTreeClassifier: @@ -72,15 +135,25 @@ class DecisionTree: X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, train_size=0.8) + # print(len(X_train[0])) + # print(X_train[0]) + drugTree = DecisionTreeClassifier(criterion="entropy", max_depth=4) clf = drugTree.fit(X_train, y_train) predicted = drugTree.predict(X_test) + # print(type(X_test)) + y_test = y_test.to_list() - self.print_logs(X_test, y_test, predicted) + # self.print_logs(X_test, y_test, predicted) - print(sklearn.tree.export_text(clf, feature_names=X_headers)) + # print(sklearn.tree.export_text(clf, feature_names=X_headers)) - return drugTree \ No newline at end of file + return drugTree + + + +# kurwa = DecisionTree() +# kurwa.get_data_good(InitialStateFactory.generate_order_list(50)) \ No newline at end of file