Skip to content

Commit ee93818

Browse files
authored
New Engine: Barabási-Albert (#197)
* add : barabasi albert engine file added. * add : stress test for BA engine added. * log : changes logged. * fix : `edge_gen` docstring fixed. * update : readme updated. * update : __main__.py updated with ba_engine. * update : functions file modules updated. * revert : documentation updated. * add : menu updated. * update : function tests updated. * add : citation to the main paper added. * change : `m_` parameter changed to `k`. * add : `k` added to the barabasi_albert engine logger. * add : tests added.
1 parent fda30e8 commit ee93818

File tree

10 files changed

+548
-2
lines changed

10 files changed

+548
-2
lines changed

.github/workflows/test.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,6 @@ jobs:
7575
- name: cProfile - Stochastic Block Model Engine
7676
run: |
7777
python -m cProfile -s cumtime otherfile/profiles/sbm_profile.py
78+
- name: cProfile - Barabasi-Albert Engine
79+
run: |
80+
python -m cProfile -s cumtime otherfile/profiles/ba_profile.py

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
### Added
9+
- `pyrgg.engines.barabasi_albert` module
810
### Changed
911
- CLI messages for stochastic block model updated
1012
- `README.md` modified

README.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,23 @@ PyRGG will likely run on a modern dual core PC. Typical configuration is:
225225
</tr>
226226
</table>
227227

228+
### Barabási-Albert
229+
230+
<table>
231+
<tr>
232+
<th>Parameter</th>
233+
<th>Description</th>
234+
</tr>
235+
<tr>
236+
<td align="center">Vertices Number (n)</td>
237+
<td align="center">The total number of vertices in the graph</td>
238+
</tr>
239+
<tr>
240+
<td align="center">Attaching Edge Number (k)</td>
241+
<td align="center">The number of edges to attach to a new node</td>
242+
</tr>
243+
</table>
244+
228245
## Supported Formats
229246

230247
### DIMACS
@@ -670,8 +687,9 @@ If you use PyRGG in your research, we would appreciate citations to the followin
670687
<blockquote>14- Gilbert, Edgar N. "Random graphs." The Annals of Mathematical Statistics 30.4 (1959): 1141-1144.</blockquote>
671688

672689
<blockquote>15- Erdős, Paul, and Alfréd Rényi. "On the strength of connectedness of a random graph." Acta Mathematica Hungarica 12.1 (1961): 261-267.</blockquote>
673-
674-
690+
691+
<blockquote>16- Barabási, Albert-László, and Réka Albert. "Emergence of scaling in random networks." science 286.5439 (1999): 509-512.</blockquote>
692+
675693
## Show Your Support
676694
677695
<h3>Star This Repo</h3>

otherfile/profiles/ba_profile.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# -*- coding: utf-8 -*-
2+
"""Profile file."""
3+
from pyrgg import *
4+
import pyrgg.engines.barabasi_albert as ba_engine
5+
import random
6+
7+
os.environ["PYRGG_TEST_MODE"] = "1"
8+
random.seed(400)
9+
10+
ba_engine.gen_using(
11+
dimacs_maker,
12+
'profile',
13+
{
14+
'vertices': 10000,
15+
'attaching_edge_number': 500,
16+
}
17+
)

pyrgg/__main__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import pyrgg.engines.erdos_reyni_gilbert as erg_engine
1313
import pyrgg.engines.erdos_reyni as er_engine
1414
import pyrgg.engines.stochastic_block_model as sbm_engine
15+
import pyrgg.engines.barabasi_albert as ba_engine
1516

1617
GENERATOR_MENU = {
1718
1: dimacs_maker,
@@ -37,6 +38,7 @@
3738
2: erg_engine,
3839
3: er_engine,
3940
4: sbm_engine,
41+
5: ba_engine,
4042
}
4143

4244

pyrgg/engines/barabasi_albert.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# -*- coding: utf-8 -*-
2+
"""Barabási-Albert Engine module."""
3+
from random import sample
4+
from pyrgg.params import ENGINE_MENU, PYRGG_LOGGER_ERROR_MESSAGE
5+
from pyrgg.functions import save_log
6+
7+
8+
def edge_gen(n, k):
9+
"""
10+
Generate each vertex connection number.
11+
12+
:param n: number of vertices
13+
:type n: int
14+
:param k: number of edges to attach to a new node in each iteration, m in the Barabási-Albert model
15+
:type k: int
16+
:return: list of dicts
17+
"""
18+
# We assume m0 is the same as k, similar to the original paper examples
19+
edge_dic = {i: [] for i in range(1, k + 1)}
20+
weight_dict = {i: [] for i in range(1, k + 1)}
21+
node_from = k + 1
22+
node_to = list(range(1, k + 1))
23+
nodes_history = []
24+
while node_from <= n:
25+
edge_dic[node_from] = [i for i in node_to]
26+
weight_dict[node_from] = [1] * k
27+
nodes_history.extend(node_to)
28+
nodes_history.extend([node_from] * k)
29+
node_to = sample(nodes_history, k)
30+
node_from += 1
31+
32+
return [edge_dic, weight_dict, (n - k) * k]
33+
34+
35+
def gen_using(
36+
gen_function,
37+
file_name,
38+
input_dict):
39+
"""
40+
Generate graph using given function based on Barabási-Albert model.
41+
42+
Refer to (https://en.wikipedia.org/wiki/Barab%C3%A1si%E2%80%93Albert_model).
43+
We assume that m0 is the same as k and k is the number of edges to attach to a new node.
44+
45+
:param gen_function: generation function
46+
:type gen_function: function object
47+
:param file_name: file name
48+
:type file_name: str
49+
:param input_dict: input data
50+
:type input_dict: dict
51+
:return: number of edges as int
52+
"""
53+
edge_dic, weight_dic, edge_number = edge_gen(
54+
input_dict['vertices'],
55+
input_dict['attaching_edge_number'])
56+
gen_function(
57+
edge_dic,
58+
weight_dic,
59+
{
60+
"file_name": file_name,
61+
"vertices_number": input_dict['vertices'],
62+
"edge_number": edge_number,
63+
"weighted": False,
64+
"max_weight": 1,
65+
"min_weight": 1,
66+
"direct": False,
67+
"multigraph": True,
68+
})
69+
return edge_number
70+
71+
72+
def logger(file, file_name, elapsed_time, input_dict):
73+
"""
74+
Save generated graph logs for Barabási-Albert engine.
75+
76+
:param file: file to write log into
77+
:type file: file object
78+
:param file_name: file name
79+
:type file_name: str
80+
:param elapsed_time: elapsed time
81+
:type elapsed_time: str
82+
:param input_dict: input data
83+
:type input_dict: dict
84+
:return: None
85+
"""
86+
try:
87+
text = "Vertices : {0}\n".format(input_dict['vertices'])
88+
text += "Edges to Attach to a New Node : {0}\n".format(input_dict['attaching_edge_number'])
89+
text += "Total Edges : {0}\n".format(input_dict['edge_number'])
90+
text += "Engine : {0} ({1})\n".format(input_dict['engine'], ENGINE_MENU[input_dict['engine']])
91+
save_log(file, file_name, elapsed_time, text)
92+
except Exception:
93+
print(PYRGG_LOGGER_ERROR_MESSAGE)

pyrgg/functions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ def handle_engine(string):
258258
"blocks": handle_natural_number,
259259
"inter_probability": handle_str_prob,
260260
"intra_probability": handle_str_prob,
261+
"attaching_edge_number": handle_natural_number,
261262
}
262263

263264

@@ -403,6 +404,7 @@ def get_input(input_func=input):
403404
"blocks": 1,
404405
"inter_probability": 0.75,
405406
"intra_probability": 0.25,
407+
"attaching_edge_number": 1,
406408
}
407409

408410
result_dict = _update_using_menu(result_dict, input_func)

pyrgg/params.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
2- Erdos-Renyi-Gilbert - G(n, p)
1616
3- Erdos-Renyi - G(n, m)
1717
4- Stochastic Block Model - G(C, P)
18+
5- Barabási-Albert - G(n, k)
1819
"""
1920
)],
2021
2: ["file_name", "- File Name (Not Empty) : "],
@@ -67,6 +68,7 @@
6768
2: "erg",
6869
3: "er",
6970
4: "sbm",
71+
5: "ba",
7072
}
7173

7274
ENGINE_MENU_INV = {v: k for k, v in ENGINE_MENU.items()}
@@ -105,11 +107,17 @@
105107
6: ["self_loop", "- No Self Loop[0] or Self Loop[1]"],
106108
}
107109

110+
BA_ENGINE_PARAMS = {
111+
1: ["vertices", "- Vertices Number (n >= 0) : "],
112+
2: ["attaching_edge_number", "- Number of Edges to Attach to a New Node (0 < k < n) : "],
113+
}
114+
108115
ENGINE_PARAM_MAP = {
109116
1: PYRGG_ENGINE_PARAMS,
110117
2: ERG_ENGINE_PARAMS,
111118
3: ER_ENGINE_PARAMS,
112119
4: SBM_ENGINE_PARAMS,
120+
5: BA_ENGINE_PARAMS,
113121
}
114122

115123
OUTPUT_FORMAT = {i: output_format[1:].upper()

0 commit comments

Comments
 (0)