Skip to content

Commit

Permalink
Change to s_solved_and_feasible
Browse files Browse the repository at this point in the history
  • Loading branch information
odow committed Feb 13, 2024
1 parent 3056246 commit 5364a31
Show file tree
Hide file tree
Showing 54 changed files with 176 additions and 178 deletions.
14 changes: 7 additions & 7 deletions docs/src/manual/solutions.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,25 @@ Subject to

## Check if an optimal solution exists

Use [`has_optimal_solution`](@ref) to check if the solver found an optimal
Use [`is_solved_and_feasible`](@ref) to check if the solver found an optimal
solution:
```jldoctest solutions
julia> has_optimal_solution(model)
julia> is_solved_and_feasible(model)
true
```

By default, [`has_optimal_solution`](@ref) returns `true` for both global and
By default, [`is_solved_and_feasible`](@ref) returns `true` for both global and
local optima. Pass `allow_local = false` to check if the solver found a globally
optimal solution:
```jldoctest solutions
julia> has_optimal_solution(model; allow_local = false)
julia> is_solved_and_feasible(model; allow_local = false)
true
```

Pass `dual = true` to check if the solver found an optimal dual solution in
addition to an optimal primal solution:
```jldoctest solutions
julia> has_optimal_solution(model; dual = true)
julia> is_solved_and_feasible(model; dual = true)
true
```

Expand Down Expand Up @@ -298,12 +298,12 @@ And data, a 2-element Vector{Float64}:
You should always check whether the solver found a solution before calling
solution functions like [`value`](@ref) or [`objective_value`](@ref).

A simple approach is to use [`has_optimal_solution`](@ref):
A simple approach is to use [`is_solved_and_feasible`](@ref):

```jldoctest solutions
julia> function solve_and_print_solution(model)
optimize!(model)
if !has_optimal_solution(model; dual = true)
if !is_solved_and_feasible(model; dual = true)
error("The model was not solved correctly.")
end
println("Solution is optimal")
Expand Down
14 changes: 7 additions & 7 deletions docs/src/tutorials/algorithms/benders_decomposition.jl
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ function solve_subproblem(x)
con = @constraint(model, A_2 * y .<= b - A_1 * x)
@objective(model, Min, c_2' * y)
optimize!(model)
@assert has_optimal_solution(model; dual = true)
@assert is_solved_and_feasible(model; dual = true)
return (obj = objective_value(model), y = value.(y), π = dual.(con))
end

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

optimize!(model)
@assert has_optimal_solution(model)
@assert is_solved_and_feasible(model)
Test.@test value.(x) == [0.0, 1.0] #src
x_optimal = value.(x)

Expand Down Expand Up @@ -270,7 +270,7 @@ set_attribute(lazy_model, MOI.LazyConstraintCallback(), my_callback)
# Now when we optimize!, our callback is run:

optimize!(lazy_model)
@assert has_optimal_solution(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 @@ -326,7 +326,7 @@ print(subproblem)
function solve_subproblem(model, x)
fix.(model[:x_copy], x)
optimize!(model)
@assert has_optimal_solution(model; dual = true)
@assert is_solved_and_feasible(model; dual = true)
return (
obj = objective_value(model),
y = value.(model[:y]),
Expand All @@ -344,7 +344,7 @@ end
println("Iteration Lower Bound Upper Bound Gap")
for k in 1:MAXIMUM_ITERATIONS
optimize!(model)
@assert has_optimal_solution(model)
@assert is_solved_and_feasible(model)
lower_bound = objective_value(model)
x_k = value.(x)
ret = solve_subproblem(subproblem, x_k)
Expand All @@ -362,7 +362,7 @@ end
# Finally, we can obtain the optimal solution:

optimize!(model)
@assert has_optimal_solution(model)
@assert is_solved_and_feasible(model)
Test.@test value.(x) == [0.0, 1.0] #src
x_optimal = value.(x)

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 has_optimal_solution(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 has_optimal_solution(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 has_optimal_solution(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 has_optimal_solution(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 has_optimal_solution(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
6 changes: 3 additions & 3 deletions docs/src/tutorials/algorithms/parallelism.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ my_lock = Threads.ReentrantLock()
Threads.@threads for i in 1:10
set_lower_bound(x, i)
optimize!(model)
@assert has_optimal_solution(model)
@assert is_solved_and_feasible(model)
Threads.lock(my_lock) do
push!(solutions, i => objective_value(model))
end
Expand Down Expand Up @@ -252,7 +252,7 @@ julia> Threads.@threads for i in 1:10
@objective(model, Min, x)
set_lower_bound(x, i)
optimize!(model)
@assert has_optimal_solution(sudoku)
@assert is_solved_and_feasible(sudoku)
Threads.lock(my_lock) do
push!(solutions, i => objective_value(model))
end
Expand Down Expand Up @@ -297,7 +297,7 @@ julia> Distributed.@everywhere begin
@objective(model, Min, x)
set_lower_bound(x, i)
optimize!(model)
@assert has_optimal_solution(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 @@ -199,7 +199,7 @@ subtour(x::AbstractMatrix{VariableRef}) = subtour(value.(x))

iterative_model = build_tsp_model(d, n)
optimize!(iterative_model)
@assert has_optimal_solution(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 @@ -210,7 +210,7 @@ while 1 < length(cycle) < n
sum(iterative_model[:x][i, j] for (i, j) in S) <= length(cycle) - 1,
)
optimize!(iterative_model)
@assert has_optimal_solution(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 @@ -264,7 +264,7 @@ set_attribute(
subtour_elimination_callback,
)
optimize!(lazy_model)
@assert has_optimal_solution(lazy_model)
@assert is_solved_and_feasible(lazy_model)
objective_value(lazy_model)

# This finds the same optimal tour:
Expand Down
6 changes: 3 additions & 3 deletions docs/src/tutorials/applications/optimal_power_flow.jl
Original file line number Diff line number Diff line change
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 has_optimal_solution(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 has_optimal_solution(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 has_optimal_solution(model; allow_almost = true)
Test.@test 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 has_optimal_solution(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 has_optimal_solution(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 has_optimal_solution(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 has_optimal_solution(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 has_optimal_solution(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 has_optimal_solution(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 @@ -76,7 +76,7 @@ print(model)
# Let's solve and inspect the solution:

optimize!(model)
@assert has_optimal_solution(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 @@ -101,7 +101,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 has_optimal_solution(model)
@assert is_solved_and_feasible(model)
value.(x) .- [3 // 7, 3 // 14]

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

optimize!(model)
@assert has_optimal_solution(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 @@ -130,7 +130,7 @@ print(model_dual)

set_optimizer(model_primal, SCS.Optimizer)
optimize!(model_primal)
@assert has_optimal_solution(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 @@ -154,7 +154,7 @@ objective_value(model_primal)

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

# and the solution we obtain is:

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

set_optimizer(model_primal, Dualization.dual_optimizer(SCS.Optimizer))
optimize!(model_primal)
@assert has_optimal_solution(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 @@ -200,7 +200,7 @@ dual.(primal_c)

set_optimizer(model_dual, Dualization.dual_optimizer(SCS.Optimizer))
optimize!(model_dual)
@assert has_optimal_solution(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 has_optimal_solution(model)
Test.@test is_solved_and_feasible(model)
solution_summary(model)

# ## Results
Expand Down Expand Up @@ -210,7 +210,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 has_optimal_solution(model)
Test.@test is_solved_and_feasible(model)
Test.@test isapprox(D, value.(Z); atol = 1e-6) #src
solve_time_1 = solve_time(model)

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

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

# This time, the solve took:

Expand Down
Loading

0 comments on commit 5364a31

Please sign in to comment.