同一函数中的客观约束与非线性约束
这个例子展示了如何在使用基于求解器的方法同时计算目标和约束的值时避免调用函数两次。若要避免使用基于问题的方法调用函数两次,请参见目标和约束具有串行或并行的共同功能,基于问题的.
您通常在模拟中使用这样的函数。求解器,比如fmincon
分别计算目标函数和非线性约束函数。当对两个结果使用相同的计算时,这种计算是浪费的。
为了避免浪费时间,只在需要时使用嵌套函数来计算目标函数和约束函数,从而保留耗时计算的值。这种方法避免使用全局变量,同时保留中间结果,并在目标函数和约束函数之间共享它们。
请注意
因为方式遗传算法
(全局优化工具箱)调用非线性约束函数,本例中的技术通常不会减少对目标函数或约束函数的调用次数。
步骤1。编写一个计算目标和约束的函数。
例如,假设computeall
是由目标函数和非线性约束函数调用的昂贵(耗时)函数。假设您想要使用fmincon
作为你的优化器。
写一个函数来计算Rosenbrock函数的一部分f1
并且包含一个非线性约束c1
这使得解在原点周围半径为1的圆盘上。Rosenbrock函数是
它在点(1,1)处的最小值是0。看到求解一个约束非线性问题,基于求解器.
这个例子没有非线性等式约束,所以Ceq1 = []
.添加一个暂停(1)
语句来模拟昂贵的计算。
函数[f1,c1,ceq1] = computeall(x) ceq1 = [];C1 = x(1)²+ x(2)²- 1;F1 = 100*(x(2) -x(1)²)²+ (1-x(1))²;暂停(1)%模拟昂贵的计算结束
保存computeall.m
作为MATLAB中的一个文件®路径。
步骤2。将函数嵌入到保持最近值的嵌套函数中。
假设目标函数是
y= 100 (x2- - - - - -x12)2+ (1 -)x1)2
+ 20 * (x3.- - - - - -x42)2+ 5*(1 -x4)2.
computeall
返回目标函数的第一部分。嵌入到的调用computeall
在嵌套函数中:
函数[x,f,eflag,outpt] = runobjconstr(x0,opts)如果Nargin == 1%未提供选项Opts = [];结束xLast = [];最后一次调用computeall的位置Myf = [];%用于xLast的目标Myc = [];用于非线性不等式约束Myceq = [];用于非线性等式约束Fun = @objfun;目标函数,嵌套在下面Cfun = @constr;%约束函数,嵌套在下面调用fmincon[x, f, eflag, outpt] = fmincon (x0有趣, ,[],[],[],[],[],[], cfun、选择);函数Y = objfun(x)如果~ isequal (x, xLast)检查是否需要计算[myf,myc,myceq] = computeall(x);xLast = x;结束现在计算目标函数Y = myf + 20*(x(3) - x(4)²)²+ 5*(1 - x(4))²;结束函数[c,ceq] = constr(x)如果~ isequal (x, xLast)检查是否需要计算[myf,myc,myceq] = computeall(x);xLast = x;结束现在计算约束函数C = myc;在这种情况下,计算是微不足道的Ceq = myceq;结束结束
将嵌套函数保存为一个名为runobjconstr.m
在MATLAB路径上。
步骤3。确定运行嵌套函数的时间。
运行该函数,为调用计时抽搐
而且toc
.
Opts = optimoptions(@fmincon,“算法”,“内点”,“显示”,“关闭”);X0 = [-1,1,1,2];Tic [x,fval,exitflag,output] = runobjconstr(x0,opts);toc
运行时间为259.364090秒。
步骤4。确定在没有嵌套函数的情况下运行的时间。
比较使用和不使用嵌套函数运行求解器的时间。对于没有嵌套函数的运行,保存myrosen2.m
作为目标函数文件和constr.m
作为约束条件。
函数Y = myrosen2(x) f1 = computeall(x);完成目标的第一部分Y = f1 + 20*(x(3) - x(4)²)²+ 5*(1 - x(4))²;结束函数[c,ceq] = constr(x) [~,c,ceq] = computeall(x);结束
运行fmincon
,打电话的时间抽搐
而且toc
.
Tic [x,fval,exitflag,output] = fmincon(@myrosen2,x0,...[],[],[],[],[],[],@ 若干,选择);toc
运行时间为518.364770秒。
求解器花费的时间是以前的两倍,因为它分别计算目标和约束。
第5步。通过并行计算节省计算时间。
如果您拥有并行计算工具箱™许可证,则可以通过设置UseParallel
选项真正的
.
parpool
使用“本地”配置文件启动并行池(parpool)…连接到并行池(number of workers: 6). ans = ProcessPool with properties: Connected: true NumWorkers: 6 Cluster: local AttachedFiles: {} AutoAddClientPath: true IdleTimeout: 30 minutes(剩余30分钟)SpmdEnabled: true
Opts = optimoptions(Opts,“UseParallel”,真正的);Tic [x,fval,exitflag,output] = runobjconstr(x0,opts);toc
运行时间为121.151203秒。
在这种情况下,与使用嵌套函数串行运行相比,启用并行计算可以将计算时间减少一半。
比较并行计算的运行,有和没有嵌套函数:
Tic [x,fval,exitflag,output] = fmincon(@myrosen2,x0,...[],[],[],[],[],[],@ 若干,选择);toc
运行时间为235.914597秒。
在这个例子中,并行但不是嵌套的计算所花费的时间与嵌套但不是并行的计算所花费的时间相同。计算嵌套和并行的时间都是单独使用的一半。