【智能算法】PSO粒子群算法求解无约束多元函数最值(Java代码实现)
文章目錄
- 粒子群算法的定義
- 模擬鳥類捕食
- 啟示
- 算法流程圖
- 案例1 - 求解二元函數(shù)最小值
- 代碼
- 運(yùn)行結(jié)果
- 迭代過程可視化
- 可視化代碼
- 案例2 - 求解六元函數(shù)最小值
- 代碼
- 運(yùn)行結(jié)果
粒子群算法的定義
粒子群優(yōu)化算法(Particle Swarm optimization,PSO)又翻譯為粒子群算法、微粒群算法、或微粒群優(yōu)化算法。是通過模擬鳥群覓食行為而發(fā)展起來的一種基于群體協(xié)作的隨機(jī)搜索算法。通常認(rèn)為它是群集智能 (Swarm intelligence, SI) 的一種。它可以被納入多主體優(yōu)化系統(tǒng)(Multiagent Optimization System, MAOS)。粒子群優(yōu)化算法是由Eberhart博士和kennedy博士發(fā)明。
模擬鳥類捕食
PSO模擬鳥群的捕食行為。一群鳥在隨機(jī)搜索食物,在這個(gè)區(qū)域里只有一塊食物。所有的鳥都不知道食物在那里。但是他們知道當(dāng)前的位置離食物還有多遠(yuǎn)。那么找到食物的最優(yōu)策略是什么呢。最簡(jiǎn)單有效的就是搜尋離食物最近的鳥的周圍區(qū)域。
啟示
PSO從這種模型中得到啟示并用于解決優(yōu)化問題。PSO中,每個(gè)優(yōu)化問題的解都是搜索空間中的一只鳥。我們稱之為“粒子”。所有的粒子都有一個(gè)由被優(yōu)化的函數(shù)決定的適應(yīng)值(fitnessvalue),每個(gè)粒子還有一個(gè)速度決定他們飛翔的方向和距離。然后粒子們就追隨當(dāng)前的最優(yōu)粒子在解空間中搜索。
算法流程圖
案例1 - 求解二元函數(shù)最小值
Z = x^2 + y^2 - xy - 10x - 4y +60代碼
import java.util.Arrays; import java.util.Random;/*** @Author:WSKH* @ClassName:PSO_Solve* @ClassType:* @Description:* @Date:2022/6/6/14:59* @Email:1187560563@qq.com* @Blog:https://blog.csdn.net/weixin_51545953?type=blog*/ public class PSO_Solve {// 粒子對(duì)象class Particle {// 粒子速度數(shù)組(每個(gè)方向都有一個(gè)速度)double[] vArr;// 當(dāng)前粒子坐標(biāo)(自變量數(shù)組)double[] curVars;// 當(dāng)前自變量對(duì)應(yīng)的目標(biāo)函數(shù)值double curObjValue;// 該粒子找到過的最佳目標(biāo)函數(shù)值double bestObjValue;// 該粒子最好位置時(shí)的坐標(biāo)double[] bestVars;// 全參構(gòu)造public Particle(double[] vArr, double[] curVars, double curObjValue, double bestObjValue, double[] bestVars) {this.vArr = vArr;this.curVars = curVars;this.curObjValue = curObjValue;this.bestObjValue = bestObjValue;this.bestVars = bestVars;}}// 粒子數(shù)量int n = 500;// 每個(gè)粒子的個(gè)體學(xué)習(xí)因子:自我認(rèn)知,設(shè)置較大則不容易被群體帶入局部最優(yōu),但會(huì)減緩收斂速度double c1 = 2;// 每個(gè)粒子的社會(huì)學(xué)習(xí)因子:社會(huì)認(rèn)知,設(shè)置較大則加快收斂,但容易陷入局部最優(yōu)double c2 = 2;// 粒子的慣性權(quán)重double w = 0.9;// 迭代的次數(shù)int MaxGen = 500;// 粒子的每個(gè)維度上的最大速度(數(shù)組)double[] vMaxArr = new double[]{1.2,1.2};// 隨機(jī)數(shù)對(duì)象Random random = new Random();// 自變量個(gè)數(shù)int varNum = 2;// 自變量的上下界數(shù)組double[] lbArr = new double[]{-1000, -1000};double[] ubArr = new double[]{1000, 1000};// 粒子群Particle[] particles;// 最佳粒子Particle bestParticle;// 記錄迭代過程public double[][][] positionArr;/*** @Description 初始化粒子的位置和速度*/private void initParticles() {// 初始化粒子群particles = new Particle[n];// 隨機(jī)生成粒子for (int i = 0; i < particles.length; i++) {// 隨機(jī)生成坐標(biāo)和速度double[] vars = new double[varNum];double[] vArr = new double[varNum];for (int j = 0; j < varNum; j++) {vars[j] = random.nextDouble() * (ubArr[j] - lbArr[j]) + lbArr[j];vArr[j] = (random.nextDouble() - 0.5) * 2 * vMaxArr[j];}// 目標(biāo)函數(shù)值double objValue = getObjValue(vars);particles[i] = new Particle(vArr.clone(), vars.clone(), objValue, objValue, vars.clone());}// 找到初始化粒子群中的最佳粒子bestParticle = copyParticle(particles[0]);for (int i = 1; i < particles.length; i++) {if (bestParticle.bestObjValue > particles[i].bestObjValue) {bestParticle = copyParticle(particles[i]);}}}/*** @Description 主要求解函數(shù)*/public void solve() {// 變量設(shè)置初步判斷if(varNum != vMaxArr.length || varNum != lbArr.length || varNum != ubArr.length){throw new RuntimeException("變量維度不一致");}positionArr = new double[MaxGen][n][varNum];// 初始化粒子的位置和速度initParticles();// 開始迭代for (int i = 0; i < MaxGen; i++) {// 依次更新第i個(gè)粒子的速度與位置for (int j = 0; j < particles.length; j++) {// 針對(duì)不同維度進(jìn)行處理for (int k = 0; k < varNum; k++) {// 更新速度double newV = particles[j].vArr[k] * w+ c1 * random.nextDouble() * (particles[j].bestVars[k] - particles[j].curVars[k])+ c2 * random.nextDouble() * (bestParticle.bestVars[k] - particles[j].curVars[k]);// 如果速度超過了最大限制,就對(duì)其進(jìn)行調(diào)整if (newV < -vMaxArr[k]) {newV = -vMaxArr[k];} else if (newV > vMaxArr[k]) {newV = vMaxArr[k];}// 更新第j個(gè)粒子第k個(gè)維度上的位置double newPos = particles[j].curVars[k] + newV;// 記錄迭代過程positionArr[i][j][k] = newPos;// 如果位置超出了定義域,就對(duì)其進(jìn)行調(diào)整if(newPos < lbArr[k]){newPos = lbArr[k];}else if(newPos > ubArr[k]){newPos = ubArr[k];}// 賦值回去particles[j].curVars[k] = newPos;particles[j].vArr[k] = newV;}// 更新完所有維度后,再計(jì)算第j個(gè)粒子的函數(shù)值double objValueJ = getObjValue(particles[j].curVars);particles[j].curObjValue = objValueJ;if(objValueJ < particles[j].bestObjValue){particles[j].bestVars = particles[j].curVars.clone();particles[j].bestObjValue = particles[j].curObjValue;}if(objValueJ < bestParticle.bestObjValue){bestParticle = copyParticle(particles[j]);}}}// 迭代結(jié)束,輸出最優(yōu)粒子位置和函數(shù)值System.out.println("最優(yōu)解為:"+ bestParticle.bestObjValue);System.out.println("最優(yōu)解坐標(biāo)為:"+ Arrays.toString(bestParticle.bestVars));}/*** @param vars 自變量數(shù)組* @return 返回目標(biāo)函數(shù)值*/public double getObjValue(double[] vars) {//目標(biāo):在變量區(qū)間范圍最小化 Z = x^2 + y^2 - xy - 10x - 4y +60return Math.pow(vars[0], 2) + Math.pow(vars[1], 2) - vars[0] * vars[1] - 10 * vars[0] - 4 * vars[1] + 60;}// 復(fù)制粒子public Particle copyParticle(Particle old) {return new Particle(old.vArr.clone(), old.curVars.clone(), old.curObjValue, old.bestObjValue, old.bestVars.clone());}}運(yùn)行結(jié)果
最優(yōu)解為:8.000057527138821 最優(yōu)解坐標(biāo)為:[8.00430921604821, 5.995551568450099] 求解用時(shí):0.019 s迭代過程可視化
可視化代碼
import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.control.Button; import javafx.scene.input.MouseEvent; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.paint.Color; import javafx.stage.Stage; import javafx.util.Duration;/*** @Author:WSKH* @ClassName:PlotUtil* @ClassType:* @Description:* @Date:2022/6/6/18:31* @Email:1187560563@qq.com* @Blog:https://blog.csdn.net/weixin_51545953?type=blog*/ public class PlotUtil extends Application {//當(dāng)前的時(shí)間軸private Timeline nowTimeline;//繪圖位置坐標(biāo)private double[][][] positionArr;public static void main(String[] args) {launch(args);}@Overridepublic void start(Stage primaryStage) throws Exception {// 調(diào)用算法獲取繪圖數(shù)據(jù)PSO_Solve psoApi = new PSO_Solve();psoApi.solve();this.positionArr = psoApi.positionArr;// 畫圖try {BorderPane root = new BorderPane();root.setStyle("-fx-padding: 20;");Scene scene = new Scene(root, 1600, 900);double canvasWid = 800;double canvasHei = 800;//根據(jù)畫布大小縮放坐標(biāo)值this.fixPosition(canvasWid - 100, canvasHei - 100);//畫布和畫筆HBox canvasHbox = new HBox();Canvas canvas = new Canvas();canvas.setWidth(canvasWid);canvas.setHeight(canvasHei);canvasHbox.setPrefWidth(canvasWid);canvasHbox.getChildren().add(canvas);canvasHbox.setAlignment(Pos.CENTER);canvasHbox.setStyle("-fx-spacing: 20;" +"-fx-background-color: #87e775;");root.setTop(canvasHbox);GraphicsContext paintBrush = canvas.getGraphicsContext2D();//啟動(dòng)HBox hBox2 = new HBox();Button beginButton = new Button("播放迭代過程");hBox2.getChildren().add(beginButton);root.setBottom(hBox2);hBox2.setAlignment(Pos.CENTER);//啟動(dòng)仿真以及暫停仿真beginButton.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {nowTimeline.play();});//創(chuàng)建掃描線連接動(dòng)畫nowTimeline = new Timeline();createAnimation(paintBrush);primaryStage.setScene(scene);primaryStage.show();} catch (Exception e) {e.printStackTrace();}}/*** 修正cityPositionArr的坐標(biāo),讓畫出來的點(diǎn)在畫布內(nèi)** @param width* @param height*/private void fixPosition(double width, double height) {double minX = Double.MAX_VALUE;double maxX = -Double.MAX_VALUE;double minY = Double.MAX_VALUE;double maxY = -Double.MAX_VALUE;for (int i = 0; i < this.positionArr.length; i++) {for (int j = 0; j < this.positionArr[0].length; j++) {minX = Math.min(minX, this.positionArr[i][j][0]);maxX = Math.max(maxX, this.positionArr[i][j][0]);minY = Math.min(minY, this.positionArr[i][j][1]);maxY = Math.max(maxY, this.positionArr[i][j][1]);}}double multiple = Math.max((maxX - minX) / width, (maxY - minY) / height);//轉(zhuǎn)化為正數(shù)數(shù)for (int i = 0; i < this.positionArr.length; i++) {for (int j = 0; j < this.positionArr[0].length; j++) {if (minX < 0) {this.positionArr[i][j][0] = this.positionArr[i][j][0] - minX;}if (minY < 0) {this.positionArr[i][j][1] = this.positionArr[i][j][1] - minY;}}}for (int i = 0; i < this.positionArr.length; i++) {for (int j = 0; j < this.positionArr[0].length; j++) {this.positionArr[i][j][0] = this.positionArr[i][j][0] / multiple;this.positionArr[i][j][1] = this.positionArr[i][j][1] / multiple;}}}/*** 用畫筆在畫布上畫出所有的孔* 畫第i代的所有粒子*/private void drawAllCircle(GraphicsContext paintBrush, int i) {paintBrush.clearRect(0, 0, 2000, 2000);paintBrush.setFill(Color.RED);for (int j = 0; j < this.positionArr[i].length; j++) {drawCircle(paintBrush, i, j);}}/*** 用畫筆在畫布上畫出一個(gè)孔* 畫第i代的第j個(gè)粒子*/private void drawCircle(GraphicsContext paintBrush, int i, int j) {double x = this.positionArr[i][j][0];double y = this.positionArr[i][j][1];double radius = 2;// 圓的直徑double diameter = radius * 2;paintBrush.fillOval(x, y, diameter, diameter);}/*** 創(chuàng)建動(dòng)畫*/private void createAnimation(GraphicsContext paintBrush) {for (int i = 0; i < this.positionArr[0].length; i++) {int finalI = i;KeyFrame keyFrame = new KeyFrame(Duration.seconds(i * 0.05), event -> drawAllCircle(paintBrush, finalI));nowTimeline.getKeyFrames().add(keyFrame);}}}案例2 - 求解六元函數(shù)最小值
設(shè)六元變量分別為 a b c d e f 目標(biāo):在變量區(qū)間范圍最小化 Z = abc - bce + cd + ef - bdf代碼
import java.util.Arrays; import java.util.Random;/*** @Author:WSKH* @ClassName:PSO_Solve_6d* @ClassType:* @Description:* @Date:2022/6/6/14:59* @Email:1187560563@qq.com* @Blog:https://blog.csdn.net/weixin_51545953?type=blog*/ public class PSO_Solve_6d {// 粒子對(duì)象class Particle {// 粒子速度數(shù)組(每個(gè)方向都有一個(gè)速度)double[] vArr;// 當(dāng)前粒子坐標(biāo)(自變量數(shù)組)double[] curVars;// 當(dāng)前自變量對(duì)應(yīng)的目標(biāo)函數(shù)值double curObjValue;// 該粒子找到過的最佳目標(biāo)函數(shù)值double bestObjValue;// 該粒子最好位置時(shí)的坐標(biāo)double[] bestVars;// 全參構(gòu)造public Particle(double[] vArr, double[] curVars, double curObjValue, double bestObjValue, double[] bestVars) {this.vArr = vArr;this.curVars = curVars;this.curObjValue = curObjValue;this.bestObjValue = bestObjValue;this.bestVars = bestVars;}}// 粒子數(shù)量int n = 100;// 每個(gè)粒子的個(gè)體學(xué)習(xí)因子:自我認(rèn)知,設(shè)置較大則不容易被群體帶入局部最優(yōu),但會(huì)減緩收斂速度double c1 = 2;// 每個(gè)粒子的社會(huì)學(xué)習(xí)因子:社會(huì)認(rèn)知,設(shè)置較大則加快收斂,但容易陷入局部最優(yōu)double c2 = 2;// 粒子的慣性權(quán)重double w = 0.9;// 迭代的次數(shù)int MaxGen = 500;// 粒子的每個(gè)維度上的最大速度(數(shù)組)double[] vMaxArr = new double[]{1.2, 1.2, 1.2, 1.2, 1.2, 1.2};// 隨機(jī)數(shù)對(duì)象Random random = new Random();// 自變量個(gè)數(shù)int varNum = 6;// 自變量的上下界數(shù)組double[] lbArr = new double[]{-1000, -1000, -1000, -1000, -1000, -1000};double[] ubArr = new double[]{1000, 1000, 1000, 1000, 1000, 1000};// 粒子群Particle[] particles;// 最佳粒子Particle bestParticle;/*** @Description 初始化粒子的位置和速度*/private void initParticles() {// 初始化粒子群particles = new Particle[n];// 隨機(jī)生成粒子for (int i = 0; i < particles.length; i++) {// 隨機(jī)生成坐標(biāo)和速度double[] vars = new double[varNum];double[] vArr = new double[varNum];for (int j = 0; j < varNum; j++) {vars[j] = random.nextDouble() * (ubArr[j] - lbArr[j]) + lbArr[j];vArr[j] = (random.nextDouble() - 0.5) * 2 * vMaxArr[j];}// 目標(biāo)函數(shù)值double objValue = getObjValue(vars);particles[i] = new Particle(vArr.clone(), vars.clone(), objValue, objValue, vars.clone());}// 找到初始化粒子群中的最佳粒子bestParticle = copyParticle(particles[0]);for (int i = 1; i < particles.length; i++) {if (bestParticle.bestObjValue > particles[i].bestObjValue) {bestParticle = copyParticle(particles[i]);}}}/*** @Description 主要求解函數(shù)*/public void solve() {// 變量設(shè)置初步判斷if (varNum != vMaxArr.length || varNum != lbArr.length || varNum != ubArr.length) {throw new RuntimeException("變量維度不一致");}// 初始化粒子的位置和速度initParticles();// 開始迭代for (int i = 0; i < MaxGen; i++) {// 依次更新第i個(gè)粒子的速度與位置for (int j = 0; j < particles.length; j++) {// 針對(duì)不同維度進(jìn)行處理for (int k = 0; k < varNum; k++) {// 更新速度double newV = particles[j].vArr[k] * w+ c1 * random.nextDouble() * (particles[j].bestVars[k] - particles[j].curVars[k])+ c2 * random.nextDouble() * (bestParticle.bestVars[k] - particles[j].curVars[k]);// 如果速度超過了最大限制,就對(duì)其進(jìn)行調(diào)整if (newV < -vMaxArr[k]) {newV = -vMaxArr[k];} else if (newV > vMaxArr[k]) {newV = vMaxArr[k];}// 更新第j個(gè)粒子第k個(gè)維度上的位置double newPos = particles[j].curVars[k] + newV;// 如果位置超出了定義域,就對(duì)其進(jìn)行調(diào)整if (newPos < lbArr[k]) {newPos = lbArr[k];} else if (newPos > ubArr[k]) {newPos = ubArr[k];}// 賦值回去particles[j].curVars[k] = newPos;particles[j].vArr[k] = newV;}// 更新完所有維度后,再計(jì)算第j個(gè)粒子的函數(shù)值double objValueJ = getObjValue(particles[j].curVars);particles[j].curObjValue = objValueJ;if (objValueJ < particles[j].bestObjValue) {particles[j].bestVars = particles[j].curVars.clone();particles[j].bestObjValue = particles[j].curObjValue;}if (objValueJ < bestParticle.bestObjValue) {bestParticle = copyParticle(particles[j]);}}}// 迭代結(jié)束,輸出最優(yōu)粒子位置和函數(shù)值System.out.println("最優(yōu)解為:" + bestParticle.bestObjValue);System.out.println("最優(yōu)解坐標(biāo)為:" + Arrays.toString(bestParticle.bestVars));}/*** @param vars 自變量數(shù)組* @return 返回目標(biāo)函數(shù)值*/public double getObjValue(double[] vars) {// 設(shè)六元變量分別為 a b c d e f// 目標(biāo):在變量區(qū)間范圍最小化 Z = abc - bce + cd + ef - bdfreturn (vars[0] * vars[1] * vars[2] - vars[1] * vars[2] * vars[3] + vars[2] * vars[4] + vars[4] * vars[5] - vars[1] * vars[3] * vars[5]);}// 復(fù)制粒子public Particle copyParticle(Particle old) {return new Particle(old.vArr.clone(), old.curVars.clone(), old.curObjValue, old.bestObjValue, old.bestVars.clone());}}運(yùn)行結(jié)果
最優(yōu)解為:-8.387035664320209E8 最優(yōu)解坐標(biāo)為:[-886.8352994556639, -748.1858708041178, -560.6940636412202, 646.2689604948565, -274.97367655848336, -404.99446493036083] 求解用時(shí):0.028 s總結(jié)
以上是生活随笔為你收集整理的【智能算法】PSO粒子群算法求解无约束多元函数最值(Java代码实现)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 抽象代数学习笔记四《群:子群、同构、同态
- 下一篇: python获取子窗口句柄