mirror of
https://github.com/deepmodeling/Uni-Lab-OS
synced 2026-05-24 20:29:57 +00:00
feat(layout_optimizer): DE optimizer V2 — custom loop, graduated hard constraints, broad phase
Replace scipy differential_evolution with custom DE loop for per-device crossover, circular θ wrapping, and configurable mutation strategy (currenttobest1bin default, best1bin as turbo mode). Key improvements: - Graduate ALL hard constraints during DE (proportional penalty instead of flat inf), giving DE smooth gradient for reachability, min_spacing, etc. Binary inf preserved for final pass/fail reporting. - 2-axis sweep-and-prune AABB broad phase for collision pair pruning - Multi-seed injection from multiple seeder presets + Gaussian variants - snap_theta_safe: collision-check after angle snapping, revert on violation - Weight normalization (100 distance / 60 angle / 5× hard multiplier) - Constraint priority field (critical/high/normal/low → weight multiplier) with LLM intent interpreter setting priority per constraint type - Final success field now checks user hard constraints in binary mode - arm_slider added to mock checker reach table (1.07m) Tests: 202 passed, 24 new tests added (optimizer 7, constraints 6, broad_phase 11) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -41,6 +41,7 @@ def _handle_reachable_by(intent: Intent, result: InterpretResult) -> None:
|
||||
type="hard",
|
||||
rule_name="reachability",
|
||||
params={"arm_id": arm, "target_device_id": target},
|
||||
priority="critical",
|
||||
)
|
||||
result.constraints.append(c)
|
||||
generated.append({"type": c.type, "rule_name": c.rule_name, "params": c.params, "weight": c.weight})
|
||||
@@ -64,6 +65,8 @@ def _handle_close_together(intent: Intent, result: InterpretResult) -> None:
|
||||
return
|
||||
|
||||
weight = _PRIORITY_WEIGHTS.get(priority, _DEFAULT_WEIGHT)
|
||||
# 映射 intent priority 到 constraint priority 等级
|
||||
constraint_priority = "high" if priority == "high" else "normal"
|
||||
generated: list[dict] = []
|
||||
for dev_a, dev_b in itertools.combinations(devices, 2):
|
||||
c = Constraint(
|
||||
@@ -71,6 +74,7 @@ def _handle_close_together(intent: Intent, result: InterpretResult) -> None:
|
||||
rule_name="minimize_distance",
|
||||
params={"device_a": dev_a, "device_b": dev_b},
|
||||
weight=weight,
|
||||
priority=constraint_priority,
|
||||
)
|
||||
result.constraints.append(c)
|
||||
generated.append({"type": c.type, "rule_name": c.rule_name, "params": c.params, "weight": c.weight})
|
||||
@@ -94,6 +98,8 @@ def _handle_far_apart(intent: Intent, result: InterpretResult) -> None:
|
||||
return
|
||||
|
||||
weight = _PRIORITY_WEIGHTS.get(priority, _DEFAULT_WEIGHT)
|
||||
# 映射 intent priority 到 constraint priority 等级
|
||||
constraint_priority = "high" if priority == "high" else "normal"
|
||||
generated: list[dict] = []
|
||||
for dev_a, dev_b in itertools.combinations(devices, 2):
|
||||
c = Constraint(
|
||||
@@ -101,6 +107,7 @@ def _handle_far_apart(intent: Intent, result: InterpretResult) -> None:
|
||||
rule_name="maximize_distance",
|
||||
params={"device_a": dev_a, "device_b": dev_b},
|
||||
weight=weight,
|
||||
priority=constraint_priority,
|
||||
)
|
||||
result.constraints.append(c)
|
||||
generated.append({"type": c.type, "rule_name": c.rule_name, "params": c.params, "weight": c.weight})
|
||||
@@ -131,6 +138,7 @@ def _handle_max_distance(intent: Intent, result: InterpretResult) -> None:
|
||||
type="hard",
|
||||
rule_name="distance_less_than",
|
||||
params={"device_a": device_a, "device_b": device_b, "distance": distance},
|
||||
priority="normal",
|
||||
)
|
||||
result.constraints.append(c)
|
||||
|
||||
@@ -160,6 +168,7 @@ def _handle_min_distance(intent: Intent, result: InterpretResult) -> None:
|
||||
type="hard",
|
||||
rule_name="distance_greater_than",
|
||||
params={"device_a": device_a, "device_b": device_b, "distance": distance},
|
||||
priority="normal",
|
||||
)
|
||||
result.constraints.append(c)
|
||||
|
||||
@@ -180,6 +189,7 @@ def _handle_min_spacing(intent: Intent, result: InterpretResult) -> None:
|
||||
type="hard",
|
||||
rule_name="min_spacing",
|
||||
params={"min_gap": min_gap},
|
||||
priority="high",
|
||||
)
|
||||
result.constraints.append(c)
|
||||
|
||||
@@ -198,6 +208,7 @@ def _handle_face_outward(intent: Intent, result: InterpretResult) -> None:
|
||||
type="soft",
|
||||
rule_name="prefer_orientation_mode",
|
||||
params={"mode": "outward"},
|
||||
priority="low",
|
||||
)
|
||||
result.constraints.append(c)
|
||||
|
||||
@@ -216,6 +227,7 @@ def _handle_face_inward(intent: Intent, result: InterpretResult) -> None:
|
||||
type="soft",
|
||||
rule_name="prefer_orientation_mode",
|
||||
params={"mode": "inward"},
|
||||
priority="low",
|
||||
)
|
||||
result.constraints.append(c)
|
||||
|
||||
@@ -234,6 +246,7 @@ def _handle_align_cardinal(intent: Intent, result: InterpretResult) -> None:
|
||||
type="soft",
|
||||
rule_name="prefer_aligned",
|
||||
params={},
|
||||
priority="low",
|
||||
)
|
||||
result.constraints.append(c)
|
||||
|
||||
@@ -246,6 +259,39 @@ def _handle_align_cardinal(intent: Intent, result: InterpretResult) -> None:
|
||||
})
|
||||
|
||||
|
||||
def _handle_keep_adjacent(intent: Intent, result: InterpretResult) -> None:
|
||||
"""keep_adjacent:两个设备保持相邻(同 close_together 逻辑,支持 priority 映射)。"""
|
||||
devices: list[str] = intent.params.get("devices", [])
|
||||
priority: str = intent.params.get("priority", "medium")
|
||||
|
||||
if len(devices) < 2:
|
||||
result.errors.append(f"keep_adjacent: 参数 'devices' 至少需要 2 个设备,当前 {len(devices)} 个")
|
||||
return
|
||||
|
||||
weight = _PRIORITY_WEIGHTS.get(priority, _DEFAULT_WEIGHT)
|
||||
# 映射 intent priority 到 constraint priority 等级
|
||||
constraint_priority = "high" if priority == "high" else "normal"
|
||||
generated: list[dict] = []
|
||||
for dev_a, dev_b in itertools.combinations(devices, 2):
|
||||
c = Constraint(
|
||||
type="soft",
|
||||
rule_name="minimize_distance",
|
||||
params={"device_a": dev_a, "device_b": dev_b},
|
||||
weight=weight,
|
||||
priority=constraint_priority,
|
||||
)
|
||||
result.constraints.append(c)
|
||||
generated.append({"type": c.type, "rule_name": c.rule_name, "params": c.params, "weight": c.weight})
|
||||
|
||||
result.translations.append({
|
||||
"source_intent": intent.intent,
|
||||
"source_description": intent.description,
|
||||
"source_params": intent.params,
|
||||
"generated_constraints": generated,
|
||||
"explanation": f"设备组 {devices} 应保持相邻(优先级: {priority})",
|
||||
})
|
||||
|
||||
|
||||
def _handle_workflow_hint(intent: Intent, result: InterpretResult) -> None:
|
||||
"""workflow_hint:工作流顺序暗示,相邻步骤设备靠近。"""
|
||||
workflow: str = intent.params.get("workflow", "")
|
||||
@@ -263,6 +309,7 @@ def _handle_workflow_hint(intent: Intent, result: InterpretResult) -> None:
|
||||
type="soft",
|
||||
rule_name="minimize_distance",
|
||||
params={"device_a": dev_a, "device_b": dev_b},
|
||||
priority="normal",
|
||||
)
|
||||
result.constraints.append(c)
|
||||
generated.append({"type": c.type, "rule_name": c.rule_name, "params": c.params, "weight": c.weight})
|
||||
|
||||
Reference in New Issue
Block a user