代码黑科技的分享区java


1、前言
很早以前就想写这篇文章了,因为各类不可描述的缘由拖延到了如今,今儿就把坑给填上吧~node
前排提示:小伙伴们能够收藏下这篇文章哦,说不定那天大家就用上了。由于真的是很干货哦!git
2、Open TS算法框架
作元启发式的小伙伴都知道,一开始须要学习一些固定的算法框架,这是理论基础。有了理论基础之后就能够针对各类奇奇怪怪问题把这些算法框架给套上去,总能跑出一些结果,不管是好的差的。github
常常有不少人来问我,这个问题用什么算法比较好啊?那个问题用什么框架比较合适?一开始我还很耐心的跟他们扯淡说:没有最好的,只有更好的。。。其实不是的,按照我这几年作启发式的经验来讲,算法框架这东西其实吧,只要是一个类别的,基本都不会有太大差异(好比TS和SA、LNS和ALNS、GA和AFAS等等)。咱们作算法开发的时候,更应该把重心放在一些问题特性的推导,或者搜索算子的思考上。web
好了又扯远了……今天的主题是分享一份代码,一个开源的Tabu Search框架,以及如何利用该框架进行二次开发。先介绍下今天的主角:Open TS。这个是由Robert Harder开发的一个基于java平台tabu search算法框架。用他的话说就是:算法
Use these classes to help build a structured and efficient Java tabu search.编程

该package包含了实现一个tabu search框架须要的各类元素,能够说得上很是全面了。你们在编写tabu search相关的算法时,只须要extend相关的class或者implements相关的interface便可。微信

这就使得咱们能够将更多的时间和精力放在算子的设计以及其余问题特性的考虑上,而不是将大量的时间浪费在维护算法框架上。固然了,这个框架因为考虑了不少general的东西,同时也作了不少额外的异常处理什么的从而使得代码更为健壮。thus,代码的速度可能就会有一点点损失。app
嗯……我这里指的损失是相对那种超级大神级别的人来讲的,毕竟他们写代码会把各类冗余的计算去掉,把全部的可能slow down算法速度的因素都杜绝掉,巴不得直接用汇编写的那种……咱这些普通打工人也还没到那么牛逼的地步嘛!框架
总之,这个算法框架仍是很是牛逼的,平时撸撸论文,作作项目直接拿来作二次开发也是一个不错的选择啦。
3、二次开发
其实上面给了不少类,可是对于一个单线程的tabu search来讲,并不须要用到全部的class,只须要继承一些基本的元素,而后针对你的问题将他们special化就行啦。下面我介绍下二次开发的要实现的一些东西吧。
1. SolutionAdapter
求解任何问题,首先仍是要定义该问题的solution结构了。只须要extend Open TS的SolutionAdapter类便可,该类中只有一个成员变量为:
private double[] objectiveValue;
为该解的目标值向量,而后你就能够在你本身的solution中定义问题的其余变量了。好比存储路径啊,解的其余中间变量等等。
2. TabuSearchListener
该类呢为接口类,里面有几个抽象方法须要实现的,分别为:
public void newBestSolutionFound(TabuSearchEvent event) {}
找到一个全局最优解时,要作的事情能够写在里面。
public void newCurrentSolutionFound(TabuSearchEvent event) {}
找到一个新的当前解时要作的事情能够写在这个函数。
public void tabuSearchStarted(TabuSearchEvent event) {
算法开始时触发的事件。
public void tabuSearchStopped(TabuSearchEvent event) {}
算法结束时触发的事件。
基本上从新写一下上面几个抽象方法就能够知足大部分的需求了。固然里面也定义了一些nonimprove相关的时间,能够做为shake使用。
3. ObjectiveFunction
该interface比较重要,继承之后须要实现下面这个抽象方法:
public double[] evaluate(Solution solution, Move proposedMove) {}
它表示评估当前解solution通过proposedMove之后造成的邻居解的目标值向量,就是前面SolutionAdapter中那个objectiveValue哦。这是什么意思呢,其实在算法实现中,咱们通常不直接生成邻居解,而是生成一个称之为 的东西,这是个什么东西呢,画个图:

其中我用紫色标出来的就是一个 ,简单来讲他记录了生成邻居解须要对当前解进行的一些操做,好比exchange(6, 15)。
所以每次生成邻域时,能够先生成邻居解对应的 ,而后去评估每一个 对应的邻居解的cost,以比较各个邻居解的好坏。
4. ComplexMove
为interface,该算法框架的邻居解是经过当前解+move得到的,所以你的问题中设计的operator算子须要实现该接口,它有一些抽象方法以下:
public abstract void operateOn( Solution soln );
该方法实际上是更上一层extends来的,表示对该move对soln执行相应的操做,好比exchange(1, 2)或者relocate(1, 3)等等。
public abstract int[] attributesDelete();
执行该move时,删除一个元素时返回的信息提供给tabu list记录。好比{1, 3}表示exchange了1和3,那么tabu list就要记录起来,防止后面的迭代中再进行exchange(1, 3)这样的操做。
public abstract int[] attributesInsert();
执行该move时,插入一个元素时返回的信息提供给tabu list记录。和删除时相似的。
5. MoveManager
这也是一个interface,是否是很爽,只须要implements相关的接口便可完成一个算法,简直不要过轻松!它的抽象方法只有一个:
public Move[] getAllMoves( Solution solution ) { }
这个方法是须要咱们本身实现的,并且很是重要,由于这里定义了咱们设计的算子所生成的move集合。
我以为这个框架最好的地方就是这里了,他把全部的move都放在一块儿集中进行管理,后面进行约束变动的时候只须要修改这里的生成规则便可。好比客户i不能插入路径j,那么你在这里生成的时候就进行这些限制便可。
6. ComplexTabuList
这是一个类,表示tabu search中的禁忌表,里面有一个多维的tabu list能够记录不少信息:
private int[][][][][] tabuList; // Data structure used to store list
同时该类已经实现了setTabu和isTabu的方法。这两个方法须要结合以前设置的attributesInsert()和attributesDelete()方法一块儿使用,若是作出修改那么须要修改相应的这几部分,特别是tabu list要进行修改的话。。。
4、实例
好了以上就是一些简单的介绍,固然这样介绍可能你们没什么感受,由于这东西在没有对代码有一个很好的全局掌控以前,很难体会到其中的精髓,反而不少人由于其中巨大的代码量感受极为繁琐。
毕竟用别人的东西,万一出错了都不知道怎么调。这里呢为了让你们更好的熟悉这个框架,我贴上了一个使用该框架实现一个求解VRPTW问题的例子,这个代码是来源于GitHub(好像是意大利都灵理工大学一些masters的课程大做业吧……)原连接为oma-vrptw。
https://github.com/oma-vrptw/oma-vrptw
这个代码自己也有不少值得借鉴参考的地方的,好比它里面实现了一个relocate(代码中叫SWPA MOVE,可是我以为relocate更合适点)算子,在评估一个move的时候就用到了此前咱们讲过的以O(n)复杂度计算邻居解的一些操做:
这个算子的效果还能够的,在Solomon的标准算例中C系列大部分能跑到最优,速度更是快得飞起。你们阅读源码时照着我上面贴出来的思路看便可。算例呢我也整合好了,我对源代码作了一些修改,使得他可以正常运行(否则待会又有不少人跑来问我代码咋不能运行呢?),更改算例在如下位置便可更改。

单线程tabu search的主体呢是在SingleThreadedTabuSearch这个类中,执行一次迭代的逻辑都写在了protected void performOneIteration()这个方法里面。
其实要写的比较高效的话,每一个算子生成的move都应该定制好本身单独的evaluate函数,示例只写了一个算子,若是move是由多个算子生成的话,须要判断下move属于哪一个算子的,而后进行相应的evaluate,能够更改ObjectiveFunction的evaluate函数成以下形式:

固然啦,你也能够修改框架中的代码以达到更多个性化的功能,不过我是不太推荐这样作的,由于别人封装好的东西,你一整的话,出错了都不知道去哪里找。不过熟悉之后能够尝试修改一下底层的代码。我就对那个tabu list进行了修改,由于感受给的那个不是很好用吧~
5、代码下载
我把修改过的代码放在了GitHub上,地址为
https://github.com/dengfaheng/omatest
好了,你们能够慢慢去看代码了。。。have a nice day!看在小编这么勤劳的份上,帮我点个在看呗~万一你的老板喜欢看微信的看一看,看到你又在微信上学习代码,ta确定要高兴得不得了呀!你就能够大胆告诉他:
推荐阅读:
干货 | 学习算法,你须要掌握这些编程基础(包含JAVA和C++)


本文分享自微信公众号 - 程序猿声(ProgramDream)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。