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.
Files changed (53) hide show
  1. seed2lp/__init__.py +12 -0
  2. seed2lp/__main__.py +837 -0
  3. seed2lp/_version.py +2 -0
  4. seed2lp/argument.py +717 -0
  5. seed2lp/asp/atom_for_transfers.lp +7 -0
  6. seed2lp/asp/community_heuristic.lp +3 -0
  7. seed2lp/asp/community_search.lp +14 -0
  8. seed2lp/asp/constraints_targets.lp +15 -0
  9. seed2lp/asp/definition_atoms.lp +87 -0
  10. seed2lp/asp/enum-cc.lp +50 -0
  11. seed2lp/asp/flux.lp +70 -0
  12. seed2lp/asp/limit_transfers.lp +9 -0
  13. seed2lp/asp/maximize_flux.lp +2 -0
  14. seed2lp/asp/maximize_produced_target.lp +7 -0
  15. seed2lp/asp/minimize.lp +8 -0
  16. seed2lp/asp/seed-solving.lp +116 -0
  17. seed2lp/asp/seed_external.lp +1 -0
  18. seed2lp/asp/show_seeds.lp +2 -0
  19. seed2lp/asp/show_tranfers.lp +1 -0
  20. seed2lp/asp/test.lp +61 -0
  21. seed2lp/clingo_lpx.py +236 -0
  22. seed2lp/color.py +34 -0
  23. seed2lp/config.yaml +56 -0
  24. seed2lp/description.py +424 -0
  25. seed2lp/file.py +151 -0
  26. seed2lp/flux.py +365 -0
  27. seed2lp/linear.py +431 -0
  28. seed2lp/log_conf.yaml +25 -0
  29. seed2lp/logger.py +112 -0
  30. seed2lp/metabolite.py +46 -0
  31. seed2lp/network.py +1921 -0
  32. seed2lp/reaction.py +207 -0
  33. seed2lp/reasoning.py +459 -0
  34. seed2lp/reasoningcom.py +753 -0
  35. seed2lp/reasoninghybrid.py +791 -0
  36. seed2lp/resmod.py +74 -0
  37. seed2lp/sbml.py +307 -0
  38. seed2lp/scope.py +124 -0
  39. seed2lp/solver.py +333 -0
  40. seed2lp/temp_flux_com.py +74 -0
  41. seed2lp/utils.py +237 -0
  42. seed2lp-2.0.0.dist-info/METADATA +404 -0
  43. seed2lp-2.0.0.dist-info/RECORD +53 -0
  44. seed2lp-2.0.0.dist-info/WHEEL +5 -0
  45. seed2lp-2.0.0.dist-info/entry_points.txt +2 -0
  46. seed2lp-2.0.0.dist-info/licenses/LICENCE.txt +145 -0
  47. seed2lp-2.0.0.dist-info/top_level.txt +2 -0
  48. tests/__init__.py +0 -0
  49. tests/fba.py +147 -0
  50. tests/full_network.py +166 -0
  51. tests/normalization.py +188 -0
  52. tests/target.py +286 -0
  53. 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
+