Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add assert_is_solved_and_feasible #3925

Merged
merged 8 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions docs/src/tutorials/algorithms/benders_decomposition.jl
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ set_silent(model)
@constraint(model, [i = 2:n-1], sum(y[i, :]) == sum(y[:, i]))
@objective(model, Min, 0.1 * sum(x) - sum(y[1, :]))
optimize!(model)
Test.@test is_solved_and_feasible(model) #src
assert_is_solved_and_feasible(model) #src
solution_summary(model)

# The optimal objective value is -5.1:
Expand Down Expand Up @@ -218,7 +218,7 @@ function solve_subproblem(x_bar)
@constraint(model, [i = 2:n-1], sum(y[i, :]) == sum(y[:, i]))
@objective(model, Min, -sum(y[1, :]))
optimize!(model)
@assert is_solved_and_feasible(model; dual = true)
assert_is_solved_and_feasible(model; dual = true)
return (obj = objective_value(model), y = value.(y), π = reduced_cost.(x))
end

Expand Down Expand Up @@ -249,7 +249,7 @@ ABSOLUTE_OPTIMALITY_GAP = 1e-6
println("Iteration Lower Bound Upper Bound Gap")
for k in 1:MAXIMUM_ITERATIONS
optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
lower_bound = objective_value(model)
x_k = value.(x)
ret = solve_subproblem(x_k)
Expand All @@ -267,7 +267,7 @@ end
# Finally, we can obtain the optimal solution:

optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
x_optimal = value.(x)
optimal_ret = solve_subproblem(x_optimal)
iterative_solution = optimal_flows(optimal_ret.y)
Expand Down Expand Up @@ -338,7 +338,7 @@ if !HAS_GUROBI #hide
set_attribute(lazy_model, MOI.LazyConstraintCallback(), nothing) #hide
end #hide
optimize!(lazy_model)
@assert is_solved_and_feasible(lazy_model)
assert_is_solved_and_feasible(lazy_model)

# For this model, the callback algorithm required more solves of the subproblem:

Expand Down Expand Up @@ -396,7 +396,7 @@ subproblem
function solve_subproblem(model, x)
fix.(model[:x_copy], x)
optimize!(model)
@assert is_solved_and_feasible(model; dual = true)
assert_is_solved_and_feasible(model; dual = true)
return (
obj = objective_value(model),
y = value.(model[:y]),
Expand All @@ -409,7 +409,7 @@ end
println("Iteration Lower Bound Upper Bound Gap")
for k in 1:MAXIMUM_ITERATIONS
optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
lower_bound = objective_value(model)
x_k = value.(x)
ret = solve_subproblem(subproblem, x_k)
Expand All @@ -427,7 +427,7 @@ end
# Finally, we can obtain the optimal solution:

optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
x_optimal = value.(x)
optimal_ret = solve_subproblem(subproblem, x_optimal)
inplace_solution = optimal_flows(optimal_ret.y)
Expand Down Expand Up @@ -504,7 +504,7 @@ end
println("Iteration Lower Bound Upper Bound Gap")
for k in 1:MAXIMUM_ITERATIONS
optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
lower_bound = objective_value(model)
x_k = value.(x)
ret = solve_subproblem_with_feasibility(subproblem, x_k)
Expand All @@ -528,7 +528,7 @@ end
# Finally, we can obtain the optimal solution:

optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
x_optimal = value.(x)
optimal_ret = solve_subproblem(subproblem, x_optimal)
feasible_inplace_solution = optimal_flows(optimal_ret.y)
Expand Down
10 changes: 5 additions & 5 deletions docs/src/tutorials/algorithms/cutting_stock_column_generation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ set_silent(model)
@objective(model, Min, sum(x))
@constraint(model, demand[i in 1:I], patterns[i]' * x >= data.pieces[i].d)
optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
solution_summary(model)

# This solution requires 421 rolls. This solution is sub-optimal because the
Expand All @@ -253,7 +253,7 @@ solution_summary(model)

unset_integer.(x)
optimize!(model)
@assert is_solved_and_feasible(model; dual = true)
assert_is_solved_and_feasible(model; dual = true)
π_13 = dual(demand[13])

# Using the economic interpretation of the dual variable, we can say that a one
Expand Down Expand Up @@ -284,7 +284,7 @@ function solve_pricing(data::Data, π::Vector{Float64})
@constraint(model, sum(data.pieces[i].w * y[i] for i in 1:I) <= data.W)
@objective(model, Max, sum(π[i] * y[i] for i in 1:I))
optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
number_of_rolls_saved = objective_value(model)
if number_of_rolls_saved > 1 + 1e-8
## Benefit of pattern is more than the cost of a new roll plus some
Expand Down Expand Up @@ -315,7 +315,7 @@ solve_pricing(data, zeros(I))
while true
## Solve the linear relaxation
optimize!(model)
@assert is_solved_and_feasible(model; dual = true)
assert_is_solved_and_feasible(model; dual = true)
## Obtain a new dual vector
π = dual.(demand)
## Solve the pricing problem
Expand Down Expand Up @@ -366,7 +366,7 @@ sum(ceil.(Int, solution.rolls))

set_integer.(x)
optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
solution = DataFrames.DataFrame([
(pattern = p, rolls = value(x_p)) for (p, x_p) in enumerate(x)
])
Expand Down
4 changes: 2 additions & 2 deletions docs/src/tutorials/algorithms/parallelism.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
end
```
For more information, read
[PSA: Thread-local state is no longer recommended](https://julialang.org/blog/2023/07/PSA-dont-use-threadid/).

Check warning on line 88 in docs/src/tutorials/algorithms/parallelism.md

View workflow job for this annotation

GitHub Actions / build

[vale] reported by reviewdog 🐶 [Google.Colons] ': T' should be in lowercase. Raw Output: {"message": "[Google.Colons] ': T' should be in lowercase.", "location": {"path": "docs/src/tutorials/algorithms/parallelism.md", "range": {"start": {"line": 88, "column": 9}}}, "severity": "WARNING"}

### Thread safety

Expand Down Expand Up @@ -141,7 +141,7 @@
@variable(model, x >= i)
@objective(model, Min, x)
optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
Threads.lock(my_lock) do
push!(solutions, i => objective_value(model))
end
Expand Down Expand Up @@ -357,7 +357,7 @@
@objective(model, Min, x)
set_lower_bound(x, i)
optimize!(model)
@assert is_solved_and_feasible(sudoku)
assert_is_solved_and_feasible(sudoku)
return objective_value(model)
end
end
Expand Down
6 changes: 3 additions & 3 deletions docs/src/tutorials/algorithms/tsp_lazy_constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ if !HAS_GUROBI #hide
end #hide
iterative_model = build_tsp_model(d, n, optimizer)
optimize!(iterative_model)
@assert is_solved_and_feasible(iterative_model)
assert_is_solved_and_feasible(iterative_model)
time_iterated = solve_time(iterative_model)
cycle = subtour(iterative_model[:x])
while 1 < length(cycle) < n
Expand All @@ -225,7 +225,7 @@ while 1 < length(cycle) < n
sum(iterative_model[:x][i, j] for (i, j) in S) <= length(cycle) - 1,
)
optimize!(iterative_model)
@assert is_solved_and_feasible(iterative_model)
assert_is_solved_and_feasible(iterative_model)
global time_iterated += solve_time(iterative_model)
global cycle = subtour(iterative_model[:x])
end
Expand Down Expand Up @@ -290,7 +290,7 @@ if !HAS_GUROBI #hide
set_attribute(lazy_model, MOI.LazyConstraintCallback(), nothing) #hide
end #hide
optimize!(lazy_model)
@assert is_solved_and_feasible(lazy_model)
assert_is_solved_and_feasible(lazy_model)
objective_value(lazy_model)

#-
Expand Down
8 changes: 4 additions & 4 deletions docs/src/tutorials/applications/optimal_power_flow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
# This tutorial takes a matrix-oriented approach focused on network nodes
# that simplifies the construction of semidefinite programs.
# Another approach is to formulate the problem focusing on network lines
# (known as a _branch model_) where it is easier to work with flow
# (known as a _branch model_) where it is easier to work with flow
# constraints. A general approach is provided by
# [PowerModels.jl](https://lanl-ansi.github.io/PowerModels.jl/stable/),
# an open-source framework to a broad range of power flow model formulations
Expand Down Expand Up @@ -137,7 +137,7 @@ println("Objective value (basic lower bound) : $basic_lower_bound")

@constraint(model, sum(P_G) >= sum(P_Demand))
optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
better_lower_bound = round(objective_value(model); digits = 2)
println("Objective value (better lower bound): $better_lower_bound")

Expand Down Expand Up @@ -281,7 +281,7 @@ P_G = real(S_G)
# We're finally ready to solve our nonlinear AC-OPF problem:

optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
Test.@test isapprox(objective_value(model), 3087.84; atol = 1e-2) #src
solution_summary(model)

Expand Down Expand Up @@ -420,7 +420,7 @@ optimize!(model)

#-

Test.@test is_solved_and_feasible(model; allow_almost = true)
assert_is_solved_and_feasible(model; allow_almost = true)
sdp_relaxation_lower_bound = round(objective_value(model); digits = 2)
Test.@test isapprox(sdp_relaxation_lower_bound, 2753.04; rtol = 1e-3) #src
println(
Expand Down
6 changes: 3 additions & 3 deletions docs/src/tutorials/applications/power_systems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ function solve_economic_dispatch(generators::Vector, wind, scenario)
@constraint(model, sum(g[i] for i in 1:N) + w == scenario.demand)
## Solve statement
optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
## return the optimal value of the objective function and its minimizers
return (
g = value.(g),
Expand Down Expand Up @@ -217,7 +217,7 @@ function solve_economic_dispatch_inplace(
wind.variable_cost * w,
)
optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
push!(obj_out, objective_value(model))
push!(w_out, value(w))
push!(g1_out, value(g[1]))
Expand Down Expand Up @@ -528,7 +528,7 @@ function solve_nonlinear_economic_dispatch(
)
@constraint(model, sum(g[i] for i in 1:N) + sqrt(w) == scenario.demand)
optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
return (
g = value.(g),
w = value(w),
Expand Down
6 changes: 3 additions & 3 deletions docs/src/tutorials/applications/two_stage_stochastic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ set_silent(model)
@expression(model, z[ω in Ω], 5y[ω] - 0.1 * (x - y[ω]))
@objective(model, Max, -2x + sum(P[ω] * z[ω] for ω in Ω))
optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
solution_summary(model)

# The optimal number of pies to make is:
Expand Down Expand Up @@ -159,7 +159,7 @@ function CVaR(Z::Vector{Float64}, P::Vector{Float64}; γ::Float64)
@constraint(model, [i in 1:N], z[i] >= ξ - Z[i])
@objective(model, Max, ξ - 1 / γ * sum(P[i] * z[i] for i in 1:N))
optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
return objective_value(model)
end

Expand Down Expand Up @@ -218,7 +218,7 @@ set_silent(model)
@constraint(model, [ω in Ω], z[ω] >= ξ - Z[ω])
@objective(model, Max, -2x + ξ - 1 / γ * sum(P[ω] * z[ω] for ω in Ω))
optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)

# When ``\gamma = 0.4``, the optimal number of pies to bake is:

Expand Down
6 changes: 3 additions & 3 deletions docs/src/tutorials/conic/arbitrary_precision.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ print(model)
# Let's solve and inspect the solution:

optimize!(model)
@assert is_solved_and_feasible(model; dual = true)
assert_is_solved_and_feasible(model; dual = true)
solution_summary(model)

# The value of each decision variable is a `BigFloat`:
Expand All @@ -103,7 +103,7 @@ value.(x) .- [3 // 7, 3 // 14]
set_attribute(model, "tol_gap_abs", 1e-32)
set_attribute(model, "tol_gap_rel", 1e-32)
optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
value.(x) .- [3 // 7, 3 // 14]

# ## Rational arithmetic
Expand Down Expand Up @@ -145,7 +145,7 @@ print(model)
# Let's solve and inspect the solution:

optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
solution_summary(model)

# The optimal values are given in exact rational arithmetic:
Expand Down
8 changes: 4 additions & 4 deletions docs/src/tutorials/conic/dualization.jl
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ print(model_dual)

set_optimizer(model_primal, SCS.Optimizer)
optimize!(model_primal)
@assert is_solved_and_feasible(model_primal; dual = true)
assert_is_solved_and_feasible(model_primal; dual = true)

# (There are five rows in the constraint matrix because SCS expects problems in
# geometric conic form, and so JuMP has reformulated the `X, PSD` variable
Expand All @@ -157,7 +157,7 @@ objective_value(model_primal)

set_optimizer(model_dual, SCS.Optimizer)
optimize!(model_dual)
@assert is_solved_and_feasible(model_dual; dual = true)
assert_is_solved_and_feasible(model_dual; dual = true)

# and the solution we obtain is:

Expand Down Expand Up @@ -187,7 +187,7 @@ objective_value(model_dual)

set_optimizer(model_primal, Dualization.dual_optimizer(SCS.Optimizer))
optimize!(model_primal)
@assert is_solved_and_feasible(model_primal; dual = true)
assert_is_solved_and_feasible(model_primal; dual = true)

# The performance is the same as if we solved `model_dual`, and the correct
# solution is returned to `X`:
Expand All @@ -203,7 +203,7 @@ dual.(primal_c)

set_optimizer(model_dual, Dualization.dual_optimizer(SCS.Optimizer))
optimize!(model_dual)
@assert is_solved_and_feasible(model_dual; dual = true)
assert_is_solved_and_feasible(model_dual; dual = true)

#-

Expand Down
6 changes: 3 additions & 3 deletions docs/src/tutorials/conic/ellipse_approx.jl
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ m, n = size(S)
@constraint(model, [t; vec(Z)] in MOI.RootDetConeSquare(n))
@objective(model, Max, t)
optimize!(model)
Test.@test is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
solution_summary(model)

# ## Results
Expand Down Expand Up @@ -212,7 +212,7 @@ f = [1 - S[i, :]' * Z * S[i, :] + 2 * S[i, :]' * z - s for i in 1:m]
## The former @objective(model, Max, t)
@objective(model, Max, 1 * t + 0)
optimize!(model)
Test.@test is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
Test.@test isapprox(D, value.(Z); atol = 1e-3) #src
solve_time_1 = solve_time(model)

Expand All @@ -235,7 +235,7 @@ print_active_bridges(model)

remove_bridge(model, MOI.Bridges.Constraint.GeoMeanToPowerBridge)
optimize!(model)
Test.@test is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)

# This time, the solve took:

Expand Down
4 changes: 2 additions & 2 deletions docs/src/tutorials/conic/ellipse_fitting.jl
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ for (i, cluster) in enumerate(clusters)
)
@objective(model, Min, ζ)
optimize!(model)
@assert is_solved_and_feasible(model)
assert_is_solved_and_feasible(model)
Q, d, e = value.(model[:Q]), value.(model[:d]), value.(model[:e])
push!(ellipses_C1, Dict(:Q => Q, :d => d, :e => e))
end
Expand Down Expand Up @@ -356,7 +356,7 @@ for (i, cluster) in enumerate(clusters)
)
@objective(model, Min, ζ)
optimize!(model)
@assert is_solved_and_feasible(model; allow_almost = true)
assert_is_solved_and_feasible(model; allow_almost = true)
Q, d, e = value.(model[:Q]), value.(model[:d]), value.(model[:e])
push!(ellipses_C2, Dict(:Q => Q, :d => d, :e => e))
end
Expand Down
Loading
Loading