In [1] I discussed a geometric problem: find a point (in 2d or 3d space) as close as possible to a number of given lines. In the comments it was suggested to write this as a Second Order Cone Programming (SOCP) model. Let's give that a try.
The lines \(L_j\) are defined by two points \(p_{j,a}\) and \(p_{j,b}\).
The min sum of distances model was formulated as a general non-linear programming (NLP) model:\[\begin{align}\min&\sum_j d_j\\ &d^2_j = \frac{|p_{j,a}-q|^2 |p_{j,b}-p_{j,a}|^2 - \left[(p_{j,a}-q)\cdot (p_{j,b}-p_{j,a}) \right]^2}{|p_{j,b}-p_{j,a}|^2}\end{align}\] or \[\min_q\>\sum_j \sqrt{\frac{|p_{j,a}-q|^2 |p_{j,b}-p_{j,a}|^2 - \left[(p_{j,a}-q)\cdot (p_{j,b}-p_{j,a}) \right]^2}{|p_{j,b}-p_{j,a}|^2}}\]
Minimizing the sum of distances in SOCP models can look like:\[\begin{align}\min&\sum_j x_j\\& x_j^2 \ge \sum_i y_{j,i}^2\\& x_j \ge 0\end{align}\]
We need to shoehorn our problem into this format. Let's give this a try. Any point \(\gamma_j\) on a line \(L_j\) can be written as:\[\begin{align}\gamma_j &= (1-t_j)p_{j,a} + t_j p_{j,b}\\ &= p_{j,a} + t_j (p_{j,b}-p_{j,a})\end{align}\] The distance between \(q\) and \(\gamma_j\) is obviously \(||q-\gamma_j||_2\) or \(||\delta_j||_2\) where \( \delta_j = q-\gamma_j\).
We are getting close. Let's denote the coordinates of \(\delta_j\) as \(\delta_{j,i}\) where \(i=\{x,y,z\}\) (or \(i=\{x,y\}\) for a 2D problem). We can finally write: \[\begin{align} \min_{q,d,\delta,t}& \sum_j d_j\\ & \delta_j = p_{j,a} + t_j (p_{j,b}-p_{j,a}) - q\\ &\sum_i \delta^2_{j,i} \le d_j^2\\ &d_j \ge 0\end{align}\] This does not look so bad. We have introduced a whole slew of extra variables, but our efforts will be rewarded. We can solve this model with solvers like Cplex, Gurobi, Mosek and Xpress without resorting to a general nonlinear solver.
Unfortunately when trying this with GAMS/Cplex, I got:
This is a longstanding, known bug (many years, ough!) in the standard GAMS/Cplex link. There is an alternative, experimental link called cplexd which has some of these bugs fixed: use option qcp=cplexd; to make this work.
Formulating proper SOCP models can be somewhat of a pain. We are giving up a more natural formulation just to accommodate the solver. I.e., we are moving away from the problem to be closer to the solver. That looks to me like the wrong direction. As an extra complication: the precise rules for solvers to accept SOCP models are not uniform (some solvers are more strict than others). Solvers may do some easy reformulations. E.g. convex QP models may be reformulated automatically into SOCP models behind the scenes. In general, however, it is not so easy for a software system (either the modeling system or the solver) to recognize natural NLP formulations and automatically reformulate into acceptable SOCP models. Which unfortunately means that the task of devising (sometimes non-obvious) reformulations is off-loaded to the modeler. (Actually AMPL has facilities to do a lot of these transformations [4]).
It would be great if modeling systems could become smarter, and can reformulate standard mathematical constructs into conic formulations. One would need access to a symbolic representation of the model. I.e., when the solver sees the model, it is probably already too late to do anything but the most basic reformulations. With the advent of more exotic features such as the exponential cone this problem will only become more important.
Likely, I am somewhat in the minority here with my concerns. I believe many developers and academics are of the opinion that cone programming is the best thing since sliced bread (may be after semi-definite programming). I suspect that the obscurity of SOCP formulations is adding some mystique to the trade. However, when I develop a model, I want to have it as mystique-less as possible. Often the main goal of a model is stated as a bridge between the problem and the algorithm (or from human to machine). May be an even more important role is as communication tool between people. Clarity and simplicity is then paramount.
The reason Cplex complains, is that GAMS generates the following ugly model:
This model leads to CPLEX Error 5002: 'QCP_row_for_dist(line1)' is not convex. If we clean this up a bit by hand, we get:
Cplex is happy with this model. We see: Barrier - Optimal: Objective = 1.2652779019e-01.
The lines \(L_j\) are defined by two points \(p_{j,a}\) and \(p_{j,b}\).
![]() |
| Minimize sum of distances to set of lines in 2d |
The min sum of distances model was formulated as a general non-linear programming (NLP) model:\[\begin{align}\min&\sum_j d_j\\ &d^2_j = \frac{|p_{j,a}-q|^2 |p_{j,b}-p_{j,a}|^2 - \left[(p_{j,a}-q)\cdot (p_{j,b}-p_{j,a}) \right]^2}{|p_{j,b}-p_{j,a}|^2}\end{align}\] or \[\min_q\>\sum_j \sqrt{\frac{|p_{j,a}-q|^2 |p_{j,b}-p_{j,a}|^2 - \left[(p_{j,a}-q)\cdot (p_{j,b}-p_{j,a}) \right]^2}{|p_{j,b}-p_{j,a}|^2}}\]
Minimizing the sum of distances in SOCP models can look like:\[\begin{align}\min&\sum_j x_j\\& x_j^2 \ge \sum_i y_{j,i}^2\\& x_j \ge 0\end{align}\]
We need to shoehorn our problem into this format. Let's give this a try. Any point \(\gamma_j\) on a line \(L_j\) can be written as:\[\begin{align}\gamma_j &= (1-t_j)p_{j,a} + t_j p_{j,b}\\ &= p_{j,a} + t_j (p_{j,b}-p_{j,a})\end{align}\] The distance between \(q\) and \(\gamma_j\) is obviously \(||q-\gamma_j||_2\) or \(||\delta_j||_2\) where \( \delta_j = q-\gamma_j\).
We are getting close. Let's denote the coordinates of \(\delta_j\) as \(\delta_{j,i}\) where \(i=\{x,y,z\}\) (or \(i=\{x,y\}\) for a 2D problem). We can finally write: \[\begin{align} \min_{q,d,\delta,t}& \sum_j d_j\\ & \delta_j = p_{j,a} + t_j (p_{j,b}-p_{j,a}) - q\\ &\sum_i \delta^2_{j,i} \le d_j^2\\ &d_j \ge 0\end{align}\] This does not look so bad. We have introduced a whole slew of extra variables, but our efforts will be rewarded. We can solve this model with solvers like Cplex, Gurobi, Mosek and Xpress without resorting to a general nonlinear solver.
Unfortunately when trying this with GAMS/Cplex, I got:
CPLEX Error 5002: 'QCP_row_for_dist(line1)' is not convex.
This is a longstanding, known bug (many years, ough!) in the standard GAMS/Cplex link. There is an alternative, experimental link called cplexd which has some of these bugs fixed: use option qcp=cplexd; to make this work.
Ciritique (a.k.a. rant)
Formulating proper SOCP models can be somewhat of a pain. We are giving up a more natural formulation just to accommodate the solver. I.e., we are moving away from the problem to be closer to the solver. That looks to me like the wrong direction. As an extra complication: the precise rules for solvers to accept SOCP models are not uniform (some solvers are more strict than others). Solvers may do some easy reformulations. E.g. convex QP models may be reformulated automatically into SOCP models behind the scenes. In general, however, it is not so easy for a software system (either the modeling system or the solver) to recognize natural NLP formulations and automatically reformulate into acceptable SOCP models. Which unfortunately means that the task of devising (sometimes non-obvious) reformulations is off-loaded to the modeler. (Actually AMPL has facilities to do a lot of these transformations [4]).
It would be great if modeling systems could become smarter, and can reformulate standard mathematical constructs into conic formulations. One would need access to a symbolic representation of the model. I.e., when the solver sees the model, it is probably already too late to do anything but the most basic reformulations. With the advent of more exotic features such as the exponential cone this problem will only become more important.
Likely, I am somewhat in the minority here with my concerns. I believe many developers and academics are of the opinion that cone programming is the best thing since sliced bread (may be after semi-definite programming). I suspect that the obscurity of SOCP formulations is adding some mystique to the trade. However, when I develop a model, I want to have it as mystique-less as possible. Often the main goal of a model is stated as a bridge between the problem and the algorithm (or from human to machine). May be an even more important role is as communication tool between people. Clarity and simplicity is then paramount.
References
- Geometry lesson: find point closest to set of lines, http://yetanothermathprogrammingconsultant.blogspot.com/2018/04/geometry-lesson-find-point-closest-to.html
- Mosek Modeling Cookbook, https://docs.mosek.com/MOSEKModelingCookbook-letter.pdf. This has a good overview of SOCP formulation tricks.
- DCP, Disciplined Convex Programming, http://dcp.stanford.edu/. Modeling tools based on DCP can help to formulate proper SOCP models.
- Victor Zverovich, Robert Fourer, Automatic Reformulation of Second-Order Cone Programming Problems, https://ampl.com/MEETINGS/TALKS/2015_01_Richmond_2E.2.pdf
Appendix: An example of a picky solver
The reason Cplex complains, is that GAMS generates the following ugly model:
\ENCODING=ISO-8859-1
\Problem name: gamsmodel
Minimize
_obj: d(line1) + d(line2) + d(line3) + z
Subject To
_eline(line1.x)#0: 0.757256448 t(line1) + q(x) + delta(line1.x)
= -0.656505736
_eline(line1.y)#1: - 1.084257608 t(line1) + q(y) + delta(line1.y)
= 0.686533416
_eline(line2.x)#2: 0.115236774 t(line2) + q(x) + delta(line2.x)
= -0.415575766
_eline(line2.y)#3: 1.26443496 t(line2) + q(y) + delta(line2.y) = -0.551894266
_eline(line3.x)#4: 1.862007808 t(line3) + q(x) + delta(line3.x)
= -0.865772554
_eline(line3.y)#5: 0.157045418 t(line3) + q(y) + delta(line3.y)
= 0.000421337999999993
dist(line1)#6: - linear_part_of_dist(line1) = 0
dist(line2)#7: - linear_part_of_dist(line2) = 0
dist(line3)#8: - linear_part_of_dist(line3) = 0
obj#9: z = 0
QCP_row_for_dist(line1): linear_part_of_dist(line1) + [ delta(line1.x) ^2
+ delta(line1.y) ^2 - d(line1) ^2 ] <= 0
QCP_row_for_dist(line2): linear_part_of_dist(line2) + [ delta(line2.x) ^2
+ delta(line2.y) ^2 - d(line2) ^2 ] <= 0
QCP_row_for_dist(line3): linear_part_of_dist(line3) + [ delta(line3.x) ^2
+ delta(line3.y) ^2 - d(line3) ^2 ] <= 0
Bounds
t(line1) Free
t(line2) Free
t(line3) Free
q(x) Free
q(y) Free
delta(line1.x) Free
delta(line1.y) Free
delta(line2.x) Free
delta(line2.y) Free
delta(line3.x) Free
delta(line3.y) Free
z Free
linear_part_of_dist(line1) Free
linear_part_of_dist(line2) Free
linear_part_of_dist(line3) Free
End
This model leads to CPLEX Error 5002: 'QCP_row_for_dist(line1)' is not convex. If we clean this up a bit by hand, we get:
\ENCODING=ISO-8859-1
\Problem name: gamsmodel
Minimize
_obj: d(line1) + d(line2) + d(line3)
Subject To
_eline(line1.x)#0: 0.757256448 t(line1) + q(x) + delta(line1.x)
= -0.656505736
_eline(line1.y)#1: - 1.084257608 t(line1) + q(y) + delta(line1.y)
= 0.686533416
_eline(line2.x)#2: 0.115236774 t(line2) + q(x) + delta(line2.x)
= -0.415575766
_eline(line2.y)#3: 1.26443496 t(line2) + q(y) + delta(line2.y) = -0.551894266
_eline(line3.x)#4: 1.862007808 t(line3) + q(x) + delta(line3.x)
= -0.865772554
_eline(line3.y)#5: 0.157045418 t(line3) + q(y) + delta(line3.y)
= 0.000421337999999993
QCP_row_for_dist(line1): [ delta(line1.x) ^2
+ delta(line1.y) ^2 - d(line1) ^2 ] <= 0
QCP_row_for_dist(line2): [ delta(line2.x) ^2
+ delta(line2.y) ^2 - d(line2) ^2 ] <= 0
QCP_row_for_dist(line3): [ delta(line3.x) ^2
+ delta(line3.y) ^2 - d(line3) ^2 ] <= 0
Bounds
t(line1) Free
t(line2) Free
t(line3) Free
q(x) Free
q(y) Free
delta(line1.x) Free
delta(line1.y) Free
delta(line2.x) Free
delta(line2.y) Free
delta(line3.x) Free
delta(line3.y) Free
End
Cplex is happy with this model. We see: Barrier - Optimal: Objective = 1.2652779019e-01.
