boolforge 1.0.0__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.
- boolforge/__init__.py +67 -0
- boolforge/_version.py +1 -0
- boolforge/bio_models.py +380 -0
- boolforge/boolean_function.py +2073 -0
- boolforge/boolean_network.py +4476 -0
- boolforge/generate.py +2358 -0
- boolforge/modularity.py +380 -0
- boolforge/utils.py +514 -0
- boolforge/wiring_diagram.py +1311 -0
- boolforge-1.0.0.dist-info/METADATA +215 -0
- boolforge-1.0.0.dist-info/RECORD +14 -0
- boolforge-1.0.0.dist-info/WHEEL +5 -0
- boolforge-1.0.0.dist-info/licenses/LICENSE +21 -0
- boolforge-1.0.0.dist-info/top_level.txt +1 -0
boolforge/__init__.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Core public classes
|
|
2
|
+
from .boolean_function import (
|
|
3
|
+
BooleanFunction,
|
|
4
|
+
display_truth_table,
|
|
5
|
+
get_layer_structure_from_canalized_outputs
|
|
6
|
+
)
|
|
7
|
+
from .boolean_network import (
|
|
8
|
+
BooleanNetwork,
|
|
9
|
+
get_entropy_of_basin_size_distribution
|
|
10
|
+
)
|
|
11
|
+
from .wiring_diagram import WiringDiagram
|
|
12
|
+
|
|
13
|
+
# Canonical public generators
|
|
14
|
+
from .generate import (
|
|
15
|
+
random_function,
|
|
16
|
+
random_NCF,
|
|
17
|
+
random_k_canalizing_function,
|
|
18
|
+
random_wiring_diagram,
|
|
19
|
+
random_network,
|
|
20
|
+
random_null_model,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
from .utils import (
|
|
24
|
+
bin2dec,
|
|
25
|
+
dec2bin,
|
|
26
|
+
get_left_side_of_truth_table,
|
|
27
|
+
hamming_weight_to_ncf_layer_structure,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
from .modularity import (
|
|
31
|
+
compress_trajectories,
|
|
32
|
+
product_of_trajectories,
|
|
33
|
+
plot_trajectory,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
from .bio_models import get_bio_models_from_repository
|
|
37
|
+
|
|
38
|
+
# Version
|
|
39
|
+
try:
|
|
40
|
+
from ._version import __version__
|
|
41
|
+
except ImportError:
|
|
42
|
+
__version__ = "unknown"
|
|
43
|
+
|
|
44
|
+
__all__ = [
|
|
45
|
+
"bin2dec",
|
|
46
|
+
"dec2bin",
|
|
47
|
+
"get_left_side_of_truth_table",
|
|
48
|
+
"hamming_weight_to_ncf_layer_structure",
|
|
49
|
+
"BooleanFunction",
|
|
50
|
+
"display_truth_table",
|
|
51
|
+
"get_layer_structure_from_canalized_outputs",
|
|
52
|
+
"BooleanNetwork",
|
|
53
|
+
"get_entropy_of_basin_size_distribution",
|
|
54
|
+
"WiringDiagram",
|
|
55
|
+
"random_function",
|
|
56
|
+
"random_NCF",
|
|
57
|
+
"random_k_canalizing_function",
|
|
58
|
+
"random_wiring_diagram",
|
|
59
|
+
"random_network",
|
|
60
|
+
"random_null_model",
|
|
61
|
+
"get_bio_models_from_repository",
|
|
62
|
+
"__version__",
|
|
63
|
+
|
|
64
|
+
"compress_trajectories",
|
|
65
|
+
"product_of_trajectories",
|
|
66
|
+
"plot_trajectory"
|
|
67
|
+
]
|
boolforge/_version.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '1.0.0'
|
boolforge/bio_models.py
ADDED
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
r"""
|
|
4
|
+
This module provides functionality for retrieving, parsing, and loading
|
|
5
|
+
biological Boolean network models from public online repositories.
|
|
6
|
+
|
|
7
|
+
The :mod:`boolforge.bio_models` module allows users to programmatically access
|
|
8
|
+
and import published Boolean and logical gene regulatory network models from
|
|
9
|
+
GitHub repositories such as:
|
|
10
|
+
|
|
11
|
+
- expert-curated (ckadelka): manually curated models from the
|
|
12
|
+
Design Principles of Gene Regulatory Networks repository.
|
|
13
|
+
|
|
14
|
+
- pystablemotifs (jcrozum): models accompanying the PyStableMotifs library.
|
|
15
|
+
|
|
16
|
+
- biodivine (sybila): models from the Sybila Biodivine Boolean Models repository.
|
|
17
|
+
|
|
18
|
+
Functions are provided to:
|
|
19
|
+
|
|
20
|
+
- Recursively list and download files from GitHub folders using the REST API.
|
|
21
|
+
- Fetch raw text or byte content from remote sources.
|
|
22
|
+
- Parse Boolean network models into BooleanNetwork objects.
|
|
23
|
+
- Batch-download and convert all models from supported repositories.
|
|
24
|
+
|
|
25
|
+
This module is intended to facilitate reproducible research by providing
|
|
26
|
+
direct access to real-world Boolean GRN models for simulation, comparison,
|
|
27
|
+
and benchmarking.
|
|
28
|
+
|
|
29
|
+
Example
|
|
30
|
+
-------
|
|
31
|
+
>>> from boolforge import bio_models
|
|
32
|
+
>>> result = bio_models.get_bio_models_from_repository('')
|
|
33
|
+
>>> len(result['BooleanNetworks'])
|
|
34
|
+
122
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
import pickle
|
|
38
|
+
import io
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
import requests
|
|
42
|
+
except ImportError as e:
|
|
43
|
+
raise ImportError(
|
|
44
|
+
"The optional dependency 'requests' is required for bio_models. "
|
|
45
|
+
"Install it with `pip install requests`."
|
|
46
|
+
) from e
|
|
47
|
+
|
|
48
|
+
from .boolean_network import BooleanNetwork
|
|
49
|
+
|
|
50
|
+
__all__ = [
|
|
51
|
+
'load_model',
|
|
52
|
+
'get_bio_models_from_repository',
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
def _get_content_in_remote_folder(
|
|
56
|
+
url: str,
|
|
57
|
+
file_names: list,
|
|
58
|
+
file_download_urls: list
|
|
59
|
+
) -> None:
|
|
60
|
+
"""
|
|
61
|
+
Recursively collect file names and raw download URLs from a GitHub folder.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
url : str
|
|
66
|
+
GitHub API URL pointing to a repository folder.
|
|
67
|
+
file_names : list
|
|
68
|
+
List that will be populated with discovered file names.
|
|
69
|
+
file_download_urls : list
|
|
70
|
+
List that will be populated with corresponding raw download URLs.
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
None
|
|
75
|
+
"""
|
|
76
|
+
import logging
|
|
77
|
+
|
|
78
|
+
folder = requests.get(url)
|
|
79
|
+
folder.raise_for_status()
|
|
80
|
+
folder_json = folder.json()
|
|
81
|
+
|
|
82
|
+
for item in folder_json:
|
|
83
|
+
if item['size'] > 0 and item['download_url'] is not None:
|
|
84
|
+
file_names.append(item['name'])
|
|
85
|
+
file_download_urls.append(item['download_url'])
|
|
86
|
+
else:
|
|
87
|
+
try:
|
|
88
|
+
_get_content_in_remote_folder(
|
|
89
|
+
item['url'], file_names, file_download_urls
|
|
90
|
+
)
|
|
91
|
+
except Exception as e:
|
|
92
|
+
logging.warning(
|
|
93
|
+
"Failed to access subfolder at %s: %s",
|
|
94
|
+
item.get('url', '<unknown>'),
|
|
95
|
+
e,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
def get_content_in_remote_folder(url: str) -> tuple:
|
|
99
|
+
"""
|
|
100
|
+
Retrieve file names and raw download URLs from a GitHub repository folder.
|
|
101
|
+
|
|
102
|
+
Parameters
|
|
103
|
+
----------
|
|
104
|
+
url : str
|
|
105
|
+
GitHub API URL pointing to a repository folder.
|
|
106
|
+
|
|
107
|
+
Returns
|
|
108
|
+
-------
|
|
109
|
+
tuple[list[str], list[str]]
|
|
110
|
+
A tuple ``(file_names, file_download_urls)``, where:
|
|
111
|
+
|
|
112
|
+
- ``file_names`` contains the names of discovered files.
|
|
113
|
+
- ``file_download_urls`` contains corresponding raw download URLs.
|
|
114
|
+
"""
|
|
115
|
+
file_names = []
|
|
116
|
+
file_download_urls = []
|
|
117
|
+
_get_content_in_remote_folder(url, file_names, file_download_urls)
|
|
118
|
+
return file_names, file_download_urls
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def fetch_file(download_url: str) -> str:
|
|
122
|
+
"""
|
|
123
|
+
Download raw text content from a remote file.
|
|
124
|
+
|
|
125
|
+
Parameters
|
|
126
|
+
----------
|
|
127
|
+
download_url : str
|
|
128
|
+
Direct download URL to the file.
|
|
129
|
+
|
|
130
|
+
Returns
|
|
131
|
+
-------
|
|
132
|
+
str
|
|
133
|
+
File content as plain text.
|
|
134
|
+
"""
|
|
135
|
+
r = requests.get(download_url)
|
|
136
|
+
r.raise_for_status()
|
|
137
|
+
return r.text
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def fetch_file_bytes(download_url: str) -> bytes:
|
|
141
|
+
"""
|
|
142
|
+
Download raw binary content from a remote file.
|
|
143
|
+
|
|
144
|
+
Parameters
|
|
145
|
+
----------
|
|
146
|
+
download_url : str
|
|
147
|
+
Direct download URL to the file.
|
|
148
|
+
|
|
149
|
+
Returns
|
|
150
|
+
-------
|
|
151
|
+
bytes
|
|
152
|
+
File content as raw bytes.
|
|
153
|
+
"""
|
|
154
|
+
r = requests.get(download_url)
|
|
155
|
+
r.raise_for_status()
|
|
156
|
+
return r.content
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def load_model(
|
|
160
|
+
download_url: str,
|
|
161
|
+
max_degree: int = 24,
|
|
162
|
+
possible_separators: list[str] = ['* =', '*=', '=', ','],
|
|
163
|
+
ignore_first_line: bool = False,
|
|
164
|
+
simplify_functions: bool = False,
|
|
165
|
+
) -> BooleanNetwork:
|
|
166
|
+
"""
|
|
167
|
+
Load and parse a Boolean network model from a remote text file.
|
|
168
|
+
|
|
169
|
+
Parameters
|
|
170
|
+
----------
|
|
171
|
+
download_url : str
|
|
172
|
+
Direct download URL to the model file.
|
|
173
|
+
max_degree : int, optional
|
|
174
|
+
Maximum allowed in-degree for nodes (default: 24).
|
|
175
|
+
possible_separators : list[str], optional
|
|
176
|
+
Possible assignment separators used in the model file.
|
|
177
|
+
ignore_first_line : bool, optional
|
|
178
|
+
If True, skip the first line of the file (default: False).
|
|
179
|
+
simplify_functions : bool, optional
|
|
180
|
+
If True, Boolean update functions are simplified after initialization.
|
|
181
|
+
Default is False.
|
|
182
|
+
|
|
183
|
+
Returns
|
|
184
|
+
-------
|
|
185
|
+
BooleanNetwork
|
|
186
|
+
Parsed Boolean network.
|
|
187
|
+
|
|
188
|
+
Raises
|
|
189
|
+
------
|
|
190
|
+
ValueError
|
|
191
|
+
If the model cannot be parsed.
|
|
192
|
+
"""
|
|
193
|
+
string = fetch_file(download_url)
|
|
194
|
+
|
|
195
|
+
if ignore_first_line:
|
|
196
|
+
string = string[string.index('\n') + 1:]
|
|
197
|
+
|
|
198
|
+
errors = []
|
|
199
|
+
|
|
200
|
+
for sep in possible_separators:
|
|
201
|
+
try:
|
|
202
|
+
return BooleanNetwork.from_string(
|
|
203
|
+
string,
|
|
204
|
+
separator=sep,
|
|
205
|
+
max_degree=max_degree,
|
|
206
|
+
simplify_functions=simplify_functions,
|
|
207
|
+
)
|
|
208
|
+
except Exception as e:
|
|
209
|
+
errors.append((sep, e))
|
|
210
|
+
|
|
211
|
+
error_msg = "\n".join(
|
|
212
|
+
f"separator '{sep}' failed with: {repr(err)}"
|
|
213
|
+
for sep, err in errors
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
raise ValueError(
|
|
217
|
+
f"Failed to parse Boolean network model from {download_url} "
|
|
218
|
+
f"using any separator.\nAttempted separators: {possible_separators}\n"
|
|
219
|
+
f"Errors:\n{error_msg}"
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
def get_bio_models_from_repository(
|
|
223
|
+
repository: str = 'expert-curated (ckadelka)',
|
|
224
|
+
download_urls_pystablemotifs: list[str] | None = None,
|
|
225
|
+
max_degree: int = 24,
|
|
226
|
+
simplify_functions: bool = False,
|
|
227
|
+
) -> dict:
|
|
228
|
+
"""
|
|
229
|
+
Load Boolean network models from selected online repositories.
|
|
230
|
+
|
|
231
|
+
This function downloads, parses, and constructs Boolean network models
|
|
232
|
+
from several curated online repositories. Models that cannot be parsed
|
|
233
|
+
are skipped and recorded separately.
|
|
234
|
+
|
|
235
|
+
Parameters
|
|
236
|
+
----------
|
|
237
|
+
repository : str, optional
|
|
238
|
+
Identifier of the source repository. Supported values are:
|
|
239
|
+
|
|
240
|
+
- 'expert-curated (ckadelka)' (default)
|
|
241
|
+
- 'pystablemotifs (jcrozum)'
|
|
242
|
+
- 'biodivine (sybila)'
|
|
243
|
+
|
|
244
|
+
download_urls_pystablemotifs : list[str] or None, optional
|
|
245
|
+
Optional list of direct download URLs for PyStableMotifs models.
|
|
246
|
+
If provided, these URLs are used instead of querying the GitHub API (faster).
|
|
247
|
+
If None (default), model URLs are fetched dynamically from GitHub.
|
|
248
|
+
max_degree : int, optional
|
|
249
|
+
Maximum allowed in-degree for nodes (default: 24).
|
|
250
|
+
simplify_functions : bool, optional
|
|
251
|
+
If True, Boolean update functions are simplified after initialization.
|
|
252
|
+
Default is False.
|
|
253
|
+
|
|
254
|
+
Returns
|
|
255
|
+
-------
|
|
256
|
+
dict
|
|
257
|
+
Dictionary with the following keys:
|
|
258
|
+
|
|
259
|
+
- 'BooleanNetworks' : list[BooleanNetwork]
|
|
260
|
+
List of successfully parsed Boolean network models.
|
|
261
|
+
|
|
262
|
+
- 'SuccessfulDownloadURLs' : list[str]
|
|
263
|
+
URLs corresponding to models that were successfully loaded.
|
|
264
|
+
|
|
265
|
+
- 'FailedDownloadURLs' : list[str]
|
|
266
|
+
URLs corresponding to models that could not be parsed or loaded.
|
|
267
|
+
"""
|
|
268
|
+
repositories = [
|
|
269
|
+
'expert-curated (ckadelka)',
|
|
270
|
+
'pystablemotifs (jcrozum)',
|
|
271
|
+
'biodivine (sybila)',
|
|
272
|
+
]
|
|
273
|
+
|
|
274
|
+
bns = []
|
|
275
|
+
successful_download_urls = []
|
|
276
|
+
failed_download_urls = []
|
|
277
|
+
|
|
278
|
+
if repository == 'expert-curated (ckadelka)':
|
|
279
|
+
download_url_base = (
|
|
280
|
+
'https://raw.githubusercontent.com/ckadelka/'
|
|
281
|
+
'DesignPrinciplesGeneNetworks/main/'
|
|
282
|
+
'update_rules_122_models_Kadelka_SciAdv/'
|
|
283
|
+
)
|
|
284
|
+
download_url = download_url_base + 'all_txt_files.csv'
|
|
285
|
+
csv = fetch_file(download_url)
|
|
286
|
+
|
|
287
|
+
for line in csv.splitlines():
|
|
288
|
+
download_url = download_url_base + line
|
|
289
|
+
if '.txt' in download_url:
|
|
290
|
+
try:
|
|
291
|
+
if 'tabular' in download_url:
|
|
292
|
+
F, I, var, constants = pickle.load(
|
|
293
|
+
io.BytesIO(fetch_file_bytes(download_url))
|
|
294
|
+
)
|
|
295
|
+
for i in range(len(constants)):
|
|
296
|
+
F.append([0, 1])
|
|
297
|
+
I.append([len(var) + i])
|
|
298
|
+
bn = BooleanNetwork(F,
|
|
299
|
+
I,
|
|
300
|
+
var + constants,
|
|
301
|
+
simplify_functions=simplify_functions)
|
|
302
|
+
else:
|
|
303
|
+
bn = load_model(
|
|
304
|
+
download_url,
|
|
305
|
+
possible_separators = ['='],
|
|
306
|
+
simplify_functions=simplify_functions,
|
|
307
|
+
max_degree = max_degree,
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
successful_download_urls.append(download_url)
|
|
311
|
+
bns.append(bn)
|
|
312
|
+
|
|
313
|
+
except Exception:
|
|
314
|
+
failed_download_urls.append(download_url)
|
|
315
|
+
|
|
316
|
+
elif repository == 'pystablemotifs (jcrozum)':
|
|
317
|
+
if download_urls_pystablemotifs is None:
|
|
318
|
+
url = "https://api.github.com/repos/jcrozum/pystablemotifs/contents/models"
|
|
319
|
+
_, download_urls = get_content_in_remote_folder(url)
|
|
320
|
+
else:
|
|
321
|
+
download_urls = download_urls_pystablemotifs
|
|
322
|
+
|
|
323
|
+
for download_url in download_urls:
|
|
324
|
+
if '.txt' in download_url:
|
|
325
|
+
try:
|
|
326
|
+
bn = load_model(
|
|
327
|
+
download_url,
|
|
328
|
+
possible_separators=['* =', '* =', '* =', '* =', '*='],
|
|
329
|
+
# original_and=[" and ", "&"],
|
|
330
|
+
# original_or=[" or ", "|"],
|
|
331
|
+
# original_not=[" not ", " !"],
|
|
332
|
+
simplify_functions=simplify_functions,
|
|
333
|
+
max_degree = max_degree,
|
|
334
|
+
)
|
|
335
|
+
successful_download_urls.append(download_url)
|
|
336
|
+
bns.append(bn)
|
|
337
|
+
except Exception:
|
|
338
|
+
failed_download_urls.append(download_url)
|
|
339
|
+
|
|
340
|
+
elif repository == 'biodivine (sybila)':
|
|
341
|
+
download_url_base = (
|
|
342
|
+
'https://raw.githubusercontent.com/sybila/'
|
|
343
|
+
'biodivine-boolean-models/main/models/'
|
|
344
|
+
)
|
|
345
|
+
download_url = download_url_base + 'summary.csv'
|
|
346
|
+
csv = fetch_file(download_url)
|
|
347
|
+
|
|
348
|
+
for line in csv.splitlines():
|
|
349
|
+
try:
|
|
350
|
+
ID, name, variables, inputs, regulations = line.split(', ')
|
|
351
|
+
download_url = (
|
|
352
|
+
download_url_base
|
|
353
|
+
+ '[id-%s]__[var-%s]__[in-%s]__[%s]/model.bnet'
|
|
354
|
+
% (ID, variables, inputs, name)
|
|
355
|
+
)
|
|
356
|
+
bn = load_model(
|
|
357
|
+
download_url,
|
|
358
|
+
# original_and=" & ",
|
|
359
|
+
# original_or=" | ",
|
|
360
|
+
# original_not="!",
|
|
361
|
+
ignore_first_line=True,
|
|
362
|
+
simplify_functions=simplify_functions,
|
|
363
|
+
max_degree=max_degree,
|
|
364
|
+
)
|
|
365
|
+
successful_download_urls.append(download_url)
|
|
366
|
+
bns.append(bn)
|
|
367
|
+
except Exception:
|
|
368
|
+
failed_download_urls.append(download_url)
|
|
369
|
+
|
|
370
|
+
else:
|
|
371
|
+
raise ValueError(
|
|
372
|
+
"repository must be one of:\n - " + "\n - ".join(repositories)
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
return {
|
|
376
|
+
"BooleanNetworks": bns,
|
|
377
|
+
"SuccessfulDownloadURLs": successful_download_urls,
|
|
378
|
+
"FailedDownloadURLs": failed_download_urls,
|
|
379
|
+
}
|
|
380
|
+
|