J.V.
J.V.

Reputation: 67

PerspectiveQuadraticCost in PyDrake, solving with MOSEK

I'm trying to solve an optimization problem that uses the PerspectiveQuadraticCost function defined in Drake. According to a 2022 paper "Motion Planning Around Obstacles with Convex Optimization", a perspective quadratic cost term can capture the cost

\frac{||\dot{r}_i||_2^2}{\dot{h}_i}

which is convex, if \dot{h}_i > 0. I see in the code GCS code base; https://github.com/mpetersen94/gcs that this is implemented using the PerspectiveQuadraticConstraint and solved with the MOSEK solver. I am assuming it is therefore that MOSEK is one of the solvers which considers this as a convex constraint (the PerspectiveQuadraticCost documentation mentions that 'most' solvers consider it as non-convex).

My problem arises when I wish to do something similar, but not on the GCS class structure (consisting of edges etc.). It seems MathematicalProgram does not have any member functions associated of the form AddPerspectiveQuadraticCost and prog.AddCost(PerspectiveQuadraticCost,vars) gives a non-supported GenericCost error. The code in GCS assigns a cost to an edge according to

H = np.vstack(((self.order) * b_ctrl, np.matmul(np.sqrt(weight_matrix), A_ctrl)))
energy_cost = PerspectiveQuadraticCost(H, np.zeros(H.shape[0]))
self.edge_costs.append(energy_cost)

for edge in self.gcs.Edges():
    if edge.u() == self.source:
       continue
    edge.AddCost(Binding[Cost](energy_cost, edge.xu()))

which seems to be allowed (I run the code successfully). My example is as

H = np.stack(((self.order)*b_ctrl[0], weight*A_ctrl[0]))
energy_cost = PerspectiveQuadraticCost(H, np.zeros(H.shape)
self.prog.AddCost(energy_cost,self.rh_var_flat)

My question: How can I add a PerspectiveQuadraticCost to my problem without using any of the GCS base-code (edges, convex sets)? Is this currently supported? If not, is there a specific workaround?

An additional peculiarity, which might be connected in some way, is that the L2NormCost seems to not have been implemented for MOSEK (it throws the error ValueError: MosekSolver is unable to solve because a L2NormCost was declared but is not supported.) after invoking self.prog.AddL2NormCost(). However, also in the GCS code, this cost term is assigned to the edges of the graph via the Binding mentioned above.

update: it seems to be working with the SnoptSolver(), yet I need to introduce some binary variables, which is why I want to use MosekSolveR()

Thank you in advance for any help you could provide!

Upvotes: 0

Views: 132

Answers (1)

Russ Tedrake
Russ Tedrake

Reputation: 5543

In both cases, Mosek (and other convex solvers) do not know how to consume these directly. You have to rewrite them using slack variables. I have a method in the GCS implementation which does exactly this, with a TODO to move it to the public API. I agree it would be useful.

In the short term, you would need to implement the objectives using slack variables and constraints yourself.

Upvotes: 1

Related Questions