Skip to content

Commit

Permalink
Memory footprint estimates
Browse files Browse the repository at this point in the history
  • Loading branch information
robertvazan committed Aug 20, 2023
1 parent 416282b commit 24add29
Show file tree
Hide file tree
Showing 8 changed files with 567 additions and 453 deletions.
217 changes: 110 additions & 107 deletions src/main/java/com/machinezoo/sourceafis/FingerprintMatcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import java.util.*;
import com.machinezoo.sourceafis.engine.matcher.*;
import com.machinezoo.sourceafis.engine.primitives.*;
import com.machinezoo.sourceafis.engine.templates.*;

/**
Expand All @@ -17,111 +18,113 @@
* @see FingerprintTemplate
*/
public class FingerprintMatcher {
/*
* API roadmap:
* + FingerprintMatcher(FingerprintTemplate, FingerprintMatcherOptions)
* + compare(FingerprintTemplate) - returns match log-odds in bits instead of current score, may be negative
* - match(FingerprintTemplate)
* + maybe features to support 1:N identification (parallelization, score adjustment, person model, ...)
*
* FingerprintMatcherOptions:
* + matchX(boolean) - enable or disable various parts of the matcher for performance reasons
* + processorBudget(double) - automated feature/algorithm selection to target "average" compute cost per candidate
*
* FingerprintEvidence:
* = calculation of effective score in multi-finger or 1:N matching
* + add(double)
* + add(FingerprintPosition, double)
* + add(FingerprintEvidence)
* + top(int subset, int population)
* + sum()
* + thresholdAtFMR(double) - might have variant, still unclear
*/
private volatile Probe probe = Probe.NULL;
/**
* Creates fingerprint template representation optimized for fast 1:N matching.
* Once the probe template is processed, candidate templates can be compared to it
* by calling {@link #match(FingerprintTemplate)}.
* <p>
* This constructor is expensive in terms of RAM footprint and CPU usage.
* Initialized {@code FingerprintMatcher} should be reused for multiple {@link #match(FingerprintTemplate)} calls in 1:N matching.
*
* @param probe
* probe fingerprint template to be matched to candidate fingerprints
* @throws NullPointerException
* if {@code probe} is {@code null}
*
* @see #match(FingerprintTemplate)
*/
public FingerprintMatcher(FingerprintTemplate probe) {
Objects.requireNonNull(probe);
SearchTemplate template = probe.inner;
this.probe = new Probe(template, EdgeHashes.build(template));
}
/**
* @deprecated Use {@link #FingerprintMatcher(FingerprintTemplate)} constructor to fully initialize the matcher.
*
* @see #FingerprintMatcher(FingerprintTemplate)
*/
@Deprecated
public FingerprintMatcher() {
}
/**
* @deprecated Use thread-local instance of {@link FingerprintTransparency} instead.
*
* @param transparency
* target {@link FingerprintTransparency} or {@code null} to disable algorithm transparency
* @return {@code this} (fluent method)
*
* @see FingerprintTransparency
*/
@Deprecated
public FingerprintMatcher transparency(FingerprintTransparency transparency) {
return this;
}
/**
* @deprecated Use {@link #FingerprintMatcher(FingerprintTemplate)} constructor to initialize the matcher.
*
* @param probe
* probe fingerprint template to be matched to candidate fingerprints
* @return {@code this} (fluent method)
* @throws NullPointerException
* if {@code probe} is {@code null}
*
* @see #FingerprintMatcher(FingerprintTemplate)
*/
@Deprecated
public FingerprintMatcher index(FingerprintTemplate probe) {
Objects.requireNonNull(probe);
SearchTemplate template = probe.inner;
this.probe = new Probe(template, EdgeHashes.build(template));
return this;
}
/**
* Matches candidate fingerprint to probe fingerprint and calculates similarity score.
* Candidate fingerprint in {@code candidate} parameter is matched to probe fingerprint
* previously passed to {@link #FingerprintMatcher(FingerprintTemplate)} constructor.
* <p>
* Returned similarity score is a non-negative number that increases with similarity between probe and candidate fingerprints.
* Application should compare the score to a threshold with expression {@code (score >= threshold)} to arrive at boolean match/non-match decision.
* Threshold 10 corresponds to FMR (False Match Rate, see <a href="https://en.wikipedia.org/wiki/Biometrics#Performance">Biometric Performance</a>
* and <a href="https://en.wikipedia.org/wiki/Confusion_matrix">Confusion matrix</a>) of 10%, threshold 20 to FMR 1%, threshold 30 to FMR 0.1%, and so on.
* <p>
* Recommended threshold is 40, which corresponds to FMR 0.01%.
* Correspondence between threshold and FMR is approximate and varies with quality of fingerprints being matched.
* Increasing threshold rapidly reduces FMR, but it also slowly increases FNMR (False Non-Match Rate).
* Threshold must be tailored to the needs of the application.
* <p>
* This method is thread-safe. Multiple threads can match candidates against single {@code FingerprintMatcher}.
*
* @param candidate
* fingerprint template to be matched with probe fingerprint represented by this {@code FingerprintMatcher}
* @return similarity score between probe and candidate fingerprints
* @throws NullPointerException
* if {@code candidate} is {@code null}
*/
public double match(FingerprintTemplate candidate) {
Objects.requireNonNull(candidate);
return MatcherEngine.match(probe, candidate.inner);
}
/*
* API roadmap:
* + FingerprintMatcher(FingerprintTemplate, FingerprintMatcherOptions)
* + compare(FingerprintTemplate) - returns match log-odds in bits instead of current score, may be negative
* - match(FingerprintTemplate)
* + maybe features to support 1:N identification (parallelization, score adjustment, person model, ...)
*
* FingerprintMatcherOptions:
* + matchX(boolean) - enable or disable various parts of the matcher for performance reasons
* + processorBudget(double) - automated feature/algorithm selection to target "average" compute cost per candidate
*
* FingerprintEvidence:
* = calculation of effective score in multi-finger or 1:N matching
* + add(double)
* + add(FingerprintPosition, double)
* + add(FingerprintEvidence)
* + top(int subset, int population)
* + sum()
* + thresholdAtFMR(double) - might have variant, still unclear
*/
private volatile Probe probe = Probe.NULL;
/**
* Creates fingerprint template representation optimized for fast 1:N matching.
* Once the probe template is processed, candidate templates can be compared to it
* by calling {@link #match(FingerprintTemplate)}.
* <p>
* This constructor is expensive in terms of RAM footprint and CPU usage.
* Initialized {@code FingerprintMatcher} should be reused for multiple {@link #match(FingerprintTemplate)} calls in 1:N matching.
*
* @param probe
* probe fingerprint template to be matched to candidate fingerprints
* @throws NullPointerException
* if {@code probe} is {@code null}
*
* @see #match(FingerprintTemplate)
*/
public FingerprintMatcher(FingerprintTemplate probe) {
Objects.requireNonNull(probe);
SearchTemplate template = probe.inner;
this.probe = new Probe(template, EdgeHashes.build(template));
}
/**
* @deprecated Use {@link #FingerprintMatcher(FingerprintTemplate)} constructor to fully initialize the matcher.
*
* @see #FingerprintMatcher(FingerprintTemplate)
*/
@Deprecated public FingerprintMatcher() {}
/**
* @deprecated Use thread-local instance of {@link FingerprintTransparency} instead.
*
* @param transparency
* target {@link FingerprintTransparency} or {@code null} to disable algorithm transparency
* @return {@code this} (fluent method)
*
* @see FingerprintTransparency
*/
@Deprecated public FingerprintMatcher transparency(FingerprintTransparency transparency) { return this; }
/**
* @deprecated Use {@link #FingerprintMatcher(FingerprintTemplate)} constructor to initialize the matcher.
*
* @param probe
* probe fingerprint template to be matched to candidate fingerprints
* @return {@code this} (fluent method)
* @throws NullPointerException
* if {@code probe} is {@code null}
*
* @see #FingerprintMatcher(FingerprintTemplate)
*/
@Deprecated public FingerprintMatcher index(FingerprintTemplate probe) {
Objects.requireNonNull(probe);
SearchTemplate template = probe.inner;
this.probe = new Probe(template, EdgeHashes.build(template));
return this;
}
/**
* Matches candidate fingerprint to probe fingerprint and calculates similarity score.
* Candidate fingerprint in {@code candidate} parameter is matched to probe fingerprint
* previously passed to {@link #FingerprintMatcher(FingerprintTemplate)} constructor.
* <p>
* Returned similarity score is a non-negative number that increases with similarity between probe and candidate fingerprints.
* Application should compare the score to a threshold with expression {@code (score >= threshold)} to arrive at boolean match/non-match decision.
* Threshold 10 corresponds to FMR (False Match Rate, see <a href="https://en.wikipedia.org/wiki/Biometrics#Performance">Biometric Performance</a>
* and <a href="https://en.wikipedia.org/wiki/Confusion_matrix">Confusion matrix</a>) of 10%, threshold 20 to FMR 1%, threshold 30 to FMR 0.1%, and so on.
* <p>
* Recommended threshold is 40, which corresponds to FMR 0.01%.
* Correspondence between threshold and FMR is approximate and varies with quality of fingerprints being matched.
* Increasing threshold rapidly reduces FMR, but it also slowly increases FNMR (False Non-Match Rate).
* Threshold must be tailored to the needs of the application.
* <p>
* This method is thread-safe. Multiple threads can match candidates against single {@code FingerprintMatcher}.
*
* @param candidate
* fingerprint template to be matched with probe fingerprint represented by this {@code FingerprintMatcher}
* @return similarity score between probe and candidate fingerprints
* @throws NullPointerException
* if {@code candidate} is {@code null}
*/
public double match(FingerprintTemplate candidate) {
Objects.requireNonNull(candidate);
return MatcherEngine.match(probe, candidate.inner);
}
/**
* Estimates memory footprint of this object.
* This is a deep estimate, including all nested objects.
* The estimate should be fairly accurate on all commonly used JVMs.
*
* @return estimated memory footprint of this object in bytes
*/
public int memory() { return MemoryEstimates.object(MemoryEstimates.REFERENCE, MemoryEstimates.REFERENCE) + probe.memory(); }
}
Loading

0 comments on commit 24add29

Please sign in to comment.