Skip to content

Commit bc38925

Browse files
committed
🐛 update edge counts efficiently
1 parent 5bc21a7 commit bc38925

File tree

1 file changed

+88
-37
lines changed

1 file changed

+88
-37
lines changed

inc/Graph.hxx

Lines changed: 88 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,24 @@ class ArenaDiGraph {
134134
inline bool directed() const noexcept {
135135
return true;
136136
}
137+
138+
/**
139+
* Set the number of vertices in the graph.
140+
* @param n new number of vertices
141+
* @note This is used for internal purposes only.
142+
*/
143+
inline void setOrder(size_t n) noexcept {
144+
N = n;
145+
}
146+
147+
/**
148+
* Set the number of edges in the graph.
149+
* @param m new number of edges
150+
* @note This is used for internal purposes only.
151+
*/
152+
inline void setSize(size_t m) noexcept {
153+
M = m;
154+
}
137155
#pragma endregion
138156

139157

@@ -793,13 +811,15 @@ class ArenaDiGraph {
793811
* @param ie end iterator of edge keys to remove
794812
* @param fl comparison function for edge keys
795813
* @note [ib, ie) must be sorted and unique.
814+
* @returns number of edges removed
796815
*/
797816
template <class I, class FL>
798-
inline void removeEdges(K u, I ib, I ie, FL fl) {
799-
if (!hasVertex(u)) return;
817+
inline size_t removeEdges(K u, I ib, I ie, FL fl) {
818+
if (!hasVertex(u)) return 0;
800819
auto *eb = edges[u], *ee = edges[u] + degrees[u];
801820
auto it = set_difference(eb, ee, ib, ie, eb, fl);
802821
degrees[u] = it - eb;
822+
return ee - it;
803823
}
804824

805825

@@ -809,11 +829,12 @@ class ArenaDiGraph {
809829
* @param ib begin iterator of edge keys to remove
810830
* @param ie end iterator of edge keys to remove
811831
* @note [ib, ie) must be sorted and unique.
832+
* @returns number of edges removed
812833
*/
813834
template <class I>
814-
inline void removeEdges(K u, I ib, I ie) {
835+
inline size_t removeEdges(K u, I ib, I ie) {
815836
auto fl = [](const auto& a, const auto& b) { return a.first < b; };
816-
removeEdges(u, ib, ie, fl);
837+
return removeEdges(u, ib, ie, fl);
817838
}
818839

819840

@@ -823,10 +844,11 @@ class ArenaDiGraph {
823844
* @param ib begin iterator of edges to add
824845
* @param ie end iterator of edges to add
825846
* @note [ib, ie) must be sorted and unique.
847+
* @returns number of edges added
826848
*/
827849
template <class I>
828-
inline void addEdges(K u, I ib, I ie) {
829-
if (!hasVertex(u) || ib==ie) return;
850+
inline size_t addEdges(K u, I ib, I ie) {
851+
if (!hasVertex(u) || ib==ie) return 0;
830852
auto *eb = edges[u], *ee = edges[u] + degrees[u];
831853
size_t deg = degrees[u] + distance(ib, ie);
832854
size_t cap = allocationCapacity(deg);
@@ -837,6 +859,7 @@ class ArenaDiGraph {
837859
edges[u] = ptr;
838860
degrees[u] = it - ptr;
839861
capacities[u] = cap;
862+
return (it - ptr) - (ee - eb);
840863
}
841864

842865

@@ -1559,36 +1582,43 @@ class DiGraphCsr {
15591582
* Subtract a graph's edges from another graph.
15601583
* @param a graph to subtract from (updated)
15611584
* @param y graph to subtract
1585+
* @returns number of edges removed
15621586
*/
15631587
template <class H, class G>
1564-
inline void subtractGraphEdgesU(H& a, const G& y) {
1588+
inline size_t subtractGraphEdgesU(H& a, const G& y) {
1589+
size_t dM = 0;
15651590
y.forEachVertexKey([&](auto u) {
15661591
if (!a.hasVertex(u)) return;
15671592
auto yb = y.beginEdges(u), ye = y.endEdges(u);
15681593
auto fl = [](const auto& a, const auto& b) { return a.first < b.first; };
1569-
a.removeEdges(u, yb, ye, fl);
1594+
dM += a.removeEdges(u, yb, ye, fl);
15701595
});
1571-
a.update(true, true);
1596+
// Update the number of edges.
1597+
a.setSize(a.size() - dM);
1598+
return dM;
15721599
}
15731600

15741601

15751602
/**
15761603
* Subtract a graph's edges from another graph [parallel].
15771604
* @param a graph to subtract from (updated)
15781605
* @param y graph to subtract
1606+
* @returns number of edges removed
15791607
*/
15801608
template <int CHUNK=1024, class H, class G>
1581-
inline void subtractGraphOmpU(H& a, const G& y) {
1609+
inline size_t subtractGraphOmpU(H& a, const G& y) {
15821610
using K = typename H::key_type;
1583-
size_t S = y.span();
1584-
#pragma omp parallel for schedule(dynamic, CHUNK)
1611+
size_t S = y.span(), dM = 0;
1612+
#pragma omp parallel for schedule(dynamic, CHUNK) reduction(+:dM)
15851613
for (K u=0; u<S; ++u) {
15861614
if (!y.hasVertex(u) || !a.hasVertex(u)) continue;
15871615
auto yb = y.beginEdges(u), ye = y.endEdges(u);
15881616
auto fl = [](const auto& a, const auto& b) { return a.first < b.first; };
1589-
a.removeEdges(u, yb, ye, fl);
1617+
dM += a.removeEdges(u, yb, ye, fl);
15901618
}
1591-
a.updateOmp(true, true);
1619+
// Update the number of edges.
1620+
a.setSize(a.size() - dM);
1621+
return dM;
15921622
}
15931623

15941624

@@ -1597,10 +1627,11 @@ inline void subtractGraphOmpU(H& a, const G& y) {
15971627
* @param a output graph (output)
15981628
* @param x graph to subtract from
15991629
* @param y graph to subtract
1630+
* @returns number of edges removed
16001631
*/
16011632
template <class H, class GX, class GY>
1602-
inline void subtractGraphW(H& a, const GX& x, const GY& y) {
1603-
size_t S = x.span();
1633+
inline size_t subtractGraphW(H& a, const GX& x, const GY& y) {
1634+
size_t S = x.span(), dM = 0;
16041635
a.clear();
16051636
a.reserve(S);
16061637
// Add the vertices.
@@ -1628,8 +1659,11 @@ inline void subtractGraphW(H& a, const GX& x, const GY& y) {
16281659
auto fl = [](const auto& a, const auto& b) { return a.first < b.first; };
16291660
auto it = set_difference(xb, xe, yb, ye, ab, fl);
16301661
a.setDegreeUnsafe(u, it - ab);
1662+
dM += (xe - xb) - (it - ab);
16311663
});
1664+
// Update the number of edges.
16321665
a.update(true, true);
1666+
return dM;
16331667
}
16341668

16351669

@@ -1639,11 +1673,12 @@ inline void subtractGraphW(H& a, const GX& x, const GY& y) {
16391673
* @param a output graph (output)
16401674
* @param x graph to subtract from
16411675
* @param y graph to subtract
1676+
* @returns number of edges removed
16421677
*/
16431678
template <int CHUNK=1024, class H, class GX, class GY>
1644-
inline void subtractGraphOmpW(H& a, const GX& x, const GY& y) {
1679+
inline size_t subtractGraphOmpW(H& a, const GX& x, const GY& y) {
16451680
using K = typename H::key_type;
1646-
size_t S = x.span();
1681+
size_t S = x.span(), dM = 0;
16471682
a.clearOmp();
16481683
a.reserveOmp(S);
16491684
// Add the vertices.
@@ -1668,7 +1703,7 @@ inline void subtractGraphOmpW(H& a, const GX& x, const GY& y) {
16681703
a.setDegreeUnsafe(u, it - ab);
16691704
}
16701705
// Now add edges of vertices that are touched.
1671-
#pragma omp parallel for schedule(dynamic, CHUNK)
1706+
#pragma omp parallel for schedule(dynamic, CHUNK) reduction(+:dM)
16721707
for (K u=0; u<S; ++u) {
16731708
if (!x.hasVertex(u) || !y.hasVertex(u)) continue;
16741709
auto xb = x.beginEdges(u), xe = x.endEdges(u);
@@ -1677,8 +1712,11 @@ inline void subtractGraphOmpW(H& a, const GX& x, const GY& y) {
16771712
auto fl = [](const auto& a, const auto& b) { return a.first < b.first; };
16781713
auto it = set_difference(xb, xe, yb, ye, ab, fl);
16791714
a.setDegreeUnsafe(u, it - ab);
1715+
dM += (xe - xb) - (it - ab);
16801716
}
1717+
// Update the number of edges.
16811718
a.updateOmp(true, true);
1719+
return dM;
16821720
}
16831721
#endif
16841722

@@ -1687,11 +1725,12 @@ inline void subtractGraphOmpW(H& a, const GX& x, const GY& y) {
16871725
* Add a graph's edges to another graph.
16881726
* @param a graph to add to (updated)
16891727
* @param y graph to add
1728+
* @returns number of edges added
16901729
*/
16911730
template <class H, class G>
1692-
inline void addGraphU(H& a, const G& y) {
1693-
size_t A = a.span(), Y = y.span();
1694-
size_t S = max(A, Y);
1731+
inline size_t addGraphU(H& a, const G& y) {
1732+
size_t A = a.span(), Y = y.span();
1733+
size_t S = max(A, Y), dM = 0;
16951734
if (S!=A) a.respan(S);
16961735
// Add new vertices.
16971736
y.forEachVertex([&](auto u, auto d) {
@@ -1700,9 +1739,11 @@ inline void addGraphU(H& a, const G& y) {
17001739
// Add new edges.
17011740
y.forEachVertex([&](auto u, auto d) {
17021741
auto yb = y.beginEdges(u), ye = y.endEdges(u);
1703-
a.addEdges(u, yb, ye);
1742+
dM += a.addEdges(u, yb, ye);
17041743
});
1705-
a.update(true, true);
1744+
// Update the number of edges.
1745+
a.setSize(a.size() + dM);
1746+
return dM;
17061747
}
17071748

17081749

@@ -1711,12 +1752,13 @@ inline void addGraphU(H& a, const G& y) {
17111752
* Add a graph's edges to another graph [parallel].
17121753
* @param a graph to add to (updated)
17131754
* @param y graph to add
1755+
* @returns number of edges added
17141756
*/
17151757
template <int CHUNK=512, class H, class G>
1716-
inline void addGraphOmpU(H& a, const G& y) {
1758+
inline size_t addGraphOmpU(H& a, const G& y) {
17171759
using K = typename H::key_type;
1718-
size_t A = a.span(), Y = y.span();
1719-
size_t S = max(A, Y);
1760+
size_t A = a.span(), Y = y.span();
1761+
size_t S = max(A, Y), dM = 0;
17201762
if (S!=A) a.respan(S);
17211763
// Add new vertices.
17221764
#pragma omp parallel for schedule(static, 2048)
@@ -1725,13 +1767,15 @@ inline void addGraphOmpU(H& a, const G& y) {
17251767
a.addVertex(u, y.vertexValue(u));
17261768
}
17271769
// Add new edges.
1728-
#pragma omp parallel for schedule(dynamic, CHUNK)
1770+
#pragma omp parallel for schedule(dynamic, CHUNK) reduction(+:dM)
17291771
for (K u=0; u<Y; ++u) {
17301772
if (!y.hasVertex(u)) continue;
17311773
auto yb = y.beginEdges(u), ye = y.endEdges(u);
1732-
a.addEdges(u, yb, ye);
1774+
dM += a.addEdges(u, yb, ye);
17331775
}
1734-
a.updateOmp(true, true);
1776+
// Update the number of edges.
1777+
a.setSize(a.size() + dM);
1778+
return dM;
17351779
}
17361780
#endif
17371781

@@ -1741,12 +1785,13 @@ inline void addGraphOmpU(H& a, const G& y) {
17411785
* @param a output graph (output)
17421786
* @param x graph to add from
17431787
* @param y graph to add
1788+
* @returns number of edges added
17441789
*/
17451790
template <class H, class GX, class GY>
1746-
inline void addGraphW(H& a, const GX& x, const GY& y) {
1791+
inline size_t addGraphW(H& a, const GX& x, const GY& y) {
17471792
using K = typename H::key_type;
1748-
size_t X = x.span(), Y = y.span();
1749-
size_t S = max(X, Y);
1793+
size_t X = x.span(), Y = y.span();
1794+
size_t S = max(X, Y), dM = 0;
17501795
a.clear();
17511796
a.reserve(S);
17521797
// Add the vertices.
@@ -1766,8 +1811,11 @@ inline void addGraphW(H& a, const GX& x, const GY& y) {
17661811
auto fl = [](const auto& a, const auto& b) { return a.first < b.first; };
17671812
auto it = set_union(xb, xe, yb, ye, ab, fl);
17681813
a.setDegreeUnsafe(u, it - ab);
1814+
dM += (it - ab) - (xe - xb);
17691815
}
1816+
// Update the number of edges.
17701817
a.update(true, true);
1818+
return dM;
17711819
}
17721820

17731821

@@ -1779,10 +1827,10 @@ inline void addGraphW(H& a, const GX& x, const GY& y) {
17791827
* @param y graph to add
17801828
*/
17811829
template <int CHUNK=512, class H, class GX, class GY>
1782-
inline void addGraphOmpW(H& a, const GX& x, const GY& y) {
1830+
inline size_t addGraphOmpW(H& a, const GX& x, const GY& y) {
17831831
using K = typename H::key_type;
1784-
size_t X = x.span(), Y = y.span();
1785-
size_t S = max(X, Y);
1832+
size_t X = x.span(), Y = y.span();
1833+
size_t S = max(X, Y), dM = 0;
17861834
a.clearOmp();
17871835
a.reserveOmp(S);
17881836
// Add the vertices.
@@ -1798,7 +1846,7 @@ inline void addGraphOmpW(H& a, const GX& x, const GY& y) {
17981846
a.allocateEdges(u, x.degree(u) + y.degree(u));
17991847
}
18001848
// Now add edges of vertices that are touched.
1801-
#pragma omp parallel for schedule(dynamic, CHUNK)
1849+
#pragma omp parallel for schedule(dynamic, CHUNK) reduction(+:dM)
18021850
for (K u=0; u<S; ++u) {
18031851
if (!x.hasVertex(u) && !y.hasVertex(u)) continue;
18041852
auto xb = x.beginEdges(u), xe = x.endEdges(u);
@@ -1807,8 +1855,11 @@ inline void addGraphOmpW(H& a, const GX& x, const GY& y) {
18071855
auto fl = [](const auto& a, const auto& b) { return a.first < b.first; };
18081856
auto it = set_union(xb, xe, yb, ye, ab, fl);
18091857
a.setDegreeUnsafe(u, it - ab);
1858+
dM += (it - ab) - (xe - xb);
18101859
}
1860+
// Update the number of edges.
18111861
a.updateOmp(true, true);
1862+
return dM;
18121863
}
18131864
#endif
18141865
#pragma endregion

0 commit comments

Comments
 (0)