seed2lp 2.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.
- seed2lp/__init__.py +12 -0
- seed2lp/__main__.py +837 -0
- seed2lp/_version.py +2 -0
- seed2lp/argument.py +717 -0
- seed2lp/asp/atom_for_transfers.lp +7 -0
- seed2lp/asp/community_heuristic.lp +3 -0
- seed2lp/asp/community_search.lp +14 -0
- seed2lp/asp/constraints_targets.lp +15 -0
- seed2lp/asp/definition_atoms.lp +87 -0
- seed2lp/asp/enum-cc.lp +50 -0
- seed2lp/asp/flux.lp +70 -0
- seed2lp/asp/limit_transfers.lp +9 -0
- seed2lp/asp/maximize_flux.lp +2 -0
- seed2lp/asp/maximize_produced_target.lp +7 -0
- seed2lp/asp/minimize.lp +8 -0
- seed2lp/asp/seed-solving.lp +116 -0
- seed2lp/asp/seed_external.lp +1 -0
- seed2lp/asp/show_seeds.lp +2 -0
- seed2lp/asp/show_tranfers.lp +1 -0
- seed2lp/asp/test.lp +61 -0
- seed2lp/clingo_lpx.py +236 -0
- seed2lp/color.py +34 -0
- seed2lp/config.yaml +56 -0
- seed2lp/description.py +424 -0
- seed2lp/file.py +151 -0
- seed2lp/flux.py +365 -0
- seed2lp/linear.py +431 -0
- seed2lp/log_conf.yaml +25 -0
- seed2lp/logger.py +112 -0
- seed2lp/metabolite.py +46 -0
- seed2lp/network.py +1921 -0
- seed2lp/reaction.py +207 -0
- seed2lp/reasoning.py +459 -0
- seed2lp/reasoningcom.py +753 -0
- seed2lp/reasoninghybrid.py +791 -0
- seed2lp/resmod.py +74 -0
- seed2lp/sbml.py +307 -0
- seed2lp/scope.py +124 -0
- seed2lp/solver.py +333 -0
- seed2lp/temp_flux_com.py +74 -0
- seed2lp/utils.py +237 -0
- seed2lp-2.0.0.dist-info/METADATA +404 -0
- seed2lp-2.0.0.dist-info/RECORD +53 -0
- seed2lp-2.0.0.dist-info/WHEEL +5 -0
- seed2lp-2.0.0.dist-info/entry_points.txt +2 -0
- seed2lp-2.0.0.dist-info/licenses/LICENCE.txt +145 -0
- seed2lp-2.0.0.dist-info/top_level.txt +2 -0
- tests/__init__.py +0 -0
- tests/fba.py +147 -0
- tests/full_network.py +166 -0
- tests/normalization.py +188 -0
- tests/target.py +286 -0
- tests/utils.py +181 -0
seed2lp/clingo_lpx.py
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Clingo lpx functions for launching command and extract results.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import subprocess
|
|
6
|
+
import json
|
|
7
|
+
from resource import getrusage, RUSAGE_CHILDREN
|
|
8
|
+
from .utils import repair_json
|
|
9
|
+
from . import logger, color
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def command(files:list, options:list, nb_model:int=0, time_limit:int=0) -> iter:
|
|
13
|
+
"""Create the Clingo-lpx command to run for solving
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
files (list): List of ASP files used for sovling.
|
|
17
|
+
options (list): Clingo options
|
|
18
|
+
nb_model (int, optional): Limit number of solutions to find. Defaults to 0 meaning unlimited.
|
|
19
|
+
time_limit (int, optional): Time limit given by user in minutes. Defaults to 0 meaning unlimited.
|
|
20
|
+
|
|
21
|
+
Raises:
|
|
22
|
+
ValueError: If the number of model is negative, the command is not correct
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
iter: Composition of the command to run
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
CMD = ['python', '-m', 'clingolpx']
|
|
29
|
+
options = list(filter(None, options))
|
|
30
|
+
|
|
31
|
+
if time_limit:
|
|
32
|
+
time_limit = int(time_limit)
|
|
33
|
+
options.append(f'--time-limit={str(time_limit)}')
|
|
34
|
+
if nb_model:
|
|
35
|
+
nb_model = int(nb_model)
|
|
36
|
+
if nb_model < 0:
|
|
37
|
+
raise ValueError("Number of model must be >= 0.")
|
|
38
|
+
options.append(f'-n {str(nb_model)}')
|
|
39
|
+
else:
|
|
40
|
+
options.append(f'-n 0')
|
|
41
|
+
|
|
42
|
+
options.append("--warn=none")
|
|
43
|
+
|
|
44
|
+
if files:
|
|
45
|
+
cmd = [*CMD, *files, *options]
|
|
46
|
+
else:
|
|
47
|
+
cmd = [*CMD, *options]
|
|
48
|
+
|
|
49
|
+
return cmd
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def solve(cmd:list, time_limit:int):
|
|
53
|
+
"""Launch the Clingo-lpx command
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
cmd (list): Clingo-lpx command
|
|
57
|
+
time_limit (int): Time limit given by user in minutes.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
proc_output (str), err_output (str), error_code (int), memory (float), is_killed (bool)
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
cmd.append(f'--outf=2')
|
|
64
|
+
is_killed=False
|
|
65
|
+
try:
|
|
66
|
+
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
67
|
+
if time_limit:
|
|
68
|
+
process.wait(timeout=time_limit+60)
|
|
69
|
+
except subprocess.TimeoutExpired:
|
|
70
|
+
logger.log.error(f'Timeout: {time_limit/60} min expired')
|
|
71
|
+
process.kill()
|
|
72
|
+
process.wait()
|
|
73
|
+
is_killed=True
|
|
74
|
+
|
|
75
|
+
proc_output, err_output = process.communicate()
|
|
76
|
+
memory=getrusage(RUSAGE_CHILDREN).ru_maxrss / (1024 * 1024)
|
|
77
|
+
error_code=process.returncode
|
|
78
|
+
if is_killed:
|
|
79
|
+
error_code=0
|
|
80
|
+
if error_code==1:
|
|
81
|
+
logger.log.error(f'Timeout: {time_limit/60} min expired')
|
|
82
|
+
return str(proc_output, 'UTF-8'), err_output, error_code, round(memory,3), is_killed
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def result_convert(proc_output:str, objectives:list=None, enum_mode:str="",
|
|
87
|
+
is_killed:bool=False, to_print:bool=True):
|
|
88
|
+
"""Convert the output result into constructed and limited output (JSON type)
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
proc_output (str): Output from the solver
|
|
92
|
+
objectives (list, optional): List of objective reactions to show on output. Defaults to None.
|
|
93
|
+
enum_mode (str, optional): Enumeration mode to detect intersection or enumeration. Defaults to "".
|
|
94
|
+
is_killed (bool, optional): Detects if the process was killed. Defaults to False.
|
|
95
|
+
to_print (bool, optional): Print the solution into consol. Defaults to True.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
result (dict), unsatisfiable (bool), has_optimum (bool), time (dict), costs (list)
|
|
99
|
+
"""
|
|
100
|
+
result={}
|
|
101
|
+
seed_accu={}
|
|
102
|
+
time={}
|
|
103
|
+
has_optimum = False
|
|
104
|
+
unsatisfiable = True
|
|
105
|
+
model_number=1
|
|
106
|
+
seeds_list=list()
|
|
107
|
+
reaction_list=list()
|
|
108
|
+
costs=None
|
|
109
|
+
if proc_output:
|
|
110
|
+
if is_killed:
|
|
111
|
+
proc_output=repair_json(proc_output, True)
|
|
112
|
+
result_data = json.loads(proc_output)
|
|
113
|
+
|
|
114
|
+
if 'Result' in result_data:
|
|
115
|
+
if result_data['Result'] == 'SATISFIABLE':
|
|
116
|
+
unsatisfiable = False
|
|
117
|
+
if result_data['Result'] == 'OPTIMUM FOUND':
|
|
118
|
+
has_optimum = True
|
|
119
|
+
unsatisfiable = False
|
|
120
|
+
elif enum_mode=="domRec":
|
|
121
|
+
unsatisfiable = False
|
|
122
|
+
if 'Time' in result_data:
|
|
123
|
+
time = result_data['Time']
|
|
124
|
+
|
|
125
|
+
if 'Call' in result_data:
|
|
126
|
+
if 'Witnesses' in result_data['Call'][0]:
|
|
127
|
+
#Case minimize finding optimum or case intersection
|
|
128
|
+
if (has_optimum and enum_mode != "enumeration") or enum_mode == "cautious":
|
|
129
|
+
model = result_data['Call'][0]['Witnesses'][-1]
|
|
130
|
+
reaction_list, seeds_list, objective_str, seeds_accu_list = \
|
|
131
|
+
get_model_data(model, objectives)
|
|
132
|
+
nb_seed=len(seeds_list)
|
|
133
|
+
nb_seed_accu=len(seeds_accu_list)
|
|
134
|
+
result[f'model_{model_number}']=["size", nb_seed] + \
|
|
135
|
+
["Set of seeds", seeds_list.copy()] + \
|
|
136
|
+
['reaction_flux', reaction_list.copy()]
|
|
137
|
+
if nb_seed_accu or nb_seed_accu>0:
|
|
138
|
+
seed_accu["size"] = nb_seed_accu
|
|
139
|
+
seed_accu["Set of seeds"] = seeds_accu_list.copy()
|
|
140
|
+
result[f'model_{model_number}']=result[f'model_{model_number}'] +\
|
|
141
|
+
["accumulation avoid with seeds", seed_accu]
|
|
142
|
+
if "Costs" in model:
|
|
143
|
+
costs = model["Costs"]
|
|
144
|
+
if to_print:
|
|
145
|
+
print_data(model_number, objective_str, seeds_list, seeds_accu_list)
|
|
146
|
+
elif not unsatisfiable:
|
|
147
|
+
for model in result_data['Call'][0]['Witnesses']:
|
|
148
|
+
reaction_list, seeds_list, objective_str, seeds_accu_list = \
|
|
149
|
+
get_model_data(model, objectives)
|
|
150
|
+
nb_seed=len(seeds_list)
|
|
151
|
+
nb_seed_accu=len(seeds_accu_list)
|
|
152
|
+
print_data(model_number, objective_str, seeds_list, seeds_accu_list)
|
|
153
|
+
result[f'model_{model_number}']=["size", nb_seed] + \
|
|
154
|
+
["Set of seeds", seeds_list.copy()] + \
|
|
155
|
+
['reaction_flux', reaction_list.copy()]
|
|
156
|
+
if nb_seed_accu or nb_seed_accu>0:
|
|
157
|
+
seed_accu["size"] = nb_seed_accu
|
|
158
|
+
seed_accu["Set of seeds"] = seeds_accu_list.copy()
|
|
159
|
+
result[f'model_{model_number}']=result[f'model_{model_number}'] +\
|
|
160
|
+
["accumulation avoid with seeds", seed_accu]
|
|
161
|
+
model_number+=1
|
|
162
|
+
|
|
163
|
+
return result, unsatisfiable, has_optimum, time, costs
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def get_model_data(model:dict, objectives:list=None):
|
|
167
|
+
"""Get clingo results and convert into lists
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
model (dict): output of clingo
|
|
171
|
+
objectives (list, optional): List of objective reactions to show on output. Defaults to None.
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
reaction_list (list), seeds_list (list), objective_str (str), seeds_accu_list (list)
|
|
175
|
+
"""
|
|
176
|
+
objective_str=''
|
|
177
|
+
reaction_list=list()
|
|
178
|
+
seeds_list=list()
|
|
179
|
+
seeds_accu_list=list()
|
|
180
|
+
for answer in model['Value']:
|
|
181
|
+
|
|
182
|
+
if 'seed("' in answer:
|
|
183
|
+
seed=answer.replace('seed("','',1).replace('")','',1)
|
|
184
|
+
seed=seed.split(',')[0].replace('"','',2)
|
|
185
|
+
seeds_list.append(seed)
|
|
186
|
+
elif 'seed_accu(' in answer:
|
|
187
|
+
seed_accu=answer.replace('seed_accu("','',1).replace('")','',1)
|
|
188
|
+
seed_accu=seed_accu.split(',')[0].replace('"','',2)
|
|
189
|
+
seeds_accu_list.append(seed_accu)
|
|
190
|
+
else:
|
|
191
|
+
answer = answer.replace('__lpx(','',1).replace(')','',1)
|
|
192
|
+
reaction = answer.split(',')[0].replace('"','',2)
|
|
193
|
+
flux = answer.split(',')[1].replace('"','',2).replace(')','',1)
|
|
194
|
+
if '/' in flux:
|
|
195
|
+
numerator=int(flux.split('/')[0])
|
|
196
|
+
denominator=int(flux.split('/')[1])
|
|
197
|
+
flux=round(float(numerator/denominator),10)
|
|
198
|
+
else:
|
|
199
|
+
flux=round(float(flux),10)
|
|
200
|
+
if reaction in objectives:
|
|
201
|
+
objective_str+=f'"{reaction}" = {flux}\n'
|
|
202
|
+
reaction_list.append((reaction,flux))
|
|
203
|
+
|
|
204
|
+
seeds_list=list(sorted(seeds_list))
|
|
205
|
+
seeds_accu_list=list(sorted(seeds_accu_list))
|
|
206
|
+
return reaction_list, seeds_list, objective_str, seeds_accu_list
|
|
207
|
+
|
|
208
|
+
def print_data(model_number:int, objective_str:str, seeds_list:list,
|
|
209
|
+
seeds_accu_list:list):
|
|
210
|
+
"""Data written into terminal
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
model_number (int): name of the solution
|
|
214
|
+
objective_str (str): Reaction name and flux
|
|
215
|
+
seeds_list (list): Seeds list
|
|
216
|
+
seeds_accu_list (list): Seeds used for accumulation list
|
|
217
|
+
"""
|
|
218
|
+
plural_seed=""
|
|
219
|
+
plural_accu=""
|
|
220
|
+
nb_seed = len(seeds_list)
|
|
221
|
+
nb_seed_accu = len(seeds_accu_list)
|
|
222
|
+
if nb_seed>=2:
|
|
223
|
+
plural_seed="s"
|
|
224
|
+
if nb_seed_accu>=2:
|
|
225
|
+
plural_accu="s"
|
|
226
|
+
#is_accu = seeds_accu_str or seeds_accu_str != ""
|
|
227
|
+
print(color.cyan_light + f"Answer: {model_number}{color.reset} ({nb_seed} seed{plural_seed}) ")
|
|
228
|
+
seeds_str = ', '.join(map(str, seeds_list))
|
|
229
|
+
print(seeds_str)
|
|
230
|
+
if nb_seed_accu > 0:
|
|
231
|
+
seeds_accu_str = ', '.join(map(str, seeds_accu_list))
|
|
232
|
+
print(f"{color.red_bright} Seed{plural_accu} for which export reaction \navoids accumulation ({nb_seed_accu} seed{plural_accu})")
|
|
233
|
+
print(seeds_accu_str+color.reset)
|
|
234
|
+
print('Assignment:')
|
|
235
|
+
print(objective_str)
|
|
236
|
+
|
seed2lp/color.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
reset = '\033[0m'
|
|
2
|
+
|
|
3
|
+
black_bright = "\033[0;90m"
|
|
4
|
+
black_pure = "\033[0;30m"
|
|
5
|
+
blue_bright = "\033[0;94m"
|
|
6
|
+
blue_dark = "\033[0;34m"
|
|
7
|
+
cyan_dark = "\033[0;36m"
|
|
8
|
+
cyan_light = "\033[0;96m"
|
|
9
|
+
green_dark = "\033[0;32m"
|
|
10
|
+
green_light = "\033[0;92m"
|
|
11
|
+
grey = '\033[38;4;236m'
|
|
12
|
+
magenta = "\033[0;95m"
|
|
13
|
+
purple = "\033[0;94m"
|
|
14
|
+
purple_bright = "\033[0;35m"
|
|
15
|
+
red_bright = "\033[0;91m"
|
|
16
|
+
yellow = "\033[0;93m"
|
|
17
|
+
white_bright = "\033[0;97m"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
blue_back = "\033[0;44m"
|
|
21
|
+
cyan_back = "\033[0;46m"
|
|
22
|
+
green_back = "\033[0;42m"
|
|
23
|
+
orange_back = "\033[0;43m"
|
|
24
|
+
pink_back = "\033[0;41m"
|
|
25
|
+
purple_back = "\033[0;45m"
|
|
26
|
+
white_back = "\033[0;47m"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
bold = "\033[1m"
|
|
30
|
+
darken = "\033[2m"
|
|
31
|
+
invisible = '\033[08m'
|
|
32
|
+
italic = "\033[3m"
|
|
33
|
+
reverse_colour = '\033[07m'
|
|
34
|
+
underline = "\033[4m"
|
seed2lp/config.yaml
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
###############################
|
|
2
|
+
# Seed2lp configuration #
|
|
3
|
+
###############################
|
|
4
|
+
|
|
5
|
+
seed2lp:
|
|
6
|
+
# Options
|
|
7
|
+
verbose : False
|
|
8
|
+
# Searching mode
|
|
9
|
+
mode : "all" # 'minimize', 'subsetmin', 'all' / for single network
|
|
10
|
+
solve : "all" # 'reasoning', 'filter', 'guess_check', 'guess_check_div', 'hybrid', 'all'
|
|
11
|
+
intersection : False
|
|
12
|
+
union : False
|
|
13
|
+
targets_as_seeds : False
|
|
14
|
+
topological_injection : False
|
|
15
|
+
keep_import_reactions : False
|
|
16
|
+
accumulation : False
|
|
17
|
+
# Flux
|
|
18
|
+
check_flux : False
|
|
19
|
+
maximize_flux : False
|
|
20
|
+
# Clingo
|
|
21
|
+
clingo_configuration : 'jumpy'
|
|
22
|
+
clingo_strategy : 'none'
|
|
23
|
+
time_limit : 45
|
|
24
|
+
number_solution : 10
|
|
25
|
+
# Directories
|
|
26
|
+
temp : "tmp/"
|
|
27
|
+
|
|
28
|
+
seed2lp_com:
|
|
29
|
+
# Options
|
|
30
|
+
verbose : False
|
|
31
|
+
# Searching mode
|
|
32
|
+
community_mode : "bisteps" # 'bisteps', 'global', 'delsupset'
|
|
33
|
+
solve : "all" # 'reasoning', 'filter', 'guess_check', 'guess_check_div', 'all'
|
|
34
|
+
intersection : False
|
|
35
|
+
union : False
|
|
36
|
+
targets_as_seeds : False
|
|
37
|
+
topological_injection : False
|
|
38
|
+
keep_import_reactions : False
|
|
39
|
+
accumulation : False
|
|
40
|
+
# Flux
|
|
41
|
+
check_flux : False
|
|
42
|
+
equality_flux : False
|
|
43
|
+
# Clingo
|
|
44
|
+
clingo_configuration : 'jumpy'
|
|
45
|
+
clingo_strategy : 'none'
|
|
46
|
+
time_limit : 45
|
|
47
|
+
number_solution : 10
|
|
48
|
+
# Directories
|
|
49
|
+
temp : "tmp/"
|
|
50
|
+
|
|
51
|
+
flux_com:
|
|
52
|
+
# Directories
|
|
53
|
+
equality_flux : False
|
|
54
|
+
temp : "tmp/"
|
|
55
|
+
|
|
56
|
+
|