Skip to content

Commit

Permalink
🚧 Removing nodes.
Browse files Browse the repository at this point in the history
  • Loading branch information
iago-lito committed May 23, 2024
1 parent ba5a67c commit a90065c
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 6 deletions.
42 changes: 40 additions & 2 deletions src/Topologies/Topologies.jl
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ function add_edge!(top::Topology, type, source, target)
i_type = U.edge_type_index(top, type)
i_source = U.node_index(top, source)
i_target = U.node_index(top, target)
check_live_node(top, i_source)
check_live_node(top, i_target)
check_live_node(top, i_source, source)
check_live_node(top, i_target, target)
U.has_edge(top, i_type, i_source, i_target) &&
argerr("There is already an edge of type $(repr(type))
betwen nodes $(repr(source)) and $(repr(target)).")
Expand All @@ -127,4 +127,42 @@ function add_edge!(top::Topology, type, source, target)
end
export add_edge!

# Remove all neighbours of this node and replace it with a tombstone.
function _remove_node!(top::Topology, i_node::Int, i_type::Int)
# Assumes the node is valid and live, and that the type does correspond.
ts = Tombstone()
top.outgoing[i_node] = ts
top.incoming[i_node] = ts
for adjacency in (top.outgoing, top.incoming)
for other in adjacency
other isa Tombstone && continue
for neighbours in other
pop!(neighbours, i_node, nothing)
end
end
end
top.n_nodes[i_type] -= 1
top
end
# Checked version.
function remove_node!(top::Topology, node, type)
check_node_ref(top, node)
check_node_type(top, type)
i_node = U.node_index(top, node)
check_live_node(top, i_node, node)
i_type = U.node_type_index(top, type)
U.is_node_of_type(top, i_node, i_type) ||
argerr("Node $(repr(node)) is not of type $(repr(type)).")
_remove_node!(top, i_node, i_type)
end
# Not specifying the type requires a linear search for it.
function remove_node!(top::Topology, node)
check_node_ref(top, node)
i_node = U.node_index(top, node)
check_live_node(top, i_node, node)
i_type = U.type_index_of_node(top, node)
_remove_node!(top, i_node, i_type)
end
export remove_node!

end
6 changes: 4 additions & 2 deletions src/Topologies/checks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ check_edge_type(top::Topology, lab::Symbol) =
check_node_ref(top::Topology, lab::Symbol) = check_label(lab, keys(top.nodes_index), "node")

# Check node liveliness, assuming the reference is valid.
function check_live_node(top::Topology, node)
function check_live_node(top::Topology, node, original_ref = node)
# (use the original reference to trace back to actual user input
# and improve error message)
U.is_removed(top, node) &&
argerr("Node $(repr(node)) has been removed from this topology.")
argerr("Node $(repr(original_ref)) has been removed from this topology.")
node
end
10 changes: 8 additions & 2 deletions src/Topologies/unchecked_queries.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,15 @@ node_label(::Topology, lab::Symbol) = lab
node_index(::Topology, i::Int) = i
# Querying node type requires a linear search,
# but it is generally assumed that if you know the node, then you already know its type.
node_type_index(top::Topology, id) =
type_index_of_node(top::Topology, id) =
findfirst(range -> node_index(top, id) in range, top.nodes_types)
node_type(top::Topology, id) = node_type_label(node_type_index(top, id))
type_of_node(top::Topology, id) = node_type_label(type_index_of_node(top, id))
# But it is O(1) to check whether a given node is of the given type.
function is_node_of_type(top::Topology, node, type)
i_node = node_index(top, node)
i_type = node_type_index(type)
i_node in top.nodes_types[i_type]
end

is_removed(top::Topology, node) = top.outgoing[node_index(top, node)] isa Tombstone
is_live(top::Topology, node) = !is_removed(top, node)
Expand Down
1 change: 1 addition & 0 deletions test/topologies.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ add_edge!(top, :trophic, :d, :u)
add_edge!(top, :trophic, :b, :v)
add_edge!(top, :mutualism, :a, :d)
add_edge!(top, :interference, :a, :c)
remove_node!(top, :b) # HERE: fix!

# Having this correct display implies that numerous internals are working correctly.
@test "$top" == "Topology(2 node types, 3 edge types, 6 nodes, 7 edges)"
Expand Down

0 comments on commit a90065c

Please sign in to comment.