improve heuristic

This commit is contained in:
Jan Petykiewicz 2026-03-18 20:45:16 -07:00
commit 6ec953b76e
2 changed files with 48 additions and 3 deletions

View file

@ -41,3 +41,4 @@ class CostConfig:
congestion_penalty: float = 10000.0 congestion_penalty: float = 10000.0
bend_penalty: float = 250.0 bend_penalty: float = 250.0
sbend_penalty: float = 500.0 sbend_penalty: float = 500.0
min_bend_radius: float = 50.0

View file

@ -2,6 +2,7 @@ from __future__ import annotations
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import numpy as np
from inire.router.config import CostConfig from inire.router.config import CostConfig
if TYPE_CHECKING: if TYPE_CHECKING:
@ -41,6 +42,7 @@ class CostEvaluator:
congestion_penalty: float = 10000.0, congestion_penalty: float = 10000.0,
bend_penalty: float = 250.0, bend_penalty: float = 250.0,
sbend_penalty: float = 500.0, sbend_penalty: float = 500.0,
min_bend_radius: float = 50.0,
) -> None: ) -> None:
""" """
Initialize the Cost Evaluator. Initialize the Cost Evaluator.
@ -53,6 +55,7 @@ class CostEvaluator:
congestion_penalty: Multiplier for path overlaps in negotiated congestion. congestion_penalty: Multiplier for path overlaps in negotiated congestion.
bend_penalty: Base cost for 90-degree bends. bend_penalty: Base cost for 90-degree bends.
sbend_penalty: Base cost for parametric S-bends. sbend_penalty: Base cost for parametric S-bends.
min_bend_radius: Minimum radius for 90-degree bends (used for alignment heuristic).
""" """
self.collision_engine = collision_engine self.collision_engine = collision_engine
self.danger_map = danger_map self.danger_map = danger_map
@ -62,6 +65,7 @@ class CostEvaluator:
congestion_penalty=congestion_penalty, congestion_penalty=congestion_penalty,
bend_penalty=bend_penalty, bend_penalty=bend_penalty,
sbend_penalty=sbend_penalty, sbend_penalty=sbend_penalty,
min_bend_radius=min_bend_radius,
) )
# Use config values # Use config values
@ -90,10 +94,50 @@ class CostEvaluator:
dy = abs(current.y - target.y) dy = abs(current.y - target.y)
dist = dx + dy dist = dx + dy
bp = self.config.bend_penalty
penalty = 0.0 penalty = 0.0
if abs(current.orientation - target.orientation) > 0.1:
# Needs at least 1 bend # 1. Orientation Difference
penalty += 10.0 + self.config.bend_penalty * 0.1 # diff in degrees, normalized to [0, 360)
diff = abs(current.orientation - target.orientation) % 360
if diff > 0.1:
if abs(diff - 180) < 0.1:
penalty += 2 * bp
else: # 90 or 270 degree rotation
penalty += 1 * bp
# 2. Side Check (Entry half-plane)
target_rad = np.radians(target.orientation)
# Vector from current to target
v_dx = target.x - current.x
v_dy = target.y - current.y
# Projection of current->target onto target orientation vector
# Should be positive if we are on the "entry" side of the port
side_proj = v_dx * np.cos(target_rad) + v_dy * np.sin(target_rad)
# Perpendicular distance to the target's travel line
perp_dist = abs(v_dx * np.sin(target_rad) - v_dy * np.cos(target_rad))
min_radius = self.config.min_bend_radius
if side_proj < -0.1 or (side_proj < min_radius and perp_dist > 0.1):
# Wrong side or too close to turn into port
penalty += 2 * bp
# 3. Traveling Away
curr_rad = np.radians(current.orientation)
# Projection of current->target onto current orientation vector
# Should be positive if we are moving towards the target's general location
move_proj = v_dx * np.cos(curr_rad) + v_dy * np.sin(curr_rad)
if move_proj < -0.1:
# Traveling away from the port
penalty += 2 * bp
# 4. Jog Alignment
# If orientations match, check if we are on the same line (jog alignment)
if diff < 0.1:
if perp_dist > 0.1:
# Same orientation but different jog coordinate needs 2 bends (S-turn)
penalty += 2 * bp
return self.greedy_h_weight * (dist + penalty) return self.greedy_h_weight * (dist + penalty)