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
|
@@ -0,0 +1,791 @@
|
|
|
1
|
+
from .solver import Solver
|
|
2
|
+
from .network import Network
|
|
3
|
+
from multiprocessing import Process, Queue
|
|
4
|
+
from .file import save, delete, write_instance_file, load_tsv, existing_file
|
|
5
|
+
import clingo
|
|
6
|
+
from . import color, logger
|
|
7
|
+
from os import path
|
|
8
|
+
import random
|
|
9
|
+
from time import time
|
|
10
|
+
from json import loads
|
|
11
|
+
|
|
12
|
+
###################################################################
|
|
13
|
+
############# Class HybridReasoning : herit Solver ################
|
|
14
|
+
###################################################################
|
|
15
|
+
class HybridReasoning(Solver):
|
|
16
|
+
def __init__(self, run_mode:str, network:Network,
|
|
17
|
+
time_limit_minute:float=None, number_solution:int=None,
|
|
18
|
+
clingo_configuration:str=None, clingo_strategy:str=None,
|
|
19
|
+
intersection:bool=False, union:bool=False,
|
|
20
|
+
minimize:bool=False, subset_minimal:bool=False,
|
|
21
|
+
temp_dir:str=None, short_option:str=None, run_solve:str=None,
|
|
22
|
+
verbose:bool=False, community_mode:str=None,all_transfers:bool=False):
|
|
23
|
+
"""Initialize Object HybridReasoning, herit from Solver
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
run_mode (str): Running command used (full or target)
|
|
27
|
+
network (Network): Network constructed
|
|
28
|
+
time_limit_minute (float, optional): Time limit given by user in minutes. Defaults to None.
|
|
29
|
+
number_solution (int, optional): Limit number of solutions to find. Defaults to None.
|
|
30
|
+
clingo_configuration (str, optional): Configuration for clingo resolution. Defaults to None.
|
|
31
|
+
clingo_strategy (str, optional): Strategy for clingo resolution. Defaults to None.
|
|
32
|
+
intersection (bool, optional): Find the intersection of all solutions without limitation (give one solution). Defaults to False.
|
|
33
|
+
union (bool, optional): Find the union of all solutions without limitation (give one solution). Defaults to False.
|
|
34
|
+
minimize (bool, optional): Search the minimal carinality of solutions. Defaults to False.
|
|
35
|
+
subset_minimal (bool, optional): Search the subset minimal solutions. Defaults to False.
|
|
36
|
+
temp_dir (str, optional): Temporary directory for saving instance file and clingo outputs. Defaults to None.
|
|
37
|
+
short_option (str, optional): Short way to write option on filename. Defaults to None.
|
|
38
|
+
verbose (bool, optional): Set debug mode. Defaults to False.
|
|
39
|
+
"""
|
|
40
|
+
super().__init__(run_mode, network, time_limit_minute, number_solution, clingo_configuration,
|
|
41
|
+
clingo_strategy, intersection, union, minimize, subset_minimal,
|
|
42
|
+
temp_dir, short_option, run_solve, verbose, community_mode)
|
|
43
|
+
|
|
44
|
+
self.all_transfers = all_transfers
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
######################## METHODS ########################
|
|
48
|
+
|
|
49
|
+
def control_init(self, full_option:list, asp_files:list, is_guess_check:bool=False):
|
|
50
|
+
"""Initiate Clingo control for package Clingo
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
full_option (list): All Clingo option
|
|
54
|
+
asp_files (list): List of needed ASP files to solve ASP (Clingo package)
|
|
55
|
+
is_guess_check (bool, optional): Determine if it is a Guess Check (True) or a Filter (Fale).
|
|
56
|
+
Defaults to False.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
ctrl (clingo.Control): Return Clingo control for solving
|
|
60
|
+
"""
|
|
61
|
+
if "--warn=none" not in full_option:
|
|
62
|
+
full_option.append("--warn=none")
|
|
63
|
+
ctrl = clingo.Control(full_option)
|
|
64
|
+
|
|
65
|
+
for file in asp_files:
|
|
66
|
+
ctrl.load(file)
|
|
67
|
+
|
|
68
|
+
ctrl.ground([("base",[])])
|
|
69
|
+
if self.diversity and is_guess_check:
|
|
70
|
+
ctrl.add("diversity", [], """
|
|
71
|
+
#program diversity.
|
|
72
|
+
#heuristic new_seed(M) : avoidseed(M). [10,false]
|
|
73
|
+
#heuristic new_seed(M). [1,false] % subset
|
|
74
|
+
#external avoidseed(M) : metabolite(M,_).
|
|
75
|
+
""")
|
|
76
|
+
ctrl.ground([("diversity",[])])
|
|
77
|
+
|
|
78
|
+
self.get_message("command")
|
|
79
|
+
logger.print_log('clingo ' + ' '.join(full_option) + ' ' + ' '.join(asp_files), 'debug')
|
|
80
|
+
return ctrl
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def get_constructed_result(self, time_solve:float, timer:dict, results:dict, solution_list:dict, number_rejected:int):
|
|
84
|
+
"""Complete and structure the resulted dictionnary
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
time_solve (float): Solving time
|
|
88
|
+
timer (dict): dictionnary of timers (with other timer if exists)
|
|
89
|
+
results (dict): final dictionnary of results
|
|
90
|
+
solution_list (dict): Dictionnary containing the models resulted for one mode (reasoning, filter, guess-check ...)
|
|
91
|
+
number_rejected (int): Used for hybrid-cobra modes (filter, guess-check, guesscheck div)
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
dict: results
|
|
95
|
+
"""
|
|
96
|
+
if time_solve != -1:
|
|
97
|
+
timer["Solving time"] = round(time_solve, 3)
|
|
98
|
+
else:
|
|
99
|
+
timer["Solving time"] = "Time out"
|
|
100
|
+
results["Timer"] = timer.copy()
|
|
101
|
+
results['solutions'] = solution_list
|
|
102
|
+
if number_rejected is not None:
|
|
103
|
+
results['rejected'] = number_rejected
|
|
104
|
+
return results
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def save_seeds_tmp(self, seeds_fact:str, idx:int):
|
|
108
|
+
"""Save seeds as asp fact in temporary file for bistep mode in community after the first step which find and subset min only on seeds
|
|
109
|
+
to be able to retrieve the seeds as an asp file and do the second step which found the first solution of subsetminimal transfers with
|
|
110
|
+
those saved seeds
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
seeds_fact (str): seeds converted into asp facts
|
|
114
|
+
idx (int): index of the soulution (solution number idx)
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
str: seeds_temp_file
|
|
118
|
+
"""
|
|
119
|
+
# create a temporary seeds instance file
|
|
120
|
+
seeds_temp_file=f"seeds_model_{idx}_{self.temp_result_file}.lp"
|
|
121
|
+
seeds_temp_file=path.join(self.temp_dir,seeds_temp_file)
|
|
122
|
+
write_instance_file(seeds_temp_file, seeds_fact)
|
|
123
|
+
return seeds_temp_file
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def get_transfers_info(self, list_transferred:list):
|
|
127
|
+
"""From list of transferred, get datas and structure them into a dictionnary for output result file
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
list_transferred (list): List of transferred metabolite
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
str,str,list: transf_short (size of transfers), trans_complete (line of printed transfers), trans_solution_list
|
|
134
|
+
"""
|
|
135
|
+
size_transf = len(list_transferred)
|
|
136
|
+
trans_complete=None
|
|
137
|
+
trans_solution_list=list()
|
|
138
|
+
if not self.network.is_community:
|
|
139
|
+
transf_short = ""
|
|
140
|
+
elif size_transf>0:
|
|
141
|
+
transf_short = f" and {size_transf} transfers"
|
|
142
|
+
trans_complete = f"\n Transfers {color.cyan_dark}|{color.reset} From {color.cyan_dark}|{color.reset} To\n"
|
|
143
|
+
trans_complete += f"--------------{color.cyan_dark}|{color.reset}--------------{color.cyan_dark}|{color.reset}--------------\n"
|
|
144
|
+
for meta in list_transferred:
|
|
145
|
+
# When we get the data from temp file, it is already formated as dictionnary
|
|
146
|
+
if type(meta) == dict:
|
|
147
|
+
dict_transf=meta
|
|
148
|
+
else:
|
|
149
|
+
dict_transf=dict()
|
|
150
|
+
dict_transf["Metabolite"] = str(meta[0]).replace('"','')
|
|
151
|
+
dict_transf["From"] = str(meta[1]).replace('"','')
|
|
152
|
+
dict_transf["To"] = str(meta[2]).replace('"','')
|
|
153
|
+
dict_transf["ID from"] = str(meta[3]).replace('"','')
|
|
154
|
+
dict_transf["ID to"] = str(meta[4]).replace('"','')
|
|
155
|
+
trans_complete += f'{dict_transf["Metabolite"]} {color.cyan_dark}|{color.reset} {dict_transf["From"]} {color.cyan_dark}|{color.reset} {dict_transf["To"]}\n'
|
|
156
|
+
trans_solution_list.append(dict_transf)
|
|
157
|
+
else:
|
|
158
|
+
transf_short = f" and no transfers"
|
|
159
|
+
|
|
160
|
+
return transf_short, trans_complete, trans_solution_list
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def complete_option(self, full_option:list, nb_sol:int):
|
|
164
|
+
"""Convert the list of clingo options into string and complete it with the wanted number of solutions.
|
|
165
|
+
The number of solutions depends on if we are minimizing the solution, or if we want to find the only the first
|
|
166
|
+
subset minimal of solutions.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
full_option (list): List of clingo options
|
|
170
|
+
nb_sol (int): number of solutions to ask to clingo
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
str: complete_option
|
|
174
|
+
"""
|
|
175
|
+
complete_option=full_option.copy()
|
|
176
|
+
complete_option.append(f'-n {nb_sol}')
|
|
177
|
+
return complete_option
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def get_transfers_asp_file(self):
|
|
181
|
+
"""Remove seed solving files and get transfers file for asp solving.
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
list: list of path to asp files
|
|
185
|
+
"""
|
|
186
|
+
transf_asp_files=self.asp_files.copy()
|
|
187
|
+
transf_asp_files.remove(self.asp.ASP_SRC_SEED_SOLVING)
|
|
188
|
+
transf_asp_files.remove(self.asp.ASP_SRC_SHOW_SEEDS)
|
|
189
|
+
transf_asp_files.append(self.asp.ASP_SRC_ATOM_TRANSF)
|
|
190
|
+
transf_asp_files.append(self.asp.ASP_SRC_SHOW_TRANSFERS)
|
|
191
|
+
return transf_asp_files
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def convert_seeds_to_fact(self, args:tuple, seeds_fact:str, is_supsetconstraint:bool = False):
|
|
195
|
+
"""Convert either seeds into asp seeds fact (bisteps mode) or constraints from seeds
|
|
196
|
+
to forbid set of seed as solution for next solve and constraints for superset of seeds
|
|
197
|
+
to frobid solution including set of seeds (delsupset mode)
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
args (tuple): Atom argument from clingo
|
|
201
|
+
seeds_fact (str): Seeds asp fact convert to string to complete
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
str: seeds_fact
|
|
205
|
+
"""
|
|
206
|
+
metabolite_id=str(args[0]).replace('"','')
|
|
207
|
+
metabolite_flag=str(args[1]).replace('"','')
|
|
208
|
+
metabolite_name=str(args[2]).replace('"','')
|
|
209
|
+
species=str(args[3]).replace('"','')
|
|
210
|
+
match self.community_mode:
|
|
211
|
+
case "bisteps":
|
|
212
|
+
seeds_fact += f'\nseed("{metabolite_id}","{metabolite_flag}","{metabolite_name}","{species}").'
|
|
213
|
+
# in case of delete superset, we do not need to create seeds fact but we need to add constraints
|
|
214
|
+
case "delsupset":
|
|
215
|
+
# Superset of set of seeds to forget for next search
|
|
216
|
+
if is_supsetconstraint:
|
|
217
|
+
seeds_fact += f', seed("{metabolite_id}","{metabolite_flag}","{metabolite_name}","{species}"), X!="{metabolite_id}"'
|
|
218
|
+
# Set of seeds to forget for next search
|
|
219
|
+
else:
|
|
220
|
+
if "seed" in seeds_fact:
|
|
221
|
+
seeds_fact += ', '
|
|
222
|
+
seeds_fact += f'seed("{metabolite_id}","{metabolite_flag}","{metabolite_name}","{species}")'
|
|
223
|
+
return seeds_fact
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def get_seeds_transfers(self, atoms):
|
|
227
|
+
"""Get Seeds solution from atoms for all modes and transfers for communtiy mode.
|
|
228
|
+
For delete superset mode, can create the needed constraints (forbid set of seeds and its super set for next search).
|
|
229
|
+
Return a list of seeds (onlyname), but also list of full seeds (all data from seeds atom), a list of transferred metabolites
|
|
230
|
+
if needed and the complete contraints to add to clingo.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
atoms: clingo atoms (returned by solver)
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
list, list, list, str: seeds, seeds_full, transferred, seed_complete_constraints
|
|
237
|
+
"""
|
|
238
|
+
seeds = list()
|
|
239
|
+
seeds_full = list()
|
|
240
|
+
transferred = list()
|
|
241
|
+
seed_constraints=":- "
|
|
242
|
+
seed_superset_constraints=":- seed(X,_,_,_)"
|
|
243
|
+
seed_complete_constraints=""
|
|
244
|
+
transfer_constraints=""
|
|
245
|
+
# For single network search, there is only seed, not transfer
|
|
246
|
+
if not self.network.is_community:
|
|
247
|
+
for a in atoms:
|
|
248
|
+
if a.name == "seed":
|
|
249
|
+
seeds.append(a.arguments[0].string)
|
|
250
|
+
seeds=list(sorted(seeds))
|
|
251
|
+
else:
|
|
252
|
+
for a in atoms:
|
|
253
|
+
if a.name == "seed":
|
|
254
|
+
seeds.append(a.arguments[0].string)
|
|
255
|
+
seeds_full.append(a.arguments)
|
|
256
|
+
if self.community_mode=="delsupset":
|
|
257
|
+
seed_constraints = self.convert_seeds_to_fact(a.arguments, seed_constraints)
|
|
258
|
+
seed_superset_constraints = self.convert_seeds_to_fact(a.arguments, seed_superset_constraints,True)
|
|
259
|
+
elif a.name == "transferred":
|
|
260
|
+
transferred.append(a.arguments)
|
|
261
|
+
seeds=list(sorted(seeds))
|
|
262
|
+
transferred=list(sorted(transferred))
|
|
263
|
+
if self.all_transfers:
|
|
264
|
+
for transfer in transferred:
|
|
265
|
+
transfer_constraints+=f", transferred({transfer[0]},{transfer[1]},{transfer[2]},{transfer[3]},{transfer[4]})"
|
|
266
|
+
seed_complete_constraints = seed_constraints+transfer_constraints+".\n"+seed_superset_constraints+"."
|
|
267
|
+
|
|
268
|
+
return seeds, seeds_full, transferred, seed_complete_constraints
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def complete_solutions(self, solution_list:dict, solution_name:str, size:int, seeds:list,
|
|
272
|
+
trans_solution_list:list=None, cobra_flux:dict=None, number_rejected:int=None):
|
|
273
|
+
"""Complete the solutions ilst and the solution temporary list to save due to of multiprocessing.
|
|
274
|
+
This function is used for filter and guess_check function, but also for delete superset mode in community
|
|
275
|
+
which also use multiprocessing du create constraints while searching solution
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
solution_list (dict): Dictionnary of solutions by name (model idx)
|
|
279
|
+
solution_name (str): Current solution name
|
|
280
|
+
size (int): size of set of seeds
|
|
281
|
+
seeds (list): list of seeds
|
|
282
|
+
trans_solution_list (list): list of transfers solution
|
|
283
|
+
cobra_flux (dict, optional): Cobra flux found for solution if exists. Defaults to None.
|
|
284
|
+
number_rejected (int, optional): Number of rejected soution if exists. Defaults to None.
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
dict, list: solution_list, solution_temp
|
|
288
|
+
"""
|
|
289
|
+
solution_temp=None
|
|
290
|
+
|
|
291
|
+
seeds=list(sorted(seeds))
|
|
292
|
+
solution = ["size", size] + ["Set of seeds", seeds]
|
|
293
|
+
if self.network.is_community:
|
|
294
|
+
solution += ["Set of transferred", trans_solution_list]
|
|
295
|
+
# Solutions from filter and guess check
|
|
296
|
+
if cobra_flux or \
|
|
297
|
+
(self.network.is_community and self.community_mode!="global"):
|
|
298
|
+
if cobra_flux:
|
|
299
|
+
solution += ["Cobra flux", cobra_flux]
|
|
300
|
+
solution_temp = [solution_name, size, seeds, number_rejected, cobra_flux]
|
|
301
|
+
if self.network.is_community:
|
|
302
|
+
solution_temp.append(trans_solution_list)
|
|
303
|
+
solution_list[solution_name]=solution
|
|
304
|
+
return solution_list, solution_temp
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def add_diversity(self, ctrl:clingo.Control, seeds:list, avoided:list):
|
|
308
|
+
"""This function add diversity for the Gess Check mode by avoiding some metabolites
|
|
309
|
+
from previous solution. For each iteration, half of the avoided metabolites is
|
|
310
|
+
deleted randomly, and half of metabolites as seeds of the current solution is added randomly
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
ctrl (clingo.Control): Clingo Control initiated
|
|
314
|
+
seeds (list): List of seeds (one solution)
|
|
315
|
+
avoided (list): List of already avoided metabolites
|
|
316
|
+
|
|
317
|
+
Returns:
|
|
318
|
+
ctrl (clingo.Control), avoided (list): Return Clingo control for solving
|
|
319
|
+
and the new list of avoided metabolites for next iteration
|
|
320
|
+
"""
|
|
321
|
+
forget = 50 # 0..100: percentage of heuristics to forget at each iteration
|
|
322
|
+
|
|
323
|
+
# tune heuristics for diversity
|
|
324
|
+
random.shuffle(avoided)
|
|
325
|
+
clue_to_forget = (len(avoided)*forget)//100
|
|
326
|
+
for a in avoided[:clue_to_forget]:
|
|
327
|
+
ctrl.assign_external(a, False)
|
|
328
|
+
avoided = avoided[clue_to_forget:]
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
random.shuffle(seeds)
|
|
332
|
+
seed_to_forget = (len(seeds)*forget)//100
|
|
333
|
+
seeds = seeds[seed_to_forget:]
|
|
334
|
+
|
|
335
|
+
clues = [clingo.Function("avoidseed", [clingo.String(s)]) for s in seeds]
|
|
336
|
+
|
|
337
|
+
for a in clues:
|
|
338
|
+
ctrl.assign_external(a, True)
|
|
339
|
+
avoided.extend(clues)
|
|
340
|
+
|
|
341
|
+
return ctrl, avoided
|
|
342
|
+
|
|
343
|
+
def get_solution_from_temp(self, unsat:bool, is_one_model:bool, full_path:str, suffix:str, search_mode:str):
|
|
344
|
+
"""Get the solution written in temporary file during execution fo seed searching while using
|
|
345
|
+
multiprocessing.
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
unsat (bool): Determine if the model is unsat
|
|
349
|
+
is_one_model (bool): Determine if the model is the optimum finding model for minimize case
|
|
350
|
+
full_path (str): Path of temporary file
|
|
351
|
+
suffix (str): suffix to add for solution enumeration (filter or guess-check)
|
|
352
|
+
search_mode (str): search_mode needed to add to results (subset minimal or minimize)
|
|
353
|
+
|
|
354
|
+
Returns:
|
|
355
|
+
dict, str: list of solutions, number of rejected solution
|
|
356
|
+
"""
|
|
357
|
+
solution_list = dict()
|
|
358
|
+
number_rejected = None
|
|
359
|
+
transferred_list = None
|
|
360
|
+
if not unsat and existing_file(full_path):
|
|
361
|
+
# in case of enumeration it is needed to get the results back from the saved temporary
|
|
362
|
+
# file which is saved during the called
|
|
363
|
+
column_len = 5
|
|
364
|
+
if self.network.is_community:
|
|
365
|
+
column_len = 6
|
|
366
|
+
if not is_one_model:
|
|
367
|
+
try:
|
|
368
|
+
temp_list = load_tsv(full_path)
|
|
369
|
+
for solution in temp_list:
|
|
370
|
+
if len(solution) == column_len:
|
|
371
|
+
# some line has no data value onlu the number of rejected solution
|
|
372
|
+
if solution[0]:
|
|
373
|
+
seeds = solution[2].replace(" ", "")
|
|
374
|
+
seeds = seeds.replace("\'", "")
|
|
375
|
+
seeds_list = seeds[1:-1].split(',')
|
|
376
|
+
|
|
377
|
+
sol = ["size", solution[1]] + \
|
|
378
|
+
["Set of seeds",seeds_list]
|
|
379
|
+
if self.network.is_community:
|
|
380
|
+
transferred_list = eval(solution[5])
|
|
381
|
+
sol += ["Set of transferred", transferred_list]
|
|
382
|
+
|
|
383
|
+
cobra_dict = loads(solution[4].replace("'",'"'))
|
|
384
|
+
sol += ["Cobra flux", cobra_dict]
|
|
385
|
+
solution_list[solution[0]] = sol
|
|
386
|
+
#get the last occurence pf rejected solutions number
|
|
387
|
+
number_rejected = solution[3]
|
|
388
|
+
logger.print_log(f'Rejected solution during process: at least {number_rejected} \n', 'info')
|
|
389
|
+
except Exception as e:
|
|
390
|
+
logger.print_log(f"An error occured while reading temporary file\n {full_path}:\n {e}", 'error')
|
|
391
|
+
|
|
392
|
+
if any(solution_list):
|
|
393
|
+
for name in solution_list:
|
|
394
|
+
seeds = solution_list[name][3]
|
|
395
|
+
self.network.add_result_seeds('REASONING '+suffix, search_mode, name, len(seeds), seeds, transferred_list=transferred_list)
|
|
396
|
+
delete(full_path)
|
|
397
|
+
return solution_list, number_rejected
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def solve_hybrid(self, step:str, full_option:list, asp_files:list, search_mode:str, is_one_model:bool):
|
|
402
|
+
"""Solve hybrid-cobra mode depending step (filter, guess_check, guess_check_div)
|
|
403
|
+
|
|
404
|
+
Args:
|
|
405
|
+
step (str): Hybrid solving mode (filter, guess_check, guess_check_div)
|
|
406
|
+
full_option (list): List of clingo options
|
|
407
|
+
asp_files (list): list of path to asp files
|
|
408
|
+
search_mode (str): Search mode (minimize or subset minimal)
|
|
409
|
+
is_one_model (bool): Determine if the model is the optimum finding model for minimize case
|
|
410
|
+
|
|
411
|
+
Returns:
|
|
412
|
+
int, int, dict, str: time_solve, time_ground, solution_list, number_rejected
|
|
413
|
+
"""
|
|
414
|
+
# api clingo doesn't have time_limit option
|
|
415
|
+
# to add a time out, it is needed to call the function into a process
|
|
416
|
+
queue = Queue()
|
|
417
|
+
start=time()
|
|
418
|
+
if step == "filter":
|
|
419
|
+
suffix = " FILTER"
|
|
420
|
+
full_path = path.join(self.temp_dir,f"{self.temp_result_file}.tsv")
|
|
421
|
+
p = Process(target=self.filter, args=(queue, full_option, asp_files, search_mode, full_path, is_one_model))
|
|
422
|
+
elif "guess_check" in step:
|
|
423
|
+
suffix = " GUESS-CHECK"
|
|
424
|
+
self.diversity=False
|
|
425
|
+
if step == "guess_check_div":
|
|
426
|
+
suffix += "-DIVERSITY"
|
|
427
|
+
self.diversity=True
|
|
428
|
+
full_path = path.join(self.temp_dir,f"{self.temp_result_file}.tsv")
|
|
429
|
+
p = Process(target=self.guess_check, args=(queue, full_option, asp_files, search_mode, full_path, is_one_model))
|
|
430
|
+
|
|
431
|
+
p.start()
|
|
432
|
+
try:
|
|
433
|
+
# the time out limit is added here
|
|
434
|
+
obj, solution_list, time_ground, time_solve, number_rejected = queue.get(timeout=self.time_limit)
|
|
435
|
+
#solution_list, number_rejected = self.get_solution_from_temp(unsat, is_one_model, full_path, suffix, search_mode)
|
|
436
|
+
|
|
437
|
+
# Because of the process, the object is not change (encapsulated and isolated)
|
|
438
|
+
# it is needed to give get the output object and modify the current object
|
|
439
|
+
if "minimize" in search_mode:
|
|
440
|
+
self.optimum_found = obj.optimum_found
|
|
441
|
+
self.optimum = obj.optimum
|
|
442
|
+
self.get_separate_optimum()
|
|
443
|
+
self.network.result_seeds = obj.network.result_seeds
|
|
444
|
+
if not is_one_model:
|
|
445
|
+
delete(full_path)
|
|
446
|
+
except:
|
|
447
|
+
time_process=time() - start
|
|
448
|
+
time_ground = time_solve = -1
|
|
449
|
+
unsat = False
|
|
450
|
+
time_out = False
|
|
451
|
+
if not self.time_limit or time_process < self.time_limit:
|
|
452
|
+
unsat = True
|
|
453
|
+
else:
|
|
454
|
+
time_out = True
|
|
455
|
+
if time_out:
|
|
456
|
+
logger.print_log(f'Time out: {self.time_limit_minute} min expired', "error")
|
|
457
|
+
|
|
458
|
+
solution_list, number_rejected = self.get_solution_from_temp(unsat, is_one_model, full_path, suffix, search_mode)
|
|
459
|
+
p.terminate()
|
|
460
|
+
queue.close()
|
|
461
|
+
|
|
462
|
+
if is_one_model:
|
|
463
|
+
if not self.optimum_found:
|
|
464
|
+
logger.print_log('Optimum not found', "error")
|
|
465
|
+
else:
|
|
466
|
+
if not any(solution_list):
|
|
467
|
+
logger.print_log('Unsatisfiable problem', "error")
|
|
468
|
+
|
|
469
|
+
return time_solve, time_ground, solution_list, number_rejected
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
def print_answer(self, message:str, seeds:list, seeds_full:list, trans_complete:str):
|
|
473
|
+
"""Print into terminal the answer (set of seeds and transfers if exists)
|
|
474
|
+
|
|
475
|
+
Args:
|
|
476
|
+
message (str): Constructed message to print
|
|
477
|
+
seeds (list): list of seeds
|
|
478
|
+
seeds_full (list): list of seeds wit all data from asp atoms answer (species associated)
|
|
479
|
+
trans_complete (str): List of transfers with all data (metabolite, from, to)
|
|
480
|
+
"""
|
|
481
|
+
if not self.network.is_community:
|
|
482
|
+
for s in seeds:
|
|
483
|
+
message += f"{s}, "
|
|
484
|
+
message=message.rstrip(', ')
|
|
485
|
+
else:
|
|
486
|
+
seeds_dict=dict()
|
|
487
|
+
seeds_full = sorted(seeds_full, key=lambda x: x[0])
|
|
488
|
+
for s in seeds_full:
|
|
489
|
+
species = str(s[3]).replace('"','')
|
|
490
|
+
seed = str(s[2]).replace('"','')
|
|
491
|
+
if species in seeds_dict.keys():
|
|
492
|
+
seeds_dict[species]+= f', {seed}'
|
|
493
|
+
else:
|
|
494
|
+
seeds_dict[species] = f'{seed}'
|
|
495
|
+
for key, value in sorted(seeds_dict.items()):
|
|
496
|
+
message += color.cyan_dark + f'{key}:' + color.reset
|
|
497
|
+
message += f' {value}'
|
|
498
|
+
message = message.rstrip(', ')
|
|
499
|
+
message += "\n"
|
|
500
|
+
if trans_complete is None:
|
|
501
|
+
trans_complete=color.yellow+"No transferred metabolites\n"+color.reset
|
|
502
|
+
message += trans_complete #+ "\n"
|
|
503
|
+
print(message)
|
|
504
|
+
|
|
505
|
+
def temp_rejected(self, number_rejected:int, full_path:str):
|
|
506
|
+
"""Save temporary data for rejected number of solution when using cobra hybrid mode
|
|
507
|
+
|
|
508
|
+
Args:
|
|
509
|
+
number_rejected (int): _description_
|
|
510
|
+
full_path (str): Path of temporary file
|
|
511
|
+
"""
|
|
512
|
+
solution_temp = [None, None, None, number_rejected, None]
|
|
513
|
+
if self.network.is_community:
|
|
514
|
+
solution_temp.append(None)
|
|
515
|
+
save(full_path, "", solution_temp, "tsv", True)
|
|
516
|
+
|
|
517
|
+
def filter(self, queue:Queue, full_option:list, asp_files:list, search_mode:str, full_path:str, is_one_model:bool=False):
|
|
518
|
+
"""Filter mode. Find a solution with Clingo package, check if the solution has flux on objective reaction.
|
|
519
|
+
This function works with multiprocessing in order to manage time limit.
|
|
520
|
+
It does not interact with the solver, only filter the solutions.
|
|
521
|
+
|
|
522
|
+
Args:
|
|
523
|
+
queue (Queue): Queue for multiprocessing program (managing time limit)
|
|
524
|
+
full_option (list): All Clingo option
|
|
525
|
+
asp_files (list): List of needed ASP files to solve ASP (Clingo package)
|
|
526
|
+
search_mode (str): Optimization selected for the search (submin/minmize and enumeration/optimum)
|
|
527
|
+
full_path (str): Full path for temp file needed to get back solution when time out
|
|
528
|
+
is_one_model (bool, optional): Define if the solution we want is to fin the optimum when minimize is used (before enumration).
|
|
529
|
+
Defaults to False.
|
|
530
|
+
"""
|
|
531
|
+
solution_list = dict()
|
|
532
|
+
|
|
533
|
+
no_limit_solution = False
|
|
534
|
+
if self.number_solution == 0:
|
|
535
|
+
no_limit_solution = True
|
|
536
|
+
|
|
537
|
+
full_option_seeds = self.complete_option(full_option,0)
|
|
538
|
+
|
|
539
|
+
ctrl = self.control_init(full_option_seeds, asp_files)
|
|
540
|
+
solution_idx = 1
|
|
541
|
+
number_rejected = 0
|
|
542
|
+
start_time=time()
|
|
543
|
+
with ctrl.solve(yield_=True) as h:
|
|
544
|
+
for model in h:
|
|
545
|
+
if (len(solution_list) < self.number_solution \
|
|
546
|
+
and not is_one_model and not no_limit_solution) \
|
|
547
|
+
or is_one_model or no_limit_solution:
|
|
548
|
+
atoms = model.symbols(shown=True)
|
|
549
|
+
seeds, seeds_full, transferred, _ = self.get_seeds_transfers(atoms)
|
|
550
|
+
size = len(seeds)
|
|
551
|
+
transf_short, trans_complete, trans_solution_list =self.get_transfers_info(transferred)
|
|
552
|
+
|
|
553
|
+
if not is_one_model:
|
|
554
|
+
res = self.network.check_seeds(seeds, trans_solution_list)
|
|
555
|
+
if res[0]:
|
|
556
|
+
# valid solution
|
|
557
|
+
logger.print_log(f'CHECK Solution {size} seeds -> OK\n', 'debug')
|
|
558
|
+
|
|
559
|
+
message = color.cyan_light + f"Answer: {solution_idx}{color.reset} ({size} seeds{transf_short})\n"
|
|
560
|
+
self.print_answer(message, seeds, seeds_full, trans_complete)
|
|
561
|
+
name = 'model_'+str(solution_idx)
|
|
562
|
+
|
|
563
|
+
solution_list, solution_temp = self.complete_solutions(solution_list, name, size, seeds,
|
|
564
|
+
trans_solution_list, res[1], number_rejected)
|
|
565
|
+
|
|
566
|
+
save(full_path, self.temp_dir, solution_temp, "tsv", True)
|
|
567
|
+
self.network.add_result_seeds('REASONING FILTER', search_mode, name, size, seeds, flux_cobra=res[1], transferred_list=trans_solution_list)
|
|
568
|
+
solution_idx +=1
|
|
569
|
+
else:
|
|
570
|
+
logger.print_log(f'CHECK Solution {size} seeds -> KO\n', 'debug')
|
|
571
|
+
number_rejected +=1
|
|
572
|
+
current_timer = time() - start_time
|
|
573
|
+
# write all 100 rejected
|
|
574
|
+
# or write from 5 minute before finishing the process near to finish the process
|
|
575
|
+
if number_rejected%100 == 0 \
|
|
576
|
+
or (current_timer!=0 and current_timer > self.time_limit_minute*60 - 300):
|
|
577
|
+
self.temp_rejected(number_rejected, full_path)
|
|
578
|
+
# This means we are in "is_one_model", we are searching for minimize
|
|
579
|
+
# there is no minimize with community mode
|
|
580
|
+
else:
|
|
581
|
+
res = self.network.check_seeds(seeds, transferred)
|
|
582
|
+
self.optimum=model.cost
|
|
583
|
+
self.get_separate_optimum()
|
|
584
|
+
name = 'model_one_solution'
|
|
585
|
+
solution_list, solution_temp = self.complete_solutions(solution_list, name, size, seeds,
|
|
586
|
+
trans_solution_list, res[1], number_rejected)
|
|
587
|
+
self.optimum_found = True
|
|
588
|
+
else:
|
|
589
|
+
break
|
|
590
|
+
|
|
591
|
+
logger.print_log(f'Rejected solution during process: {number_rejected} \n', "info")
|
|
592
|
+
|
|
593
|
+
stats = ctrl.statistics
|
|
594
|
+
total_time = stats["summary"]["times"]["total"]
|
|
595
|
+
time_solve = stats["summary"]["times"]["solve"]
|
|
596
|
+
time_ground = total_time - time_solve
|
|
597
|
+
|
|
598
|
+
# Because it is needed to get all answers from clingo to have optimum, we save it after
|
|
599
|
+
# No minimize in community mode
|
|
600
|
+
if is_one_model and self.optimum_found:
|
|
601
|
+
logger.print_log(f"Optimum found.", "info")
|
|
602
|
+
if self.network.is_subseed:
|
|
603
|
+
logger.print_log(f"Number of producible targets: {- self.opt_prod_tgt}", "info")
|
|
604
|
+
logger.print_log(f"Minimal size of seed set is {self.opt_size}\n", "info")
|
|
605
|
+
save(full_path, self.temp_dir, solution_temp, "tsv", True)
|
|
606
|
+
self.network.add_result_seeds('REASONING FILTER', search_mode, name, size, seeds, flux_cobra=res[1], transferred_list=trans_solution_list)
|
|
607
|
+
|
|
608
|
+
ctrl.cleanup()
|
|
609
|
+
ctrl.interrupt()
|
|
610
|
+
queue.put([self, solution_list, time_ground, time_solve, number_rejected])
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
def guess_check_constraints(self, ctrl, atoms, seeds:list, avoided:list):
|
|
614
|
+
"""Add constraints to clingo controller for guess Check mode, and supplementary constraints for diversity mode.
|
|
615
|
+
|
|
616
|
+
Args:
|
|
617
|
+
ctrl: clingo controller to add constraints
|
|
618
|
+
atoms: clingo atoms
|
|
619
|
+
seeds (list): list of seeds
|
|
620
|
+
avoided (list): list of previous avoided seeds
|
|
621
|
+
|
|
622
|
+
Returns:
|
|
623
|
+
clingo controller, str, list: ctrl, mode, avoided (list of new avoided seeds)
|
|
624
|
+
"""
|
|
625
|
+
if atoms:
|
|
626
|
+
if self.diversity:
|
|
627
|
+
ctrl, avoided = self.add_diversity(ctrl, seeds, avoided)
|
|
628
|
+
# exclude solution and its superset
|
|
629
|
+
ctrl.add("skip", [], f":- {','.join(map(str,atoms))}.")
|
|
630
|
+
##################################################
|
|
631
|
+
# exclude only solution, keep superset
|
|
632
|
+
# not used because superset are so much that it founds less solutions
|
|
633
|
+
# than when we delete the superset (more networks work, more solution
|
|
634
|
+
# found per network)
|
|
635
|
+
# code kept in case it is needed
|
|
636
|
+
|
|
637
|
+
#ctrl.add("skip", [], f":- {','.join(map(str,atoms))}, #count{{M: seed(M,_)}} = {len(atoms)}.")
|
|
638
|
+
##################################################
|
|
639
|
+
ctrl.ground([("skip",[])])
|
|
640
|
+
return ctrl, avoided
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
def get_gc_mode(self):
|
|
644
|
+
mode = 'REASONING GUESS-CHECK'
|
|
645
|
+
if self.diversity:
|
|
646
|
+
mode = 'REASONING GUESS-CHECK DIVERSITY'
|
|
647
|
+
return mode
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
def guess_check(self, queue:Queue, full_option:list, asp_files:list, search_mode:str, full_path:str, is_one_model:bool=False):
|
|
651
|
+
"""Guess and Check mode. Find a solution with Clingo package, check if the solution has flux on objective reaction.
|
|
652
|
+
This function works with multiprocessing in order to manage time limit.
|
|
653
|
+
Interacts with ASP solver and exclude supersets of the current tested solution.
|
|
654
|
+
If diversity is asked, the function add_diversity is called.
|
|
655
|
+
|
|
656
|
+
Args:
|
|
657
|
+
queue (Queue): Queue for multiprocessing program (managing time limit)
|
|
658
|
+
full_option (list): All Clingo option
|
|
659
|
+
asp_files (list): List of needed ASP files to solve ASP (Clingo package)
|
|
660
|
+
search_mode (str): Optimization selected for the search (submin/minmize and enumeration/optimum)
|
|
661
|
+
full_path (str): Full path for temp file needed to get back solution when time out
|
|
662
|
+
is_one_model (bool, optional): Define if the solution we want is to fin the optimum when minimize is used (before enumration).
|
|
663
|
+
Defaults to False.
|
|
664
|
+
"""
|
|
665
|
+
solution_list = dict()
|
|
666
|
+
avoided = []
|
|
667
|
+
all_time_solve = 0
|
|
668
|
+
all_time_ground = 0
|
|
669
|
+
|
|
670
|
+
# No limit on number of solution
|
|
671
|
+
no_limit_solution = False
|
|
672
|
+
if self.number_solution == 0:
|
|
673
|
+
no_limit_solution = True
|
|
674
|
+
|
|
675
|
+
full_option_seeds = self.complete_option(full_option,0)
|
|
676
|
+
|
|
677
|
+
ctrl = self.control_init(full_option_seeds, asp_files, True)
|
|
678
|
+
solution_idx = 1
|
|
679
|
+
number_rejected = 0
|
|
680
|
+
start_time = time()
|
|
681
|
+
while ((len(solution_list) < self.number_solution \
|
|
682
|
+
and not is_one_model and not no_limit_solution) \
|
|
683
|
+
or is_one_model or no_limit_solution )\
|
|
684
|
+
and \
|
|
685
|
+
(self.time_limit and float(all_time_ground + all_time_solve) < float(self.time_limit)
|
|
686
|
+
or not self.time_limit):
|
|
687
|
+
with ctrl.solve(yield_=True) as h:
|
|
688
|
+
seeds = list()
|
|
689
|
+
transferred = list()
|
|
690
|
+
for model in h:
|
|
691
|
+
atoms = model.symbols(shown=True)
|
|
692
|
+
|
|
693
|
+
seeds, seeds_full, transferred, _ = self.get_seeds_transfers(atoms)
|
|
694
|
+
size = len(seeds)
|
|
695
|
+
|
|
696
|
+
transf_short, trans_complete, trans_solution_list =self.get_transfers_info(transferred)
|
|
697
|
+
|
|
698
|
+
# is_one_model is for minimize.
|
|
699
|
+
# Community doesn't have minimize
|
|
700
|
+
if not is_one_model:
|
|
701
|
+
break
|
|
702
|
+
else:
|
|
703
|
+
self.optimum=model.cost
|
|
704
|
+
if not seeds:
|
|
705
|
+
if is_one_model:
|
|
706
|
+
name = 'model_one_solution'
|
|
707
|
+
solution_list[name] = ["size", 0] + \
|
|
708
|
+
["Set of seeds", []]
|
|
709
|
+
self.optimum_found = True
|
|
710
|
+
else:
|
|
711
|
+
if transferred:
|
|
712
|
+
transf_short, trans_complete, trans_solution_list = self.get_transfers_info(transferred)
|
|
713
|
+
else:
|
|
714
|
+
transf_short = trans_complete = ""
|
|
715
|
+
trans_solution_list = list()
|
|
716
|
+
break
|
|
717
|
+
# Sum all grounding time together and all solving time together
|
|
718
|
+
stats = ctrl.statistics
|
|
719
|
+
total_time = stats["summary"]["times"]["total"]
|
|
720
|
+
time_solve = stats["summary"]["times"]["solve"]
|
|
721
|
+
time_ground = total_time - time_solve
|
|
722
|
+
|
|
723
|
+
all_time_solve += float(time_solve)
|
|
724
|
+
all_time_ground += float(time_ground)
|
|
725
|
+
res = self.network.check_seeds(seeds, trans_solution_list)
|
|
726
|
+
if res[0]:
|
|
727
|
+
logger.print_log(f'CHECK Solution {size} seeds -> OK\n', 'debug')
|
|
728
|
+
# valid solution
|
|
729
|
+
if not is_one_model:
|
|
730
|
+
message = color.cyan_light + f"Answer: {solution_idx}{color.reset} ({size} seeds{transf_short})\n"
|
|
731
|
+
self.print_answer(message, seeds, seeds_full, trans_complete)
|
|
732
|
+
name = 'model_'+str(solution_idx)
|
|
733
|
+
|
|
734
|
+
solution_list, solution_temp = self.complete_solutions(solution_list, name, size, seeds,
|
|
735
|
+
trans_solution_list, res[1], number_rejected)
|
|
736
|
+
save(full_path, "", solution_temp, "tsv", True)
|
|
737
|
+
# exclude solutions and its supersets
|
|
738
|
+
ctrl, avoided= self.guess_check_constraints(ctrl, atoms, seeds, avoided)
|
|
739
|
+
mode = self.get_gc_mode()
|
|
740
|
+
self.network.add_result_seeds(mode, search_mode, name, size, seeds, flux_cobra=res[1], transferred_list=trans_solution_list)
|
|
741
|
+
solution_idx +=1
|
|
742
|
+
else:
|
|
743
|
+
name = 'model_one_solution'
|
|
744
|
+
solution_list, solution_temp = self.complete_solutions(solution_list, name, size, seeds,
|
|
745
|
+
trans_solution_list, res[1], number_rejected)
|
|
746
|
+
logger.print_log(f"Optimum found.", "info")
|
|
747
|
+
self.optimum_found = True
|
|
748
|
+
mode = 'REASONING GUESS-CHECK'
|
|
749
|
+
# Do not exclude superset because we will rerun the minimize by set the size
|
|
750
|
+
# and we want to find back this first minimize found
|
|
751
|
+
if self.diversity:
|
|
752
|
+
ctrl, avoided = self.add_diversity(ctrl, seeds, avoided)
|
|
753
|
+
mode = 'REASONING GUESS-CHECK DIVERSITY'
|
|
754
|
+
save(full_path, self.temp_dir, solution_temp, "tsv", True)
|
|
755
|
+
|
|
756
|
+
self.network.add_result_seeds(mode, search_mode, name, size, seeds, flux_cobra=res[1], transferred_list=trans_solution_list)
|
|
757
|
+
self.get_separate_optimum()
|
|
758
|
+
if self.network.is_subseed:
|
|
759
|
+
logger.print_log(f"Number of producible targets: {- self.opt_prod_tgt}", "info")
|
|
760
|
+
logger.print_log(f"Minimal size of seed set is {self.opt_size}\n", "info")
|
|
761
|
+
break
|
|
762
|
+
|
|
763
|
+
else:
|
|
764
|
+
logger.print_log(f'CHECK Solution {size} seeds -> KO\n', 'debug')
|
|
765
|
+
#logger.print_log(f'{seeds}\n', 'debug')
|
|
766
|
+
|
|
767
|
+
ctrl, avoided= self.guess_check_constraints(ctrl, atoms, seeds, avoided)
|
|
768
|
+
mode = self.get_gc_mode()
|
|
769
|
+
number_rejected +=1
|
|
770
|
+
|
|
771
|
+
current_timer = time() - start_time
|
|
772
|
+
# write all 100 rejected
|
|
773
|
+
# or write from 5 minute before finishing the process near to finish the process
|
|
774
|
+
if number_rejected%100 == 0 \
|
|
775
|
+
or (current_timer!=0 and current_timer > self.time_limit_minute*60 - 300):
|
|
776
|
+
self.temp_rejected(number_rejected, full_path)
|
|
777
|
+
|
|
778
|
+
# Needed when all solutions are rejected and not 100 solution tested
|
|
779
|
+
# to retrieve the last number rejected and save into temp file
|
|
780
|
+
if not existing_file(full_path):
|
|
781
|
+
solution_temp = [None, None, None, number_rejected, None, None]
|
|
782
|
+
|
|
783
|
+
if not is_one_model:
|
|
784
|
+
save(full_path, "", solution_temp, "tsv", True)
|
|
785
|
+
logger.print_log(f'Rejected solution during process: {number_rejected} \n', 'info')
|
|
786
|
+
|
|
787
|
+
ctrl.cleanup()
|
|
788
|
+
ctrl.interrupt()
|
|
789
|
+
queue.put([self, solution_list, all_time_ground, all_time_solve, number_rejected])
|
|
790
|
+
|
|
791
|
+
########################################################
|