外点惩处函数法·约束优化问题
外點懲處函數法·約束優化問題
?????? 外點法懲處函數(r添加,SUMT.java)用于求解約束優化問題。解題過程例如以下:
?????? Step1 輸入目標函數與約束方程,構建外點懲處函數法求解方程,求解初始化。
?????? Step2 對求解方程進行一次無約束優化方法求解(鮑威爾BWE),得到新解。
?????? Step3 新解與原解求誤差。如誤差滿足精度要求,則輸出解,否則添加因子r,運行Step 2。
?????? 鮑威爾法(BWE.java)是N維無約束求解方法。須要調用一維求解方法。一維求解方法採用黃金切割法(GSM.java)。
? ? ? ?在實現算法的代碼中,我去掉了輸入處理,人為地將輸入確定下來。可降低代碼篇幅。
? ? ? ?我會將文件打包放入我的下載,歡迎大家一起交流。
(1)外點法懲處函數 SUMT.java:
package ODM.Method;import java.util.Arrays; /** 無約束優化方法:懲處函數法·外點法*/ public class SUMT {private int n = 6; // 維數,變量個數private final double eps = 1e-5; // 精度private final double c = 5; // 遞增系數private double r = 0.1; // 懲處因子,趨向無窮public SUMT(){Finit();AlgorithmProcess();AnswerOutput();}// 結果private double[] xs; private double ans;private void Finit(){xs = new double[n];Arrays.fill(xs, 0);ans = -1;//xs[0] = xs[1] = xs[2] = xs[4] = 1; xs[3] = 3; xs[5] = 5;}// 算法主要流程private void AlgorithmProcess(){int icnt = 0; // 迭代次數double[] x = new double[n]; // 轉化為無約束優化問題的解while(true){icnt++;BWE temp = new BWE(n, r, xs); // 採用鮑威爾方法求函數最優解x = temp.retAns();if(retOK(x) <= eps){ // 滿足精度要求for(int i = 0; i < n; i++)xs[i] = x[i];ans = temp.mAns();break;}r = c * r;for(int i = 0; i < n; i++)xs[i] = x[i];}System.out.println("迭代次數:" + icnt);}// 收斂條件(僅僅有一個,不完好)private double retOK(double[] x){double sum = 0;for(int i = 0; i < n; i++){sum += Math.pow(x[i] - xs[i], 2);}return Math.sqrt(sum);}// 結果輸出private void AnswerOutput(){for(int i = 0; i < n; i++)System.out.printf("%.6f\t", xs[i]);System.out.printf("%.6f\n", ans);}public static void main(String[] args) {// TODO Auto-generated method stubnew SUMT();}}(2)鮑威爾法 BWE.java: package ODM.Method;import java.util.Arrays;public class BWE {private double r;// 初始化變量private double[] x0; // 初始解集private double[][] e; // 初始方向private int N;final private double eps = 1e-5;private Func F;// 初始化:初始點, 初始矢量(n 個,n*n 矩陣), 維數private void Init(int n){this.x0 = new double[n];if(r == -1)Arrays.fill(this.x0, 0);else{}this.e = new double[n][n];for(int i = 0; i < n; i++){for(int j = 0; j < n; j++){if(i != j)e[i][j] = 0;else e[i][j] = 1;}}this.N = n;if(r != -1)F = new Func(r);elseF = new Func();}// 搜索點, 方向矢量private double[][] x;private double[][] d;// 方向重排, 隊列操作private void queueDir(double[] X){// 刪去首方向for(int i = 0; i < N-1; i++){for(int j = 0; j < N; j++){d[i][j] = d[i+1][j];}}// 新方向插入隊尾for(int i = 0; i < N; i++)d[N-1][i] = X[i];}private void Process(){x = new double[N+1][N];d = new double[N][N];for(int j = 0; j < N; j++)x[0][j] = x0[j];for(int i = 0; i < N; i++){for(int j = 0; j < N; j++){d[i][j] = e[i][j];}}int k = 0; // 迭代次數while(k < N){for(int i = 1; i <= N; i++){GSM t = new GSM(F, x[i-1], d[i-1]);x[i] = t.getOs();}double[] X = new double[N];for(int i = 0; i < N; i++)X[i] = x[N][i] - x[0][i];queueDir(X);GSM t = new GSM(F, x[N], X);x[0] = t.getOs();k++;}}// 答案打印private void AnswerOutput(){for(int i = 0; i < N; i++){System.out.printf("x[%d] = %.6f\n", i+1, x[0][i]); // System.out.print(x[0][i] + " ");}System.out.printf("最小值:%.6f\n", F.fGetVal(x[0])); // System.out.println(": " + F.fGetVal(x[0]));}public BWE(int n){this.r = -1;Init(n);Process();AnswerOutput();}public BWE(int n, double r, double[] x){this.r = r;Init(n);for(int i = 0; i < n; i++)x0[i] = x[i];Process();}// 返回結果,解向量和最優值public double[] retAns(){return x[0];}public double mAns(){return F.fGetVal(x[0], 0);}/*public static void main(String[] args) {// TODO Auto-generated method stubnew BWE(2);}*/}
(3)黃金切割 GSM.java: package ODM.Method; /** 黃金切割法*/ public class GSM {private int N; // 維度private final double landa = (Math.sqrt(5)-1)/2; // 0.618private double[] x1;private double[] x2;private double[] os;private final double eps = 1e-5; // 解精度private ExtM EM; // 用于獲取外推法結果// 最優值輸出public double[] getOs() {return os;}// 函數, 初始點, 方向矢量public GSM(Func Sample, double[] x, double[] e) {//for(int i = 0; i < e.length; i++)System.out.print(e[i] + " ");System.out.println();initial(Sample, x, e);process(Sample);AnswerPrint(Sample);}// 結果打印private void AnswerPrint(Func Sample) {os = new double[N];for(int i = 0; i < N; i++)os[i] = 0.5*(x1[i] + x2[i]);// System.out.println("os = " + os[0] + " " + os[1]); // System.out.println("ans = " + Sample.fGetVal(os));}// 向量范值private double FanZhi(double[] b, double[] a){double sum = 0;for(int i = 0; i < N; i++){if(b[i] - a[i] != 0 && b[i] == 0)return eps*(1e10);if(b[i] == 0)continue;sum += Math.pow((b[i] - a[i]) / b[i], 2);}return Math.pow(sum, 0.5);}// 算法主流程private void process(Func Sample) {double[] xx1 = new double[N];SubArraysCopy(xx1);double yy1 = Sample.fGetVal(xx1);double[] xx2 = new double[N];AddArraysCopy(xx2);double yy2 = Sample.fGetVal(xx2);// 迭代過程while(true){if(yy1 >= yy2){ArraysCopy(xx1, x1);ArraysCopy(xx2, xx1); yy1 = yy2;AddArraysCopy(xx2);yy2 = Sample.fGetVal(xx2);}else{ArraysCopy(xx2, x2);ArraysCopy(xx1, xx2); yy2 = yy1;SubArraysCopy(xx1);yy1 = Sample.fGetVal(xx1);}//System.out.println(FanZhi(x2, x1) + " / " + Math.abs((yy2 - yy1)/yy2));if(FanZhi(x2, x1) < eps && Math.abs(yy2 - yy1) < eps)break;}}// 獲得外推法結果:左右邊界private void initial(Func Sample, double[] x, double[] e) {N = x.length;EM = new ExtM(Sample, x, e);x1 = EM.getX1();x2 = EM.getX3();}// 向量賦值private void ArraysCopy(double[] s, double[] e){for(int i = 0; i < N; i++)e[i] = s[i];}// + landaprivate void AddArraysCopy(double[] arr){for(int i = 0; i < N; i++)arr[i] = x1[i] + landa*(x2[i] - x1[i]);}// - landaprivate void SubArraysCopy(double[] arr){for(int i = 0; i < N; i++)arr[i] = x2[i] - landa*(x2[i] - x1[i]);}/*public static void main(String[] args) {// TODO Auto-generated method stubdouble[] C = {0, 0};double[] d = {1, 0};new GSM(new Func(), C, d);}*/ }
函數方程 Func.java。外推法 ExtM.java。
Func.java:
package ODM.Method;public class Func {private int N; // N 維private double[] left; // 函數左邊界private double[] right; // 函數右邊界private double r;public Func() {r = -1;}public Func(double r) {this.r = r;}// 定義函數與函數值返回public double fGetVal(double[] x){if(r != -1)return fGetVal(x, r);// 10*(x1+x2-5)^2 + (x1-x2)^2return 10*Math.pow(x[0]+x[1]-5, 2) + Math.pow(x[0]-x[1], 2);//}private double max(double a, double b){return a > b ? a : b;}public double fGetVal(double[] x, double r){double ret = 0; // function f1 // ret = Math.pow(x[0]-5, 2) + 4*Math.pow(x[1]-6, 2) // + r * ( // + Math.pow(max(64-x[0]*x[0]-x[1]*x[1], 0), 2) // + Math.pow(max(x[1]-x[0]-10, 0), 0) // + Math.pow(max(x[0]-10, 0), 2) // );// function f2 // ret = x[0]*x[0] + x[1]*x[1] + r*(1-x[0]>0 ? 1-x[0] : 0)*(1-x[0]>0 ?1-x[0] : 0); // function f3 ret = Math.pow(x[0]-x[3], 2) + Math.pow(x[1]-x[4], 2) + Math.pow(x[2]-x[5], 2) + r * ( + Math.pow(max(x[0]*x[0]+x[1]*x[1]+x[2]*x[2]-5, 0), 2) + Math.pow(max(Math.pow(x[3]-3, 2)+x[4]*x[4]-1, 0), 2) + Math.pow(max(x[5]-8, 0), 2) + Math.pow(max(4-x[5], 0), 2) ); return ret; } }
ExtM.java: package ODM.Method;/** 外推法確定“高-低-高”區間*/ public class ExtM {private int N; // 函數維數private double[] x1;private double[] x2;private double[] x3;private double y1;private double y2;private double y3;private double h; // 步長private double[] d; // 方向矢量public double[] getX1() {return x1;}public double[] getX2() {return x2;}public double[] getX3() {return x3;}public double getH() {return h;}// 函數, 初始點,方向public ExtM(Func Sample, double[] x, double[] e) {initial(Sample, x, e);process(Sample);AnswerPrint();}// 初始化階段private void initial(Func Sample, double[] x, double[] e){N = x.length;x1 = new double[N];x2 = new double[N];x3 = new double[N];h = 0.01;d = new double[N];ArraysCopy(e, 0, d);//for(int i = 0; i < d.length; i++)System.out.print(d[i]);System.out.println();ArraysCopy(x, 0, x1);y1 = Sample.fGetVal(x1);ArraysCopy(x, h, x2);y2 = Sample.fGetVal(x2);}// 循環部分private void process(Func Sample){if(y2 > y1){h = -h;ArraysCopy(x1, 0, x3);y3 = y1;}else{ArraysCopy(x2, h, x3); y3 = Sample.fGetVal(x3);}while(y3 < y2){h = 2*h; // System.out.println("h = " + h);ArraysCopy(x2, 0, x1); y1 = y2;ArraysCopy(x3, 0, x2); y2 = y3;ArraysCopy(x2, h, x3); y3 = Sample.fGetVal(x3); // System.out.println("x1 = " + x1[0] + " " + x1[1] + " y1 = " + y1); // System.out.println("x2 = " + x2[0] + " " + x2[1] + " y2 = " + y2); // System.out.println("x3 = " + x3[0] + " " + x3[1] + " y3 = " + y3);}}// 打印算法結果private void AnswerPrint(){ // System.out.println("x1 = " + x1[0] + " " + x1[1] + " y1 = " + y1); // System.out.println("x2 = " + x2[0] + " " + x2[1] + " y2 = " + y2); // System.out.println("x3 = " + x3[0] + " " + x3[1] + " y3 = " + y3);}// 向量轉移private void ArraysCopy(double[] s, double c, double[] e){for(int i = 0; i < s.length; i++)e[i] = d[i]*c + s[i];}/*public static void main(String[] args) {// TODO Auto-generated method stub// new ExtM();}*/}
轉載于:https://www.cnblogs.com/ldxsuanfa/p/10761431.html
總結
以上是生活随笔為你收集整理的外点惩处函数法·约束优化问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一公升等于多少升
- 下一篇: 两列布局、三列适应布局、两列等高适应布局