Agent Skills: facility-layout-optimizer

Facility layout optimization skill for material flow minimization and space utilization.

supply-chainID: a5c-ai/babysitter/facility-layout-optimizer

Install this agent skill to your local

pnpm dlx add-skill https://github.com/a5c-ai/babysitter/tree/HEAD/plugins/babysitter/skills/babysit/process/specializations/domains/science/industrial-engineering/skills/facility-layout-optimizer

Skill Files

Browse the full folder contents for facility-layout-optimizer.

Download Skill

Loading file tree…

plugins/babysitter/skills/babysit/process/specializations/domains/science/industrial-engineering/skills/facility-layout-optimizer/SKILL.md

Skill Metadata

Name
facility-layout-optimizer
Description
Facility layout optimization skill for material flow minimization and space utilization.

facility-layout-optimizer

You are facility-layout-optimizer - a specialized skill for optimizing facility layouts to minimize material flow and maximize space utilization.

Overview

This skill enables AI-powered facility layout optimization including:

  • From-To chart analysis
  • Activity relationship diagramming
  • CRAFT and ALDEP algorithm implementation
  • Block layout generation
  • Aisle design and dimensioning
  • Material flow visualization
  • Space requirement calculation
  • Layout alternative evaluation

Capabilities

1. From-To Chart Analysis

import numpy as np
import pandas as pd

def create_from_to_chart(flow_data: list):
    """
    Create From-To chart from material flow data

    flow_data: list of (from_dept, to_dept, flow_volume, cost_per_unit)
    """
    # Get unique departments
    depts = set()
    for from_d, to_d, _, _ in flow_data:
        depts.add(from_d)
        depts.add(to_d)
    depts = sorted(list(depts))

    # Create matrix
    n = len(depts)
    flow_matrix = np.zeros((n, n))
    cost_matrix = np.zeros((n, n))

    dept_idx = {d: i for i, d in enumerate(depts)}

    for from_d, to_d, flow, cost in flow_data:
        i, j = dept_idx[from_d], dept_idx[to_d]
        flow_matrix[i, j] = flow
        cost_matrix[i, j] = cost

    # Calculate weighted flow
    weighted_flow = flow_matrix * cost_matrix

    return {
        "departments": depts,
        "flow_matrix": pd.DataFrame(flow_matrix, index=depts, columns=depts),
        "cost_matrix": pd.DataFrame(cost_matrix, index=depts, columns=depts),
        "weighted_flow": pd.DataFrame(weighted_flow, index=depts, columns=depts),
        "total_flow": flow_matrix.sum(),
        "total_weighted_flow": weighted_flow.sum()
    }

2. Activity Relationship Diagram

from dataclasses import dataclass
from enum import Enum

class Closeness(Enum):
    A = "Absolutely necessary"
    E = "Especially important"
    I = "Important"
    O = "Ordinary"
    U = "Unimportant"
    X = "Undesirable"

@dataclass
class RelationshipEntry:
    dept1: str
    dept2: str
    closeness: Closeness
    reason: str

def create_relationship_chart(relationships: list):
    """
    Create Activity Relationship Chart (REL chart)
    """
    # Extract departments
    depts = set()
    for r in relationships:
        depts.add(r.dept1)
        depts.add(r.dept2)
    depts = sorted(list(depts))

    # Create relationship matrix
    n = len(depts)
    rel_matrix = {}

    for r in relationships:
        key = (r.dept1, r.dept2) if r.dept1 < r.dept2 else (r.dept2, r.dept1)
        rel_matrix[key] = {
            "closeness": r.closeness.name,
            "reason": r.reason
        }

    # Closeness score for layout optimization
    closeness_scores = {
        'A': 64, 'E': 16, 'I': 4, 'O': 1, 'U': 0, 'X': -64
    }

    # Create numeric matrix for algorithms
    score_matrix = np.zeros((n, n))
    dept_idx = {d: i for i, d in enumerate(depts)}

    for (d1, d2), rel in rel_matrix.items():
        i, j = dept_idx[d1], dept_idx[d2]
        score = closeness_scores[rel['closeness']]
        score_matrix[i, j] = score
        score_matrix[j, i] = score

    return {
        "departments": depts,
        "relationships": rel_matrix,
        "score_matrix": pd.DataFrame(score_matrix, index=depts, columns=depts),
        "summary": {
            "total_relationships": len(relationships),
            "A_count": sum(1 for r in relationships if r.closeness == Closeness.A),
            "X_count": sum(1 for r in relationships if r.closeness == Closeness.X)
        }
    }

3. CRAFT Algorithm

def craft_algorithm(initial_layout: np.ndarray, flow_matrix: np.ndarray,
                   distance_matrix_func, max_iterations: int = 100):
    """
    CRAFT (Computerized Relative Allocation of Facilities Technique)

    Improvement algorithm - starts with initial layout and iteratively improves
    """
    n = len(flow_matrix)
    current_layout = initial_layout.copy()

    def calculate_cost(layout, flow, dist_func):
        total_cost = 0
        for i in range(n):
            for j in range(n):
                if i != j:
                    loc_i = np.argwhere(layout == i)[0]
                    loc_j = np.argwhere(layout == j)[0]
                    dist = dist_func(loc_i, loc_j)
                    total_cost += flow[i, j] * dist
        return total_cost

    current_cost = calculate_cost(current_layout, flow_matrix, distance_matrix_func)
    iteration = 0
    improvement_history = [{"iteration": 0, "cost": current_cost}]

    while iteration < max_iterations:
        best_swap = None
        best_cost = current_cost

        # Try all pairwise exchanges
        for i in range(n):
            for j in range(i + 1, n):
                # Swap departments i and j
                test_layout = current_layout.copy()
                pos_i = np.argwhere(test_layout == i)[0]
                pos_j = np.argwhere(test_layout == j)[0]
                test_layout[tuple(pos_i)] = j
                test_layout[tuple(pos_j)] = i

                test_cost = calculate_cost(test_layout, flow_matrix, distance_matrix_func)

                if test_cost < best_cost:
                    best_cost = test_cost
                    best_swap = (i, j)

        if best_swap is None:
            break  # No improvement found

        # Apply best swap
        i, j = best_swap
        pos_i = np.argwhere(current_layout == i)[0]
        pos_j = np.argwhere(current_layout == j)[0]
        current_layout[tuple(pos_i)] = j
        current_layout[tuple(pos_j)] = i
        current_cost = best_cost
        iteration += 1

        improvement_history.append({
            "iteration": iteration,
            "swap": best_swap,
            "cost": current_cost
        })

    return {
        "final_layout": current_layout,
        "final_cost": current_cost,
        "iterations": iteration,
        "improvement_history": improvement_history,
        "improvement_percent": (improvement_history[0]['cost'] - current_cost) /
                              improvement_history[0]['cost'] * 100
    }

4. Block Layout Generation

def generate_block_layout(departments: list, space_requirements: dict,
                         facility_dimensions: tuple, rel_chart: dict):
    """
    Generate block layout from space requirements
    """
    width, height = facility_dimensions
    total_space = width * height

    # Calculate space allocation
    total_required = sum(space_requirements.values())

    layouts = []

    # Simple strip-based layout
    x_pos = 0
    y_pos = 0
    max_height_in_row = 0

    for dept in departments:
        required = space_requirements.get(dept, 100)
        # Calculate block dimensions (roughly square)
        block_width = np.sqrt(required)
        block_height = required / block_width

        if x_pos + block_width > width:
            # Move to next row
            x_pos = 0
            y_pos += max_height_in_row
            max_height_in_row = 0

        layouts.append({
            "department": dept,
            "x": x_pos,
            "y": y_pos,
            "width": block_width,
            "height": block_height,
            "area": required
        })

        x_pos += block_width
        max_height_in_row = max(max_height_in_row, block_height)

    return {
        "blocks": layouts,
        "facility_dimensions": facility_dimensions,
        "total_space_used": sum(b['area'] for b in layouts),
        "utilization": sum(b['area'] for b in layouts) / total_space * 100
    }

5. Layout Evaluation

def evaluate_layout(layout: list, flow_data: dict, rel_chart: dict):
    """
    Evaluate layout quality
    """
    # Calculate centroids
    centroids = {}
    for block in layout:
        centroids[block['department']] = (
            block['x'] + block['width'] / 2,
            block['y'] + block['height'] / 2
        )

    # Calculate total material handling cost
    def euclidean_dist(c1, c2):
        return np.sqrt((c1[0] - c2[0])**2 + (c1[1] - c2[1])**2)

    def rectilinear_dist(c1, c2):
        return abs(c1[0] - c2[0]) + abs(c1[1] - c2[1])

    total_flow_cost = 0
    flow_matrix = flow_data.get('flow_matrix', pd.DataFrame())

    for dept1 in centroids:
        for dept2 in centroids:
            if dept1 != dept2 and dept1 in flow_matrix.index and dept2 in flow_matrix.columns:
                flow = flow_matrix.loc[dept1, dept2]
                dist = rectilinear_dist(centroids[dept1], centroids[dept2])
                total_flow_cost += flow * dist

    # Check relationship satisfaction
    rel_score = 0
    score_matrix = rel_chart.get('score_matrix', pd.DataFrame())

    for dept1 in centroids:
        for dept2 in centroids:
            if dept1 < dept2 and dept1 in score_matrix.index:
                target_score = score_matrix.loc[dept1, dept2]
                dist = rectilinear_dist(centroids[dept1], centroids[dept2])
                # Adjacent if distance < threshold
                is_adjacent = dist < 50  # Threshold
                if target_score > 0 and is_adjacent:
                    rel_score += target_score
                elif target_score < 0 and not is_adjacent:
                    rel_score -= target_score  # Good that they're apart

    # Space utilization
    total_area = max(b['x'] + b['width'] for b in layout) * \
                 max(b['y'] + b['height'] for b in layout)
    used_area = sum(b['area'] for b in layout)

    return {
        "flow_cost": total_flow_cost,
        "relationship_score": rel_score,
        "space_utilization": used_area / total_area * 100,
        "adjacency_satisfaction": rel_score / (len(centroids) * (len(centroids) - 1) / 2),
        "metrics": {
            "total_departments": len(layout),
            "total_area": total_area,
            "used_area": used_area
        }
    }

6. Aisle Design

def design_aisles(layout: list, traffic_data: dict):
    """
    Design aisle system for layout
    """
    aisles = []

    # Main aisle (runs length of facility)
    main_width = traffic_data.get('main_aisle_width', 12)  # feet
    aisles.append({
        "type": "main",
        "width": main_width,
        "orientation": "horizontal",
        "y_position": max(b['y'] + b['height'] for b in layout) / 2
    })

    # Cross aisles
    cross_width = traffic_data.get('cross_aisle_width', 8)
    num_cross = traffic_data.get('num_cross_aisles', 2)
    facility_width = max(b['x'] + b['width'] for b in layout)

    for i in range(num_cross):
        aisles.append({
            "type": "cross",
            "width": cross_width,
            "orientation": "vertical",
            "x_position": facility_width * (i + 1) / (num_cross + 1)
        })

    # Calculate aisle area
    main_length = facility_width
    cross_length = max(b['y'] + b['height'] for b in layout)

    total_aisle_area = (main_width * main_length +
                       num_cross * cross_width * cross_length)

    return {
        "aisles": aisles,
        "total_aisle_area": total_aisle_area,
        "aisle_percentage": total_aisle_area /
                           (facility_width * cross_length) * 100
    }

Process Integration

This skill integrates with the following processes:

  • warehouse-layout-slotting-optimization.js
  • workstation-design-optimization.js

Output Format

{
  "layout": {
    "blocks": [
      {"department": "Receiving", "x": 0, "y": 0, "width": 50, "height": 40},
      {"department": "Storage", "x": 50, "y": 0, "width": 100, "height": 60}
    ]
  },
  "evaluation": {
    "flow_cost": 15420,
    "relationship_score": 85,
    "space_utilization": 78
  },
  "aisles": {
    "total_area": 1200,
    "percentage": 12
  },
  "recommendations": [
    "Swap Shipping and QC to reduce material handling"
  ]
}

Best Practices

  1. Start with relationships - Define closeness requirements
  2. Quantify flows - Use actual material handling data
  3. Consider expansion - Plan for growth
  4. Safety first - Emergency egress, hazard separation
  5. Validate with users - Operations input essential
  6. Compare alternatives - Evaluate multiple options

Constraints

  • Fixed building constraints
  • Column locations
  • Utility access points
  • Building codes and regulations
  • Budget limitations