Skip to content

Commit

Permalink
Merge pull request YangLab-um#29 from biphy/feature-enumerate-cycle
Browse files Browse the repository at this point in the history
Add function to find all cycles and their types in any networks
  • Loading branch information
ftavella authored Sep 19, 2023
2 parents 98d096f + eb3ddab commit 3f4d59f
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/BiologicalOscillations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
47 changes: 46 additions & 1 deletion src/network_utilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -430,4 +430,49 @@ function unique_cycle_addition(connectivity::AbstractMatrix)
end

return connectivity_vector
end
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
28 changes: 27 additions & 1 deletion test/network_utilities_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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))
@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"

0 comments on commit 3f4d59f

Please sign in to comment.