Skip to content

Commit

Permalink
Merge pull request #2 from COBREXA/mk-separate-frontend
Browse files Browse the repository at this point in the history
separate the frontend functions from frontend-style builders and builders
  • Loading branch information
exaexa authored Feb 2, 2024
2 parents bd57b38 + 73f2852 commit c5e7df7
Show file tree
Hide file tree
Showing 17 changed files with 490 additions and 268 deletions.
2 changes: 1 addition & 1 deletion docs/src/examples/02-flux-balance-analysis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ model = load_model("e_coli_core.json")
# is captured in the default behavior of function
# [`flux_balance_analysis`](@ref):

solution = flux_balance_analysis(model, GLPK.Optimizer)
solution = flux_balance_analysis(model, optimizer = GLPK.Optimizer)

@test isapprox(solution.objective, 0.8739, atol = TEST_TOLERANCE) #src

Expand Down
4 changes: 2 additions & 2 deletions docs/src/examples/02a-optimizer-parameters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ model = load_model("e_coli_core.json")
# limit for IPM algorithm may now look as follows:
solution = flux_balance_analysis(
model,
Tulip.Optimizer;
optimizer = Tulip.Optimizer,
settings = [silence, set_optimizer_attribute("IPM_IterationsLimit", 1000)],
)

Expand All @@ -59,7 +59,7 @@ solution = flux_balance_analysis(

solution = flux_balance_analysis(
model,
Tulip.Optimizer;
optimizer = Tulip.Optimizer,
settings = [set_optimizer_attribute("IPM_IterationsLimit", 2)],
)

Expand Down
4 changes: 2 additions & 2 deletions docs/src/examples/02b-model-modifications.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ model.reactions["CS"].stoichiometry

import GLPK

base_solution = flux_balance_analysis(model, GLPK.Optimizer)
base_solution = flux_balance_analysis(model, optimizer = GLPK.Optimizer)
base_solution.objective

# Now, for example, we can limit the intake of glucose by the model:
Expand All @@ -91,7 +91,7 @@ model.reactions["EX_glc__D_e"].lower_bound = -5.0

# ...and solve the modified model:
#
low_glucose_solution = flux_balance_analysis(model, GLPK.Optimizer)
low_glucose_solution = flux_balance_analysis(model, optimizer = GLPK.Optimizer)
low_glucose_solution.objective

@test isapprox(low_glucose_solution.objective, 0.41559777, atol = TEST_TOLERANCE) #src
Expand Down
23 changes: 13 additions & 10 deletions docs/src/examples/03-parsimonious-flux-balance.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,33 @@

# # Parsimonious flux balance analysis

# We will use [`parsimonious_flux_balance_analysis`](@ref) and
# [`minimization_of_metabolic_adjustment`](@ref) to find the optimal flux
# distribution in the *E. coli* "core" model.
# We will use [`parsimonious_flux_balance_analysis`](@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
using COBREXA

!isfile("e_coli_core.json") &&
download("http://bigg.ucsd.edu/static/models/e_coli_core.json", "e_coli_core.json")
download_model(
"http://bigg.ucsd.edu/static/models/e_coli_core.json",
"e_coli_core.json",
"7bedec10576cfe935b19218dc881f3fb14f890a1871448fc19a9b4ee15b448d8",
)

# 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_analysis(model, Clarabel.Optimizer; settings = [silence])
vt = parsimonious_flux_balance_analysis(
model;
optimizer = Clarabel.Optimizer,
settings = [silence],
)

@test isapprox(vt.objective, 0.87392; atol = TEST_TOLERANCE) #src
@test sum(x^2 for x in values(vt.fluxes)) < 15000 #src
Expand Down
12 changes: 7 additions & 5 deletions docs/src/examples/04-minimization-of-metabolic-adjustment.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@

# TODO MOMA citation

import Downloads: download
using COBREXA

!isfile("e_coli_core.json") &&
download("http://bigg.ucsd.edu/static/models/e_coli_core.json", "e_coli_core.json")
download_model(
"http://bigg.ucsd.edu/static/models/e_coli_core.json",
"e_coli_core.json",
"7bedec10576cfe935b19218dc881f3fb14f890a1871448fc19a9b4ee15b448d8",
)

using COBREXA
import AbstractFBCModels.CanonicalModel as CM
import JSONFBCModels
import Clarabel
Expand All @@ -36,7 +38,7 @@ model = convert(CM.Model, load_model("e_coli_core.json"))
reference_fluxes =
parsimonious_flux_balance_analysis(
model,
Clarabel.Optimizer,
optimizer = Clarabel.Optimizer,
settings = [silence],
).fluxes

Expand Down
4 changes: 2 additions & 2 deletions docs/src/examples/06-mmdf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ reference_flux = Dict(
# ## Solving the MMDF problem

mmdf_solution = max_min_driving_force_analysis(
model,
reaction_standard_gibbs_free_energies;
model;
reaction_standard_gibbs_free_energies,
reference_flux,
concentration_ratios = Dict(
"atp" => ("atp_c", "adp_c", 10.0),
Expand Down
7 changes: 7 additions & 0 deletions docs/src/reference/analysis.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,10 @@ Pages = ["src/analysis/screen.jl", "src/analysis/variability.jl", "src/analysis/
Modules = [COBREXA]
Pages = ["src/analysis/sample.jl"]
```

## Analysis front-end API helpers

```@autodocs
Modules = [COBREXA]
Pages = ["src/analysis/frontend.jl"]
```
1 change: 1 addition & 0 deletions src/COBREXA.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ include("worker_data.jl")

# generic analysis functions
include("analysis/envelope.jl")
include("analysis/frontend.jl")
include("analysis/parsimonious.jl")
include("analysis/sample.jl")
include("analysis/screen.jl")
Expand Down
93 changes: 93 additions & 0 deletions src/analysis/frontend.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@

# Copyright (c) 2021-2024, University of Luxembourg
# Copyright (c) 2021-2024, Heinrich-Heine University Duesseldorf
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
$(TYPEDSIGNATURES)
A helper that converts a front-end constraint `builder` function (the output of
which would normally be just passed through [`optimized_values`](@ref)) to
front-end analysis function.
"""
function frontend_optimized_values(
builder,
args...;
builder_kwargs = NamedTuple(),
objective,
output = identity,
sense = Maximal,
optimizer,
settings = [],
kwargs...,
)
constraints = builder(args...; builder_kwargs..., kwargs...)

# arguments need to be kept in sync
optimized_values(
constraints;
objective = objective(constraints),
output = output(constraints),
sense,
optimizer,
settings,
)
end

export frontend_optimized_values

"""
$(TYPEDSIGNATURES)
A helper that converts a parsimonious-style front-end constraint `builder`
function to front-end analysis function.
Like [`frontend_optimized_values`](@ref), but internally calls
[`parsimonious_optimized_values`](@ref).
"""
function frontend_parsimonious_optimized_values(
builder,
args...;
builder_kwargs = NamedTuple(),
objective = identity,
output = identity,
sense = Maximal,
optimizer,
settings = [],
parsimonious_objective,
parsimonious_optimizer = nothing,
parsimonious_sense = Minimal,
parsimonious_settings = [],
tolerances = [absolute_tolerance_bound(0)],
kwargs...,
)
constraints = builder(args...; builder_kwargs..., kwargs...)

# arguments need to be kept in sync
parsimonious_optimized_values(
constraints;
objective = objective(constraints),
output = output(constraints),
sense,
settings,
optimizer,
parsimonious_objective = parsimonious_objective(constraints),
parsimonious_optimizer,
parsimonious_sense,
parsimonious_settings,
tolerances,
)
end

export frontend_parsimonious_optimized_values
4 changes: 3 additions & 1 deletion src/analysis/parsimonious.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@ function parsimonious_optimized_values(
settings = [],
parsimonious_objective::C.Value,
parsimonious_optimizer = nothing,
parsimonious_sense = J.MIN_SENSE,
parsimonious_sense = Minimal,
parsimonious_settings = [],
tolerances = [absolute_tolerance_bound(0)],
output = constraints,
kwargs...,
)
# arguments need to be kept in sync with
# frontend_parsimonious_optimized_values

# first solve the optimization problem with the original objective
om = optimization_model(constraints; objective, kwargs...)
Expand Down
2 changes: 2 additions & 0 deletions src/analysis/solver.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ function optimized_values(
output::C.ConstraintTreeElem = constraints,
kwargs...,
)
# arguments need to be kept in sync with frontend_optimized_values

om = optimization_model(constraints; kwargs...)
for m in settings
m(om)
Expand Down
15 changes: 6 additions & 9 deletions src/frontend/balance.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,11 @@ Most arguments are forwarded to [`optimized_values`](@ref).
Returns a tree with the optimization solution of the same shape as
given by [`flux_balance_constraints`](@ref).
"""
function flux_balance_analysis(model::A.AbstractFBCModel, optimizer; kwargs...)
constraints = flux_balance_constraints(model)
optimized_values(
constraints;
objective = constraints.objective.value,
optimizer,
kwargs...,
)
end
flux_balance_analysis(model::A.AbstractFBCModel; kwargs...) = frontend_optimized_values(
flux_balance_constraints,
model;
objective = x -> x.objective.value,
kwargs...,
)

export flux_balance_analysis
Loading

0 comments on commit c5e7df7

Please sign in to comment.