diff --git a/README.md b/README.md index 3877684..9a38c30 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,15 @@ |:---:|:---:| | ![CI status](https://github.com/COBREXA/ConstraintTrees.jl/workflows/CI/badge.svg?branch=master) [![codecov](https://codecov.io/gh/COBREXA/ConstraintTrees.jl/branch/master/graph/badge.svg?token=A2ui7exGIH)](https://codecov.io/gh/COBREXA/ConstraintTrees.jl) | [![stable documentation](https://img.shields.io/badge/docs-stable-blue)](https://cobrexa.github.io/ConstraintTrees.jl/stable) [![dev documentation](https://img.shields.io/badge/docs-dev-cyan)](https://cobrexa.github.io/ConstraintTrees.jl/dev) | -ConstraintTree provides a simple data structure `ConstraintTree` for organizing -the contents of constraint-based linear problems. As a main goal, it abstracts -over the distinction between constraints and variables, allowing much tidier -representation for many kinds of complex constraint systems. The primary -purpose is to support constraint-based metabolic modeling within COBREXA.jl. +Package `ConstraintTrees.jl` provides a simple data structure `ConstraintTree` +for organizing the contents of linear constrained optimization problems. As a +main goal, it abstracts over the distinction between constraints and variables, +allowing much tidier representation for many kinds of complex constraint +systems. The primary purpose is to support constraint-based metabolic modeling +within [COBREXA.jl](https://github.com/LCSB-BioCore/COBREXA.jl). + +`ConstraintTrees.jl` is new and under active development. Feel free to discuss +the changes and ideas. #### Acknowledgements diff --git a/docs/src/metabolic-modeling.jl b/docs/src/metabolic-modeling.jl index 1f193d8..fa1be4f 100644 --- a/docs/src/metabolic-modeling.jl +++ b/docs/src/metabolic-modeling.jl @@ -90,12 +90,22 @@ collect(keys(c)) @test 2 == length((keys(c)))#src -# ## Adding combined constraints +# ## Value and constraint arithmetics # Values may be combined additively and multiplied by real constants; which # allows us to easily create more complex linear combination of any values # already occurring in the model: -c.fluxes.R_PFK.value - 2 * c.fluxes.R_ACALD.value +3 * c.fluxes.R_PFK.value - c.fluxes.R_ACALD.value / 2 + +# For simplicity, you can also scale whole constraints, but it is impossible to +# add them together because the meaning of the bounds would get broken: +(3 * c.fluxes.R_PFK, -c.fluxes.R_ACALD / 2) + +# To process constraints in bulk, you may use `C.value` for easier access to +# values and making constraints. +sum(C.value.(values(c.fluxes))) + +# ## Adding combined constraints # Metabolic modeling relies on the fact that the total rates of any metabolite # getting created and consumed by the reaction equals to zero (which diff --git a/src/constraint.jl b/src/constraint.jl index 6a338f8..4ddfd5c 100644 --- a/src/constraint.jl +++ b/src/constraint.jl @@ -38,6 +38,7 @@ Base.@kwdef struct Constraint bound::Bound = nothing end +Base.:-(a::Constraint) = -1 * a Base.:*(a::Real, b::Constraint) = b * a Base.:*(a::Constraint, b::Real) = Constraint( value = a.value * b, diff --git a/test/misc.jl b/test/misc.jl new file mode 100644 index 0000000..4291425 --- /dev/null +++ b/test/misc.jl @@ -0,0 +1,35 @@ + +import ConstraintTrees as C +import SparseArrays as SP + +@testset "Values" begin + x = C.Value(SP.sparse([5.0, 0, 6.0, 0])) + C.Value(idxs = [2, 3], weights = [5.0, 4.0]) + @test x.idxs == [1, 2, 3] + @test x.weights == [5.0, 5.0, 10.0] +end + +@testset "Constraint tree operations" begin + ct1 = C.allocate_variables(keys = [:a, :b]) + ct2 = C.allocate_variables(keys = [:c, :d]) + + @test collect(propertynames(ct1)) == [:a, :b] + @test [k for (k, _) in ct2] == [:c, :d] + @test eltype(ct2) == Pair{Symbol,C.ConstraintTreeElem} + @test collect(keys((:x^ct1 * :x^ct2).x)) == [:a, :b, :c, :d] + @test_throws ErrorException ct1 * ct1 + @test_throws ErrorException :a^ct1 * ct1 + @test_throws ErrorException ct1 * :a^ct1 +end + +@testset "Constraint tree operations" begin + ct = C.allocate_variables(keys = [:a, :b]) + @test_throws BoundsError C.solution_tree(ct, [1.0]) + st = C.solution_tree(ct, [123.0, 321.0]) + @test st.a == 123.0 + @test st[:b] == 321.0 + @test collect(propertynames(st)) == [:a, :b] + @test collect(keys(st)) == [:a, :b] + @test sum([v for (_, v) in st]) == 444.0 + @test sum(values(st)) == 444.0 + @test eltype(st) == Pair{Symbol,C.SolutionTreeElem} +end diff --git a/test/runtests.jl b/test/runtests.jl index 5efb811..c2ff7d6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,5 +3,11 @@ import ConstraintTrees using Test @testset "ConstraintTrees tests" begin - include("../docs/src/metabolic-modeling.jl") + @testset "Metabolic modeling" begin + include("../docs/src/metabolic-modeling.jl") + end + + @testset "Miscellaneous methods" begin + include("misc.jl") + end end