[AI] 优先级LRTA*搜索算法 Prioritized-LRTA*

一、算法原理

原文点这儿!

优先级扫描(Prioritized Sweeping)是一种用于强化学习问题的算法,它根据优先级排序的状态更新执行异步动态规划(Moore & Atkeson 1993) 1。如果一个状态的值函数有很大的潜在变化,则它具有很高的优先级。为了保持算法的实时保证,每个计划阶段都可以进行最多的β更新,并且只有潜在更新大于的状态才会被添加到队列中。优先级扫描被证明比q-学习和Dyna-PI更有经验效率(Moore & Atkeson 1993)。

上边是原文翻译过来的,主要就是说这个算法是按优先级给节点进行更新的,这个节点的值潜在变化越大优先级就越高,“潜在变化: Δ \Delta Δ” 在下文程序二中给出了具体的计算方式。

下边才到了算法重点哈,下文的结构是先笼统讲一下P-LRTA*算法的流程,流程中用到的具体的三个函数伪代码将在流程下边进行详细介绍:

P-LRTA*(Prioritized简称P-)分为两个阶段,一个是规划阶段(planning phase),一个是动作阶段(action phase),我把具体操作步骤加粗了,未加粗的是各种算法特性之类的。

  • 规划阶段

    • P-LRTA*仅通过考虑邻近节点来更新当前节点(函数2:StateUpdate(s)),然后把已更新状态的节点的近邻节点加入队列,优先级是根据 Δ \Delta Δ 的大小。
    • 如果队列满了,就把队列中优先级低的移走(函数3:AddToQueue(s, Δ \Delta Δ))。
    • P-LRTA* 和 LRTA* 一样不需要地图的初始信息,并且对不可见区域采用自由空间假设。
    • 当队列大小为0时,P-LRTA等同于LRTA
    • 队列有明确的大小,这也严格保证了有限内存的使用。
    • 当更新完当前节点的 h 值后,开始优先级更新
    • 从队列顶部取最多 PS_MAX_UPDATE 个节点并使用函数1:Prioritized-LRTA(s) 进行更新
    • 那些队列中没取完的节点下个规划阶段再用,这也产生了一个不连续的搜索空间,但这是有益的,因为改变单个状态的启发式值可能会影响许多可能是遥远的状态的启发式值
  • 动作阶段

    • Agent 从 s 节点移动到拥有最小 f ( s , s ′ ) f(s, s') f(s,s) 的 s’ 节点, 其中 f ( s , s ′ ) = c ( s , s ′ ) + h ( s ′ ) f(s, s')=c(s, s')+h(s') f(s,s)=c(s,s)+h(s) c ( s , s ′ ) c(s, s') c(s,s)是节点s和s‘ 直接的距离,h(s’)是节点s’的启发式值。

下面介绍下用到的三个函数:

  • 函数 1
    在这里插入图片描述

函数1应该是主体函数了,输入就是 节点s,先判断s是不是目标节点,如果不是,就进入循环,先调用函数2更新当前节点的 h 值,然后它有个最大更新数,前面提到了,主要没超过这个更新次数并且队列里还有节点,就依次取出队列顶部的节点,只要不是目标节点,就更新h值最后向 f 值最小的节点移动。 加粗部分对应上边加粗的步骤

  • 函数 2
    在这里插入图片描述
    函数2用于更新节点h值,先判断s是不是目标节点,然后计算最低 f(s, s’),然后计算 Δ \Delta Δ Δ \Delta Δ就是用来衡量优先级的, Δ \Delta Δ越大优先级越高。如果 Δ \Delta Δ大于0,就把节点s的所有临近节点加入队列,然后更新当前节点 s的启发式值 h

  • 函数 3
    在这里插入图片描述
    函数3 用于把节点加入队列,队列要是没满并且节点s不在里面,就加进入,否则,把优先级低的移走,再把s加入

二、举个栗子!

在这里插入图片描述
如上图a所示,有A, B, C, D和Goal五个节点,从最远的D开始,目标是Goal,其启发式值总是为0,每个相邻节点见的移动代价 c = 1,每条路径都是双向的,圈内的值是当前该节点的启发式值 h,上边的方格表示队列。

以下是对该算法的具体应用例子步骤:

  • 首先执行 函数1 Prioritized-LRTA*(D), 更新D,进入StateUpdate(D),计算最小f,f(D, C)=f(D, B)=1+1=2, Δ = 2 − 1 > 0 \Delta=2-1>0 Δ=21>0 , 把 D 的所有临近节点即B, C加入队列,其优先级都是1写在了下标处,更新 h(D)=2,如图b所示

  • 继续运行函数1,此时队列非空,依次置行取出队列顶部节点,先取B,调用StateUpdate(B),f(B, A)=1+1=2, Δ = 2 − 1 = 1 > 0 \Delta=2-1=1>0 Δ=21=1>0,把B相邻节点A,D加入队列,其优先级也都是1,更新h(B)=2, 对C同理,由于A,D已在队列中了,最终结果如图c所示

  • 从队列取出A,最小 f ( A , G o a l ) = 1 + 0 = 1 , f(A,Goal)=1+0=1, f(A,Goal)=1+0=1, Δ = 1 − 1 = 0 \Delta=1-1=0 Δ=11=0,所以h(A)不更新,也不将临近节点加入队列。

  • 从队列取出D,最小 f ( D , B ) = f ( D , C ) = 1 + 2 = 3 , Δ = 3 − 2 = 1 > 0 f(D, B)=f(D,C)=1+2=3, \Delta=3-2=1>0 f(D,B)=f(D,C)=1+2=3,Δ=32=1>0,将B, C加入队列,优先级都是1,更新 h ( D ) = f ( D , B ) = f ( D , C ) = 3 h(D)=f(D, B)=f(D,C)=3 h(D)=f(D,B)=f(D,C)=3, 如图d所示

  • 从队列中取出B,最小 f ( B , A ) = 2 , Δ = 0 f(B, A)=2, \Delta=0 f(B,A)=2,Δ=0,无事发生,C同理

  • 队列空了,跳出循环,找到最小 f ( D , B ) = f ( D , C ) = 1 + 3 = 4 f(D, B)=f(D, C)=1+3=4 f(D,B)=f(D,C)=1+3=4,节点从D移动到B或者C。

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 限制每个状态的扩展不超过一次的带有权值迭代的Anytime repair Astar算法LRTA*)是一个基于Astar算法的增强版本,用于解决路径规划问题。Java是一种面向对象的编程语言,我们可以使用它来实现这种算法。下面是一个简单的实现示例: 首先,我们需要定义一个节点类,用于存储状态和计算节点的代价。 ```java public class Node { private int[] state; private double cost; public Node(int[] state, double cost) { this.state = state; this.cost = cost; } public int[] getState() { return state; } public double getCost() { return cost; } } ``` 接下来,我们需要定义一个LRTAstar类,用于执行算法。 ```java import java.util.*; public class LRTAstar { private static final int MAX_ITERATIONS = 1000; private static final double INFINITY = Double.MAX_VALUE; private int[] startState; private int[] goalState; private Map<Integer, List<Integer>> successors; private Map<Integer, Double> heuristic; private Map<Integer, Double> gValues; public LRTAstar(int[] startState, int[] goalState, Map<Integer, List<Integer>> successors, Map<Integer, Double> heuristic) { this.startState = startState; this.goalState = goalState; this.successors = successors; this.heuristic = heuristic; this.gValues = new HashMap<>(); gValues.put(Arrays.hashCode(startState), 0.0); } public List<Integer> search() { List<Integer> path = new ArrayList<>(); int[] currentState = startState; double gValue = 0.0; int iterations = 0; while (!Arrays.equals(currentState, goalState) && iterations < MAX_ITERATIONS) { List<Integer> nextStates = successors.get(Arrays.hashCode(currentState)); double minValue = INFINITY; int[] nextState = null; for (int state : nextStates) { double value = gValues.getOrDefault(state, INFINITY) + heuristic.getOrDefault(state, INFINITY); if (value < minValue) { minValue = value; nextState = new int[] {state}; } } if (nextState == null) { return null; } path.add(nextState[0]); gValue += heuristic.getOrDefault(Arrays.hashCode(nextState), INFINITY); gValues.put(Arrays.hashCode(currentState), gValue); currentState = nextState; if (!Arrays.equals(currentState, goalState)) { double hValue = heuristic.getOrDefault(Arrays.hashCode(currentState), INFINITY); gValue += hValue; int[] parentState = currentState; double parentGValue = gValues.getOrDefault(Arrays.hashCode(parentState), INFINITY); for (int i = 0; i < MAX_ITERATIONS; i++) { double minValue = INFINITY; nextState = null; for (int state : nextStates) { double value = gValues.getOrDefault(state, INFINITY) + heuristic.getOrDefault(state, INFINITY); if (value < minValue) { minValue = value; nextState = new int[] {state}; } } if (nextState == null) { return null; } double hValue = heuristic.getOrDefault(Arrays.hashCode(nextState), INFINITY); double fValue = minValue + hValue; if (fValue >= parentGValue) { break; } parentState = nextState; parentGValue = gValues.getOrDefault(Arrays.hashCode(parentState), INFINITY); } currentState = parentState; gValue = parentGValue - heuristic.getOrDefault(Arrays.hashCode(currentState), INFINITY); } iterations++; } if (Arrays.equals(currentState, goalState)) { return path; } else { return null; } } } ``` 在LRTAstar类中,我们首先定义了一些常量,例如最大迭代次数和无限大的值。然后,我们定义了一个构造函数,该函数接受起始状态,目标状态,后继状态和启发式函数作为输入,并初始化gValues映射。 接下来,我们定义了一个search方法,该方法执行LRTAstar算法。我们使用一个while循环迭代,直到当前状态等于目标状态或达到最大迭代次数。在每个迭代中,我们首先计算下一个状态的代价,并将其添加到路径中。然后,我们更新gValues映射和当前状态,并检查当前状态是否等于目标状态。如果当前状态不等于目标状态,则我们使用另一个while循环来查找当前状态的最佳邻居,并使用任意时间修复策略来更新路径和gValue。最后,我们递增迭代次数,并返回找到的路径或null。 最后,我们可以使用以下示例代码来测试LRTAstar类。 ```java import java.util.*; public class Main { public static void main(String[] args) { int[] startState = new int[] {0, 0}; int[] goalState = new int[] {3, 3}; Map<Integer, List<Integer>> successors = new HashMap<>(); successors.put(Arrays.hashCode(new int[] {0, 0}), Arrays.asList(Arrays.hashCode(new int[] {1, 0}), Arrays.hashCode(new int[] {0, 1}))); successors.put(Arrays.hashCode(new int[] {1, 0}), Arrays.asList(Arrays.hashCode(new int[] {2, 0}), Arrays.hashCode(new int[] {1, 1}), Arrays.hashCode(new int[] {0, 0}))); successors.put(Arrays.hashCode(new int[] {0, 1}), Arrays.asList(Arrays.hashCode(new int[] {1, 1}), Arrays.hashCode(new int[] {0, 2}), Arrays.hashCode(new int[] {0, 0}))); successors.put(Arrays.hashCode(new int[] {2, 0}), Arrays.asList(Arrays.hashCode(new int[] {3, 0}), Arrays.hashCode(new int[] {2, 1}), Arrays.hashCode(new int[] {1, 0}))); successors.put(Arrays.hashCode(new int[] {1, 1}), Arrays.asList(Arrays.hashCode(new int[] {2, 1}), Arrays.hashCode(new int[] {1, 2}), Arrays.hashCode(new int[] {1, 0}), Arrays.hashCode(new int[] {0, 1}))); successors.put(Arrays.hashCode(new int[] {0, 2}), Arrays.asList(Arrays.hashCode(new int[] {1, 2}), Arrays.hashCode(new int[] {0, 1}))); successors.put(Arrays.hashCode(new int[] {3, 0}), Arrays.asList(Arrays.hashCode(new int[] {2, 0}), Arrays.hashCode(new int[] {3, 1}))); successors.put(Arrays.hashCode(new int[] {2, 1}), Arrays.asList(Arrays.hashCode(new int[] {3, 1}), Arrays.hashCode(new int[] {2, 2}), Arrays.hashCode(new int[] {2, 0}), Arrays.hashCode(new int[] {1, 1}))); successors.put(Arrays.hashCode(new int[] {1, 2}), Arrays.asList(Arrays.hashCode(new int[] {2, 2}), Arrays.hashCode(new int[] {1, 1}), Arrays.hashCode(new int[] {0, 2}))); successors.put(Arrays.hashCode(new int[] {3, 1}), Arrays.asList(Arrays.hashCode(new int[] {2, 1}), Arrays.hashCode(new int[] {3, 2}), Arrays.hashCode(new int[] {3, 0}))); successors.put(Arrays.hashCode(new int[] {2, 2}), Arrays.asList(Arrays.hashCode(new int[] {3, 2}), Arrays.hashCode(new int[] {2, 1}), Arrays.hashCode(new int[] {1, 2}))); successors.put(Arrays.hashCode(new int[] {3, 2}), Arrays.asList(Arrays.hashCode(new int[] {2, 2}), Arrays.hashCode(new int[] {3, 1}))); Map<Integer, Double> heuristic = new HashMap<>(); heuristic.put(Arrays.hashCode(new int[] {0, 0}), 6.0); heuristic.put(Arrays.hashCode(new int[] {1, 0}), 5.0); heuristic.put(Arrays.hashCode(new int[] {0, 1}), 5.0); heuristic.put(Arrays.hashCode(new int[] {2, 0}), 4.0); heuristic.put(Arrays.hashCode(new int[] {1, 1}), 3.0); heuristic.put(Arrays.hashCode(new int[] {0, 2}), 4.0); heuristic.put(Arrays.hashCode(new int[] {3, 0}), 3.0); heuristic.put(Arrays.hashCode(new int[] {2, 1}), 2.0); heuristic.put(Arrays.hashCode(new int[] {1, 2}), 2.0); heuristic.put(Arrays.hashCode(new int[] {3, 1}), 2.0); heuristic.put(Arrays.hashCode(new int[] {2, 2}), 1.0); heuristic.put(Arrays.hashCode(new int[] {3, 2}), 0.0); LRTAstar lrtaStar = new LRTAstar(startState, goalState, successors, heuristic); List<Integer> path = lrtaStar.search(); if (path != null) { for (int state : path) { System.out.println(Arrays.toString(NodeUtils.getState(state))); } } else { System.out.println("No path found."); } } } ``` 在这个示例中,我们定义了一个简单的4x4网格世界,并使用它来测试LRTAstar算法。我们定义了起始状态,目标状态,后继状态和启发式函数,并创建一个LRTAstar对象。然后,我们调用search方法来执行算法并打印找到的路径。在这个例子中,输出应该是: ``` [0, 1] [0, 2] [1, 2] [2, 2] [3, 2] [3, 3] ``` 这表明从起始状态到目标状态的最佳路径是[0, 1], [0, 2], [1, 2], [2, 2], [3, 2], [3, 3]。 ### 回答2: Anytime repair A*算法是一种启发式搜索算法,用于解决图搜索问题,它在处理大规模问题时能得到较好的效果。迭代意味着算法可以在有限的时间内进行多次迭代,每次迭代都会得到一个更好的解决方案。而限制每个状态的扩展不超过一次可以减少算法运行的时间和空间复杂度。 使用Java语言实现限制每个状态的扩展不超过一次的带有权值迭代的Anytime repair A*算法,可以按照以下步骤进行: 1. 定义搜索问题的状态表示和目标状态。 2. 定义启发函数,用来估计每个状态到目标状态的代价。 3. 创建一个优先队列,用来存储待扩展的状态。状态的优先级由启发函数和已搜索到的代价决定。 4. 创建一个哈希表,用来保存已扩展的状态及其对应的代价。 5. 初始化起始状态,并将其加入到优先队列和哈希表中。 6. 进入迭代循环,直到达到停止条件(例如达到一定的时间限制或找到满足目标的解决方案): a. 从优先队列中取出优先级最高的状态。 b. 检查该状态是否已经被扩展过,如果是则跳过。 c. 若未扩展过,将该状态标记为已扩展,并将其相邻的状态加入到优先队列中。 d. 如果优先队列不为空,返回步骤a继续迭代;否则表示无解或达到停止条件。 7. 根据需要返回结果(例如返回搜索到的最优解)。 其中,限制每个状态的扩展不超过一次的核心思想是通过哈希表来记录已扩展的状态,以避免重复扩展相同的状态。 此外,带有权值迭代的Anytime repair A*算法还可以通过设置不同的权值来调整搜索的策略,以获得更好的性能和解决方案。 以上是用Java实现限制每个状态的扩展不超过一次的带有权值迭代的Anytime repair A*算法的简要步骤和思路。具体的实现代码可以根据具体问题进行进一步细化和调整。 ### 回答3: 限制每个状态的扩展不超过一次的带有权值迭代的Anytime repair Astar算法可以用Java语言实现。 首先,我们需要定义一个类来表示搜索状态,包括状态的值、权值、父状态和估计代价等信息。该类可以命名为Node。 然后,我们需要实现一个优先级队列来存储Open列表中的节点。Java中的PriorityQueue类可以满足此要求,我们可以根据节点的估计代价设定优先级。 接下来,我们可以实现算法的核心部分——Anytime repair Astar算法的主体函数。在函数中,我们首先需要创建Open和Closed列表,并将初始状态加入Open列表。然后,进入一个循环,直到找到解或者Open列表为空。 在每次循环中,我们从Open列表中选择估计代价最小的节点进行扩展。根据限制条件,我们仅对当前最优节点进行扩展一次。当扩展一个节点时,我们需要生成其所有邻居节点,并计算它们的权值和估计代价。对于已经在Closed列表中的节点,我们可以直接跳过。对于新生成的节点,我们将其加入Open列表。 当找到解时,我们可以回溯路径并输出结果。如果Open列表为空,则意味着无解。 最后,我们可以实现主函数,读取输入和调用主体函数进行搜索。在主函数中,我们可以设定限制条件,并设定权值的迭代次数。随着迭代次数的增加,我们可以逐渐优化搜索效果。 以上就是用Java实现限制每个状态的扩展不超过一次的带有权值迭代的Anytime repair Astar算法的基本思路和步骤。根据具体需求,我们还可以对算法进行更加详细和精细的实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是土豆大叔啊!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值