pythoncvxpyscs

cvxpy solvers produce solutions of different shapes?


I am trying to use maxrect's get_maximal_rectangle, which uses cvxpy under the hood.

With the shapely polygon: POLYGON ((0 0.95, 0 2, 2 2, 2 1.95, 0 0.95))

max_hull = shapely.wkt.loads('POLYGON ((0 0.95, 0 2, 2 2, 2 1.95, 0 0.95))') # this is a sample of a dynamically generated valid, simple, convex polygon
max_rect = get_maximal_rectangle(max_hull.exterior.coords[:-1])
print('max rectangle', max_rect)

this produces the error

Either candidate conic solvers (['CVXOPT']) do not support the cones output by the problem (ExpCone, NonNeg, Zero), or there are not enough constraints in the problem.

so I checked maxrect's github issues. someone else reported the same problem. they solved it by modifying the call to cvx solve. So, I downloaded the source and modified the call to solve: prob.solve(solver=cvxpy.CVXOPT, verbose=False, max_iters=1000, reltol=1e-9) to just call it empty at first prob.solve(), but that produces

Solver 'ECOS' failed. Try another solver, or solve with verbose=True for more information.

(and verbose gives me no additional detail after "Invoking solver ECOS to obtain a solution")

so I thought to use SCS. It works, actually, but here the solution values don't have the right shape(!?). the get_maximal_rectangle function wants to return list(bottom_left[0]), list(top_right[0]), but this raises

TypeError: 'numpy.float64' object is not iterable

if I print bottom left and top_right I see 4 values:

[-3.86442831e+01 -2.49322910e+06] [ 8.14325412e+02 -2.03083800e+06]

but its hard to treat these as coordinates because 1. they are negative, so they are not inscribed in my polygon, and 2. it seems like the solver should return the same shape as CVXOPT.


Solution

  • I found success in customizing this library for modern use.

        prob = cvxpy.Problem(obj, constraints)
        #prob.solve(solver=cvxpy.CVXOPT, verbose=False, max_iters=1000, reltol=1e-9)
        prob.solve()
    
        bottom_left = np.array(bl.value).T * scale
        top_right = np.array(tr.value).T * scale
        
        #return list(bottom_left[0]), list(top_right[0])
        return bottom_left, top_right
    

    to convert the results back into a shapely object:

        pa = get_maximal_rectangle(maximum_plot.exterior.coords)
        return Polygon([(pa[0][0],pa[0][1]), (pa[0][0],pa[1][1]), (pa[1][0],pa[1][1]), (pa[1][0],pa[0][1])])