Skip to content

Commit

Permalink
edge degree functions (fixes #22)
Browse files Browse the repository at this point in the history
  • Loading branch information
arashbm committed Nov 17, 2023
1 parent a6c8b31 commit c208666
Show file tree
Hide file tree
Showing 3 changed files with 246 additions and 1 deletion.
65 changes: 64 additions & 1 deletion include/reticula/algorithms.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ namespace reticula {
const typename EdgeT::VertexType& vert);

/**
Calculate out-degree of a vertex in a network
Calculate incident degree of a vertex in a network
*/
template <network_edge EdgeT>
std::size_t incident_degree(
Expand All @@ -386,6 +386,34 @@ namespace reticula {
const network<EdgeT>& net,
const typename EdgeT::VertexType& vert);

/**
Calculate in-degree of an edge
*/
template <network_edge EdgeT>
std::size_t edge_in_degree(
const EdgeT& edge);

/**
Calculate out-degree of an edge
*/
template <network_edge EdgeT>
std::size_t edge_out_degree(
const EdgeT& edge);

/**
Calculate incident degree (order) of an edge
*/
template <network_edge EdgeT>
std::size_t edge_incident_degree(
const EdgeT& edge);

/**
Calculate degree (order) of an edge
*/
template <undirected_network_edge EdgeT>
std::size_t edge_degree(
const EdgeT& edge);

/**
Returns the in-degree sequence of a network
*/
Expand Down Expand Up @@ -421,6 +449,41 @@ namespace reticula {
std::vector<std::size_t>
degree_sequence(const network<EdgeT>& net);

/**
Returns the edge in-degree sequence of a network
*/
template <network_edge EdgeT>
std::vector<std::size_t>
edge_in_degree_sequence(const network<EdgeT>& net);

/**
Returns the edge out-degree sequence of a network
*/
template <network_edge EdgeT>
std::vector<std::size_t>
edge_out_degree_sequence(const network<EdgeT>& net);

/**
Returns the edge degree (order) sequence of a network
*/
template <network_edge EdgeT>
std::vector<std::size_t>
edge_incident_degree_sequence(const network<EdgeT>& net);

/**
Returns the (in-, out-) edge-degree-pair sequence of a network
*/
template <network_edge EdgeT>
std::vector<std::pair<std::size_t, std::size_t>>
edge_in_out_degree_pair_sequence(const network<EdgeT>& net);

/**
Returns the edge degree (order) sequence of an undirected network
*/
template <undirected_network_edge EdgeT>
std::vector<std::size_t>
edge_degree_sequence(const network<EdgeT>& net);


/**
Calculate degree assortativity on undirected networks.
Expand Down
79 changes: 79 additions & 0 deletions src/algorithms.tpp
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,29 @@ namespace reticula {
return net.degree(vert);
}

template <network_edge EdgeT>
std::size_t edge_in_degree(
const EdgeT& edge) {
return edge.mutator_verts().size();
}

template <network_edge EdgeT>
std::size_t edge_out_degree(
const EdgeT& edge) {
return edge.mutated_verts().size();
}

template <network_edge EdgeT>
std::size_t edge_incident_degree(
const EdgeT& edge) {
return edge.incident_verts().size();
}

template <undirected_network_edge EdgeT>
std::size_t edge_degree(
const EdgeT& edge) {
return edge.incident_verts().size();
}

template <network_edge EdgeT>
std::vector<std::size_t>
Expand Down Expand Up @@ -811,6 +834,62 @@ namespace reticula {
}


template <network_edge EdgeT>
std::vector<std::size_t>
edge_in_degree_sequence(const network<EdgeT>& net) {
std::vector<std::size_t> seq;
seq.reserve(net.edges().size());
for (auto&& e: net.edges())
seq.push_back(edge_in_degree(e));

return seq;
}

template <network_edge EdgeT>
std::vector<std::size_t>
edge_out_degree_sequence(const network<EdgeT>& net) {
std::vector<std::size_t> seq;
seq.reserve(net.edges().size());
for (auto&& e: net.edges())
seq.push_back(edge_out_degree(e));

return seq;
}

template <network_edge EdgeT>
std::vector<std::size_t>
edge_incident_degree_sequence(const network<EdgeT>& net) {
std::vector<std::size_t> seq;
seq.reserve(net.edges().size());
for (auto&& e: net.edges())
seq.push_back(edge_incident_degree(e));

return seq;
}

template <network_edge EdgeT>
std::vector<std::pair<std::size_t, std::size_t>>
edge_in_out_degree_pair_sequence(const network<EdgeT>& net) {
std::vector<std::pair<std::size_t, std::size_t>> seq;
seq.reserve(net.edges().size());
for (auto&& e: net.edges())
seq.emplace_back(edge_in_degree(e), edge_out_degree(e));

return seq;
}

template <undirected_network_edge EdgeT>
std::vector<std::size_t>
edge_degree_sequence(const network<EdgeT>& net) {
std::vector<std::size_t> seq;
seq.reserve(net.edges().size());
for (auto&& e: net.edges())
seq.push_back(edge_degree(e));

return seq;
}


template <
undirected_static_network_edge EdgeT,
std::invocable<const typename EdgeT::VertexType&> AttrFun>
Expand Down
103 changes: 103 additions & 0 deletions src/test/reticula/algorithms.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,42 @@ TEST_CASE("shortest path to vert", "[reticula::shortest_path_lengths_to]") {
{1, 4}, {2, 3}, {3, 2}, {5, 1}, {4, 0}});
}

TEST_CASE("edge degree functions",
"[reticula::edge_in_degree][reticula::edge_out_degree]"
"[reticula::edge_incident_degree][reticula::edge_degree]") {
REQUIRE(reticula::edge_in_degree(
reticula::directed_edge<int>(0, 0)) == 1);
REQUIRE(reticula::edge_in_degree(
reticula::directed_edge<int>(0, 1)) == 1);
REQUIRE(reticula::edge_in_degree(
reticula::directed_hyperedge<int>(
{0, 1}, {1, 2, 3})) == 2);

REQUIRE(reticula::edge_out_degree(
reticula::directed_edge<int>(0, 0)) == 1);
REQUIRE(reticula::edge_out_degree(
reticula::directed_edge<int>(0, 1)) == 1);
REQUIRE(reticula::edge_out_degree(
reticula::directed_hyperedge<int>(
{0, 1}, {1, 2, 3})) == 3);

REQUIRE(reticula::edge_incident_degree(
reticula::directed_edge<int>(0, 0)) == 1);
REQUIRE(reticula::edge_incident_degree(
reticula::directed_edge<int>(0, 1)) == 2);
REQUIRE(reticula::edge_incident_degree(
reticula::directed_hyperedge<int>(
{0, 1}, {1, 2, 3})) == 4);

REQUIRE(reticula::edge_degree(
reticula::undirected_edge<int>(0, 0)) == 1);
REQUIRE(reticula::edge_degree(
reticula::undirected_edge<int>(0, 1)) == 2);
REQUIRE(reticula::edge_degree(
reticula::undirected_hyperedge<int>(
{0, 1, 2, 3})) == 4);
}

TEST_CASE("degree functions",
"[reticula::in_degree][reticula::out_degree]"
"[reticula::incident_degree][reticula::degree]") {
Expand Down Expand Up @@ -993,6 +1029,18 @@ TEST_CASE("degree functions",
REQUIRE(reticula::in_out_degree_pair_sequence(graph) ==
std::vector<std::pair<std::size_t, std::size_t>>{
{0, 0}, {2, 2}, {3, 3}, {2, 2}, {3, 3}, {3, 3}, {1, 1}});

REQUIRE(reticula::edge_in_degree_sequence(graph) ==
std::vector<std::size_t>{2, 2, 2, 2, 2, 2, 2});
REQUIRE(reticula::edge_out_degree_sequence(graph) ==
std::vector<std::size_t>{2, 2, 2, 2, 2, 2, 2});
REQUIRE(reticula::edge_incident_degree_sequence(graph) ==
std::vector<std::size_t>{2, 2, 2, 2, 2, 2, 2});
REQUIRE(reticula::edge_degree_sequence(graph) ==
std::vector<std::size_t>{2, 2, 2, 2, 2, 2, 2});
REQUIRE(reticula::edge_in_out_degree_pair_sequence(graph) ==
std::vector<std::pair<std::size_t, std::size_t>>{
{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}});
}

SECTION("when given an undirected hypergraph") {
Expand Down Expand Up @@ -1032,6 +1080,18 @@ TEST_CASE("degree functions",
REQUIRE(reticula::in_out_degree_pair_sequence(graph) ==
std::vector<std::pair<std::size_t, std::size_t>>{
{0, 0}, {2, 2}, {3, 3}, {2, 2}, {3, 3}, {3, 3}, {1, 1}, {1, 1}});

REQUIRE(reticula::edge_in_degree_sequence(graph) ==
std::vector<std::size_t>{2, 2, 2, 2, 3, 2, 2});
REQUIRE(reticula::edge_out_degree_sequence(graph) ==
std::vector<std::size_t>{2, 2, 2, 2, 3, 2, 2});
REQUIRE(reticula::edge_incident_degree_sequence(graph) ==
std::vector<std::size_t>{2, 2, 2, 2, 3, 2, 2});
REQUIRE(reticula::edge_degree_sequence(graph) ==
std::vector<std::size_t>{2, 2, 2, 2, 3, 2, 2});
REQUIRE(reticula::edge_in_out_degree_pair_sequence(graph) ==
std::vector<std::pair<std::size_t, std::size_t>>{
{2, 2}, {2, 2}, {2, 2}, {2, 2}, {3, 3}, {2, 2}, {2, 2}});
}

SECTION("when given an undirected temporal network") {
Expand Down Expand Up @@ -1070,6 +1130,18 @@ TEST_CASE("degree functions",
REQUIRE(reticula::in_out_degree_pair_sequence(graph) ==
std::vector<std::pair<std::size_t, std::size_t>>{
{0, 0}, {3, 3}, {4, 4}, {2, 2}, {1, 1}});

REQUIRE(reticula::edge_in_degree_sequence(graph) ==
std::vector<std::size_t>{2, 2, 2, 2, 2});
REQUIRE(reticula::edge_out_degree_sequence(graph) ==
std::vector<std::size_t>{2, 2, 2, 2, 2});
REQUIRE(reticula::edge_incident_degree_sequence(graph) ==
std::vector<std::size_t>{2, 2, 2, 2, 2});
REQUIRE(reticula::edge_degree_sequence(graph) ==
std::vector<std::size_t>{2, 2, 2, 2, 2});
REQUIRE(reticula::edge_in_out_degree_pair_sequence(graph) ==
std::vector<std::pair<std::size_t, std::size_t>>{
{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}});
}

SECTION("when given a directed network") {
Expand Down Expand Up @@ -1102,6 +1174,16 @@ TEST_CASE("degree functions",
REQUIRE(reticula::in_out_degree_pair_sequence(graph) ==
std::vector<std::pair<std::size_t, std::size_t>>{
{0, 0}, {0, 1}, {2, 1}, {1, 1}, {1, 1}, {1, 2}, {1, 0}});

REQUIRE(reticula::edge_in_degree_sequence(graph) ==
std::vector<std::size_t>{1, 1, 1, 1, 1, 1});
REQUIRE(reticula::edge_out_degree_sequence(graph) ==
std::vector<std::size_t>{1, 1, 1, 1, 1, 1});
REQUIRE(reticula::edge_incident_degree_sequence(graph) ==
std::vector<std::size_t>{2, 2, 2, 2, 2, 2});
REQUIRE(reticula::edge_in_out_degree_pair_sequence(graph) ==
std::vector<std::pair<std::size_t, std::size_t>>{
{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}});
}

SECTION("when given a directed hypernetwork") {
Expand Down Expand Up @@ -1134,6 +1216,17 @@ TEST_CASE("degree functions",
REQUIRE(reticula::in_out_degree_pair_sequence(graph) ==
std::vector<std::pair<std::size_t, std::size_t>>{
{0, 0}, {0, 1}, {2, 2}, {2, 1}, {1, 1}, {1, 2}, {1, 0}, {1, 0}});

REQUIRE(reticula::edge_in_degree_sequence(graph) ==
std::vector<std::size_t>{1, 1, 1, 1, 1, 1, 1});
REQUIRE(reticula::edge_out_degree_sequence(graph) ==
std::vector<std::size_t>{1, 1, 2, 1, 1, 1, 1});
REQUIRE(reticula::edge_incident_degree_sequence(graph) ==
std::vector<std::size_t>{2, 2, 3, 2, 2, 2, 2});
REQUIRE(reticula::edge_in_out_degree_pair_sequence(graph) ==
std::vector<std::pair<std::size_t, std::size_t>>{
{1, 1}, {1, 1}, {1, 2}, {1, 1},
{1, 1}, {1, 1}, {1, 1}});
}

SECTION("when given an directed temporal network") {
Expand Down Expand Up @@ -1166,6 +1259,16 @@ TEST_CASE("degree functions",
REQUIRE(reticula::in_out_degree_pair_sequence(graph) ==
std::vector<std::pair<std::size_t, std::size_t>>{
{0, 0}, {1, 2}, {2, 2}, {1, 1}, {1, 0}});

REQUIRE(reticula::edge_in_degree_sequence(graph) ==
std::vector<std::size_t>{1, 1, 1, 1, 1});
REQUIRE(reticula::edge_out_degree_sequence(graph) ==
std::vector<std::size_t>{1, 1, 1, 1, 1});
REQUIRE(reticula::edge_incident_degree_sequence(graph) ==
std::vector<std::size_t>{2, 2, 2, 2, 2});
REQUIRE(reticula::edge_in_out_degree_pair_sequence(graph) ==
std::vector<std::pair<std::size_t, std::size_t>>{
{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}});
}
}

Expand Down

0 comments on commit c208666

Please sign in to comment.