source: trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/treeimpl/TaskModel.java

Last change on this file was 2242, checked in by pharms, 7 years ago
  • solved some findbugs issues
  • Property svn:executable set to *
File size: 14.1 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.tasktrees.treeimpl;
16
17import java.util.Arrays;
18import java.util.Collection;
19import java.util.Collections;
20import java.util.HashMap;
21import java.util.List;
22import java.util.Map;
23
24import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
25import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
26import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration;
27import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance;
28import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship;
29import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptional;
30import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptionalInstance;
31import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection;
32import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance;
33import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship;
34import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
35import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
36import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstanceList;
37import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
38import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInfo;
39import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession;
40import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskMetric;
41
42/**
43 * <p>
44 * this is the default implementation of the interface {@link ITaskModel}. It
45 * does not do anything fancy except implementing the interface. It also calculates on
46 * initialisations the measures for diverse metrics of the task belonging to the model
47 * </p>
48 *
49 * @author Patrick Harms
50 */
51class TaskModel implements ITaskModel {
52   
53    /**
54     * <p>
55     * default serial version UID
56     * </p>
57     */
58    private static final long serialVersionUID = 1L;
59   
60    /**
61     * <p>
62     * all metrics calculated by this type of task model
63     * </p>
64     */
65    private static final TaskMetric[] taskMetrics = new TaskMetric[]
66        { TaskMetric.COUNT,
67          TaskMetric.DEPTH,
68          TaskMetric.EVENT_COVERAGE,
69          TaskMetric.EVENT_COVERAGE_RATIO,
70          TaskMetric.EVENT_COVERAGE_QUANTILE };
71
72    /**
73     * <p>
74     * the user sessions belonging to the model
75     * </p>
76     */
77    private List<IUserSession> userSessions;
78
79    /**
80     * <p>
81     * index for effectively accessing the model and calculating statistics about it
82     * </p>
83     */
84    private transient TaskModelIndex index = null;
85   
86    /**
87     * <p>
88     * initializes the task model with the user sessions out of which the tasks are extracted
89     * </p>
90     *
91     * @param userSessions as described
92     */
93    TaskModel(List<IUserSession> userSessions) {
94        if ((userSessions == null) || (userSessions.size() == 0)) {
95            throw new IllegalArgumentException("user sessions must not be null");
96        }
97       
98        this.userSessions = userSessions;
99    }
100
101   
102    /* (non-Javadoc)
103     * @see de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel#getUserSessions()
104     */
105    @Override
106    public List<IUserSession> getUserSessions() {
107        ensureInitialized();
108        return Collections.unmodifiableList(userSessions);
109    }
110
111
112    /* (non-Javadoc)
113     * @see de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel#getTasks()
114     */
115    @Override
116    public Collection<ITask> getTasks() {
117        ensureInitialized();
118        return Collections.unmodifiableCollection(index.taskMap.keySet());
119    }
120
121
122    /* (non-Javadoc)
123     * @see de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel#getTaskInfo(ITask)
124     */
125    @Override
126    public ITaskInfo getTaskInfo(ITask task) {
127        ensureInitialized();
128        return index.taskMap.get(task);
129    }
130
131    /* (non-Javadoc)
132     * @see de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel#getAllMetrics()
133     */
134    @Override
135    public TaskMetric[] getAllMetrics() {
136        return taskMetrics;
137    }
138
139
140    /* (non-Javadoc)
141     * @see java.lang.Object#clone()
142     */
143    @Override
144    public TaskModel clone() {
145        return new TaskModel(userSessions);
146    }
147
148    /* (non-Javadoc)
149     * @see java.lang.Object#toString()
150     */
151    @Override
152    public String toString() {
153        ensureInitialized();
154        return "Task Model (" + userSessions.size() + " sessions, " + index.taskMap.size() +
155            " tasks, hash " + System.identityHashCode(this) + ")";
156    }
157
158    /**
159     * <p>
160     * internal convenience method that initializes the internal index and calculates all measures
161     * for metrics available for the tasks
162     * </p>
163     */
164    private void ensureInitialized() {
165        synchronized (this) {
166            if (index == null) {
167                index = new TaskModelIndex();
168
169                for (IUserSession session : this.userSessions) {
170                    for (ITaskInstance taskInstance : session) {
171                        index.handleTaskInstance(taskInstance);
172                    }
173                }
174
175                // count all events covered
176                int allEventsCovered = 0;
177                Collection<ITask> tasks = getTasks();
178                for (ITask task : tasks) {
179                    if (task instanceof IEventTask) {
180                        allEventsCovered += task.getInstances().size();
181                    }
182                }
183
184                int[] eventCoverageRatios = new int[tasks.size()];
185                int i = 0;
186
187                // add some further measures
188                for (ITask task : tasks) {
189                    TaskInfo info = index.taskMap.get(task);
190                    info.addMeasure(TaskMetric.EVENT_COVERAGE_RATIO);
191
192                    int coveredEvents = info.getMeasureValue(TaskMetric.EVENT_COVERAGE);
193                    int coverageRatio = 0;
194
195                    if (allEventsCovered > 0) {
196                        coverageRatio = (coveredEvents * 1000) / allEventsCovered;
197                    }
198
199                    eventCoverageRatios[i++] = coverageRatio;
200                    info.setCount(TaskMetric.EVENT_COVERAGE_RATIO, coverageRatio);
201                }
202
203                Arrays.sort(eventCoverageRatios);
204
205                // add some further measures
206                for (ITask task : tasks) {
207                    TaskInfo info = index.taskMap.get(task);
208                    info.addMeasure(TaskMetric.EVENT_COVERAGE_QUANTILE);
209                    int quantile = Arrays.binarySearch
210                            (eventCoverageRatios, info.getMeasureValue(TaskMetric.EVENT_COVERAGE_RATIO));
211
212                    quantile = 1000 * quantile / eventCoverageRatios.length;
213
214                    info.setCount(TaskMetric.EVENT_COVERAGE_QUANTILE, quantile);
215                }
216
217                //index.dumpToCSV(System.out);
218                /*try {
219                    OutputStream stream = new FileOutputStream(new File("tasks.csv"));
220                    index.dumpToCSV(new PrintStream(stream));
221                    stream.close();
222                }
223                catch (FileNotFoundException e) {
224                    e.printStackTrace();
225                }*/
226            }
227        }
228    }
229
230    /**
231     * <p>
232     * the index of task infos used internally. The index is created once and while that filled
233     * with task infos for each observed task containing all measures for metrics belonging
234     * to the tasks.
235     * </p>
236     *
237     * @author Patrick Harms
238     */
239    private static class TaskModelIndex {
240
241        /**
242         * <p>
243         * the tasks contained in the user session belonging to the model as well as statistical
244         * infos about them
245         * </p>
246         */
247        private Map<ITask, TaskInfo> taskMap = new HashMap<ITask, TaskInfo>();
248
249        /**
250         * <p>
251         * called on initialization to fill the index with infos about the given task instance
252         * as well as to calculate the appropriate metrics
253         * </p>
254         */
255        private int[] handleTaskInstance(ITaskInstance taskInstance) {
256            int eventTaskInstancesCovered = 0;
257            int depth = 0;
258           
259            if (taskInstance instanceof ITaskInstanceList) {
260                for (ITaskInstance child : (ITaskInstanceList) taskInstance) {
261                    int[] measures = handleTaskInstance(child);
262                    eventTaskInstancesCovered += measures[0];
263                    depth = Math.max(depth, measures[1]);
264                }
265               
266                if ((((ITaskInstanceList) taskInstance).size() == 0) &&
267                    (taskInstance instanceof IIterationInstance))
268                {
269                    // ensure also empty task infos for unselected variants
270                    ensureTaskInfo(((IIteration) taskInstance.getTask()).getMarkedTask());
271                }
272            }
273            else if (taskInstance instanceof ISelectionInstance) {
274                ITaskInstance child = ((ISelectionInstance) taskInstance).getChild();
275                int[] measures = handleTaskInstance(child);
276                eventTaskInstancesCovered += measures[0];
277                depth = Math.max(depth, measures[1]);
278               
279                // ensure also empty task infos for unselected variants
280                for (ITask otherChildTask : ((ISelection) taskInstance.getTask()).getChildren()) {
281                    ensureTaskInfo(otherChildTask);
282                }
283            }
284            else if (taskInstance instanceof IOptionalInstance) {
285                ITaskInstance child = ((IOptionalInstance) taskInstance).getChild();
286                if (child != null) {
287                    int[] measures = handleTaskInstance(child);
288                    eventTaskInstancesCovered += measures[0];
289                    depth = Math.max(depth, measures[1]);
290                }
291                else {
292                    // ensure also empty task infos for unselected variants
293                    ensureTaskInfo(((IOptional) taskInstance.getTask()).getMarkedTask());
294                }
295            }
296            else if (taskInstance instanceof IEventTaskInstance) {
297                eventTaskInstancesCovered = 1;
298            }
299           
300            depth++;
301           
302            ensureTaskInfo(taskInstance.getTask(), eventTaskInstancesCovered, depth);
303           
304            return new int[] { eventTaskInstancesCovered, depth };
305        }
306       
307        /**
308         * <p>
309         * internal convenience method to build the task model during initialization
310         * </p>
311         */
312        private void ensureTaskInfo(ITask task) {
313            ensureTaskInfo(task, 0, 0);
314           
315            if (task instanceof IStructuringTemporalRelationship) {
316                for (ITask child : ((IStructuringTemporalRelationship) task).getChildren()) {
317                    ensureTaskInfo(child);
318                }
319            }
320            else if (task instanceof IMarkingTemporalRelationship) {
321                ensureTaskInfo(((IMarkingTemporalRelationship) task).getMarkedTask());
322            }
323       
324        }
325       
326        /**
327         * <p>
328         * internal convenience method to build the task model during initialization. Adds a new
329         * task info object to the map for the provided task and fills it with measures. If there
330         * are already some task infos for the task, the contained measures are updated according
331         * to the parameters.
332         * </p>
333         */
334        private void ensureTaskInfo(ITask task,
335                                    int   eventTaskInstancesCovered,
336                                    int   depth)
337        {
338            TaskInfo taskInfo = taskMap.get(task);
339
340            if (taskInfo == null) {
341                taskInfo = new TaskInfo(task);
342                taskInfo.addMeasure(TaskMetric.COUNT);
343                taskInfo.addMeasure(TaskMetric.EVENT_COVERAGE);
344                taskInfo.addMeasure(TaskMetric.DEPTH);
345                taskMap.put(task, taskInfo);
346               
347                taskInfo.setCount(TaskMetric.DEPTH, getDepth(task));
348            }
349
350            taskInfo.increaseCount(TaskMetric.COUNT, 1);
351            taskInfo.increaseCount(TaskMetric.EVENT_COVERAGE, eventTaskInstancesCovered);
352
353            taskInfo.setCount(TaskMetric.DEPTH, depth);
354        }
355
356        /**
357         * <p>
358         * internal convenience method to calculate the maximum depth of a task
359         * </p>
360         */
361        private int getDepth(ITask task) {
362            if (task instanceof IMarkingTemporalRelationship) {
363                return getDepth(((IMarkingTemporalRelationship) task).getMarkedTask()) + 1;
364            }
365            else if (task instanceof IStructuringTemporalRelationship) {
366                int maxDepth = 0;
367               
368                for (ITask child : ((IStructuringTemporalRelationship) task).getChildren()) {
369                    maxDepth = Math.max(maxDepth, getDepth(child));
370                }
371               
372                return maxDepth + 1;
373            }
374            else {
375                // event tasks
376                return 1;
377            }
378        }
379
380        /**
381         *
382         */
383        /*private void dumpToCSV(PrintStream out) {
384            out.println("taskid;depth;count;eventcoverage;eventcoverageratio");
385           
386            for (Map.Entry<ITask, TaskInfo> entry : taskMap.entrySet()) {
387                out.print(entry.getKey().getId());
388                out.print(';');
389                out.print(entry.getValue().getMeasureValue(TaskMetric.DEPTH));
390                out.print(';');
391                out.print(entry.getValue().getMeasureValue(TaskMetric.COUNT));
392                out.print(';');
393                out.print(entry.getValue().getMeasureValue(TaskMetric.EVENT_COVERAGE));
394                out.print(';');
395                out.print(entry.getValue().getMeasureValue(TaskMetric.EVENT_COVERAGE_RATIO));
396                out.println();
397            }
398        }*/
399
400    }
401
402
403}
Note: See TracBrowser for help on using the repository browser.