RePast如何使用中文版非常全面的翻译Word文档格式.docx
《RePast如何使用中文版非常全面的翻译Word文档格式.docx》由会员分享,可在线阅读,更多相关《RePast如何使用中文版非常全面的翻译Word文档格式.docx(48页珍藏版)》请在冰点文库上搜索。
2.TheSimModelObject(RepastJ中的一个对象)
Model对象会继承RePast的SimModelImpl对象。
我想,你绝对不会看许多SimModelImpl对象实现的代码,但是事实上这些代码是最重要的,因为它控制了整个RePast环境和仿真的过程。
而且,它预期在你创建的Model对象中找到一些东西——不幸的是这些东西没有一个真正的Interface(接口)正式,但是思路是差不多的。
你创建的Model对象将会被分块在Eclipse上设计,其实就是一个功能一个功能往上加,并且最终由RePastJ的工具条上的按钮触发运行。
第一个按钮用来打开一个模型,红叉用来关闭一个模型,红叉左边的小灯泡用来设置参数;
最重要的是第三、四、五个按钮,第三个表示运行,第四个表示单步运行,第五个表示初始化模型;
第六个表示停止,第七个表示暂停,第八个按钮(循环箭头)表示截断并将仿真恢复到未初始化状态。
(这些按钮的名称务必记住,后面讲到时不再附图)
我们先做一个小小的测试模型,下面译者一步一步实现给大家看:
/*译者注
1.打开Eclipse,文件,新,Java项目,项目名填上MyFirstRePastModel,Next
此时界面应该是:
2.选择第三个标签:
库,右边按钮“添加外部JAR”
3.(3,4两步很重要)选择安装RePast的文件夹RePast3,进入后打开RePastJ,单击选中repast.jar文件,点击打开
4.重复步骤2,进入RePastJ文件夹后,直接双击打开lib文件夹,Ctrl+A实现全选,点击打开,然后完成(如果以后写代码时出现包未导入的提示,说明这两步你没有导入成功,这两步其实很no-brainer的:
就是把repast.jar和lib文件夹下所有的jar文件都导入就行了)
5.最后点击完成
不要管我其他的项目
此时,就完成了与RePastJ的连接,说白了就是在Eclipse中写代码,然后让RePastJ环境运行,导入外部的这些jar文件,目的是写程序时需要导入诸多Repast包,此时再回头看看教程1里的第一句话:
RePast仿真工具箱是一个预先制作好的编程元素的集合。
6.双击打开MyFirstRePastModel,右键src,新建,包,包名填上demo(随意),完成
7.右键demo,新建,类(分别新建三个类,我这里分别取名为Model,Space,Agent)
8.对于Model.java,仅保留第一行代码(如右上图所示),然后开始在Model里,请一步一步添加代码,自己敲一遍的过程可以把我们以后要用到的基本方法都熟悉一遍*/
9.我们的模型,主类首先继承SimModelImpl,还必须自己扩充一些方法(methods)。
比如,必须有一个getName方法来返回正在仿真模型的名字,这个名字出现在设置参数的面板的工具栏里。
这里默认你懂得Java基本的知识,虽然译者对于Java也只能算是初级的水平。
下面是getName实现的代码,注意,为加深大家印象,我特意截图,你们不得不自己敲。
这里说明一下,教程2的代码全部在packagedemo;
这一句下方添加。
10.但是,这里还有更多的需要。
当你在RePast工具栏上点初始化按钮的时候,RePast将会触发一个在你模型当中叫做begin的方法,这个方法是为了初始化仿真器。
注意,从这里开始,每新加入的代码都用红色粗体标注。
11.用技术上的术语来说,SimModelImpl类是一个抽象类,它实现了一个接口;
接口需要实现某些方法,我们已经看到的begin()和getName()就是其中的两个需要实现的方法,马上还会看到更多;
然而,有一个附加的框架,虽然不是Java也不是RePast包必须要求的,但是它是更加简单更加传统的方法,用来组织程序。
就是将begin()方法分块:
buildModel,buildSchedule和buildDisplay。
因此,此时代码变为:
我前面说了,这种结构不是必须的,你可以按照你自己的方法来。
但是,unfortunately,当你发现许多其他RePast模型都这么写的时候,你就不淡定了。
而且事实上这样写有很多优点,所以你以后也这么写吧。
12.没有必须的、明确的方法用来实现运行、暂停和停止函数,尽管他们依赖于模型中核心的成分。
但是有另外的三个函数是必须实现的。
第一个是setup函数,当循环箭头被按下时调用该函数,我通常把这个setup函数放在begin函数前面,个人喜好。
13.第二个是getSchedule函数,它必须返回一个Schedule类型的对象。
每一个RePast模型将至少有一个schedule对象。
一般的,通过加一个schedule对象作为类变量来生成。
注意:
Schedule是一个对象,schedule是一个变量,这是Java传统规范规定的。
因此:
注意到,为了添加一个schedule对象,必须导入该类的包,一个schedule变量在变量域声明,其方法在下方添加。
/*到这里,译者简单说下,schedule主要是运行方法,尤其指时间上的安排*/
这里有一点奇怪,schedule对象是model的内部的,却被声明为private,这样的话,就不能直接被外部程序或者是对象获取。
然后,getSchedule方法作为公共方法被给出,从而间接的将schedule对象传递给外部程序或者是其他对象。
显然,直接把schedule给它们似乎更高效,所以把schedule声明为public类型的岂不是更好?
当然不行,这简直糟透了。
马上RePast引擎就要启动了,它必须要获得模型的schedule,这就必须通过调用getSchedule方法,而这个方法有时SimModelImpl接口所必须实现的。
所以,编译器强迫你得这么写。
好吧,如果你真的把schedule设成public类型的了,那么RePast引擎就会直接找schedule,这就无法确保编译器是不是温柔了,改了值也不一定。
更加重要的是,通过遵守内部变量一律设置成private而且有对应的方法可以间接存取,程序员就轻松了,想怎么实现内部schedule就怎么实现,theyarefree~在这个例子中,我命名我的schedule对象为‘schedule’,但是这不是必须的,可能有更加间接的名字,比如sch等等。
更更更加重要的是,我可以生成一个Schedule类的子类并且添加更多的功能函数,或者干点其他的事来满足我的需要;
只要getSchedule方法返回一个合适类型的对象就行了,根本不用管它是不是还做了其他额外的工作,RePast引擎都会很开心,因为getSchedule的工作圆满完成了。
最后,我们注意到public/private在这里的重要性并没有它应该有的那么大;
我们可以让我们的schedule对象是public的,并且不用太在意它,因为相对于使用我们构建的API的其他程序员来说,我们更加懂得这个模型是怎么使用的,因为模型就是我们做的。
14.最后一个必须的函数比较复杂,它叫做getInitParam,它返回一个字符串变量数组,该数组列出了一组特殊变量的名字。
你将在RePast控制面板设置这些变量。
假设你想要一个实现了N个实体的仿真器,但是你又想能够通过点击setup和initialize按钮来运行不同的N个实体来进行仿真实验,巧了,RePast允许这样,但是:
●你必须提供给RePast一个参数列表,这个例子里叫做numAgents
●你必须为每一个列表中的参数创建get和set方法,注意,是每一个
下面是控制面板和这一步的代码:
15.典型的编程实例和特殊的RePast结构需要我们提供get和set方法;
最后,你得告诉RePast你想能够通过控制面板来设置这些变量,你需要实现getInitParam方法,完整代码:
其实你们不知道,大写是件很难搞的问题,因为变量是NumAgents但是get和set方法变成了getNumAgents(注意这里N是大写)和setNumAgents。
事实上,RePast到时候会自动寻找名为”get”+”NumAgents”和”set”+“NumAgents”的方法,因此找到了”getNumAgents”和”setNumAgents”方法,具体的你们不必深究。
getInitParams返回的是一个字符串数组;
但是到目前为止我们只有一个字符串会被返回,那就是”NumAgents”;
我们学到后面会发现要返回的有很多,绝对不止一个,那么可以这么写:
即使只有一个返回的参数名,返回类型也必须是数组类型。
其中的[]告诉我们,返回的其实是一个指向字符串数组的指针。
到这里为止,原作的教程2部分就完全结束了。
我想大家跟我第一次看这个的时候心情是一样的,估计早就已经迫不及待的点了运行,然后发现竟然要配置运行环境,然后又不管三七二十一直接点了运行,发现Eclipse在苦苦的找main函数,最后弹出个令你灰心丧气的窗口,不得不放弃了。
这时候你心想,这不坑爹呢嘛我敲了那么久的代码,压根不能运行啊。
这时候请你回想当初说RePast需要的三个因素,我们到底实现了几个?
即使是Model我们也没有实现啊同志们!
这个教程2只是为了让我们了解我们今后为Model编程时一些必须的参数或者是方法,这些只是基础中的基础。
或者可以说,这些是任何Model的框架,我们今后写项目,就是往这里面填内容,RePast很难的,等你继续往后再学个十几个教程你就知道了。
等到学完了教程,实现了那个例子,你又跃跃欲试想写个新的,你又会发现自己什么都不会!
就是这样的,哪有随随便便就学会一个新工具的,何况主要的部分是在扩充别人的东西,如果你对那些预先做好的元素不熟,做一个新项目简直就是自杀行为。
到这里,我现在把主要的内容总结一下,求求你们了,一定要耐着性子再看几分钟:
继承SimpleModel类
a)buildModel:
创建模型中的智能体对象、空间对象等。
b)buildDisplay:
建立显示界面内容,包括空间对象的显示、统计图表等。
c)buildSchedule:
建立程序的运行方法
d)Setup:
设置/初始化程序(与仿真界面中的setup图形按钮相对应)
e)Step:
每个仿真时钟向前推进一个单位时,需要执行的操作(与仿真界面中的step图形按钮相对应)
f)Begin:
程序开始运行,其中需要调用buildModel,buildDisplay,buildSchedule三个方法
g)getInitParam:
在Settings窗口中显示和编辑的参数名序列
h)getSchedule:
显示模型中的运行schedule(buildSchedule方法中创建)
i)getName:
返回模型的名字
单单教程1和2,翻译加上做Word文档就用了6个小时!
从下一个教程3到最后一个教程,长达30个!
而且都只是围绕一个模型来的,如果一步一步来做,收获会非常大!
有人把这个例子实现了,又抄了抄帮助文档,竟然发了一篇文章,真是…唉,中国的学术…
3.TheCarryDropmodel(掉钱捡钱模型)
假设我们想创建一个基本的RePast模型,该模型有以下以下特点:
●Agents只在有限的网格区域内移动
●Agents总是沿上、下、左、右、左上、左下、右上、右下八个方向呈直线移动
●区域内每个格子都有可能放着一些钱;
当agents走入一个有钱的格子后就会捡起所有的钱,并且之后也带着这些钱移动
●当一个agent移入一个格子,而恰巧格子里已经有了一个agent,那么碰撞发生,新移入的agent需要付给原先占据格子的agent一个单位的买路钱,并且立刻选择一个新的方向在下一个时间片到来时移出格子,新的方向同样允许八个方向
●Agents有生命期,这个生命期由参数给出,参数有一定的范围([min,max]);
当一个agent死亡后,它生前拥有的钱全部随机分散到区域中的格子里,然后把这个agent从格子里抹掉,即清空格子,但是随即又有一个新的agent在不同的格子里诞生,其拥有新的移动方向规律和新的生命期
为了达到这个目的,我们需要三个文件:
一个实例化SimModel对象的类,一个指定agents的类,一个描述space的类。
请按照之前的教程,新建名为CarryDrop的工程(别忘了添加外部JAR!
),在src里新建名为demo的包,在demo里新建三个Java类:
∙CarryDropModel//与之前不同的是,需要加入Main方法,代码如下图
∙CarryDropAgent//新建后暂时不管
∙CarryDropSpace//新建后暂时不管
细心的话,你应该会发现,这个时候右键,运行,就会出现一个运行方式是“Java应用程序”,而不是先前的运行配置,但是现在依然运行不起来,到底缺少的是什么呢?
缺少的东西有很多,事实上。
4.添加用户可设定的参数
让我们考虑一下哪些参数需要设置为用户可设定:
●Agents数量(NumAgents)
●区域X轴方向长度(WorldXSize)
●区域Y轴方向长度(WorldYSize)
既然要引入两个新的变量,就需要:
●在类变量域添加新的变量
●在面板上加入变量与变量之间相隔的线
●添加变量相应的get和set方法
从这里开始,由于代码越来越长,对截图造成极大不便,所以只截出添加新代码的那部分:
还有:
5.编译和运行基本模型
我想大家等待着一刻都快疯了吧?
别着急,直接运行还不行,得再加几个东西。
还有Main函数
导入包不多解释,需要解释一下Main函数里的三条语句:
●第一行创建了一个SimInit类型的对象,导入部分就是为了它
●第二行创建了CarryDropModel类型的对象,就是实例化了模型对象
●第三行用Init对象里的loadModel方法装载模型
在CarryDropModel.java编辑区,右键,运行方式,Java应用程序,然后出现:
看右上方的工具条和参数面板的GUI,你发现可以输入数字,但是现在输没有任何意义,我们运行只是为了看一下效果,帮大家缓解一下欲望。
你要真是实在忍不住点击了运行按钮,你会发现它蹦出一个窗口:
6.用户可设定的参数的默认值
看上上一张图,你会发现参数面板上各个参数值都为0,这样的话,不太可能启动模型,所以我们来为三个参数设定默认值:
要修改的代码就这一部分,添加三个常量并赋值为100,40,40,再用常量为初始化变量域,对于Java不熟悉的人来说,你不要管常量怎么声明的,按照上面的方法声明就对了。
有些人认为为这些用户运行时要设定的参数赋上初值没有什么意义,确实没意义,但是这是一个非常好的编程习惯,很多小细节的把握会让你的编程水平越来越高。
7.子程序的提醒
为了示范和教学目的,现添加以下代码,来输出提示信息,在CarryDropModel.java中:
现在再运行一下模型看看效果吧!
这些代码是完全无害的。
在Eclipse运行之后点击工具条上的运行,除了之前说的效果之外,你会发现RePastOutput会出现:
8.Space对象
从这节教程开始,我们暂时先跳出model对象的构建,来考虑其他两个对象:
CarryDropSpace和CarryDropAgent。
首先我们考虑一下Space对象。
Space对象似乎一个单独的对象,它将包括预先打包好的RePast空间环境因素;
这个例子我们使用的是RePast的Object2DGrid对象。
一开始我们来为网格空间对象定义变量。
Object2DGrid是一个RePast里专门为我们做好了的Space对象;
有些它提供的函数还不得不使用,所以先导入这个包:
这个例子中,只创建space对象是不够的。
不管怎样我们先把这个对象必须的一些东西写好。
这个moneySpace存储的是一些整数对象,好吧你可以认为是整数,但是实际上与整数相差甚远。
整数对象的值代表着在网格里放着的钱的总数,为了方便,我们一律初始为0:
上面的代码告诉我们,Object2DGrid对象的构造器需要两个整数作为参数,分别对应的是X和Y的大小。
你肯定问你怎么知道?
!
开始,所有程序,RePast3,RePastJ,docs,API。
既然提到了钱,那么肯定不能全部都是0,所以我们现在来为space对象初始化一些钱。
我们的策略将是创建一个构造器,它需要一些钱的参数来初始化space对象。
这个时候,肯定需要一个参数:
钱的数量。
仔细考虑一下这个参数放在哪,Space空间吗?
不,个人认为放在Model对象里好一些,为什么?
自己想(参数…初始化…明白了么?
还有下面:
别忘了get和set方法:
9.在SimModel里的Space对象
space对象需要更多的工作来做,但是现在又可以回到model对象了,因为我们需要在model对象里为space对象做点集成性的工作。
我们要做三件事:
1.为space对象分配一个变量
2.在一个合适的时间创建space对象
3.在一个合适的时间销毁space对象
space对象必须在模型构建起来的时候创建;
也就是说,begin方法被调用时,它会在buildModel里被触发。
但是奇怪的是,它也会在这会儿被销毁。
讲白了就是我一运行,space对象就被销毁了,这不坑爹嘛!
所以我们需要在model对象里加一些代码,这些代码生成一个对象变量,它可以维持住space对象,让它不会那么快就挂了;
我们需要在setup方法中设置这个变量的值为null,并且需要在buildModel方法中创建space对象。
听懂没?
10.初始化Space对象
我们现在需要存一些钱,放在网格里。
这需要为CarryDropSpace对象创建一个新方法,用来在对象空间objectSpace周围随机的在网格里放一些钱。
在对象空间被创建后不久这个方法就会被立即调用,在buildModel方法里调用。
还有这个方法的具体实现过程:
下面简单解释一下这段代码:
11.小小的跑题—取钱
事实上,部分spreadMoney方法里的代码的用处可能远不止散钱这么简单;
因此我们把几行代码单独提出来放到一个新的方法里。
很不幸的,刚写好的代码又要改了:
自习体会一下,这么写是不是更简洁易懂了?
貌似没有。
但是扩展性就强了。
12.一些可见输出
概念上说,我们继续谈论model部分是有意义的,我们已经创建了环境,但是没有主体和行为(agentsandactions)。
但是,如果我们开始创建图形显示界面,很多部分我们会越来越清晰。
这就是RePast其中一个非常方便的地方,但是依然有些小问题需要注意。
首先我们要定义我们的目标:
说到现在我们都还没实现二维网格的可视化呢。
背景是白色的;
格子里的钱应该是能看见的(如果有的话),意思就是钱的颜色应与背景颜色不同。
为了实现这些,我们需要使用三个预先构建好的RePast对象:
DisplaySurface,Value2DDisplay,和ColorMap.
DisplaySurface对象是基本的窗口。
一个ColorMap对象是特定值到特定颜色间的单映射,比如0是黑色,1是暗红,2是亮红,3是更加亮的红,通过颜色的深浅可以显示出网格里的数量多少(很直观不是么?
但是可惜的是网格太小了,颜色差异不易区分)。
Value2DDisplay是一个对象,它连接了一个地图和你模型中要显示的值相对应,它连接了窗体,功能函数,颜色地图于一身。
为了使用这些对象我们必须:
创建一个DisplaySurface类型的变量来储存它
1.在setup方法里,撤销一个displaysurface,这通过执行dispose方法来实现(但是只要对象被实例化了,对object!
=null进行测试就是合适的),然后设置对象值为null
2.实例化一个新的displaysurface;
为了实现这个目的你必须传递两个参数:
a)displaysurface将要服务的模型对象
b)被创建的displaysurface的名字(这将出现在窗体的标题栏里)
3.注册displaysurface,告诉RePast它的存在,并且让RePast知道它的名字
4.创建一个colormap并指定初始值
5.创建一个Value2DDisplay对象来连接我们想要设置的值的集和colormap
6.把Value2DDisplay对象加到DisplaySurface对象中去
听起来很复杂,其实做起来容易,但是仍然有许多小的步骤,所以我们慢慢来。
DisplaySurface对象的变量将在变量域声明;
撤销displaysurface,重新实例化它,注册,这几步都在setup方法中完成,看下图(注意到有新的import语句!
)。
注意创建displaysurface对象的参数是’this’,这就是说,运行setup方法的model对象将把它自己作为参数传递给displaysurface。
在CarryDropModel.java中加入新代码:
13.创建一个ColorMap
干嘛要创建一个colormap,前文书已经