遗传编程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 ...
随机推荐
- 51nod 挑剔的美食家
挑剔的美食家 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 与很多奶牛一样,Farmer John那群养尊处优的奶牛们对食物越来越挑剔,随便拿堆草就能打发她们午饭的日子自然是一 ...
- activiti工作流引擎学习(三)
5.接收任务活动(receiveTask,即等待活动)不是一个任务节点 接收任务是一个简单任务,他会等待回应消息的到达,当前,官方只实现了这个任务的java语义,当流程达到接受任务,流程状态会保存到数 ...
- Java基础系列8——IO流超详细总结
该系列博文会告诉你如何从入门到进阶,一步步地学习Java基础知识,并上手进行实战,接着了解每个Java知识点背后的实现原理,更完整地了解整个Java技术体系,形成自己的知识框架. 在初学Java时,I ...
- js实现防抖,节流
防抖函数. 将几次操作合并为一次操作进行.设置一个计时器,规定在延迟时间后触发函数,但是在延迟时间内如果再次触发,就会取消之前的计时器.如此,只有最后一次操作能触发.代码如下: function de ...
- 2018-8-10-C#-6.0-字符串-String-Interpolation
title author date CreateTime categories C# 6.0 字符串 String Interpolation lindexi 2018-08-10 19:16:52 ...
- PDF.JS 读取文件流前端展示 C#
最近再搞PDF得展示问题,因为aspose.pdf成本太高,只能使用pdf.js这个开源强大的前端东东了. 在百度了很久后 网上大都是node,java,php的事例,有位大哥的是C#的后台代码按他写 ...
- linux安装python3.*,更换Python2.*
下载并解压:Python-3.5.7.tgz [root@AH-aQYWTYSJZX01 python3]# ll total 20268 -rw-r----- 1 temp01 temp01 207 ...
- tjoi2019题解
t1:矩阵快速幂 t2:裸的平衡树 splay比treap代码长太多 常数大一倍 没加输优直接t了 还要特判n=1(我的splay删除的时候会遇到问题) t3: 很显然是容斥 然后对于$A+B+C+D ...
- Visual Studio Team Services使用教程【2】:添加团队成员
2017.4.23之后建议朋友看下面的帖子 TFS2017 & VSTS 实战(繁体中文视频) Visual Studio Team Services(VSTS)与敏捷开发ALM实战关键报告( ...
- mysql中information_schema.schemata字段说明
1. 获取所有数据库信息(SCHEMATA) show databases; 查看用户下所有数据库信息:SCHEMATA表:提供了关于数据库中的库的信息.详细表述了某个库的名称,默认编码,排序规则.各 ...