From 0437c00c03fe66c30dac7981c2fe80029490e931 Mon Sep 17 00:00:00 2001 From: Marvin Kastner Date: Sun, 10 Sep 2023 00:55:57 +0200 Subject: [PATCH] Add helper to reproducible shuffle the containers and schedules --- .../sqlite_database_connection.py | 12 ++++++++++++ ...pace_for_containers_delivered_by_truck_service.py | 3 +-- .../assign_destination_to_container_service.py | 4 ++++ .../large_scheduled_vehicle_creation_service.py | 6 +++++- ...uled_vehicle_for_onward_transportation_manager.py | 2 +- .../truck_for_export_containers_manager.py | 4 ++++ .../truck_for_import_containers_manager.py | 4 ++++ 7 files changed, 31 insertions(+), 4 deletions(-) diff --git a/conflowgen/database_connection/sqlite_database_connection.py b/conflowgen/database_connection/sqlite_database_connection.py index 618c5d62..ca430adf 100644 --- a/conflowgen/database_connection/sqlite_database_connection.py +++ b/conflowgen/database_connection/sqlite_database_connection.py @@ -1,5 +1,6 @@ from __future__ import annotations +import hashlib import logging import os from typing import List, Tuple, Optional @@ -7,6 +8,7 @@ from peewee import SqliteDatabase from conflowgen.application.models.container_flow_generation_properties import ContainerFlowGenerationProperties +from conflowgen.application.repositories.random_seed_store_repository import get_initialised_random_object from conflowgen.database_connection.create_tables import create_tables from conflowgen.domain_models.base_model import database_proxy from conflowgen.domain_models.container import Container @@ -52,6 +54,7 @@ class SqliteDatabaseConnection: ) def __init__(self, sqlite_databases_directory: Optional[str] = None): + self.seeded_random = None if sqlite_databases_directory is None: sqlite_databases_directory = self.SQLITE_DEFAULT_DIR @@ -123,6 +126,15 @@ def choose_database( for vehicle in (DeepSeaVessel, Feeder, Barge, Train, Truck, Container): self.logger.debug(f"Number entries in table '{vehicle.__name__}': {vehicle.select().count()}") + self.seeded_random = get_initialised_random_object(self.__class__.__name__) + randbits = self.seeded_random.getrandbits(100) + + @self.sqlite_db_connection.func('assign_random_value') + def convert_to_random_value(row_id): + h = hashlib.new('sha256') + h.update((randbits + row_id).to_bytes(16, 'big')) + return h.hexdigest() + return self.sqlite_db_connection def delete_database(self, database_name: str) -> None: diff --git a/conflowgen/flow_generator/allocate_space_for_containers_delivered_by_truck_service.py b/conflowgen/flow_generator/allocate_space_for_containers_delivered_by_truck_service.py index 65676001..c506dba8 100644 --- a/conflowgen/flow_generator/allocate_space_for_containers_delivered_by_truck_service.py +++ b/conflowgen/flow_generator/allocate_space_for_containers_delivered_by_truck_service.py @@ -81,8 +81,7 @@ def allocate(self) -> None: successful_assignment = 0 teu_total = 0 - for i in range(number_containers_to_allocate): - i += 1 + for i in range(1, number_containers_to_allocate + 1): if i % 1000 == 0 or i == 1 or i == number_containers_to_allocate: self.logger.info( f"Progress: {i} / {number_containers_to_allocate} ({i / number_containers_to_allocate:.2%}) " diff --git a/conflowgen/flow_generator/assign_destination_to_container_service.py b/conflowgen/flow_generator/assign_destination_to_container_service.py index 5af2aeab..b04e0911 100644 --- a/conflowgen/flow_generator/assign_destination_to_container_service.py +++ b/conflowgen/flow_generator/assign_destination_to_container_service.py @@ -3,6 +3,8 @@ import logging import typing +from peewee import fn + from conflowgen.application.repositories.random_seed_store_repository import get_initialised_random_object from conflowgen.domain_models.container import Container from conflowgen.domain_models.distribution_repositories.container_destination_distribution_repository import \ @@ -55,6 +57,8 @@ def assign(self) -> None: LargeScheduledVehicle, on=Container.picked_up_by_large_scheduled_vehicle ).where( Container.picked_up_by_large_scheduled_vehicle.schedule == schedule + ).order_by( + fn.assign_random_value(Container.id) ) distribution_for_schedule = self.distribution[schedule] destinations = list(distribution_for_schedule.keys()) diff --git a/conflowgen/flow_generator/large_scheduled_vehicle_creation_service.py b/conflowgen/flow_generator/large_scheduled_vehicle_creation_service.py index b1091b01..33ff7d7f 100644 --- a/conflowgen/flow_generator/large_scheduled_vehicle_creation_service.py +++ b/conflowgen/flow_generator/large_scheduled_vehicle_creation_service.py @@ -2,6 +2,8 @@ from typing import List, Type import logging +from peewee import fn + from conflowgen.domain_models.data_types.mode_of_transport import ModeOfTransport from conflowgen.domain_models.factories.container_factory import ContainerFactory from conflowgen.domain_models.factories.fleet_factory import FleetFactory @@ -37,7 +39,9 @@ def reload_properties( def create(self) -> None: assert self.container_flow_start_date is not None assert self.container_flow_end_date is not None - schedules = Schedule.select() + schedules = Schedule.select().orderby( + fn.assign_random_value(Schedule.id) + ) number_schedules = schedules.count() for i, schedule in enumerate(schedules): i += 1 diff --git a/conflowgen/flow_generator/large_scheduled_vehicle_for_onward_transportation_manager.py b/conflowgen/flow_generator/large_scheduled_vehicle_for_onward_transportation_manager.py index 402a3dbc..f0819892 100644 --- a/conflowgen/flow_generator/large_scheduled_vehicle_for_onward_transportation_manager.py +++ b/conflowgen/flow_generator/large_scheduled_vehicle_for_onward_transportation_manager.py @@ -74,7 +74,7 @@ def choose_departing_vehicle_for_containers(self) -> None: # This way no vehicle has an advantage over another by its earlier arrival (getting better slots etc.) selected_containers: ModelSelect = Container.select( ).order_by( - fn.Random() + fn.assign_random_value(Container.id) ).where( (Container.picked_up_by << ModeOfTransport.get_scheduled_vehicles()) & (Container.delivered_by << ModeOfTransport.get_scheduled_vehicles()) diff --git a/conflowgen/flow_generator/truck_for_export_containers_manager.py b/conflowgen/flow_generator/truck_for_export_containers_manager.py index c4e34e3f..53bc0106 100644 --- a/conflowgen/flow_generator/truck_for_export_containers_manager.py +++ b/conflowgen/flow_generator/truck_for_export_containers_manager.py @@ -2,6 +2,8 @@ import datetime from typing import Dict, Optional +from peewee import fn + from .abstract_truck_for_containers_manager import AbstractTruckForContainersManager, \ UnknownDistributionPropertyException from ..domain_models.data_types.container_length import ContainerLength @@ -113,6 +115,8 @@ def generate_trucks_for_delivering(self) -> None: """ containers = Container.select().where( Container.delivered_by == ModeOfTransport.truck + ).order_by( + fn.assign_random_value(Container.id) ) number_containers = containers.count() self.logger.info( diff --git a/conflowgen/flow_generator/truck_for_import_containers_manager.py b/conflowgen/flow_generator/truck_for_import_containers_manager.py index 1de0e6cb..313a2083 100644 --- a/conflowgen/flow_generator/truck_for_import_containers_manager.py +++ b/conflowgen/flow_generator/truck_for_import_containers_manager.py @@ -1,6 +1,8 @@ import datetime from typing import Dict, Optional +from peewee import fn + from .abstract_truck_for_containers_manager import AbstractTruckForContainersManager, \ UnknownDistributionPropertyException from ..domain_models.data_types.container_length import ContainerLength @@ -88,6 +90,8 @@ def _get_container_pickup_time( def generate_trucks_for_picking_up(self): containers = Container.select().where( Container.picked_up_by == ModeOfTransport.truck + ).order_by( + fn.assign_random_value(Container.id) ) number_containers = containers.count() self.logger.info(