import java.util.*;
import java.util.zip.*;
import java.util.List;
import java.util.regex.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.concurrent.locks.*;
import java.util.function.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.table.*;
import java.io.*;
import java.net.*;
import java.lang.reflect.*;
import java.lang.ref.*;
import java.lang.management.*;
import java.security.*;
import java.security.spec.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.imageio.*;
import java.math.*;
import java.time.Duration;
import java.lang.invoke.VarHandle;
import java.lang.invoke.MethodHandles;
import static x30_pkg.x30_util.DynamicObject;
import java.awt.geom.*;
import java.text.*;
import java.text.NumberFormat;
import java.util.TimeZone;
import java.nio.file.Path;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
class main {
static class G22FindSimilarMasksTask {
// Image we are looking up
final public G22FindSimilarMasksTask setQueryImage(Image2B queryImage){ return queryImage(queryImage); }
public G22FindSimilarMasksTask queryImage(Image2B queryImage) { this.queryImage = queryImage; return this; } final public Image2B getQueryImage(){ return queryImage(); }
public Image2B queryImage() { return queryImage; }
Image2B queryImage;
// optional - which primary mask holder is tasked with the search
final public G22FindSimilarMasksTask setMaskSet(IG22MasksHolder maskSet){ return maskSet(maskSet); }
public G22FindSimilarMasksTask maskSet(IG22MasksHolder maskSet) { this.maskSet = maskSet; return this; } final public IG22MasksHolder getMaskSet(){ return maskSet(); }
public IG22MasksHolder maskSet() { return maskSet; }
IG22MasksHolder maskSet;
// where the found masks go (probability = similarity)
final public G22FindSimilarMasksTask setOutList(ProbabilisticList outList){ return outList(outList); }
public G22FindSimilarMasksTask outList(ProbabilisticList outList) { this.outList = outList; return this; } final public ProbabilisticList getOutList(){ return outList(); }
public ProbabilisticList outList() { return outList; }
ProbabilisticList outList = new ProbabilisticList();
// probabilistic stack & scheduler
final public G22FindSimilarMasksTask setPstack(PStack pstack){ return pstack(pstack); }
public G22FindSimilarMasksTask pstack(PStack pstack) { this.pstack = pstack; return this; } final public PStack getPstack(){ return pstack(); }
public PStack pstack() { return pstack; }
PStack pstack = new PStack();
// how many full mask comparisons were made
int comparisons;
// We all know what this is for
final public G22FindSimilarMasksTask setVerbose(boolean verbose){ return verbose(verbose); }
public G22FindSimilarMasksTask verbose(boolean verbose) { this.verbose = verbose; return this; } final public boolean getVerbose(){ return verbose(); }
public boolean verbose() { return verbose; }
boolean verbose = false;
// Has the search been ended?
final public G22FindSimilarMasksTask setEnded(boolean ended){ return ended(ended); }
public G22FindSimilarMasksTask ended(boolean ended) { this.ended = ended; return this; } final public boolean getEnded(){ return ended(); }
public boolean ended() { return ended; }
boolean ended = false;
class FoundMask {
final public FoundMask setMask(IG22Mask mask){ return mask(mask); }
public FoundMask mask(IG22Mask mask) { this.mask = mask; return this; } final public IG22Mask getMask(){ return mask(); }
public IG22Mask mask() { return mask; }
IG22Mask mask;
final public FoundMask setSimilarity(double similarity){ return similarity(similarity); }
public FoundMask similarity(double similarity) { this.similarity = similarity; return this; } final public double getSimilarity(){ return similarity(); }
public double similarity() { return similarity; }
double similarity; // zero to one
final public FoundMask setCandidateNumber(int candidateNumber){ return candidateNumber(candidateNumber); }
public FoundMask candidateNumber(int candidateNumber) { this.candidateNumber = candidateNumber; return this; } final public int getCandidateNumber(){ return candidateNumber(); }
public int candidateNumber() { return candidateNumber; }
int candidateNumber;
final public FoundMask setStepCount(long stepCount){ return stepCount(stepCount); }
public FoundMask stepCount(long stepCount) { this.stepCount = stepCount; return this; } final public long getStepCount(){ return stepCount(); }
public long stepCount() { return stepCount; }
long stepCount;
final public FoundMask setFoundAtProbability(double foundAtProbability){ return foundAtProbability(foundAtProbability); }
public FoundMask foundAtProbability(double foundAtProbability) { this.foundAtProbability = foundAtProbability; return this; } final public double getFoundAtProbability(){ return foundAtProbability(); }
public double foundAtProbability() { return foundAtProbability; }
double foundAtProbability;
Image2B image() { return mask.image(); }
A label() { return mask.label(); }
public String toString() {
return renderVars("FoundMask",
"label", label(),
"similarity" , formatPercent(similarity),
"candidateNumber", candidateNumber);
}
}
G22FindSimilarMasksTask() {}
G22FindSimilarMasksTask(IG22Mask mask) { queryImage(mask.image()); }
G22FindSimilarMasksTask(Image2B image) { queryImage(image); }
G22FindSimilarMasksTask(IImageRegion region, IG22MasksHolder maskSet) {
this.maskSet = maskSet;
queryImage(maskSet.regionToMaskImage(region));
}
IProbabilisticScheduler scheduler() { return pstack.scheduler(); }
void tryMask(IG22Mask candidate) {
if (candidate == null) return;
comparisons++;
var candidateImage = candidate.image();
long diff = binaryImagePixelDifference_sameSize(queryImage, candidateImage);
double p = liftProbabilityOffGround(1-doubleRatio(diff, area(candidateImage)));
if (verbose)
printVars("Candidate tested", "diff", diff, "p", p, "candidate", candidate);
foundMask(candidate, p);
}
void foundMask(IG22Mask mask, double similarity) {
long stepCount = scheduler().stepCount();
if (verbose)
print("Found mask with similarity " + formatDouble3X(similarity) + " in step " + stepCount);
outList.at(similarity,
new FoundMask().mask(mask).similarity(similarity)
// stats to test effectivity of search heuristic
.candidateNumber(comparisons).stepCount(stepCount)
.foundAtProbability(scheduler().currentProbability()));
}
void endSearch() { ended(true); }
// one-stop function
ProbabilisticList get() { return get(maskSet); }
ProbabilisticList get(IG22MasksHolder maskSet) {
pstack.run(maskSet.findSimilarMasks(this));
return outList;
}
}
// Use like this: renderVars(+x, +y)
// Or like this: renderVars SomeID(+x, +y)
static String renderVars(Object... params) {
return renderVars_str(params);
}
static String formatPercent(double ratio) {
return formatDouble(ratio*100, 1) + "%";
}
static int binaryImagePixelDifference_sameSize(Image2B img1, Image2B img2) {
assertSameSize(img1, img2);
return countDifferingBits(img1.pixels, img2.pixels);
}
static int binaryImagePixelDifference_sameSize(Image2BAsInts img1, Image2BAsInts img2) {
assertSameSize(img1, img2);
return countDifferingBits(img1.pixels, img2.pixels);
}
static int binaryImagePixelDifference_sameSize(Image2BAsLongs img1, Image2BAsLongs img2) {
assertSameSize(img1, img2);
return countDifferingBits(img1.pixels, img2.pixels);
}
static double liftProbabilityOffGround(double p) {
double epsilon = 0.01;
return 1-(1-p)*(1-epsilon);
}
static double doubleRatio(double x, double y) {
return y == 0 ? 0 : x/y;
}
static double doubleRatio(Seconds x, Seconds y) {
return doubleRatio(x.get(), y.get());
}
static int area(Rect r) {
return rectArea(r);
}
static double area(DoubleRect r) {
return r == null ? 0 : r.w*r.h;
}
static int area(WidthAndHeight img) {
return img == null ? 0 : img.getWidth()*img.getHeight();
}
static int area(BufferedImage img) {
return img == null ? 0 : img.getWidth()*img.getHeight();
}
// Use like this: printVars(+x, +y);
// Or: printVars("bla", +x);
// Or: printVars bla(, +x);
static void printVars(Object... params) {
printVars_str(params);
}
static volatile StringBuffer local_log = new StringBuffer(); // not redirected
static boolean printAlsoToSystemOut = true;
static volatile Appendable print_log = local_log; // might be redirected, e.g. to main bot
// in bytes - will cut to half that
static volatile int print_log_max = 1024*1024;
static volatile int local_log_max = 100*1024;
static boolean print_silent = false; // total mute if set
static Object print_byThread_lock = new Object();
static volatile ThreadLocal