package org.overture.interpreter.traces; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Random; import java.util.Vector; import org.overture.interpreter.traces.util.RandomList; public class ReducedTestSequence extends TestSequence { public interface ShapeIterator extends Iterator<CallSequence> { int iterationCount(); } /** * A random reduction iterator that only returns the elements within the random restrictions * * @author kel */ private static class RandomReductionIterator implements ShapeIterator { private TestSequence data; private int size; private int nextIndex; private RandomList randomList; private int numberOfTests; public RandomReductionIterator(TestSequence data, int size, long numberOfTests, Random prng) { this.data = data; this.size = size; this.numberOfTests = (int) numberOfTests; final int N = size; final int R = this.numberOfTests; this.randomList = new RandomList(N, R, prng); computeNextIndex(); } private void computeNextIndex() { this.nextIndex = randomList.next() - 1; } @Override public boolean hasNext() { return this.nextIndex >= 0 && this.nextIndex < size; } @Override public CallSequence next() { CallSequence next = data.get(nextIndex); computeNextIndex(); return next; } @Override public void remove() { throw new UnsupportedOperationException(); } @Override public int iterationCount() { return this.numberOfTests; } } /** * A shape reduction iterator that only returns the elements within the shape restrictions * * @author kel */ private static class ShapeReductionIterator implements ShapeIterator { private TestSequence data; private long delta; private Random prng; private int size; private TraceReductionType type; private List<Integer> chosenTestIndices = new Vector<Integer>(); private int choosenIndexPtr = 0; private Iterator<CallSequence> choosenTestItr; private int choosenTestIndexPtr = 0; public ShapeReductionIterator(TestSequence data, int size, long delta, Random prng, TraceReductionType type) { this.data = data; this.delta = delta; this.prng = prng; this.size = size; this.type = type; initialize(); } private void initialize() { Map<String, List<Integer>> map = new HashMap<String, List<Integer>>(); int index = 0; for (Iterator<CallSequence> itr = data.iterator(); itr.hasNext();) { String shape = itr.next().toShape(type); List<Integer> subset = map.get(shape); if (subset == null) { subset = new Vector<Integer>(); map.put(shape, subset); } subset.add(index); index++; } String[] shapes = map.keySet().toArray(new String[0]); if (size - delta < shapes.length) { // We must keep one test for each shape delta = size - shapes.length; } for (long i = 0; i < delta; i++) { int x = prng.nextInt(shapes.length); List<Integer> tests = map.get(shapes[x]); int s = tests.size(); if (s < 2) { i--; // Find another group } else { tests.remove(prng.nextInt(s)); } } for (Entry<String, List<Integer>> entry : map.entrySet()) { chosenTestIndices.addAll(map.get(entry.getKey())); } Collections.sort(chosenTestIndices); } @Override public boolean hasNext() { return !chosenTestIndices.isEmpty() && choosenIndexPtr < chosenTestIndices.size(); } @Override public CallSequence next() { if (choosenTestItr == null) { choosenTestItr = data.iterator(); choosenTestIndexPtr = -1; } int index = chosenTestIndices.get(choosenIndexPtr++); CallSequence test = null; do { test = choosenTestItr.next(); choosenTestIndexPtr++; } while (choosenTestIndexPtr < index); return test; } @Override public void remove() { throw new UnsupportedOperationException(); } @Override public int iterationCount() { return chosenTestIndices.size(); } } /** * serial */ private static final long serialVersionUID = 1L; private final TestSequence data; private final boolean enabled; private final Random prng; private int size; private final float subset; private final TraceReductionType type; private Iterator<CallSequence> iterator; public ReducedTestSequence(TestSequence data, float subset, TraceReductionType type, long seed) { this.data = data; this.subset = subset; this.type = type; this.prng = new Random(seed); this.size = this.data.size(); long n = Math.round(Math.ceil(size * subset)); this.enabled = n < size; } @Override public synchronized Iterator<CallSequence> iterator() { if(iterator != null) { return iterator; } if (!enabled || type == TraceReductionType.NONE) { iterator = this.data.iterator(); return iterator; } long n = Math.round(Math.ceil(size * subset)); long delta = size - n; switch (type) { case RANDOM: iterator = new RandomReductionIterator(this.data, size, n, prng); return iterator; case SHAPES_NOVARS: case SHAPES_VARNAMES: case SHAPES_VARVALUES: iterator = new ShapeReductionIterator(this.data, size, delta, prng, type); return iterator; case NONE: default: iterator = this.data.iterator(); return iterator; } } @Override public synchronized int size() { if(iterator == null) { iterator(); } if(iterator instanceof ShapeIterator) { return ((ShapeIterator) iterator).iterationCount(); } return this.data.size(); } // private void randomReduction(long delta, Random prng) // { // int s = size(); // // for (long i = 0; i < delta; i++) // { // int x = prng.nextInt(s); // this.remove(x); // s--; // } // } // // private void reduce(float subset, TraceReductionType type, long seed) // { // Random prng = new Random(seed); // int s = size(); // long n = Math.round(Math.ceil(s * subset)); // // if (n < s) // { // long delta = s - n; // // switch (type) // { // case NONE: // break; // // case RANDOM: // randomReduction(delta, prng); // break; // // case SHAPES_NOVARS: // case SHAPES_VARNAMES: // case SHAPES_VARVALUES: // shapesReduction(delta, type, prng); // break; // // default: // throw new InternalException(53, "Unknown trace reduction"); // } // } // } // private void shapesReduction(long delta, TraceReductionType type, // Random prng) // { // Map<String, TestSequence> map = new HashMap<String, TestSequence>(); // // for (CallSequence cs : this) // { // String shape = cs.toShape(type); // TestSequence subset = map.get(shape); // // if (subset == null) // { // subset = new TestSequence(); // map.put(shape, subset); // } // // subset.add(cs); // } // // String[] shapes = map.keySet().toArray(new String[0]); // // if (size() - delta < shapes.length) // { // // We must keep one test for each shape // delta = size() - shapes.length; // } // // for (long i = 0; i < delta; i++) // { // int x = prng.nextInt(shapes.length); // TestSequence tests = map.get(shapes[x]); // int s = tests.size(); // // if (s < 2) // { // i--; // Find another group // } else // { // tests.remove(prng.nextInt(s)); // } // } // // clear(); // // for (Entry<String, TestSequence> entry : map.entrySet()) // { // addAll(map.get(entry.getKey())); // } // } }