Skip to content

Commit ee1925c

Browse files
committed
fix: default fn saving to BMA, add sync step
1 parent f8952bc commit ee1925c

File tree

3 files changed

+88
-17
lines changed

3 files changed

+88
-17
lines changed

src/qualitative_networks.jl

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -598,27 +598,32 @@ function limit_change(
598598
return limited_value
599599
end
600600

601-
"""
602-
$(TYPEDSIGNATURES)
603-
"""
604-
function async_qn_step!(qn::QN)
605-
entity_labels = entities(qn)
606-
entity = rand(entity_labels)
601+
function _compute_next_state!(qn::QN, entity)
607602
(min_level, max_level) = extrema(get_domain(qn, entity))
608603
t = target_functions(qn)[entity]
609604
old_state = get_state(qn, entity)
610605
new_state = interpret(t, qn)
611606
new_state = isnan(new_state) ? min_level : new_state
612607
new_state = isinf(new_state) ? max_level : new_state
613608
limited_state = limit_change(old_state, floor(Int, new_state), min_level, max_level)
614-
set_state!(qn, entity, limited_state)
609+
end
610+
611+
"""
612+
$(TYPEDSIGNATURES)
613+
"""
614+
function async_qn_step!(qn::QN)
615+
entity_labels = entities(qn)
616+
entity = rand(entity_labels)
617+
next_state = _compute_next_state!(qn, entity)
618+
set_state!(qn, entity, next_state)
615619
end
616620

617621
"""
618622
$(TYPEDSIGNATURES)
619623
"""
620624
function sync_qn_step!(qn::QN)
621-
throw(ErrorException("Synchronous step function not yet implemented"))
625+
next_states = _compute_next_state!.((qn,), entities(qn))
626+
set_state!.((qn,), entities(qn), next_states)
622627
end
623628

624629
extract_state(model::QN) = model.state
@@ -706,7 +711,7 @@ function bma_dict_to_qn(bma_model::JSONModel)
706711
) for e in bma_entities
707712
]
708713

709-
return QualitativeNetwork(entities_with_functions; schedule = Asynchronous)
714+
return QualitativeNetwork(entities_with_functions; schedule = Synchronous)
710715
end
711716

712717
"""
@@ -753,6 +758,47 @@ function swap_entity_names_to_var_ids(ex)
753758
end
754759
end
755760

761+
"""
762+
stringify_fn(ex, lower_bound, upper_bound)
763+
764+
Take an `ex` and if it's of the form of a default function, return "".
765+
"""
766+
function stringify_fn(ex, lower_bound, upper_bound)
767+
if is_default_function(ex, lower_bound, upper_bound)
768+
return ""
769+
else
770+
string(ex)
771+
end
772+
end
773+
774+
function is_default_function(ex, lower_bound, upper_bound)
775+
@match ex begin
776+
# single activator
777+
:(var($id)) => true
778+
779+
# multiple activators
780+
Expr(:call, :/, Expr(:call, :+, vars...), denom) && (
781+
if length(vars) == denom
782+
end
783+
) => true
784+
785+
# only inhibitor(s)
786+
:($bound - $inh) && (
787+
if bound == upper_bound
788+
end
789+
) => is_default_function(inh, lower_bound, upper_bound)
790+
791+
# both inhibitor(s) and activator(s)
792+
:(max($bound, $act - $inh)) && (
793+
if bound == lower_bound
794+
end
795+
) =>
796+
is_default_function(@show(act), lower_bound, upper_bound) &&
797+
is_default_function(@show(inh), lower_bound, upper_bound)
798+
_ => false
799+
end
800+
end
801+
756802
"""
757803
$(SIGNATURES)
758804
@@ -767,13 +813,14 @@ function qn_to_bma_dict(qn::QN{N,S,M}) where {N,S,C,G,L<:EntityIdName,M<:MetaGra
767813
functions = [target_functions(qn)[e] for e in entities(qn)]
768814
activator_inhibitor_pairs = classify_activators_inhibitors(target_functions(qn))
769815
functions = swap_entity_names_to_var_ids.(functions)
816+
functions = stringify_fn.(functions, first.(lower_upper), last.(lower_upper))
770817

771818
variables = [
772819
Dict(
773820
"RangeFrom" => d[1],
774821
"RangeTo" => d[2],
775822
"Id" => i,
776-
"Formula" => string(f),
823+
"Formula" => f,
777824
"Name" => n,
778825
) for (d, i, n, f) in zip(lower_upper, ids, entity_names, functions)
779826
]

test/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Attractors = "f3fd9213-ca85-4dba-9dfd-7fc91308fec7"
44
DynamicalSystemsBase = "6e36e845-645a-534a-86f2-f5d4aa5a06b4"
55
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
66
HerbCore = "2b23ba43-8213-43cb-b5ea-38c12b45bd45"
7+
IterTools = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
78
JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b"
89
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
910
MetaGraphsNext = "fa8bd995-216d-47f1-8a91-f3b68fbeb377"

test/qn_test.jl

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ end
179179

180180
@testitem "Save to BMA" begin
181181
import MetaGraphsNext: edge_labels, labels
182+
import GraphDynamicalSystems: is_default_function
182183
using JSON
183184

184185
function test_json_roundtrip(model_path::AbstractString)
@@ -201,6 +202,16 @@ end
201202

202203
@test haskey(model_dict, "Variables")
203204
variables = model_dict["Variables"]
205+
for (orig_v, v) in zip(orig_dict["Model"]["Variables"], variables)
206+
orig_f = Meta.parse(orig_v["Formula"])
207+
f = Meta.parse(v["Formula"])
208+
209+
if is_default_function(orig_f, orig_v["RangeFrom"], orig_v["RangeTo"])
210+
@test isnothing(f)
211+
else
212+
@test orig_f == f
213+
end
214+
end
204215
orig_variables_no_f = [
205216
Dict(k => v for (k, v) in var if k != "Formula") for
206217
var in orig_dict["Model"]["Variables"]
@@ -222,15 +233,27 @@ end
222233
bma_models_path = joinpath(@__DIR__, "resources", "bma_models")
223234
good_models = joinpath(bma_models_path, "well_formed_examples")
224235

236+
# just another reminder that the "Skin1D" example isn't working with this test
237+
@test_broken false
238+
225239
for model_path in filter(!contains(r"Skin1D"), readdir(good_models; join = true))
226240
test_json_roundtrip(model_path)
227241
end
228-
# toy_model = joinpath(
229-
# @__DIR__,
230-
# "resources",
231-
# "bma_models",
232-
# "well_formed_examples",
233-
# "ToyModelStable.json",
234-
# )
242+
end
235243

244+
@testitem "is default function" begin
245+
import IterTools: subsets
246+
import GraphDynamicalSystems:
247+
is_default_function, default_target_function, swap_entity_names_to_var_ids
248+
combinations = Iterators.filter(
249+
x -> !all(isempty.(x)),
250+
Iterators.product(subsets([:A_1, :B_2, :X_5, :Y_6]), subsets([:C_3, :D_4, :Z_7])),
251+
)
252+
activators = first.(combinations)
253+
inhibitors = last.(combinations)
254+
255+
fns = default_target_function.(0, 4, activators, inhibitors)
256+
for f in swap_entity_names_to_var_ids.(fns)
257+
@test is_default_function(f, 0, 4)
258+
end
236259
end

0 commit comments

Comments
 (0)