/* * ModeShape (http://www.modeshape.org) * * 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 org.modeshape.common.statistic; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Random; import org.junit.Test; import org.modeshape.common.i18n.MockI18n; import org.modeshape.common.logging.Logger; import org.modeshape.common.math.FloatOperations; import org.modeshape.common.math.MathOperations; import org.modeshape.common.text.Inflector; public class HistogramTest { private Logger logger = Logger.getLogger(HistogramTest.class); private Inflector inflector = Inflector.getInstance(); public static <T extends Number> Histogram<T> createRandomHistogram( T minimum, T maximum, int numberOfValues, MathOperations<T> ops ) { List<T> values = new ArrayList<T>(); Random rng = new Random(); for (int i = 0; i != numberOfValues; ++i) { T newValue = ops.random(minimum, maximum, rng); values.add(newValue); } return new Histogram<T>(ops, values); } public static <T extends Number> void writeHistogramToLog( Logger logger, Histogram<T> histogram, int barLength, String description ) { logger.info(MockI18n.passthrough, description != null ? description : "Histogram:"); List<String> barGraph = histogram.getTextGraph(barLength); for (String line : barGraph) { logger.debug(" " + line); } } public <T extends Number> void assertBucketValueCount( Histogram<T> histogram, long... values ) { // CHECKSTYLE IGNORE check FOR NEXT 1 LINES List<Histogram<T>.Bucket> buckets = histogram.getBuckets(); // Check the number of buckets ... assertEquals("The number of buckets didn't match expected number", values.length, buckets.size()); // Check the number of values ... for (int i = 0; i != buckets.size(); ++i) { assertEquals("The " + inflector.ordinalize(i + 1) + " bucket didn't have the expected number of values", values[i], buckets.get(i).getNumberOfValues()); } } @Test public void shouldCorrectlyPlaceAnOddNumberOfFloatValuesIntoSameOddNumberOfBuckets() { Float[] values = {3.0f, 1.0f, 2.0f, 4.0f}; Histogram<Float> gram = new Histogram<Float>(new FloatOperations(), values); gram.setBucketCount(3); // HistogramTest.writeHistogramToLog(this.logger, gram, 0, // "shouldCorrectlyPlaceAnOddNumberOfFloatValuesIntoSameOddNumberOfBuckets"); assertBucketValueCount(gram, 1, 1, 2); } @Test public void shouldCorrectlyPlaceAnEvenNumberOfFloatValuesIntoSameEvenNumberOfBuckets() { Float[] values = {3.0f, 1.0f, 2.0f, 4.0f}; Histogram<Float> gram = new Histogram<Float>(new FloatOperations(), values); gram.setBucketCount(4); // HistogramTest.writeHistogramToLog(this.logger, gram, 0, // "shouldCorrectlyPlaceAnEvenNumberOfFloatValuesIntoSameEvenNumberOfBuckets"); assertBucketValueCount(gram, 1, 1, 1, 1); } @Test public void shouldCorrectlyPlaceAnOddNumberOfFloatValuesIntoSmallerNumberOfBuckets() { Float[] values = {3.0f, 1.0f, 2.0f}; Histogram<Float> gram = new Histogram<Float>(new FloatOperations(), values); gram.setBucketCount(2); // HistogramTest.writeHistogramToLog(this.logger, gram, 0, // "shouldCorrectlyPlaceAnEvenNumberOfFloatValuesIntoSameEvenNumberOfBuckets"); assertBucketValueCount(gram, 1, 2); } @Test public void shouldCorrectlyPlaceAnEvenNumberOfFloatValuesIntoSmallerNumberOfBuckets() { Float[] values = {3.0f, 1.0f, 2.0f, 4.0f}; Histogram<Float> gram = new Histogram<Float>(new FloatOperations(), values); gram.setBucketCount(2); // HistogramTest.writeHistogramToLog(this.logger, gram, 0, // "shouldCorrectlyPlaceAnEvenNumberOfFloatValuesIntoSmallerNumberOfBuckets"); assertBucketValueCount(gram, 2, 2); } @Test public void shouldReturnListOfBuckets() { Float[] values = {3.0f, 1.0f, 2.0f, 4.0f}; Histogram<Float> gram = new Histogram<Float>(new FloatOperations(), values); assertTrue(gram.getBuckets() instanceof LinkedList<?>); } @Test public void shouldCorrectlyPlaceAnOddNumberOfFloatValuesIntoSmallerNumberOfBucketsWithMinimumAndMaximumRanges() { Float[] values = {3.0f, 1.0f, 2.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f}; Histogram<Float> gram = new Histogram<Float>(new FloatOperations(), values); gram.setBucketCount(5); // HistogramTest.writeHistogramToLog(this.logger, gram, 0, // "shouldCorrectlyPlaceAnOddNumberOfFloatValuesIntoSmallerNumberOfBucketsWithMinimumAndMaximumRanges"); assertBucketValueCount(gram, 2, 2, 2, 2, 2); } @Test public void shouldCorrectlyPlaceAnOddNumberOfFloatValuesIntoSmallerNumberOfBucketsWithMinimumRanges() { Float[] values = {3.0f, 1.0f, 2.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 9.999f}; Histogram<Float> gram = new Histogram<Float>(new FloatOperations(), values); gram.setBucketCount(5); // HistogramTest.writeHistogramToLog(this.logger, gram, 0, // "shouldCorrectlyPlaceAnOddNumberOfFloatValuesIntoSmallerNumberOfBucketsWithMinimumRanges"); assertBucketValueCount(gram, 2, 2, 2, 2, 2); } @Test public void shouldCorrectlyConstructHistogramWithStandardDeviation() { Float[] values = {3.0f, 1.0f, 2.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 9.999f, 3.1f, 3.2f, 3.3f, 3.21f, 3.22f, 3.33f}; // RunningStatistics<Float> stats = new RunningStatistics<Float>(new FloatOperations()); // for (Float value : values) stats.add(value); // System.out.println(stats); Histogram<Float> gram = new Histogram<Float>(new FloatOperations(), values); gram.setBucketCount(6); gram.setStrategy(3.315f, 2.52367f, 1); HistogramTest.writeHistogramToLog(this.logger, gram, 0, "shouldCorrectlyConstructHistogramWithStandardDeviation"); assertBucketValueCount(gram, 1, 1, 7, 1, 1, 5); } @Test public void shouldCorrectlyPlace1000RandomFloatValues() { Histogram<Float> gram = createRandomHistogram(10.0f, 100.0f, 1000, new FloatOperations()); // gram.setDesiredRange(0.0f,100.0f); HistogramTest.writeHistogramToLog(this.logger, gram, 0, "Histogram of 1000 random float values in " + gram.getBucketCount() + " buckets: "); } @Test public void shouldCorrectlyConstructBoundariesWithWindowSmallerThanActualFloats() { List<Float> boundaries = Histogram.getBucketBoundaries(new FloatOperations(), 10.0f, 20.0f, 5.0f, 25.0f, 12, 3); assertNotNull(boundaries); assertEquals(13, boundaries.size()); Float[] expectedBoundaries = {5.0f, 10.0f, 11f, 12f, 13f, 14f, 15f, 16f, 17f, 18f, 19f, 20f, 25f}; assertArrayEquals(expectedBoundaries, boundaries.toArray(new Float[boundaries.size()])); } @Test public void shouldCorrectlyConstructBoundariesWithWindowSmallerThanActualNarrowlyVaryingFloats() { List<Float> boundaries = Histogram.getBucketBoundaries(new FloatOperations(), 10.00020f, 10.00030f, 10.00011f, 10.00050f, 12, 3); assertNotNull(boundaries); assertEquals(13, boundaries.size()); assertEquals(10.00011f, boundaries.get(0), 0.00001f); assertEquals(10.00020f, boundaries.get(1), 0.00001f); assertEquals(10.00021f, boundaries.get(2), 0.00001f); assertEquals(10.00022f, boundaries.get(3), 0.00001f); assertEquals(10.00023f, boundaries.get(4), 0.00001f); assertEquals(10.00024f, boundaries.get(5), 0.00001f); assertEquals(10.00025f, boundaries.get(6), 0.00001f); assertEquals(10.00026f, boundaries.get(7), 0.00001f); assertEquals(10.00027f, boundaries.get(8), 0.00001f); assertEquals(10.00028f, boundaries.get(9), 0.00001f); assertEquals(10.00029f, boundaries.get(10), 0.00001f); assertEquals(10.00030f, boundaries.get(11), 0.00001f); assertEquals(10.00050f, boundaries.get(12), 0.00001f); } }