001/*
002 * ModeShape (http://www.modeshape.org)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *       http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.modeshape.common.statistic;
017
018import static org.junit.Assert.assertArrayEquals;
019import static org.junit.Assert.assertEquals;
020import static org.junit.Assert.assertNotNull;
021import static org.junit.Assert.assertTrue;
022import java.util.ArrayList;
023import java.util.LinkedList;
024import java.util.List;
025import java.util.Random;
026import org.junit.Test;
027import org.modeshape.common.i18n.MockI18n;
028import org.modeshape.common.logging.Logger;
029import org.modeshape.common.math.FloatOperations;
030import org.modeshape.common.math.MathOperations;
031import org.modeshape.common.text.Inflector;
032
033public class HistogramTest {
034
035    private Logger logger = Logger.getLogger(HistogramTest.class);
036    private Inflector inflector = Inflector.getInstance();
037
038    public static <T extends Number> Histogram<T> createRandomHistogram( T minimum,
039                                                                         T maximum,
040                                                                         int numberOfValues,
041                                                                         MathOperations<T> ops ) {
042        List<T> values = new ArrayList<T>();
043        Random rng = new Random();
044        for (int i = 0; i != numberOfValues; ++i) {
045            T newValue = ops.random(minimum, maximum, rng);
046            values.add(newValue);
047        }
048        return new Histogram<T>(ops, values);
049    }
050
051    public static <T extends Number> void writeHistogramToLog( Logger logger,
052                                                               Histogram<T> histogram,
053                                                               int barLength,
054                                                               String description ) {
055        logger.info(MockI18n.passthrough, description != null ? description : "Histogram:");
056        List<String> barGraph = histogram.getTextGraph(barLength);
057        for (String line : barGraph) {
058            logger.debug("  " + line);
059        }
060    }
061
062    public <T extends Number> void assertBucketValueCount( Histogram<T> histogram,
063                                                           long... values ) {
064        // CHECKSTYLE IGNORE check FOR NEXT 1 LINES
065        List<Histogram<T>.Bucket> buckets = histogram.getBuckets();
066        // Check the number of buckets ...
067        assertEquals("The number of buckets didn't match expected number", values.length, buckets.size());
068        // Check the number of values ...
069        for (int i = 0; i != buckets.size(); ++i) {
070            assertEquals("The " + inflector.ordinalize(i + 1) + " bucket didn't have the expected number of values",
071                         values[i],
072                         buckets.get(i).getNumberOfValues());
073        }
074    }
075
076    @Test
077    public void shouldCorrectlyPlaceAnOddNumberOfFloatValuesIntoSameOddNumberOfBuckets() {
078        Float[] values = {3.0f, 1.0f, 2.0f, 4.0f};
079        Histogram<Float> gram = new Histogram<Float>(new FloatOperations(), values);
080        gram.setBucketCount(3);
081        // HistogramTest.writeHistogramToLog(this.logger, gram, 0,
082        // "shouldCorrectlyPlaceAnOddNumberOfFloatValuesIntoSameOddNumberOfBuckets");
083        assertBucketValueCount(gram, 1, 1, 2);
084    }
085
086    @Test
087    public void shouldCorrectlyPlaceAnEvenNumberOfFloatValuesIntoSameEvenNumberOfBuckets() {
088        Float[] values = {3.0f, 1.0f, 2.0f, 4.0f};
089        Histogram<Float> gram = new Histogram<Float>(new FloatOperations(), values);
090        gram.setBucketCount(4);
091        // HistogramTest.writeHistogramToLog(this.logger, gram, 0,
092        // "shouldCorrectlyPlaceAnEvenNumberOfFloatValuesIntoSameEvenNumberOfBuckets");
093        assertBucketValueCount(gram, 1, 1, 1, 1);
094
095    }
096
097    @Test
098    public void shouldCorrectlyPlaceAnOddNumberOfFloatValuesIntoSmallerNumberOfBuckets() {
099        Float[] values = {3.0f, 1.0f, 2.0f};
100        Histogram<Float> gram = new Histogram<Float>(new FloatOperations(), values);
101        gram.setBucketCount(2);
102        // HistogramTest.writeHistogramToLog(this.logger, gram, 0,
103        // "shouldCorrectlyPlaceAnEvenNumberOfFloatValuesIntoSameEvenNumberOfBuckets");
104        assertBucketValueCount(gram, 1, 2);
105    }
106
107    @Test
108    public void shouldCorrectlyPlaceAnEvenNumberOfFloatValuesIntoSmallerNumberOfBuckets() {
109        Float[] values = {3.0f, 1.0f, 2.0f, 4.0f};
110        Histogram<Float> gram = new Histogram<Float>(new FloatOperations(), values);
111        gram.setBucketCount(2);
112        // HistogramTest.writeHistogramToLog(this.logger, gram, 0,
113        // "shouldCorrectlyPlaceAnEvenNumberOfFloatValuesIntoSmallerNumberOfBuckets");
114        assertBucketValueCount(gram, 2, 2);
115    }
116
117    @Test
118    public void shouldReturnListOfBuckets() {
119        Float[] values = {3.0f, 1.0f, 2.0f, 4.0f};
120        Histogram<Float> gram = new Histogram<Float>(new FloatOperations(), values);
121        assertTrue(gram.getBuckets() instanceof LinkedList<?>);
122    }
123
124    @Test
125    public void shouldCorrectlyPlaceAnOddNumberOfFloatValuesIntoSmallerNumberOfBucketsWithMinimumAndMaximumRanges() {
126        Float[] values = {3.0f, 1.0f, 2.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f};
127        Histogram<Float> gram = new Histogram<Float>(new FloatOperations(), values);
128        gram.setBucketCount(5);
129        // HistogramTest.writeHistogramToLog(this.logger, gram, 0,
130        // "shouldCorrectlyPlaceAnOddNumberOfFloatValuesIntoSmallerNumberOfBucketsWithMinimumAndMaximumRanges");
131        assertBucketValueCount(gram, 2, 2, 2, 2, 2);
132    }
133
134    @Test
135    public void shouldCorrectlyPlaceAnOddNumberOfFloatValuesIntoSmallerNumberOfBucketsWithMinimumRanges() {
136        Float[] values = {3.0f, 1.0f, 2.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 9.999f};
137        Histogram<Float> gram = new Histogram<Float>(new FloatOperations(), values);
138        gram.setBucketCount(5);
139        // HistogramTest.writeHistogramToLog(this.logger, gram, 0,
140        // "shouldCorrectlyPlaceAnOddNumberOfFloatValuesIntoSmallerNumberOfBucketsWithMinimumRanges");
141        assertBucketValueCount(gram, 2, 2, 2, 2, 2);
142    }
143
144    @Test
145    public void shouldCorrectlyConstructHistogramWithStandardDeviation() {
146        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};
147        // RunningStatistics<Float> stats = new RunningStatistics<Float>(new FloatOperations());
148        // for (Float value : values) stats.add(value);
149        // System.out.println(stats);
150        Histogram<Float> gram = new Histogram<Float>(new FloatOperations(), values);
151        gram.setBucketCount(6);
152        gram.setStrategy(3.315f, 2.52367f, 1);
153
154        HistogramTest.writeHistogramToLog(this.logger, gram, 0, "shouldCorrectlyConstructHistogramWithStandardDeviation");
155        assertBucketValueCount(gram, 1, 1, 7, 1, 1, 5);
156    }
157
158    @Test
159    public void shouldCorrectlyPlace1000RandomFloatValues() {
160        Histogram<Float> gram = createRandomHistogram(10.0f, 100.0f, 1000, new FloatOperations());
161        // gram.setDesiredRange(0.0f,100.0f);
162        HistogramTest.writeHistogramToLog(this.logger,
163                                          gram,
164                                          0,
165                                          "Histogram of 1000 random float values in " + gram.getBucketCount() + " buckets: ");
166    }
167
168    @Test
169    public void shouldCorrectlyConstructBoundariesWithWindowSmallerThanActualFloats() {
170        List<Float> boundaries = Histogram.getBucketBoundaries(new FloatOperations(), 10.0f, 20.0f, 5.0f, 25.0f, 12, 3);
171        assertNotNull(boundaries);
172        assertEquals(13, boundaries.size());
173        Float[] expectedBoundaries = {5.0f, 10.0f, 11f, 12f, 13f, 14f, 15f, 16f, 17f, 18f, 19f, 20f, 25f};
174        assertArrayEquals(expectedBoundaries, boundaries.toArray(new Float[boundaries.size()]));
175    }
176
177    @Test
178    public void shouldCorrectlyConstructBoundariesWithWindowSmallerThanActualNarrowlyVaryingFloats() {
179        List<Float> boundaries = Histogram.getBucketBoundaries(new FloatOperations(),
180                                                               10.00020f,
181                                                               10.00030f,
182                                                               10.00011f,
183                                                               10.00050f,
184                                                               12,
185                                                               3);
186        assertNotNull(boundaries);
187        assertEquals(13, boundaries.size());
188        assertEquals(10.00011f, boundaries.get(0), 0.00001f);
189        assertEquals(10.00020f, boundaries.get(1), 0.00001f);
190        assertEquals(10.00021f, boundaries.get(2), 0.00001f);
191        assertEquals(10.00022f, boundaries.get(3), 0.00001f);
192        assertEquals(10.00023f, boundaries.get(4), 0.00001f);
193        assertEquals(10.00024f, boundaries.get(5), 0.00001f);
194        assertEquals(10.00025f, boundaries.get(6), 0.00001f);
195        assertEquals(10.00026f, boundaries.get(7), 0.00001f);
196        assertEquals(10.00027f, boundaries.get(8), 0.00001f);
197        assertEquals(10.00028f, boundaries.get(9), 0.00001f);
198        assertEquals(10.00029f, boundaries.get(10), 0.00001f);
199        assertEquals(10.00030f, boundaries.get(11), 0.00001f);
200        assertEquals(10.00050f, boundaries.get(12), 0.00001f);
201    }
202
203}