// 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;
//     }
// }


import org.apache.commons.math3.complex.Complex;
import org.apache.commons.math3.exception.NumberIsTooSmallException;
import org.apache.commons.math3.transform.DftNormalization;
import org.apache.commons.math3.transform.FastFourierTransformer;
import org.apache.commons.math3.transform.TransformType;
import ro.hasna.ts.math.stat.BothWaySummaryStatistics;
import java.io.Serializable;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
/*
 * Copyright 2015 Octavian Hasna
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ro.hasna.ts.math.representation.mp;



/**
 * Useful methods used by full and self join matrix profile algorithms.
 *
 * @since 0.17
 */
public abstract class AbstractMatrixProfileTransformer implements Serializable {
    private static final long serialVersionUID = -4758909899130005950L;

    protected final int window;
    protected final double exclusionZonePercentage;
    protected final boolean useNormalization;

    /**
     * Creates a new instance of this class with normalization enabled and an exclusion zone of 25%.
     *
     * @param window the length of the window
     * @throws NumberIsTooSmallException if window is lower than 4
     */
    public AbstractMatrixProfileTransformer(int window) {
        this(window, 0.25, true);
    }

    /**
     * @param window                  the length of the window
     * @param exclusionZonePercentage percentage of window that should be excluded at distance profile computing
     * @param useNormalization        flag to use Z-Normalization
     * @throws NumberIsTooSmallException if window is lower than 1
     */
    public AbstractMatrixProfileTransformer(int window, double exclusionZonePercentage, boolean useNormalization) {
        this.useNormalization = useNormalization;
        if (window < 1) {
            throw new NumberIsTooSmallException(window, 1, true);
        }

        this.window = window;
        this.exclusionZonePercentage = exclusionZonePercentage;
    }

    /**
     * This method will update bStatistics with last sliding window statistics
     */
// 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/representation/mp/AbstractMatrixProfileTransformer.java
import org.apache.commons.math3.complex.Complex;
import org.apache.commons.math3.exception.NumberIsTooSmallException;
import org.apache.commons.math3.transform.DftNormalization;
import org.apache.commons.math3.transform.FastFourierTransformer;
import org.apache.commons.math3.transform.TransformType;
import ro.hasna.ts.math.stat.BothWaySummaryStatistics;
import java.io.Serializable;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

/*
 * Copyright 2015 Octavian Hasna
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ro.hasna.ts.math.representation.mp;



/**
 * Useful methods used by full and self join matrix profile algorithms.
 *
 * @since 0.17
 */
public abstract class AbstractMatrixProfileTransformer implements Serializable {
    private static final long serialVersionUID = -4758909899130005950L;

    protected final int window;
    protected final double exclusionZonePercentage;
    protected final boolean useNormalization;

    /**
     * Creates a new instance of this class with normalization enabled and an exclusion zone of 25%.
     *
     * @param window the length of the window
     * @throws NumberIsTooSmallException if window is lower than 4
     */
    public AbstractMatrixProfileTransformer(int window) {
        this(window, 0.25, true);
    }

    /**
     * @param window                  the length of the window
     * @param exclusionZonePercentage percentage of window that should be excluded at distance profile computing
     * @param useNormalization        flag to use Z-Normalization
     * @throws NumberIsTooSmallException if window is lower than 1
     */
    public AbstractMatrixProfileTransformer(int window, double exclusionZonePercentage, boolean useNormalization) {
        this.useNormalization = useNormalization;
        if (window < 1) {
            throw new NumberIsTooSmallException(window, 1, true);
        }

        this.window = window;
        this.exclusionZonePercentage = exclusionZonePercentage;
    }

    /**
     * This method will update bStatistics with last sliding window statistics
     */
    protected void computeFirstNormalizedDistanceProfile(double[] a, BothWaySummaryStatistics aStatistics, double[] b, BothWaySummaryStatistics bStatistics, int skip, int nb, double[] productSums, double[] distanceProfile) {