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

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