From a4ee75a1b1e9dc94ff8524b541326c365b072923 Mon Sep 17 00:00:00 2001 From: AlexanderMitrofanov Date: Mon, 12 Oct 2026 13:24:46 +0200 Subject: [PATCH] perf: finalize seed-extension partitions to reduce ensemble memory --- ChangeLog | 17 + README.md | 12 +- doc/Makefile.am | 4 + doc/benchmark-ensemble-memory.py | 107 + doc/ensemble-memory-benchmark.json | 2328 +++++++++++++++++ doc/ensemble-memory-probability-port.patch | 232 ++ doc/ensemble-memory.md | 183 ++ src/IntaRNA/PredictorMfeEns.cpp | 37 +- src/IntaRNA/PredictorMfeEns.h | 41 + ...redictorMfeEns2dHeuristicSeedExtension.cpp | 10 +- .../PredictorMfeEns2dSeedExtension.cpp | 28 +- src/IntaRNA/PredictorMfeEns2dSeedExtension.h | 9 + tests/PredictorMfeEnsRegression_test.cpp | 64 +- 13 files changed, 3048 insertions(+), 24 deletions(-) create mode 100644 doc/benchmark-ensemble-memory.py create mode 100644 doc/ensemble-memory-benchmark.json create mode 100644 doc/ensemble-memory-probability-port.patch create mode 100644 doc/ensemble-memory.md diff --git a/ChangeLog b/ChangeLog index de36b63d..1f906104 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,9 @@ ## Interface and handling +- reduce seed-extension ensemble memory by finalizing completed site sums and + storing smaller boundary keys; preserve partition/ranked output (issue #260) + - deterministic kinetic seed extension with --model=X --mode=K and configurable local scoring; complete-energy downhill steps, atomic noLP loop/stack moves and retained greedy traceback; equilibrium probability output is unsupported @@ -129,6 +132,20 @@ energies, restricted partition sums, and trackers. ################################################################################ ################################################################################ +261012 Alexander Mitrofanov + * PredictorMfeEns, PredictorMfeEns2dSeedExtension, + PredictorMfeEns2dHeuristicSeedExtension + + group partial site partitions by target right boundary with three-index keys + * finalize and release complete sums using the minimum remaining seed start, + preserving traversal, partition addition, filters and tracker callbacks + * reset the frontier for reused predictors and empty regions (issue #260) + * PredictorMfeEnsRegression_test.cpp + + compare streamed and buffered exact/heuristic predictions across LP/noLP, + stack/bulged/explicit seeds, cropped regions and repeated predictions + * README.md, doc/ensemble-memory*, doc/benchmark-ensemble-memory.py, doc/Makefile.am + + explain master/probability-branch memory differences and limits; provide + controlled runtime/RSS measurements, raw results and a tested forward port + 261007 Alexander Mitrofanov * doc/doxygen.cfg, doc/doxygen/* : + introduce the API main page with component links, prediction flow, diff --git a/README.md b/README.md index 8c12ed48..f9fe1e9b 100644 --- a/README.md +++ b/README.md @@ -814,9 +814,15 @@ See [IntaRNAexact personality](#IntaRNAexact) for additional information. ### Limiting memory consumption - window-based prediction -The memory requirement of IntaRNA grows quadratically with lengths of the input -sequences. Thus, for very long input RNAs, the requested memory can exceed the -available RAM of smaller computers. +Memory use depends on the predictor, sequence lengths and interaction span +limits. The ensemble model (`--model=P`) aggregates contributions from several +seeds to each interaction site and can need more memory than model X even when +their recurrence tables have the same dimensions. Seeded ensemble prediction +releases completed site sums during traversal to reduce peak memory; ensemble +trackers retain the deferred site information. See the +[memory audit and measurements](doc/ensemble-memory.md) for details. For very +long input RNAs, the requested memory can exceed the available RAM of smaller +computers. This can be circumvented by using a window-based prediction where the input sequences are decomposed in overlapping subsequences (windows) that are diff --git a/doc/Makefile.am b/doc/Makefile.am index cb78b081..dd56e412 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -4,6 +4,10 @@ ################################################################ EXTRA_DIST = \ + ensemble-memory.md \ + ensemble-memory-benchmark.json \ + ensemble-memory-probability-port.patch \ + benchmark-ensemble-memory.py \ conda.txt \ api-documentation.md \ build-api.sh \ diff --git a/doc/benchmark-ensemble-memory.py b/doc/benchmark-ensemble-memory.py new file mode 100644 index 00000000..1a9e51dd --- /dev/null +++ b/doc/benchmark-ensemble-memory.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 +"""Compare fresh-process peak RSS/runtime and prediction bytes for issue #260.""" +import argparse +import csv +import hashlib +import io +import json +from pathlib import Path +import random +import statistics +import subprocess + + +def canonical(output): + rows = list(csv.reader(io.StringIO(output), delimiter=';')) + return [rows[0], *sorted(rows[1:])] + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + for name in ('before', 'after', 'feat-before', 'feat-after'): + parser.add_argument('--'+name, type=Path, required=True) + parser.add_argument('--benchmark-dir', type=Path, required=True) + parser.add_argument('--outdir', type=Path, required=True) + parser.add_argument('--repeats', type=int, default=5) + parser.add_argument('--cases', nargs='+', help='Optional subset of named fixtures') + parser.add_argument('--models', nargs='+', choices=('X', 'P'), default=['X', 'P']) + args = parser.parse_args() + args.outdir.mkdir(parents=True, exist_ok=True) + fixtures = args.outdir/'fixtures' + fixtures.mkdir(exist_ok=True) + records = (args.benchmark_dir/'input/NC_000913/target/NC_000913.fa').read_text().split('>')[1:] + targets = {} + for count in (1, 8, 32): + targets[count] = fixtures/f'ecoli-{count}.fa' + targets[count].write_text('>'+'>'.join(records[:count])) + target, query = fixtures/'dense-target.fa', fixtures/'dense-query.fa' + target.write_text('>dense-target\n'+'G'*256+'\n') + query.write_text('>dense-query\n'+'C'*24+'\n') + query_dir = args.benchmark_dir/'input/NC_000913/query' + cases = [ + ('OxyS-one', targets[1], query_dir/'OxyS_NC_000913.fasta', 1, False, []), + ('OxyS-eight', targets[8], query_dir/'OxyS_NC_000913.fasta', 4, False, []), + ('GcvB-32', targets[32], query_dir/'GcvB_NC_000913.fasta', 4, False, []), + ('GcvB-32-noLP', targets[32], query_dir/'GcvB_NC_000913.fasta', 4, True, []), + ('dense256x24', target, query, 1, False, + ['--energy=B', '--acc=N', '--seedBP=4', '--intLoopMax=0']), + ] + binaries = {name: getattr(args, name.replace('-', '_')).resolve() + for name in ('before', 'after', 'feat-before', 'feat-after')} + raw, summary, commands = [], [], {} + for case, target, query, threads, noLP, extra in cases: + if args.cases and case not in args.cases: + continue + for model in args.models: + options = ['--target='+str(target.resolve()), '--query='+str(query.resolve()), + '--threads='+str(threads), '--model='+model, '--mode=H', + '--outNoLP='+str(noLP).lower(), '--tIntLenMax=80', + '--outMode=C', '--outNumber=1', '--default-log-file=/dev/null', + '--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall', *extra] + expected = None + for version, binary in binaries.items(): + command = [str(binary), *options] + commands[f'{case}/{model}/{version}'] = command + output = subprocess.run(command, check=True, capture_output=True, text=True, timeout=300).stdout + value = canonical(output) + if expected is None: + expected = value + assert value == expected, (case, model, version, value, expected) + (args.outdir/f'{case}-{model}-{version}.csv').write_text(output) + for repeat in range(args.repeats): + order = list(binaries) + random.Random(260+repeat).shuffle(order) + for version in order: + timing = args.outdir/'time.txt' + result = subprocess.run(['/usr/bin/time', '-f', '%e %U %S %M', '-o', str(timing), + *commands[f'{case}/{model}/{version}']], + check=True, capture_output=True, text=True, timeout=300) + if canonical(result.stdout) != expected: + (args.outdir/'mismatch.csv').write_text(result.stdout) + (args.outdir/'mismatch.stderr').write_text(result.stderr) + (args.outdir/'mismatch.json').write_text(json.dumps(dict(case=case, model=model, + version=version, repeat=repeat, expected=expected, + observed=canonical(result.stdout)), indent=2)+'\n') + raise AssertionError((case, model, version, repeat)) + wall, user, system, rss = map(float, timing.read_text().split()) + raw.append(dict(case=case, model=model, version=version, repeat=repeat, + wall=wall, user=user, system=system, rss_kib=rss)) + for version in binaries: + runs = [r for r in raw if (r['case'], r['model'], r['version']) == (case, model, version)] + summary.append(dict(case=case, model=model, version=version, + wall_median=statistics.median(r['wall'] for r in runs), + wall_min=min(r['wall'] for r in runs), wall_max=max(r['wall'] for r in runs), + rss_median_kib=statistics.median(r['rss_kib'] for r in runs))) + for filename, data in [('raw.json', raw), ('summary.json', summary), ('commands.json', commands)]: + (args.outdir/filename).write_text(json.dumps(data, indent=2)+'\n') + print('verified', case, model, flush=True) + metadata = dict(repeats=args.repeats, binaries={name: dict(path=str(path), + sha256=hashlib.sha256(path.read_bytes()).hexdigest()) for name, path in binaries.items()}, + methodology='Fresh processes, one correctness warmup; deterministically interleaved repetitions. ' + 'GNU time wall/user/system seconds and peak RSS KiB. Compare all CSV rows after sorting by contents ' + 'to account for thread completion order. Both model X and P are compared across all four binaries.') + (args.outdir/'metadata.json').write_text(json.dumps(metadata, indent=2)+'\n') + + +if __name__ == '__main__': + main() diff --git a/doc/ensemble-memory-benchmark.json b/doc/ensemble-memory-benchmark.json new file mode 100644 index 00000000..b0a84074 --- /dev/null +++ b/doc/ensemble-memory-benchmark.json @@ -0,0 +1,2328 @@ +{ + "metadata": { + "repeats": 3, + "binaries": { + "before": { + "path": "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-before", + "sha256": "5cd7c43ac9f27b523eb6bd0f12795bb730f85b70360f4a769fd64adea048cff5" + }, + "after": { + "path": "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-after", + "sha256": "a541343abfb6642055286a2ee344711553235f1e7e6a2acd589fc8b8b2571349" + }, + "feat-before": { + "path": "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-before", + "sha256": "3005137ae2bb09a835298186da2e834563b96e391efacb807af6b68d6a67dda4" + }, + "feat-after": { + "path": "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-after", + "sha256": "96fbb14c1fa6138d5e3cf9acd16d20e0da2b533686b26774b50cc8070dcc89fb" + } + }, + "methodology": "Fresh processes, one correctness warmup; deterministically interleaved repetitions. GNU time wall/user/system seconds and peak RSS KiB. Compare all CSV rows after sorting by contents to account for thread completion order. Both model X and P are compared across all four binaries.", + "repeats_by_case": { + "GcvB-32/P": 6, + "others": 3 + }, + "cpu_affinity": [ + 0, + 1, + 2, + 3 + ], + "compiler": "GCC 14.4, C++23, O3, Kokkos mdspan, double partitions", + "source_revisions": { + "master": "c5f1d51ce0f8d473b9a3e23ca2e0d410d92d77d7", + "probability": "c0ef61f1603ffc41c2ae4f8bbcf98b56027880e9" + }, + "fixture_sha256": { + "issue-260-validation/performance-last/fixtures/dense-query.fa": "ea9533ae2ececb209703bcaccb84b6abf93287d287b22fc8715dd36b901ddc1f", + "issue-260-validation/performance-last/fixtures/dense-target.fa": "cd47fde2aa6c5da5446225f18b107d46f1c3015eb6c42d407ac3554360d620ad", + "issue-260-validation/performance-last/fixtures/ecoli-1.fa": "0aeaccf63a328651292b5c8c529afd6e53bfbc4c27fb94afdc192ec60c7fe5a7", + "issue-260-validation/performance-last/fixtures/ecoli-32.fa": "193d51854548bb427902a401fa664524a4221bbf80016ac4a411cc2c80719876", + "issue-260-validation/performance-last/fixtures/ecoli-8.fa": "6b2d02e1bfc44a94d162611a1ee48347afb4966f243796a3f527a1265155ad4e" + }, + "query_sha256": { + "OxyS": "20a29f18416deef72cf0fe8f709b01b18984208b1ebb2a980d16454854a42328", + "GcvB": "5cb9b6dc5b9c17c77a5546465e54d9d07a1d14fdaf862498d337b752dcf40c14" + } + }, + "summary": [ + { + "case": "OxyS-one", + "model": "X", + "version": "before", + "wall_median": 0.14, + "wall_min": 0.14, + "wall_max": 0.14, + "rss_median_kib": 19120.0 + }, + { + "case": "OxyS-one", + "model": "X", + "version": "after", + "wall_median": 0.14, + "wall_min": 0.14, + "wall_max": 0.14, + "rss_median_kib": 18996.0 + }, + { + "case": "OxyS-one", + "model": "X", + "version": "feat-before", + "wall_median": 0.14, + "wall_min": 0.14, + "wall_max": 0.14, + "rss_median_kib": 19124.0 + }, + { + "case": "OxyS-one", + "model": "X", + "version": "feat-after", + "wall_median": 0.14, + "wall_min": 0.14, + "wall_max": 0.14, + "rss_median_kib": 19124.0 + }, + { + "case": "OxyS-one", + "model": "P", + "version": "before", + "wall_median": 0.14, + "wall_min": 0.14, + "wall_max": 0.15, + "rss_median_kib": 19124.0 + }, + { + "case": "OxyS-one", + "model": "P", + "version": "after", + "wall_median": 0.14, + "wall_min": 0.14, + "wall_max": 0.18, + "rss_median_kib": 19080.0 + }, + { + "case": "OxyS-one", + "model": "P", + "version": "feat-before", + "wall_median": 0.14, + "wall_min": 0.14, + "wall_max": 0.14, + "rss_median_kib": 19124.0 + }, + { + "case": "OxyS-one", + "model": "P", + "version": "feat-after", + "wall_median": 0.14, + "wall_min": 0.14, + "wall_max": 0.14, + "rss_median_kib": 18896.0 + }, + { + "case": "OxyS-eight", + "model": "X", + "version": "before", + "wall_median": 0.75, + "wall_min": 0.74, + "wall_max": 0.75, + "rss_median_kib": 23720.0 + }, + { + "case": "OxyS-eight", + "model": "X", + "version": "after", + "wall_median": 0.74, + "wall_min": 0.72, + "wall_max": 0.75, + "rss_median_kib": 23708.0 + }, + { + "case": "OxyS-eight", + "model": "X", + "version": "feat-before", + "wall_median": 0.74, + "wall_min": 0.73, + "wall_max": 0.75, + "rss_median_kib": 23772.0 + }, + { + "case": "OxyS-eight", + "model": "X", + "version": "feat-after", + "wall_median": 0.74, + "wall_min": 0.74, + "wall_max": 0.74, + "rss_median_kib": 23932.0 + }, + { + "case": "OxyS-eight", + "model": "P", + "version": "before", + "wall_median": 0.78, + "wall_min": 0.77, + "wall_max": 0.79, + "rss_median_kib": 26484.0 + }, + { + "case": "OxyS-eight", + "model": "P", + "version": "after", + "wall_median": 0.78, + "wall_min": 0.77, + "wall_max": 0.78, + "rss_median_kib": 25728.0 + }, + { + "case": "OxyS-eight", + "model": "P", + "version": "feat-before", + "wall_median": 0.77, + "wall_min": 0.77, + "wall_max": 0.78, + "rss_median_kib": 26984.0 + }, + { + "case": "OxyS-eight", + "model": "P", + "version": "feat-after", + "wall_median": 0.78, + "wall_min": 0.77, + "wall_max": 0.8, + "rss_median_kib": 25756.0 + }, + { + "case": "GcvB-32", + "model": "X", + "version": "before", + "wall_median": 8.57, + "wall_min": 8.56, + "wall_max": 8.7, + "rss_median_kib": 24976.0 + }, + { + "case": "GcvB-32", + "model": "X", + "version": "after", + "wall_median": 8.57, + "wall_min": 8.5, + "wall_max": 8.62, + "rss_median_kib": 25116.0 + }, + { + "case": "GcvB-32", + "model": "X", + "version": "feat-before", + "wall_median": 8.6, + "wall_min": 8.51, + "wall_max": 8.76, + "rss_median_kib": 25236.0 + }, + { + "case": "GcvB-32", + "model": "X", + "version": "feat-after", + "wall_median": 8.6, + "wall_min": 8.57, + "wall_max": 8.78, + "rss_median_kib": 25236.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "before", + "wall_median": 10.195, + "wall_min": 10.13, + "wall_max": 10.28, + "rss_median_kib": 89438.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "after", + "wall_median": 9.895, + "wall_min": 9.85, + "wall_max": 9.92, + "rss_median_kib": 80378.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "feat-before", + "wall_median": 10.305, + "wall_min": 10.23, + "wall_max": 10.31, + "rss_median_kib": 89894.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "feat-after", + "wall_median": 10.024999999999999, + "wall_min": 9.89, + "wall_max": 10.06, + "rss_median_kib": 80304.0 + }, + { + "case": "GcvB-32-noLP", + "model": "X", + "version": "before", + "wall_median": 3.3, + "wall_min": 3.29, + "wall_max": 3.32, + "rss_median_kib": 25208.0 + }, + { + "case": "GcvB-32-noLP", + "model": "X", + "version": "after", + "wall_median": 3.31, + "wall_min": 3.3, + "wall_max": 3.38, + "rss_median_kib": 25156.0 + }, + { + "case": "GcvB-32-noLP", + "model": "X", + "version": "feat-before", + "wall_median": 3.29, + "wall_min": 3.28, + "wall_max": 3.3, + "rss_median_kib": 25312.0 + }, + { + "case": "GcvB-32-noLP", + "model": "X", + "version": "feat-after", + "wall_median": 3.32, + "wall_min": 3.29, + "wall_max": 3.33, + "rss_median_kib": 25140.0 + }, + { + "case": "GcvB-32-noLP", + "model": "P", + "version": "before", + "wall_median": 3.61, + "wall_min": 3.59, + "wall_max": 3.63, + "rss_median_kib": 44204.0 + }, + { + "case": "GcvB-32-noLP", + "model": "P", + "version": "after", + "wall_median": 3.62, + "wall_min": 3.58, + "wall_max": 3.63, + "rss_median_kib": 42076.0 + }, + { + "case": "GcvB-32-noLP", + "model": "P", + "version": "feat-before", + "wall_median": 3.64, + "wall_min": 3.63, + "wall_max": 3.68, + "rss_median_kib": 44908.0 + }, + { + "case": "GcvB-32-noLP", + "model": "P", + "version": "feat-after", + "wall_median": 3.66, + "wall_min": 3.64, + "wall_max": 3.67, + "rss_median_kib": 42312.0 + }, + { + "case": "dense256x24", + "model": "X", + "version": "before", + "wall_median": 0.19, + "wall_min": 0.19, + "wall_max": 0.19, + "rss_median_kib": 14336.0 + }, + { + "case": "dense256x24", + "model": "X", + "version": "after", + "wall_median": 0.19, + "wall_min": 0.19, + "wall_max": 0.19, + "rss_median_kib": 14464.0 + }, + { + "case": "dense256x24", + "model": "X", + "version": "feat-before", + "wall_median": 0.19, + "wall_min": 0.19, + "wall_max": 0.19, + "rss_median_kib": 14592.0 + }, + { + "case": "dense256x24", + "model": "X", + "version": "feat-after", + "wall_median": 0.19, + "wall_min": 0.19, + "wall_max": 0.19, + "rss_median_kib": 14592.0 + }, + { + "case": "dense256x24", + "model": "P", + "version": "before", + "wall_median": 31.9, + "wall_min": 31.66, + "wall_max": 32.19, + "rss_median_kib": 17908.0 + }, + { + "case": "dense256x24", + "model": "P", + "version": "after", + "wall_median": 31.54, + "wall_min": 31.24, + "wall_max": 32.02, + "rss_median_kib": 18560.0 + }, + { + "case": "dense256x24", + "model": "P", + "version": "feat-before", + "wall_median": 31.79, + "wall_min": 31.49, + "wall_max": 31.98, + "rss_median_kib": 18032.0 + }, + { + "case": "dense256x24", + "model": "P", + "version": "feat-after", + "wall_median": 32.14, + "wall_min": 31.76, + "wall_max": 32.28, + "rss_median_kib": 18816.0 + } + ], + "raw": [ + { + "case": "OxyS-one", + "model": "X", + "version": "feat-before", + "repeat": 0, + "wall": 0.14, + "user": 0.54, + "system": 0.0, + "rss_kib": 19252.0 + }, + { + "case": "OxyS-one", + "model": "X", + "version": "feat-after", + "repeat": 0, + "wall": 0.14, + "user": 0.53, + "system": 0.0, + "rss_kib": 18996.0 + }, + { + "case": "OxyS-one", + "model": "X", + "version": "before", + "repeat": 0, + "wall": 0.14, + "user": 0.54, + "system": 0.0, + "rss_kib": 19120.0 + }, + { + "case": "OxyS-one", + "model": "X", + "version": "after", + "repeat": 0, + "wall": 0.14, + "user": 0.53, + "system": 0.0, + "rss_kib": 18996.0 + }, + { + "case": "OxyS-one", + "model": "X", + "version": "after", + "repeat": 1, + "wall": 0.14, + "user": 0.53, + "system": 0.0, + "rss_kib": 18992.0 + }, + { + "case": "OxyS-one", + "model": "X", + "version": "feat-before", + "repeat": 1, + "wall": 0.14, + "user": 0.53, + "system": 0.0, + "rss_kib": 19000.0 + }, + { + "case": "OxyS-one", + "model": "X", + "version": "before", + "repeat": 1, + "wall": 0.14, + "user": 0.54, + "system": 0.0, + "rss_kib": 19124.0 + }, + { + "case": "OxyS-one", + "model": "X", + "version": "feat-after", + "repeat": 1, + "wall": 0.14, + "user": 0.54, + "system": 0.0, + "rss_kib": 19124.0 + }, + { + "case": "OxyS-one", + "model": "X", + "version": "before", + "repeat": 2, + "wall": 0.14, + "user": 0.54, + "system": 0.0, + "rss_kib": 18864.0 + }, + { + "case": "OxyS-one", + "model": "X", + "version": "after", + "repeat": 2, + "wall": 0.14, + "user": 0.53, + "system": 0.0, + "rss_kib": 18996.0 + }, + { + "case": "OxyS-one", + "model": "X", + "version": "feat-after", + "repeat": 2, + "wall": 0.14, + "user": 0.54, + "system": 0.0, + "rss_kib": 19248.0 + }, + { + "case": "OxyS-one", + "model": "X", + "version": "feat-before", + "repeat": 2, + "wall": 0.14, + "user": 0.54, + "system": 0.0, + "rss_kib": 19124.0 + }, + { + "case": "OxyS-one", + "model": "P", + "version": "feat-before", + "repeat": 0, + "wall": 0.14, + "user": 0.54, + "system": 0.0, + "rss_kib": 19124.0 + }, + { + "case": "OxyS-one", + "model": "P", + "version": "feat-after", + "repeat": 0, + "wall": 0.14, + "user": 0.53, + "system": 0.01, + "rss_kib": 18984.0 + }, + { + "case": "OxyS-one", + "model": "P", + "version": "before", + "repeat": 0, + "wall": 0.14, + "user": 0.54, + "system": 0.0, + "rss_kib": 19124.0 + }, + { + "case": "OxyS-one", + "model": "P", + "version": "after", + "repeat": 0, + "wall": 0.14, + "user": 0.54, + "system": 0.0, + "rss_kib": 19080.0 + }, + { + "case": "OxyS-one", + "model": "P", + "version": "after", + "repeat": 1, + "wall": 0.14, + "user": 0.54, + "system": 0.0, + "rss_kib": 18996.0 + }, + { + "case": "OxyS-one", + "model": "P", + "version": "feat-before", + "repeat": 1, + "wall": 0.14, + "user": 0.54, + "system": 0.0, + "rss_kib": 19032.0 + }, + { + "case": "OxyS-one", + "model": "P", + "version": "before", + "repeat": 1, + "wall": 0.14, + "user": 0.54, + "system": 0.01, + "rss_kib": 19124.0 + }, + { + "case": "OxyS-one", + "model": "P", + "version": "feat-after", + "repeat": 1, + "wall": 0.14, + "user": 0.54, + "system": 0.0, + "rss_kib": 18896.0 + }, + { + "case": "OxyS-one", + "model": "P", + "version": "before", + "repeat": 2, + "wall": 0.15, + "user": 0.54, + "system": 0.0, + "rss_kib": 18868.0 + }, + { + "case": "OxyS-one", + "model": "P", + "version": "after", + "repeat": 2, + "wall": 0.18, + "user": 0.49, + "system": 0.0, + "rss_kib": 19136.0 + }, + { + "case": "OxyS-one", + "model": "P", + "version": "feat-after", + "repeat": 2, + "wall": 0.14, + "user": 0.54, + "system": 0.0, + "rss_kib": 18652.0 + }, + { + "case": "OxyS-one", + "model": "P", + "version": "feat-before", + "repeat": 2, + "wall": 0.14, + "user": 0.54, + "system": 0.0, + "rss_kib": 19128.0 + }, + { + "case": "OxyS-eight", + "model": "X", + "version": "feat-before", + "repeat": 0, + "wall": 0.75, + "user": 1.42, + "system": 0.02, + "rss_kib": 23724.0 + }, + { + "case": "OxyS-eight", + "model": "X", + "version": "feat-after", + "repeat": 0, + "wall": 0.74, + "user": 1.42, + "system": 0.02, + "rss_kib": 23932.0 + }, + { + "case": "OxyS-eight", + "model": "X", + "version": "before", + "repeat": 0, + "wall": 0.74, + "user": 1.41, + "system": 0.02, + "rss_kib": 23512.0 + }, + { + "case": "OxyS-eight", + "model": "X", + "version": "after", + "repeat": 0, + "wall": 0.74, + "user": 1.42, + "system": 0.02, + "rss_kib": 23708.0 + }, + { + "case": "OxyS-eight", + "model": "X", + "version": "after", + "repeat": 1, + "wall": 0.72, + "user": 1.4, + "system": 0.02, + "rss_kib": 23296.0 + }, + { + "case": "OxyS-eight", + "model": "X", + "version": "feat-before", + "repeat": 1, + "wall": 0.74, + "user": 1.41, + "system": 0.02, + "rss_kib": 23772.0 + }, + { + "case": "OxyS-eight", + "model": "X", + "version": "before", + "repeat": 1, + "wall": 0.75, + "user": 1.44, + "system": 0.02, + "rss_kib": 23720.0 + }, + { + "case": "OxyS-eight", + "model": "X", + "version": "feat-after", + "repeat": 1, + "wall": 0.74, + "user": 1.42, + "system": 0.02, + "rss_kib": 23980.0 + }, + { + "case": "OxyS-eight", + "model": "X", + "version": "before", + "repeat": 2, + "wall": 0.75, + "user": 1.43, + "system": 0.02, + "rss_kib": 23720.0 + }, + { + "case": "OxyS-eight", + "model": "X", + "version": "after", + "repeat": 2, + "wall": 0.75, + "user": 1.43, + "system": 0.02, + "rss_kib": 23716.0 + }, + { + "case": "OxyS-eight", + "model": "X", + "version": "feat-after", + "repeat": 2, + "wall": 0.74, + "user": 1.41, + "system": 0.02, + "rss_kib": 23836.0 + }, + { + "case": "OxyS-eight", + "model": "X", + "version": "feat-before", + "repeat": 2, + "wall": 0.73, + "user": 1.41, + "system": 0.01, + "rss_kib": 23932.0 + }, + { + "case": "OxyS-eight", + "model": "P", + "version": "feat-before", + "repeat": 0, + "wall": 0.77, + "user": 1.55, + "system": 0.02, + "rss_kib": 27208.0 + }, + { + "case": "OxyS-eight", + "model": "P", + "version": "feat-after", + "repeat": 0, + "wall": 0.78, + "user": 1.55, + "system": 0.02, + "rss_kib": 25644.0 + }, + { + "case": "OxyS-eight", + "model": "P", + "version": "before", + "repeat": 0, + "wall": 0.77, + "user": 1.54, + "system": 0.02, + "rss_kib": 26420.0 + }, + { + "case": "OxyS-eight", + "model": "P", + "version": "after", + "repeat": 0, + "wall": 0.77, + "user": 1.53, + "system": 0.02, + "rss_kib": 25728.0 + }, + { + "case": "OxyS-eight", + "model": "P", + "version": "after", + "repeat": 1, + "wall": 0.78, + "user": 1.54, + "system": 0.02, + "rss_kib": 25728.0 + }, + { + "case": "OxyS-eight", + "model": "P", + "version": "feat-before", + "repeat": 1, + "wall": 0.78, + "user": 1.55, + "system": 0.02, + "rss_kib": 26660.0 + }, + { + "case": "OxyS-eight", + "model": "P", + "version": "before", + "repeat": 1, + "wall": 0.79, + "user": 1.57, + "system": 0.02, + "rss_kib": 26484.0 + }, + { + "case": "OxyS-eight", + "model": "P", + "version": "feat-after", + "repeat": 1, + "wall": 0.8, + "user": 1.59, + "system": 0.02, + "rss_kib": 25956.0 + }, + { + "case": "OxyS-eight", + "model": "P", + "version": "before", + "repeat": 2, + "wall": 0.78, + "user": 1.56, + "system": 0.03, + "rss_kib": 26640.0 + }, + { + "case": "OxyS-eight", + "model": "P", + "version": "after", + "repeat": 2, + "wall": 0.78, + "user": 1.54, + "system": 0.02, + "rss_kib": 26068.0 + }, + { + "case": "OxyS-eight", + "model": "P", + "version": "feat-after", + "repeat": 2, + "wall": 0.77, + "user": 1.55, + "system": 0.02, + "rss_kib": 25756.0 + }, + { + "case": "OxyS-eight", + "model": "P", + "version": "feat-before", + "repeat": 2, + "wall": 0.77, + "user": 1.54, + "system": 0.02, + "rss_kib": 26984.0 + }, + { + "case": "GcvB-32", + "model": "X", + "version": "feat-before", + "repeat": 0, + "wall": 8.51, + "user": 31.85, + "system": 0.06, + "rss_kib": 25240.0 + }, + { + "case": "GcvB-32", + "model": "X", + "version": "feat-after", + "repeat": 0, + "wall": 8.6, + "user": 32.14, + "system": 0.06, + "rss_kib": 25236.0 + }, + { + "case": "GcvB-32", + "model": "X", + "version": "before", + "repeat": 0, + "wall": 8.56, + "user": 32.2, + "system": 0.06, + "rss_kib": 24976.0 + }, + { + "case": "GcvB-32", + "model": "X", + "version": "after", + "repeat": 0, + "wall": 8.57, + "user": 31.96, + "system": 0.07, + "rss_kib": 25116.0 + }, + { + "case": "GcvB-32", + "model": "X", + "version": "after", + "repeat": 1, + "wall": 8.5, + "user": 32.12, + "system": 0.06, + "rss_kib": 25280.0 + }, + { + "case": "GcvB-32", + "model": "X", + "version": "feat-before", + "repeat": 1, + "wall": 8.6, + "user": 32.11, + "system": 0.06, + "rss_kib": 25208.0 + }, + { + "case": "GcvB-32", + "model": "X", + "version": "before", + "repeat": 1, + "wall": 8.57, + "user": 32.29, + "system": 0.06, + "rss_kib": 25112.0 + }, + { + "case": "GcvB-32", + "model": "X", + "version": "feat-after", + "repeat": 1, + "wall": 8.57, + "user": 32.11, + "system": 0.07, + "rss_kib": 25148.0 + }, + { + "case": "GcvB-32", + "model": "X", + "version": "before", + "repeat": 2, + "wall": 8.7, + "user": 32.53, + "system": 0.06, + "rss_kib": 24972.0 + }, + { + "case": "GcvB-32", + "model": "X", + "version": "after", + "repeat": 2, + "wall": 8.62, + "user": 32.67, + "system": 0.06, + "rss_kib": 24984.0 + }, + { + "case": "GcvB-32", + "model": "X", + "version": "feat-after", + "repeat": 2, + "wall": 8.78, + "user": 32.83, + "system": 0.07, + "rss_kib": 25240.0 + }, + { + "case": "GcvB-32", + "model": "X", + "version": "feat-before", + "repeat": 2, + "wall": 8.76, + "user": 32.81, + "system": 0.07, + "rss_kib": 25236.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "feat-before", + "repeat": 0, + "wall": 10.23, + "user": 38.36, + "system": 0.09, + "rss_kib": 90232.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "feat-after", + "repeat": 0, + "wall": 9.89, + "user": 37.31, + "system": 0.09, + "rss_kib": 80244.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "before", + "repeat": 0, + "wall": 10.13, + "user": 38.17, + "system": 0.09, + "rss_kib": 89816.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "after", + "repeat": 0, + "wall": 9.9, + "user": 36.93, + "system": 0.09, + "rss_kib": 80404.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "after", + "repeat": 1, + "wall": 9.85, + "user": 37.14, + "system": 0.09, + "rss_kib": 80768.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "feat-before", + "repeat": 1, + "wall": 10.27, + "user": 38.71, + "system": 0.09, + "rss_kib": 89112.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "before", + "repeat": 1, + "wall": 10.28, + "user": 38.29, + "system": 0.09, + "rss_kib": 88552.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "feat-after", + "repeat": 1, + "wall": 10.06, + "user": 37.71, + "system": 0.1, + "rss_kib": 84812.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "before", + "repeat": 2, + "wall": 10.18, + "user": 38.33, + "system": 0.09, + "rss_kib": 89060.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "after", + "repeat": 2, + "wall": 9.9, + "user": 37.15, + "system": 0.09, + "rss_kib": 80352.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "feat-after", + "repeat": 2, + "wall": 10.0, + "user": 37.4, + "system": 0.09, + "rss_kib": 84832.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "feat-before", + "repeat": 2, + "wall": 10.3, + "user": 38.6, + "system": 0.1, + "rss_kib": 89864.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "before", + "repeat": 3, + "wall": 10.17, + "user": 38.3, + "system": 0.1, + "rss_kib": 89972.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "feat-before", + "repeat": 3, + "wall": 10.31, + "user": 38.75, + "system": 0.11, + "rss_kib": 90548.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "after", + "repeat": 3, + "wall": 9.88, + "user": 37.28, + "system": 0.08, + "rss_kib": 79636.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "feat-after", + "repeat": 3, + "wall": 10.01, + "user": 37.57, + "system": 0.09, + "rss_kib": 79992.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "after", + "repeat": 4, + "wall": 9.92, + "user": 37.2, + "system": 0.1, + "rss_kib": 79680.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "before", + "repeat": 4, + "wall": 10.22, + "user": 38.22, + "system": 0.09, + "rss_kib": 90328.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "feat-after", + "repeat": 4, + "wall": 10.04, + "user": 37.32, + "system": 0.1, + "rss_kib": 80032.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "feat-before", + "repeat": 4, + "wall": 10.31, + "user": 38.64, + "system": 0.1, + "rss_kib": 89924.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "before", + "repeat": 5, + "wall": 10.21, + "user": 38.09, + "system": 0.1, + "rss_kib": 88328.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "feat-before", + "repeat": 5, + "wall": 10.31, + "user": 38.69, + "system": 0.09, + "rss_kib": 88788.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "after", + "repeat": 5, + "wall": 9.89, + "user": 37.16, + "system": 0.09, + "rss_kib": 80608.0 + }, + { + "case": "GcvB-32", + "model": "P", + "version": "feat-after", + "repeat": 5, + "wall": 10.04, + "user": 37.82, + "system": 0.08, + "rss_kib": 80364.0 + }, + { + "case": "GcvB-32-noLP", + "model": "X", + "version": "feat-before", + "repeat": 0, + "wall": 3.3, + "user": 7.83, + "system": 0.05, + "rss_kib": 25312.0 + }, + { + "case": "GcvB-32-noLP", + "model": "X", + "version": "feat-after", + "repeat": 0, + "wall": 3.29, + "user": 7.8, + "system": 0.04, + "rss_kib": 25408.0 + }, + { + "case": "GcvB-32-noLP", + "model": "X", + "version": "before", + "repeat": 0, + "wall": 3.3, + "user": 7.81, + "system": 0.06, + "rss_kib": 25024.0 + }, + { + "case": "GcvB-32-noLP", + "model": "X", + "version": "after", + "repeat": 0, + "wall": 3.3, + "user": 7.83, + "system": 0.07, + "rss_kib": 25156.0 + }, + { + "case": "GcvB-32-noLP", + "model": "X", + "version": "after", + "repeat": 1, + "wall": 3.31, + "user": 7.88, + "system": 0.05, + "rss_kib": 25028.0 + }, + { + "case": "GcvB-32-noLP", + "model": "X", + "version": "feat-before", + "repeat": 1, + "wall": 3.29, + "user": 7.82, + "system": 0.05, + "rss_kib": 25420.0 + }, + { + "case": "GcvB-32-noLP", + "model": "X", + "version": "before", + "repeat": 1, + "wall": 3.32, + "user": 7.88, + "system": 0.06, + "rss_kib": 25208.0 + }, + { + "case": "GcvB-32-noLP", + "model": "X", + "version": "feat-after", + "repeat": 1, + "wall": 3.32, + "user": 7.82, + "system": 0.07, + "rss_kib": 25140.0 + }, + { + "case": "GcvB-32-noLP", + "model": "X", + "version": "before", + "repeat": 2, + "wall": 3.29, + "user": 7.83, + "system": 0.05, + "rss_kib": 25280.0 + }, + { + "case": "GcvB-32-noLP", + "model": "X", + "version": "after", + "repeat": 2, + "wall": 3.38, + "user": 8.1, + "system": 0.05, + "rss_kib": 25296.0 + }, + { + "case": "GcvB-32-noLP", + "model": "X", + "version": "feat-after", + "repeat": 2, + "wall": 3.33, + "user": 7.88, + "system": 0.06, + "rss_kib": 25028.0 + }, + { + "case": "GcvB-32-noLP", + "model": "X", + "version": "feat-before", + "repeat": 2, + "wall": 3.28, + "user": 7.79, + "system": 0.06, + "rss_kib": 25148.0 + }, + { + "case": "GcvB-32-noLP", + "model": "P", + "version": "feat-before", + "repeat": 0, + "wall": 3.64, + "user": 9.7, + "system": 0.03, + "rss_kib": 44268.0 + }, + { + "case": "GcvB-32-noLP", + "model": "P", + "version": "feat-after", + "repeat": 0, + "wall": 3.64, + "user": 9.4, + "system": 0.03, + "rss_kib": 42084.0 + }, + { + "case": "GcvB-32-noLP", + "model": "P", + "version": "before", + "repeat": 0, + "wall": 3.63, + "user": 9.42, + "system": 0.04, + "rss_kib": 44204.0 + }, + { + "case": "GcvB-32-noLP", + "model": "P", + "version": "after", + "repeat": 0, + "wall": 3.63, + "user": 9.34, + "system": 0.04, + "rss_kib": 42076.0 + }, + { + "case": "GcvB-32-noLP", + "model": "P", + "version": "after", + "repeat": 1, + "wall": 3.58, + "user": 9.26, + "system": 0.03, + "rss_kib": 42368.0 + }, + { + "case": "GcvB-32-noLP", + "model": "P", + "version": "feat-before", + "repeat": 1, + "wall": 3.63, + "user": 9.57, + "system": 0.03, + "rss_kib": 44968.0 + }, + { + "case": "GcvB-32-noLP", + "model": "P", + "version": "before", + "repeat": 1, + "wall": 3.59, + "user": 9.42, + "system": 0.04, + "rss_kib": 43948.0 + }, + { + "case": "GcvB-32-noLP", + "model": "P", + "version": "feat-after", + "repeat": 1, + "wall": 3.66, + "user": 9.58, + "system": 0.04, + "rss_kib": 42388.0 + }, + { + "case": "GcvB-32-noLP", + "model": "P", + "version": "before", + "repeat": 2, + "wall": 3.61, + "user": 9.37, + "system": 0.03, + "rss_kib": 46400.0 + }, + { + "case": "GcvB-32-noLP", + "model": "P", + "version": "after", + "repeat": 2, + "wall": 3.62, + "user": 9.3, + "system": 0.03, + "rss_kib": 41924.0 + }, + { + "case": "GcvB-32-noLP", + "model": "P", + "version": "feat-after", + "repeat": 2, + "wall": 3.67, + "user": 9.48, + "system": 0.03, + "rss_kib": 42312.0 + }, + { + "case": "GcvB-32-noLP", + "model": "P", + "version": "feat-before", + "repeat": 2, + "wall": 3.68, + "user": 9.67, + "system": 0.03, + "rss_kib": 44908.0 + }, + { + "case": "dense256x24", + "model": "X", + "version": "feat-before", + "repeat": 0, + "wall": 0.19, + "user": 0.59, + "system": 0.0, + "rss_kib": 14592.0 + }, + { + "case": "dense256x24", + "model": "X", + "version": "feat-after", + "repeat": 0, + "wall": 0.19, + "user": 0.59, + "system": 0.0, + "rss_kib": 14592.0 + }, + { + "case": "dense256x24", + "model": "X", + "version": "before", + "repeat": 0, + "wall": 0.19, + "user": 0.59, + "system": 0.0, + "rss_kib": 14208.0 + }, + { + "case": "dense256x24", + "model": "X", + "version": "after", + "repeat": 0, + "wall": 0.19, + "user": 0.59, + "system": 0.0, + "rss_kib": 14336.0 + }, + { + "case": "dense256x24", + "model": "X", + "version": "after", + "repeat": 1, + "wall": 0.19, + "user": 0.59, + "system": 0.0, + "rss_kib": 14464.0 + }, + { + "case": "dense256x24", + "model": "X", + "version": "feat-before", + "repeat": 1, + "wall": 0.19, + "user": 0.59, + "system": 0.0, + "rss_kib": 14464.0 + }, + { + "case": "dense256x24", + "model": "X", + "version": "before", + "repeat": 1, + "wall": 0.19, + "user": 0.59, + "system": 0.0, + "rss_kib": 14336.0 + }, + { + "case": "dense256x24", + "model": "X", + "version": "feat-after", + "repeat": 1, + "wall": 0.19, + "user": 0.59, + "system": 0.0, + "rss_kib": 14464.0 + }, + { + "case": "dense256x24", + "model": "X", + "version": "before", + "repeat": 2, + "wall": 0.19, + "user": 0.59, + "system": 0.0, + "rss_kib": 14464.0 + }, + { + "case": "dense256x24", + "model": "X", + "version": "after", + "repeat": 2, + "wall": 0.19, + "user": 0.59, + "system": 0.0, + "rss_kib": 14464.0 + }, + { + "case": "dense256x24", + "model": "X", + "version": "feat-after", + "repeat": 2, + "wall": 0.19, + "user": 0.58, + "system": 0.0, + "rss_kib": 14592.0 + }, + { + "case": "dense256x24", + "model": "X", + "version": "feat-before", + "repeat": 2, + "wall": 0.19, + "user": 0.58, + "system": 0.0, + "rss_kib": 14720.0 + }, + { + "case": "dense256x24", + "model": "P", + "version": "feat-before", + "repeat": 0, + "wall": 31.98, + "user": 32.37, + "system": 0.01, + "rss_kib": 18168.0 + }, + { + "case": "dense256x24", + "model": "P", + "version": "feat-after", + "repeat": 0, + "wall": 32.28, + "user": 32.68, + "system": 0.0, + "rss_kib": 18816.0 + }, + { + "case": "dense256x24", + "model": "P", + "version": "before", + "repeat": 0, + "wall": 31.66, + "user": 32.05, + "system": 0.0, + "rss_kib": 17908.0 + }, + { + "case": "dense256x24", + "model": "P", + "version": "after", + "repeat": 0, + "wall": 31.54, + "user": 31.93, + "system": 0.0, + "rss_kib": 18688.0 + }, + { + "case": "dense256x24", + "model": "P", + "version": "after", + "repeat": 1, + "wall": 32.02, + "user": 32.41, + "system": 0.0, + "rss_kib": 18304.0 + }, + { + "case": "dense256x24", + "model": "P", + "version": "feat-before", + "repeat": 1, + "wall": 31.49, + "user": 31.88, + "system": 0.0, + "rss_kib": 18032.0 + }, + { + "case": "dense256x24", + "model": "P", + "version": "before", + "repeat": 1, + "wall": 31.9, + "user": 32.3, + "system": 0.0, + "rss_kib": 17852.0 + }, + { + "case": "dense256x24", + "model": "P", + "version": "feat-after", + "repeat": 1, + "wall": 32.14, + "user": 32.53, + "system": 0.01, + "rss_kib": 18944.0 + }, + { + "case": "dense256x24", + "model": "P", + "version": "before", + "repeat": 2, + "wall": 32.19, + "user": 32.58, + "system": 0.0, + "rss_kib": 18064.0 + }, + { + "case": "dense256x24", + "model": "P", + "version": "after", + "repeat": 2, + "wall": 31.24, + "user": 31.63, + "system": 0.01, + "rss_kib": 18560.0 + }, + { + "case": "dense256x24", + "model": "P", + "version": "feat-after", + "repeat": 2, + "wall": 31.76, + "user": 32.15, + "system": 0.01, + "rss_kib": 18816.0 + }, + { + "case": "dense256x24", + "model": "P", + "version": "feat-before", + "repeat": 2, + "wall": 31.79, + "user": 32.18, + "system": 0.0, + "rss_kib": 17860.0 + } + ], + "commands": { + "OxyS-one/X/before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-1.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/OxyS_NC_000913.fasta", + "--threads=1", + "--model=X", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "OxyS-one/X/after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-1.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/OxyS_NC_000913.fasta", + "--threads=1", + "--model=X", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "OxyS-one/X/feat-before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-1.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/OxyS_NC_000913.fasta", + "--threads=1", + "--model=X", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "OxyS-one/X/feat-after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-1.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/OxyS_NC_000913.fasta", + "--threads=1", + "--model=X", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "OxyS-one/P/before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-1.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/OxyS_NC_000913.fasta", + "--threads=1", + "--model=P", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "OxyS-one/P/after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-1.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/OxyS_NC_000913.fasta", + "--threads=1", + "--model=P", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "OxyS-one/P/feat-before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-1.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/OxyS_NC_000913.fasta", + "--threads=1", + "--model=P", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "OxyS-one/P/feat-after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-1.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/OxyS_NC_000913.fasta", + "--threads=1", + "--model=P", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "OxyS-eight/X/before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-8.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/OxyS_NC_000913.fasta", + "--threads=4", + "--model=X", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "OxyS-eight/X/after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-8.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/OxyS_NC_000913.fasta", + "--threads=4", + "--model=X", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "OxyS-eight/X/feat-before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-8.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/OxyS_NC_000913.fasta", + "--threads=4", + "--model=X", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "OxyS-eight/X/feat-after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-8.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/OxyS_NC_000913.fasta", + "--threads=4", + "--model=X", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "OxyS-eight/P/before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-8.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/OxyS_NC_000913.fasta", + "--threads=4", + "--model=P", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "OxyS-eight/P/after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-8.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/OxyS_NC_000913.fasta", + "--threads=4", + "--model=P", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "OxyS-eight/P/feat-before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-8.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/OxyS_NC_000913.fasta", + "--threads=4", + "--model=P", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "OxyS-eight/P/feat-after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-8.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/OxyS_NC_000913.fasta", + "--threads=4", + "--model=P", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "GcvB-32/X/before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-32.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/GcvB_NC_000913.fasta", + "--threads=4", + "--model=X", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "GcvB-32/X/after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-32.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/GcvB_NC_000913.fasta", + "--threads=4", + "--model=X", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "GcvB-32/X/feat-before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-32.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/GcvB_NC_000913.fasta", + "--threads=4", + "--model=X", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "GcvB-32/X/feat-after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-final/fixtures/ecoli-32.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/GcvB_NC_000913.fasta", + "--threads=4", + "--model=X", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "GcvB-32/P/before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/gcvb-audit/fixtures/ecoli-32.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/GcvB_NC_000913.fasta", + "--threads=4", + "--model=P", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "GcvB-32/P/after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/gcvb-audit/fixtures/ecoli-32.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/GcvB_NC_000913.fasta", + "--threads=4", + "--model=P", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "GcvB-32/P/feat-before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/gcvb-audit/fixtures/ecoli-32.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/GcvB_NC_000913.fasta", + "--threads=4", + "--model=P", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "GcvB-32/P/feat-after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/gcvb-audit/fixtures/ecoli-32.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/GcvB_NC_000913.fasta", + "--threads=4", + "--model=P", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "GcvB-32-noLP/X/before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/ecoli-32.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/GcvB_NC_000913.fasta", + "--threads=4", + "--model=X", + "--mode=H", + "--outNoLP=true", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "GcvB-32-noLP/X/after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/ecoli-32.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/GcvB_NC_000913.fasta", + "--threads=4", + "--model=X", + "--mode=H", + "--outNoLP=true", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "GcvB-32-noLP/X/feat-before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/ecoli-32.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/GcvB_NC_000913.fasta", + "--threads=4", + "--model=X", + "--mode=H", + "--outNoLP=true", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "GcvB-32-noLP/X/feat-after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/ecoli-32.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/GcvB_NC_000913.fasta", + "--threads=4", + "--model=X", + "--mode=H", + "--outNoLP=true", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "GcvB-32-noLP/P/before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/ecoli-32.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/GcvB_NC_000913.fasta", + "--threads=4", + "--model=P", + "--mode=H", + "--outNoLP=true", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "GcvB-32-noLP/P/after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/ecoli-32.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/GcvB_NC_000913.fasta", + "--threads=4", + "--model=P", + "--mode=H", + "--outNoLP=true", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "GcvB-32-noLP/P/feat-before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/ecoli-32.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/GcvB_NC_000913.fasta", + "--threads=4", + "--model=P", + "--mode=H", + "--outNoLP=true", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "GcvB-32-noLP/P/feat-after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/ecoli-32.fa", + "--query=/home/alex/CodexProjects/IntaRNA/intarna-benchmark/input/NC_000913/query/GcvB_NC_000913.fasta", + "--threads=4", + "--model=P", + "--mode=H", + "--outNoLP=true", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall" + ], + "dense256x24/X/before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/dense-target.fa", + "--query=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/dense-query.fa", + "--threads=1", + "--model=X", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall", + "--energy=B", + "--acc=N", + "--seedBP=4", + "--intLoopMax=0" + ], + "dense256x24/X/after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/dense-target.fa", + "--query=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/dense-query.fa", + "--threads=1", + "--model=X", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall", + "--energy=B", + "--acc=N", + "--seedBP=4", + "--intLoopMax=0" + ], + "dense256x24/X/feat-before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/dense-target.fa", + "--query=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/dense-query.fa", + "--threads=1", + "--model=X", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall", + "--energy=B", + "--acc=N", + "--seedBP=4", + "--intLoopMax=0" + ], + "dense256x24/X/feat-after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/dense-target.fa", + "--query=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/dense-query.fa", + "--threads=1", + "--model=X", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall", + "--energy=B", + "--acc=N", + "--seedBP=4", + "--intLoopMax=0" + ], + "dense256x24/P/before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/dense-target.fa", + "--query=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/dense-query.fa", + "--threads=1", + "--model=P", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall", + "--energy=B", + "--acc=N", + "--seedBP=4", + "--intLoopMax=0" + ], + "dense256x24/P/after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-master-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/dense-target.fa", + "--query=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/dense-query.fa", + "--threads=1", + "--model=P", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall", + "--energy=B", + "--acc=N", + "--seedBP=4", + "--intLoopMax=0" + ], + "dense256x24/P/feat-before": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-before", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/dense-target.fa", + "--query=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/dense-query.fa", + "--threads=1", + "--model=P", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall", + "--energy=B", + "--acc=N", + "--seedBP=4", + "--intLoopMax=0" + ], + "dense256x24/P/feat-after": [ + "/home/alex/CodexProjects/IntaRNA/issue-260-validation/IntaRNA-feat-after", + "--target=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/dense-target.fa", + "--query=/home/alex/CodexProjects/IntaRNA/issue-260-validation/performance-last/fixtures/dense-query.fa", + "--threads=1", + "--model=P", + "--mode=H", + "--outNoLP=false", + "--tIntLenMax=80", + "--outMode=C", + "--outNumber=1", + "--default-log-file=/dev/null", + "--outCsvCols=id1,id2,start1,end1,start2,end2,E,Zall", + "--energy=B", + "--acc=N", + "--seedBP=4", + "--intLoopMax=0" + ] + } +} diff --git a/doc/ensemble-memory-probability-port.patch b/doc/ensemble-memory-probability-port.patch new file mode 100644 index 00000000..b492c110 --- /dev/null +++ b/doc/ensemble-memory-probability-port.patch @@ -0,0 +1,232 @@ +diff --git a/src/IntaRNA/PredictorMfeEns.cpp b/src/IntaRNA/PredictorMfeEns.cpp +index 3ed283e..6e07713 100644 +--- a/src/IntaRNA/PredictorMfeEns.cpp ++++ b/src/IntaRNA/PredictorMfeEns.cpp +@@ -36,0 +37,2 @@ initZ() ++ Z_frontier.clear(); ++ Z_frontierNext = 0; +@@ -123,6 +125,6 @@ updateZ( const size_t i1, const size_t j1 +- Interaction::Boundary key(i1,j1,i2,j2); +- auto [keyEntry, inserted] = Z_partition.try_emplace(key, partZ_noED); +- if (!inserted) { +- // update entry +- keyEntry->second += partZ_noED; +- } ++ auto accumulate = [partZ_noED](auto & partitions,const auto & key) { ++ auto [keyEntry,inserted] = partitions.try_emplace(key,partZ_noED); ++ if (!inserted) keyEntry->second += partZ_noED; ++ }; ++ if (Z_frontier.empty()) accumulate(Z_partition,Interaction::Boundary(i1,j1,i2,j2)); ++ else accumulate(Z_frontier.at(j1),FrontierBoundary{i1,i2,j2}); +@@ -182,0 +185 @@ updateOptimaUsingZ() ++ advanceZFrontier(Z_frontier.size()); +@@ -191,0 +195,22 @@ updateOptimaUsingZ() ++void PredictorMfeEns::beginZFrontier(size_t size1) ++{ ++ if (predTracker == nullptr) Z_frontier.resize(size1); ++} ++ ++void PredictorMfeEns::advanceZFrontier(size_t minimumSeedStart) ++{ ++ const size_t end = std::min(minimumSeedStart,Z_frontier.size()); ++ while (Z_frontierNext < end) { ++ auto & partitions = Z_frontier[Z_frontierNext]; ++ for (const auto & [boundary,partition] : partitions) { ++ if (Z_isNotINF(partition) && partition > 0) { ++ PredictorMfe::updateOptima(boundary.i1,Z_frontierNext,boundary.i2,boundary.j2, ++ energy.getE(partition),true,false); ++ } ++ } ++ // Free both nodes and bucket storage as soon as this boundary is complete. ++ decltype(Z_frontier)::value_type{}.swap(partitions); ++ ++Z_frontierNext; ++ } ++} ++ +diff --git a/src/IntaRNA/PredictorMfeEns.h b/src/IntaRNA/PredictorMfeEns.h +index c51fd65..10fb14d 100644 +--- a/src/IntaRNA/PredictorMfeEns.h ++++ b/src/IntaRNA/PredictorMfeEns.h +@@ -11,0 +12 @@ ++#include +@@ -77,0 +79,15 @@ protected: ++ //! a bucket supplies j1, so its key needs only the other three coordinates ++ struct FrontierBoundary { ++ size_t i1, i2, j2; ++ bool operator==(const FrontierBoundary &) const = default; ++ struct Hash { ++ size_t operator()(const FrontierBoundary & boundary) const; ++ }; ++ }; ++ ++ //! partial sums grouped by target right boundary; used only without trackers ++ std::vector> Z_frontier; ++ //! first right-boundary bucket that has not yet been finalized ++ size_t Z_frontierNext = 0; ++ ++ +@@ -123,0 +140,12 @@ protected: ++ /** Enable partial-partition buckets by target right boundary. Tracker runs ++ * keep the original map to preserve callback ordering. Call advanceZFrontier ++ * only when no remaining seed can start below the supplied target index. ++ * @param size1 number of target positions in the current prediction region ++ */ ++ void beginZFrontier(size_t size1); ++ ++ /** Consume completed boundary sums without adding their mass to Zall again. ++ * @param minimumSeedStart smallest target start of any remaining seed ++ */ ++ void advanceZFrontier(size_t minimumSeedStart); ++ +@@ -163,0 +192,11 @@ private: ++inline ++size_t ++PredictorMfeEns::FrontierBoundary::Hash::operator()(const FrontierBoundary & boundary) const ++{ ++ size_t key=0; ++ boost::hash_combine(key,boundary.i1); ++ boost::hash_combine(key,boundary.i2); ++ boost::hash_combine(key,boundary.j2); ++ return key; ++} ++ +diff --git a/src/IntaRNA/PredictorMfeEns2dHeuristicSeedExtension.cpp b/src/IntaRNA/PredictorMfeEns2dHeuristicSeedExtension.cpp +index 278eb74..527d493 100644 +--- a/src/IntaRNA/PredictorMfeEns2dHeuristicSeedExtension.cpp ++++ b/src/IntaRNA/PredictorMfeEns2dHeuristicSeedExtension.cpp +@@ -88,5 +88,4 @@ predict( const IndexRange & r1, const IndexRange & r2 ) +- size_t si1 = RnaSequence::lastPos, si2 = RnaSequence::lastPos; +- while( seedHandler.updateToNextSeed(si1,si2 +- , 0, range_size1-1 +- , 0, range_size2-1) ) +- { ++ beginZFrontier(range_size1); ++ for (const auto & seed : getSeedStarts(range_size1-1,range_size2-1)) { ++ advanceZFrontier(seed.minimumRemaining); ++ const size_t si1=seed.i1, si2=seed.i2; +diff --git a/src/IntaRNA/PredictorMfeEns2dSeedExtension.cpp b/src/IntaRNA/PredictorMfeEns2dSeedExtension.cpp +index 7fd217f..6c964e4 100644 +--- a/src/IntaRNA/PredictorMfeEns2dSeedExtension.cpp ++++ b/src/IntaRNA/PredictorMfeEns2dSeedExtension.cpp +@@ -9,0 +10,21 @@ namespace IntaRNA { ++ ++std::vector ++PredictorMfeEns2dSeedExtension::getSeedStarts(size_t max1,size_t max2) const ++{ ++ std::vector starts; ++ size_t i1=RnaSequence::lastPos, i2=RnaSequence::lastPos; ++ while (seedHandler.updateToNextSeed(i1,i2, ++ 0,max1,0,max2)) { ++ starts.push_back({i1,i2,i1}); ++ } ++ // A suffix minimum is safe for either traversal order and custom handlers. ++ size_t minimum=max1; ++ for (auto seed=starts.rbegin(); seed!=starts.rend(); ++seed) { ++ minimum=std::min(minimum,seed->i1); ++ seed->minimumRemaining=minimum; ++ } ++ return starts; ++} ++ ++ ++ +@@ -271,5 +292,5 @@ predict( const IndexRange & r1, const IndexRange & r2 ) +- size_t si1 = RnaSequence::lastPos, si2 = RnaSequence::lastPos; +- while( seedHandler.updateToNextSeed(si1,si2 +- , 0, range_size1+1-seedHandler.getConstraint().getBasePairs() +- , 0, range_size2+1-seedHandler.getConstraint().getBasePairs()) ) +- { ++ beginZFrontier(range_size1); ++ for (const auto & seed : getSeedStarts(range_size1+1-seedHandler.getConstraint().getBasePairs(), ++ range_size2+1-seedHandler.getConstraint().getBasePairs())) { ++ advanceZFrontier(seed.minimumRemaining); ++ const size_t si1=seed.i1, si2=seed.i2; +diff --git a/src/IntaRNA/PredictorMfeEns2dSeedExtension.h b/src/IntaRNA/PredictorMfeEns2dSeedExtension.h +index 0b344e4..7bb46c1 100644 +--- a/src/IntaRNA/PredictorMfeEns2dSeedExtension.h ++++ b/src/IntaRNA/PredictorMfeEns2dSeedExtension.h +@@ -27,0 +28,10 @@ protected: ++ //! seed coordinates in handler order and the minimum remaining target start ++ struct SeedStart { size_t i1, i2, minimumRemaining; }; ++ ++ /** Collect seed starts without changing traversal or partition summation order. ++ * @param max1 largest target seed start ++ * @param max2 largest reversed-query seed start ++ * @return starts with a safe lower bound for all remaining target seed starts ++ */ ++ std::vector getSeedStarts(size_t max1,size_t max2) const; ++ +diff --git a/tests/PredictorMfeEnsRegression_test.cpp b/tests/PredictorMfeEnsRegression_test.cpp +index e4f5537..f1a20e3 100644 +--- a/tests/PredictorMfeEnsRegression_test.cpp ++++ b/tests/PredictorMfeEnsRegression_test.cpp +@@ -15,0 +16,2 @@ ++#include "IntaRNA/SeedHandlerMfe.h" ++#include "IntaRNA/SeedHandlerExplicit.h" +@@ -29,2 +31,2 @@ public: +- SeedHandler * seedHandler) +- : PredictorType(energy, output, NULL, seedHandler) ++ SeedHandler * seedHandler, PredictionTracker * tracker=nullptr) ++ : PredictorType(energy, output, tracker, seedHandler) +@@ -34 +36,3 @@ public: +- return this->Z_partition.size(); ++ size_t count=this->Z_partition.size(); ++ for (const auto & bucket : this->Z_frontier) count+=bucket.size(); ++ return count; +@@ -234 +238 @@ TEST_CASE("ensemble predictor regressions", "[PredictorMfeEns]") { +- // The new exact stack backend streams each completed boundary once. ++ // The exact stack backend streams each completed boundary once. +@@ -245 +249 @@ TEST_CASE("ensemble predictor regressions", "[PredictorMfeEns]") { +- REQUIRE(heuristic.getPartitionCount() > 0); ++ REQUIRE(heuristic.getPartitionCount() == 0); +@@ -250,0 +255,50 @@ TEST_CASE("ensemble predictor regressions", "[PredictorMfeEns]") { ++ SECTION("seed frontier preserves partial sums, ranked sites and filtered regions") { ++ RnaSequence target("target", "GGAGGGGAGGGGAGGGG"); ++ RnaSequence query("query", "CCCCACCCC"); ++ AccessibilityDisabled targetAcc(target, 8, nullptr), queryAcc(query, 8, nullptr); ++ ReverseAccessibility reversed(queryAcc); ++ InteractionEnergyBasePair energy(targetAcc,reversed); ++ for (bool noLP : {false,true}) for (bool heuristic : {false,true}) for (int handler : {0,1,2}) { ++ const size_t bulges=handler==1?1:0; ++ SeedConstraint seeds(2,bulges,bulges,bulges,E_INF,Accessibility::ED_UPPER_BOUND,E_INF, ++ IndexRangeList(),IndexRangeList(),handler==2?"4||&2||,10||&6||":"",false,false,noLP); ++ auto createSeed=[&]() -> SeedHandler * { ++ if (handler==1) return new SeedHandlerMfe(energy,seeds); ++ if (handler==2) return new SeedHandlerExplicit(energy,seeds); ++ return new SeedHandlerNoBulge(energy,seeds); ++ }; ++ OutputConstraint constraint(5,OutputConstraint::OVERLAP_BOTH,E_INF,E_INF, ++ false,noLP,false,true,false); ++ OutputHandlerInteractionList streamedOut(constraint,5), bufferedOut(constraint,5); ++ size_t callbacks=0; ++ auto check=[&](auto & streamed,auto & buffered) { ++ for (const auto & region : {IndexRange(0,16),IndexRange(3,14)}) { ++ streamed.predict(region,IndexRange(1,7)); ++ buffered.predict(region,IndexRange(1,7)); ++ REQUIRE(streamed.getPartitionCount()==0); ++ REQUIRE(buffered.getPartitionCount()>0); ++ REQUIRE(streamed.getZall()==buffered.getZall()); ++ REQUIRE(streamedOut.getZ()==bufferedOut.getZ()); ++ REQUIRE(streamedOut.reported()==bufferedOut.reported()); ++ auto a=streamedOut.begin(), b=bufferedOut.begin(); ++ for (; a!=streamedOut.end() && b!=bufferedOut.end(); ++a,++b) REQUIRE(**a==**b); ++ REQUIRE(a==streamedOut.end()); REQUIRE(b==bufferedOut.end()); ++ } ++ REQUIRE(callbacks>0); ++ }; ++ if (heuristic) { ++ InspectableEnsemblePredictor streamed( ++ energy,streamedOut,createSeed()); ++ InspectableEnsemblePredictor buffered( ++ energy,bufferedOut,createSeed(),new CountingPredictionTracker(callbacks)); ++ check(streamed,buffered); ++ } else { ++ InspectableEnsemblePredictor streamed( ++ energy,streamedOut,createSeed()); ++ InspectableEnsemblePredictor buffered( ++ energy,bufferedOut,createSeed(),new CountingPredictionTracker(callbacks)); ++ check(streamed,buffered); ++ } ++ } ++ } ++ diff --git a/doc/ensemble-memory.md b/doc/ensemble-memory.md new file mode 100644 index 00000000..06a1bcd2 --- /dev/null +++ b/doc/ensemble-memory.md @@ -0,0 +1,183 @@ +# Seed-extension ensemble memory audit (issue #260) + +The additional memory in default `--model=P --mode=H` comes primarily from +retaining a partition for every considered interaction site. Sharing the same +recurrence dimensions with `--model=X` does not imply the same total storage. +The fix releases completed site partitions during seed traversal and stores a +smaller key for the partitions that remain active. Predictions and partition +values are preserved. The measurements below distinguish total process peak RSS +from the sizes of individual recurrence matrices. + +## Source audit + +The reference is `master` at `c5f1d51ce0f8d473b9a3e23ca2e0d410d92d77d7`. +The forward branch is `feat/258-bpsvg` at +`c0ef61f1603ffc41c2ae4f8bbcf98b56027880e9` (PR #259's October 12 revision). + +The CLI routes seeded model X/mode H to +`PredictorMfe2dHeuristicSeedExtension`, and seeded model P/mode H to +`PredictorMfeEns2dHeuristicSeedExtension`. Their common costs include accessibility, +seed preprocessing, local left/right extension tables and ranked-output storage. +They differ in two ways: + +1. Model X uses integer `E_type` energies. The default ensemble `Z_type` is a + double, so equal-size partition matrices need twice the payload bytes on the + measured platform. Optional multiprecision increases this difference. +2. `PredictorMfeEns::updateZ()` also aggregates hybrid partition sums by the + four-coordinate boundary `(i1,j1,i2,j2)` in `Z_partition`. Each entry needs + the boundary, a partition value, hash-node storage and bucket storage. The + seed-extension predictor visits overlapping contributions to the same site; + the site cannot be ranked correctly until those contributions have been + summed. Model X can retain its current minimum and discard worse candidates. + +For example, two seeds contributing to the same site require a sum of their +accepted terms, rather than selecting the better individual term. Reducing this +map to one candidate per left start would change the ensemble objective. +`--outNumber=1` limits reporting, not the number of site sums needed to select +that result. The legacy O(n²) space descriptions account for recurrence tables, +but omit the potentially much larger boundary map. + +The exact **unseeded** 2D predictor already streams complete boundaries through +`updateCompleteZ()`. Seed-extension updates are partial, so applying that path to +each individual seed contribution would be incorrect. + +PR #259 retains the same map on ordinary seeded heuristic runs. Its pair matrix, +outside calculations, signed seed-extension traces and SVG document are optional +and do not explain the issue's commands, which request no probability output. +The patched forward branch was built and tested separately, including its +probability regressions. The benchmark also compares normal CSV predictions +between the master and forward implementations. + +The [tested forward-branch patch](ensemble-memory-probability-port.patch) can be +applied with `git apply --unidiff-zero` at the PR #259 revision above. It preserves that branch's +full heuristic seed-start ranges (`range_size1-1`, `range_size2-1`); master retains +its existing nominal seed-length limits. The exact seeded probability backend's +separate regional finalization path is unchanged. This PR targets master; the +port is supplied separately so the SVG review and memory change remain independent. + +## Finalization without changing recurrences + +The seeded predictors collect starts in their existing handler order and compute +a suffix minimum of the remaining target seed starts. Before processing a seed, +any buffered site with `j1` below this minimum is complete: no remaining seed +can fit inside that site's target boundary. Its final partition updates the +ranked candidates and is then released. Its contributions have already entered +`Zall`, so finalization must not increment `Zall` again. + +Partitions are bucketed by target right boundary. This avoids repeatedly scanning +the whole active map, and makes `j1` redundant in each key. On the measured 64-bit +build, keys shrink from four 8-byte coordinates to three. The final bucket scan +consumes every remaining boundary at `reportOptima()`. + +The recurrence, per-site addition order, global partition addition order, site +filters, seed-overlap corrections and virtual `updateZ()` call are preserved. +`initZ()` resets all storage for predictor reuse and empty subsequent regions. +Tracker-enabled predictions keep the previous deferred map, preserving callback +timing and ordering. Completed boundaries are sufficient for ranked and +nonoverlapping suboptimal selection; that selection uses the existing +`mfe4leftEnd` structure rather than the full partition map. + +The suffix minimum is necessary because computed bulged-seed handlers can advance +query-first, whereas stack/explicit handlers advance target-first. It prevents +premature finalization for either traversal, without changing summation order. +Early release is most effective with target-ordered seeds and a target span much +shorter than the sequence. Query-first traversal, large allowed spans, very sparse +seeds, or requested trackers can reduce the benefit. The additional seed-start +list and right-boundary bucket descriptors are linear storage; the ensemble is +not expected to match model X's memory in every configuration. + +## Measurements + +132 timed runs plus 40 correctness/warmup runs, pinned to CPUs 0–3. Each row +reports the median of three repetitions (six for GcvB-32/model P). All final +runs produce identical CSV field values across the four binaries; parallel row +ordering is ignored. Normal model X controls are included in the JSON. + +Peak RSS, MiB (KiB / 1024): + +| Input | Master X | Master P before | Master P after | Forward P before | Forward P after | +| --- | ---: | ---: | ---: | ---: | ---: | +| OxyS-one | 18.67 | 18.68 | 18.63 | 18.68 | 18.45 | +| OxyS-eight | 23.16 | 25.86 | 25.12 | 26.35 | 25.15 | +| GcvB-32 | 24.39 | 87.34 | 78.49 | 87.79 | 78.42 | +| GcvB-32-noLP | 24.62 | 43.17 | 41.09 | 43.86 | 41.32 | +| dense256x24 | 14.00 | 17.49 | 18.12 | 17.61 | 18.38 | + +Model P wall time, seconds: + +| Input | Master before | Master after | Forward before | Forward after | +| --- | ---: | ---: | ---: | ---: | +| OxyS-one | 0.140 | 0.140 | 0.140 | 0.140 | +| OxyS-eight | 0.780 | 0.780 | 0.770 | 0.780 | +| GcvB-32 | 10.195 | 9.895 | 10.305 | 10.025 | +| GcvB-32-noLP | 3.610 | 3.620 | 3.640 | 3.660 | +| dense256x24 | 31.900 | 31.540 | 31.790 | 32.140 | + +The GcvB-32 cases reproduce the large gap relative to model X on both source +branches. The reduction comes from the boundary storage changes, not from +changing the ensemble or skipping work. The short OxyS cases are dominated by +startup/accessibility and centisecond timing granularity. RSS differences of a +few hundred KiB at the baseline footprint also include allocator/process noise. +The dense stack-only case has little boundary-map storage to release; the seed +list and bucket descriptors can therefore slightly increase its peak RSS. +See the raw results for ranges; these measurements do not promise universal +speedups or equality with the model X footprint. + +## Correctness and integration checks + +- GCC 14.4, C++23, default double partitions and Kokkos mdspan: full release and + debug `make tests -j2`, all six master suites pass; 76,009 API assertions in + 68 cases in both builds. +- Full tests after porting the fix to the current probability implementation: + all seven suites pass, including 101,247 API assertions in 97 cases and the + CSV/SVG probability regressions. +- A buffered tracker run is the independent storage-path reference for the + streaming regression. Exact partition equality and complete ranked-output + equality hold for exact/heuristic seed extension, LP/noLP, computed stack, + computed bulged and explicit seed handlers, cropped regions and predictor + reuse. Tracker callbacks remain active; completed maps are empty after reporting. +- All 69 installed master public headers compile independently. An installed + pkg-config predictor consumer compiles, links and predicts with the documented + Easylogging initialization and installed `libeasylogging`. +- `git diff --check`, UTF-8/LF checks and distribution inclusion are checked. + +A preliminary four-thread CSV comparison failed once before differing output +was retained. The saved warmup CSVs matched. Eight targeted repeats and a further +28 interleaved checks then matched exactly; the cause of that initial observation +could not be established. The final measurements require output equality on +every run, and the supplied script saves any future mismatch for diagnosis. + +Apple Clang, multiprecision builds and the full 4,319-target benchmark screen were +not run locally. The sampled benchmark results describe these inputs and this +machine; they do not establish a universal runtime or memory bound. Requested +pair-probability output and tracker-heavy workloads have additional storage costs. + +## Reproduction + +Build the before/after revisions with the same Autotools configuration and +dependencies. Preserve both binaries before modifying the checkout. Use +`--enable-debug` in a separate source/build tree for debug validation. + +The fixtures come from [BackofenLab/IntaRNA-benchmark](https://github.com/BackofenLab/IntaRNA-benchmark), +revision `2b6a23547039f5a7d883706f12674109d046dec7`: the first 1, 8 and 32 E. coli +target records, OxyS and GcvB queries. An additional synthetic input has 256 G +target nucleotides and 24 C query nucleotides. The script writes the selected +FASTA fixtures, exact commands, raw CSVs, timings, summaries and binary hashes. +GNU time reports wall/user/system seconds and peak RSS in KiB. + +```sh +taskset -c 0-3 python3 doc/benchmark-ensemble-memory.py \ + --before /path/to/master-before --after /path/to/master-after \ + --feat-before /path/to/probability-before --feat-after /path/to/probability-after \ + --benchmark-dir /path/to/IntaRNA-benchmark \ + --outdir /path/to/new-results --repeats 3 +``` + +Select four available CPUs for the affinity mask on another machine. Each +configuration has a correctness/warmup run, followed by three deterministically +interleaved fresh-process repetitions (six for the GcvB-32 ensemble audit). The normal X/P output fields and `Zall` +must match across all four binaries; parallel CSV rows are sorted to ignore +thread completion order. Model X's reported `Zall` is only an output-parity check, +not an exact ensemble partition. No compilation runs during the final timing +pass. [The recorded measurements](ensemble-memory-benchmark.json) include all +model X controls and runtime ranges, rather than only the improved cases. diff --git a/src/IntaRNA/PredictorMfeEns.cpp b/src/IntaRNA/PredictorMfeEns.cpp index 08b2e2d7..e454cf02 100644 --- a/src/IntaRNA/PredictorMfeEns.cpp +++ b/src/IntaRNA/PredictorMfeEns.cpp @@ -33,6 +33,8 @@ initZ() { // reset storage Z_partition.clear(); + Z_frontier.clear(); + Z_frontierNext = 0; } //////////////////////////////////////////////////////////////////////////// @@ -108,12 +110,12 @@ updateZ( const size_t i1, const size_t j1 } // store partial Z (without ED) - Interaction::Boundary key(i1,j1,i2,j2); - auto [keyEntry, inserted] = Z_partition.try_emplace(key, partZ_noED); - if (!inserted) { - // update entry - keyEntry->second += partZ_noED; - } + auto accumulate = [partZ_noED](auto & partitions,const auto & key) { + auto [keyEntry,inserted] = partitions.try_emplace(key,partZ_noED); + if (!inserted) keyEntry->second += partZ_noED; + }; + if (Z_frontier.empty()) accumulate(Z_partition,Interaction::Boundary(i1,j1,i2,j2)); + else accumulate(Z_frontier.at(j1),FrontierBoundary{i1,i2,j2}); } @@ -154,6 +156,7 @@ void PredictorMfeEns:: updateOptimaUsingZ() { + advanceZFrontier(Z_frontier.size()); for (auto it = Z_partition.begin(); it != Z_partition.end(); ++it) { // if partition function is > 0 @@ -163,6 +166,28 @@ updateOptimaUsingZ() } } +void PredictorMfeEns::beginZFrontier(size_t size1) +{ + if (predTracker == nullptr) Z_frontier.resize(size1); +} + +void PredictorMfeEns::advanceZFrontier(size_t minimumSeedStart) +{ + const size_t end = std::min(minimumSeedStart,Z_frontier.size()); + while (Z_frontierNext < end) { + auto & partitions = Z_frontier[Z_frontierNext]; + for (const auto & [boundary,partition] : partitions) { + if (Z_isNotINF(partition) && partition > 0) { + PredictorMfe::updateOptima(boundary.i1,Z_frontierNext,boundary.i2,boundary.j2, + energy.getE(partition),true,false); + } + } + // Free both nodes and bucket storage as soon as this boundary is complete. + decltype(Z_frontier)::value_type{}.swap(partitions); + ++Z_frontierNext; + } +} + //////////////////////////////////////////////////////////////////////////// void diff --git a/src/IntaRNA/PredictorMfeEns.h b/src/IntaRNA/PredictorMfeEns.h index 2037d52f..3b6af68f 100644 --- a/src/IntaRNA/PredictorMfeEns.h +++ b/src/IntaRNA/PredictorMfeEns.h @@ -8,7 +8,10 @@ #include "IntaRNA/IndexRangeList.h" #include +#include #include +#include +#include namespace IntaRNA { @@ -65,6 +68,21 @@ class PredictorMfeEns : public PredictorMfe { bool updateZisComplete; + //! a bucket supplies j1, so its key needs only the other three coordinates + struct FrontierBoundary { + size_t i1, i2, j2; + bool operator==(const FrontierBoundary &) const = default; + struct Hash { + size_t operator()(const FrontierBoundary & boundary) const; + }; + }; + + //! partial sums grouped by target right boundary; used only without trackers + std::vector> Z_frontier; + //! first right-boundary bucket that has not yet been finalized + size_t Z_frontierNext = 0; + + /** * Initializes the hybridization partition functions. * Will be called by predict(). @@ -111,6 +129,18 @@ class PredictorMfeEns : public PredictorMfe { , const Z_type partFunct , const bool isHybridZ ); + /** Enable partial-partition buckets by target right boundary. Tracker runs + * keep the original map to preserve callback ordering. Call advanceZFrontier + * only when no remaining seed can start below the supplied target index. + * @param size1 number of target positions in the current prediction region + */ + void beginZFrontier(size_t size1); + + /** Consume completed boundary sums without adding their mass to Zall again. + * @param minimumSeedStart smallest target start of any remaining seed + */ + void advanceZFrontier(size_t minimumSeedStart); + /** * Calls for the stored Z_partition information updateOptima() before * calling reportOptima() from its super class. @@ -151,6 +181,17 @@ class PredictorMfeEns : public PredictorMfe { }; +inline +size_t +PredictorMfeEns::FrontierBoundary::Hash::operator()(const FrontierBoundary & boundary) const +{ + size_t key=0; + boost::hash_combine(key,boundary.i1); + boost::hash_combine(key,boundary.i2); + boost::hash_combine(key,boundary.j2); + return key; +} + } // namespace #endif /* INTARNA_PREDICTORMFEENS_H_ */ diff --git a/src/IntaRNA/PredictorMfeEns2dHeuristicSeedExtension.cpp b/src/IntaRNA/PredictorMfeEns2dHeuristicSeedExtension.cpp index 4cf8aeaa..a018c4dd 100644 --- a/src/IntaRNA/PredictorMfeEns2dHeuristicSeedExtension.cpp +++ b/src/IntaRNA/PredictorMfeEns2dHeuristicSeedExtension.cpp @@ -72,11 +72,11 @@ predict( const IndexRange & r1, const IndexRange & r2 ) // initialize overall partition function for updates initZ(); - size_t si1 = RnaSequence::lastPos, si2 = RnaSequence::lastPos; - while( seedHandler.updateToNextSeed(si1,si2 - , 0, range_size1+1-seedHandler.getConstraint().getBasePairs() - , 0, range_size2+1-seedHandler.getConstraint().getBasePairs()) ) - { + beginZFrontier(range_size1); + for (const auto & seed : getSeedStarts(range_size1+1-seedHandler.getConstraint().getBasePairs(), + range_size2+1-seedHandler.getConstraint().getBasePairs())) { + advanceZFrontier(seed.minimumRemaining); + const size_t si1=seed.i1, si2=seed.i2; const Z_type seedZ = energy.getBoltzmannWeight( seedHandler.getSeedE(si1, si2) ); const size_t sl1 = seedHandler.getSeedLength1(si1, si2); const size_t sl2 = seedHandler.getSeedLength2(si1, si2); diff --git a/src/IntaRNA/PredictorMfeEns2dSeedExtension.cpp b/src/IntaRNA/PredictorMfeEns2dSeedExtension.cpp index d5adb5c4..34281ea2 100644 --- a/src/IntaRNA/PredictorMfeEns2dSeedExtension.cpp +++ b/src/IntaRNA/PredictorMfeEns2dSeedExtension.cpp @@ -3,6 +3,24 @@ namespace IntaRNA { +std::vector +PredictorMfeEns2dSeedExtension::getSeedStarts(size_t max1,size_t max2) const +{ + std::vector starts; + size_t i1=RnaSequence::lastPos, i2=RnaSequence::lastPos; + while (seedHandler.updateToNextSeed(i1,i2, + 0,max1,0,max2)) { + starts.push_back({i1,i2,i1}); + } + // A suffix minimum is safe for either traversal order and custom handlers. + size_t minimum=max1; + for (auto seed=starts.rbegin(); seed!=starts.rend(); ++seed) { + minimum=std::min(minimum,seed->i1); + seed->minimumRemaining=minimum; + } + return starts; +} + ////////////////////////////////////////////////////////////////////////// PredictorMfeEns2dSeedExtension:: @@ -73,11 +91,11 @@ predict( const IndexRange & r1, const IndexRange & r2 ) // initialize overall partition function for updates initZ(); - size_t si1 = RnaSequence::lastPos, si2 = RnaSequence::lastPos; - while( seedHandler.updateToNextSeed(si1,si2 - , 0, range_size1+1-seedHandler.getConstraint().getBasePairs() - , 0, range_size2+1-seedHandler.getConstraint().getBasePairs()) ) - { + beginZFrontier(range_size1); + for (const auto & seed : getSeedStarts(range_size1+1-seedHandler.getConstraint().getBasePairs(), + range_size2+1-seedHandler.getConstraint().getBasePairs())) { + advanceZFrontier(seed.minimumRemaining); + const size_t si1=seed.i1, si2=seed.i2; // get Z and boundaries of seed const Z_type seedZ = energy.getBoltzmannWeight( seedHandler.getSeedE(si1, si2) ); const size_t sl1 = seedHandler.getSeedLength1(si1, si2); diff --git a/src/IntaRNA/PredictorMfeEns2dSeedExtension.h b/src/IntaRNA/PredictorMfeEns2dSeedExtension.h index 92107dac..5320acd5 100644 --- a/src/IntaRNA/PredictorMfeEns2dSeedExtension.h +++ b/src/IntaRNA/PredictorMfeEns2dSeedExtension.h @@ -23,6 +23,15 @@ namespace IntaRNA { class PredictorMfeEns2dSeedExtension: public PredictorMfeEns { protected: + //! seed coordinates in handler order and the minimum remaining target start + struct SeedStart { size_t i1, i2, minimumRemaining; }; + + /** Collect seed starts without changing traversal or partition summation order. + * @param max1 largest target seed start + * @param max2 largest reversed-query seed start + * @return starts with a safe lower bound for all remaining target seed starts + */ + std::vector getSeedStarts(size_t max1,size_t max2) const; //! matrix type to hold the partition functions for interaction site starts typedef Matrix Z2dMatrix; diff --git a/tests/PredictorMfeEnsRegression_test.cpp b/tests/PredictorMfeEnsRegression_test.cpp index faf71ec2..1ff4fbe7 100644 --- a/tests/PredictorMfeEnsRegression_test.cpp +++ b/tests/PredictorMfeEnsRegression_test.cpp @@ -13,6 +13,8 @@ #include "IntaRNA/ReverseAccessibility.h" #include "IntaRNA/RnaSequence.h" #include "IntaRNA/SeedHandlerNoBulge.h" +#include "IntaRNA/SeedHandlerMfe.h" +#include "IntaRNA/SeedHandlerExplicit.h" #include #include @@ -26,12 +28,14 @@ class InspectableEnsemblePredictor : public PredictorType { InspectableEnsemblePredictor( const InteractionEnergy & energy, OutputHandler & output, - SeedHandler * seedHandler) - : PredictorType(energy, output, NULL, seedHandler) + SeedHandler * seedHandler, PredictionTracker * tracker=nullptr) + : PredictorType(energy, output, tracker, seedHandler) {} size_t getPartitionCount() const { - return this->Z_partition.size(); + size_t count=this->Z_partition.size(); + for (const auto & bucket : this->Z_frontier) count+=bucket.size(); + return count; } }; @@ -231,7 +235,7 @@ TEST_CASE("ensemble predictor regressions", "[PredictorMfeEns]") { InspectableEnsemblePredictor exact( energy, exactOut, new SeedHandlerNoBulge(energy, seedConstraint)); exact.predict(); - REQUIRE(exact.getPartitionCount() > 0); + REQUIRE(exact.getPartitionCount() == 0); exact.predict(IndexRange(0, 0), IndexRange(0, 0)); REQUIRE(exact.getPartitionCount() == 0); REQUIRE(exact.getZall() == 0.0); @@ -240,12 +244,62 @@ TEST_CASE("ensemble predictor regressions", "[PredictorMfeEns]") { InspectableEnsemblePredictor heuristic( energy, heuristicOut, new SeedHandlerNoBulge(energy, seedConstraint)); heuristic.predict(); - REQUIRE(heuristic.getPartitionCount() > 0); + REQUIRE(heuristic.getPartitionCount() == 0); heuristic.predict(IndexRange(0, 0), IndexRange(0, 0)); REQUIRE(heuristic.getPartitionCount() == 0); REQUIRE(heuristic.getZall() == 0.0); } + SECTION("seed frontier preserves partial sums, ranked sites and filtered regions") { + RnaSequence target("target", "GGAGGGGAGGGGAGGGG"); + RnaSequence query("query", "CCCCACCCC"); + AccessibilityDisabled targetAcc(target, 8, nullptr), queryAcc(query, 8, nullptr); + ReverseAccessibility reversed(queryAcc); + InteractionEnergyBasePair energy(targetAcc,reversed); + for (bool noLP : {false,true}) for (bool heuristic : {false,true}) for (int handler : {0,1,2}) { + const size_t bulges=handler==1?1:0; + SeedConstraint seeds(2,bulges,bulges,bulges,E_INF,Accessibility::ED_UPPER_BOUND,E_INF, + IndexRangeList(),IndexRangeList(),handler==2?"4||&2||,10||&6||":"",false,false,noLP); + auto createSeed=[&]() -> SeedHandler * { + if (handler==1) return new SeedHandlerMfe(energy,seeds); + if (handler==2) return new SeedHandlerExplicit(energy,seeds); + return new SeedHandlerNoBulge(energy,seeds); + }; + OutputConstraint constraint(5,OutputConstraint::OVERLAP_BOTH,E_INF,E_INF, + false,noLP,false,true,false); + OutputHandlerInteractionList streamedOut(constraint,5), bufferedOut(constraint,5); + size_t callbacks=0; + auto check=[&](auto & streamed,auto & buffered) { + for (const auto & region : {IndexRange(0,16),IndexRange(3,14)}) { + streamed.predict(region,IndexRange(1,7)); + buffered.predict(region,IndexRange(1,7)); + REQUIRE(streamed.getPartitionCount()==0); + REQUIRE(buffered.getPartitionCount()>0); + REQUIRE(streamed.getZall()==buffered.getZall()); + REQUIRE(streamedOut.getZ()==bufferedOut.getZ()); + REQUIRE(streamedOut.reported()==bufferedOut.reported()); + auto a=streamedOut.begin(), b=bufferedOut.begin(); + for (; a!=streamedOut.end() && b!=bufferedOut.end(); ++a,++b) REQUIRE(**a==**b); + REQUIRE(a==streamedOut.end()); REQUIRE(b==bufferedOut.end()); + } + REQUIRE(callbacks>0); + }; + if (heuristic) { + InspectableEnsemblePredictor streamed( + energy,streamedOut,createSeed()); + InspectableEnsemblePredictor buffered( + energy,bufferedOut,createSeed(),new CountingPredictionTracker(callbacks)); + check(streamed,buffered); + } else { + InspectableEnsemblePredictor streamed( + energy,streamedOut,createSeed()); + InspectableEnsemblePredictor buffered( + energy,bufferedOut,createSeed(),new CountingPredictionTracker(callbacks)); + check(streamed,buffered); + } + } + } + SECTION("exact complete boundaries stream unless tracker ordering is required") { RnaSequence target("target", "GGGG"); RnaSequence query("query", "CCCC");