-
Notifications
You must be signed in to change notification settings - Fork 9
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
Implement quadratic functionality #802
Changes from 23 commits
ab8dfda
7d99991
7e82e47
5090be8
e877a1b
612d5f4
ab3696d
0015fa5
7eda0e9
6e67341
9f886af
68c7135
cc7cd5e
800c471
a1c2edf
a30eea6
f1884db
a985ffa
2e0ec3c
3d821fe
48cbc6e
a2c121e
53cc6b7
c6b8af4
a391061
be71bf9
ce81855
39cb1e9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
|
||
# # Parsimonious flux balance analysis | ||
|
||
# We will use [`parsimonious_flux_balance`](@ref) and | ||
# [`minimize_metabolic_adjustment`](@ref) to find the optimal flux | ||
# distribution in the *E. coli* "core" model. | ||
# | ||
# TODO pFBA citation | ||
|
||
# If it is not already present, download the model and load the package: | ||
import Downloads: download | ||
|
||
!isfile("e_coli_core.json") && | ||
download("http://bigg.ucsd.edu/static/models/e_coli_core.json", "e_coli_core.json") | ||
|
||
# next, load the necessary packages | ||
|
||
using COBREXA | ||
|
||
import JSONFBCModels | ||
import Clarabel # can solve QPs | ||
|
||
model = load_model("e_coli_core.json") # load the model | ||
|
||
# Use the convenience function to run standard pFBA on | ||
|
||
vt = parsimonious_flux_balance(model, Clarabel.Optimizer; modifications = [silence]) | ||
|
||
# Or use the piping functionality | ||
|
||
model |> parsimonious_flux_balance(Clarabel.Optimizer; modifications = [silence]) | ||
|
||
@test isapprox(vt.objective, 0.87392; atol = TEST_TOLERANCE) #src | ||
@test sum(x^2 for x in values(vt.fluxes)) < 15000 #src | ||
|
||
#= | ||
|
||
# Alternatively, you can construct your own constraint tree model with | ||
# the quadratic objective (this approach is much more flexible). | ||
|
||
ctmodel = fbc_model_constraints(model) | ||
ctmodel *= :l2objective^squared_sum_objective(ctmodel.fluxes) | ||
ctmodel.objective.bound = 0.3 # set growth rate # TODO currently breaks | ||
|
||
opt_model = optimization_model( | ||
ctmodel; | ||
objective = ctmodel.:l2objective.value, | ||
optimizer = Clarabel.Optimizer, | ||
sense = Minimal, | ||
) | ||
|
||
J.optimize!(opt_model) # JuMP is called J in COBREXA | ||
|
||
is_solved(opt_model) # check if solved | ||
|
||
vt = C.constraint_values(ctmodel, J.value.(opt_model[:x])) # ConstraintTrees.jl is called C in COBREXA | ||
|
||
@test isapprox(vt.l2objective, ?; atol = QP_TEST_TOLERANCE) #src # TODO will break until mutable bounds | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can remove TODO There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is still commented out :D |
||
|
||
# It is likewise as simple to run MOMA using the convenience functions. | ||
|
||
ref_sol = Dict("ATPS4r" => 33.0, "CYTBD" => 22.0) | ||
|
||
vt = minimize_metabolic_adjustment(model, ref_sol, Gurobi.Optimizer) | ||
|
||
# Or use the piping functionality | ||
|
||
model |> | ||
minimize_metabolic_adjustment(ref_sol, Clarabel.Optimizer; modifications = [silence]) | ||
|
||
@test isapprox(vt.:momaobjective, 0.81580806; atol = TEST_TOLERANCE) #src | ||
|
||
# Alternatively, you can construct your own constraint tree model with | ||
# the quadratic objective (this approach is much more flexible). | ||
|
||
ctmodel = fbc_model_constraints(model) | ||
ctmodel *= | ||
:minoxphospho^squared_sum_error_objective( | ||
ctmodel.fluxes, | ||
Dict(:ATPS4r => 33.0, :CYTBD => 22.0), | ||
) | ||
ctmodel.objective.bound = 0.3 # set growth rate # TODO currently breaks | ||
|
||
opt_model = optimization_model( | ||
ctmodel; | ||
objective = ctmodel.minoxphospho.value, | ||
optimizer = Clarabel.Optimizer, | ||
sense = Minimal, | ||
) | ||
|
||
J.optimize!(opt_model) # JuMP is called J in COBREXA | ||
|
||
is_solved(opt_model) # check if solved | ||
|
||
vt = C.constraint_values(ctmodel, J.value.(opt_model[:x])) # ConstraintTrees.jl is called C in COBREXA | ||
|
||
@test isapprox(vt.l2objective, ?; atol = QP_TEST_TOLERANCE) #src # TODO will break until mutable bounds | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can remove TODO |
||
|
||
=# |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
|
||
# # Minimization of metabolic adjustment | ||
|
||
# TODO MOMA citation | ||
|
||
import Downloads: download | ||
|
||
!isfile("e_coli_core.json") && | ||
download("http://bigg.ucsd.edu/static/models/e_coli_core.json", "e_coli_core.json") | ||
|
||
using COBREXA | ||
import AbstractFBCModels.CanonicalModel as CM | ||
import JSONFBCModels | ||
import Clarabel | ||
|
||
# TODO this might do the convert immediately as with the old cobrexa... | ||
# probably better have an actual output-type argument tho rather than force the | ||
# guessing. | ||
model = convert(CM.Model, load_model("e_coli_core.json")) | ||
|
||
reference_fluxes = parsimonious_flux_balance(model, Clarabel.Optimizer).fluxes | ||
|
||
# TODO MOMA from here |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
|
||
""" | ||
$(TYPEDSIGNATURES) | ||
|
||
Find a feasible solution of the "minimal metabolic adjustment analysis" (MOMA) | ||
for the `model`, which is the "closest" feasible solution to the given | ||
`reference_fluxes`, in the sense of squared-sum error distance. The minimized | ||
squared distance (the objective) is present in the result tree as | ||
`minimal_adjustment_objective`. | ||
|
||
This is often used for models with smaller feasible region than the reference | ||
models (typically handicapped by a knockout, nutritional deficiency or a | ||
similar perturbation). MOMA solution then gives an expectable "easiest" | ||
adjustment of the organism towards a somewhat working state. | ||
|
||
Reference fluxes that do not exist in the model are ignored (internally, the | ||
objective is constructed via [`squared_sum_error_objective`](@ref)). | ||
|
||
Additional parameters are forwarded to [`optimized_constraints`](@ref). | ||
""" | ||
function minimal_metabolic_adjustment( | ||
model::A.AbstractFBCModel, | ||
reference_fluxes::Dict{Symbol,Float64}, | ||
optimizer; | ||
kwargs..., | ||
) | ||
constraints = fbc_model_constraints(model) | ||
objective = squared_sum_error_objective(constraints.fluxes, reference_fluxes) | ||
optimized_constraints( | ||
constraints * :minimal_adjustment_objective^C.Constraint(objective); | ||
optimizer, | ||
objective, | ||
sense = Minimal, | ||
kwargs..., | ||
) | ||
end | ||
|
||
""" | ||
$(TYPEDSIGNATURES) | ||
|
||
A slightly easier-to-use version of [`minimal_metabolic_adjustment`](@ref) that | ||
computes the reference flux as the optimal solution of the | ||
[`reference_model`](@ref). The reference flux is calculated using | ||
`reference_optimizer` and `reference_modifications`, which default to the | ||
`optimizer` and `modifications`. | ||
|
||
Leftover arguments are passed to the overload of | ||
[`minimal_metabolic_adjustment`](@ref) that accepts the reference flux | ||
dictionary. | ||
""" | ||
function minimal_metabolic_adjustment( | ||
model::A.AbstractFBCModel, | ||
reference_model::A.AbstractFBCModel, | ||
optimizer; | ||
reference_optimizer = optimizer, | ||
modifications = [], | ||
reference_modifications = modifications, | ||
kwargs..., | ||
) | ||
reference_constraints = fbc_model_constraints(reference_model) | ||
reference_fluxes = optimized_constraints( | ||
reference_constraints; | ||
optimizer = reference_optimizer, | ||
modifications = reference_modifications, | ||
output = reference_constraints.fluxes, | ||
) | ||
isnothing(reference_fluxes) && return nothing | ||
minimal_metabolic_adjustment( | ||
model, | ||
reference_fluxes, | ||
optimizer; | ||
modifications, | ||
kwargs..., | ||
) | ||
end | ||
|
||
export minimal_metabolic_adjustment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like this
Minimal
. Since we are using JuMP'sset_optimizer_attribute
etc., we should use JuMP'sMin
andMax
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we're renaming JuMP's symbols to ours (people don't import them from JuMP!) so we shouldn't also force them to import parameters.