Управление генератором извне генератора (networkx simple_cycles)

51
4

Я использую NetworkX simple_cycles для генерации всех циклов, и я повторяю при условии разрыва, если обнаружен цикл размера k (k предоставляется пользователем).

try:
for cycle in nx.simple_cycles(G):
if len(cycle) == k:
checkval = True
break
if not checkval:
print "no path of size k"
except nx.NetworkXNoPath:
print "There was no path of size k"
checkval = False

В зависимости от графика простые_циклы могут в основном навсегда пытаться найти цикл размера k. Я хотел бы прекратить проверку через определенное количество времени. Я не могу остановиться на основе количества найденных циклов, потому что это ненадежно. Иногда 1 цикл можно найти в течение полной минуты, и через 30 секунд можно найти 100000 циклов.

Мой вопрос в том, есть ли способ остановить генератор на основе определенного количества времени, проходящего от OUTSIDE генератора.. или если единственным способом было бы изменить код самого генератора.

(Также будет оценен любой общий совет о том, что я пытаюсь сделать).

спросил(а) 2018-02-26T19:02:00+03:00 2 года, 1 месяц назад
1
Решение
53

Беда в том, что есть патологические угловые случаи... например, огромный огромный график с нулевыми циклами, так что для этого требуется слишком много времени, прежде чем даже первая итерация nx.simple_cycles(G) может завершиться.

В результате не будет возможности сделать это извне генератора, если вы не поместите выполнение в другой контекст, который вы можете завершить, например отдельный Process из multiprocessing, или запустите сопрограмму с asyncio.

Затем для каждого цикла, который выполняется асинхронно (либо из процесса, либо потока), вы можете проверить условие длины и условие на общее количество прошедшего времени и выбрать прекратить другой процесс/поток, если вы превысите ограничение по времени.

С другой стороны, если вам не nx.simple_cycles(G) этот тип углового футляра, и вы уверены, что значения, полученные nx.simple_cycles(G), вернутся в разумные сроки, тогда вы можете обернуть этот генератор, чтобы сделать ваш собственный генератор с ограничением по времени:

import time

def time_limited_cycles(G, time_limit=100.0):
elapsed, cycle_generator = 0.0, nx.simple_cycles(G)
while elapsed <= time_limit:
start_time = time.time()
try:
# crucial assumption here, that calling next on
# the original generator never takes too long.
cycle = next(cycle_generator)
except StopIteration:
break
yield cycle
elapsed += time.time() - start_time
# move elapsed above the yield line if you are looking
# to limit the internal runtime of the generator, rather
# than overall time spent processing cycles.

С помощью вышеизложенного вы можете заменить свое первоначальное использование nx.simple_cycles вызовом time_limited_cycles вместо этого (с вашим желаемым временным лимитом), а остальная часть вашего кода будет работать одинаково, потому что time_limited_cycles дает те же результаты цикла, что и nx.simple_cycles будет доходить до такой степени, что она прекратится.

ответил(а) 2018-02-26T19:11:00+03:00 2 года, 1 месяц назад
38

Часть, где вы проверяете длину, выглядит как хорошее место для начала. Использование time - также хорошая идея для синхронизации вещей. В верхней части кода вставьте:

from time import time

Перед циклом for вставьте:

time_to_wait = int (time()) + x # x is the time you want to wait. 

В вашем цикле for измените оператор if:

if len (cycle) == k or int (time()) == time_to_wait

Возможно, вы захотите сделать другой, if вместо его слияния, потому что тайм-аут все равно установит checkval в True, чего вы, возможно, не захотите. В этом случае просто оставьте первый, if один, и сделайте еще один:

if int (time()) == time_to_wait: break

ответил(а) 2018-02-26T19:16:00+03:00 2 года, 1 месяц назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема