sgtlib 3.4.0__py3-none-any.whl → 3.4.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- StructuralGT/__init__.py +1 -1
- StructuralGT/compute/graph_analyzer.py +140 -86
- StructuralGT/networks/fiber_network.py +3 -3
- {sgtlib-3.4.0.dist-info → sgtlib-3.4.1.dist-info}/METADATA +1 -1
- {sgtlib-3.4.0.dist-info → sgtlib-3.4.1.dist-info}/RECORD +9 -11
- StructuralGT/compute/c_lang/sgt_base.c +0 -61
- StructuralGT/compute/c_lang/sgtmodule.c +0 -183
- {sgtlib-3.4.0.dist-info → sgtlib-3.4.1.dist-info}/WHEEL +0 -0
- {sgtlib-3.4.0.dist-info → sgtlib-3.4.1.dist-info}/entry_points.txt +0 -0
- {sgtlib-3.4.0.dist-info → sgtlib-3.4.1.dist-info}/licenses/LICENSE +0 -0
- {sgtlib-3.4.0.dist-info → sgtlib-3.4.1.dist-info}/top_level.txt +0 -0
StructuralGT/__init__.py
CHANGED
@@ -24,7 +24,7 @@ of the GNU General Public License along with this program. If not, see <https:/
|
|
24
24
|
|
25
25
|
|
26
26
|
# Project Details
|
27
|
-
__version__ = "3.4.
|
27
|
+
__version__ = "3.4.1"
|
28
28
|
__install_version__ = "3.3.9"
|
29
29
|
__title__ = f"StructuralGT (v{__version__})"
|
30
30
|
__author__ = "Dickson Owuor"
|
@@ -15,6 +15,7 @@ import multiprocessing
|
|
15
15
|
import numpy as np
|
16
16
|
import scipy as sp
|
17
17
|
import pandas as pd
|
18
|
+
import igraph as ig
|
18
19
|
import networkx as nx
|
19
20
|
import matplotlib.table as tbl
|
20
21
|
import matplotlib.pyplot as plt
|
@@ -67,6 +68,15 @@ except cp.cuda.runtime.CUDARuntimeError:
|
|
67
68
|
"""
|
68
69
|
|
69
70
|
|
71
|
+
def _worker_vertex_connectivity(ig_graph_obj, i, j):
|
72
|
+
try:
|
73
|
+
lnc = ig_graph_obj.vertex_connectivity(source=i, target=j, neighbors="negative")
|
74
|
+
return lnc if lnc != -1 else None
|
75
|
+
except Exception as err:
|
76
|
+
logging.exception("Computing iGraph ANC Error: %s", err, extra={'user': 'SGT Logs'})
|
77
|
+
return None
|
78
|
+
|
79
|
+
|
70
80
|
class GraphAnalyzer(ProgressUpdate):
|
71
81
|
"""
|
72
82
|
A class that computes all the user-selected graph theory metrics and writes the results in a PDF file.
|
@@ -247,22 +257,7 @@ class GraphAnalyzer(ProgressUpdate):
|
|
247
257
|
self.update_status([-1, "Task aborted."])
|
248
258
|
return None
|
249
259
|
self.update_status([15, "Computing node connectivity..."])
|
250
|
-
|
251
|
-
# use_igraph = opt_gtc["compute_lang == 'C'"]["value"]
|
252
|
-
if self.use_igraph:
|
253
|
-
# use iGraph Lib in C
|
254
|
-
self.update_status([15, "Using iGraph library..."])
|
255
|
-
avg_node_con = self.igraph_average_node_connectivity(graph)
|
256
|
-
else:
|
257
|
-
# Use NetworkX Lib in Python
|
258
|
-
self.update_status([15, "Using NetworkX library..."])
|
259
|
-
if self.allow_mp: # Multi-processing
|
260
|
-
avg_node_con = self.average_node_connectivity(graph)
|
261
|
-
else:
|
262
|
-
avg_node_con = average_node_connectivity(graph)
|
263
|
-
avg_node_con = round(avg_node_con, 5)
|
264
|
-
else:
|
265
|
-
avg_node_con = np.nan
|
260
|
+
avg_node_con = self.compute_average_node_connectivity(graph, connected_graph)
|
266
261
|
data_dict["parameter"].append("Average node connectivity")
|
267
262
|
data_dict["value"].append(avg_node_con)
|
268
263
|
|
@@ -586,88 +581,147 @@ class GraphAnalyzer(ProgressUpdate):
|
|
586
581
|
|
587
582
|
return ohms_dict, res
|
588
583
|
|
589
|
-
def
|
584
|
+
def compute_average_node_connectivity(self, nx_graph: nx.Graph, is_graph_connected=False):
|
590
585
|
r"""Returns the average connectivity of a graph G.
|
591
586
|
|
592
587
|
The average connectivity `\bar{\kappa}` of a graph G is the average
|
593
588
|
of local node connectivity over all pairs of the nx_graph nodes.
|
594
589
|
|
595
|
-
https://networkx.org/documentation/stable/_modules/networkx/algorithms/connectivity/connectivity.html#average_node_connectivity
|
596
|
-
|
597
|
-
Parameters
|
598
|
-
----------
|
599
590
|
:param nx_graph: NetworkX graph object.
|
600
|
-
:param
|
601
|
-
A function for computing the maximum flow between a pair of nodes.
|
602
|
-
The function has to accept at least three parameters: a Digraph,
|
603
|
-
a source node, and a target node. And return a residual network
|
604
|
-
that follows NetworkX conventions (see: meth:`maximum_flow` for
|
605
|
-
details). If flow_func is None, the default maximum flow function
|
606
|
-
(:meth:`edmonds_karp`) is used. See :meth:`local_node_connectivity`
|
607
|
-
for details. The choice of the default function may change from
|
608
|
-
version to version and should not be relied on. Default value: None.
|
609
|
-
|
610
|
-
Returns
|
611
|
-
-------
|
612
|
-
K : float
|
613
|
-
Average node connectivity
|
614
|
-
|
615
|
-
References
|
616
|
-
----------
|
617
|
-
[1] Beineke, L., O. Oellermann, and r_network. Pippert (2002). The average
|
618
|
-
connectivity of a graph. Discrete mathematics 252(1-3), 31-45.
|
619
|
-
https://www.sciencedirect.com/science/article/pii/S0012365X01001807
|
620
|
-
|
591
|
+
:param is_graph_connected: Boolean
|
621
592
|
"""
|
622
593
|
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
594
|
+
def nx_average_node_connectivity(flow_func=None):
|
595
|
+
r"""Returns the average connectivity of a graph G.
|
596
|
+
|
597
|
+
The average connectivity `\bar{\kappa}` of a graph G is the average
|
598
|
+
of local node connectivity over all pairs of the nx_graph nodes.
|
599
|
+
|
600
|
+
https://networkx.org/documentation/stable/_modules/networkx/algorithms/connectivity/connectivity.html#average_node_connectivity
|
601
|
+
|
602
|
+
Parameters
|
603
|
+
----------
|
604
|
+
:param flow_func : Function
|
605
|
+
A function for computing the maximum flow between a pair of nodes.
|
606
|
+
The function has to accept at least three parameters: a Digraph,
|
607
|
+
a source node, and a target node. And return a residual network
|
608
|
+
that follows NetworkX conventions (see: meth:`maximum_flow` for
|
609
|
+
details). If flow_func is None, the default maximum flow function
|
610
|
+
(:meth:`edmonds_karp`) is used. See :meth:`local_node_connectivity`
|
611
|
+
for details. The choice of the default function may change from
|
612
|
+
version to version and should not be relied on. Default value: None.
|
613
|
+
|
614
|
+
Returns
|
615
|
+
-------
|
616
|
+
K : float
|
617
|
+
Average node connectivity
|
618
|
+
|
619
|
+
References
|
620
|
+
----------
|
621
|
+
[1] Beineke, L., O. Oellermann, and r_network. Pippert (2002). The average
|
622
|
+
connectivity of a graph. Discrete mathematics 252(1-3), 31-45.
|
623
|
+
https://www.sciencedirect.com/science/article/pii/S0012365X01001807
|
648
624
|
|
649
|
-
|
650
|
-
of local node connectivity over all pairs of the Graph (G) nodes.
|
625
|
+
"""
|
651
626
|
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
627
|
+
if nx_graph.is_directed():
|
628
|
+
iter_func = itertools.permutations
|
629
|
+
else:
|
630
|
+
iter_func = itertools.combinations
|
631
|
+
|
632
|
+
# Reuse the auxiliary digraph and the residual network
|
633
|
+
a_digraph = nx.algorithms.connectivity.build_auxiliary_node_connectivity(nx_graph)
|
634
|
+
r_network = nx.algorithms.flow.build_residual_network(a_digraph, "capacity")
|
635
|
+
# kwargs = {"flow_func": flow_func, "auxiliary": a_digraph, "residual": r_network}
|
636
|
+
|
637
|
+
total, count = 0, 0
|
638
|
+
with multiprocessing.Pool() as pool:
|
639
|
+
items = [(nx_graph, u, v, flow_func, a_digraph, r_network) for u, v in iter_func(nx_graph, 2)]
|
640
|
+
async_result = pool.starmap_async(nx.algorithms.connectivity.local_node_connectivity, items)
|
641
|
+
for n in async_result.get():
|
642
|
+
total += n
|
643
|
+
count += 1
|
644
|
+
if self.abort:
|
645
|
+
self.update_status([-1, "Task aborted."])
|
646
|
+
pool.terminate()
|
647
|
+
pool.join()
|
648
|
+
return 0
|
649
|
+
if n is not None:
|
650
|
+
total += n
|
651
|
+
count += 1
|
652
|
+
anc = total / count if count > 0 else 0
|
653
|
+
return anc
|
654
|
+
|
655
|
+
def igraph_average_node_connectivity():
|
656
|
+
r"""
|
657
|
+
Returns the average connectivity of a graph G.
|
658
|
+
|
659
|
+
The average connectivity of a graph G is the average
|
660
|
+
of local node connectivity over all pairs of the Graph (G) nodes.
|
661
|
+
"""
|
657
662
|
|
658
|
-
|
659
|
-
|
660
|
-
|
663
|
+
ig_graph = ig.Graph.from_networkx(nx_graph)
|
664
|
+
num_nodes = ig_graph.vcount()
|
665
|
+
total, count = 0, 0
|
666
|
+
with multiprocessing.Pool() as pool:
|
667
|
+
# Prepare all node pairs (i < j)
|
668
|
+
items = [(ig_graph, i, j) for i in range(num_nodes) for j in range(i + 1, num_nodes)]
|
669
|
+
async_result = pool.starmap_async(_worker_vertex_connectivity, items)
|
670
|
+
for n in async_result.get():
|
671
|
+
if self.abort:
|
672
|
+
self.update_status([-1, "Task aborted."])
|
673
|
+
pool.terminate()
|
674
|
+
pool.join()
|
675
|
+
return 0
|
676
|
+
if n is not None:
|
677
|
+
total += n
|
678
|
+
count += 1
|
679
|
+
anc = total / count if count > 0 else 0
|
680
|
+
return anc
|
681
|
+
|
682
|
+
def igraph_clang_average_node_connectivity():
|
683
|
+
r"""Returns the average connectivity of a graph G.
|
684
|
+
|
685
|
+
The average connectivity of a graph G is the average
|
686
|
+
of local node connectivity over all pairs of the Graph (G) nodes.
|
661
687
|
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
nx.
|
667
|
-
anc =
|
668
|
-
|
669
|
-
|
670
|
-
|
688
|
+
"""
|
689
|
+
from .c_lang import sgt_c_module as sgt
|
690
|
+
|
691
|
+
cpu_count = get_num_cores()
|
692
|
+
num_threads = cpu_count if nx.number_of_nodes(nx_graph) < 2000 else cpu_count * 2
|
693
|
+
anc = 0
|
694
|
+
|
695
|
+
try:
|
696
|
+
filename, output_location = self.ntwk_p.get_filenames()
|
697
|
+
g_filename = filename + "_graph.txt"
|
698
|
+
graph_file = os.path.join(output_location, g_filename)
|
699
|
+
nx.write_edgelist(nx_graph, graph_file, data=False)
|
700
|
+
anc = sgt.compute_anc(graph_file, num_threads, self.allow_mp)
|
701
|
+
except Exception as err:
|
702
|
+
logging.exception("Computing ANC Error: %s", err, extra={'user': 'SGT Logs'})
|
703
|
+
return anc
|
704
|
+
|
705
|
+
if is_graph_connected:
|
706
|
+
# use_igraph = opt_gtc["compute_lang == 'C'"]["value"]
|
707
|
+
if self.use_igraph:
|
708
|
+
# use iGraph Lib in C
|
709
|
+
self.update_status([15, "Using iGraph library..."])
|
710
|
+
try:
|
711
|
+
avg_node_con = igraph_clang_average_node_connectivity()
|
712
|
+
except ImportError:
|
713
|
+
avg_node_con = igraph_average_node_connectivity()
|
714
|
+
else:
|
715
|
+
# Use NetworkX Lib in Python
|
716
|
+
self.update_status([15, "Using NetworkX library..."])
|
717
|
+
if self.allow_mp: # Multi-processing
|
718
|
+
avg_node_con = nx_average_node_connectivity()
|
719
|
+
else:
|
720
|
+
avg_node_con = average_node_connectivity(nx_graph)
|
721
|
+
avg_node_con = round(avg_node_con, 5)
|
722
|
+
else:
|
723
|
+
avg_node_con = np.nan
|
724
|
+
return avg_node_con
|
671
725
|
|
672
726
|
def compute_graph_conductance(self, graph_obj):
|
673
727
|
"""
|
@@ -5,9 +5,9 @@ Builds a graph network from nanoscale microscopy images.
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
import os
|
8
|
-
import igraph
|
9
8
|
import itertools
|
10
9
|
import numpy as np
|
10
|
+
import igraph as ig
|
11
11
|
import networkx as nx
|
12
12
|
import matplotlib.pyplot as plt
|
13
13
|
from PIL import Image, ImageQt
|
@@ -43,7 +43,7 @@ class FiberNetworkBuilder(ProgressUpdate):
|
|
43
43
|
self.img_ntwk: MatLike | None = None
|
44
44
|
self.nx_giant_graph: nx.Graph | None = None
|
45
45
|
self.nx_graph: nx.Graph | None = None
|
46
|
-
self.ig_graph:
|
46
|
+
self.ig_graph: ig.Graph | None = None
|
47
47
|
self.gsd_file: str | None = None
|
48
48
|
self.skel_obj: GraphSkeleton | None = None
|
49
49
|
|
@@ -149,7 +149,7 @@ class FiberNetworkBuilder(ProgressUpdate):
|
|
149
149
|
nx_graph[s][e]['weight'] = wt
|
150
150
|
# print(f"{nx_graph[s][e]}\n")
|
151
151
|
self.nx_graph = nx_graph
|
152
|
-
self.ig_graph =
|
152
|
+
self.ig_graph = ig.Graph.from_networkx(nx_graph)
|
153
153
|
return True
|
154
154
|
|
155
155
|
def plot_graph_network(self, image_arr: MatLike, giant_only: bool = False, plot_nodes: bool = False, a4_size: bool = False):
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: sgtlib
|
3
|
-
Version: 3.4.
|
3
|
+
Version: 3.4.1
|
4
4
|
Summary: A software tool for graph theory analysis of microscopy images.
|
5
5
|
Author-email: Dickson Owuor <owuordickson@gmail.com>, "Drew A. Vecchio" <vecdrew@umich.edu>, Kody Whisnant <kgwhis@umich.edu>, Alain Kadar <alaink@umich.edu>, Xiong Ye Xiao <xiongyex@usc.edu>, Nicholas Kotov <kotov@umich.edu>
|
6
6
|
Maintainer-email: Dickson Owuor <owuordickson@gmail.com>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
StructuralGT/__init__.py,sha256=
|
1
|
+
StructuralGT/__init__.py,sha256=UoEP1e5QcjHqzVbt7cUCTL1rRksz3Qsze5OTmSAzeZo,1254
|
2
2
|
StructuralGT/entrypoints.py,sha256=s2upsOVsy9zsoorxiZXaZKiLw7fUOQwHjwup3C089Hs,1413
|
3
3
|
StructuralGT/modules.py,sha256=CYudBMwP70cRFWj_Dppr_Kdc08V_-9wWKVd48bEHkS0,743
|
4
4
|
StructuralGT/apps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -50,15 +50,13 @@ StructuralGT/apps/sgt_qml/widgets/RescaleControlWidget.qml,sha256=qb6fXok5C1HJjb
|
|
50
50
|
StructuralGT/apps/sgt_qml/widgets/RibbonWidget.qml,sha256=POaPwXh7vE4UwU82x-80BuI2625FLWbmJQsZliy618w,13990
|
51
51
|
StructuralGT/apps/sgt_qml/widgets/StatusBarWidget.qml,sha256=YRTSg_4aYA3FO69wT1NnX0Ri_qRx3AHhVrS1n3pVwd4,5969
|
52
52
|
StructuralGT/compute/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
53
|
-
StructuralGT/compute/graph_analyzer.py,sha256=
|
54
|
-
StructuralGT/compute/c_lang/sgt_base.c,sha256=VFgwVDALjWl_zAP5NqNwG5pLv6no91_93RYPziHT2hY,1953
|
55
|
-
StructuralGT/compute/c_lang/sgtmodule.c,sha256=85VhQCxNow49yslayaCnCFwseS6vXVvJ77RjypkHG1o,5492
|
53
|
+
StructuralGT/compute/graph_analyzer.py,sha256=JeUlfeC0phR5JqAqDXAhrUq8amDXNekcIYfvbIUl0q8,72274
|
56
54
|
StructuralGT/compute/c_lang/include/sgt_base.h,sha256=jkCpNy_01bSKk_ay6_1TilNhribMmw-p8r8FRhamstM,530
|
57
55
|
StructuralGT/imaging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
58
56
|
StructuralGT/imaging/base_image.py,sha256=Cc4xeVOxpID6SukVolYtD6OiEQ4tsUGQ4mYjE3QF_2E,16555
|
59
57
|
StructuralGT/imaging/image_processor.py,sha256=dElOT51scHbEwsRpfnUUbLQ68twiGAhALgxcqTJBzzM,32878
|
60
58
|
StructuralGT/networks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
61
|
-
StructuralGT/networks/fiber_network.py,sha256=
|
59
|
+
StructuralGT/networks/fiber_network.py,sha256=dr-JCfAGi52Lkcn_L4bT1939hXwg-Jp9-90VHMv324I,20058
|
62
60
|
StructuralGT/networks/graph_skeleton.py,sha256=_uWDvoHG4Pu-iKIRbIx0FyYqkiQZDk73md9-bOnWswQ,19246
|
63
61
|
StructuralGT/networks/sknw_mod.py,sha256=rBLdBmiawj1eURGKreuUJjKeEg5v76WNHkNxVEZhQWY,5542
|
64
62
|
StructuralGT/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -66,9 +64,9 @@ StructuralGT/utils/config_loader.py,sha256=8px8iGOFCGz8qIZCfyGuAFfvvaVdOjogf9PqS
|
|
66
64
|
StructuralGT/utils/configs.ini,sha256=sKPsAd15_YubgGhLMVuse1JRuU7S6bFYjLbzkuoD5JI,2326
|
67
65
|
StructuralGT/utils/progress_update.py,sha256=9X_9mGLgTMF5dDSTNKpELQcmFv8r1wz6YZQCqy4tCl8,1621
|
68
66
|
StructuralGT/utils/sgt_utils.py,sha256=0vg7I4P6PIao_H8-KYgkCJ6TM9eESW-RwGZB4sGgCI4,9109
|
69
|
-
sgtlib-3.4.
|
70
|
-
sgtlib-3.4.
|
71
|
-
sgtlib-3.4.
|
72
|
-
sgtlib-3.4.
|
73
|
-
sgtlib-3.4.
|
74
|
-
sgtlib-3.4.
|
67
|
+
sgtlib-3.4.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
68
|
+
sgtlib-3.4.1.dist-info/METADATA,sha256=VPPMOWhLdj4PB4XvU5Gj5CN_-UJTQx-NJZw0Gv_UIGk,45278
|
69
|
+
sgtlib-3.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
70
|
+
sgtlib-3.4.1.dist-info/entry_points.txt,sha256=zY3v_U9Qi4L965BPrURXn84yF_TxdKDZI3VcTUbTh0M,120
|
71
|
+
sgtlib-3.4.1.dist-info/top_level.txt,sha256=daVVcqfvgGeWXFnHArFOFbRmtWxL93fxmZjF19Sg69I,13
|
72
|
+
sgtlib-3.4.1.dist-info/RECORD,,
|
@@ -1,61 +0,0 @@
|
|
1
|
-
//#define _POSIX_C_SOURCE 200809L // Linux
|
2
|
-
#include <stdio.h>
|
3
|
-
#include <stdarg.h>
|
4
|
-
#include <string.h>
|
5
|
-
//#include "sgt_base.h"
|
6
|
-
#include "include/sgt_base.h"
|
7
|
-
|
8
|
-
// Function to compute Local Node Connectivity
|
9
|
-
void* compute_lnc(void *arg) {
|
10
|
-
ThreadArgsLNC *args = (ThreadArgsLNC*)arg;
|
11
|
-
igraph_integer_t lnc;
|
12
|
-
|
13
|
-
igraph_st_vertex_connectivity(args->graph, &lnc, args->i, args->j, IGRAPH_VCONN_NEI_NEGATIVE);
|
14
|
-
|
15
|
-
// Update shared data under mutex lock
|
16
|
-
pthread_mutex_lock(args->mutex);
|
17
|
-
if (lnc != -1){
|
18
|
-
*(args->total_nc) += lnc;
|
19
|
-
*(args->total_count) += 1;
|
20
|
-
//printf("got %d\n", lnc);
|
21
|
-
//printf("NC:%d Count:%d \n", *(args->total_nc), *(args->total_count));
|
22
|
-
}
|
23
|
-
pthread_mutex_unlock(args->mutex);
|
24
|
-
|
25
|
-
pthread_exit(NULL);
|
26
|
-
}
|
27
|
-
|
28
|
-
// Function to convert string representation of adjacency matrix to 2D matrix
|
29
|
-
igraph_matrix_t* str_to_matrix(char* str_adj_mat, igraph_integer_t num_vertices) {
|
30
|
-
// Allocate memory for the matrix
|
31
|
-
igraph_matrix_t* mat = (igraph_matrix_t*)malloc(sizeof(igraph_matrix_t));
|
32
|
-
if (!mat) {
|
33
|
-
fprintf(stderr, "Failed to allocate memory for matrix structure\n");
|
34
|
-
exit(EXIT_FAILURE);
|
35
|
-
}
|
36
|
-
igraph_matrix_init(mat, num_vertices, num_vertices);
|
37
|
-
|
38
|
-
// Parse string and populate matrix
|
39
|
-
char* token;
|
40
|
-
char* nextToken;
|
41
|
-
const char delimiters[] = ",";
|
42
|
-
|
43
|
-
// Get the first token
|
44
|
-
// strtok_r - MacOs
|
45
|
-
//token = strtok_r(str_adj_mat, delimiters, &nextToken);
|
46
|
-
token = strtok_s(str_adj_mat, delimiters, &nextToken);
|
47
|
-
|
48
|
-
// Iterate through the remaining tokens
|
49
|
-
for (igraph_integer_t i = 0; i < num_vertices; i++) {
|
50
|
-
for (igraph_integer_t j = 0; j < num_vertices; j++) {
|
51
|
-
MATRIX(*mat, i, j) = atoi(token);
|
52
|
-
// Get the next token
|
53
|
-
// strtok_r - MacOs
|
54
|
-
//token = strtok_r(NULL, delimiters, &nextToken);
|
55
|
-
token = strtok_s(NULL, delimiters, &nextToken);
|
56
|
-
}
|
57
|
-
}
|
58
|
-
|
59
|
-
return mat;
|
60
|
-
}
|
61
|
-
|
@@ -1,183 +0,0 @@
|
|
1
|
-
#include <stdlib.h>
|
2
|
-
#include <stdio.h>
|
3
|
-
#include <stdarg.h>
|
4
|
-
|
5
|
-
#define PY_SSIZE_T_CLEAN
|
6
|
-
#include <Python.h>
|
7
|
-
//#include "sgt_base.h"
|
8
|
-
#include "include/sgt_base.h"
|
9
|
-
|
10
|
-
|
11
|
-
static PyObject *ErrorObject;
|
12
|
-
static PyObject *
|
13
|
-
compute_anc(PyObject *self, PyObject *args)
|
14
|
-
{
|
15
|
-
int num_cpus;
|
16
|
-
int allow_mp;
|
17
|
-
char *f_name;
|
18
|
-
|
19
|
-
// Consider passing graph as String
|
20
|
-
if (!PyArg_ParseTuple(args, "sii:compute_anc", &f_name, &num_cpus, &allow_mp)){
|
21
|
-
return NULL;
|
22
|
-
}
|
23
|
-
|
24
|
-
/*if ( f_name == ''){
|
25
|
-
PyErr_SetString(ErrorObject, "Unable to retrieve graph.");
|
26
|
-
return NULL;
|
27
|
-
}*/
|
28
|
-
|
29
|
-
if ( num_cpus <= 0 || allow_mp < 0){
|
30
|
-
PyErr_SetString(ErrorObject, "Invalid CPU parameters.");
|
31
|
-
return NULL;
|
32
|
-
}
|
33
|
-
|
34
|
-
// Declare required variables
|
35
|
-
FILE *file;
|
36
|
-
|
37
|
-
igraph_t graph;
|
38
|
-
igraph_integer_t num_nodes;
|
39
|
-
igraph_integer_t count_nc = 0;
|
40
|
-
igraph_integer_t sum_nc = 0;
|
41
|
-
igraph_real_t anc = 0;
|
42
|
-
|
43
|
-
// Open the file containing the serialized graph
|
44
|
-
file = fopen(f_name, "r");
|
45
|
-
// Read the graph from the file
|
46
|
-
igraph_read_graph_edgelist(&graph, file, 0, IGRAPH_UNDIRECTED);
|
47
|
-
fclose(file);
|
48
|
-
// printf("Nodes: %d\nEdges: %d\n", (int)igraph_vcount(&graph), (int)igraph_ecount(&graph));
|
49
|
-
|
50
|
-
num_nodes = igraph_vcount(&graph);
|
51
|
-
if (allow_mp == 0){
|
52
|
-
printf("Using single processing\n");
|
53
|
-
igraph_integer_t lnc;
|
54
|
-
for (igraph_integer_t i=0; i<num_nodes; i++) {
|
55
|
-
for (igraph_integer_t j=i+1; j<num_nodes; j++){
|
56
|
-
igraph_st_vertex_connectivity(&graph, &lnc, i, j, IGRAPH_VCONN_NEI_NEGATIVE);
|
57
|
-
if (lnc == -1) { continue; }
|
58
|
-
sum_nc += lnc;
|
59
|
-
count_nc += 1;
|
60
|
-
}
|
61
|
-
}
|
62
|
-
|
63
|
-
}
|
64
|
-
else {
|
65
|
-
printf("Using multiprocessing\n");
|
66
|
-
// Initialize mutex
|
67
|
-
pthread_mutex_t mutex;
|
68
|
-
pthread_mutex_init(&mutex, NULL);
|
69
|
-
|
70
|
-
// Create thread pool
|
71
|
-
const int MAX_THREAD_COUNT = num_cpus;
|
72
|
-
|
73
|
-
// Allocate memory for threads and args arrays
|
74
|
-
pthread_t *threads = (pthread_t *)malloc(MAX_THREAD_COUNT * sizeof(pthread_t));
|
75
|
-
ThreadArgsLNC *args = (ThreadArgsLNC *)malloc(MAX_THREAD_COUNT * sizeof(ThreadArgsLNC));
|
76
|
-
|
77
|
-
if (threads == NULL || args == NULL) {
|
78
|
-
PyErr_SetString(ErrorObject, "Memory allocation failed\n");
|
79
|
-
return NULL;
|
80
|
-
}
|
81
|
-
|
82
|
-
// Initialize thread pool
|
83
|
-
for (int i = 0; i < MAX_THREAD_COUNT; i++) {
|
84
|
-
args[i].graph = &graph;
|
85
|
-
args[i].mutex = &mutex;
|
86
|
-
args[i].total_nc = &sum_nc;
|
87
|
-
args[i].total_count = &count_nc;
|
88
|
-
}
|
89
|
-
|
90
|
-
// Create threads for computing LNC
|
91
|
-
int idx = 0;
|
92
|
-
int thread_count = 0;
|
93
|
-
for (igraph_integer_t i = 0; i < num_nodes; i++) {
|
94
|
-
for (igraph_integer_t j = i + 1; j < num_nodes; j++) {
|
95
|
-
idx = (int)(thread_count % MAX_THREAD_COUNT);
|
96
|
-
if (thread_count >= MAX_THREAD_COUNT) {
|
97
|
-
// Wait for a thread to finish before starting a new one
|
98
|
-
pthread_join(threads[idx], NULL);
|
99
|
-
thread_count++;
|
100
|
-
}
|
101
|
-
args[idx].i = (int)i;
|
102
|
-
args[idx].j = (int)j;
|
103
|
-
pthread_create(&threads[idx], NULL, compute_lnc, &args[idx]);
|
104
|
-
thread_count++;
|
105
|
-
// printf("thread %d running...\n", (idx));
|
106
|
-
}
|
107
|
-
}
|
108
|
-
|
109
|
-
// Join threads
|
110
|
-
for (int i = 0; i < MAX_THREAD_COUNT && i < thread_count; i++) {
|
111
|
-
pthread_join(threads[i], NULL);
|
112
|
-
}
|
113
|
-
|
114
|
-
// Destroy mutex
|
115
|
-
pthread_mutex_destroy(&mutex);
|
116
|
-
// Free dynamically allocated memory
|
117
|
-
free(threads);
|
118
|
-
free(args);
|
119
|
-
}
|
120
|
-
|
121
|
-
// Compute ANC
|
122
|
-
anc = (float) sum_nc / count_nc;
|
123
|
-
|
124
|
-
// Destroy graph
|
125
|
-
igraph_destroy(&graph);
|
126
|
-
|
127
|
-
return PyFloat_FromDouble((double) anc);
|
128
|
-
|
129
|
-
}
|
130
|
-
static char compute_anc_doc[] =
|
131
|
-
"A C method that uses iGraph library to compute average node connectivity of a graph.\n"
|
132
|
-
"\n"
|
133
|
-
"Args:\n"
|
134
|
-
" file (string): CSV file with edge list of graph A.\n"
|
135
|
-
" cpus (int): number of available CPUs.\n"
|
136
|
-
" mp (int): allow multi-processing (0: No, 1: Yes).\n"
|
137
|
-
"\n"
|
138
|
-
"Returns:\n"
|
139
|
-
" ANC (float): Average Node Connectivity as a float value.\n";
|
140
|
-
|
141
|
-
|
142
|
-
static char sgt_doc[] =
|
143
|
-
"A C language module leveraging the iGraph library to compute Graph Theory (GT) metrics,"
|
144
|
-
"enhanced with multi-threading capabilities for accelerated computation.\n";
|
145
|
-
|
146
|
-
/* Method Table: ist of functions defined in the module */
|
147
|
-
static PyMethodDef sgt_methods[] = {
|
148
|
-
{"compute_anc", compute_anc, METH_VARARGS, compute_anc_doc },
|
149
|
-
//{"compute_lnc", compute_lnc, METH_VARARGS, "Compute local node connectivity." },
|
150
|
-
{NULL, NULL, 0, NULL} /* Sentinel */
|
151
|
-
};
|
152
|
-
|
153
|
-
/* Create module */
|
154
|
-
static struct PyModuleDef sgt_c_module = {
|
155
|
-
PyModuleDef_HEAD_INIT,
|
156
|
-
"sgt_c_module", /* name of module */
|
157
|
-
sgt_doc, /* module documentation, may be NULL */
|
158
|
-
-1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */
|
159
|
-
sgt_methods
|
160
|
-
};
|
161
|
-
|
162
|
-
/* Initialization function for the module */
|
163
|
-
PyMODINIT_FUNC
|
164
|
-
PyInit_sgt_c_module(void)
|
165
|
-
{
|
166
|
-
PyObject *m;
|
167
|
-
|
168
|
-
m = PyModule_Create(&sgt_c_module);
|
169
|
-
if (m == NULL)
|
170
|
-
return NULL;
|
171
|
-
|
172
|
-
ErrorObject = PyErr_NewException("sgt_c_module.error", NULL, NULL);
|
173
|
-
Py_XINCREF(ErrorObject);
|
174
|
-
if (PyModule_AddObject(m, "error", ErrorObject) < 0) {
|
175
|
-
Py_XDECREF(ErrorObject);
|
176
|
-
Py_CLEAR(ErrorObject);
|
177
|
-
Py_DECREF(m);
|
178
|
-
return NULL;
|
179
|
-
}
|
180
|
-
|
181
|
-
return m;
|
182
|
-
}
|
183
|
-
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|