hots.plugins.problem.placement

Provide placement heuristics and all placement-related methods.

class hots.plugins.problem.placement.PlacementPlugin(instance)[source]

Bases: ProblemPlugin

Handles the ‘placement’ business problem.

adjust(moving: list[Any], working_df)[source]

Finalize move list by finding new targets and apply moves.

allocation_distant_pairwise(df_indiv: DataFrame, df_host_meta: DataFrame, distance_mat: ndarray, labels: Sequence[Any], lower_bound: float | None = None) list[dict[str, Any]][source]

Place containers by repeatedly pairing the most distant clusters and assigning their items together when possible.

allocation_ffd(df_indiv: DataFrame, df_host_meta: DataFrame, time_horizon: int | None = None) list[dict[str, Any]][source]

First-Fit Decreasing across time-series capacity.

Sort containers by descending peak demand; assign to first host whose remaining timeline supports the entire demand.

allocation_spread(df_indiv: DataFrame, df_host_meta: DataFrame, labels: Series | None = None) list[dict[str, Any]][source]

Greedy spread over the full horizon.

Move one heaviest container off each most-constrained host to the feasible host that maximizes slack after placement. One move per source host.

build_place_adj_matrix(df_indiv: DataFrame, id_map: dict[int, Any]) ndarray[source]

Build adjacency matrix where A[i,j] = 1 if containers i and j share host.

colocalize_clusters(df_indiv: DataFrame, df_host_meta: DataFrame, labels: Series, n_clusters: int) list[dict[str, Any]][source]

Colocalize cluster members using majority-host heuristic.

For each cluster:
  1. Identify the majority host (host with most members of that cluster).

  2. Move minority members to that host if they fit over the full horizon.

Containers are processed in descending peak demand to increase feasibility.

colocalize_clusters_new(df_indiv: DataFrame, df_host_meta: DataFrame, labels: Series, n_clusters: int) list[dict[str, Any]][source]

Compatibility wrapper for the merged colocalize_clusters.

find_substitution(*args, **kwargs) list[dict[str, Any]][source]

Find a beneficial two-way swap between hosts.

initial(labels, df_indiv: DataFrame, df_host: DataFrame) list[dict[str, Any]][source]

From initial labels, get first placement solution.

move_container(inst, container_id, tmin: int, tmax: int, old_id, working_df: DataFrame)[source]

Move container_id to the best node in [tmin, tmax], choosing a feasible candidate (capacity per tick) that minimizes the variance of (node_ts + container_ts). Falls back to opening a new node if needed. Returns a move dict or None.

move_list_containers(instance: Any, working_df, moving: list[int], tmin: int, tmax: int, order: str = 'max') list[dict[str, Any]][source]

Move the list of containers to move.

Process: 1. Remove all moving containers from their nodes first 2. Store their old host IDs 3. Order containers by consumption (max or mean) 4. Reassign each container to best available node

Parameters:
  • instance – Problem instance

  • moving – List of container indices to move

  • tmin – Minimum window time

  • tmax – Maximum window time

  • order – Order to consider (‘max’ or ‘mean’), defaults to ‘max’

Returns:

List of move dicts

place_opposite_clusters(df_indiv: DataFrame, df_host_meta: DataFrame, labels: Series, clusters_to_separate: Sequence[int]) list[dict[str, Any]][source]

Enforce strong separation for a set of ‘opposite’ clusters.

spread_containers(df_indiv: DataFrame, tick: int, *, single_move: bool = False) list[dict[str, Any]][source]

Greedy spread at a single tick.

spread_containers_new(df_indiv: DataFrame, tick: int) list[dict[str, Any]][source]

Single step of spread_containers (kept for compatibility).