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

Last change on this file since 1948 was 1948, checked in by pharms, 9 years ago
  • bugfix to prevent null pointer after reading task model from stored global data container
  • 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 synchronized void ensureInitialized() {
165        if (index == null) {
166            index = new TaskModelIndex();
167           
168            for (IUserSession session : this.userSessions) {
169                for (ITaskInstance taskInstance : session) {
170                    index.handleTaskInstance(taskInstance);
171                }
172            }
173           
174            // count all events covered
175            int allEventsCovered = 0;
176            Collection<ITask> tasks = getTasks();
177            for (ITask task : tasks) {
178                if (task instanceof IEventTask) {
179                    allEventsCovered += task.getInstances().size();
180                }
181            }
182           
183            int[] eventCoverageRatios = new int[tasks.size()];
184            int i = 0;
185
186            // add some further measures
187            for (ITask task : tasks) {
188                TaskInfo info = index.taskMap.get(task);
189                info.addMeasure(TaskMetric.EVENT_COVERAGE_RATIO);
190               
191                int coveredEvents = info.getMeasureValue(TaskMetric.EVENT_COVERAGE);
192                int coverageRatio = 0;
193               
194                if (allEventsCovered > 0) {
195                    coverageRatio = (coveredEvents * 1000) / allEventsCovered;
196                }
197               
198                eventCoverageRatios[i++] = coverageRatio;
199                info.setCount(TaskMetric.EVENT_COVERAGE_RATIO, coverageRatio);
200            }
201           
202            Arrays.sort(eventCoverageRatios);
203           
204            // add some further measures
205            for (ITask task : tasks) {
206                TaskInfo info = index.taskMap.get(task);
207                info.addMeasure(TaskMetric.EVENT_COVERAGE_QUANTILE);
208                int quantile = Arrays.binarySearch
209                    (eventCoverageRatios, info.getMeasureValue(TaskMetric.EVENT_COVERAGE_RATIO));
210               
211                quantile = 1000 * quantile / eventCoverageRatios.length;
212               
213                info.setCount(TaskMetric.EVENT_COVERAGE_QUANTILE, quantile);
214            }
215           
216            //index.dumpToCSV(System.out);
217            /*try {
218                OutputStream stream = new FileOutputStream(new File("tasks.csv"));
219                index.dumpToCSV(new PrintStream(stream));
220                stream.close();
221            }
222            catch (FileNotFoundException e) {
223                e.printStackTrace();
224            }*/
225        }
226       
227    }
228
229    /**
230     * <p>
231     * the index of task infos used internally. The index is created once and while that filled
232     * with task infos for each observed task containing all measures for metrics belonging
233     * to the tasks.
234     * </p>
235     *
236     * @author Patrick Harms
237     */
238    private static class TaskModelIndex {
239
240        /**
241         * <p>
242         * the tasks contained in the user session belonging to the model as well as statistical
243         * infos about them
244         * </p>
245         */
246        private Map<ITask, TaskInfo> taskMap = new HashMap<ITask, TaskInfo>();
247
248        /**
249         * <p>
250         * called on initialization to fill the index with infos about the given task instance
251         * as well as to calculate the appropriate metrics
252         * </p>
253         */
254        private int[] handleTaskInstance(ITaskInstance taskInstance) {
255            int eventTaskInstancesCovered = 0;
256            int depth = 0;
257           
258            if (taskInstance instanceof ITaskInstanceList) {
259                for (ITaskInstance child : (ITaskInstanceList) taskInstance) {
260                    int[] measures = handleTaskInstance(child);
261                    eventTaskInstancesCovered += measures[0];
262                    depth = Math.max(depth, measures[1]);
263                }
264               
265                if ((((ITaskInstanceList) taskInstance).size() == 0) &&
266                    (taskInstance instanceof IIterationInstance))
267                {
268                    // ensure also empty task infos for unselected variants
269                    ensureTaskInfo(((IIteration) taskInstance.getTask()).getMarkedTask());
270                }
271            }
272            else if (taskInstance instanceof ISelectionInstance) {
273                ITaskInstance child = ((ISelectionInstance) taskInstance).getChild();
274                int[] measures = handleTaskInstance(child);
275                eventTaskInstancesCovered += measures[0];
276                depth = Math.max(depth, measures[1]);
277               
278                // ensure also empty task infos for unselected variants
279                for (ITask otherChildTask : ((ISelection) taskInstance.getTask()).getChildren()) {
280                    ensureTaskInfo(otherChildTask);
281                }
282            }
283            else if (taskInstance instanceof IOptionalInstance) {
284                ITaskInstance child = ((IOptionalInstance) taskInstance).getChild();
285                if (child != null) {
286                    int[] measures = handleTaskInstance(child);
287                    eventTaskInstancesCovered += measures[0];
288                    depth = Math.max(depth, measures[1]);
289                }
290                else {
291                    // ensure also empty task infos for unselected variants
292                    ensureTaskInfo(((IOptional) taskInstance.getTask()).getMarkedTask());
293                }
294            }
295            else if (taskInstance instanceof IEventTaskInstance) {
296                eventTaskInstancesCovered = 1;
297            }
298           
299            depth++;
300           
301            ensureTaskInfo(taskInstance.getTask(), eventTaskInstancesCovered, depth);
302           
303            return new int[] { eventTaskInstancesCovered, depth };
304        }
305       
306        /**
307         * <p>
308         * internal convenience method to build the task model during initialization
309         * </p>
310         */
311        private void ensureTaskInfo(ITask task) {
312            ensureTaskInfo(task, 0, 0);
313           
314            if (task instanceof IStructuringTemporalRelationship) {
315                for (ITask child : ((IStructuringTemporalRelationship) task).getChildren()) {
316                    ensureTaskInfo(child);
317                }
318            }
319            else if (task instanceof IMarkingTemporalRelationship) {
320                ensureTaskInfo(((IMarkingTemporalRelationship) task).getMarkedTask());
321            }
322       
323        }
324       
325        /**
326         * <p>
327         * internal convenience method to build the task model during initialization. Adds a new
328         * task info object to the map for the provided task and fills it with measures. If there
329         * are already some task infos for the task, the contained measures are updated according
330         * to the parameters.
331         * </p>
332         */
333        private void ensureTaskInfo(ITask task,
334                                    int   eventTaskInstancesCovered,
335                                    int   depth)
336        {
337            TaskInfo taskInfo = taskMap.get(task);
338
339            if (taskInfo == null) {
340                taskInfo = new TaskInfo(task);
341                taskInfo.addMeasure(TaskMetric.COUNT);
342                taskInfo.addMeasure(TaskMetric.EVENT_COVERAGE);
343                taskInfo.addMeasure(TaskMetric.DEPTH);
344                taskMap.put(task, taskInfo);
345               
346                taskInfo.setCount(TaskMetric.DEPTH, getDepth(task));
347            }
348
349            taskInfo.increaseCount(TaskMetric.COUNT, 1);
350            taskInfo.increaseCount(TaskMetric.EVENT_COVERAGE, eventTaskInstancesCovered);
351
352            taskInfo.setCount(TaskMetric.DEPTH, depth);
353        }
354
355        /**
356         * <p>
357         * internal convenience method to calculate the maximum depth of a task
358         * </p>
359         */
360        private int getDepth(ITask task) {
361            if (task instanceof IMarkingTemporalRelationship) {
362                return getDepth(((IMarkingTemporalRelationship) task).getMarkedTask()) + 1;
363            }
364            else if (task instanceof IStructuringTemporalRelationship) {
365                int maxDepth = 0;
366               
367                for (ITask child : ((IStructuringTemporalRelationship) task).getChildren()) {
368                    maxDepth = Math.max(maxDepth, getDepth(child));
369                }
370               
371                return maxDepth + 1;
372            }
373            else {
374                // event tasks
375                return 1;
376            }
377        }
378
379        /**
380         *
381         */
382        /*private void dumpToCSV(PrintStream out) {
383            out.println("taskid;depth;count;eventcoverage;eventcoverageratio");
384           
385            for (Map.Entry<ITask, TaskInfo> entry : taskMap.entrySet()) {
386                out.print(entry.getKey().getId());
387                out.print(';');
388                out.print(entry.getValue().getMeasureValue(TaskMetric.DEPTH));
389                out.print(';');
390                out.print(entry.getValue().getMeasureValue(TaskMetric.COUNT));
391                out.print(';');
392                out.print(entry.getValue().getMeasureValue(TaskMetric.EVENT_COVERAGE));
393                out.print(';');
394                out.print(entry.getValue().getMeasureValue(TaskMetric.EVENT_COVERAGE_RATIO));
395                out.println();
396            }
397        }*/
398
399    }
400
401
402}
Note: See TracBrowser for help on using the repository browser.