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

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