package com.ldbc.driver.util; import com.ldbc.driver.generator.GeneratorException; import org.apache.commons.math3.distribution.ExponentialDistribution; import org.apache.commons.math3.random.RandomDataGenerator; import static java.lang.String.format; public abstract class NumberHelper<T extends Number> { private static final NumberHelper<Integer> integerNumberHelper = new IntegerNumberHelper(); private static final NumberHelper<Long> longNumberHelper = new LongNumberHelper(); private static final NumberHelper<Double> doubleNumberHelper = new DoubleNumberHelper(); public static <T1 extends Number> NumberHelper<T1> createNumberHelper( Class<?> type ) { /* * Supported: Double, Integer, Long */ if ( type.isAssignableFrom( Integer.class ) ) { return (NumberHelper<T1>) integerNumberHelper; } if ( type.isAssignableFrom( Long.class ) ) { return (NumberHelper<T1>) longNumberHelper; } if ( type.isAssignableFrom( Double.class ) ) { return (NumberHelper<T1>) doubleNumberHelper; } /* * Not supported: Byte, Float, Short, AtomicInteger, AtomicLong, BigDecimal, BigInteger */ throw new GeneratorException( format( "%s not supported. Only supports: Double, Integer, Long", type.getName() ) ); } public static <T1 extends Number> boolean withinTolerance( T1 a, T1 b, Number tolerance ) { Double difference = Math.abs( (a.doubleValue() - b.doubleValue()) ); return difference <= tolerance.doubleValue(); } public final T sum( Iterable<T> ts ) { T sum = zero(); for ( T t : ts ) { sum = sum( sum, t ); } return sum; } public final T one() { return inc( zero() ); } public abstract T cast( Number n ); public abstract T inc( T a ); public abstract T zero(); public abstract T sum( T a, T b ); public abstract T sub( T a, T b ); public abstract T div( T a, T b ); public abstract T min(); public abstract T max(); public abstract T round( Number number ); public abstract T uniform( RandomDataGenerator random, T min, T max ); public abstract T exponential( ExponentialDistribution exponentialDistribution ); public abstract boolean lt( T a, T b ); public abstract boolean lte( T a, T b ); public abstract boolean gt( T a, T b ); public abstract boolean gte( T a, T b ); private static class IntegerNumberHelper extends NumberHelper<Integer> { @Override public Integer cast( Number n ) { return n.intValue(); } @Override public Integer zero() { return 0; } @Override public Integer inc( Integer a ) { return a + 1; } @Override public Integer sum( Integer a, Integer b ) { return a + b; } @Override public Integer sub( Integer a, Integer b ) { return a - b; } @Override public Integer div( Integer a, Integer b ) { return a / b; } @Override public Integer min() { return Integer.MIN_VALUE; } @Override public Integer max() { return Integer.MAX_VALUE; } @Override public Integer round( Number number ) { return (int) Math.round( number.doubleValue() ); } @Override public Integer uniform( RandomDataGenerator random, Integer min, Integer max ) { if ( min == max ) { return min; } return random.nextInt( min, max ); } @Override public Integer exponential( ExponentialDistribution exponentialDistribution ) { return new Double( exponentialDistribution.sample() ).intValue(); } @Override public boolean lt( Integer a, Integer b ) { return a < b; } @Override public boolean gt( Integer a, Integer b ) { return a > b; } @Override public boolean lte( Integer a, Integer b ) { return a <= b; } @Override public boolean gte( Integer a, Integer b ) { return a >= b; } } private static class LongNumberHelper extends NumberHelper<Long> { @Override public Long cast( Number n ) { return n.longValue(); } @Override public Long zero() { return 0l; } @Override public Long inc( Long a ) { return a + 1; } @Override public Long sum( Long a, Long b ) { return a + b; } @Override public Long sub( Long a, Long b ) { return a - b; } @Override public Long div( Long a, Long b ) { return a / b; } @Override public Long min() { return Long.MIN_VALUE; } @Override public Long max() { return Long.MAX_VALUE; } @Override public Long round( Number number ) { return Math.round( number.doubleValue() ); } @Override public Long uniform( RandomDataGenerator random, Long min, Long max ) { if ( min == max ) { return min; } return random.nextLong( min, max ); } @Override public Long exponential( ExponentialDistribution exponentialDistribution ) { return new Double( exponentialDistribution.sample() ).longValue(); } @Override public boolean lt( Long a, Long b ) { return a < b; } @Override public boolean gt( Long a, Long b ) { return a > b; } @Override public boolean lte( Long a, Long b ) { return a <= b; } @Override public boolean gte( Long a, Long b ) { return a >= b; } } private static class DoubleNumberHelper extends NumberHelper<Double> { @Override public Double cast( Number n ) { return n.doubleValue(); } @Override public Double zero() { return 0d; } @Override public Double inc( Double a ) { return a + 1; } @Override public Double sum( Double a, Double b ) { return a + b; } @Override public Double sub( Double a, Double b ) { return a - b; } @Override public Double div( Double a, Double b ) { return a / b; } @Override public Double min() { return Double.MIN_VALUE; } @Override public Double max() { return Double.MAX_VALUE; } @Override public Double round( Number number ) { return number.doubleValue(); } @Override public Double uniform( RandomDataGenerator random, Double min, Double max ) { if ( min == max ) { return min; } return random.nextUniform( min, max, true ); } @Override public Double exponential( ExponentialDistribution exponentialDistribution ) { return exponentialDistribution.sample(); } @Override public boolean lt( Double a, Double b ) { return a < b; } @Override public boolean gt( Double a, Double b ) { return a > b; } @Override public boolean lte( Double a, Double b ) { return a <= b; } @Override public boolean gte( Double a, Double b ) { return a >= b; } } }