// Path: src/main/java/ro/hasna/ts/math/stat/BothWaySummaryStatistics.java
// public class BothWaySummaryStatistics implements StatisticalSummary, Serializable, Cloneable {
//     private static final long serialVersionUID = -8419769227216721345L;
//     private long n;
//     private double sum;
//     private double sumSquares;
//     private Max max;
//     private Min min;
//     private boolean removeMade;
// 
//     public BothWaySummaryStatistics() {
//         n = 0;
//         sum = 0;
//         sumSquares = 0;
//         max = new Max();
//         min = new Min();
//         removeMade = false;
//     }
// 
//     public void addValue(double d) {
//         sum += d;
//         sumSquares += d * d;
//         n++;
//         if (!removeMade) {
//             max.increment(d);
//             min.increment(d);
//         }
//     }
// 
//     public void removeValue(double d) {
//         if (n == 0) {
//             throw new InsufficientDataException();
//         }
// 
//         sum -= d;
//         sumSquares -= d * d;
//         n--;
//         removeMade = true;
//         max.clear();
//         min.clear();
//     }
// 
//     @Override
//     public double getMean() {
//         if (n == 0) return 0;
//         return sum / n;
//     }
// 
//     @Override
//     public double getVariance() {
//         if (n == 0) return Double.NaN;
//         if (n == 1) return 0;
//         double mean = getMean();
//         return sumSquares / n - mean * mean;
//     }
// 
//     @Override
//     public double getStandardDeviation() {
//         if (n == 0) return Double.NaN;
//         if (n == 1) return 0;
//         return FastMath.sqrt(getVariance());
//     }
// 
//     /**
//      * @return max value or Double.NaN if removeValue was called
//      */
//     @Override
//     public double getMax() {
//         return max.getResult();
//     }
// 
//     /**
//      * @return min value or Double.NaN if removeValue was called
//      */
//     @Override
//     public double getMin() {
//         return min.getResult();
//     }
// 
//     @Override
//     public long getN() {
//         return n;
//     }
// 
//     @Override
//     public double getSum() {
//         return sum;
//     }
// 
//     @Override
//     public BothWaySummaryStatistics clone() {
//         BothWaySummaryStatistics copy = new BothWaySummaryStatistics();
//         copy.n = n;
//         copy.sum = sum;
//         copy.sumSquares = sumSquares;
//         return copy;
//     }
// }
// 
// Path: src/main/java/ro/hasna/ts/math/type/MatrixProfile.java
// @Data
// public class MatrixProfile implements Cloneable {
//     private final double[] profile;
//     private final int[] indexProfile;
// 
//     public MatrixProfile(double[] profile, int[] indexProfile) {
//         if (profile.length != indexProfile.length) {
//             throw new DimensionMismatchException(profile.length, indexProfile.length);
//         }
// 
//         this.profile = profile;
//         this.indexProfile = indexProfile;
//     }
// 
//     public MatrixProfile(int size) {
//         profile = new double[size];
//         indexProfile = new int[size];
//         for (int j = 0; j < size; j++) {
//             profile[j] = Double.POSITIVE_INFINITY;
//             indexProfile[j] = -1;
//         }
//     }
// 
//     @Override
//     public MatrixProfile clone() {
//         int size = profile.length;
//         MatrixProfile copy = new MatrixProfile(size);
//         for (int i = 0; i < size; i++) {
//             copy.profile[i] = profile[i];
//             copy.indexProfile[i] = indexProfile[i];
//         }
//         return copy;
//     }
// }


import org.apache.commons.math3.complex.Complex;
import ro.hasna.ts.math.stat.BothWaySummaryStatistics;
import ro.hasna.ts.math.type.MatrixProfile;
import java.util.function.Predicate;
        int n = input.length - window + 1;
        MatrixProfile mp = new MatrixProfile(n);
        double[] distanceProfile = new double[n];

        int[] indices = generateRandomIndices(n);
        for (int i = 0; i < n; i++) {
            int index = indices[i];
            computeDistanceProfileWithProductSums(input, index, input, skip, n, distanceProfile);
            updateMatrixProfileFromDistanceProfile(distanceProfile, n, index, mp, callback);
        }

        updateMatrixProfileWithSqrt(mp);
        return mp;
    }

    protected void computeDistanceProfileWithProductSums(double[] a, int i, double[] b, int skip, int nb, double[] distanceProfile) {
        for (int j = 0; j < nb; j++) {
            if (inExclusionZone(i, j, skip)) {
                distanceProfile[j] = Double.POSITIVE_INFINITY;
            } else {
                double distance = 0;
                for (int k = 0; k < window; k++) {
                    distance += (a[k + i] - b[k + j]) * (a[k + i] - b[k + j]);
                }
                distanceProfile[j] = distance;
            }
        }
    }

    protected void computeNormalizedDistanceProfileWithFft(double[] a, int i, double[] b, int skip, int nb, double[] distanceProfile) {
// Path: src/main/java/ro/hasna/ts/math/stat/BothWaySummaryStatistics.java
// public class BothWaySummaryStatistics implements StatisticalSummary, Serializable, Cloneable {
//     private static final long serialVersionUID = -8419769227216721345L;
//     private long n;
//     private double sum;
//     private double sumSquares;
//     private Max max;
//     private Min min;
//     private boolean removeMade;
// 
//     public BothWaySummaryStatistics() {
//         n = 0;
//         sum = 0;
//         sumSquares = 0;
//         max = new Max();
//         min = new Min();
//         removeMade = false;
//     }
// 
//     public void addValue(double d) {
//         sum += d;
//         sumSquares += d * d;
//         n++;
//         if (!removeMade) {
//             max.increment(d);
//             min.increment(d);
//         }
//     }
// 
//     public void removeValue(double d) {
//         if (n == 0) {
//             throw new InsufficientDataException();
//         }
// 
//         sum -= d;
//         sumSquares -= d * d;
//         n--;
//         removeMade = true;
//         max.clear();
//         min.clear();
//     }
// 
//     @Override
//     public double getMean() {
//         if (n == 0) return 0;
//         return sum / n;
//     }
// 
//     @Override
//     public double getVariance() {
//         if (n == 0) return Double.NaN;
//         if (n == 1) return 0;
//         double mean = getMean();
//         return sumSquares / n - mean * mean;
//     }
// 
//     @Override
//     public double getStandardDeviation() {
//         if (n == 0) return Double.NaN;
//         if (n == 1) return 0;
//         return FastMath.sqrt(getVariance());
//     }
// 
//     /**
//      * @return max value or Double.NaN if removeValue was called
//      */
//     @Override
//     public double getMax() {
//         return max.getResult();
//     }
// 
//     /**
//      * @return min value or Double.NaN if removeValue was called
//      */
//     @Override
//     public double getMin() {
//         return min.getResult();
//     }
// 
//     @Override
//     public long getN() {
//         return n;
//     }
// 
//     @Override
//     public double getSum() {
//         return sum;
//     }
// 
//     @Override
//     public BothWaySummaryStatistics clone() {
//         BothWaySummaryStatistics copy = new BothWaySummaryStatistics();
//         copy.n = n;
//         copy.sum = sum;
//         copy.sumSquares = sumSquares;
//         return copy;
//     }
// }
// 
// Path: src/main/java/ro/hasna/ts/math/type/MatrixProfile.java
// @Data
// public class MatrixProfile implements Cloneable {
//     private final double[] profile;
//     private final int[] indexProfile;
// 
//     public MatrixProfile(double[] profile, int[] indexProfile) {
//         if (profile.length != indexProfile.length) {
//             throw new DimensionMismatchException(profile.length, indexProfile.length);
//         }
// 
//         this.profile = profile;
//         this.indexProfile = indexProfile;
//     }
// 
//     public MatrixProfile(int size) {
//         profile = new double[size];
//         indexProfile = new int[size];
//         for (int j = 0; j < size; j++) {
//             profile[j] = Double.POSITIVE_INFINITY;
//             indexProfile[j] = -1;
//         }
//     }
// 
//     @Override
//     public MatrixProfile clone() {
//         int size = profile.length;
//         MatrixProfile copy = new MatrixProfile(size);
//         for (int i = 0; i < size; i++) {
//             copy.profile[i] = profile[i];
//             copy.indexProfile[i] = indexProfile[i];
//         }
//         return copy;
//     }
// }


// Path: src/main/java/ro/hasna/ts/math/representation/mp/StampTransformer.java
import org.apache.commons.math3.complex.Complex;
import ro.hasna.ts.math.stat.BothWaySummaryStatistics;
import ro.hasna.ts.math.type.MatrixProfile;
import java.util.function.Predicate;

        int n = input.length - window + 1;
        MatrixProfile mp = new MatrixProfile(n);
        double[] distanceProfile = new double[n];

        int[] indices = generateRandomIndices(n);
        for (int i = 0; i < n; i++) {
            int index = indices[i];
            computeDistanceProfileWithProductSums(input, index, input, skip, n, distanceProfile);
            updateMatrixProfileFromDistanceProfile(distanceProfile, n, index, mp, callback);
        }

        updateMatrixProfileWithSqrt(mp);
        return mp;
    }

    protected void computeDistanceProfileWithProductSums(double[] a, int i, double[] b, int skip, int nb, double[] distanceProfile) {
        for (int j = 0; j < nb; j++) {
            if (inExclusionZone(i, j, skip)) {
                distanceProfile[j] = Double.POSITIVE_INFINITY;
            } else {
                double distance = 0;
                for (int k = 0; k < window; k++) {
                    distance += (a[k + i] - b[k + j]) * (a[k + i] - b[k + j]);
                }
                distanceProfile[j] = distance;
            }
        }
    }

    protected void computeNormalizedDistanceProfileWithFft(double[] a, int i, double[] b, int skip, int nb, double[] distanceProfile) {
        BothWaySummaryStatistics first = new BothWaySummaryStatistics();