数学建模常用算法:人工鱼群算法(AFAS)求解二元函数最小值+限定x,y范围测试【java实现--详细注释+Matlab绘制小鱼游动过程】
一、代码
鱼类
package com.dam.heuristic.afas.test;import java.io.Serializable;
import java.util.Random;/*** 人工鱼*/
public class Fish implements Serializable {//记录位置的维度(x,y,z,……)private int dimension;//记录位置private double[] position;//鱼的适应度private double fitness;//位置每个维度坐标的区间private double[][] axisScopeArr;//目标函数是否为取最大值private boolean isGetMax;public Fish(int dimension, double[][] axisScopeArr, boolean isGetMax) {this.dimension = dimension;this.position = new double[this.dimension];this.axisScopeArr = axisScopeArr;this.isGetMax = isGetMax;this.fitness = 0;}/*** 初始化鱼的位置及适应度*/public void initFishMessage() {Random random = new Random();//初始化位置for (int i = 0; i < this.dimension; i++) {position[i] = random.nextDouble() * (this.axisScopeArr[i][1] - this.axisScopeArr[i][0]) + this.axisScopeArr[i][0];}//初始化适应度this.fitness = new ObjectFunction().objectFunction(position,this.isGetMax);}public int getDimension() {return dimension;}public void setDimension(int dimension) {this.dimension = dimension;}public double[] getPosition() {return position;}public void setPosition(double[] position) {this.position = position;}public double getFitness() {return fitness;}public void setFitness(double fitness) {this.fitness = fitness;}}
目标函数类
package com.dam.heuristic.afas.test;public class ObjectFunction {/*** 目标函数* 由于所举例子的目标函数的目标是最小化,适应度则是越大越好,因此这里需要取负值** @param position* @param isGetMax 是否获取函数的最大值* @return*/public double objectFunction(double[] position, boolean isGetMax) {//目标:在变量区间范围最小化 y=x^2+y^2-xy-10x-4y+60double value = Math.pow(position[0], 2) + Math.pow(position[1], 2) - position[0] * position[1] - 10 * position[0] - 4 * position[1] + 60;if (isGetMax == false) {return -value;} else {return value;}}
}
算法类
package com.dam.heuristic.afas.test;import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;public class AfasApi {//鱼群中鱼的数量private int fishNum;//尝试次数,该数越大,鱼的觅食能力越强,收敛速度越快private int tryNum;//维度private int dimension;//鱼的移动步长private double stepLen;//拥挤度因子(delta=1/(random.nextDouble()*maxFishNum):maxFishNum为鱼的视野范围内最大的鱼的总数量)//当delta越大时,拥挤程度越小,鱼更难聚在一起,因此容易跳出局部最优,但是也会让其他鱼不想过来,造成找到的解不能精确逼近最优解private double delta;//鱼的视野范围private double visual;//迭代次数private int genNum;//目标函数是否为取最大值private boolean isGetMax;//位置每个维度坐标的区间private double[][] axisScopeArr;public AfasApi(int fishNum, int tryNum, double stepLen, double delta, double visual, int genNum, boolean isGetMax, double[][] axisScopeArr) {this.fishNum = fishNum;this.tryNum = tryNum;this.dimension = axisScopeArr[0].length;this.stepLen = stepLen;this.delta = delta;this.visual = visual;this.genNum = genNum;this.isGetMax = isGetMax;this.axisScopeArr = axisScopeArr;}public double[][][] solve() {变量声明long start = System.currentTimeMillis();//鱼群Fish[] fishArr;//最好的鱼Fish bestFish;//存储觅食、聚群、追尾所找到的最优鱼Fish[] nextFishArr;//随机数工具类Random random = new Random();//目标函数类ObjectFunction objectFunction = new ObjectFunction();//存储每一代鱼所在位置double[][][] positionArr = new double[this.genNum][this.fishNum][this.dimension];初始化鱼群//初始化最优鱼bestFish = new Fish(this.dimension, this.axisScopeArr, isGetMax);//初始化最优鱼的适应度为很小的值,说明当前最优鱼不咋的bestFish.setFitness(-Double.MAX_VALUE);fishArr = new Fish[this.fishNum];for (int i = 0; i < this.fishNum; i++) {//创建鱼fishArr[i] = new Fish(this.dimension, this.axisScopeArr, isGetMax);//初始化鱼的位置及适应度fishArr[i].initFishMessage();//更新初始最优鱼if (fishArr[i].getFitness() > bestFish.getFitness()) {bestFish = (Fish) deepClone(fishArr[i]);}}//初始化(觅食、聚群、追尾)所找到的最优鱼数组,三种方式nextFishArr = new Fish[3];求解for (int t = 0; t < this.genNum; t++) {for (int i = 0; i < this.fishNum; i++) {// System.out.println("找位置--------------------------------------------------------------------------");//自己出门觅觅食,万一找到什么好地方就爽了this.foraging(fishArr, nextFishArr, i, random, objectFunction, 0);//找到第i条鱼视野范围内的小鱼群List<Fish> fishNearingFishIList = this.findFishArrNearFishI(i, fishArr);//如果鱼群的中间吃的比较多,又不太挤,就跟着去看看this.cluster(fishArr, nextFishArr, i, fishNearingFishIList, random, objectFunction);//看一下哪条小鱼仔吃得比较好,旁边的地方又不太挤,就跟着去看看this.follow(fishArr, nextFishArr, i, fishNearingFishIList, random, objectFunction);//汇总一下信息,根据所找到的位置选择出最好的位置,再决定去不去this.upDateFishPositionAndBestFish(fishArr, nextFishArr, i, bestFish);positionArr[t][i] = fishArr[i].getPosition();}}//如果函数求的是最小值,要取负值,因为算法是根据将目标函数取负号并以目标为求最大值来进行求解double fitness = this.isGetMax == false ? -bestFish.getFitness() : bestFish.getFitness();System.out.println("最优目标函数值:" + String.format("%.6f", fitness));System.out.println("最优位置:" + Arrays.toString(bestFish.getPosition()));System.out.println("求解时间:" + (System.currentTimeMillis() - start) + "ms");return positionArr;}/*** 觅食** @param index 由于聚群,追尾时找不到好位置的话,也要觅食,用index来控制所找位置的填充参数*/private void foraging(Fish[] fishArr, Fish[] nextFishArr, int i, Random random, ObjectFunction objectFunction, int index) {//该鱼的下一可能位置double[] nextPositionOfThisFish = new double[this.dimension];//存储所寻找的最优位置Fish bestPositionOfThisFish = new Fish(this.dimension, this.axisScopeArr, isGetMax);bestPositionOfThisFish.setFitness(-Double.MAX_VALUE);// 进行this.tryNum次尝试觅食,选择一个比较好的位置for (int j = 0; j < this.tryNum; j++) {//让鱼在视野范围内随意走动一下for (int k = 0; k < this.dimension; k++) {nextPositionOfThisFish[k] = fishArr[i].getPosition()[k] + (2 * (random.nextDouble()) - 1) * this.visual;}//修正一下位置this.fixPosition(nextPositionOfThisFish, this.axisScopeArr);//计算一下所走动到的位置的食物如何,即适应度如何double nextPositionFitness = objectFunction.objectFunction(nextPositionOfThisFish, this.isGetMax);if (nextPositionFitness > fishArr[i].getFitness()) {double distance = this.getDistanceOfTwoPositions(fishArr[i].getPosition(), nextPositionOfThisFish);for (int k = 0; k < this.dimension; k++) {//fishArr[i].getPosition()[k]:鱼的当前坐标//(nextPositionOfThisFish.getPosition()[k] - fishArr[i].getPosition()[k]) / distance:该方向走的步长/两位置距离(可以结合直角三角形的投影关系进行理解)//this.stepLen * random.nextDouble():虽然一步可以走这么远,但是鱼不一定要竭尽全力地游,* random.nextDouble()可以让鱼在自己的大长腿范围内随机走一段距离bestPositionOfThisFish.getPosition()[k] =fishArr[i].getPosition()[k] +((nextPositionOfThisFish[k] - fishArr[i].getPosition()[k]) / distance)* this.stepLen * random.nextDouble();}//设置新位置的适应度bestPositionOfThisFish.setFitness(objectFunction.objectFunction(bestPositionOfThisFish.getPosition(), this.isGetMax));}}//存储觅食找到的最优位置nextFishArr[index] = bestPositionOfThisFish;
// System.out.println("通过觅食找到更优位置" + bestPositionOfThisFish.getFitness());}/*** 聚群** @param fishArr* @param nextFishArr* @param i* @param random* @param objectFunction*/private void cluster(Fish[] fishArr, Fish[] nextFishArr, int i, List<Fish> fishNearingFishIList, Random random, ObjectFunction objectFunction) {//存储所寻找的最优位置Fish bestPositionOfThisFish = new Fish(this.dimension, this.axisScopeArr, this.isGetMax);bestPositionOfThisFish.setFitness(-Double.MAX_VALUE);//鱼群的中心位置double[] centerPosition = new double[this.dimension];for (int k = 0; k < this.dimension; k++) {centerPosition[k] = 0;}if (fishNearingFishIList.size() > 0) {//计算小鱼群的中心位置for (int j = 0; j < fishNearingFishIList.size(); j++) {for (int k = 0; k < this.dimension; ++k) {centerPosition[k] += fishNearingFishIList.get(j).getPosition()[k];}}//人工鱼的中心位置(各维度位置的平均值)for (int k = 0; k < this.dimension; k++) {centerPosition[k] /= fishNearingFishIList.size();}//修正一下位置this.fixPosition(centerPosition, this.axisScopeArr);//求中心位置的适应度double centerPositionFitness = objectFunction.objectFunction(centerPosition, this.isGetMax);//求中心位置离第i条鱼的距离double distance = this.getDistanceOfTwoPositions(fishArr[i].getPosition(), centerPosition);//centerPositionFitness / fishNearingFishIList.size() > this.delta * fishArr[i].getFitness():看一下要去的地方性价比怎么样//就算那里伙食很好,住宿条件不太行(鱼太多,贼拥挤),小鱼鱼也懒得去if (centerPositionFitness > fishArr[i].getFitness()&& centerPositionFitness / fishNearingFishIList.size() > this.delta * fishArr[i].getFitness()) {for (int k = 0; k < this.dimension; k++) {bestPositionOfThisFish.getPosition()[k] = fishArr[i].getPosition()[k] +((centerPosition[k] - fishArr[i].getPosition()[k]) / distance)* this.stepLen * random.nextDouble();}//设置新位置的适应度bestPositionOfThisFish.setFitness(objectFunction.objectFunction(bestPositionOfThisFish.getPosition(), this.isGetMax));//存储聚群找到的最优位置nextFishArr[1] = bestPositionOfThisFish;
// System.out.println("通过聚群找到更优位置" + bestPositionOfThisFish.getFitness());} else {//找到的中心位置不咋地,不如自己出去觅食this.foraging(fishArr, nextFishArr, i, random, objectFunction, 1);}} else {//附近找不到鱼群,只能继续觅食了this.foraging(fishArr, nextFishArr, i, random, objectFunction, 1);}}/*** 追尾行为** @param fishArr* @param nextFishArr* @param i* @param random* @param objectFunction* @throws IOException*/private void follow(Fish[] fishArr, Fish[] nextFishArr, int i, List<Fish> fishNearingFishIList, Random random, ObjectFunction objectFunction) {//存储所寻找的最优位置Fish bestPositionOfThisFish = new Fish(this.dimension, this.axisScopeArr, isGetMax);bestPositionOfThisFish.setFitness(-Double.MAX_VALUE);if (fishNearingFishIList.size() > 0) {//存储最优邻居鱼Fish bestNeighbourFish = new Fish(this.dimension, this.axisScopeArr, isGetMax);//存储最优邻居鱼对应的索引int bestNeighbourFishIndex = i;//找邻居中适应度最高的那条鱼for (int j = 0; j < fishNearingFishIList.size(); j++) {if (fishNearingFishIList.get(j).getFitness() > bestNeighbourFish.getFitness()) {bestNeighbourFish.setPosition(fishNearingFishIList.get(j).getPosition().clone());bestNeighbourFishIndex = j;}}//修正一下坐标this.fixPosition(bestNeighbourFish.getPosition(), this.axisScopeArr);if (bestNeighbourFish.getFitness() < fishArr[i].getFitness()) {//邻居鱼不咋地,还是自己去觅食吧this.foraging(fishArr, nextFishArr, i, random, objectFunction, 2);} else {//找到最优邻居鱼旁边的鱼群List<Fish> fishArrNearBestNeighbourFish = this.findFishArrNearFishI(bestNeighbourFishIndex, fishArr);if (fishArrNearBestNeighbourFish.size() > 0 &&bestNeighbourFish.getFitness() / fishArrNearBestNeighbourFish.size() > this.delta * fishArr[i].getFitness()) {//求第i条鱼和最优邻居鱼之间的距离double distance = this.getDistanceOfTwoPositions(fishArr[i].getPosition(), bestNeighbourFish.getPosition());for (int k = 0; k < this.dimension; k++) {bestPositionOfThisFish.getPosition()[k] = fishArr[i].getPosition()[k]+ ((bestNeighbourFish.getPosition()[k] - fishArr[i].getPosition()[k]) / distance)* this.stepLen * random.nextDouble();}//设置新位置的适应度bestPositionOfThisFish.setFitness(objectFunction.objectFunction(bestPositionOfThisFish.getPosition(), this.isGetMax));//存储追尾找到的最优位置nextFishArr[2] = bestPositionOfThisFish;
// System.out.println("通过追尾找到更优位置" + bestPositionOfThisFish.getFitness());} else {this.foraging(fishArr, nextFishArr, i, random, objectFunction, 2);}}} else {this.foraging(fishArr, nextFishArr, i, random, objectFunction, 2);}}/*** 更新第i条鱼的位置,同时更新最优的鱼** @param fishArr* @param nextFishArr* @param i* @param bestFish*/private void upDateFishPositionAndBestFish(Fish[] fishArr, Fish[] nextFishArr, int i, Fish bestFish) {for (int j = 0; j < nextFishArr.length; j++) {if (nextFishArr[j].getFitness() > fishArr[i].getFitness()) {fishArr[i].setPosition(nextFishArr[j].getPosition());fishArr[i].setFitness(nextFishArr[j].getFitness());}if (nextFishArr[j].getFitness() > bestFish.getFitness()) {// System.out.println("更新最优解");bestFish.setPosition(nextFishArr[j].getPosition());bestFish.setFitness(nextFishArr[j].getFitness());}}}/*** 找一下附近有哪些鱼鱼** @param i* @return*/private List<Fish> findFishArrNearFishI(int i, Fish[] fishArr) {List<Fish> fishNearingFishIList = new ArrayList<>();for (int j = 0; j < this.fishNum; j++) {if (this.getDistanceOfTwoPositions(fishArr[i].getPosition(), fishArr[j].getPosition()) < this.visual) {fishNearingFishIList.add(fishArr[j]);}}return fishNearingFishIList;}/*** 获取两个位置之间的距离** @param position1* @param position2*/private double getDistanceOfTwoPositions(double[] position1, double[] position2) {double distance = 0;for (int i = 0; i < position1.length; i++) {distance += Math.pow((position1[i] - position2[i]), 2);}return Math.sqrt(distance);}/*** 对位置进行限制,限制再变量区间内** @param position*/private void fixPosition(double[] position, double[][] axisScopeArr) {for (int i = 0; i < position.length; i++) {//让坐标处于区间内if (position[i] > axisScopeArr[i][1]) {position[i] = axisScopeArr[i][1];} else if (position[i] < axisScopeArr[i][0]) {position[i] = axisScopeArr[i][0];}}}/*** 深拷贝对象** @param srcObject* @return*/private Object deepClone(Object srcObject) {ByteArrayOutputStream bos = null;ObjectOutputStream oos = null;ByteArrayInputStream bis = null;ObjectInputStream ois = null;Object result = null;try {bos = new ByteArrayOutputStream();oos = new ObjectOutputStream(bos);//将对象写到流里oos.writeObject(srcObject);//从流里读回来bis = new ByteArrayInputStream(bos.toByteArray());ois = new ObjectInputStream(bis);result = ois.readObject();} catch (Exception e) {e.printStackTrace();} finally {try {bos.close();oos.close();bis.close();ois.close();} catch (IOException e) {e.printStackTrace();}}return result;}}
二、测试
package com.dam.heuristic.afas.test;import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;public class AfasMainRun {public static void main(String[] args) {//变量的区间double[][] axisScopeArr = {{-1000, 1000},{-1000, 1000}};AfasApi afasApi = new AfasApi(50, 50, 5, 0.2, 5, 1000, false, axisScopeArr);double[][][] position = afasApi.solve();//创建WorkBookWorkbook workbook = new XSSFWorkbook();Sheet xData = workbook.createSheet("xData");Sheet yData = workbook.createSheet("yData");//获取每一代,每一个粒子的x坐标CellStyle cellStyle = workbook.createCellStyle();//设置居中cellStyle.setAlignment(XSSFCellStyle.ALIGN_CENTER);for (int i = 0; i < position.length; i++) {Row xRow = xData.createRow(i);Row yRow = yData.createRow(i);for (int j = 0; j < position[0].length; j++) {Cell xCell = xRow.createCell(j);xCell.setCellValue(position[i][j][0]);//设置数据类型xCell.setCellType(XSSFCell.CELL_TYPE_NUMERIC);//设置居中xCell.setCellStyle(cellStyle);Cell yCell = yRow.createCell(j);yCell.setCellValue(position[i][j][1]);//设置数据类型yCell.setCellType(XSSFCell.CELL_TYPE_NUMERIC);//设置居中yCell.setCellStyle(cellStyle);}}try {FileOutputStream fileOutputStream = new FileOutputStream(new File("D:\\Desktop\\paintData.xlsx"));workbook.write(fileOutputStream);fileOutputStream.close();System.out.println("存储文件完成");} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}
最优目标函数值:8.000012
最优位置:[8.00392710826662, 6.001480250477476]
求解时间:283ms
三、Matlab绘图
具体绘图方法可以参照文章数学建模常用算法:粒子群算法(PSO)求解二元函数最小值+限定x,y范围测试【java实现–详细注释+Matlab绘制粒子群飞行过程】
数学建模常用算法:人工鱼群算法(AFAS)求解二元函数最小值+限定x,y范围测试【java实现--详细注释+Matlab绘制小鱼游动过程】相关推荐
- 数学建模常用算法:粒子群算法(PSO)求解二元函数最小值+限定x,y范围测试【java实现--详细注释+Matlab绘制粒子群飞行过程】
代码 package com.dam.heuristic.pso.test;import java.util.List; import java.util.Random;public class Ps ...
- matlab球落点的数学建模,MATLAB数学建模:智能优化算法-人工鱼群算法
MATLAB 数学建模: 人工鱼群算法 1. 基本原理 人工鱼群算法是一种受鱼群聚集规律而启发的优化算法. 在人工鱼群算法中, 我们假定鱼群的活动行为分为: 觅食行为, 群聚行为, 追随行为和随机行为 ...
- 数学建模常用的十大算法
1. 蒙特卡罗算法. 该算法又称随机性模拟算法,是通过计算机仿真来解决问题的算法,同时可以通过模拟来检验自己模型的正确性,几乎是比赛时必用的方法. 2. 数据拟合.参数估计.插值等数据处理算法. 比赛 ...
- 数学建模常用算法:启发式优化算法合辑(内含多种智能优化算法,使用java实现算法、详细注释、并进行结果可视化)
一.启发式算法介绍 启发式算法(heuristic algorithm)是相对于最优化算法提出的.一个问题的最优算法求得该问题每个实例的最优解.启发式算法可以这样定义:一个基于直观或经验构造的算法 ...
- 【运筹优化】AFSA人工鱼群算法求解无约束多元函数最值(Java代码实现)
文章目录 前言 优化目标 求解结果 迭代结果可视化 算法流程 Java代码 可视化代码 前言 本文以求解二元函数最小值为例,如果需要求解多元函数,只需要修改以下变量即可: varNum:变量维度数 u ...
- 【Python数学建模常用算法代码(二)之BP神经网络】
Python数学建模常用算法代码(二) BP神经网络模型Python代码 import numpy as np import math import random import string impo ...
- 人工鱼群算法python_人工鱼群算法简介及应用
简介 定义 人工鱼群算法为山东大学副教授李晓磊2002年从鱼找寻食物的现象中表现的种种移动寻觅特点中得到启发而阐述的仿生学优化方案.在一片水域中,鱼往往能自行或尾随其他鱼找到营养物质多的地方,因而鱼生 ...
- matlab实战系列之人工鱼群算法求解TSP问题原理解析(下篇源码解析)
从算法的名字中可以看出该算法是群体智能优化算法中的一种,人工鱼群算法通过模拟鱼群的觅食.聚群.追尾.随机等行为在搜索域中进行寻优. 人工鱼群算法有三个比较重要的概念:视野范围.k-距离邻域.多条鱼的中 ...
- 【AFSA TSP】基于matlab改进的人工鱼群算法求解旅行商问题【含Matlab源码 1479期】
⛄一. TSP简介 旅行商问题,即TSP问题(Traveling Salesman Problem)又译为旅行推销员问题.货郎担问题,是数学领域中著名问题之一.假设有一个旅行商人要拜访n个城市,他必须 ...
- 【AFSA TSP】基于matlab人工鱼群算法求解旅行商问题【含Matlab源码 422期】
一.获取代码方式 获取代码方式1: 完整代码已上传我的资源:[TSP]基于matlab人工鱼群算法求解旅行商问题[含Matlab源码 422期] 点击上面蓝色字体,直接付费下载,即可. 获取代码方式2 ...
最新文章
- linux下top命令
- FTP之‘基础连接已关闭:服务器提交了协议冲突’错误探析
- linux usb-skeleton,Linux USB驱动程序(2)----usb-skeleton.c分析
- IdentityServer4实战 - JWT Token Issuer 详解
- python账号密码一一对应_python模拟用户登录系统,如何两个用户输入各自的密码才能登入?...
- vue 扫码页面限制区域_Vue.js 单页面多路由区域操作的实例详解
- 随机森林RF、XGBoost、GBDT和LightGBM的原理和区别
- Navicat premium查看数据库表中文注释的两种方式
- html span设置外边距,行内元素内外边距探究:为何span设置上下margin和padding不起效...
- 彩虹QQ查看对方ip原理
- 穿越Java - 基础篇 第三章 面向对象介绍 | 第4节 成员变量和局部变量
- 外国程序员和中国程序员的区别
- mybatis的大于小于号转义符号
- 【生活篇】微信运动刷步,高达98000!微信运动计步作弊教程!
- TP真阳性, FP假阳性, FN假阴性, TN真阴性
- torch对于tensor的常规操作
- 使用二分法来解决的一些问题
- 【flask】Blueprint蓝图
- maya2018arnold renderview保存图片渲染色彩空间偏差问题
- NLP的bigrams函数“generator object bigrams at 0x000001D32A95A678“问题解决