Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/Test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ jobs:
fail-fast: false
matrix:
version:
- "lts"
- "1"
os:
- ubuntu-latest
Expand Down
33 changes: 14 additions & 19 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,32 +1,27 @@
name = "GraphDynamicalSystems"
uuid = "13529e2e-ed53-56b1-bd6f-420b01fca819"
version = "0.0.9"
version = "0.0.10"
authors = ["Reuben Gardos Reid <5456207+ReubenJ@users.noreply.github.com>"]

[workspace]
projects = ["test"]
projects = ["docs", "test", "implementations/QualitativeNetworks", "implementations/BooleanNetworks"]

[deps]
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"

[weakdeps]
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
DynamicalSystemsBase = "6e36e845-645a-534a-86f2-f5d4aa5a06b4"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078"
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
MetaGraphsNext = "fa8bd995-216d-47f1-8a91-f3b68fbeb377"
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
TermInterface = "8ea1fca8-c5ef-4a55-8b96-4e9afe9c9a3c"

[extensions]
AbstractTreesExt = "AbstractTrees"
DynamicalSystemsBaseExt = "DynamicalSystemsBase"
GraphsExt = "Graphs"

[compat]
AbstractTrees = "0.4.5"
Compat = "4.18.1"
DocStringExtensions = "0.9.3"
DynamicalSystemsBase = "3.10"
Graphs = "1.12"
MLStyle = "0.4.17"
MacroTools = "0.5.16"
MetaGraphsNext = "0.7, 0.8"
SciMLBase = "2.74.1, 3"
TermInterface = "2.0.0"
julia = "1.10"
Compat = "3.47,4.10"
DynamicalSystemsBase = "3.19.3"
Graphs = "1.14.0"
julia = "1.12"
1 change: 0 additions & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
GraphDynamicalSystems = "13529e2e-ed53-56b1-bd6f-420b01fca819"
LiveServer = "16fef848-5104-11e9-1b77-fb7a48bbb589"
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"

[compat]
Documenter = "1"
4 changes: 0 additions & 4 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
using Revise

Revise.revise()

using GraphDynamicalSystems
using Documenter

Expand Down
8 changes: 7 additions & 1 deletion docs/src/95-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,11 @@ Pages = ["95-reference.md"]
```

```@autodocs
Modules = [GraphDynamicalSystems]
Modules = [
GraphDynamicalSystems,
GraphDynamicalSystems.Interface,
GraphDynamicalSystems.Schedule,
GraphDynamicalSystems.Conversions,
GraphDynamicalSystems.Constructors
]
```
9 changes: 9 additions & 0 deletions ext/AbstractTreesExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module AbstractTreesExt
import AbstractTrees as AT
import GraphDynamicalSystems as GDS

function GDS.Constructors.vertex_function_to_edgelist(vertex, fn, all_vertices)
recurse_if = x -> !(x in all_vertices)
return filter(in(all_vertices), collect(AT.PreOrderDFS(recurse_if, fn))) .=> (vertex,)
end
end
50 changes: 50 additions & 0 deletions ext/DynamicalSystemsBaseExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
module DynamicalSystemsBaseExt
import DynamicalSystemsBase as DSB
import GraphDynamicalSystems as GDS

function step!(gds)
v_to_update = GDS.to_update(gds)
current_state = Dict(GDS.vertices(gds) .=> GDS.get_state(gds))
new_state = v_to_update .=> [f(current_state) for f in GDS.update_function(gds, v_to_update)]
GDS.set_state!(gds, new_state)
return nothing
end

function extract_state(gds)
return GDS.get_state(gds)
end

function extract_parameters(::Any)
return () # no parameters exposed by default
end

function reset_model!(gds, u, ::Any)
GDS.set_state!(gds, round.(Int, u))
return nothing
end

function GDS.Conversions.to_arbitrary_steppable(gds)
isdeterministic = GDS.is_deterministic(gds)

return DSB.ArbitrarySteppable(
gds,
step!,
extract_state,
extract_parameters,
reset_model!;
isdeterministic
)
end

function DSB.reinit!(as::DSB.ArbitrarySteppable, u)
as.reinit(as.model, u, ())
return nothing
end

# Implements part of the GDS interface for DSB's `DynamicalSystem`s
# Useful to apply methods written over the GDS interface directly to
# some DSB-based object.
GDS.update_function(ds::DSB.DynamicalSystem) = DSB.dynamic_rule(ds)
GDS.get_state(ds::DSB.DynamicalSystem) = DSB.current_state(ds)
GDS.set_state!(ds::DSB.DynamicalSystem, u::AbstractVector{<:Real}) = DSB.set_state!(ds, u)
end
13 changes: 13 additions & 0 deletions ext/GraphsExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module GraphsExt
import Graphs
import GraphDynamicalSystems as GDS

GDS.vertices(graph::Graphs.AbstractGraph) = Graphs.vertices(graph)
GDS.edges(graph::Graphs.AbstractGraph) = Graphs.edges(graph)

function GDS.Conversions.to_simple_graph(gds)
v = GDS.vertices(gds)
e = [Graphs.Edge(findfirst(==(s), v), findfirst(==(d), v)) for (s, d) in GDS.edges(gds)]
return Graphs.SimpleDiGraph(e)
end
end
20 changes: 20 additions & 0 deletions implementations/BooleanNetworks/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name = "BooleanNetworks"
uuid = "97f9906b-beee-4f75-a06a-7a05f392a141"
version = "0.0.1"
authors = ["Reuben Gardos Reid <5456207+ReubenJ@users.noreply.github.com>"]

[workspace]
projects = ["test"]

[deps]
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
Compat = "34da2185-b29b-5c13-b0c7-acf172513d20"
GraphDynamicalSystems = "13529e2e-ed53-56b1-bd6f-420b01fca819"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
MetaGraphsNext = "fa8bd995-216d-47f1-8a91-f3b68fbeb377"

[compat]
AbstractTrees = "0.4.5"
Compat = "4.18.1"
Graphs = "1.14.0"
MetaGraphsNext = "0.8.0"
90 changes: 90 additions & 0 deletions implementations/BooleanNetworks/src/BooleanNetworks.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
module BooleanNetworks
import AbstractTrees as AT
import GraphDynamicalSystems as GDS
import MetaGraphsNext as MG
using Graphs: Graphs
using Compat: @compat

@compat public BooleanNetwork

mutable struct VertexData
update_function::Any
state::Bool
end
GDS.update_function(e::VertexData) = e.update_function
GDS.get_state(e::VertexData) = e.state
function GDS.set_state!(e::VertexData, v::Integer)
return e.state = v
end
GDS.domain(e::VertexData) = false:true

const BNGraphType{G <: Graphs.AbstractGraph{Int}, L, V <: VertexData} = MG.MetaGraph{Int, G, L, V}

"""
BooleanNetwork

A graph dynamical system with Boolean domains.

Update functions are Boolean functions. The schedule style is `Asynchronous` by
default, but can be specified by passing a different type to the first type
parameter explicitly.

Alias: [`BN`](@ref).
"""
struct BooleanNetwork{S <: GDS.ScheduleStyle, G <: BNGraphType}
graph::G
end

"""
BN

Alias for a [`BooleanNetwork`](@ref).
"""
const BN = BooleanNetwork

function BooleanNetwork{S}(vs, fns) where {S}
edge_list = GDS.Constructors.vertex_function_to_edgelist(vs .=> fns)
e = [Graphs.Edge(findfirst(==(s), vs), findfirst(==(d), vs)) for (s, d) in edge_list]
simple_graph = Graphs.SimpleDiGraph(e)
vertex_data = vs .=> VertexData.(fns, falses(length(vs)))
edge_data = Tuple.(edge_list) .=> nothing # could add edge sign here
meta_graph = MG.MetaGraph(simple_graph, vertex_data, edge_data)

return BooleanNetwork{S, typeof(meta_graph)}(meta_graph)
end

function GDS.schedule_style(::BooleanNetwork{S}) where {S}
return S()
end

function GDS.domain(bn::BN, vertices = MG.labels(bn.graph))
return GDS.domain.(getindex.((bn.graph,), vertices))
end

function GDS.update_function(bn::BN, vertices = MG.labels(bn.graph))
return GDS.update_function.(getindex.((bn.graph,), vertices))
end

function GDS.get_state(bn::BN, vertices = MG.labels(bn.graph))
return GDS.get_state.(getindex.((bn.graph,), vertices))
end

function GDS.set_state!(bn::BN, state::AbstractVector{<:Integer})
g = bn.graph
return foreach(((i, v),) -> GDS.set_state!(g[v], state[i]), enumerate(MG.labels(g)))
end

function GDS.set_state!(bn::BN, vertex_state_pairs::AbstractVector{<:Pair})
g = bn.graph
return foreach(((v, s),) -> GDS.set_state!(g[v], s), vertex_state_pairs)
end

function GDS.vertices(bn::BN)
return MG.labels(bn.graph)
end

function GDS.edges(bn::BN)
return MG.edge_labels(bn.graph)
end

end
10 changes: 10 additions & 0 deletions implementations/BooleanNetworks/test/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[deps]
Attractors = "f3fd9213-ca85-4dba-9dfd-7fc91308fec7"
BooleanNetworks = "97f9906b-beee-4f75-a06a-7a05f392a141"
DynamicalSystemsBase = "6e36e845-645a-534a-86f2-f5d4aa5a06b4"
ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7"
GraphDynamicalSystems = "13529e2e-ed53-56b1-bd6f-420b01fca819"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
MetaGraphsNext = "fa8bd995-216d-47f1-8a91-f3b68fbeb377"
ReTestItems = "817f1d60-ba6b-4fd5-9520-3cf149f6a823"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
66 changes: 66 additions & 0 deletions implementations/BooleanNetworks/test/bn_tests.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
@testitem "Construct" begin
import BooleanNetworks as BNs
import GraphDynamicalSystems as GDS

bn = BNs.BN{GDS.Asynchronous}([:x, :y, :z], Union{Symbol, Int, Expr}[:x, :x, :(y & ~x)])

@test length(GDS.vertices(bn)) == 3
@test length(GDS.edges(bn)) == 4
@test GDS.update_function(bn) == [:x, :x, :(y & ~x)]
@test GDS.update_function(bn, [:z]) == [:(y & ~x)]
end

@testitem "Convert to SimpleDiGraph" begin
import BooleanNetworks as BNs
import GraphDynamicalSystems as GDS
import Graphs

bn = BNs.BN{GDS.Asynchronous}([:x, :y, :z], Union{Symbol, Int, Expr}[:x, :x, :(y & ~x)])
graph = GDS.Conversions.to_simple_graph(bn)

@test Graphs.nv(graph) == 3
@test Graphs.ne(graph) == 4
end

@testitem "Convert to DynamicalSystem" begin
import BooleanNetworks as BNs
import GraphDynamicalSystems as GDS
import DynamicalSystemsBase as DSB
import MetaGraphsNext as MG
import Graphs
using Attractors: AttractorsViaRecurrences, basins_of_attraction

vs = [:x, :y, :z]
fns = [
_ -> true,
state -> state[:x],
state -> state[:y] & ~state[:x],
]
vd = BNs.VertexData.(fns, zeros(length(vs)))
es = Graphs.Edge.([(1, 1), (1, 2), (1, 3), (2, 3)])
es_sym = [(:x, :x), (:x, :y), (:x, :z), (:y, :z)]
graph = Graphs.SimpleDiGraph(es)
meta_graph = MG.MetaGraph(graph, vs .=> vd, Tuple.(es_sym) .=> nothing)
bn = BNs.BooleanNetwork{GDS.Asynchronous, typeof(meta_graph)}(meta_graph)
as = GDS.Conversions.to_arbitrary_steppable(bn)

@test DSB.current_state(as) == [0, 0, 0]

grid = Tuple(range(0, 1) for _ in 1:3)

mapper = AttractorsViaRecurrences(as, grid)

basins = basins_of_attraction(mapper, grid)
@test length(basins.attractors) == 1
@test collect(keys(basins.attractors)) == [1]
@test first(basins.attractors[1]) == [1, 1, 0]
end

@testitem "Convert to discrete system" begin
@test_skip false
end

@testitem "Explicit imports" begin
using ExplicitImports: test_explicit_imports
test_explicit_imports(BooleanNetworks)
end
4 changes: 4 additions & 0 deletions implementations/BooleanNetworks/test/runtests.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
using ReTestItems: runtests, @testitem
using BooleanNetworks

runtests(BooleanNetworks)
18 changes: 18 additions & 0 deletions implementations/QualitativeNetworks/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name = "QualitativeNetworks"
uuid = "ba61d19f-daf7-42ed-91ab-e8e04fc92a6d"
version = "0.0.1"
authors = ["Reuben Gardos Reid <5456207+ReubenJ@users.noreply.github.com>"]

[workspace]
projects = ["test"]

[deps]
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
GraphDynamicalSystems = "13529e2e-ed53-56b1-bd6f-420b01fca819"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
MetaGraphsNext = "fa8bd995-216d-47f1-8a91-f3b68fbeb377"

[compat]
AbstractTrees = "0.4.5"
Graphs = "1.14.0"
MetaGraphsNext = "0.8.0"
Loading
Loading