suprisingly complicated optimization problem
200 Ansichten (letzte 30 Tage)
Ältere Kommentare anzeigen
Michal
am 24 Sep. 2025 um 13:11
Kommentiert: Matt J
vor etwa 4 Stunden
I have the following constrained (global) optimization problem:
For a user defined sorted real values vector:
xi = [xi(1), ... , xi(N+1)]
I need to find unknown vector:
x = [x(1), ..., x(L)]
where the integer L is the unknown length of the vector x (L>=0, L = 0 is the trivial case)
and the unknown vector x = [x(1), ..., x(L)] must satisfy the following specific conditions:
===============================================================
0. The new "refined" sorted vector xo = union(xi,x), where length(xo) = L+N+1
should to fulfil the following set of conditions:
1. min(xo) = xo(1) = xi(1), max(xo) = xo(L+N+1) = xi(N+1)
2. q = max(z(j)/z(j+1),z(j+1)/z(j)) < q_max, for j = 1, 2, ... L+N
where z(j) = xo(j+1) - xo(j) , z = diff(xo), length(z) = L+N
and q_max is user defined max ratio, where q_max > 1 (typically q_max ~ 1.05 - 1.2)
3. min(z) -> maximal, minimal distance between xo vector elements should be maximized.
It is obvious that for small L the constraint conditions (2) is not possible to satisfy.
===============================================================
The motivation of this problem is the creation of the so called, "homogenized" 1-D grid, where consecutive distances between elements of vector xo are relatively "slowly" changing.
I will be very happy for any recommendation how to effectively solve this problem using MATLAB + (global) optimization toolbox.
See additional function to generate "realistic" (in my case) test input data xi:
function [x,q,x_base,x_aux] = nodegridtest(shift,show)
%
% input:
% shift ... discrete shift of aux nodes 0<=shift<=125
% show ... logical flag for visualization
%
% output:
% x ... test vector
% q ... nodes ratio vector
% x_base ... fixed part
% x_aux ... shifted part
% check input
if ~(0 <= shift && shift <= 125.0)
error('shift must be in the interval [0 , 125]')
else
shift = 2*fix(shift);
end
if nargin < 2
show = false;
end
% realistic data generation
z_base = [7.0,7.0, ...
2.0, ...
3.4, ...
0.6, ...
7.25,7.25,7.25,7.25,7.25,7.25,7.25,7.25, ...
7.25,7.25,7.25,7.25,7.25,7.25,7.25,7.25, ...
7.25,7.25,7.25,7.25,7.25,7.25,7.25,7.25, ...
7.25,7.25,7.25,7.25,7.25,7.25,7.25,7.25];
z_aux = [3.4, ...
0.6, ...
6.0, ...
1.0, ...
8.0, ...
7.0, ...
17.5, ...
3.6, ...
6.4, ...
240.0];
% upper limit of x
xmax = sum(z_base) + sum(z_aux(1:6));
%
x_base = [0, cumsum(z_base)];
x_aux = x_base(end)+ [0, cumsum(z_aux)];
x_aux_actual = x_aux - shift;
x_full = union(x_base,x_aux_actual);
x = [x_full(x_full < xmax),xmax];
x_aux = [x_aux_actual(x_aux_actual < xmax),xmax];
z = diff(x);
q = max([z(1:end-1)./z(2:end);z(2:end)./z(1:end-1)],[],1);
if show
plot(x(2:end-1),q,'bo-','LineWidth',3)
title(['q distribution for shift = ' num2str(shift)])
xlabel('position');ylabel('q ratio');
hold on
xline(x_base,'k-')
xline(x_aux,'k--')
hold off
end
then simple generate test data for any integer 0<=shift<=125 like:
xi = nodegridtest(69,1)
to get

and
xi'
ans =
0
7.0000
14.0000
16.0000
19.4000
20.0000
27.2500
34.5000
41.7500
49.0000
56.2500
63.5000
70.7500
78.0000
85.2500
92.5000
99.7500
107.0000
114.0000
114.2500
117.4000
118.0000
121.5000
124.0000
125.0000
128.7500
133.0000
136.0000
140.0000
143.2500
150.5000
157.5000
157.7500
161.1000
165.0000
167.5000
172.2500
179.5000
186.7500
194.0000
201.2500
208.5000
215.7500
223.0000
230.2500
237.5000
244.7500
252.0000
278.0000
11 Kommentare
Akzeptierte Antwort
Matt J
am 24 Sep. 2025 um 14:05
Bearbeitet: Matt J
am 25 Sep. 2025 um 2:02
My thought is that you,
(1) Do not include L in your list of unknowns. Solve a series of optimization problems for fixed L=1,2,3,...
(2) Treat xo, not x, as your independent, unknown vector.
With (1) and (2), all of your listed constraints become linear, recognizing that
max(A/B,C/D)<=E
is the same as the linear constraints,
A<=B*E
C<=D*E
The only complicated constraint to express is that xi ⊂ xo. This can be done by introducing an unknown binary N+1 x (N+1+L) matrix variable P with the linear constraints,
|xi - x0|<=2*max(abs(xi)) .* (1-P)
sum(P,1)==1
sum(P,2)>=2
The objective would be rewritten as,
max q
s.t.
q<=z %additional linear constraints
This whole thing is an MILP, and can be solved with intlinprog. No need for a global solver. I would recommend setting it up with optimproblem.
13 Kommentare
Matt J
am 24 Sep. 2025 um 20:18
Bearbeitet: Matt J
am 24 Sep. 2025 um 20:24
1. condition (1) is not satisfied reliably when I create the data differently
It's because xo.Lower was hardcoded to 0. I've fixed it in the revision below.
Any idea how to speed up solver?
Not sure. Maybe by providing initial guesses for the unknowns? The example below includes one way of doing this, but you would have to try it out on realistic data sizes.
%Problem data
xi=[sort(rand(1,5))]';
L=10;
qmax=1.2;
N=numel(xi)-1;
xiMax=max(xi);
xiMin=min(xi);
U=max(abs(xiMin), abs(xiMax));
eNL=ones(N+L+1,1);
eN=ones(N+1,1);
%Unknowns
q = optimvar('q');
P = optimvar('P',N+1, L+N+1, Type='integer', Lower=0,Upper=1);
xo = optimvar('xo',L+N+1, Lower=xiMin,Upper=xiMax);
z=diff(xo);
%Constraints
Constraints.con_mono=z>=0; %monotonicity of xo
Constraints.conq= q<=z; %defines objective value q
Constraints.con2a_1=z(1:end-1)<=qmax*z(2:end); %qmax constraints
Constraints.con2a_2=z(2:end)<=qmax*z(1:end-1);
Constraints.conP_1=xi*eNL'- eN*xo' <=2*U*(1-P); %constraints on P
Constraints.conP_2=eN*xo' - xi*eNL'<=2*U*(1-P);
Constraints.conP_3=sum(P,2)==1;
Constraints.conP_4=sum(P,1)<=1;
%Solve
prob=optimproblem('Objective',q,'ObjectiveSense','max','Constraints', Constraints);
%Possible initial guess
y=linspace(xiMin,xiMax,L+2); y([1,end])=[];
sol0.xo=union(xi',y)';
sol0.P=double(xi==sol0.xo');
sol0.q=min(diff(sol0.xo));
sol = solve(prob,sol0)
xo=sol.xo'
xi'
Weitere Antworten (2)
Matt J
am 25 Sep. 2025 um 16:11
Bearbeitet: Matt J
am 25 Sep. 2025 um 16:28
Here's another formulation, closer to your original one. It uses fmincon and is really fast (when the problem is feasible), but one of the constraints is nonconvex and only piecewise differentiable. You will probably have to incorporate MultiStart to help ensure global optimality.
%Problem data
xi=[sort(rand(1,5))]';
L=10;
qmax=1.2;
N=numel(xi)-1;
xiMax=max(xi);
xiMin=min(xi);
U=max(abs(xiMin), abs(xiMax));
eNL=ones(N+L+1,1);
eN=ones(N+1,1);
%Unknowns
x = optimvar('x', L, Lower=xiMin,Upper=xiMax);
z = optimvar('z', L+N, Lower=0,Upper=xiMax-xiMin);
fobj = optimvar('fobj', Lower=0);
%Constraints
fcn=@(c)diff(sort([c(:);xi(:)]));
Constraints.con_zdef= z(:) == fcn2optimexpr(fcn,x);
Constraints.con2a_1=z(1:end-1)<=qmax*z(2:end); %qmax constraints
Constraints.con2a_2=z(2:end)<=qmax*z(1:end-1);
Constraints.obj=fobj<=z;
%Solve
prob=optimproblem('Objective',fobj,'ObjectiveSense','max','Constraints', Constraints);
sol0.x=linspace(xiMin,xiMax,L)';
sol0.z=fcn(sol0.x);
sol0.fobj=min(sol0.z);
opts=optimoptions('fmincon','StepTol',1e-10,'OptimalityTol',1e-10,'FunctionTol',1e-10, ...
'MaxFunEvals',1e7,'MaxIterations',1e5);
sol = solve(prob, sol0,Options=opts)
xo=union(xi,sol.x)'
xi'
3 Kommentare
Matt J
am 25 Sep. 2025 um 19:09
No, the output above took a blink of an eye for me. The problem is that sometimes the randomly generated problem data doesn't give an optimization problem with a feasible solution. It can take fmincon a very long time to figure out that the optimization problem is infeasible.
Matt J
am 26 Sep. 2025 um 0:13
It can take fmincon a very long time to figure out that the optimization problem is infeasible.
You can abort the optimization if it runs to long using an OuputFcn,
Matt J
am 25 Sep. 2025 um 20:42
Bearbeitet: Matt J
am 25 Sep. 2025 um 21:17
The motivation of this problem is the creation of the so called, "homogenized" 1-D grid, where consecutive distances between elements of vector xo are relatively "slowly" changing.
If so, you might consider a simplified solution using minL1intlin from this File Exchange submission,
Basically, this chooses a number of points dL(k) to place between each xi, with sum(dL)==L and in proportion to the spacing xi(k+1)-xi(k). I think this is almost what you want, though there is no qmax parameter to let you bound the z ratios. If nothing else, it may give you a good way to form an initial guess for one of the other solution methods.
%Problem data
xi=[sort(rand(1,7))]';
L=12;
% qmax=1.2;
N=numel(xi)-1;
xiMax=max(xi);
xiMin=min(xi);
dL0 = diff(xi)./(xiMax-xiMin)*L;
dL=minL1intlin(speye(N),round(dL0(:)),1:N,[],[],ones(1,N),L,zeros(N,1) );
xo=getxo(dL,xi);
check = numel(xo) == L+N+1
h=plot(xi,0*xi,'x',xo,0*xo,'o'); axis padded
set(h,'MarkerSize',8);
legend xi xo
function xo=getxo(dL,xi)
K=numel(xi)-1;
xo=cell(1,K);
for k=1:numel(xi)-1
tmp=linspace(xi(k), xi(k+1),dL(k)+2);
xo{k}=tmp(1:end-1);
end
xo=[cell2mat(xo),xi(end)];
end
3 Kommentare
Siehe auch
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!