Unverified Commit 189fecb2 authored by Miroslav Kratochvil's avatar Miroslav Kratochvil Committed by GitHub
Browse files

Merge pull request #415 from LCSB-BioCore/mk-silencer

Simple option to silence the JuMP solvers
parents e0ef1855 7c2660e3
Pipeline #44969 passed with stages
in 32 minutes and 57 seconds
......@@ -122,7 +122,7 @@ dict_soln = parsimonious_flux_balance_analysis_dict(
model,
OSQP.Optimizer;
modifications = [
change_optimizer_attribute("verbose", false), # silence the optimizer (OSQP is very verbose by default)
silence, # silence the optimizer (OSQP is very verbose by default)
change_constraint("R_EX_glc__D_e", -12, -12),
],
)
......@@ -143,6 +143,6 @@ vec_soln = parsimonious_flux_balance_analysis_vec(
],
qp_modifications = [
change_optimizer(OSQP.Optimizer), # now switch to OSQP (Tulip wouldn't be able to finish the computation)
change_optimizer_attribute("verbose", false), # and silence it.
silence, # and make it quiet.
],
)
"""
constrain_objective_value(tolerance)
Limit the objective value to `tolerance`-times the current objective value, as
with [`objective_bounds`](@ref).
"""
constrain_objective_value(tolerance) =
(_, opt_model) -> begin
lambda_min, lambda_max = objective_bounds(tolerance)(objective_value(opt_model))
old_objective = objective_function(opt_model)
@constraint(opt_model, lambda_min <= sum(old_objective) <= lambda_max)
end
"""
change_constraint(id::String, lb, ub)
Change the lower and upper bounds (`lb` and `ub` respectively) of reaction `id`.
"""
change_constraint(id::String, lb, ub) =
(model, opt_model) -> begin
ind = first(indexin([id], reactions(model)))
isnothing(ind) && throw(DomainError(id, "No matching reaction was found."))
set_optmodel_bound!(ind, opt_model, lb = lb, ub = ub)
end
"""
change_objective(new_objective::Union{String,Vector{String}}; weights=[], sense=MOI.MAX_SENSE)
Modification that changes the objective function used in a constraint based
analysis function. `new_objective` can be a single reaction identifier, or an
array of reactions identifiers.
Optionally, the objective can be weighted by a vector of `weights`, and a
optimization `sense` can be set.
"""
change_objective(
new_objective::Union{String,Vector{String}};
weights = [],
sense = MOI.MAX_SENSE,
) =
(model, opt_model) -> begin
# Construct objective_indices array
if typeof(new_objective) == String
objective_indices = indexin([new_objective], reactions(model))
else
objective_indices =
[first(indexin([rxnid], reactions(model))) for rxnid in new_objective]
end
any(isnothing.(objective_indices)) && throw(
DomainError(new_objective, "No matching reaction found for one or more ids."),
)
# Initialize weights
opt_weights = spzeros(n_reactions(model))
isempty(weights) && (weights = ones(length(objective_indices))) # equal weights
for (j, i) in enumerate(objective_indices)
opt_weights[i] = weights[j]
end
v = opt_model[:x]
@objective(opt_model, sense, sum(opt_weights[i] * v[i] for i in objective_indices))
end
......@@ -8,9 +8,8 @@ Possible arguments are `MOI.MAX_SENSE` and `MOI.MIN_SENSE`.
If you want to change the objective and sense at the same time, use
[`change_objective`](@ref) instead to do both at once.
"""
function change_sense(objective_sense)
(model, opt_model) -> set_objective_sense(opt_model, objective_sense)
end
change_sense(objective_sense) =
(_, opt_model) -> set_objective_sense(opt_model, objective_sense)
"""
change_optimizer(optimizer)
......@@ -21,9 +20,7 @@ This may be used to try different approaches for reaching the optimum, and in
problems that may require different optimizers for different parts, such as the
[`parsimonious_flux_balance_analysis`](@ref).
"""
function change_optimizer(optimizer)
(model, opt_model) -> set_optimizer(opt_model, optimizer)
end
change_optimizer(optimizer) = (_, opt_model) -> set_optimizer(opt_model, optimizer)
"""
change_optimizer_attribute(attribute_key, value)
......@@ -32,96 +29,13 @@ Change a JuMP optimizer attribute. The attributes are optimizer-specific, refer
to the JuMP documentation and the documentation of the specific optimizer for
usable keys and values.
"""
function change_optimizer_attribute(attribute_key, value)
(model, opt_model) -> set_optimizer_attribute(opt_model, attribute_key, value)
end
change_optimizer_attribute(attribute_key, value) =
(_, opt_model) -> set_optimizer_attribute(opt_model, attribute_key, value)
"""
constrain_objective_value(tolerance)
silence
Limit the objective value to `tolerance`-times the current objective value, as
with [`objective_bounds`](@ref).
Modification that disable all output from the JuMP optimizer (shortcut for
`set_silent` from JuMP).
"""
function constrain_objective_value(tolerance)
return (model, opt_model) -> begin
lambda_min, lambda_max = objective_bounds(tolerance)(objective_value(opt_model))
old_objective = objective_function(opt_model)
@constraint(opt_model, lambda_min <= sum(old_objective) <= lambda_max)
end
end
"""
change_constraint(id::String, lb, ub)
Change the lower and upper bounds (`lb` and `ub` respectively) of reaction `id`.
"""
function change_constraint(id::String, lb, ub)
(model, opt_model) -> begin
ind = first(indexin([id], reactions(model)))
isnothing(ind) && throw(DomainError(id, "No matching reaction was found."))
set_optmodel_bound!(ind, opt_model, lb = lb, ub = ub)
end
end
"""
change_objective(rxn::Union{Int,String}; weight::Float64 = 1.0, sense = MOI.MAX_SENSE)
Modification that changes the objective to maximize or minimize the specified
reaction (either by index or string ID), optionally specifying the objective
weight.
"""
change_objective(rxn::Union{Int,String}; weight::Float64 = 1.0, sense = MOI.MAX_SENSE) =
change_objective([rxn]; weights = [weight], sense = sense)
"""
change_objective(
rids::Vector{String};
weights::Vector{Float64} = ones(length(rids)),
sense = MOI.MAX_SENSE,
)
Modification that changes the objective function used in a constraint based
analysis function to maximize (or minimize, based on `sense`) the sum
(optionally weighted by `weights`) of the rates of the reactions specified by
string IDs.
"""
change_objective(
rids::Vector{String};
weights::Vector{Float64} = ones(length(rids)),
sense = MOI.MAX_SENSE,
) =
(model, opt_model) -> begin
ridxs = indexin(rids, reactions(model))
any(isnothing, ridxs) &&
throw(DomainError(rids[isnothing.(ridxs)], "Unknown reaction IDs"))
change_objective(Vector{Int}(ridxs); weights = weights, sense = sense)(
model,
opt_model,
)
end
"""
change_objective(
ridxs::Vector{Int};
weights::Vector{Float64} = ones(length(ridxs)),
sense = MOI.MAX_SENSE,
)
A potentially more efficient variant of [`change_objective`](@ref) that works
on integer indexes of the reactions.
"""
change_objective(
ridxs::Vector{Int};
weights::Vector{Float64} = ones(length(ridxs)),
sense = MOI.MAX_SENSE,
) =
(model, opt_model) -> begin
@objective(
opt_model,
sense,
sum(weights[i] * opt_model[:x][ridx] for (i, ridx) in enumerate(ridxs))
)
end
const silence = (_, opt_model) -> set_silent(opt_model)
......@@ -7,10 +7,7 @@
change_constraint("EX_glc__D_e", -12, -12),
change_optimizer_attribute("IPM_IterationsLimit", 500),
],
qp_modifications = [
change_optimizer(OSQP.Optimizer),
change_optimizer_attribute("verbose", false),
],
qp_modifications = [change_optimizer(OSQP.Optimizer), silence],
)
v = parsimonious_flux_balance_analysis_vec(
model,
......@@ -19,10 +16,7 @@
change_constraint("EX_glc__D_e", -12, -12),
change_optimizer_attribute("IPM_IterationsLimit", 500),
],
qp_modifications = [
change_optimizer(OSQP.Optimizer),
change_optimizer_attribute("verbose", false),
],
qp_modifications = [change_optimizer(OSQP.Optimizer), silence],
)
# The used optimizer doesn't really converge to the same answer everytime
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment