Quadratic objectives with variables on separate nodes is not supported
Closed this issue · 3 comments
Plasmo seems to only support quadratic objectives when the two terms of the quadratic objectives are on the same node. If a quadratic term is added to the objective function which has variables on separate nodes, the line here returns an error. The example below returns the error:
using Plasmo, JuMP, Ipopt
graph = OptiGraph()
set_optimizer(graph, Ipopt.Optimizer)
@optinode(graph, nodes[1:4])
for (i, node) in enumerate(nodes)
@variable(node, x >= i)
@objective(node, Min, 2 * x^2)
end
optimize!(graph)
obj_func = objective_function(graph)
new_term = UnorderedPair(nodes[1][:x], nodes[2][:x])
obj_func.terms[new_term] = 3.0
optimize!(graph)
On the modeling side, this can be avoided by placing dummy variables on each node and then adding a linking constraint between the dummy variable and the variable it represents, but it could be nice to someday support quadratic objectives on different nodes.
I am not sure if this is sufficient (or robust), but I currently avoid this error by changing these lines into the following code:
for (i, terms) in enumerate(quad_terms(obj))
term1 = terms[2]
term2 = terms[3]
node1 = optinode(term1)
node2 = optinode(term2)
#@assert optinode(term1) == optinode(term2)
moi_term1 = index(term1)
moi_term2 = index(term2)
node_idx_map1 = backend(node1).optimizers[graph.id].node_to_optimizer_map
node_idx_map2 = backend(node2).optimizers[graph.id].node_to_optimizer_map
new_moi_idx_1 = node_idx_map1[moi_term1]
new_moi_idx_2 = node_idx_map2[moi_term2]
moi_obj = _swap_quad_term!(moi_obj, i, new_moi_idx_1, new_moi_idx_2)
end
When I make this change, I no longer get an error. I have quadratic terms with variables from separate nodes, and the OptiGraph solves without issue.
This should work now in v0.6. The following example demonstrates what you should be able to do:
using Plasmo, JuMP, Ipopt
graph = OptiGraph()
set_optimizer(graph, Ipopt.Optimizer)
@optinode(graph, nodes[1:4])
for (i, node) in enumerate(nodes)
@variable(node, x >= i)
@objective(node, Min, 2 * x^2)
end
node_objectives = sum([objective_function(node) for node in nodes])
# set quadratic over multiple nodes
@objective(graph, Min, node_objectives + nodes[1][:x]^2*nodes[2][:x]^2)
optimize!(graph)