Skip to content

Commit

Permalink
fix issues with operators
Browse files Browse the repository at this point in the history
  • Loading branch information
jalving committed Jun 18, 2024
1 parent 7a03518 commit 5babcc3
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 69 deletions.
2 changes: 1 addition & 1 deletion src/Plasmo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ num_local_link_constraints, num_link_constraints,

local_link_constraints, all_link_constraints,

set_node_objectives,
set_to_node_objectives,

containing_optigraphs, source_graph, assemble_optigraph,

Expand Down
5 changes: 5 additions & 0 deletions src/backends/moi_backend.jl
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@ end

# element attributes

# By default, just try to get the attribute from the graph MOI backend
function MOI.get(backend::GraphMOIBackend, attr::MOI.AnyAttribute, element::OptiElement)
return MOI.get(backend.moi_backend, attr)
end

function MOI.get(backend::GraphMOIBackend, attr::MOI.NumberOfVariables, node::OptiNode)
return length(backend.node_variables[node])
end
Expand Down
2 changes: 1 addition & 1 deletion src/optigraph.jl
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ end
# Objective function
#

function set_node_objectives(graph::OptiGraph)
function set_to_node_objectives(graph::OptiGraph)
obj = 0
for node in all_nodes(graph)
if has_objective(node)
Expand Down
2 changes: 2 additions & 0 deletions test/test_moi_backend.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# TODO: specific tests for MOI backend.

module TestMOIGraph

using Plasmo
Expand Down
93 changes: 60 additions & 33 deletions test/test_optigraph.jl
Original file line number Diff line number Diff line change
Expand Up @@ -146,19 +146,18 @@ function test_optigraph()
@objective(n3, Min, n3[:x][1]^2 + n3[:x][2]^2)
@objective(n4, Min, n4[:x]^2)

set_node_objectives(graph)
set_to_node_objectives(graph)
@test objective_function(graph) == n1[:x] - n2[:x] + n3[:x][1]^2 + n3[:x][2]^2 + n4[:x]^2
@objective(n4, Min, n4[:x]^3)
set_node_objectives(graph)
set_to_node_objectives(graph)
@test typeof(objective_function(graph)) == GenericNonlinearExpr{NodeVariableRef}

JuMP.set_optimizer(graph, Ipopt.Optimizer)
set_optimizer(graph, optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0))
JuMP.optimize!(graph)
@test graph.is_model_dirty == false
@test JuMP.termination_status(graph) == MOI.LOCALLY_SOLVED
end


function test_subgraphs()
graph = OptiGraph(;name=:root)

Expand Down Expand Up @@ -218,7 +217,7 @@ function test_subgraphs()
# optimize root graph
set_optimizer(graph, optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0))
optimize!(graph)
@test JuMP.termination_status(graph) == MOI.LOCALLY_SOLVED
@test termination_status(graph) == MOI.LOCALLY_SOLVED

# check that node solution matches source graph solution
@test value(n11[:x]) == value(sg1, n11[:x])
Expand Down Expand Up @@ -251,8 +250,7 @@ function test_variables()
optimize!(graph)
@test value(n1[:x]) == 0

# TODO
# set start value
# TODO: set start value
# set_start_value(n2[:x], 3.0)
# @test start_value(n2[:x]) == 3.0

Expand All @@ -266,50 +264,79 @@ function test_variables()
optimize!(graph)
end

function test_nonlinear_operators()
graph = _create_test_nonlinear_optigraph()
n1 = graph[1]

# setup node operator
square(x) = x^2
f(x, y) = (x - 1)^2 + (y - 2)^2

@operator(n1, op_square, 1, square)
@operator(n1, op_f, 2, f)
@objective(n1, Min, op_f(n1[:x], op_square(n1[:y])))

set_to_node_objectives(graph)
set_optimizer(graph, optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0))
optimize!(graph)

@test value(op_square(n1[:x])) != nothing
@test value(op_f(n1[:x], n1[:y])) != nothing

n2 = graph[2]
@operator(graph, op_f_graph, 2, f)
@linkconstraint(graph, con_ref, op_f_graph(n2[:x],n2[:y]) + n1[:x] >= 0)
@test num_constraints(graph) == 60
optimize!(graph)
@test dual(con_ref) != nothing
@test value(op_f_graph(n2[:x],n2[:y])) != nothing
end

function test_assemble_optigraph()
graph = _create_test_nonlinear_optigraph()
new_optigraph = assemble_optigraph(all_nodes(graph), all_edges(graph))
new_graph = assemble_optigraph(all_nodes(graph), all_edges(graph))

@test num_nodes(new_graph) == num_nodes(graph)
@test num_variables(new_graph) == num_variables(graph)
@test num_constraints(new_graph) == num_constraints(graph)
@test num_link_constraints(new_graph) == num_link_constraints(graph)

@test num_nodes(new_optigraph) == num_nodes(graph)
@test num_variables(new_optigraph) == num_variables(graph)
@test num_constraints(new_optigraph) == num_constraints(graph)
@test num_link_constraints(new_optigraph) == num_link_constraints(graph)
set_optimizer(graph, optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0))
optimize!(graph)

set_optimizer(new_graph, optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0))
optimize!(new_graph)
@test termination_status(new_graph) == MOI.LOCALLY_SOLVED
@test value.(all_variables(graph)) == value.(all_variables(new_graph))
end

function test_multiple_solves()
graph = _create_test_nonlinear_optigraph()
n1 = graph[1]
set_optimizer(graph, optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0))
optimize!(graph)
@test isapprox(value(n1[:x]), 1, atol=1e-6)

n1 = graph[1]
set_lower_bound(n1[:x], 1.5)
optimize!(graph)
@test isapprox(value(n1[:x]), 1.5, atol=1e-6)

set_start_value(n1[:x], 10)
optimize!(graph)
@test isapprox(value(n1[:x]), 1.5, atol=1e-6)
@test start_value(n1[:x]) == 10

# TODO: support variable attributes on optigraph
set_start_value(graph, n1[:x], 20)
@linkconstraint(graph, sum(all_variables(graph)) <= 100)
optimize!(graph)
@test isapprox(value(n1[:x]), 1.5, atol=1e-6)
@test start_value(graph, n1[:x]) == 20
@test graph.moi_backend.optimizer.model.variable_primal_start[1] == 20
@test termination_status(graph) == MOI.LOCALLY_SOLVED
end

# function test_optimizer_attributes()
# graph = _create_optigraph()
# set_optimizer(graph, optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0))
# JuMP.set_optimizer_attribute(graph, "max_cpu_time", 1e2)
# @test JuMP.get_optimizer_attribute(graph, "max_cpu_time") == 100.0
# end
function test_optimizer_attributes()
graph = _create_test_nonlinear_optigraph()
set_optimizer(graph, optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0))

set_optimizer_attribute(graph, "max_cpu_time", 1e2)
@test get_optimizer_attribute(graph, "max_cpu_time") == 100.0
end

# function test_nlp_exceptions()
# @test_throws Exception @NLconstraint(graph, graph[1][:x]^3 >= 0)
# end
function test_nlp_exceptions()
graph = _create_test_nonlinear_optigraph()
@test_throws Exception @NLconstraint(graph, graph[1][:x]^3 >= 0)
end

function run_tests()
for name in names(@__MODULE__; all=true)
Expand Down
68 changes: 34 additions & 34 deletions test/test_partition.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ module TestPartition

using Plasmo
using KaHyPar
using Ipopt
using Suppressor
using Test

kahypar_config = (@__DIR__) * "/cut_kKaHyPar_sea20.ini"

function _create_optigraph()
optigraph = OptiGraph()
@optinode(optigraph, nodes[1:4])
function _create_simple_optigraph()
graph = OptiGraph()
@optinode(graph, nodes[1:4])

#node 1
@variable(nodes[1], 0 <= x <= 2)
Expand All @@ -20,7 +21,7 @@ function _create_optigraph()
#node 2
@variable(nodes[2], x >= 1)
@variable(nodes[2], 0 <= y <= 5)
@NLconstraint(nodes[2], exp(x) + y <= 7)
@constraint(nodes[2], exp(x) + y <= 7)
@objective(nodes[2], Min, x)

#node 3
Expand All @@ -35,12 +36,11 @@ function _create_optigraph()
@constraint(nodes[4], x + y <= 3)
@objective(nodes[4], Max, y)

#Link constraints take the same expressions as the JuMP @constraint macro
@linkconstraint(optigraph, nodes[1][:x] == nodes[2][:x])
@linkconstraint(optigraph, nodes[2][:y] == nodes[3][:x])
@linkconstraint(optigraph, nodes[3][:x] == nodes[4][:x])
@linkconstraint(graph, nodes[1][:x] == nodes[2][:x])
@linkconstraint(graph, nodes[2][:y] == nodes[3][:x])
@linkconstraint(graph, nodes[3][:x] == nodes[4][:x])

return optigraph
return graph
end

function _create_chain_optigraph()
Expand All @@ -55,31 +55,31 @@ function _create_chain_optigraph()
return graph
end

# function test_partition_manual()
# graph = OptiGraph()
# @optinode(graph, nodes[1:100])
# for node in nodes
# @variable(node, x >= 0)
# end
# for j in 1:99
# @linkconstraint(graph, nodes[j][:x] == nodes[j + 1][:x])
# end
# A = reshape(nodes, 20, 5)
# node_vectors = [A[c, :] for c in 1:size(A, 1)]
# partition = Partition(graph, node_vectors)
# @test length(partition.subpartitions) == 20
# @test num_nodes(graph) == 100
# apply_partition!(graph, partition)
# @test num_nodes(graph) == 0
# @test num_all_nodes(graph) == 100

# @test Plasmo.n_subpartitions(partition) == 20
# @test optinodes(partition) == OptiNode[]
# @test optiedges(partition) == optiedges(graph)
# @test length(Plasmo.all_subpartitions(partition)) == 20
# @test Base.string(partition) == "OptiGraph Partition w/ 20 subpartitions"
# @test Plasmo.graph_depth(graph) == 1
# end
function test_partition_manual()
graph = _create_chain_optigraph()

@objective(graph, Min, sum(all_variables(graph)))
set_optimizer(graph, optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0))
optimize!(graph)

obj_val = objective_value(graph)

nodes = all_nodes(graph)
A = reshape(nodes, 20, 5)
node_vectors = [A[c, :] for c in 1:size(A, 1)]
partition = Partition(graph, node_vectors)
@test length(partition.subpartitions) == 20
@test num_nodes(graph) == 100
apply_partition!(graph, partition)
@test num_local_nodes(graph) == 0
@test num_nodes(graph) == 100

@objective(graph, Min, sum(all_variables(graph)))
set_optimizer(graph, optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0))
optimize!(graph)

@test objective_value(graph) == obj_val
end

# function test_node_vector_partition()
# graph = _create_optigraph()
Expand Down

0 comments on commit 5babcc3

Please sign in to comment.