遗传编程GP-地图路径寻路
本文介绍的是基于GP,并非A*算法,算是另类实现吧。
先看看地图定义,在文本文件中定义如下字符串,代表30列11行大小的地图
初始位置在左上角(0,0) ,值为1的是允许走的通的路,目标位置为右下角(29,10)
1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 1 1 1 1 1 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1
算法运行效果如下:
"C:\Program Files\Java\jdk1.8.0_211\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.1.2\lib\idea_rt.jar=54171:C:\Program Files\JetBrains\IntelliJ IDEA 2019.1.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_211\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_211\jre\lib\rt.jar;C:\Research-Code\demo1\target\classes;C:\Users\McKay\.m2\repository\io\jenetics\jenetics\5.1.0\jenetics-5.1.0.jar;C:\Users\McKay\.m2\repository\io\jenetics\jenetics.ext\5.1.0\jenetics.ext-5.1.0.jar;C:\Users\McKay\.m2\repository\io\jenetics\jenetics.prog\5.1.0\jenetics.prog-5.1.0.jar;C:\Users\McKay\.m2\repository\commons-lang\commons-lang\2.6\commons-lang-2.6.jar" MapGame.GameDemo
1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 1 1 1 1 1 1 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1
G: 15769
--------------------
map-->Right-->Right-->Right-->Right-->Right-->Down-->Down-->Down-->Left-->Down-->Down-->Left-->Down-->Down-->Right-->Right-->Right-->Right-->Right-->Down-->Down-->Down-->Right-->Right-->Right-->Right-->Right-->Right-->Right-->Right-->Right-->Right-->
E: 1320.0 Process finished with exit code 0
这边由于是套遗传编程,因此会定义几个固定操作算子:上移、下移、左移、右移;看看上移算子代码:
public class GoUpOp implements Op<TempMapInfo> {
private MapController mapController; //地图控制工具类,比如判断能否移动到某个坐标、是否完成地图等
public GoUpOp(MapController mapController) {
this.mapController=mapController;
} @Override
public String name() {
return "Up";
} @Override
public int arity() {
return 1;
} @Override
public String toString() {
return "Up";
} @Override
public TempMapInfo apply(TempMapInfo[] tempMapInfos) {
TempMapInfo newInfo=tempMapInfos[0].cloneMe(); //需要深度克隆,防止多线程对象直接互相影响 if(newInfo.currentLocationY==0)
{
newInfo.score-=1000; //已经在最上方了,不能再做上移动作了
newInfo.tag+="-UP"; //惩罚分,扣除1000分
return newInfo;
}
if(!mapController.canMove2(newInfo.currentLocationX, newInfo.currentLocationY-1)) //是否上移位置是路
{
newInfo.score-=1000; //惩罚扣除1000分
newInfo.tag+="-UP";
return newInfo;
} newInfo.score+=10; //可以走,奖励10分
newInfo.currentLocationY--; //递减y坐标
if(newInfo.visited.contains(newInfo.currentLocationX+","+newInfo.currentLocationY)) //不能重复访问点
newInfo.score-=1000;
else
newInfo.visited.add(newInfo.currentLocationX+","+newInfo.currentLocationY); if(mapController.isSuccess(newInfo.currentLocationX, newInfo.currentLocationY)) //判断是否地图完成
newInfo.score+=1000;
newInfo.tag+="-UP";
return newInfo;
} }
下面需要将这些操作算子嵌进GP中:
public static void main(String[] args) { Integer[][] map=GetMap();
dispalyMap(map); TempMapInfo mapInfo=new TempMapInfo();
mapInfo.score=0;
mapInfo.currentLocationX=0;
mapInfo.currentLocationY=0; //左上角为起点 List<Op<TempMapInfo>> terminals=new ArrayList<>();
terminals.add(Const.of("map", mapInfo)); MapController mapController=new MapController(map); final ISeq<Op<TempMapInfo>> TMS = ISeq.of(terminals);
final ISeq<Op<TempMapInfo>> OPS = ISeq.of(new GoLeftOp(mapController), new GoRightOp(mapController), new GoUpOp(mapController), new GoDownOp(mapController));
final GameSearcher gameSearcher = GameSearcher.of(
GameSearcher.codecOf(
OPS, TMS, 20,
t -> t.getGene().size() < 60
)
); final Engine<ProgramGene<TempMapInfo>, Double> engine = Engine
.builder(gameSearcher)
.populationSize(500)
.maximizing()
.alterers(
new SingleNodeCrossover<>(0.1),
new Mutator<>(0.3),
new UniformCrossover<>(0.5)
)
.offspringSelector(new TournamentSelector<>(2))
.survivorsSelector(new TournamentSelector<>())
.build(); final EvolutionResult<ProgramGene<TempMapInfo>, Double> er =
engine.stream()
.limit(Limits.byExecutionTime(Duration.ofSeconds(60)))
.collect(EvolutionResult.toBestEvolutionResult()); final ProgramGene<TempMapInfo> program = er.getBestPhenotype()
.getGenotype()
.getGene(); final TreeNode<Op<TempMapInfo>> tree = program.toTreeNode();
System.out.println("G: " + er.getTotalGenerations());
printTree(tree.depthFirstStream().collect(Collectors.toList()));
System.out.println("E: " + gameSearcher._fitness(tree));
} private static void printTree(List<TreeNode<Op<TempMapInfo>>> lst) {
System.out.println("--------------------");
for(TreeNode<Op<TempMapInfo>> node:lst)
System.out.print(node.getValue()+"-->");
System.out.println();
}
上面的terminals变量是存放终结符的,此处是直接把操作动作放进去了,包含了分数、访问步骤、当前xy坐标等,只有1个变量
public class TempMapInfo {
public int currentLocationX;
public int currentLocationY;
public double score;
public List<String> visited=new ArrayList<>();
public String tag=""; public TempMapInfo()
{
visited.add("0,0");
} public TempMapInfo cloneMe()
{
TempMapInfo info=new TempMapInfo(); info.currentLocationX=this.currentLocationX;
info.currentLocationY=this.currentLocationY;
info.score=this.score;
info.tag=this.tag;
info.visited=new ArrayList<>();
for(String i:this.visited)
info.visited.add(i); return info;
}
}
GameSearcher是对GP算法的编码、解码封装、计算分值,算是核心:
public final class GameSearcher
implements Problem<Tree<Op<TempMapInfo>, ?>, ProgramGene<TempMapInfo>, Double>
{ private final Codec<Tree<Op<TempMapInfo>, ?>, ProgramGene<TempMapInfo>> _codec; private GameSearcher(
final Codec<Tree<Op<TempMapInfo>, ?>, ProgramGene<TempMapInfo>> codec
) {
_codec = requireNonNull(codec);
} @Override
public Function<Tree<Op<TempMapInfo>, ?>, Double> fitness() {
return this::_fitness;
} @Override
public Codec<Tree<Op<TempMapInfo>, ?>, ProgramGene<TempMapInfo>> codec() {
return _codec;
} public double _fitness(final Tree<Op<TempMapInfo>, ?> program) { List<TempMapInfo> lst=new ArrayList<>();
lst.add(new TempMapInfo()); List<TempMapInfo> results=lst.stream().map(args -> Program.eval(program, args)).collect(Collectors.toList()); double score=results.stream().mapToDouble(a->a.score).sum(); //这行是用来统计整个操作算子序列总得分用的,很重要
return score;
} public static GameSearcher of(
final Codec<Tree<Op<TempMapInfo>, ?>, ProgramGene<TempMapInfo>> codec
) {
return new GameSearcher(codec);
} public static Codec<Tree<Op<TempMapInfo>, ?>, ProgramGene<TempMapInfo>>
codecOf(
final ISeq<Op<TempMapInfo>> operations,
final ISeq<Op<TempMapInfo>> terminals,
final int depth,
final Predicate<? super ProgramChromosome<TempMapInfo>> validator
) {
if (depth > 200 || depth < 0) {
throw new IllegalArgumentException(format(
"Tree depth out of range [0, 30): %d", depth
));
} return Codec.of(
Genotype.of(ProgramChromosome.of(
depth,
validator,
operations,
terminals
)),
Genotype::getGene
);
}
}
算法介绍完毕,pom依赖如下:
<dependencies>
<!-- https://mvnrepository.com/artifact/io.jenetics/jenetics -->
<dependency>
<groupId>io.jenetics</groupId>
<artifactId>jenetics</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>io.jenetics</groupId>
<artifactId>jenetics.ext</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>io.jenetics</groupId>
<artifactId>jenetics.prog</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
遗传编程GP-地图路径寻路的更多相关文章
- 【比较】遗传算法GA和遗传编程GP有什么不同?
遗传算法GA 本质上有一个固定的长度,这意味着所产生的功能有限的复杂性 通常会产生无效状态,因此需要以非破坏性方式处理这些状态 通常依赖于运算符优先级(例如,在我们的例子中,乘法发生在减法之前),这可 ...
- 第四届58topcoder编程大赛--地图路径规划
layout: post title: 第四届58topcoder编程大赛 subtitle: 58ACM catalog: true tags: - A* 算法 - C++ - 程序设计 问题及背景 ...
- 【Python Deap库】遗传算法/遗传编程 进化算法基于python DEAP库深度解析讲解
目录 前言 概述 启发式的理解(重点) 优化问题的定义 个体编码 初始族群的创建 评价 配种选择 锦标赛 轮盘赌选择 随机普遍抽样选择 变异 单点交叉 两点交叉 均匀交叉 部分匹配交叉 突变 高斯突变 ...
- 遗传编程(GA,genetic programming)算法初探,以及用遗传编程自动生成符合题解的正则表达式的实践
1. 遗传编程简介 0x1:什么是遗传编程算法,和传统机器学习算法有什么区别 传统上,我们接触的机器学习算法,都是被设计为解决某一个某一类问题的确定性算法.对于这些机器学习算法来说,唯一的灵活性体现在 ...
- 【遗传编程/基因规划】Genetic Programming
目录 背景介绍 程序表示 初始化 (Initialization) Depth定义 Grow方法 Full方法 Ramped half-and-half方法 适应度(Fitness)与选择(Selec ...
- 【python(deap库)实现】GEAP 遗传算法/遗传编程 genetic programming +
目录 前言 1.优化问题的定义 单目标优化 多目标优化 2.个体编码 实数编码 二进制编码 序列编码(Permutation encoding) 粒子(Particles) 3 初始种群建立 一般族群 ...
- Android中Google地图路径导航,使用mapfragment地图上画出线路(google map api v2)详解
在这篇里我们只聊怎么在android中google map api v2地图上画出路径导航,用mapfragment而不是mapview,至于怎么去申请key,manifest.xml中加入的权限,系 ...
- iOS百度地图路径规划和POI检索详细总结-b
路径规划.png 百度地图的使用 百度地图API的导入网上说了许多坑,不过我遇到的比较少,这里就放两个比较常见的吧.坑一: 奥联WIFI_xcodeproj.png 如上图所示,在infoplist里 ...
- Vue 高德地图 路径规划 画点
CDN 方式 <!--引入高德地图JSAPI --> <script src="//webapi.amap.com/maps?v=1.4.13&key=您申请的ke ...
随机推荐
- linux 基于 jiffy 的超时
到目前为止所展示的次优化的延时循环通过查看 jiffy 计数器而不告诉任何人来工作. 但是最好的实现一个延时的方法, 如你可能猜想的, 常常是请求内核为你做. 有 2 种方 法来建立一个基于 jiff ...
- 2018.10.26 浪在ACM 集训队第二次测试赛
2018.10.26 浪在ACM 集训队第二次测试赛 整理人:苗学林 A海港 参考博客:[1]:李继朋https://www.cnblogs.com/violet-acmer/p/9859006.ht ...
- Spring Security 学习笔记-securityContext过滤器过滤链学习
web.xml配置委托代理filter,filter-name默认与filter bean的名字保持一致. <filter> <filter-name>springSecuri ...
- JS逻辑运算操作
非! 如果一个操作数是一个对象,返回false; 如果一个操作数是一个空字符串,返回true; 如果一个操作数是一个非空字符串,返回false; 如果一个操作数是一个数值0,返回true; 如果一个操 ...
- Linux网络文件共享服务之FTP
一.FTP介绍 ftp(File Transfer Protocol)是早期的三个应用级协议之一,基于C/S结构,双通道协议,数据和命令连接,数据传输格式默认是二进制,当然也支持文件方式传输.默认情况 ...
- Netty小结
前言 在实际开发中,netty的开发使用相对较小,why?在企业中涉及网络编程的部分比重较小,在这大环境内,企业会优先使用简单的http,udp等基础的通讯协议工具,如果不能满足需求,会考虑基于rpc ...
- 009.MFC_Spin
数值调节按钮CSpinButtonCtrl属性 Alignment Auto Buddy Set Buddy integer成员函数 SetRange32() SetBase()
- 深入浅出Java并发中的CountDownLatch
1. CountDownLatch 正如每个Java文档所描述的那样,CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行.在Java并发中 ...
- starUml破解
在安装目录的:StarUML\www\license\node 找到LicenseManagerDomain.js 在 try 前面加上: return { name:"0xcb" ...
- zabbix安装完成后查看编译参数
最近学习zabbix分布式监控系统,突然想如何查看自己编译时的参数,最终找到自己想要的结果. 1.首先进入zabbix源码目录 2.用ls -l命令查看是否有一个叫config.log文件 3.这个文 ...