From a34c7aa05da751738b553148ba0ad8534c5a88ea Mon Sep 17 00:00:00 2001 From: Yeonghoon Kim Date: Mon, 18 Sep 2023 16:52:17 +0000 Subject: [PATCH 1/2] Add function to find all cycles and their types from any connectivity (merge conflict resolved) --- src/BiologicalOscillations.jl | 2 +- src/network_utilities.jl | 47 ++++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/BiologicalOscillations.jl b/src/BiologicalOscillations.jl index 9ff07af..b0188a9 100644 --- a/src/BiologicalOscillations.jl +++ b/src/BiologicalOscillations.jl @@ -22,7 +22,7 @@ export network_permutations, is_same_network, all_network_additions, unique_netw export is_directed_cycle_graph, is_same_set_of_networks, unique_cycle_addition export unique_negative_feedback_networks, count_inputs_by_coherence, is_negative_feedback_network export connectivity_to_binary, find_all_binary_circular_permutations, binary_to_connectivity -export calculate_node_coherence +export calculate_node_coherence, find_all_cycles_and_types # User input handling export is_valid_connectivity, connectivity_string_to_matrix # Default hyperparameters diff --git a/src/network_utilities.jl b/src/network_utilities.jl index 2ca11af..27c8215 100644 --- a/src/network_utilities.jl +++ b/src/network_utilities.jl @@ -430,4 +430,49 @@ function unique_cycle_addition(connectivity::AbstractMatrix) end return connectivity_vector -end \ No newline at end of file +end + + +""" + find_all_cycles_and_types(connectivity::AbstractMatrix) + + Returns a vector containing all unique cycles in a connectivity matrix. Each cycle is represented by a vector of nonduplicate node indices that define a cycle.a vector containing all unique cycles that can be found in a connectivity matrix. For example, if a Goodwin oscillator with a self-loop ([1 0 1; 1 0 0; 0 -1 0]) is given as an input, vectors [[1], [1, 2, 3]] and ["positive", "negative"] will be returned. + +# Arguments (Required) +- `connectivity::AbstractMatrix`: Connectivity matrix of a network + +# Returns +- `all_cycles::AbstractVector`: Vector containing vectors of node indices +- `all_types::AbstractVector`: Vector containing types of respective cycles in `all_cycles` +""" +function find_all_cycles_and_types(connectivity::AbstractMatrix) + all_cycles = [] + all_types = [] + n = size(connectivity)[1] + + # Following for statements iterate over all possible cycles in a complete directed graph (self-loops allowed) of the same size as the given graph + for cycle_length in 1:n + # Iterate over lengths of cycles + for c in combinations(1:n, cycle_length) + # With a given cycle length, iterate over possible combinations of nodes + for p in permutations(c[2:cycle_length]) + # With a given combination of nodes, iterate over its all circular permutations + + path_candidate = vcat(c[1], p, c[1]) + # Note that the start (end) point of a cycle is repeated in the above list + + index_start_node = path_candidate[1:end - 1] + index_end_node = path_candidate[2:end] + + path_in_given_connectivity = connectivity[CartesianIndex.(index_end_node, index_start_node)] + + if all(path_in_given_connectivity .!= 0) + # When possible path exists in given connectivity + push!(all_cycles, index_start_node) + push!(all_types, (prod(path_in_given_connectivity) == 1 ? "positive" : "negative")) + end + end + end + end + return all_cycles, all_types +end From eb3ddabc4afd00bbd5ba565d7678273ac3ae446b Mon Sep 17 00:00:00 2001 From: Yeonghoon Kim Date: Mon, 18 Sep 2023 17:17:48 +0000 Subject: [PATCH 2/2] Rewrite tests to find cycles and types with new function --- test/network_utilities_tests.jl | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/test/network_utilities_tests.jl b/test/network_utilities_tests.jl index 674a6b1..bfdc631 100644 --- a/test/network_utilities_tests.jl +++ b/test/network_utilities_tests.jl @@ -274,4 +274,30 @@ p2 = [0 0 0 0 -1; -1 0 0 0 0; 0 -1 0 0 0; 0 0 1 0 0; 0 0 0 1 0] @test is_same_set_of_networks(unique_network_additions(t2, 1), unique_cycle_addition(t2)) @test is_same_set_of_networks(unique_network_additions(s1, 1), unique_cycle_addition(s1)) @test is_same_set_of_networks(unique_network_additions(s3, 1), unique_cycle_addition(s3)) -@test is_same_set_of_networks(unique_network_additions(p2, 1), unique_cycle_addition(p2)) \ No newline at end of file +@test is_same_set_of_networks(unique_network_additions(p2, 1), unique_cycle_addition(p2)) + +# Test find_all_cycles_and_types. Note that the outputs of find_all_cycles_and_types are sorted by the cycle length (ascending order) +connectivity = [0 0 0 1 -1;-1 0 0 0 0;0 -1 0 0 0;0 0 -1 0 0;0 0 0 -1 0] +cycle, type = find_all_cycles_and_types(connectivity) +@test cycle[1] == [1, 2, 3, 4] +@test type[1] == "negative" + +connectivity = [1 0 0 0 -1;-1 0 0 0 0;0 -1 0 0 0;0 0 -1 0 0;0 0 0 -1 0] +cycle, type = find_all_cycles_and_types(connectivity) +@test cycle[1] == [1] +@test type[1] == "positive" + +connectivity = [0 0 0 0 -1;-1 0 0 1 0;0 -1 0 0 0;0 0 -1 0 0;0 0 0 -1 0] +cycle, type = find_all_cycles_and_types(connectivity) +@test cycle[1] == [2, 3, 4] +@test type[1] == "positive" + +connectivity = [0 0 0 0 -1;-1 0 0 0 0;0 -1 0 1 0;0 0 -1 0 0;0 0 0 -1 0] +cycle, type = find_all_cycles_and_types(connectivity) +@test cycle[1] == [3, 4] +@test type[1] == "negative" + +connectivity = [0 0 0 0 -1;-1 0 0 0 0;0 -1 0 -1 0;0 0 -1 0 0;0 0 0 -1 0] +cycle, type = find_all_cycles_and_types(connectivity) +@test cycle[1] == [3, 4] +@test type[1] == "positive"