source: trunk/quest-core-testgeneration/src/main/java/de/ugoe/cs/quest/testgeneration/HybridGenerator.java @ 655

Last change on this file since 655 was 655, checked in by pharms, 12 years ago
  • removed old copyright file header
  • Property svn:mime-type set to text/plain
File size: 7.1 KB
Line 
1package de.ugoe.cs.quest.testgeneration;
2
3import java.security.InvalidParameterException;
4import java.util.ArrayList;
5import java.util.Collection;
6import java.util.LinkedHashSet;
7import java.util.LinkedList;
8import java.util.List;
9import java.util.Random;
10import java.util.logging.Level;
11
12import de.ugoe.cs.quest.eventcore.Event;
13import de.ugoe.cs.quest.usageprofiles.IStochasticProcess;
14import de.ugoe.cs.util.console.Console;
15
16/**
17 * <p>
18 * Generates a test suite with a hybrid approach that is a mixture of random walks and drawing from
19 * all possible sequences.
20 * </p>
21 *
22 * @author Steffen Herbold
23 * @version 1.0
24 */
25public class HybridGenerator {
26
27    /**
28     * <p>
29     * Number of sequences in the test suite.
30     * </p>
31     */
32    private final int numSequences;
33
34    /**
35     * <p>
36     * Length of a test sequence.
37     * </p>
38     */
39    private final int length;
40
41    /**
42     * <p>
43     * Maximal length where it is possible to generate all sequences and draw from them.
44     * </p>
45     */
46    private final int maxLengthAll;
47
48    /**
49     * <p>
50     * In case this member is true, only test cases that end in the global end event
51     * {@link Event#ENDEVENT} are generated. If it is false, the end event can be any event.
52     * </p>
53     */
54    private final boolean validEnd;
55
56    /**
57     * <p>
58     * Constructor. Creates a new HybridGenerator and ensures the validity of the parameters:
59     * <ul>
60     * <li>numSequences must at least be 1
61     * <li>length must be at least 1
62     * </ul>
63     * If one of these conditions is violated an {@link InvalidParameterException} is thrown.
64     * </p>
65     *
66     * @param numSequences
67     *            number of sequences desired for the test suite
68     * @param length
69     *            length of a test sequence
70     * @param maxLengthAll
71     *            maximal length where it is possible to generate all sequences and draw from them
72     * @param validEnd
73     *            defines if test cases have to end with the global end event {@link Event#ENDEVENT}
74     *            (see {@link #validEnd})
75     */
76    public HybridGenerator(int numSequences, int length, int maxLengthAll, boolean validEnd) {
77        // check validity of the parameters
78        if (numSequences < 1) {
79            throw new InvalidParameterException("number of sequences must be at least 1 but is " +
80                numSequences);
81        }
82        if (length < 1) {
83            throw new InvalidParameterException("length of test cases must be at least 1 but is " +
84                length);
85        }
86        this.numSequences = numSequences;
87        this.length = length;
88        this.maxLengthAll = maxLengthAll;
89        this.validEnd = validEnd;
90    }
91
92    /**
93     * <p>
94     * Generates a test suite with a hybrid approach that is a mixture of random walks and drawing
95     * from all possible sequences
96     * </p>
97     *
98     * @param model
99     *            model used to determine the probability of each possible sequence
100     * @return the test suite
101     */
102    public Collection<List<Event>> generateTestSuite(IStochasticProcess model) {
103        if (model == null) {
104            throw new InvalidParameterException("model must not be null!");
105        }
106
107        Collection<List<Event>> sequences = new LinkedHashSet<List<Event>>();
108
109        List<List<Event>> seqsTmp =
110            new ArrayList<List<Event>>(model.generateSequences(maxLengthAll + 1, true));
111
112        Console.traceln(Level.INFO, "" + seqsTmp.size() + " of length " + maxLengthAll + " possible");
113        List<Double> probabilities = new ArrayList<Double>(seqsTmp.size());
114        double probSum = 0.0;
115        for (List<Event> sequence : seqsTmp) {
116            double prob = model.getProbability(sequence);
117            probabilities.add(prob);
118            probSum += prob;
119        }
120
121        Random r = new Random();
122        int j = 0;
123        while (sequences.size() < numSequences && j <= numSequences * 100) {
124            j++;
125            double randVal = r.nextDouble() * probSum;
126            double sum = 0.0d;
127            int index = -1;
128            while (sum < randVal) {
129                index++;
130                double currentProb = probabilities.get(index);
131                sum += currentProb;
132            }
133            List<Event> seqTmp = seqsTmp.get(index);
134            if (!Event.ENDEVENT.equals(seqTmp.get(seqTmp.size() - 1))) {
135                List<Event> sequence;
136                if (validEnd) {
137                    sequence = finishSequence(seqTmp, model, length + 2, validEnd);
138                    if (sequence != null && sequence.size() != length + 2) {
139                        sequence = null;
140                    }
141                }
142                else {
143                    sequence = finishSequence(seqTmp, model, length + 1, validEnd);
144                    if (sequence != null && sequence.size() != length + 1) {
145                        sequence = null;
146                    }
147                }
148                if (sequence != null) {
149                    sequences.add(sequence);
150                }
151            }
152        }
153
154        return sequences;
155    }
156
157    /**
158     * <p>
159     * Finishes a sequence with a random walk.
160     * </p>
161     *
162     * @param sequence
163     *            sequence to be finished
164     * @param model
165     *            model used for the random walk
166     * @param length
167     *            desired length of the sequence
168     * @param validEnd
169     *            if the sequence should end in {@link Event#ENDEVENT}.
170     * @return finished sequence of the desired length
171     */
172    private List<Event> finishSequence(List<Event> sequence,
173                                       IStochasticProcess model,
174                                       int length,
175                                       boolean validEnd)
176    {
177        Random r = new Random();
178        boolean endFound = false;
179        List<Event> sequenceCopy = new LinkedList<Event>(sequence);
180        final int maxIter = 30000;
181        int iter = 0;
182        while (!endFound && iter < maxIter) {
183            iter++;
184            sequenceCopy = new LinkedList<Event>(sequence);
185            while (!endFound && sequenceCopy.size() <= length) {
186                double randVal = r.nextDouble();
187                double probSum = 0.0;
188                for (Event symbol : model.getEvents()) {
189                    probSum += model.getProbability(sequenceCopy, symbol);
190                    if (probSum >= randVal) {
191                        if (!(Event.STARTEVENT.equals(symbol) || (!validEnd && Event.ENDEVENT
192                            .equals(symbol))))
193                        {
194                            // only add the symbol the sequence if it is not
195                            // START
196                            // or END
197                            sequenceCopy.add(symbol);
198                        }
199                        endFound =
200                            Event.ENDEVENT.equals(symbol) ||
201                                (!validEnd && sequenceCopy.size() == length);
202                        break;
203                    }
204                }
205            }
206        }
207        if (iter == maxIter) {
208            return null;
209        }
210        return sequenceCopy;
211    }
212
213}
Note: See TracBrowser for help on using the repository browser.