package com.milaboratory.core.alignment.benchmark; import cc.redberry.pipe.CUtils; import cc.redberry.pipe.Processor; import com.milaboratory.core.alignment.batch.BatchAlignerWithBaseParameters; import com.milaboratory.core.alignment.AlignmentUtils; import com.milaboratory.core.alignment.batch.AlignmentHit; import com.milaboratory.core.alignment.batch.AlignmentResult; import com.milaboratory.core.alignment.batch.BatchAlignerWithBase; import com.milaboratory.core.alignment.kaligner2.KAligner2Statistics; import com.milaboratory.core.sequence.NucleotideSequence; import com.milaboratory.util.RandomUtil; public final class Benchmark<T extends BatchAlignerWithBaseParameters> implements Processor<BenchmarkInput<T>, BenchmarkResults> { final long maxExecutionTime; final long maxNoHits; ExceptionListener exceptionListener; public Benchmark(long maxExecutionTime) { this(maxExecutionTime, Integer.MAX_VALUE); } public Benchmark(long maxExecutionTime, long maxNoHits) { this.maxExecutionTime = maxExecutionTime; this.maxNoHits = maxNoHits; } public void setExceptionListener(ExceptionListener exceptionListener) { this.exceptionListener = exceptionListener; } @Override public BenchmarkResults process(BenchmarkInput input) { RandomUtil.reseedThreadLocal(input.challenge.seed); KAligner2Statistics stat = new KAligner2Statistics(); BatchAlignerWithBase<NucleotideSequence, Integer, ? extends AlignmentHit> aligner = input.params.createAligner(); NucleotideSequence[] db = input.challenge.getDB(); for (int i = 0; i < db.length; i++) aligner.addReference(db[i], i); long executionTime = 0; int processedQueries = 0; int processedGoodQueries = 0; int falsePositives = 0; int mismatched = 0; int noHits = 0; int scoreError = 0; long start = System.nanoTime(); OUTER: for (KAlignerQuery query : CUtils.it(input.challenge.queries())) { if (System.nanoTime() - start > maxExecutionTime) break; if (noHits > maxNoHits) break; long seed = RandomUtil.reseedThreadLocal(); try { long b = System.nanoTime(); AlignmentResult<? extends AlignmentHit> result = aligner.align(query.query); executionTime += (System.nanoTime() - b); ++processedQueries; if (query.isFalse()) { if (result.hasHits()) ++falsePositives; } else { ++processedGoodQueries; if (!result.hasHits()) { ++noHits; continue; } for (AlignmentHit hit : result.getHits()) if (!query.query.getRange(hit.getAlignment().getSequence2Range()) .equals(AlignmentUtils.getAlignedSequence2Part(hit.getAlignment()))) { System.out.println("Expected:"); System.out.println(query.expectedAlignment.getAlignmentHelper()); System.out.println("Actual:"); System.out.println(hit.getAlignment().getAlignmentHelper()); throw new RuntimeException("Wrong answer."); } float topScore = result.getHits().get(0).getAlignment().getScore(); for (AlignmentHit hit : result.getHits()) { if (hit.getAlignment().getScore() != topScore) break; if (hit.getRecordPayload().equals(query.targetId)) { if (topScore < 0.95 * query.expectedAlignment.getScore()) { // System.out.println("\n\n\n======================\n\n"); // System.out.println("expected score: " + query.expectedAlignment.getScore()); // System.out.println(query.expectedAlignment.getAlignmentHelper()); // System.out.println("\n"); // System.out.println("actual score: " + hit.getAlignment().getScore()); // System.out.println(hit.getAlignment().getAlignmentHelper()); ++scoreError; } continue OUTER; } } ++mismatched; } } catch (Exception e) { if (exceptionListener != null) exceptionListener.onException(new ExceptionData(seed, e, db, query.query, input)); else throw e; } } return new BenchmarkResults(input, stat, executionTime, processedQueries, processedGoodQueries, falsePositives, mismatched, noHits, scoreError); } public interface ExceptionListener { void onException(ExceptionData exceptionData); } public static final class ExceptionData { public final long seed; public final Throwable exception; public final NucleotideSequence[] db; public final NucleotideSequence query; public final BenchmarkInput input; public ExceptionData(long seed, Throwable exception, NucleotideSequence[] db, NucleotideSequence query, BenchmarkInput input) { this.seed = seed; this.exception = exception; this.db = db; this.query = query; this.input = input; } } }