Skip to content

Commit ef95f56

Browse files
authored
Merge pull request #4 from SciML/docs_test_build
Docs test build
2 parents 80c613e + 551c6e0 commit ef95f56

14 files changed

+222
-141
lines changed

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Nemo = "2edaba10-b0f1-5616-af89-8c11ac63239a"
2121
Oscar = "f1435218-dba5-11e9-1e4d-f1a5fab5fc13"
2222
Polyhedra = "67491407-f73d-577b-9b50-8179a7c68029"
2323
PolynomialRoots = "3a141323-8675-5d76-9d11-e1df1406c778"
24+
PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
2425
ReactionNetworkImporters = "b4db0fb7-de2a-5028-82bf-5021f5cfa881"
2526
SBMLToolkit = "86080e66-c8ac-44c2-a1a0-9adaadfe4a4e"
2627
Satisfiability = "160ab843-0bc6-4ba4-9585-b7478b70f443"
@@ -45,6 +46,7 @@ Nemo = "0.47"
4546
Oscar = "1.1.1"
4647
Polyhedra = "0.7.8"
4748
PolynomialRoots = "1.0.0"
49+
PrecompileTools = "1.2.1"
4850
ReactionNetworkImporters = "0.15.1"
4951
SBMLToolkit = "0.1.29"
5052
SafeTestsets = "0.1.0"

ext/CNACDDLib.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module CNACDDLibExt
2+
3+
using ModelingToolkit, Setfield
4+
#import BifurcationKit
5+
#
6+
#### Observable Plotting Handling ###
7+
end

src/CatalystNetworkAnalysis.jl

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
module CatalystNetworkAnalysis
22

3+
using PrecompileTools: @setup_workload, @compile_workload
4+
35
using Catalyst
46
using Satisfiability # For siphon detection
57

68
# Algebraic functionality
7-
using Oscar, Nemo
8-
import Hecke: n_positive_roots
9+
using Oscar
10+
11+
# Linear programming (for concordance + deficiency)
12+
using JuMP, HiGHS
13+
const M::Float64 = 1E4
14+
const ϵ::Float64 = 1E-4
915

10-
using JuMP, HiGHS # For concordance and deficiency algorithms
11-
using MixedSubdivisions, DynamicPolynomials # For polytope analysis
1216
using LinearAlgebra
1317
using Graphs
14-
15-
using SparseArrays, StaticArrays
1618
using IterTools, Combinatorics
19+
using SparseArrays
1720

21+
# Polytope analysis (EFMs)
22+
using MixedSubdivisions, DynamicPolynomials
1823
using Polyhedra
1924
import CDDLib
2025

21-
import ModelingToolkit as MT
22-
23-
const M::Float64 = 1E4
24-
const ϵ::Float64 = 1E-1
25-
2626
include("persistence.jl")
2727
export ispersistent, minimalsiphons, iscritical, isconservative, isconsistent
2828
include("concordance.jl")

src/concentrationrobustness.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
- :GLOBAL_ACR - this species is absolutely concentration-robust for every choice of rate constants
77
- :INCONCLUSIVE - the algorithm currently cannot decide whether this network has ACR. One could try calling this function with rate constants provided.
88
- :NO_ACR - the reaction network does not have ACR.
9-
- :INEXACTPARAMS - the algorithm cannot conclude concentration-robustness due to inexact parameters (Floats that are too small)
9+
- :INEXACTPARAMS - the algorithm cannot conclude concentration-robustness due to inexact parameters (floats that are too small)
1010
1111
Follows the approach outlined in [Puente et al. 2023](https://arxiv.org/abs/2401.00078).
1212
"""
1313
function isconcentrationrobust(rn::ReactionSystem; p::VarMapType = Dict())
1414
nps = Catalyst.get_networkproperties(rn)
15-
Catalyst.deficiency(rn) == 1 && (isempty(robustspecies(rn)) : return :GLOBAL_ACR)
15+
Catalyst.deficiency(rn) == 1 && !isempty(robustspecies_δ1(rn)) && return :GLOBAL_ACR
1616

1717
# Check necessary condition
1818
possibly_ACR = false
@@ -28,7 +28,6 @@ function isconcentrationrobust(rn::ReactionSystem; p::VarMapType = Dict())
2828
end
2929

3030
# Convert parameter values to rational values.
31-
3231
try
3332
ftype, stype = eltype(p).parameters
3433
stype <: Rational || (p = Dict{ftype, Rational}(p))
@@ -67,8 +66,10 @@ function isconcentrationrobust(rn::ReactionSystem; p::VarMapType = Dict())
6766
r_ξ, ξ = polynomial_ring(QQ, )
6867

6968
!isempty(p) && for i in 1:numspecies(rn)
70-
IQ = eliminate(I, vcat(specs[1:i-1], specs[i+1:end]))
69+
IQ = Oscar.eliminate(I, vcat(specs[1:i-1], specs[i+1:end]))
7170
for g in gens(IQ)
71+
iszero(g) && continue
72+
7273
# Generate the univariate polynomial corresponding to the generator
7374
coeff_pos = [exponent_vector(g, j)[i]+1 for j in 1:length(Oscar.terms(g))]
7475
coeffs = zeros(QQFieldElem, first(coeff_pos))
@@ -83,7 +84,6 @@ function isconcentrationrobust(rn::ReactionSystem; p::VarMapType = Dict())
8384
end
8485
end
8586

86-
8787
return :INCONCLUSIVE
8888
end
8989

@@ -118,7 +118,7 @@ end
118118
119119
For a network of deficiency one, return a vector of indices corresponding to species that are concentration robust, i.e. for every positive equilbrium, the concentration of species s will be the same.
120120
"""
121-
function robustspecies(rn::ReactionSystem)
121+
function robustspecies_δ1(rn::ReactionSystem)
122122
complexes, D = reactioncomplexes(rn)
123123
nps = Catalyst.get_networkproperties(rn)
124124

src/concordance.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ end
4949
"""
5050
isconcordant(rn::ReactionSystem, atol=1e-12)
5151
52-
Given a reaction network (and an absolute tolerance for the nullspace matrix below which entries should be zero), test whether the reaction network's graph has a property called concordance. A concordant network will not admit multiple equilibria in any stoichiometric compatibility class. The algorithm for this check follows Haixia Ji's PhD thesis, (Ji, 2011).
52+
Given a reaction network (and an absolute tolerance for the nullspace matrix below which entries should be zero), test whether the reaction network's graph has a property called concordance. A concordant network will not admit multiple equilibria in any stoichiometric compatibility class. The algorithm for this check follows Haixia Ji's PhD thesis, (Ji, 2011).
5353
"""
5454
function isconcordant(rn::ReactionSystem)
5555
S = netstoichmat(rn)
@@ -66,8 +66,8 @@ function isconcordant(rn::ReactionSystem)
6666
# 2. If α[r] == 0 for some reaction r, either σ[s] == 0 for all s in the reactant complex,
6767
# 3. or else there are two species s1, s2 in the reactant complex for which sign(σ[s1]) != sign(σ[s2])
6868

69-
model = add_sign_constraints(S; varName = "σ")
70-
add_subspace_constraints(kerS; model, varName = "α")
69+
model = add_sign_constraints(S; var_name = "σ")
70+
add_subspace_constraints(kerS; model, var_name = "α")
7171
add_concordance_constraints(model, rn)
7272

7373
optimize!(model)

src/cycles.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
Checks if a reaction network is consistent, i.e. admits a positive equilibrium for some choice of rate constants. Equivalent to [`ispositivelydependent`](@ref).
55
"""
66
function isconsistent(rs::ReactionSystem)
7-
cyclemat = cycles(rs)
7+
cyclemat = Catalyst.cycles(rs)
88
has_positive_solution(cyclemat)
99
end
1010

src/deficiencytheory.jl

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,17 @@ function deficiencyonealgorithm(rn::ReactionSystem)
1717
s, c = size(Y); r = size(S, 2)
1818

1919
# Initialize sign compatibility model.
20-
model = C.add_sign_constraints(S, var = "μ")
20+
model = C.add_sign_constraints(S, var_name = "μ")
2121
@variable(model, n)
2222

2323
# Iterate over partitions. For each pair of UML partition and confluence vector,
2424
# check if there exists a μ that satisfies the resulting constraints.
2525
for partition in partitions
26-
feasible = solveconstraints(rn, model, g, partition, cutdict)
26+
sol, feasible = solveconstraints(rn, model, g, partition, cutdict)
2727
feasible && return true
2828

2929
if reversible
30-
feasible = solveconstraints(rn, model, -g, partition, cutdict)
30+
sol, feasible = solveconstraints(rn, model, -g, partition, cutdict)
3131
feasible && return true
3232
end
3333
end
@@ -36,7 +36,8 @@ function deficiencyonealgorithm(rn::ReactionSystem)
3636
end
3737

3838
function isregular(rn::ReactionSystem)
39-
lcs = linkageclasses(rn); tlcs = terminallinkageclasses(rn)
39+
lcs = Catalyst.linkageclasses(rn)
40+
tlcs = terminallinkageclasses(rn)
4041

4142
img = incidencematgraph(rn)
4243
tlc_graphs = [Graphs.induced_subgraph(img, tlc)[1] for tlc in tlcs]
@@ -57,7 +58,8 @@ function confluencevector(rn::ReactionSystem)
5758

5859
idx = findfirst(i -> @view(g[:, i]) != zeros(nc), 1:nc)
5960
g = g[:, idx]
60-
tlcs = terminallinkageclasses(rn); lcs = linkageclasses(rn)
61+
tlcs = terminallinkageclasses(rn)
62+
lcs = Catalyst.linkageclasses(rn)
6163

6264
absorptive = true
6365
for tlc in tlcs
@@ -127,7 +129,7 @@ end
127129
# created by removing each cut-link connecting two terminal complexes.
128130
function cutlinkpartitions(rn::ReactionSystem)
129131
tlcs = terminallinkageclasses(rn)
130-
lcs = linkageclasses(rn)
132+
lcs = Catalyst.linkageclasses(rn)
131133
inclusions = [findfirst(lc -> issubset(tlc, lc), lcs) for tlc in tlcs]
132134

133135
img = Graphs.SimpleGraph(incidencematgraph(rn))

src/lp_utils.jl

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
#################################
66

77
"""
8-
add_subspace_constraints(S; model = nothing, varName = "")
8+
add_subspace_constraints(S; model = nothing, var_name = "")
99
1010
Given a matrix S, add the constraints that the solution vector μ will lie in the image space of S. If the model does not already exists, initialize one.
1111
"""
12-
function add_subspace_constraints(S::M; model = nothing, varName::String = "") where M <: AbstractMatrix
12+
function add_subspace_constraints(S::T; model = nothing, var_name::String = "") where T <: AbstractMatrix
1313
(s, r) = size(S)
1414

1515
# Initialize model if none provided.
@@ -20,20 +20,20 @@ function add_subspace_constraints(S::M; model = nothing, varName::String = "") w
2020
@objective(model, Min, 0)
2121
end
2222

23-
coeffs = varName*"_coeffs"
23+
coeffs = var_name*"_coeffs"
2424
model[Symbol(coeffs)] = @variable(model, [i = 1:r], base_name = coeffs)
25-
model[Symbol(varName)] = @variable(model, [i = 1:s], base_name = varName)
25+
model[Symbol(var_name)] = @variable(model, [i = 1:s], base_name = var_name)
2626

27-
@constraint(model, S*model[Symbol(coeffs)] == model[Symbol(var)])
27+
@constraint(model, S*model[Symbol(coeffs)] == model[Symbol(var_name)])
2828
return model
2929
end
3030

3131
"""
32-
add_sign_constraints(S; model = nothing, varName = "")
32+
add_sign_constraints(S; model = nothing, var_name = "")
3333
34-
Given a matrix S, add the constraints that the solution vector var will be sign-compatible with the image space of S. If the model does not already exists, initialize one.
34+
Given a matrix S, add the constraints that the solution vector var will be sign-compatible with the image space of S. If the model does not already exists, initialize one.
3535
"""
36-
function add_sign_constraints(S::M; model = nothing, varName::String = "") where M <: AbstractMatrix
36+
function add_sign_constraints(S::T; model = nothing, var_name::String = "") where T <: AbstractMatrix
3737
(s, r) = size(S)
3838

3939
# Initialize model if none provided.
@@ -44,13 +44,13 @@ function add_sign_constraints(S::M; model = nothing, varName::String = "") where
4444
@objective(model, Min, 0)
4545
end
4646

47-
coeffs = varName*"_coeffs"
47+
coeffs = var_name*"_coeffs"
4848
model[Symbol(coeffs)] = @variable(model, [i = 1:r], base_name = coeffs)
49-
model[Symbol(varName)] = @variable(model, [i = 1:s], base_name = varName)
49+
model[Symbol(var_name)] = @variable(model, [i = 1:s], base_name = var_name)
5050

51-
ispos = var*"_ispos"
52-
isneg = var*"_isneg"
53-
iszer = var*"_iszero"
51+
ispos = var_name*"_ispos"
52+
isneg = var_name*"_isneg"
53+
iszer = var_name*"_iszero"
5454
model[Symbol(ispos)] = @variable(model, [i = 1:s], Bin, base_name = ispos)
5555
model[Symbol(isneg)] = @variable(model, [i = 1:s], Bin, base_name = isneg)
5656
model[Symbol(iszer)] = @variable(model, [i = 1:s], Bin, base_name = iszer)
@@ -60,17 +60,17 @@ function add_sign_constraints(S::M; model = nothing, varName::String = "") where
6060
sum(model[Symbol(iszer)]) <= s - 1 # Ensure that var is not the zero vector.
6161

6262
# iszero = 1 --> var[i] == 0 <--> (S * coeffs)[i] == 0
63-
model[Symbol(var)] + M * (ones(s) - model[Symbol(iszer)]) zeros(s)
64-
model[Symbol(var)] - M * (ones(s) - model[Symbol(iszer)]) zeros(s)
63+
model[Symbol(var_name)] + M * (ones(s) - model[Symbol(iszer)]) zeros(s)
64+
model[Symbol(var_name)] - M * (ones(s) - model[Symbol(iszer)]) zeros(s)
6565
(S*model[Symbol(coeffs)]) + M * (ones(s) - model[Symbol(iszer)]) zeros(s)
6666
(S*model[Symbol(coeffs)]) - M * (ones(s) - model[Symbol(iszer)]) zeros(s)
6767

6868
# isnegative = 1 --> var[i] < 0 <--> (S * coeffs)[i] < 0
69-
model[Symbol(var)] - M * (ones(s) - model[Symbol(isneg)]) -ones(s) * ϵ
69+
model[Symbol(var_name)] - M * (ones(s) - model[Symbol(isneg)]) -ones(s) * ϵ
7070
(S*model[Symbol(coeffs)]) - M * (ones(s) - model[Symbol(isneg)]) -ones(s) * ϵ
7171

7272
# ispositive = 1 --> var[i] > 0 <--> (S * coeffs)[i] > 0
73-
model[Symbol(var)] + M * (ones(s) - model[Symbol(ispos)]) ones(s) * ϵ
73+
model[Symbol(var_name)] + M * (ones(s) - model[Symbol(ispos)]) ones(s) * ϵ
7474
(S*model[Symbol(coeffs)]) + M * (ones(s) - model[Symbol(ispos)]) ones(s) * ϵ
7575
end)
7676

@@ -101,15 +101,15 @@ function has_positive_solution(M::T; nonneg = false) where {T <: AbstractMatrix}
101101
end
102102

103103
# Suppose we have a cone defined by the intersection of the nullspace of S and the positive orthant. Then is_extreme_ray tells whether a given vector in this cone is an extreme ray.
104-
function is_extreme_ray(S::M, x::V; atol = 1e-9) where {M <: AbstractMatrix, V <: AbstractVector}
104+
function is_extreme_ray(S::T, x::V; atol = 1e-9) where {T <: AbstractMatrix, V <: AbstractVector}
105105
m, n = size(S)
106106
length(x) != n && error("The length of x is not correct, expected $n and received $(length(x)).")
107107
!isapprox(S*x, zeros(m); atol) && error("The provided vector $x is not a solution to Sx = 0.")
108108
idxset = findall(!=(0), x)
109109
is_extreme_idxset(S, idxset)
110110
end
111111

112-
function is_extreme_idxset(S::M, idxs::Vector{Int}) where {M <: AbstractMatrix}
112+
function is_extreme_idxset(S::T, idxs::Vector{Int}) where {T <: AbstractMatrix}
113113
m, n = size(S)
114114
cone_mat = [I; S; -S]
115115
cone_mat_eq = Matrix{eltype(S)}(undef, n+2*m - length(idxs), n)

0 commit comments

Comments
 (0)