// Path: fast-ftrl-proximal/src/main/java/io/scaledml/core/util/Util.java
// public class Util {
//     private final static HashFunction murmur = Hashing.murmur3_128(42);
// 
//     private final static HashFunction murmur32 = Hashing.murmur3_32(17);
//     public static final double EPSILON = 0.0000001;
// 
//     public static boolean doublesEqual(double d1, double d2, double precision) {
//         if (!Doubles.isFinite(d1) || !Doubles.isFinite(d2)) {
//             return false;
//         }
//         return Math.abs(d1 - d2) < precision;
//     }
// 
//     public static boolean doublesEqual(double d1, double d2) {
//         return doublesEqual(d1, d2, EPSILON);
//     }
// 
//     public static HashFunction murmur() {
//         return murmur;
//     }
// 
//     public static HashFunction murmur32() {
//         return murmur32;
//     }
// 
//     public static boolean doublesLess(double v1, double v2) {
//         return v1 < v2 - EPSILON;
//     }
// }


import com.clearspring.analytics.stream.quantile.TDigest;
import com.clearspring.analytics.util.Preconditions;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import io.scaledml.core.util.Util;
import it.unimi.dsi.fastutil.doubles.Double2DoubleArrayMap;
import it.unimi.dsi.fastutil.doubles.Double2DoubleMap;
import it.unimi.dsi.fastutil.longs.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
                digests.get(index).add(handler.digests().get(index));
            }
        }
        for (long index : handler.counts().keySet()) {
            long count = handler.counts().get(index);
            counts.put(index, counts.get(index) + count);
        }
        for (long index : handler.minimums().keySet()) {
            double min = handler.minimums().get(index);
            minimums.put(index, Math.min(minimums.get(index), min));
        }
        for (long index : handler.maximums().keySet()) {
            double max = handler.maximums().get(index);
            maximums.put(index, Math.max(maximums.get(index), max));
        }
    }

    private synchronized Long2ObjectMap<Binning> buildBinning() {
        Long2ObjectMap<Binning> newBinnings = new Long2ObjectLinkedOpenHashMap<>();
        for (long index : digests.keySet()) {
            TDigest digest = digests.get(index);
            double min = minimums.get(index);
            Binning binning = buildBinning(digest, min);
            newBinnings.put(index, binning);
        }
        return newBinnings;
    }

    Binning buildBinning(TDigest digest, double min) {
        Binning binning = new Binning().addPercentile(min);
// Path: fast-ftrl-proximal/src/main/java/io/scaledml/core/util/Util.java
// public class Util {
//     private final static HashFunction murmur = Hashing.murmur3_128(42);
// 
//     private final static HashFunction murmur32 = Hashing.murmur3_32(17);
//     public static final double EPSILON = 0.0000001;
// 
//     public static boolean doublesEqual(double d1, double d2, double precision) {
//         if (!Doubles.isFinite(d1) || !Doubles.isFinite(d2)) {
//             return false;
//         }
//         return Math.abs(d1 - d2) < precision;
//     }
// 
//     public static boolean doublesEqual(double d1, double d2) {
//         return doublesEqual(d1, d2, EPSILON);
//     }
// 
//     public static HashFunction murmur() {
//         return murmur;
//     }
// 
//     public static HashFunction murmur32() {
//         return murmur32;
//     }
// 
//     public static boolean doublesLess(double v1, double v2) {
//         return v1 < v2 - EPSILON;
//     }
// }


// Path: fast-ftrl-proximal/src/main/java/io/scaledml/features/NumericalFeaturesStatistics.java
import com.clearspring.analytics.stream.quantile.TDigest;
import com.clearspring.analytics.util.Preconditions;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import io.scaledml.core.util.Util;
import it.unimi.dsi.fastutil.doubles.Double2DoubleArrayMap;
import it.unimi.dsi.fastutil.doubles.Double2DoubleMap;
import it.unimi.dsi.fastutil.longs.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

                digests.get(index).add(handler.digests().get(index));
            }
        }
        for (long index : handler.counts().keySet()) {
            long count = handler.counts().get(index);
            counts.put(index, counts.get(index) + count);
        }
        for (long index : handler.minimums().keySet()) {
            double min = handler.minimums().get(index);
            minimums.put(index, Math.min(minimums.get(index), min));
        }
        for (long index : handler.maximums().keySet()) {
            double max = handler.maximums().get(index);
            maximums.put(index, Math.max(maximums.get(index), max));
        }
    }

    private synchronized Long2ObjectMap<Binning> buildBinning() {
        Long2ObjectMap<Binning> newBinnings = new Long2ObjectLinkedOpenHashMap<>();
        for (long index : digests.keySet()) {
            TDigest digest = digests.get(index);
            double min = minimums.get(index);
            Binning binning = buildBinning(digest, min);
            newBinnings.put(index, binning);
        }
        return newBinnings;
    }

    Binning buildBinning(TDigest digest, double min) {
        Binning binning = new Binning().addPercentile(min);
        for (double p = percentsBinningStep; Util.doublesLess(p, 1.); p += percentsBinningStep) {