Beispiel #1
0
    class GeneralInfoMatrix(NodeBase):
        """Used to save matrix, and provide matrix accessor"""

        # distribution of full from port to port
        full_on_ports = NodeAttribute("i", slot_num=port_num * port_num)
        # distribution of full from vessel to port
        full_on_vessels = NodeAttribute("i", slot_num=vessel_num * port_num)
        # planed route info for vessels
        vessel_plans = NodeAttribute("i", slot_num=vessel_num * port_num)

        def __init__(self):
            # we cannot create matrix accessor here, since the attributes will be bind after frame setup,
            self._acc_dict = {}
            self._acc_dict["full_on_ports"] = MatrixAttributeAccessor(
                self, "full_on_ports", port_num, port_num)
            self._acc_dict["full_on_vessels"] = MatrixAttributeAccessor(
                self, "full_on_vessels", vessel_num, port_num)
            self._acc_dict["vessel_plans"] = MatrixAttributeAccessor(
                self, "vessel_plans", vessel_num, port_num)

        def __getitem__(self, key):
            if key in self._acc_dict:
                return self._acc_dict[key]

            return None
Beispiel #2
0
class DataCenter(NodeBase):
    """Cluster node definition in frame."""
    id = NodeAttribute("i2")
    region_id = NodeAttribute("i2")
    zone_id = NodeAttribute("i2")

    total_machine_num = NodeAttribute("i")
    empty_machine_num = NodeAttribute("i")

    def __init__(self):
        self._id: int = 0
        self._region_id: int = 0
        self._zone_id: int = 0
        self._total_machine_num: int = 0

        self._name: str = ""
        self._cluster_list: List[int] = []

    def set_init_state(self, id: int, region_id: int, zone_id: int,
                       total_machine_num: int):
        """Set initialize state, that will be used after frame reset.

        Args:
            id (int): Region id.
        """
        self._id = id
        self._region_id = region_id
        self._zone_id = zone_id
        self._total_machine_num = total_machine_num

        self.reset()

    def reset(self):
        """Reset to default value."""
        self.id = self._id
        self.region_id = self._region_id
        self.zone_id = self._zone_id
        self.total_machine_num = self._total_machine_num

        self.empty_machine_num = self.total_machine_num

    @property
    def cluster_list(self) -> List[int]:
        return self._cluster_list

    @cluster_list.setter
    def cluster_list(self, cluster_list: List[int]):
        self._cluster_list = cluster_list

    @property
    def name(self) -> str:
        return self._name

    @name.setter
    def name(self, name: str):
        self._name = name
Beispiel #3
0
class Warehouse(NodeBase):
    inventories = NodeAttribute("i", TOTAL_PRODUCT_CATEGORIES)
    shortages = NodeAttribute("i", TOTAL_PRODUCT_CATEGORIES)

    def __init__(self):
        self._init_inventories = [
            100 * (i + 1) for i in range(TOTAL_PRODUCT_CATEGORIES)
        ]
        self._init_shortages = [0] * TOTAL_PRODUCT_CATEGORIES

    def reset(self):
        self.inventories[:] = self._init_inventories
        self.shortages[:] = self._init_shortages
Beispiel #4
0
class DummyNode(NodeBase):
    val = NodeAttribute("i")
Beispiel #5
0
class DynamicNode(NodeBase):
    b1 = NodeAttribute("f")
    b2 = NodeAttribute("d")
Beispiel #6
0
class StaticNode(NodeBase):
    a1 = NodeAttribute("i", 2)
    a2 = NodeAttribute("i2")
    a3 = NodeAttribute("i8")
Beispiel #7
0
class Station(NodeBase):
    """Station node definition in Frame"""

    bikes = NodeAttribute("i")

    # statistics features
    shortage = NodeAttribute("i")
    trip_requirement = NodeAttribute("i")
    fulfillment = NodeAttribute("i")

    capacity = NodeAttribute("i")
    id = NodeAttribute("i")

    # additional features
    weekday = NodeAttribute("i2")
    temperature = NodeAttribute("i2")  # avg temp
    weather = NodeAttribute("i2")  # 0: sunny, 1: rainy, 2: snowy, 3: sleet
    holiday = NodeAttribute("i2")  # 0: holiday, 1: not holiday
    extra_cost = NodeAttribute("i")
    transfer_cost = NodeAttribute("i")
    failed_return = NodeAttribute("i")

    # min bikes between a frame
    min_bikes = NodeAttribute("i")

    def __init__(self):
        self._init_capacity = 0  # internal use for reset
        self._init_bikes = 0  # internal use for reset
        self._id = 0  # original id in data file

    def set_init_state(self, bikes: int, capacity: int, id: int):
        """set initialize state, usually for 1st using"""
        self._init_bikes = bikes
        self._init_capacity = capacity
        self._id = id

        self.reset()

    def reset(self):
        """reset to default value"""
        # when we reset frame, all the value will be set to 0, so we need these lines
        self.capacity = self._init_capacity
        self.bikes = self._init_bikes
        self.min_bikes = self._init_bikes
        self.id = self._id

    def _on_bikes_changed(self, value: int):
        """Update min bikes after bikes changed"""
        cur_min_bikes = self.min_bikes

        self.min_bikes = min(value, cur_min_bikes)
Beispiel #8
0
class Port(NodeBase):
    # The capacity of port for stocking containers.
    capacity = NodeAttribute("i")

    # Empty container volume on the port.
    empty = NodeAttribute("i")

    # Laden container volume on the port.
    full = NodeAttribute("i")

    # Empty containers, which are released to the shipper.
    # After loading cargo, laden containers will return to the port for onboarding.
    on_shipper = NodeAttribute("i")

    # Laden containers, which are delivered to the consignee.
    # After discharging cargo, empty containers will return to the port for reuse.
    on_consignee = NodeAttribute("i")

    # Shortage of empty container at current tick.
    # It happens, when the current empty container inventory of port cannot fulfill order requirements.
    shortage = NodeAttribute("i")

    # Accumulated shortage number to the current tick.
    acc_shortage = NodeAttribute("i")

    # Order booking number of a port at the current tick.
    booking = NodeAttribute("i")

    # Accumulated order booking number of a port to the current tick.
    acc_booking = NodeAttribute("i")

    # Fulfilled order number of a port at the current tick.
    fulfillment = NodeAttribute("i")

    # Accumulated fulfilled order number of a port to the current tick.
    acc_fulfillment = NodeAttribute("i")

    # Cost of transferring container, which also covers loading and discharging cost.
    transfer_cost = NodeAttribute("f")

    def __init__(self):
        self._name = None
        self._capacity = None
        self._empty = None

    @property
    def idx(self) -> int:
        """int: Index of this port.
        """
        return self.index

    @property
    def name(self) -> str:
        """str: Name of this port.
        """
        return self._name

    def set_init_state(self, name: str, capacity: int, empty: int):
        """Set initialize state for port, business engine will use these values to reset
        port at the end of each episode (reset).

        Args:
            name (str): Port name.
            capacity (int): Capacity of this port.
            empty (int): Default empty number on this port.
        """
        self._name = name
        self._capacity = capacity
        self._empty = empty

        self.reset()

    def reset(self):
        """Reset port state to initializing.

        Note:
            Since frame reset will reset all the nodes' attributes to 0, we need to
            call set_init_state to store correct initial value.
        """
        self.capacity = self._capacity
        self.empty = self._empty

    def _on_shortage_changed(self, value):
        self._update_fulfilment(value, self.booking)

    def _on_booking_changed(self, value):
        self._update_fulfilment(self.shortage, value)

    def _update_fulfilment(self, shortage: int, booking: int):
        # Update fulfillment.

        self.fulfillment = booking - shortage

    def __str__(self):
        return f"<Port index={self.index}, name={self._name}, capacity={self.capacity}, empty={self.empty}>"
Beispiel #9
0
class Station(NodeBase):
    """Station node definition in frame."""

    bikes = NodeAttribute("i")

    # statistics features
    shortage = NodeAttribute("i")
    trip_requirement = NodeAttribute("i")
    fulfillment = NodeAttribute("i")

    capacity = NodeAttribute("i")
    id = NodeAttribute("i")

    # additional features
    weekday = NodeAttribute("i2")

    # avg temp
    temperature = NodeAttribute("i2")

    # 0: sunny, 1: rainy, 2: snowy, 3: sleet
    weather = NodeAttribute("i2")

    # 0: holiday, 1: not holiday
    holiday = NodeAttribute("i2")

    extra_cost = NodeAttribute("i")
    transfer_cost = NodeAttribute("i")
    failed_return = NodeAttribute("i")

    # min bikes between a frame
    min_bikes = NodeAttribute("i")

    def __init__(self):
        # internal use for reset
        self._init_capacity = 0
        # internal use for reset
        self._init_bikes = 0
        # original id in data file
        self._id = 0

    def set_init_state(self, bikes: int, capacity: int, id: int):
        """Set initialize state, that will be used after frame reset.

        Args:
            bikes (int): Total bikes on this station.
            capacity (int): How many bikes this station can hold.
            id (int): Id of this station.
        """
        self._init_bikes = bikes
        self._init_capacity = capacity
        self._id = id

        self.reset()

    def reset(self):
        """Reset to default value."""
        # when we reset frame, all the value will be set to 0, so we need these lines
        self.capacity = self._init_capacity
        self.bikes = self._init_bikes
        self.min_bikes = self._init_bikes
        self.id = self._id

    def _on_bikes_changed(self, value: int):
        """Update min bikes after bikes changed"""
        cur_min_bikes = self.min_bikes

        self.min_bikes = min(value, cur_min_bikes)
Beispiel #10
0
 class TestNode(NodeBase):
     a1 = NodeAttribute("i", 2, is_const=True)
Beispiel #11
0
class DynamicNode(NodeBase):
    b1 = NodeAttribute(AttributeType.Float)
    b2 = NodeAttribute(AttributeType.Double)
Beispiel #12
0
class StaticNode(NodeBase):
    a1 = NodeAttribute("i", 2)
    a2 = NodeAttribute(AttributeType.Short)
    a3 = NodeAttribute(AttributeType.Long)
Beispiel #13
0
class TestNode2(NodeBase):
    b = NodeAttribute("i", 20)
Beispiel #14
0
class TestNode1(NodeBase):
    a = NodeAttribute("i")
    b = NodeAttribute("i")
    c = NodeAttribute("i")
    d = NodeAttribute("i")
    e = NodeAttribute("i", 16)
Beispiel #15
0
class Port(NodeBase):
    # The capacity of port for stocking containers.
    capacity = NodeAttribute("i")

    # Empty container volume on the port.
    empty = NodeAttribute("i")

    # Laden container volume on the port.
    full = NodeAttribute("i")

    # Empty containers, which are released to the shipper.
    # After loading cargo, laden containers will return to the port for onboarding.
    on_shipper = NodeAttribute("i")

    # Laden containers, which are delivered to the consignee.
    # After discharging cargo, empty containers will return to the port for reuse.
    on_consignee = NodeAttribute("i")

    # Shortage of empty container at current tick.
    # It happens, when the current empty container inventory of port cannot fulfill order requirements.
    shortage = NodeAttribute("i")

    # Accumulated shortage number to the current tick.
    acc_shortage = NodeAttribute("i")

    # Order booking number of a port at the current tick.
    booking = NodeAttribute("i")

    # Accumulated order booking number of a port to the current tick.
    acc_booking = NodeAttribute("i")

    # Fulfilled order number of a port at the current tick.
    fulfillment = NodeAttribute("i")

    # Accumulated fulfilled order number of a port to the current tick.
    acc_fulfillment = NodeAttribute("i")

    # Cost of transferring container, which also covers loading and discharging cost.
    transfer_cost = NodeAttribute("f")

    def __init__(self):
        self._name = None
        self._capacity = None
        self._empty = None

    @property
    def idx(self) -> int:
        """
        Index of this port
        """
        return self.index

    @property
    def name(self) -> str:
        """
        Name of this port
        """
        return self._name

    def set_init_state(self, name: str, capacity: int, empty: int):
        self._name = name
        self._capacity = capacity
        self._empty = empty

        self.reset()

    def reset(self):
        self.capacity = self._capacity
        self.empty = self._empty

    def _on_shortage_changed(self, value):
        self._update_fulfilment(value, self.booking)

    def _on_booking_changed(self, value):
        self._update_fulfilment(self.shortage, value)

    def _update_fulfilment(self, shortage: int, booking: int):
        # Update fulfillment.

        self.fulfillment = booking - shortage

    def __str__(self):
        return f"<Port index={self.index}, name={self._name}, capacity={self.capacity}, empty={self.empty}>"
Beispiel #16
0
 class TestNode(NodeBase):
     a1 = NodeAttribute("i", 1, is_list=True)
     a2 = NodeAttribute("i", 2, is_const=True)
     a3 = NodeAttribute("i")
Beispiel #17
0
 class TestNode(NodeBase):
     a1 = NodeAttribute("i", 1, is_list=True)
Beispiel #18
0
class PhysicalMachine(NodeBase):
    """Physical machine node definition in frame."""
    # Initial parameters.
    id = NodeAttribute("i")
    cpu_cores_capacity = NodeAttribute("i2")
    memory_capacity = NodeAttribute("i2")
    # Statistical features.
    cpu_cores_allocated = NodeAttribute("i2")
    memory_allocated = NodeAttribute("i2")

    cpu_utilization = NodeAttribute("f")
    energy_consumption = NodeAttribute("f")

    def __init__(self):
        """Internal use for reset."""
        self._id = 0
        self._init_cpu_cores_capacity = 0
        self._init_memory_capacity = 0
        # PM resource.
        self._live_vms: Set[int] = set()

    def update_cpu_utilization(self,
                               vm: VirtualMachine = None,
                               cpu_utilization: float = None):
        if vm is None and cpu_utilization is None:
            raise Exception(
                f"Wrong calling method {self.update_cpu_utilization.__name__}")

        if vm is not None:
            cpu_utilization = (
                (self.cpu_cores_capacity * self.cpu_utilization +
                 vm.cpu_cores_requirement * vm.cpu_utilization) /
                self.cpu_cores_capacity)

        self.cpu_utilization = round(max(0, cpu_utilization), 2)

    def set_init_state(self, id: int, cpu_cores_capacity: int,
                       memory_capacity: int):
        """Set initialize state, that will be used after frame reset.

        Args:
            id (int): PM id, from 0 to N. N means the amount of PM, which can be set in config.
            cpu_cores_capacity (int): The capacity of cores of the PM, which can be set in config.
            memory_capacity (int): The capacity of memory of the PM, which can be set in config.
        """
        self._id = id
        self._init_cpu_cores_capacity = cpu_cores_capacity
        self._init_memory_capacity = memory_capacity

        self.reset()

    def reset(self):
        """Reset to default value."""
        # When we reset frame, all the value will be set to 0, so we need these lines.
        self.id = self._id
        self.cpu_cores_capacity = self._init_cpu_cores_capacity
        self.memory_capacity = self._init_memory_capacity

        self._live_vms.clear()

        self.cpu_cores_allocated = 0
        self.memory_allocated = 0

        self.cpu_utilization = 0.0
        self.energy_consumption = 0.0

    @property
    def live_vms(self) -> Set[int]:
        return self._live_vms

    def allocate_vms(self, vm_ids: List[int]):
        for vm_id in vm_ids:
            self._live_vms.add(vm_id)

    def deallocate_vms(self, vm_ids: List[int]):
        for vm_id in vm_ids:
            self._live_vms.remove(vm_id)
Beispiel #19
0
 class TestNode(NodeBase):
     a1 = NodeAttribute("i", batch_number)
     a2 = NodeAttribute("i")
Beispiel #20
0
    class Matrices(NodeBase):
        trips_adj = NodeAttribute("i", station_num * station_num)

        def reset(self):
            pass
Beispiel #21
0
class PhysicalMachine(NodeBase):
    """Physical machine node definition in frame."""
    # Initial parameters.
    id = NodeAttribute("i")
    cpu_cores_capacity = NodeAttribute("i2")
    memory_capacity = NodeAttribute("i2")
    pm_type = NodeAttribute("i2")
    # Statistical features.
    cpu_cores_allocated = NodeAttribute("i2")
    memory_allocated = NodeAttribute("i2")

    cpu_utilization = NodeAttribute("f")
    energy_consumption = NodeAttribute("f")

    # PM type: non-oversubscribable is -1, empty: 0, oversubscribable is 1.
    oversubscribable = NodeAttribute("i2")

    region_id = NodeAttribute("i2")
    zone_id = NodeAttribute("i2")
    data_center_id = NodeAttribute("i2")
    cluster_id = NodeAttribute("i2")
    rack_id = NodeAttribute("i")

    def __init__(self):
        """Internal use for reset."""
        self._id = 0
        self._init_cpu_cores_capacity = 0
        self._init_memory_capacity = 0
        self._init_pm_type = 0
        self._init_pm_state = 0

        self._region_id = 0
        self._zone_id = 0
        self._data_center_id = 0
        self._cluster_id = 0
        self._rack_id = 0

        # PM resource.
        self._live_vms: Set[int] = set()

    def update_cpu_utilization(self,
                               vm: VirtualMachine = None,
                               cpu_utilization: float = None):
        if vm is None and cpu_utilization is None:
            raise Exception(
                f"Wrong calling method {self.update_cpu_utilization.__name__}")

        if vm is not None:
            cpu_utilization = (
                (self.cpu_cores_capacity * self.cpu_utilization +
                 vm.cpu_cores_requirement * vm.cpu_utilization) /
                self.cpu_cores_capacity)

        self.cpu_utilization = round(max(0, cpu_utilization), 2)

    def set_init_state(
        self,
        id: int,
        cpu_cores_capacity: int,
        memory_capacity: int,
        pm_type: int,
        region_id: int,
        zone_id: int,
        data_center_id: int,
        cluster_id: int,
        rack_id: int,
        oversubscribable: PmState = 0,
        idle_energy_consumption: float = 0,
    ):
        """Set initialize state, that will be used after frame reset.

        Args:
            id (int): PM id, from 0 to N. N means the amount of PM, which can be set in config.
            cpu_cores_capacity (int): The capacity of cores of the PM, which can be set in config.
            memory_capacity (int): The capacity of memory of the PM, which can be set in config.
            pm_type (int): The type of the PM.
            region_id (int): The region's id where the PM locates in.
            zone_id (int): The zone's id where the PM locates in.
            data_center_id (int): The data center's id where the PM locates in.
            cluster_id (int): The cluster's id where the PM locates in.
            rack_id (int): The rack's id where the PM locates in.
            oversubscribable (int): The state of the PM:
                                    - non-oversubscribable: -1.
                                    - empty: 0.
                                    - oversubscribable: 1.
        """
        self._id = id
        self._init_cpu_cores_capacity = cpu_cores_capacity
        self._init_memory_capacity = memory_capacity
        self._init_pm_type = pm_type
        self._init_pm_state = oversubscribable

        self._region_id = region_id
        self._zone_id = zone_id
        self._data_center_id = data_center_id
        self._cluster_id = cluster_id
        self._rack_id = rack_id

        self._idle_energy_consumption = idle_energy_consumption

        self.reset()

    def reset(self):
        """Reset to default value.

        Note:
            Since frame reset will reset all the node's attributes to 0, we need to
            call set_init_state to store correct initial value.
        """
        # When we reset frame, all the value will be set to 0, so we need these lines.
        self.id = self._id
        self.cpu_cores_capacity = self._init_cpu_cores_capacity
        self.memory_capacity = self._init_memory_capacity
        self.pm_type = self._init_pm_type
        self.oversubscribable = self._init_pm_state

        self.region_id = self._region_id
        self.zone_id = self._zone_id
        self.data_center_id = self._data_center_id
        self.cluster_id = self._cluster_id
        self.rack_id = self._rack_id

        self._live_vms.clear()

        self.cpu_cores_allocated = 0
        self.memory_allocated = 0

        self.cpu_utilization = 0.0
        self.energy_consumption = self._idle_energy_consumption

    @property
    def live_vms(self) -> Set[int]:
        return self._live_vms

    def allocate_vms(self, vm_ids: List[int]):
        for vm_id in vm_ids:
            self._live_vms.add(vm_id)

    def deallocate_vms(self, vm_ids: List[int]):
        for vm_id in vm_ids:
            self._live_vms.remove(vm_id)
Beispiel #22
0
    class Vessel(NodeBase):
        # The capacity of vessel for transferring containers.
        capacity = NodeAttribute("i")

        # Empty container volume on the vessel.
        empty = NodeAttribute("i")

        # Laden container volume on the vessel.
        full = NodeAttribute("i")

        # Remaining space of the vessel.
        remaining_space = NodeAttribute("i")

        # Discharged empty container number for loading laden containers.
        early_discharge = NodeAttribute("i")

        # Which route current vessel belongs to.
        route_idx = NodeAttribute("i")

        # Stop port index in route, it is used to identify where is current vessel.
        # last_loc_idx == next_loc_idx means vessel parking at a port.
        last_loc_idx = NodeAttribute("i")
        next_loc_idx = NodeAttribute("i")

        past_stop_list = NodeAttribute("i", stop_nums[0])
        past_stop_tick_list = NodeAttribute("i", stop_nums[0])
        future_stop_list = NodeAttribute("i", stop_nums[1])
        future_stop_tick_list = NodeAttribute("i", stop_nums[1])

        def __init__(self):
            self._name = None
            self._capacity = None
            self._total_space = None
            self._container_volume = None
            self._route_idx = None
            self._empty = None

        @property
        def name(self) -> str:
            """str: Name of vessel (from config).
            """
            return self._name

        @property
        def idx(self) -> int:
            """int: Index of vessel.
            """
            return self.index

        def set_init_state(self, name: str, container_volume: float,
                           capacity: int, route_idx: int, empty: int):
            """Initialize vessel info that will be used after frame reset.

            Args:
                name (str): Name of vessel.
                container_volume (float): Volume of each container.
                capacity (int): Capacity of this vessel.
                route_idx (int): The index of the route that this vessel belongs to.
                empty (int): Initial empty number of this vessel.
            """
            self._name = name
            self._container_volume = container_volume
            self._total_space = floor(capacity / container_volume)

            self._capacity = capacity
            self._route_idx = route_idx
            self._empty = empty

            self.reset()

        def reset(self):
            """Reset states of vessel."""
            self.capacity = self._capacity
            self.route_idx = self._route_idx
            self.empty = self._empty

        def set_stop_list(self, past_stop_list: list, future_stop_list: list):
            """Set the future stops (configured in config) when the vessel arrive at a port.

            Args:
                past_stop_list (list): List of past stop list tuple.
                future_stop_list (list): List of future stop list tuple.
            """
            # update past and future stop info
            features = [(past_stop_list, self.past_stop_list,
                         self.past_stop_tick_list),
                        (future_stop_list, self.future_stop_list,
                         self.future_stop_tick_list)]

            for feature in features:
                for i, stop in enumerate(feature[0]):
                    tick = stop.arrive_tick if stop is not None else -1
                    port_idx = stop.port_idx if stop is not None else -1

                    feature[1][i] = port_idx
                    feature[2][i] = tick

        def _on_empty_changed(self, value):
            self._update_remaining_space()

        def _on_full_changed(self, value):
            self._update_remaining_space()

        def _update_remaining_space(self):
            self.remaining_space = self._total_space - self.full - self.empty

        def __str__(self):
            return f"<Vessel Index={self.index}, capacity={self.capacity}, empty={self.empty}, full={self.full}>"
Beispiel #23
0
class Cluster(NodeBase):
    """Cluster node definition in frame."""
    id = NodeAttribute("i2")
    region_id = NodeAttribute("i2")
    zone_id = NodeAttribute("i2")
    data_center_id = NodeAttribute("i2")

    # Total number of machines in the cluster.
    total_machine_num = NodeAttribute("i")
    # The number of empty machines in this cluster. A empty machine means that its allocated CPU cores are 0.
    empty_machine_num = NodeAttribute("i")

    def __init__(self):
        self._id: int = 0
        self._region_id: int = 0
        self._zone_id: int = 0
        self._data_center_id: int = 0
        self._total_machine_num: int = 0

        self._cluster_type: str = ""
        self._rack_list: List[int] = []

    def set_init_state(self, id: int, region_id: int, zone_id: int, data_center_id: int, total_machine_num: int):
        """Set initialize state, that will be used after frame reset.

        Args:
            id (int): Region id.
        """
        self._id = id
        self._region_id = region_id
        self._zone_id = zone_id
        self._data_center_id = data_center_id
        self._total_machine_num = total_machine_num

        self.reset()

    def reset(self):
        """Reset to default value."""
        self.id = self._id
        self.region_id = self._region_id
        self.zone_id = self._zone_id
        self.data_center_id = self._data_center_id
        self.total_machine_num = self._total_machine_num

        self.empty_machine_num = self.total_machine_num

    @property
    def rack_list(self) -> List[int]:
        return self._rack_list

    @rack_list.setter
    def rack_list(self, rack_list: List[int]):
        self._rack_list = rack_list

    @property
    def cluster_type(self) -> str:
        return self._cluster_type

    @cluster_type.setter
    def cluster_type(self, cluster_type: str):
        self._cluster_type = cluster_type