Skip to content

Commit

Permalink
🚧 Fix untill all tests pass again.
Browse files Browse the repository at this point in the history
  • Loading branch information
iago-lito committed Jun 5, 2024
1 parent 43453b9 commit 43e3443
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 101 deletions.
2 changes: 2 additions & 0 deletions src/Framework/Framework.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ module Framework
# - [ ] `depends(other_method_name)` to inherit all dependent components.
# - [ ] Recurring pattern: various blueprints types provide 'the same component': reify.
# - [ ] Namespace properties into like system.namespace.namespace.property.
# - [ ] Hooks need to trigger when special components combination become available.
# See for instance the expansion of `Nutrients.Nodes`.

using Crayons
using MacroTools
Expand Down
1 change: 1 addition & 0 deletions src/Internals/model/model_parameters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ function ModelParameters(
temperature_response,
network,
biorates,
Topology(),
functional_response,
producer_growth,
nothing,
Expand Down
13 changes: 8 additions & 5 deletions src/Topologies/Topologies.jl
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,9 @@ include("display.jl")
function add_nodes!(top::Topology, labels, type::Symbol)

# Check whole transaction before commiting.
is_node_type_valid(top, type) &&
has_node_type(top, type) &&
argerr("Node type $(repr(type)) already exists in the topology.")
is_edge_type_valid(top, type) &&
has_edge_type(top, type) &&
argerr("Node type $(repr(type)) would be confused with edge type $(repr(type)).")
labels = check_new_nodes_labels(top, labels)

Expand Down Expand Up @@ -163,7 +163,7 @@ function add_edge_type!(top::Topology, type::Symbol)
end
export add_edge_type!

function add_edge!(top::Topology, type, source::AbsRef, target::AbsRef)
function add_edge!(top::Topology, type::IRef, source::AbsRef, target::AbsRef)
# Check transaction.
check_edge_type(top, type)
check_node_ref(top, source)
Expand Down Expand Up @@ -193,7 +193,7 @@ include("./edges_from_matrices.jl")
# Remove all neighbours of this node and replace it with a tombstone.

# The exposed version is checked.
function remove_node!(top::Topology, node::RelRef, type)
function remove_node!(top::Topology, node::RelRef, type::IRef)
# Check transaction.
check_node_type(top, type)
check_node_ref(top, node, type)
Expand Down Expand Up @@ -264,7 +264,10 @@ function disconnected_components(top::Topology)
Iterators.filter(weakly_connected_components(graph)) do component_nodes
# Removed nodes result in degenerated singleton components.
# Dismiss them.
!(length(component_nodes) == 1 && U.is_removed(top, component_nodes[1]))
!(
length(component_nodes) == 1 &&
U.is_removed(top, Abs(first(component_nodes)))
)
end,
) do component_nodes
# Construct a whole new value with only these nodes remaining.
Expand Down
38 changes: 19 additions & 19 deletions src/Topologies/checks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,30 @@
#-------------------------------------------------------------------------------------------
# Check indices validity.

is_index_valid(i, n) = 1 <= i <= n
has_index(i, n) = 1 <= i <= n
err_index(i, n, what) = argerr("Invalid $what index ($i) \
when there $(n > 1 ? "are" : "is") $n $what$(s(n)).")
function check_index(i, n, what)
is_index_valid(i, n) || err_index(i, n, what isa String ? what : what())
has_index(i, n) || err_index(i, n, what isa String ? what : what())
i
end

is_node_type_valid(top::Topology, i::Int) = is_index_valid(i, length(top.node_types_labels))
has_node_type(top::Topology, i::Int) = has_index(i, length(top.node_types_labels))
check_node_type(top::Topology, i::Int) =
check_index(i, length(top.node_types_labels), "node type")

is_edge_type_valid(top::Topology, i::Int) = is_index_valid(i, length(top.edge_types_labels))
has_edge_type(top::Topology, i::Int) = has_index(i, length(top.edge_types_labels))
check_edge_type(top::Topology, i::Int) =
check_index(i, length(top.edge_types_labels), "edge type")

is_node_ref_valid(top::Topology, abs::Abs) = is_index_valid(abs.i, length(top.nodes_labels))
has_node_ref(top::Topology, abs::Abs) = has_index(abs.i, length(top.nodes_labels))
check_node_ref(top::Topology, abs::Abs) =
check_index(abs.i, length(top.nodes_labels), "node")

# Check relative indices ASSUMING the node type is valid.
is_node_ref_valid(top::Topology, rel::Rel, type) =
is_index_valid(rel.i, U.n_nodes_including_removed(top, type))
check_node_ref(top::Topology, rel::Rel, type) = check_index(
has_node_ref(top::Topology, rel::Rel, type::IRef) =
has_index(rel.i, U.n_nodes_including_removed(top, type))
check_node_ref(top::Topology, rel::Rel, type::IRef) = check_index(
rel.i,
U.n_nodes_including_removed(top, type),
() -> "$(repr(U.node_type_label(top, type))) node",
Expand All @@ -35,7 +35,7 @@ check_node_ref(top::Topology, rel::Rel, type) = check_index(
#-------------------------------------------------------------------------------------------
# Check labels validity.

is_label_valid(lab, set) = lab in set
has_label(lab, set) = lab in set
function err_label(lab, set, what)
valid = if isempty(set)
"There are no labels yet."
Expand All @@ -45,27 +45,27 @@ function err_label(lab, set, what)
argerr("Invalid $what label: $(repr(lab)). $valid")
end
function check_label(lab, set, what)
is_label_valid(lab, set) || err_label(lab, set, what isa String ? what : what())
has_label(lab, set) || err_label(lab, set, what isa String ? what : what())
lab
end

is_node_type_valid(top::Topology, lab::Symbol) =
is_label_valid(lab, keys(top.node_types_index))
has_node_type(top::Topology, lab::Symbol) =
has_label(lab, keys(top.node_types_index))
check_node_type(top::Topology, lab::Symbol) =
check_label(lab, keys(top.node_types_index), "node type")

is_edge_type_valid(top::Topology, lab::Symbol) =
is_label_valid(lab, keys(top.edge_types_index))
has_edge_type(top::Topology, lab::Symbol) =
has_label(lab, keys(top.edge_types_index))
check_edge_type(top::Topology, lab::Symbol) =
check_label(lab, keys(top.edge_types_index), "edge type")

is_node_ref_valid(top::Topology, lab::Symbol) = is_label_valid(lab, keys(top.nodes_index))
has_node_ref(top::Topology, lab::Symbol) = has_label(lab, keys(top.nodes_index))
check_node_ref(top::Topology, lab::Symbol) = check_label(lab, keys(top.nodes_index), "node")

# Check "relative labels" ASSUMING the node type is valid.
is_node_ref_valid(top::Topology, lab::Symbol, type) =
is_label_valid(lab, U._node_labels(top, type))
check_node_ref(top::Topology, lab::Symbol, type) = check_label(
has_node_ref(top::Topology, lab::Symbol, type::IRef) =
has_label(lab, U._node_labels(top, type))
check_node_ref(top::Topology, lab::Symbol, type::IRef) = check_label(
lab,
U._nodes_labels(top, type),
() -> "$(repr(U.node_type_label(top, type))) node",
Expand All @@ -85,7 +85,7 @@ end
# Check node labels availability.
function check_new_nodes_labels(top::Topology, labels::Vector{Symbol})
for new_lab in labels
if is_node_ref_valid(top, new_lab)
if has_node_ref(top, new_lab)
argerr("Label :$new_lab was already given \
to a node of type \
$(repr(U.type_of_node(top, new_lab))).")
Expand Down
14 changes: 7 additions & 7 deletions src/Topologies/edges_from_matrices.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# including (blank) removed nodes.
function add_edges_within_node_type!(
top::Topology,
node_type,
edge_type,
node_type::IRef,
edge_type::IRef,
e::AbstractSparseMatrix{Bool},
)
# Check transaction.
Expand Down Expand Up @@ -71,7 +71,7 @@ function add_edges_within_node_type!(

top
end
add_edges_within_node_type!(top::Topology, n, e, m::Matrix{Bool}) =
add_edges_within_node_type!(top::Topology, n::IRef, e::IRef, m::Matrix{Bool}) =
add_edges_within_node_type!(top, n, e, sparse(m))
export add_edges_within_node_type!

Expand All @@ -81,9 +81,9 @@ export add_edges_within_node_type!

function add_edges_accross_node_types!(
top::Topology,
source_node_type,
target_node_type,
edge_type,
source_node_type::IRef,
target_node_type::IRef,
edge_type::IRef,
e::AbstractSparseMatrix{Bool},
)
# Check transaction.
Expand Down Expand Up @@ -160,6 +160,6 @@ function add_edges_accross_node_types!(

top
end
add_edges_accross_node_types!(top::Topology, n, m, t, e::Matrix{Bool}) =
add_edges_accross_node_types!(top::Topology, n::IRef, m::IRef, t::IRef, e::Matrix{Bool}) =
add_edges_accross_node_types!(top, n, m, t, sparse(e))
export add_edges_accross_node_types!
60 changes: 30 additions & 30 deletions src/Topologies/unchecked_queries.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Methods that would leak references are protected with a '_' prefix.
module Unchecked

import ..Topologies: Topology, Tombstone, Abs, Rel, AbsRef
import ..Topologies: Topology, Tombstone, Abs, Rel, AbsRef, IRef

const imap = Iterators.map
const ifilter = Iterators.filter
Expand All @@ -25,31 +25,31 @@ edge_type_index(::Topology, i::Int) = i
# Nodes.

# General information.
n_nodes(top::Topology, type) = top.n_nodes[node_type_index(top, type)]
n_nodes_including_removed(top::Topology, type) =
n_nodes(top::Topology, type::IRef) = top.n_nodes[node_type_index(top, type)]
n_nodes_including_removed(top::Topology, type::IRef) =
length(top.nodes_types[node_type_index(top, type)])
_nodes_abs_range(top::Topology, type) = # Okay to leak (immutable) but not abs-wrapped..
_nodes_abs_range(top::Topology, type::IRef) = # Okay to leak (immutable) but not abs-wrapped..
top.nodes_types[node_type_index(top, type)]
nodes_abs_indices(top::Topology, type) =
nodes_abs_indices(top::Topology, type::IRef) =
imap(Abs, top.nodes_types[node_type_index(top, type)])
_nodes_labels(top::Topology, type) = top.nodes_labels[_nodes_abs_range(top, type)]
node_labels(top::Topology, type) = idmap(_nodes_labels(top, type))
_nodes_labels(top::Topology, type::IRef) = top.nodes_labels[_nodes_abs_range(top, type)]
node_labels(top::Topology, type::IRef) = idmap(_nodes_labels(top, type))

# Particular information about nodes.
node_label(top::Topology, abs::Abs) = top.nodes_labels[abs.i]
node_abs_index(top::Topology, label::Symbol) = Abs(top.nodes_index[label])
node_label(::Topology, lab::Symbol) = lab
node_abs_index(::Topology, abs::Abs) = abs
# Append correct offset to convert between relative / absolute indices.
first_node_abs_index(top::Topology, type) = first(nodes_abs_indices(top, type))
node_index_offset(top::Topology, type) = first_node_abs_index(top, type).i - 1
node_abs_index(top::Topology, relative_index::Rel, type) =
first_node_abs_index(top::Topology, type::IRef) = first(nodes_abs_indices(top, type))
node_index_offset(top::Topology, type::IRef) = first_node_abs_index(top, type).i - 1
node_abs_index(top::Topology, relative_index::Rel, type::IRef) =
Abs(relative_index.i + node_index_offset(top, type))
node_rel_index(top::Topology, node::AbsRef, type) =
node_rel_index(top::Topology, node::AbsRef, type::IRef) =
Rel(node_abs_index(top, node).i - node_index_offset(top, type))
# For consistency with the above, node type information is ignored when unnecessary
# because we ASSUME here that it has already been checked for consistency.
node_abs_index(top::Topology, lab::AbsRef, _) = node_abs_index(top, lab)
node_abs_index(top::Topology, lab::AbsRef, ::IRef) = node_abs_index(top, lab)

# Querying node type requires a linear search,
# but it is generally assumed that if you know the node, then you already know its type.
Expand All @@ -58,7 +58,7 @@ type_index_of_node(top::Topology, node::AbsRef) =
type_of_node(top::Topology, node::AbsRef) =
node_type_label(top, type_index_of_node(top, node))
# But it is O(1) to check whether a given node is of the given type.
function is_node_of_type(top::Topology, node::AbsRef, type)
function is_node_of_type(top::Topology, node::AbsRef, type::IRef)
i_type = node_type_index(top, type)
i_node = node_abs_index(top, node)
i_node.i in top.nodes_types[i_type]
Expand All @@ -75,21 +75,21 @@ n_edges(top::Topology, type) = top.n_edges[edge_type_index(top, type)]

# Direct neighbourhood when querying particular edge type.
# (assuming focal node is not a tombstone)
function _outgoing_indices(top::Topology, node::AbsRef, edge_type)
function _outgoing_indices(top::Topology, node::AbsRef, edge_type::IRef)
i_type = edge_type_index(top, edge_type)
_outgoing_indices(top, node)[i_type]
end
function _incoming_indices(top::Topology, node::AbsRef, edge_type)
function _incoming_indices(top::Topology, node::AbsRef, edge_type::IRef)
i_type = edge_type_index(top, edge_type)
_incoming_indices(top, node)[i_type]
end
outgoing_indices(top::Topology, node::AbsRef, type) =
outgoing_indices(top::Topology, node::AbsRef, type::IRef) =
imap(Abs, _outgoing_indices(top, node, type))
incoming_indices(top::Topology, node::AbsRef, type) =
imap(Abs, _incoming_indices(top, node::AbsRef, type))
outgoing_labels(top::Topology, node::AbsRef, type) =
incoming_indices(top::Topology, node::AbsRef, type::IRef) =
imap(Abs, _incoming_indices(top, node, type))
outgoing_labels(top::Topology, node::AbsRef, type::IRef) =
imap(i -> top.nodes_labels[i], _outgoing_indices(top, node, type))
incoming_labels(top::Topology, node::AbsRef, type) =
incoming_labels(top::Topology, node, type::IRef) =
imap(i -> top.nodes_labels[i], _incoming_indices(top, node, type))

# Direct neighbourhood: return twolevel slices:
Expand Down Expand Up @@ -129,41 +129,41 @@ incoming_labels(top::Topology, node::AbsRef) =

# Filter adjacency iterators given one particular edge type.
# Also return twolevel iterators: focal node, then its neighbours.
function _outgoing_edges_indices(top::Topology, edge_type)
function _outgoing_edges_indices(top::Topology, edge_type::IRef)
i_type = edge_type_index(top, edge_type)
imap(ifilter(enumerate(top.outgoing)) do (_, node)
!(node isa Tombstone)
end) do (i, _neighbours)
(i, _neighbours[i_type])
end
end
function _incoming_edges_indices(top::Topology, edge_type)
function _incoming_edges_indices(top::Topology, edge_type::IRef)
i_type = edge_type_index(top, edge_type)
imap(ifilter(enumerate(top.incoming)) do (_, node)
!(node isa Tombstone)
end) do (i, _neighbours)
(i, _neighbours[i_type])
end
end
outgoing_edges_indices(top::Topology, edge_type) =
outgoing_edges_indices(top::Topology, edge_type::IRef) =
imap(_outgoing_edges_indices(top, edge_type)) do (i_node, _neighbours)
(Abs(i_node), imap(Abs, _neighbours))
end
incoming_edges_indices(top::Topology, edge_type) =
incoming_edges_indices(top::Topology, edge_type::IRef) =
imap(_incoming_edges_indices(top, edge_type)) do (i_node, _neighbours)
(Abs(i_node), imap(Abs, _neighbours))
end
outgoing_edges_labels(top::Topology, edge_type) =
outgoing_edges_labels(top::Topology, edge_type::IRef) =
imap(_outgoing_edges_indices(top, edge_type)) do (i_node, _neighbours)
(node_label(top, i_node), imap(i -> node_label(top, i), _neighbours))
end
incoming_edges_labels(top::Topology, edge_type) =
incoming_edges_labels(top::Topology, edge_type::IRef) =
imap(_incoming_edges_indices(top, edge_type)) do (i_node, _neighbours)
(node_label(top, i_node), imap(i -> node_label(top, i), _neighbours))
end

# Same, but filters for one particular node type.
function outgoing_edges_indices(top::Topology, edge_type, node_type)
function outgoing_edges_indices(top::Topology, edge_type::IRef, node_type::IRef)
i_et = edge_type_index(top, edge_type)
range = _nodes_abs_range(top, node_type)
imap(ifilter(zip(range, top.outgoing[range])) do (_, node)
Expand All @@ -172,7 +172,7 @@ function outgoing_edges_indices(top::Topology, edge_type, node_type)
(Abs(i_node), imap(Abs, ifilter(in(range), _neighbours[i_et])))
end
end
function incoming_edges_indices(top::Topology, edge_type, node_type)
function incoming_edges_indices(top::Topology, edge_type::IRef, node_type::IRef)
i_et = edge_type_index(top, edge_type)
range = _nodes_abs_range(top, node_type)
imap(ifilter(zip(range, top.incoming[range])) do (_, node)
Expand All @@ -181,11 +181,11 @@ function incoming_edges_indices(top::Topology, edge_type, node_type)
(Abs(i_node), imap(Abs, ifilter(in(range), _neighbours[i_et])))
end
end
outgoing_edges_labels(top::Topology, edge_type, node_type) =
outgoing_edges_labels(top::Topology, edge_type::IRef, node_type::IRef) =
imap(outgoing_edges_indices(top, edge_type, node_type)) do (i_node, neighbours)
(node_label(top, i_node), imap(i -> node_label(top, i), neighbours))
end
incoming_edges_labels(top::Topology, edge_type, node_type) =
incoming_edges_labels(top::Topology, edge_type::IRef, node_type::IRef) =
imap(incoming_edges_indices(top, edge_type, node_type)) do (i_node, neighbours)
(node_label(top, i_node), imap(i -> node_label(top, i), neighbours))
end
Expand Down
5 changes: 5 additions & 0 deletions src/components/foodweb.jl
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,11 @@ function F.expand!(m, bp::Foodweb)
top = m.topology
add_edge_type!(top, :trophic)
add_edges_within_node_type!(top, :species, :trophic, A)

# TODO: this should happen with components-combinations-triggered-hooks
# (see Nutrient.Nodes expansion)
Topologies.has_node_type(top, :nutrients) && Nutrients.connect_producers_to_nutrients(m)

end

@component Foodweb implies(Species)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ end
# ==========================================================================================
# Check/expand full layer components.

has_nontrophic_layers(model) = model.network isa MultiplexNetwork
has_nontrophic_layers(model) = model.network isa Internals.MultiplexNetwork
export has_nontrophic_layers

# The application procedure differs
Expand Down
Loading

0 comments on commit 43e3443

Please sign in to comment.