When I previously did optimization with IPOPT, I only found one global minimum. It recently occurred to me that some problems have multiple global minima and these could be found by IPOPT, given enough random starting points. The code finds all the results with the lowest objective function value and then does a same test on the variable results to eliminate variable results which are close to each other.
The inputs to to iMin are the
objective (obj),
the constraints (cons),
the variables with bounds (vwb),
the startsIn, which is list of starting points or the number of random points and the random seed,
and the unionsametestval, which is used to remove nearly identical lists of variables in which the objective value is the global minimum.

Parametric IPOPT Minimize Code

In[]:=
Needs["IPOPTLink`"]
In[]:=
statusrl={0"Solve_Succeeded",1"Solved_To_Acceptable_Level",2"Infeasible_Problem_Detected",3"Search_Direction_Becomes_Too_Small",4"Diverging_Iterates",5"User_Requested_Stop",6"Feasible_Point_Found",-1"Maximum_Iterations_Exceeded",-2"Restoration_Failed",-3"Error_In_Step_Computation",-4"Maximum_CpuTime_Exceeded",-10"Not_Enough_Degrees_Of_Freedom",-11"Invalid_Problem_Definition",-12"Invalid_Option",-13"Invalid_Number_Detected",-100"Unrecoverable_Exception",-101"NonIpopt_Exception_Thrown",-102"Insufficient_Memory",-199"Internal_Error"};
In[]:=
iMin[obj_,cons_List,vwb_List,startsIn_List,unionsametestval_,opts___]:=​​Block{lecons,consviol,vars,lbubs,cfuns,clbubs,v,lb,ub,params,param,pip,starts,nrands,seed,pres,listres,status,goodres,finalres,resrl,minmin,minmins,minmins1,coords,ucoords},​​​​lecons=cons/.​​ (a_==b_)->LessEqual[0,a-b,0],​​ (a_<=b_)->LessEqual[-∞,a-b,0],​​ (a_>=b_)->LessEqual[0,a-b,∞]​​;​​​​consviol=cons/.{Equal[x_,y_]Abs[x-y],LessEqual[x_,y_]Max[x-y,0],GreaterEqual[x_,y_]Max[y-x,0],LessEqual[lb_,x_,ub_]Max[0,lb-x,x-ub]};​​​​{vars,lbubs}=Transpose[vwb/.​​{v_,lb_?NumericQ,ub_?NumericQ}{v,{lb,ub}}];​​​​If[Length[cons]0,{cfuns,clbubs}={{},{}},​​{cfuns,clbubs}=Transpose[lecons/.LessEqual[lb_,v_,ub_]{v,{lb,ub}}]​​];​​​​params=Table[param[i],{i,Length[vwb]}];​​pip=ParametricIPOPTMinimize[obj,vars,params,lbubs,cfuns,clbubs,params,"RuntimeOptions"{"WarningMessages"False},opts];​​​​If[MatrixQ[startsIn],​​starts=startsIn,​​{nrands,seed}=startsIn;​​SeedRandom[seed];​​starts=Transpose[BlockRandom[RandomReal[#,nrands]&/@lbubs]]​​];​​​​pres=pip@@@starts;​​listres={IPOPTMinValue[#],IPOPTArgMin[#],IPOPTReturnCode[#]}&/@pres;​​IPOPTDataDelete/@pres;​​status=listresAll,3;​​Print[Tally[status]/.{s_,n_Integer}{s/.statusrl,n}];​​goodres=Select[listres,Or[#〚3〛0,#〚3〛1]&];​​minmin=Min[goodres[[All,1]]];​​minmins=Selectgoodres,#[[1]]<=minmin+
-4
10
&;​​coords=minmins[[All,2]];​​ucoords=Union[coords,SameTest->(Norm[#1-#2]<=10^-1&)];​​Table[{minmin,Thread[vars->ucoords[[i]]]},{i,Length[ucoords]}]​​

Circle PackingCode

xyvars[nCircs_Integer]:=Flatten@Table[{x[i],y[i]},{i,nCircs}]​​xyvarswb[nCircs_Integer]:=Thread[{xyvars[nCircs],-1.5,1.5}]​​varswb[nCircs_Integer]:=Join[xyvarswb[nCircs],{{s,1,4}}]​​inCons[s_,radii_List]:=Flatten@Table[Thread[s>=2(radii[[i]]+{x[i],-x[i],y[i],-y[i]})],{i,Length[radii]}]​​nOvLapCons[radii_List]:=Flatten@Table
2
(x[i]-x[j])
+
2
(y[i]-y[j])
>=
2
(radii[[i]]+radii[[j]])
,{i,Length[radii]-1},{j,i+1,Length[radii]}​​allCons[s_,radii_List]:=Join[inCons[s,radii],nOvLapCons[radii]]​​plt[sln_,radii_List]:=​​Show​​Graphics@Line
s
2
{{-1,-1},{1,-1},{1,1},{-1,1},{-1,-1}}/.sln[[2]],​​Graphics@TableHue
i-1
Length[radii]
,Disk[{x[i],y[i]}/.sln[[2]],radii[[i]]],{i,Length[radii]},​​Frame->True,ImageSize->Small​​

Test with Function

In[]:=
iMin
4
x
+
4
y
+
4
z
+x*y*z,
2
x
+
2
y
+
2
z
>=
1
4
,{{x,-1,1},{y,-1,1},{z,-1,1}},{100,0},
-8
10
//TableForm
{{Solve_Succeeded,100}}
Out[]//TableForm=
-0.00322293
x-0.288675
y-0.288675
z-0.288675
-0.00322293
x-0.288675
y0.288675
z0.288675
-0.00322293
x0.288675
y-0.288675
z0.288675
-0.00322293
x0.288675
y0.288675
z-0.288675

Circle Packing Test

Circle Packing requires a higher value for union same test, as some of the circles can move freely among the other circles.

2 Circles

In[]:=
n=2;radii=
-1/2
Range[n]
;
In[]:=
AbsoluteTiming[sln[n]=iMin[s,allCons[s,radii],varswb[n],{10,0},0.1];]
{{Solve_Succeeded,10}}
Out[]=
{0.0721173,Null}
In[]:=
Table[plt[sln[n][[i]],radii],{i,Length@sln[n]}]
Out[]=

,
,
,


3 Circles

In[]:=
n=3;radii=
-1/2
Range[n]
;
In[]:=
AbsoluteTiming[sln[n]=iMin[s,allCons[s,radii],varswb[n],{100,0},0.1];]
{{Solve_Succeeded,100}}
Out[]=
{0.725482,Null}
In[]:=
Table[plt[sln[n][[i]],radii],{i,Length@sln[n]}]
Out[]=

,
,
,
,
,
,
,


4 Circles

5 Circles

CITE THIS NOTEBOOK

Finding all global minima with IPOPT (Interior Point OPTimizer)​
by Frank Kampas​
Wolfram Community, STAFF PICKS, August 31, 2026
​https://community.wolfram.com/groups/-/m/t/3790113