Skip to content

Commit

Permalink
Erdos Reyni - G(n,m) engine added (#177)
Browse files Browse the repository at this point in the history
* fix : minor fix in profiling.

* fix : `gen_using` docstring for erdos_reyni_gilbert fixed.

* fix : bug in `weight_list` in ERG engine fixed.

* fix : erdos_reyni_gilbert tests fixed.

* add : Erdos-Reyni engine added.

* update : main updated.

* test : tests added.

* add : Erdos-Reyni profiling added.

* log : changes logged.

* fix : `math.comb` dependency removed.

* rename : `TOTAL_EDGE` -> `max_edge`.

* fix : code readability fixed. (Sepand's comment)
  • Loading branch information
sadrasabouri authored Oct 1, 2024
1 parent 2eecf42 commit de95cec
Show file tree
Hide file tree
Showing 12 changed files with 658 additions and 14 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,6 @@ jobs:
- name: cProfile - Erdos Reyni Gilbert Engine
run: |
python -m cProfile -s cumtime otherfile/profiles/erg_profile.py
- name: cProfile - Erdos Reyni Engine
run: |
python -m cProfile -s cumtime otherfile/profiles/er_profile.py
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- `pyrgg.engines.erdos_reyni` module
## [1.5] - 2024-09-16
### Added
- `feature_request.yml` template
Expand Down
18 changes: 18 additions & 0 deletions otherfile/profiles/er_profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
"""Profile file."""
from pyrgg import *
import pyrgg.engines.erdos_reyni as er_engine
import random

os.environ["PYRGG_TEST_MODE"] = "1"
random.seed(400)

er_engine.gen_using(
dimacs_maker,
'profile',
{
'vertices': 10000,
'edge_number': 5000,
'direct': 1,
}
)
6 changes: 3 additions & 3 deletions otherfile/profiles/erg_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
dimacs_maker,
'profile',
{
'vertices':10000,
'probability':0.5,
'direct':1,
'vertices': 10000,
'probability': 0.5,
'direct': 1,
}
)
2 changes: 2 additions & 0 deletions pyrgg/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from art import tprint
import pyrgg.engines.pyrgg as pyrgg_engine
import pyrgg.engines.erdos_reyni_gilbert as erg_engine
import pyrgg.engines.erdos_reyni as er_engine

GENERATOR_MENU = {
1: dimacs_maker,
Expand All @@ -33,6 +34,7 @@
ENGINE_MAPPER = {
1: pyrgg_engine,
2: erg_engine,
3: er_engine,
}


Expand Down
114 changes: 114 additions & 0 deletions pyrgg/engines/erdos_reyni.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# -*- coding: utf-8 -*-
"""Erdős-Rényi Engine module."""
import datetime
from random import shuffle
from pyrgg.params import ENGINE_MENU, PYRGG_LOGGER_ERROR_MESSAGE

LOGGER_TEMPLATE = """{0}
Filename : {1}
Vertices : {2}
Total Edges : {3}
Directed : {4}
Engine : {5} ({6})
Elapsed Time : {7}
-------------------------------
"""


def edge_gen(n, m, direct):
"""
Generate each vertex connection number.
:param n: number of vertices
:type n: int
:param m: number of edges
:type m: int
:param direct: directed graph flag
:type direct: bool
:return: list of dicts
"""
edge_dic = {}
weight_list = []
edge_mold = []
max_edge = (n * (n - 1)) // 2
if direct:
max_edge *= 2
m = min(m, max_edge)
edge_mold = m * [1] + (max_edge - m) * [0]
shuffle(edge_mold)
for i in range(1, n + 1):
edge_dic[i] = []
temp_list = []
dest_list = range(i + 1, n + 1)
if direct:
dest_list = [*range(1, i), *dest_list]
for j in dest_list:
if edge_mold.pop() == 1:
temp_list.append(1)
edge_dic[i].append(j)
weight_list.append(temp_list)
return [edge_dic, dict(zip(range(1, n + 1), weight_list)), m]


def gen_using(
gen_function,
file_name,
input_dict):
"""
Generate graph using given function based on Erdos Renyi - G(n, m) model.
Refer to (https://en.wikipedia.org/wiki/Erd%C5%91s%E2%80%93R%C3%A9nyi_model).
:param gen_function: generation function
:type gen_function: function object
:param file_name: file name
:type file_name: str
:param input_dict: input data
:type input_dict: dict
:return: number of edges as int
"""
edge_dic, weight_dic, edge_number = edge_gen(
input_dict['vertices'],
input_dict['edge_number'],
input_dict['direct'])
gen_function(
edge_dic,
weight_dic,
{
"file_name": file_name,
"vertices_number": input_dict['vertices'],
"edge_number": edge_number,
"weighted": False,
"max_weight": 1,
"min_weight": 1,
"direct": input_dict['direct'],
"multigraph": False,
})
return edge_number


def logger(file, file_name, elapsed_time, input_dict):
"""
Save generated graph logs for Erdős-Rényi engine.
:param file: file to write log into
:type file: file object
:param file_name: file name
:type file_name: str
:param elapsed_time: elapsed time
:type elapsed_time: str
:param input_dict: input data
:type input_dict: dict
:return: None
"""
try:
file.write(LOGGER_TEMPLATE.format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
file_name,
str(input_dict["vertices"]),
str(input_dict["edge_number"]),
str(bool(input_dict["direct"])),
input_dict["engine"],
ENGINE_MENU[input_dict["engine"]],
elapsed_time))
except Exception:
print(PYRGG_LOGGER_ERROR_MESSAGE)
4 changes: 2 additions & 2 deletions pyrgg/engines/erdos_reyni_gilbert.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ def edge_gen(n, p, direct):
if direct:
dest_list = [*range(1, i), *dest_list]
for j in dest_list:
temp_list.append(1)
if random() < p:
temp_list.append(1)
edge_dic[i].append(j)
edge_number += 1
weight_list.append(temp_list)
Expand All @@ -51,7 +51,7 @@ def gen_using(
file_name,
input_dict):
"""
Generate graph using given function based on Erdos Renyi Gilbert model.
Generate graph using given function based on Erdos Renyi Gilbert - G(n, p) model.
Refer to (https://en.wikipedia.org/wiki/Erd%C5%91s%E2%80%93R%C3%A9nyi_model).
Expand Down
2 changes: 2 additions & 0 deletions pyrgg/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ def handle_engine(string):
"min_weight": handle_str_to_number,
"min_edge": handle_pos_int,
"max_edge": handle_pos_int,
"edge_number": handle_pos_int,
"sign": handle_str_to_bool,
"direct": handle_str_to_bool,
"self_loop": handle_str_to_bool,
Expand Down Expand Up @@ -372,6 +373,7 @@ def get_input(input_func=input):
"min_weight": 1,
"min_edge": 0,
"max_edge": 0,
"edge_number": 0,
"sign": True,
"output_format": 1,
"weight": True,
Expand Down
21 changes: 15 additions & 6 deletions pyrgg/params.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- Select generation engine :
1- Pyrgg engine
2- Erdos-Renyi-Gilbert - G(n, p)
3- Erdos-Renyi - G(n, m)
"""
)],
2: ["file_name", "- File Name (Not Empty) : "],
Expand Down Expand Up @@ -61,16 +62,11 @@
ENGINE_MENU = {
1: "pyrgg",
2: "erg",
3: "er",
}

ENGINE_MENU_INV = {v: k for k, v in ENGINE_MENU.items()}

ERG_ENGINE_PARAMS = {
1: ["vertices", "- Vertices Number (>=0) : "],
2: ["probability", "- Probability (0 <= p <= 1) : "],
3: ["direct", "- Undirected[0] or Directed[1]"],
}

PYRGG_ENGINE_PARAMS = {
1: ["vertices", "- Vertices Number (>=0) : "],
2: ["min_edge", "- Min Edge Number - Connected to Each Vertex (>=0) : "],
Expand All @@ -84,9 +80,22 @@
10: ["multigraph", "- Simple[0] or Multigraph[1]"],
}

ERG_ENGINE_PARAMS = {
1: ["vertices", "- Vertices Number (>=0) : "],
2: ["probability", "- Probability (0 <= p <= 1) : "],
3: ["direct", "- Undirected[0] or Directed[1]"],
}

ER_ENGINE_PARAMS = {
1: ["vertices", "- Vertices Number (>=0) : "],
2: ["edge_number", "- Edge Number (>=0) : "],
3: ["direct", "- Undirected[0] or Directed[1]"],
}

ENGINE_PARAM_MAP = {
1: PYRGG_ENGINE_PARAMS,
2: ERG_ENGINE_PARAMS,
3: ER_ENGINE_PARAMS,
}

OUTPUT_FORMAT = {i: output_format[1:].upper()
Expand Down
6 changes: 3 additions & 3 deletions test/engines/erdos_reyni_gilbert_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@
>>> ## ========= logger function =========
>>> ######################################
>>> with open('logfile.log','a') as file:
... engine.logger(file,'test','2min',{'vertices':100,'edge_number':50,'direct':0,'engine':1,'probability':0.5,'output_format':1})
... engine.logger(file,'test','2min',{'vertices':100,'edge_number':50,'direct':0,'engine':2,'probability':0.5,'output_format':1})
>>> file = open('logfile.log','r')
>>> print("\\n".join(file.read().splitlines()[1:-1]))
Filename : test
Probability : 0.5
Vertices : 100
Total Edges : 50
Directed : False
Engine : 1 (pyrgg)
Engine : 2 (erg)
Elapsed Time : 2min
>>> class StrError:
... def __init__(self):
Expand All @@ -29,7 +29,7 @@
... raise ValueError
>>> str_error_object = StrError()
>>> with open('logfile.log','a') as file:
... engine.logger(file,'test','2min',{'vertices':str_error_object,'edge_number':50,'direct':0,'engine':1,'probability':0.5,'output_format':1})
... engine.logger(file,'test','2min',{'vertices':str_error_object,'edge_number':50,'direct':0,'engine':2,'probability':0.5,'output_format':1})
[Error] Logger failed!
>>> ##########################################
>>> ## ========= edge_gen function =========
Expand Down
Loading

0 comments on commit de95cec

Please sign in to comment.