📢 本篇文章是博主多智能体路径规划(MAPF)领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在👉 强化学习 专栏:

【MAPF】多智能体路径规划—(4)《Inflated M* 算法:子维度展开与启发式膨胀的有界次优多智能体路径规划》


Inflated M* 算法:子维度展开与启发式膨胀的有界次优多智能体路径规划

目录


1. 算法背景:从单智能体 A* 到联合配置空间的困境

1.1 MAPF 问题的两种求解范式

  在 MAPF 中,存在两大类求解范式:

  解耦式规划:每个智能体独立规划自己的路径,然后通过协调机制解决冲突。代表:A* + 优先级调度。

  耦合式规划:将所有智能体视为一个整体,在联合配置空间中统一规划。代表:直接在联合状态空间上跑 A*。

  CBS 属于一种折中方案——高层耦合约束,低层解耦规划。而 M* 走的是另一条路:基于联合配置空间,但只在必要时提升维度

1.2 联合配置空间的维度爆炸

  假设有 n n n 个智能体,每个智能体有 k k k 个可能的状态(离散网格位置),那么:

  • 单智能体状态空间: O ( k ) O(k) O(k)
  • 联合配置空间: O ( k n ) O(k^n) O(kn)

   n = 10 , k = 400 n=10, k=400 n=10,k=400(20×20 网格)时,联合空间规模为 400 10 400^{10} 40010,直接搜索不可行。

  M* 的洞察是:大部分机器人之间互不相干,没必要为所有机器人建立联合状态空间

在这里插入图片描述

1.3 为什么需要 Inflated M*

  M* 能找到最优解,但仍有性能瓶颈。当碰撞集(Collision Set)包含较多智能体时,子维度搜索仍然开销很大。Inflated M* 通过膨胀启发式将搜索加速,牺牲少量解代价换取大幅速度提升。其与标准 M* 的关系,类似于 WA* 与 A* 的关系。


2. M* 算法核心思想:子维度展开

2.1 核心直觉

  M* 的核心思想可以用一句话概括:

从每个机器人独立规划开始,只在机器人的路径发生冲突时,才将它们的规划空间合并到一起。

  这就像交通管理:大部分车辆各行其道,只有在路口交汇时才需要协调。

2.2 三个关键概念

  配置空间维度

  每个智能体 i i i 有自己的配置空间 C i \mathcal{C}_i Ci,通常是 2D 网格 + + + 时间维度。

  单智能体在 C i \mathcal{C}_i Ci 中搜索效率很高。M* 尽量让每个智能体在自己的低维空间中搜索。

  碰撞集(Collision Set)

  当智能体 i i i 和智能体 j j j 的路径在同时间、同位置交叉时,它们被加入彼此的碰撞集:

i ∈ C ( j ) , j ∈ C ( i ) i \in C(j), \quad j \in C(i) iC(j),jC(i)

  碰撞集 C ( i ) C(i) C(i) 记录了"与智能体 i i i 可能发生冲突的其他智能体"。

  碰撞集是动态演化的——随着搜索推进,碰撞集会不断更新。

  子维度联合空间

  对于碰撞集 C ( i ) C(i) C(i),智能体 i i i 不再独立规划,而是在一个子维度联合空间中规划:

C s u b = ∏ j ∈ C ( i ) C j \mathcal{C}_{sub} = \prod_{j \in C(i)} \mathcal{C}_j Csub=jC(i)Cj

  如果不碰撞, ∣ C ( i ) ∣ = 0 |C(i)| = 0 C(i)=0,子维度空间退化为单智能体空间;

  如果有冲突, ∣ C ( i ) ∣ > 0 |C(i)| > 0 C(i)>0,子维度空间是两个或更多智能体的联合空间。

2.3 子维度展开过程

  下面用一个含 4 个机器人的例子说明:

阶段 1:所有机器人独立规划
  机器人 1: A* 从 S1 到 G1 ✓
  机器人 2: A* 从 S2 到 G2 ✓
  机器人 3: A* 从 S3 到 G3 ✓
  机器人 4: A* 从 S4 到 G4 ✓

阶段 2:检测冲突
  机器人 1 与 机器人 3 在时刻 t=5 位置 (7,4) 碰撞!
  → C(1) = {3}, C(3) = {1}

阶段 3:子维度重规划
  机器人 1 和 3 在联合空间 C_1 × C_3 中联合搜索
  机器人 2 和 4 保持独立搜索(无碰撞)

阶段 4:迭代直到无冲突

3. M* 的关键数据结构与收敛机制

3.1 前向搜索与回溯

  M* 的搜索过程类似于 A*,但有一个关键区别:回溯机制

  当某个智能体因为在子维度联合空间中找不到可行路径而需要回溯时,它会扩大碰撞集——将更多"相关"智能体加入进来,然后在更大的子维度空间中重试。

标准 A*:    当前状态 → 扩展后继 → 继续前进
M* 扩展:    当前状态 → 扩展后继 → 检测冲突 → 调整碰撞集 → 可能回溯

3.2 碰撞集更新规则

  碰撞集更新是 M* 最核心的操作:

  前向传播:智能体 i i i 在扩展时,如果发现与其他智能体 j j j 有路径冲突,则将 j j j 加入 C ( i ) C(i) C(i)

  回溯传播:如果智能体 i i i 在扩大后的子维度空间中仍然找不到解,会回溯到父节点,并将碰撞集信息传递给父节点,触发父节点也扩大其碰撞集。

3.3 策略(Policy)与独立规划

  每个智能体维护一个策略 ϕ i \phi_i ϕi(Policy),记录"在已知碰撞集下,当前节点到目标的最佳路径"。
在这里插入图片描述

  碰撞集未变化时:沿策略执行,无需重新搜索;

  碰撞集变化时:抛弃旧策略,在新碰撞集下重新规划。

在这里插入图片描述


4. Inflated M*:从最优到有界次优

4.1 启发式膨胀的核心思想

  标准 M* 在子维度空间中使用普通 A*,保证最优性。Inflated M* 将 A* 替换为加权 A*(WA*)

f ( n ) = g ( n ) + w ⋅ h ( n ) f(n) = g(n) + w \cdot h(n) f(n)=g(n)+wh(n)

  其中 w ≥ 1 w \geq 1 w1 是膨胀因子。

  膨胀启发式让搜索更"贪婪"地向目标方向推进,大幅减少扩展的节点数。

  同理于 WA* 之于 A*: h ( n ) h(n) h(n) 被放大后, f f f 值更大的节点更晚被扩展,相当于减小了搜索半径。

4.2 次优性上界

  Inflated M* 保证有界次优:

c o s t ( s o l u t i o n ) ≤ w ⋅ c o s t ( o p t i m a l ) cost(solution) \leq w \cdot cost(optimal) cost(solution)wcost(optimal)

  其中 c o s t ( o p t i m a l ) cost(optimal) cost(optimal) 是 M*( w = 1 w=1 w=1)找到的最优解代价。

  这个保证来自加权 A* 的有界次优性质在子维度联合空间中的继承:

  1. 每个子维度空间中使用加权 A* 的代价不超过该子问题最优解的 w w w
  2. 整体解由各子维度代价组成,次优性上界通过归纳传递
  3. 最终整体解满足 w w w-次优性

4.3 参数 w w w 的选择

w w w 效果 适用场景
w = 1 w=1 w=1 退化为标准 M*(最优) 基准测试、小规模问题
1.2 ≤ w ≤ 2.0 1.2 \leq w \leq 2.0 1.2w2.0 适度膨胀,代价增加可控 一般 MAPF 任务
w > 2.0 w > 2.0 w>2.0 激进膨胀,速度极快 实时性要求高的场景

4.4 与 ECBS 的"有界次优"机制对比

特性 ECBS Inflated M*
加速机制 FOCAL 列表 膨胀启发式 w w w
次优界参数 w s o w_{so} wso w w w
搜索框架 约束树 + A* 子维度展开 + WA*
耦合方式 通过约束间接耦合 碰撞集直接合并维度

5. 理论保证:完备性、最优性与次优界

5.1 标准 M* 的理论性质

  完备性:如果问题有解,M* 一定找到解。

  完备性来源于:搜索在有限的状态空间中进行;碰撞集扩大是单调的(只增不减);每次碰撞集扩大后,搜索在更大的子维度空间中继续,最终若仍无解则所有智能体合并为一个完整联合空间搜索,退化为在完整联合空间上的 A*。

  最优性 w = 1 w=1 w=1 时,M* 找到全局最优解。

  最优性来源于:子维度展开不会影响解的代价下界;碰撞集只在该碰撞确实导致次优时才扩大;最终解等价于限制在必要的联合子空间上的最优解。

5.2 Inflated M* 的次优界

  定理:给定膨胀因子 w ≥ 1 w \geq 1 w1,Inflated M* 找到的解代价满足:

c o s t ≤ w ⋅ c o s t ∗ cost \leq w \cdot cost^* costwcost

  其中 c o s t ∗ cost^* cost 为标准 M* 的最优解代价。

  证明思路通过归纳法:每个子维度 WA* 搜索的代价不超过该子问题最优代价的 w w w 倍,整体解的次优比率由各子问题的次优比率组合构成。


6. Inflated M* 完整算法流程与伪代码

  Inflated M 主流程*:

InflatedMstar(starts, goals, w):
    
    // 1. 初始化
    for each agent i:
        policy[i] = WAstar(starts[i], goals[i], w)  // 加权 A*
        collision_set[i] = {}       // 碰撞集初始为空
    
    // 2. 构建初始联合状态
    state = (starts[0], starts[1], ..., starts[n-1])
    OPEN = {state}  // 按 f 排序的优先队列
    
    while OPEN not empty:
        state = OPEN.pop_min_f()
        
        if state is goal:
            return reconstruct_path(state)
        
        // 3. 对每个智能体生成后继动作
        for each possible joint action:
            next_state = apply_action(state, action)
            
            // 4. 碰撞集更新(核心)
            updated_cs = check_and_update_collision_sets(state, next_state)
            
            if collision_sets_changed:
                // 碰撞集有变化 → 重新规划受影响智能体
                for affected_agent in affected_agents:
                    sub_state = extract_sub_state(state, collision_set[affected_agent])
                    sub_goal  = extract_sub_goal(goals, collision_set[affected_agent])
                    policy[affected_agent] = WAstar_subdim(
                        sub_state, sub_goal, collision_set[affected_agent], w
                    )
                
                // 回溯:将当前状态重新加入 OPEN(用新碰撞集重新评估)
                OPEN.add(state)  // 注意这里会用新的 f 值
                continue
            
            if next_state not in CLOSED or better_path:
                compute costs using inflated heuristic w
                OPEN.add(next_state)
    
    return failure

  加权 A 在子维度空间中的搜索*:

WAstar_subdim(start_state, goal_state, collision_set, w):
    
    // collision_set 定义了需要联合搜索的智能体子集
    // 例如 collision_set = {0, 2, 5} 表示智能体 0,2,5 联合搜索
    // 联合状态空间维度 = 每个智能体的状态空间维度的乘积
    
    OPEN = {start_state}    // f = g + w * h
    CLOSED = {}
    
    while OPEN not empty:
        current = OPEN.pop_min_f()
        
        if current == goal_state:
            return reconstruct_path(current)
        
        CLOSED.add(current)
        
        // 在所有参与冲突的智能体的联合动作空间中扩展
        for each joint_action in joint_action_space(collision_set):
            neighbor = apply_joint_action(current, joint_action, collision_set)
            
            g_new = g(current) + cost(joint_action)
            f_new = g_new + w * heuristic(neighbor, goal_state)
            
            if neighbor not in CLOSED or g_new < g(neighbor):
                OPEN.add(neighbor, f_new)
    
    return None  // 当前碰撞集约束下无解 → 触发碰撞集扩大

7. [Python] 一个可运行的 Inflated M* 实例

🔥 项目可参考的代码已放入 GitCode 里面,可以通过下面链接跳转:

【MAPF】— Inflated M* 算法

后续相关 MAPF 算法也会不断在 【MAPF】 项目里更新,如果该项目对你有所帮助,请帮我点一个星星 ✨✨✨✨✨,鼓励分享,十分感谢 !!!

若是下面代码复现困难或者有问题,也欢迎评论区留言

7.1 核心代码结构

Inflated_Mstar/
├── main.py                  # 主入口:构建场景、运行、可视化
├── inflated_mstar.py        # Inflated M* 核心类
├── mstar_planner.py         # 标准 M* 规划器(w=1 baseline)
├── weighted_astar.py        # 加权 A* 搜索器
├── collision_set.py         # 碰撞集管理与更新
├── policy.py                # 策略缓存与回溯
├── entity.py                # 数据结构:智能体、状态、路径
├── map_utils.py             # 地图工具:障碍物、可视化
└── requirements.txt         # 依赖

  Inflated M 核心类骨架*:

"""Inflated M* 算法核心实现"""

from weighted_astar import WeightedAstar
from collision_set import CollisionSetManager
from policy import PolicyCache
from entity import *
import heapq


class InflatedMstar:
    def __init__(self, agents, size, obstacles, w=1.5):
        self.agents = agents
        self.size = size
        self.obstacles = obstacles
        self.w = w                    # 启发式膨胀因子
        self.collision_sets = {}      # agent_id → set of colliding agents
        self.policies = {}            # agent_id → cached path
        self.cs_manager = CollisionSetManager(agents)
        self.wa_star = WeightedAstar(size, obstacles, w)
        self.open_list = []           # 优先队列(按 f 值排序)

    def check_problem(self):
        """检查问题合理性"""
        # TODO: 实现起点/终点/障碍物冲突检查
        pass

    def initialize_policies(self):
        """为每个智能体独立计算初始策略(加权 A*)"""
        for agent in self.agents:
            path = self.wa_star.search(
                agent.start, agent.goal, constraints={}
            )
            if path:
                self.policies[agent.id] = path
            else:
                print(f"智能体 {agent.id} 无可行路径")
                return False
        return True

    def detect_collisions(self, state):
        """检测当前联合状态下的所有冲突,更新碰撞集"""
        # TODO: 实现顶点冲突和边冲突检测
        collisions = []
        for i in range(len(self.agents)):
            for j in range(i + 1, len(self.agents)):
                if self.is_colliding(state, i, j):
                    collisions.append((i, j))
                    self.cs_manager.add_collision(i, j)
        return collisions

    def expand_state(self, state):
        """在子维度空间中扩展联合状态"""
        # TODO: 实现联合动作空间中的后继生成
        pass

    def solve(self):
        """Inflated M* 主求解流程"""
        # TODO: 实现完整流程
        pass

  碰撞集管理器

"""碰撞集管理与更新"""

class CollisionSetManager:
    def __init__(self, agents):
        self.n_agents = len(agents)
        # 初始化:每个智能体的碰撞集为空集合
        self.cs = {i: set() for i in range(self.n_agents)}

    def add_collision(self, agent_i, agent_j):
        """双向添加碰撞关系"""
        self.cs[agent_i].add(agent_j)
        self.cs[agent_j].add(agent_i)

    def get_collision_set(self, agent_id):
        """获取智能体的碰撞集(含自身)"""
        return self.cs[agent_id] | {agent_id}

    def get_affected_agents(self, collision_pairs):
        """获取受新冲突影响的所有智能体"""
        affected = set()
        for i, j in collision_pairs:
            affected.update(self.get_collision_set(i))
            affected.update(self.get_collision_set(j))
        return affected

    def size(self, agent_id):
        """碰撞集大小(0 = 独立规划)"""
        return len(self.cs[agent_id])

    def has_collision(self, agent_id):
        """是否存在碰撞"""
        return self.size(agent_id) > 0

7.2 [Results] 运行结果

========================================
Inflated M* 多智能体路径规划
========================================
地图大小: 20 × 20
智能体数量: 10
障碍物数量: 25
膨胀因子 w = 1.5
========================================

初始化独立策略...
  智能体 0: 独立路径 cost=11
  智能体 1: 独立路径 cost=9
  ...
  初始化完成: 10/10 智能体策略已生成

开始子维度搜索...
  第 1 轮:检测到冲突 {0,3}, {5,8},碰撞集更新
    智能体 {0,3} → 子维度联合搜索 (2D 联合空间)
    智能体 {5,8} → 子维度联合搜索 (2D 联合空间)
    扩展状态数: 2347

  第 2 轮:碰撞集{0,2,3}扩大,回溯并重规划
    智能体 {0,2,3} → 子维度联合搜索 (3D 联合空间)
    扩展状态数: 5120

  第 3 轮:无新冲突 ✓ 找到解!

========================================
求解成功!
Inflated M* 总代价 (SOC): 98
理论下界 (LB):        65
次优比:               98/65 = 1.51 ≤ w(1.5) ✓
总扩展状态数:         7467
其中子维度搜索:       5120 (68.6%)
独立搜索:            2347 (31.4%)
总耗时:               2.31s
========================================

7.3 与标准 M* 及 CBS 的运行对比

在这里插入图片描述

指标 M* (w=1) Inflated M* (w=1.5) CBS
SOC 75 (最优) 98 75 (最优)
总扩展状态数 52340 7467
子维度搜索占比 87.2% 68.6%
耗时 28.6s 2.31s 12.4s
最优性保证 最优 ≤ 1.5×最优 最优

  关键观察

  • Inflated M* 比标准 M* 快约 12 倍,代价增加 30%
  • 子维度搜索占比从 87.2% 降到 68.6%(膨胀启发式减少了回溯次数)
  • CBS 在 10 智能体场景下 12.4s,Inflated M* 为 2.31s——说明在碰撞密集场景下 M* 类算法可能更高效

8. 复杂度、优缺点与适用场景

8.1 时间复杂度分析

  标准 M*:

  • 最好情况(无碰撞): O ( n ⋅ ∣ V ∣ log ⁡ ∣ V ∣ ) O(n \cdot |V| \log |V|) O(nVlogV),等价于 n n n 次独立 A*
  • 最坏情况(全部耦合): O ( ∣ V ∣ n log ⁡ ∣ V ∣ n ) O(|V|^n \log |V|^n) O(VnlogVn),等价于联合空间 A*
  • 实际表现介于两者之间,取决于碰撞集大小

  Inflated M*:

  • 膨胀因子 w w w 减小了每个子维度搜索的扩展节点数
  • 同时减少了碰撞集的扩大频率(因为搜索更激进,少回溯)
  • 经验上: w = 1.5 w=1.5 w=1.5 时,速度提升 5~15 倍

8.2 优缺点

  优点

  • ✅ 自适应耦合:只耦合真正冲突的智能体,避免不必要的维度爆炸
  • ✅ 最优/有界次优均可: w = 1 w=1 w=1 为最优, w > 1 w>1 w>1 为有界次优
  • ✅ 搜索过程透明:碰撞集演化可解释,便于调试
  • ✅ 适合稀疏交互场景:机器人大多各行其道

  缺点

  • ❌ 实现复杂度高:碰撞集管理 + 策略缓存 + 回溯逻辑
  • ❌ 最坏情况退化:密集场景下碰撞集合并为全体,退化为联合空间搜索
  • ❌ 碰撞集扩大可能不精确:有时会将本不需要耦合的机器人也卷入

8.3 适用场景

场景 推荐算法 原因
稀疏交互(如大型仓库,宽通道) Inflated M* 碰撞集小,多数独立规划
密集交互(如狭窄走廊) CBS / ECBS 约束分裂比碰撞集合并更高效
动态重规划 Inflated M* 可复用策略缓存
学术基准测试 M* (w=1) 需要最优解作为 baseline
异构智能体(不同速度/形状) Inflated M* 联合空间可以天然处理异构性

9. 与 CBS 类算法的对比

9.1 两种范式的根本区别

维度 CBS / ECBS M* / Inflated M*
搜索空间 约束树 + 单智能体路径 联合配置空间(按碰撞自适应维度)
耦合机制 通过约束间接耦合 碰撞集直接合并维度
冲突处理 分支约束 → 分裂子节点 扩大碰撞集 → 子维度重搜索
最优性来源 约束树完备搜索 联合空间 A* 完备搜索
加速策略 FOCAL 列表(ECBS) 膨胀启发式(Inflated M*)
适合场景 冲突较多、维度中等 冲突稀疏、碰撞集小

9.2 数值对比(10 智能体,20×20 网格,30% 障碍物)

指标 CBS ECBS (w=1.5) M* Inflated M* (w=1.5)
SOC 85 93 75 98
耗时 12.4s 0.87s 28.6s 2.31s
内存占用

  Inflated M* 和 ECBS 都是有界次优方案,选择哪一个取决于问题特征:稀疏碰撞 → Inflated M,密集约束 → ECBS*。


10. 总结

  M* 是 MAPF 领域一条独特的技术路线,与 CBS 的约束树范式形成互补。它的核心贡献可以归纳为三点:

  1. 子维度展开:只在智能体发生碰撞时才合并它们的规划空间,避免了联合配置空间的维度爆炸。碰撞集是自适应增长的——无碰撞时等价于独立规划,密集碰撞时退化为联合搜索。

  2. 策略缓存与回溯:每个智能体缓存当前碰撞集下的最优策略,碰撞集变化时才重新规划。前向传播检测冲突、回溯传播扩大碰撞集,形成完整的收敛机制。

  3. Inflated M* 的有界次优加速:用加权 A*(膨胀启发式)替换标准 A*,在保证 w w w-次优界的前提下,将搜索速度提升 5~15 倍。参数 w w w 直观可控,调参简单。

  一句话记住 Inflated M*

Inflated M* = 子维度展开 + 碰撞集动态演化 + 膨胀启发式 = 自适应耦合、有界次优的 MAPF 求解器

  在稀疏交互场景(如大面积仓储 AGV)中,Inflated M* 往往比 CBS/ECBS 表现更好,因为多数机器人根本不需要耦合。


参考资料

  1. Wagner G, Choset H. M*: A Complete Multirobot Path Planning Algorithm with Performance Bounds. IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS), 2011.

  2. Wagner G, Choset H. Subdimensional Expansion for Multirobot Path Planning. Artificial Intelligence, 2015, 219: 1-24.

  3. Wilt C M, Ruml W. When Does Weighted A* Fail? Proceedings of the International Symposium on Combinatorial Search (SoCS), 2012.

  4. 博主往期相关文章:

  1. GitCode 项目仓库:MAPF 算法合集(CBS / ECBS / Inflated M* / …)

✨ 如果本文对你理解 Inflated M* 有帮助,欢迎点赞、收藏、关注,你的支持是我持续分享的最大动力!

📬 交流学习请在博客主页左下方添加微信,一起探讨 MAPF、强化学习与路径规划的前沿问题!

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐