LRTA*(Learning-RTA*)

news2025/1/13 15:53:53

1、基本概念

LRTA* 算法是对RTA* 算法的改进,在RTA* 的原论文中,提到了:

Unfortunately, while RTA* as described above is ideally suited to single problem solving trials, it must be modified to accommodate multi-trial learning. The reason is that the algorithm records the second best estimate in the previous state, which represents an accurate estimate of that state looking back from the perspective of the next state.However, if the best estimate turns out to be correct, then storing the second best value can result in inflated values for some states. These inflated values will direct the next agents in the wrong direction on subsequent problem solving trials.

即:

RTA* 算法记录了前一状态下的第二个最佳估计,这代表了从下一状态的角度回顾该状态的准确估计。然而,如果最佳估计被证明是正确的,那么存储第二个最好的值可能会导致某些状态的值被夸大。这些夸大的价值观将引导下一代在随后的问题解决试验中走向错误的方向。

LRTA* 通过记录最优解而不是第二最优解解决了这个问题。LRTA* 算法的核心是对节点的启发式值的更新,启发式值的更新使用启发式函数:
H ( s ) = g ( s , s ′ ) + H ( s ′ ) H(s)=g(s,s^′)+H(s^′) H(s)=g(s,s)+H(s)
其中H(s)表示前一节点的启发式值,g(s, s’)表示从节点s到s‘的代价,H(s’)表示当前节点的启发式值。LRTA*的完整算法如下:

在这里插入图片描述
h(s) 的设计,是为了防止之前A* 算法在搜索时陷入局部最小值,在LRTA* 搜索中,如果陷入了局部最小值,算法会根据访问附近节点的次数增加h(s),即增加总成本f(s),从而经过h(s)的多次叠加后,跳出局部最小值。

h(s) 的更新是这样的:

例如从 s 节点到 s’ 节点,假设路程g(s, s’) = 1,已知 h(s’) = 2(这个初始的时候就是已知的,代表了从该节点到目标节点的距离),那么从 s 节点访问 s’ 节点后,是对s节点的h(s)进行更新的,h(s) = g(s) + h(s’) = 1 + 2 = 3。

另外,如果想从 s’ 再回到 s节点的话,那么就要对 h(s’) 更新,h(s’) = g(s’, s) + h(s) = 1 + 3 = 4。

该算法的精髓就在 h(s) 的更新上,理解了 h(s) 的更新,LRTA* 算法就基本理解了。

具体例子可以看参考文档里面的第一篇,这里就不细述了。

2、代码示例:

import os
import sys
import math
import copy
import heapq
import matplotlib.pyplot as plt


class LRTAStar:
    """AStar set the cost + heuristics as the priority
    """
    def __init__(self, s_start, s_goal, heuristic_type,xI, xG):
        self.s_start = s_start
        self.s_goal = s_goal
        self.heuristic_type = heuristic_type

        self.u_set = [(-1, 0), (-1, 1), (0, 1), (1, 1),
                        (1, 0), (1, -1), (0, -1), (-1, -1)]  # feasible input set
        self.obs = self.obs_map()  # position of obstacles

        self.OPEN = dict()  # priority queue / OPEN set
        self.CLOSED = []  # CLOSED set / VISITED order
        self.PARENT = dict()  # recorded parent
        self.h = dict()
        self.g = dict()  # cost to come
        self.x_range = 51  # size of background
        self.y_range = 31
        
        self.xI, self.xG = xI, xG
        self.obs = self.obs_map()

    def update_obs(self, obs):
        self.obs = obs

    def animation(self, path, visited, name):
        self.plot_grid(name)
        self.plot_visited(visited)
        self.plot_path(path)
        plt.show()


    def plot_grid(self, name):
        obs_x = [x[0] for x in self.obs]
        obs_y = [x[1] for x in self.obs]

        plt.plot(self.xI[0], self.xI[1], "bs")
        plt.plot(self.xG[0], self.xG[1], "gs")
        plt.plot(obs_x, obs_y, "sk")
        plt.title(name)
        plt.axis("equal")

    def plot_visited(self, visited, cl='gray'):
        if self.xI in visited:
            visited.remove(self.xI)

        if self.xG in visited:
            visited.remove(self.xG)

        count = 0

        for x in visited:
            count += 1
            plt.plot(x[0], x[1], color=cl, marker='o')
            plt.gcf().canvas.mpl_connect('key_release_event',
                                         lambda event: [exit(0) if event.key == 'escape' else None])

            if count < len(visited) / 3:
                length = 20
            elif count < len(visited) * 2 / 3:
                length = 30
            else:
                length = 40
            #
            # length = 15

            if count % length == 0:
                plt.pause(0.001)
        plt.pause(0.01)

    def plot_path(self, path, cl='r', flag=False):
        path_x = [path[i][0] for i in range(len(path))]
        path_y = [path[i][1] for i in range(len(path))]

        if not flag:
            plt.plot(path_x, path_y, linewidth='3', color='r')
        else:
            plt.plot(path_x, path_y, linewidth='3', color=cl)

        plt.plot(self.xI[0], self.xI[1], "bs")
        plt.plot(self.xG[0], self.xG[1], "gs")

        plt.pause(0.01)


    def update_obs(self, obs):
        self.obs = obs

    def obs_map(self):
        """
        Initialize obstacles' positions
        :return: map of obstacles
        """

        x = 51
        y = 31
        obs = set()

        for i in range(x):
            obs.add((i, 0))
        for i in range(x):
            obs.add((i, y - 1))

        for i in range(y):
            obs.add((0, i))
        for i in range(y):
            obs.add((x - 1, i))

        for i in range(10, 21):
            obs.add((i, 15))
        for i in range(15):
            obs.add((20, i))

        for i in range(15, 30):
            obs.add((30, i))
        for i in range(16):
            obs.add((40, i))

        return obs
    def searching(self):
        """
        A_star Searching.
        :return: path, visited order
        """

        self.PARENT[self.s_start] = self.s_start
        self.g[self.s_start] = 0
        self.g[self.s_goal] = math.inf
        self.OPEN[self.s_start] = self.f_value(self.s_start,self.s_start)
        count = 1
        while self.OPEN:
            s = min(self.OPEN, key=self.OPEN.get)
            print(count)
            self.OPEN.pop(s)
            self.CLOSED.append(s)
            
            count += 1
            if s == self.s_goal:  # stop condition
                break
            new_h = math.inf
            for s_n in self.get_neighbor(s):
                new_cost = self.g[s] + self.cost(s, s_n)
                new_s_n = self.heuristic2(s,s_n) + self.heuristic(s_n)
                if new_s_n < new_h:
                    new_h = copy.deepcopy(new_s_n);
                if s_n not in self.g or new_cost < self.g[s_n]:  
                    self.g[s_n] = new_cost
                    self.PARENT[s_n] = s
                    self.OPEN[s_n] = self.f_value(s,s_n)
            if new_s_n > self.h[s]:
                self.h[s] = new_s_n
        #print(self.CLOSED)
        return self.extract_path(self.PARENT), self.CLOSED

    def get_neighbor(self, s):
        """
        find neighbors of state s that not in obstacles.
        :param s: state
        :return: neighbors
        """

        return [(s[0] + u[0], s[1] + u[1]) for u in self.u_set]

    def cost(self, s_start, s_goal):
        """
        Calculate Cost for this motion
        :param s_start: starting node
        :param s_goal: end node
        :return:  Cost for this motion
        :note: Cost function could be more complicate!
        """

        if self.is_collision(s_start, s_goal):
            return math.inf

        return math.hypot(s_goal[0] - s_start[0], s_goal[1] - s_start[1])

    def is_collision(self, s_start, s_end):
        """
        check if the line segment (s_start, s_end) is collision.
        :param s_start: start node
        :param s_end: end node
        :return: True: is collision / False: not collision
        """

        if s_start in self.obs or s_end in self.obs:
            return True

        if s_start[0] != s_end[0] and s_start[1] != s_end[1]:
            if s_end[0] - s_start[0] == s_start[1] - s_end[1]:
                s1 = (min(s_start[0], s_end[0]), min(s_start[1], s_end[1]))
                s2 = (max(s_start[0], s_end[0]), max(s_start[1], s_end[1]))
            else:
                s1 = (min(s_start[0], s_end[0]), max(s_start[1], s_end[1]))
                s2 = (max(s_start[0], s_end[0]), min(s_start[1], s_end[1]))

            if s1 in self.obs or s2 in self.obs:
                return True

        return False

    def f_value(self,s, s_n):
        """
        f = g + h. (g: Cost to come, h: heuristic value)
        :param s: current state
        :return: f
        """
        if s_n in self.h:
            return self.g[s_n] + self.h[s_n]
        else:
            self.h[s_n] = self.heuristic(s_n)
        return self.g[s_n] + self.heuristic(s_n)

    def extract_path(self, PARENT):
        """
        Extract the path based on the PARENT set.
        :return: The planning path
        """

        path = [self.s_goal]
        s = self.s_goal

        while True:
            s = PARENT[s]
            path.append(s)

            if s == self.s_start:
                break

        return list(path)

    def heuristic2(self, s1,s2):
        heuristic_type = self.heuristic_type  # heuristic type
        goal = self.s_goal  # goal node

        if heuristic_type == "manhattan":
            return abs(s1[0] - s2[0]) + abs(s1[1] - s2[1])
        else:#sqrt(x^2+y^2)
            return math.hypot(s1[0] - s2[0], s1[1] - s2[1])

    def heuristic(self, s):
        """
        Calculate heuristic.
        :param s: current node (state)
        :return: heuristic function value
        """

        heuristic_type = self.heuristic_type  # heuristic type
        goal = self.s_goal  # goal node

        if heuristic_type == "manhattan":
            return abs(goal[0] - s[0]) + abs(goal[1] - s[1])
        else:#sqrt(x^2+y^2)
            return math.hypot(goal[0] - s[0], goal[1] - s[1])


def main():
    s_start = (5, 5)
    s_goal = (45, 25)

    astar = LRTAStar(s_start, s_goal, "euclidean",s_start,s_goal)

    path, visited = astar.searching()
    astar.animation(path, visited, "LRTA*")  # animation



if __name__ == '__main__':
    main()

上述代码运行后执行的循环次数是和A* 的那个是一样的,这里有点奇怪,不知道是我理解的有问题还是确实它起到的作用比较有限,因为LRTA* 的作用主要是快速的跳出局部最优解的问题,但是这里可能没有出现这方面的问题所以其实也就没有起到优化的效果,总的来说,相当于了解一个算法思路,但是作用似乎很有限。

参考:
1、《[PR] LRTA* 搜索算法》
2、《[AI] LRTA*搜索算法及其扩展算法》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/998718.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

集成学习-树模型

可以分为三部分学习树模型&#xff1a; 基本树&#xff08;包括 ID3、C4.5、CART&#xff09;.Random Forest、Adaboost、GBDTXgboost 和 LightGBM。 基本树 选择特征的准则 ID3&#xff1a;信息增益max C4.5&#xff1a;信息增益比max CART&#xff1a;基尼指数min 优缺…

【uniapp关联unicloud,阿里云云服务空间】unicloud本地调试服务启动失败:当前项目未关联unicloud服务空间,请调整后重新运行,已解决

最近开发app项目&#xff0c;很多都是第一次上手 1、在Hbuider中运行项目&#xff0c;出现如下提示 2、项目根目录下已有uniCloud文件夹 3、如果云开发环境未创建&#xff0c;可以右击项目&#xff0c;选择创建uniCloud云开发环境 4、创建好的目录如下&#xff0c;index.js中…

图解三重积分的对称性

1.图解三重积分的对称性 关于三重积分详见&#xff1a;三重积分(Triple Integral) 三重积分的对称性原理与二重积分类似&#xff0c;关于二重积分的对称性详见&#xff1a;图解二重积分的对称性 被积函数 f ( x , y , z ) f(x,y,z) f(x,y,z)可以有不同的物理意义&#xff0c;…

查询设计之查询条件对结果的影响

在sql使用中&#xff0c;最常用的就是查询。 在实践过程中&#xff0c;丰富的查询场景也使得查询sql有多种写法&#xff0c;不同的写法会带来不同的效果 以下&#xff0c;就查询条件对结果的影响。 一、数据 二、需求 把查询 type A’的 user 以及 type ‘A’ 的 department…

网络爬虫的意义:连接信息世界的纽带

本文将探讨网络爬虫的意义及其在连接信息世界中的重要作用。网络爬虫作为一种自动化程序&#xff0c;通过收集和提取互联网上的数据&#xff0c;为搜索引擎、数据分析和机器学习等领域提供了宝贵的资源。同时&#xff0c;我们也将探讨网络爬虫的伦理和法律责任&#xff0c;以及…

5、DVWA——文件上传

文章目录 一、文件上传原理二、low2.1 源码分析2.2 通关步骤 三、medium3.1 源码分析3.2 通关思路 四、high4.1 源码分析4.2 通关思路 一、文件上传原理 文件上传漏洞一般指用户上传了一个可执行的脚本文件&#xff0c;并通过此脚本文件获得了执行服务器端命令的能力。文件上传…

C语言经典100例题(45)--学习使用register定义变量的方法

目录 题目 问题分析 代码 运行结果 题目 学习使用register定义变量的方法 问题分析 register是做声明的&#xff0c;为了提高效率。 register变量不能做取地址运算符&操作。 声明变量具有register储类型就要求编译器把变量存储在寄存器中&#xff0c;而不是像其他变量…

第4篇 vue的基本语法操作以及组件,声明周期,路由的操作

一 vue常用操作案例 1.1 事件渲染 1.数据渲染的方式&#xff1a;使用插值表达式{{}}进行数据渲染 2.数据渲染的方式&#xff1a;以使用 v-bind指令&#xff0c;它的简写的形式就是一个冒号&#xff08;:&#xff09;&#xff0c;v-bind 特性被称为指令。指令带有前缀 v- 代…

OLED透明屏交互技术:开创未来科技的新篇章

OLED透明屏交互技术作为一项前沿的科技创新&#xff0c;正在以其高透明度、触摸和手势交互等特点&#xff0c;引领着未来科技的发展。 不仅在智能手机、可穿戴设备和汽车行业有着广泛应用&#xff0c;还在广告和展示领域展现出巨大的潜力。 那么&#xff0c;尼伽在这篇文章中将…

无涯教程-JavaScript - DDB函数

描述 DDB函数使用双倍余额递减法或您指定的某些其他方法返回指定期间内资产的折旧。 语法 DDB (cost, salvage, life, period, [factor])争论 Argument描述Required/OptionalCostThe initial cost of the asset.RequiredSalvage 折旧结束时的价值(有时称为资产的残值)。 该…

三、lock类的编写与解析 —— TinyWebServer

lock类的编写与解析 —— TinyWebServer 一、前言 这个类的作用作者已经给了解释 —— “多线程同步&#xff0c;确保任一时刻只能有一个线程能进入关键代码段.” 对于这句话其实看了&#xff0c;会有似懂非懂的感觉&#xff0c;然后写代码的时候&#xff0c;就会完全不懂。其…

分享一个开发者和设计者的免费图标库

图标是现代界面设计的不可或缺的一部分&#xff0c;无论是移动应用、网页设计还是软件界面。然而&#xff0c;许多开发者和设计师都面临着一个共同的挑战&#xff1a;寻找高品质、开源且免费的矢量图标资源。在这个领域&#xff0c;Yesicon 脱颖而出&#xff0c;成为了一个备受…

【计算机网络】UDP数据包是如何在网络中传输的?

List item 创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 更多计算机网络知识专栏&#xff1a;计算机网络&#x1f525;…

【性能测试】中间件优化

1、Tomcat 优化连接数、线程池 打开tomcat安装目录\conf\server.xml文件&#xff0c;在server.xml中 有以下配置&#xff1a; tomcat HTTP/1.1 <Connector port"8080" protocol"HTTP/1.1" maxThreads"1000" acceptCount"1500" c…

Python网络爬虫库:轻松提取网页数据的利器

网络爬虫是一种自动化程序&#xff0c;它可以通过访问网页并提取所需的数据。Python是一种流行的编程语言&#xff0c;拥有许多强大的网络爬虫库。在本文中&#xff0c;我们将介绍几个常用的Python网络爬虫库以及它们的使用。 Requests库 Requests是一个简单而优雅的HTTP库&…

mysql中GROUP_CONCAT函数详解

GROUP_CONCAT是MySQL中的一个聚合函数&#xff0c;它用于将多行数据按照指定的顺序连接成一个字符串&#xff0c;并返回结果。下面是对GROUP_CONCAT函数的详解&#xff1a; 语法&#xff1a; GROUP_CONCAT([DISTINCT] expr [,expr …] [ORDER BY {unsigned_integer | col_name…

揭秘动态网页与JavaScript渲染的处理技巧

大家好&#xff01;作为一名互联网技术爱好者&#xff0c;今天我要和大家分享一个关于Python数据采集的重要技巧——处理动态网页与JavaScript渲染&#xff01;这是一项在数据获取领域中非常关键的技能&#xff0c;让我们一起揭秘它的神秘面纱吧&#xff01; 首先&#xff0c;让…

antd-vue - - - - - select自定义渲染[封装select组件]

select自定义渲染[封装select组件] 1. 期望效果2. 代码展示 1. 期望效果 标签值和option展示不一致&#xff01; 2. 代码展示 官网地址:【antd-vue select】 封装的select组件&#xff1a; <template><a-form ref"refForm" :model"selectConfig&…

K8S1.23.6版本详细安装教程以及错误解决方案(包括前置环境,使用部署工具kubeadm来引导集群)

准备工作&#xff08;来自官方文档&#xff09; 一台兼容的 Linux 主机。Kubernetes 项目为基于 Debian 和 Red Hat 的 Linux 发行版以及一些不提供包管理器的发行版提供通用的指令。每台机器 2 GB 或更多的 RAM&#xff08;如果少于这个数字将会影响你应用的运行内存&#xf…

Python中的包管理方法

在Python开发中&#xff0c;包管理与依赖问题一直是开发者头疼的问题之一。随着项目规模的增大和复杂性的增加&#xff0c;管理各种依赖包和解决版本冲突变得尤为重要。本文将分享解决Python中的包管理与依赖问题的方法和工具&#xff0c;帮助开发者更好地管理项目中的依赖关系…