Повторно выполнять правило Snakemake, пока не будут выполнены определенные условия.

Я хотел бы использовать Snakemake для потока, который требует многократного выполнения определенного шага до тех пор, пока не будут выполнены определенные условия. Заранее определить, сколько раз потребуется этот шаг, невозможно. Это может быть 1 или 6 или любое другое число.

Я нутром чувствую, что Snakemake не может этого сделать, потому что направленный ациклический граф и все такое...

Я надеялся, что контрольная точка может оказаться полезной, потому что она вызывает переоценку DAG, но я просто не могу понять, как именно она работает.

Возможна ли петля в Snakefile?

Спасибо!


Добавление некоторых комментариев о том, что на самом деле происходит, в отличном ответе ниже. Надеюсь, это поможет другим и мне, когда я неизбежно вернусь к этому вопросу.

all:  call function all_input to determine rule's input requirements.
all_input:  file "succes.txt" doesn't exist.  do checkpoint keep_trying with i == 1.     
keep_trying:  output "round_1" doesn't exist.  do run section.  random() decides to touch output[0], which is "round_1".

snakemake reevaluates graph after checkpoint is complete

all:  call function all_input to determine rule's input requirements.
all_input:  file "succes.txt" doesn't exist.  do checkpoint keep_trying with i == 2.
keep_trying:   output "round_2" doesn't exist.  do run section.  random() decides to touch output[0], which is "round_2".

snakemake reevaluates graph after checkpoint is complete

all:  call function all_input to determine rule's input requirements.
all_input:  file "succes.txt" doesn't exist.  do checkpoint keep_trying with i == 3.
keep_trying:  output "round_3" doesn't exist.  do run section.  random() decides to touch "succes.txt".

snakemake reevaluates graph after checkpoint is complete

all:  call function all_input to determine rule's input requirements.
all_input:  file "succes.txt" exists.  return "success.txt" to rule all.
all:  input requirement is "success.txt", which is now satisfied.

person jjarmagost    schedule 30.12.2019    source источник


Ответы (1)


Вы правы, что для этого нужны чекпоинты! Вот небольшой пример, который делает то, что вы хотите:

import os
from pathlib import Path


tries = 0
def all_input(wildcards):
    global tries
    if not os.path.exists("succes.txt"):
        tries += 1
        checkpoints.keep_trying.get(i=tries)
    else:
        return "succes.txt"


rule all:
    input:
        all_input


checkpoint keep_trying:
    output:
        "round_{i}"
    run:
        import random
        if random.random() > 0.9:
            Path('succes.txt').touch()
        Path(output[0]).touch()

Здесь мы говорим, что rule all требуется в качестве входных данных то, что возвращается функцией all_input. Эта функция проверяет, существует ли уже файл succes.txt. Если этого не произойдет, это приведет к запуску контрольной точки, продолжающей попытки, что может привести к созданию файла succes.txt (вероятность 10%). Если succes.txt действительно существует, то это входные данные для rule all, и змейка завершается успешно.

person Maarten-vd-Sande    schedule 30.12.2019