运行蚂蚁。跑

本文讨论了在模拟环境“ AnyLogic” 中创建蚁群行为的模拟模型(可以在Wikipedia上阅读)的过程。本文是实用的。它将考虑使用ant算法解决旅行商问题(您可以在此处阅读)。



简要介绍精华


旅行推销员问题的实质是,旅行推销员(卖方)必须沿着最短的路线仅对N个城市进行一次访问,然后再访问N个城市。由于此任务是NP复杂的,并且将N个城市之间所有可能路线的选项数量计算为“ N!”,因此最短路线搜索时间将随着N的增加呈指数增加。因此,使用该算法的最短路线(解决方案)搜索时间N> 16的城市数量的“穷举搜索”(提供精确的解决方案)急剧增加(呈指数增长)。因此,我们将不会搜索长度最短的路线,而是使用“蚂蚁算法”在有限时间内接近(合理)路线。

关于AnyLogic的几句话是一个功能强大的工具,可让您创建复杂程度各异的仿真模型。它实现了各种模拟方法。我们将仅分析一种方法,即“代理”建模。它是用Java编程语言实现的,它是对现有工具的补充。“ AnyLogic”的主要缺点是免费版本限制了已创建代理的数量;代理数量不能超过50,000;“ Agent”是AnyLogic仿真系统的基本单位。可以在网站www.anylogic.ru上找到更多信息。

工具类


1. Anylogic-从此处下载免费版本www.anylogic.ru/downloads
AnyLogic初始介绍:

AnyLogic界面如图1所示。它包括:
  • 绿色区域是我们将在其中创建代理的空间;
  • 红色区域-焦点对准的对象的属性;
  • 调色板-创建模型时可以使用的工具;
  • 项目-所开发模型的结构。



图。1- AnyLogic弹出窗口

项目创建


这里的一切都很简单。单击“创建”旁边的“文件”菜单项,然后单击“模型”,输入模型名称,然后单击“完成”按钮(图2)。


图。2-建立模型

创建城市


好吧,让我们开始吧。我们要做的第一件事是创建蚂蚁将要参观的所谓的城市(图的顶部)。我们为什么要打开调色板中的“ Agent”选项卡,然后将带有小矮人的红色圆圈从那里拖到“ Main”代理中,如图3


所示。 3-创建城市

释放鼠标按钮后,将出现一个对话框(“步骤1”),提示您创建座席。在需要选择“特工人口”项并单击“下一步”按钮的地方。


图。 4-创建城市

以下对话框出现(第2步),您需要在其中输入新座席类型的名称和座席人口的名称。输入类型“ MyTown”和人口名称“ myTowns”,然后单击“下一步”按钮。


图。 4a-输入新代理的名称

然后将出现以下窗口(步骤4)。在这里,我们选择“ 2D Agent Animation”和带有“ Plant”字样的图标,然后单击“ Finish”按钮(图5)。


图。 5-为代理添加动画

现在创建一个变量,该变量将确定模型中城市的初始数量。为什么将带有铭文“ Variable”的图标从“调色板”中拖到代理“ Main”中,并输入其名称“ numberTown”。接下来,单击变量的图标,然后在“属性”选项卡中,输入其初始值,例如等于10,然后选择其类型“ int”(图6)。


图。 6-创建变量

现在,我们将城市人口的初始值设置为“ myTowns”,为此,请单击其图标,然后在“属性”选项卡中的“代理的初始数量”字段中输入我们先前创建的变量的名称(图7)。


图。7-更改“ myTowns”人口的属性接下来,

我们将随机地在“主要”代理中得出我们城市结论。该空间限制为400x400像素的正方形。为什么在“项目”选项卡中用鼠标选择“主”代理,并在“属性”选项卡的“启动时”字段中添加以下Java代码(图7a):
for (int i=0; i<myTowns.size(); i++) {
	myTowns.get(i).setXY(uniform(0,400), uniform(0,400));
}

哪里:
  • myTowns.size()-创建的城市数;
  • myTowns.get(i).setXY(均匀(0.400),均匀(0.400))-设置第i个城市的X和Y坐标;
  • 统一(0,400)-根据随机变量的等概率分布定律返回从0到400范围内的随机数的函数。AnyLogic环境具有用于处理各种随机变量分布的广泛工具包。工具栏提供了一个内置的概率分布构造函数。

哪里:
  • myTowns.size()-创建的城市数;
  • myTowns.get(i).setXY(均匀(0.400),均匀(0.400))-设置第i个城市的X和Y坐标;
  • uniform(0,400) – , 0 400 . AnyLogic . .



图。7a-我们安排了城市,

然后我们已经可以看到我们所做的事情并开始我们的模型。为此,使用“ F5”键,单击它,然后启动用于启动实验的窗口,如图8


所示。8-开始实验

接下来,单击窗口左下角的“运行”按钮,实验开始。您应该在屏幕上得到一个包含其内容的窗口,如图9


所示。9-实验的结果

因此,在此步骤中,我们创建了10个城市,并将它们放置在屏幕上的随机(随机)位置。现在让我们继续创建“蚂蚁”

创建一只蚂蚁


因此,我们模型的主要作战单位将是一只蚂蚁。我们必须首先创建它,然后对其行为建模。

创建蚂蚁类似于创建城市。在“面板”中,选择“代理”并将其拖动到“主”。选择“填充代理”,然后选择“我要创建新的代理类型”,然后输入“新类型的名称”和“填充名称”,“ MyAnt”,“ myAnts”,然后单击“下一步”。之后,我们选择“ 2D”动画,例如,带有铭文“ Fighter”的图标按“ Finish”,结果应如图10


所示。 10-创建蚂蚁

同意,飞机看起来不像蚂蚁,因此我们将对其进行修复。我们进入搜索引擎,寻找描述蚂蚁的图片,然后将飞机更改为蚂蚁。为什么我们双击“ myAnts”附近的红色圆圈。之后,“ myAnt”选项卡将打开,您需要在其中移除飞机并将蚂蚁放置在其位置(图11)。


图。 11-MyAnt选项卡

用鼠标选择平面,然后按“ Del”。接下来,转到“演示文稿”选项卡,然后从此处拖动“图像”元素。之后,将自动打开一个对话框以选择文件。用我们的蚂蚁选择文件(图12),然后单击OK。


图。 12-MyAnt选项卡上有蚂蚁,已经没有飞机了

继续。缩放蚂蚁并将其移动到飞机曾经所在的地方。结果应该如图12a所示。所有这些操作都是使用鼠标执行的。


图。12a-带蚂蚁的MyAnt标签

我们使蚂蚁复活


现在我们需要教我们新鲜出炉的蚂蚁在城市之间爬行。没错,到目前为止,没有考虑数学模型,但仍然让它运行。因此,在“面板”中打开“状态图”图,然后继续。我们传输以下块并将它们连接在一起:
  • 状态图的开始是我们蚂蚁生命周期的起点;
  • 状态-此区块将描述蚂蚁生命周期的状态。此类块是必需的。
  • 过渡-箭头,它将使我们的“州”彼此连接,并在某些条件下执行从一个“州”到另一个“州”的过渡。

结果,结果应该如图13


所示。13-蚂蚁行为的逻辑

现在让我们编写蚂蚁图的初始逻辑。我们用鼠标选择在“选择城市”名称下退出该街区的箭头,并在“属性”选项卡的“操作”字段中添加以下代码(图14):
for (int i=0; i<main.myTowns.size(); i++) {
	if (randomTrue(0.5)) {
		this.moveTo(main.myTowns.get(i));
		break;
	} 
}

这里的一切都很简单,我们在所有城市中进行循环并抛硬币(我们生成概率为0.5的随机变量),如果其值为true(鹰),则将蚂蚁发送到该城市,离开循环。表达式“ this.moveTo(main.myTowns.get(i))”是将一个代理发送到另一个代理的函数。


图。 14-设置蚂蚁运动的初始逻辑

,然后单击离开“运动”块的箭头,然后在“属性”选项卡的“出现”字段中,设置值“一旦收到消息”,然后在“出现”字段中选择“一旦收到指定消息”。 »如图15


所示。 15-设置“运动”和“超越一切”之间的过渡逻辑

现在,配置“运动”块中出现的最后一个箭头。我们用鼠标选择它,然后在“属性”选项卡的过渡字段中,设置“代理到达时”。“状态图”的最终视图应如图16


所示。16-在块之间配置了过渡的状态图

让我们看一下蚂蚁行为的“状态图”如何工作:
  1. 蚂蚁掉落的第一个状态是“ Vybor_city”,到目前为止,还没有阐明任何动作。
  2. 然后他在过渡时进入下一个状态。在此过渡中,我们添加了一个代码,该代码开始在所有山脉之间循环,并使蚂蚁在城市周围奔跑。
  3. “运动”块是蚂蚁所在的位置,直到它到达先前选择的城市为止。
  4. 此外,他有两种方法。首先,他返回到块“ City_Choice”,然后再次重复所有操作。在第二条道路上,他已经参观了所有城市之后将不得不走。到目前为止,第二种方法尚未与我们建立。我们待会儿再处理。



图。17-状态图的操作

现在我们可以按“ F5”键查看发生的情况(图18)。


图。18-蚂蚁的复兴

定义标准


那么,这些标准是什么(规则):
  1. 一只蚂蚁只能参观每个城市一次。
  2. 蚂蚁参观了所有城市,结束了他在最后一个城市的运动。

这些标准是由旅行商问题决定的。每只蚂蚁都会和我们一起在城市旅行的推销员。

让我们教蚂蚁遵守这些规则。为什么从“调色板”的“代理”选项卡将“集合”和“变量”转移到“ MyAnt”选项卡,然后将它们首先命名为“ isVisited”,然后将其命名为“ distance”。第一个考虑到我们已经访问过的城市,第二个考虑到蚂蚁走过的距离。


图。 19-添加变量

设置isVisited集合。为什么我们用鼠标选择它,然后在“属性”选项卡中设置“ int”元素的“类型”,如图20所示。
对于其属性中的“距离”变量,在“初始值”字段中,设置“ 0”,变量类型为“双精度” ”。


图。 20-类型“ int”的集合

现在,选择离开“ City_block”块的箭头,并将“动作”字段中的代码更改为以下代码:
for (int i=0; i<main.myTowns.size(); i++) {
	if (randomTrue(0.9) && isVisited.indexOf(i)==-1) {
		this.moveTo(main.myTowns.get(i));
		distance=distance+this.distanceTo(main.myTowns.get(i));
		isVisited.add(i);
		break;
	} 
}

在上面的代码中,我们添加了对我们已经设法访问过的城市的检查,并考虑了我们访问过的城市,并考虑了行驶的距离。代码很简单,我认为您不会很难理解。

您可以尝试启动“ F5”我们的模型,看看发生了什么。现在,蚂蚁将只穿过所有城市一次,并在街区中完成移动。

更改蚂蚁的初始位置


在这一步,我们将为每只蚂蚁确定我们将随机选择一个城市作为他开始旅程的城市。为什么在“项目”选项卡上用鼠标选择“主”代理,然后在“属性”选项卡中将以下代码添加到“启动时”字段中(图20a):
for (int i=0; i<myAnts.size(); i++) {
	//        
	int startTown = uniform_discr(0,myTowns-1);
	//     
	myAnts.get(i).setPosition(myTowns.get(startTown));
	//      
	myAnts.get(i).isVisited.add(startTown);
}



图。20a-按城市排列蚂蚁

我对初始城市进行了随机选择。您最初只能识别一个城市中的所有蚂蚁。

使蚂蚁变幻莫测


让我们在模型中引入以下公式:



其中Pi是沿第i条路径的路径过渡的概率,li是第i条过渡的长度,fi是第i条过渡的信息素量,q是确定算法“贪婪”的值,p -确定算法“群数”的值,其中q + p = 1。

我从现场借了这个公式

简而言之,该公式使您可以计算出蚂蚁必须过渡到特定城市的概率。

现在我们需要添加几个变量,如果没有这些变量我们将无法做到。为什么回到图21的“ Main”选项卡


。 21-标签“主要”

因此,我们添加了变量“ numberAnt”,其中将存储蚁群的大小。我们将其类型设置为“ int”,初始值为100


。 21-变量“ numberAnt”

接下来,选择总体“ myAnts”,并将“代理的初始数量”字段设置为“ numberAnt”。

变量“ p”,它将确定算法的遗传。其类型为double,初始值为0.5。

变量“ q”,它将确定算法的贪婪程度。其类型为double,初始值为0.5。


图。 22-变量“ q和p”

因此,现在我们将为城市之间的每个边缘(道路)设置一个随机信息素值。为什么要创建变量(二维数组)“ matrixF”。在“类型”(Type)字段的“属性”(Properties)选项卡中进行设置,选择值“其他”(Other),然后在字段中写入“ double [] []”作为初始值“ new double [numberTown] [numberTown]”(图23)。


图。 23-创建一个二维数组“ matrixF”。信息素矩阵

接下来,我们需要初始化此矩阵。换句话说,用随机值填充它。我们在0.1到
1 的范围内随机获取信息素值。为此,在“项目”选项卡上,用鼠标选择“主”代理,然后在“属性”选项卡中将以下代码添加到“启动时”字段(图23a):
for (int i=0; i<myTowns.size(); i++) {
	for (int j=0; j<myTowns.size(); j++) {
		matrixF[i][j]=uniform(0.1,1);
	}
} 



图。

23a- 信息素矩阵的初始化代码现在,我们返回“ MyAnt”选项卡,并根据上述公式继续计算转移概率。选择“ City_Choice”和“ Motion”之间的过渡,并将“动作”字段中的代码更改为以下内容(图24):
//       
double denominator=0; 
//          
for (int i=0; i<main.myTowns.size(); i++) {
	if (isVisited.indexOf(i)==-1) {	//     
	    //  i   
		denominator=denominator+(Math.pow(this.distanceTo(main.myTowns.get(i)), main.q)*Math.pow(main.myTowns.get(i).f, main.p));
	} 
}
//      i 
double Pi=0;
//    
double probility=uniform(0,1);
for (int i=0; i<main.myTowns.size(); i++) {
	//        Pi
	if (isVisited.indexOf(i)==-1) {
		//     i-      
		Pi=Pi+(Math.pow(this.distanceTo(main.myTowns.get(i)), main.q)*Math.pow(main.myTowns.get(i).f, main.p))/denominator;
	}
	//      Pi      probility
	if (probility<Pi && isVisited.indexOf(i)==-1) {
		//       i  
		this.moveTo(main.myTowns.get(i));
		//     
		distance=distance+this.distanceTo(main.myTowns.get(i));
		//           
		isVisited.add(i);
		break;
	} 
}



图。24-我们根据上述分析表达式来设置蚂蚁的行为,

因此,我现在将解释一些含义:
  • li-this.distanceTo(main.myTowns.get(i)),蚂蚁当前位置和“ i”城市之间的长度值;
  • fi-main.matrixF [currentPos] [i],当前城市和城市“ i”之间的信息素水平值;
  • 分母-分母+(Math.pow(this.distanceTo(main.myTowns.get(i)),main.q)* Math.pow(main.matrixF [currentPos] [i],main.p));,分母皮
  • Pi-Pi +(Math.pow(this.distanceTo(main.myTowns.get(i),main.q)* Math.pow(main.myTowns.get(i).f,main.p))/分母,蚂蚁从当前城市移至城市“ i”的概率。

接下来,我们用鼠标选择“ Motion”和“ All-bypassed”块之间的过渡,并在“ Occurs”字段中选择“ When满足条件”,然后在条件字段中编写蚂蚁停止“ isVisited.size()== main.myTowns.size()”的条件。 (图25)。


图。25-确定停止蚂蚁的条件,

然后您可以运行“ F5”模型并查看发生了什么。蚂蚁将以上述解析表达式计算出的概率在城市之间旅行。

更新信息素的价值


现在让我们做两件事。第一步是增加蚂蚁经过的城市之间边缘的信息素值。第二个是城市之间边缘的信息素的蒸发,这包括相对于模拟时间减少信息素的值。

因此,从第一个动作开始,我们将更新蚂蚁所在的城市和他要去的城市之间的肋骨信息素的值。我们将非常非常简单地计算出用于增加城市之间信息素边的当前值的值。我们将信息素值的最大初始值设为1 cu然后将其除以蚂蚁所在的城市与他要去的城市之间的距离。因此,城市之间的距离越小,将增加肋骨的信息素水平的值越大。为什么要在“项目”选项卡中选择MyAnt代理,使用鼠标选择“ City_title”和“ Movement”块之间的过渡,然后将以下代码添加到操作字段:“ main.matrixF [currentPos] [i] = main.matrixF [currentPos] [i ] +1 / this.distanceTo(main.myTowns.get(i);”。结果应如图26所示


图。 26-更新蚂蚁经过的肋骨信息素水平的值

现在,我们继续执行步骤 2,并创建一个事件,该事件将模拟城市之间肋骨上信息素的蒸发。为什么在项目选项卡中选择“主”代理并在那里创建更多变量。第一个是“强度”-它将确定信息素蒸发的速率(强度)(初始值为“ 0.5”,键入“ double”)。第二个“部分”-将表征边缘上信息素的值减少的分数(初始值“ 0.9”,键入“ double”)。


图。 27-创建变量“强度”和“零件”

接下来,我们从“ Agent”选项卡的“ Palette”中获取“ Event”元素,并将其转移到“ Main”代理中,并将其称为“ evaporation”-该元素将模拟边缘信息素的蒸发。用鼠标单击它,然后在“事件类型”(Event Type)字段的“属性”(Properties)中,在“强度”(Intensity)字段中选择值“具有给定强度”(With有了给定强度),并写出存储“强度”强度值的变量的名称。响应时间为秒。接下来,将以下代码添加到操作中:
for (int i=0; i<myTowns.size(); i++) {
	for (int j=0; j<myTowns.size(); j++) {
		matrixF[i][j]=matrixF[i][j]*Part;
		if (matrixF[i][j]<0.1) matrixF[i][j]=0.1;
	}
}

当触发“蒸发”事件时,MatrixF矩阵中的信息素水平将被更新。结果,您应该能够如图28


所示。28-创建“蒸发”事件

确定获胜者


在这一步,我们将添加一个代码,该代码将确定我们的蚂蚁马拉松的赢家。获胜者将是路线最短的蚂蚁之一。除所有内容外,马拉松结束后,我们还在屏幕上绘制此路线。为此,我们将在“主”代理中创建三个变量“ bestAnt”,“ bestDistance”和“ numberFinish”。在变量“ bestAnt”中,我们将存储“最快”蚂蚁的索引,变量的类型将为“ int”,初始值将设置为“ -1”。在变量“ bestDistance”中,我们将存储城市之间最佳路线长度的当前值,变量的类型将为“ double”,初始值将设置为infinity“ infinity”。在变量“ numberFinish”中,我们将存储在马拉松比赛中完成的蚂蚁数量,变量的类型将为“ int”,初始值为“ 0”(图29)。


图。29-创建变量事件

接下来,我们创建一个函数,在完成所有蚂蚁之后,将绘制城市之间最佳路线的线。为什么将具有名称功能的元素从“调色板”中拖到代理“主”中。将函数名称设置为drawPath,然后在“属性”选项卡的函数正文字段中,添加以下代码:
//        
for (int i=0; i<myAnts.get(bestAnt).isVisited.size()-1; i++) {
	//    
	ShapeLine myLine = new ShapeLine();
	//            i
	myLine.setX(myTowns.get(myAnts.get(bestAnt).isVisited.get(i)).getX());
	myLine.setY(myTowns.get(myAnts.get(bestAnt).isVisited.get(i)).getY());
	//            i+1
	myLine.setEndX(myTowns.get(myAnts.get(bestAnt).isVisited.get(i+1)).getX());
	myLine.setEndY(myTowns.get(myAnts.get(bestAnt).isVisited.get(i+1)).getY());
	//    ""
	myLine.setColor(blue);
	//   
	myLine.setLineStyle(LINE_STYLE_SOLID );
	//   
	myLine.setLineWidth(1);
	//    
	presentation.add(myLine);	
}
	//           
	ShapeLine myLine = new ShapeLine();
	myLine.setX(myTowns.get(myAnts.get(bestAnt).isVisited.get(myAnts.get(bestAnt).isVisited.size()-1)).getX());
	myLine.setY(myTowns.get(myAnts.get(bestAnt).isVisited.get(myAnts.get(bestAnt).isVisited.size()-1)).getY());
	myLine.setEndX(myTowns.get(myAnts.get(bestAnt).isVisited.get(0)).getX());
	myLine.setEndY(myTowns.get(myAnts.get(bestAnt).isVisited.get(0)).getY());
	myLine.setColor(blue);
	myLine.setLineStyle(LINE_STYLE_SOLID );
	myLine.setLineWidth(1);
	presentation.add(myLine);

结果,您应该能够如图29a所示。


图。29a-创建“ drawPath”函数

现在我们回到蚂蚁并添加一个代码,该代码将确定获胜者的蚂蚁,最佳路线的长度并在城市之间绘制此路线。为什么在“项目”选项卡中选择“ MyAnt”代理,然后选择“所有绕过”块并将以下代码添加到“登录操作”字段中:
//    
main.numberFinish++;
//      
if (main.bestDistance>distance) {
	//           
	//      
	main.bestDistance=distance;
	//    
	main.bestAnt = this.getIndex();
}
//         Main   
if (main.numberFinish==main.myAnts.size()) main.drawPath();

结果应该如图30


所示。30-在“所有绕过”块中添加逻辑,

然后可以按“ F5”并运行模型。蚂蚁会四处寻找路线,当城市结束时,蓝线将连接起来,这是最佳路线。

向模型添加直方图


为了使模型更加科学,必须添加图形。因此,我们将不仅添加图形和直方图,还可以向我们显示蚂蚁克服的路径长度的分布。为什么在选项卡“项目”中选择代理“主”并转到其空间。此外,在“面板”中,我们转到“统计信息”选项卡,然后从那里到“主”代理,我们传输“直方图数据”元素,并直接传输“直方图”本身。然后,我们使用鼠标选择直方图,然后在“属性”标签中的“数据”字段中,指定“直方图数据”的名称,即“数据”。

结果应该如图31所示


。 31-建立时间表

之后,我们将再次返回到蚂蚁并使其充满路线长度值的``直方图''。为什么在项目选项卡中选择代理“ MyAnt”并转到其空间。接下来,选择“ All Bypass”块,并在其中添加一行“ main.data.add(distance);”。结果应该如图32


所示。32-构建图形

接下来,按“ F5”,然后继续研究ant算法的行为。结果应该如图33


所示。33-建模

结论


最后,我建议为模型添加更多的不可预测性。为此,在“ Projects”选项卡中,用鼠标选择“ Simulation:Main”元素,然后在“ Properties”选项卡中将“ Randomness”参数设置为“ Random initial number(unique run)”-这将使每个模型启动都是唯一的(图34)。


图。34-随机运行

谢谢您的关注!可以从GitHub下载源代码

All Articles