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
RevLine 
[1113]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
[922]15package de.ugoe.cs.autoquest.tasktrees.treeimpl;
[439]16
[1494]17import java.util.Arrays;
[1146]18import java.util.Collection;
19import java.util.Collections;
[439]20import java.util.HashMap;
[1146]21import java.util.List;
[439]22import java.util.Map;
23
[1423]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;
[1146]34import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
35import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
[1287]36import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstanceList;
[1146]37import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
38import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInfo;
39import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession;
[1423]40import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskMetric;
[439]41
42/**
[1216]43 * <p>
44 * this is the default implementation of the interface {@link ITaskModel}. It
[1423]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
[1216]47 * </p>
[439]48 *
[1216]49 * @author Patrick Harms
[439]50 */
[1146]51class TaskModel implements ITaskModel {
[557]52   
[1216]53    /**
54     * <p>
55     * default serial version UID
56     * </p>
57     */
[1146]58    private static final long serialVersionUID = 1L;
[1423]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,
[1494]69          TaskMetric.EVENT_COVERAGE_RATIO,
70          TaskMetric.EVENT_COVERAGE_QUANTILE };
[439]71
[1216]72    /**
73     * <p>
74     * the user sessions belonging to the model
75     * </p>
76     */
[1146]77    private List<IUserSession> userSessions;
[439]78
[1216]79    /**
80     * <p>
[1423]81     * index for effectively accessing the model and calculating statistics about it
[1216]82     * </p>
83     */
[1423]84    private transient TaskModelIndex index = null;
85   
[557]86    /**
[1216]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
[557]92     */
[1146]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;
[439]99    }
100
[1287]101   
[1146]102    /* (non-Javadoc)
103     * @see de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel#getUserSessions()
[557]104     */
105    @Override
[1146]106    public List<IUserSession> getUserSessions() {
[1423]107        ensureInitialized();
[1146]108        return Collections.unmodifiableList(userSessions);
[439]109    }
[557]110
[1146]111
112    /* (non-Javadoc)
113     * @see de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel#getTasks()
[557]114     */
115    @Override
[1146]116    public Collection<ITask> getTasks() {
[1423]117        ensureInitialized();
118        return Collections.unmodifiableCollection(index.taskMap.keySet());
[439]119    }
[557]120
[1146]121
122    /* (non-Javadoc)
[1216]123     * @see de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel#getTaskInfo(ITask)
[1146]124     */
125    @Override
126    public ITaskInfo getTaskInfo(ITask task) {
[1423]127        ensureInitialized();
128        return index.taskMap.get(task);
[1146]129    }
130
[1216]131    /* (non-Javadoc)
[1423]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)
[1216]141     * @see java.lang.Object#clone()
142     */
143    @Override
144    public TaskModel clone() {
145        return new TaskModel(userSessions);
146    }
147
[1891]148    /* (non-Javadoc)
149     * @see java.lang.Object#toString()
150     */
151    @Override
152    public String toString() {
[1948]153        ensureInitialized();
[1891]154        return "Task Model (" + userSessions.size() + " sessions, " + index.taskMap.size() +
155            " tasks, hash " + System.identityHashCode(this) + ")";
156    }
157
[557]158    /**
[1216]159     * <p>
[1423]160     * internal convenience method that initializes the internal index and calculates all measures
161     * for metrics available for the tasks
[1287]162     * </p>
163     */
[1423]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) {
[1891]170                    index.handleTaskInstance(taskInstance);
[1423]171                }
[1287]172            }
[1423]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           
[1494]183            int[] eventCoverageRatios = new int[tasks.size()];
184            int i = 0;
185
[1423]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);
[1494]192                int coverageRatio = 0;
[1423]193               
194                if (allEventsCovered > 0) {
[1494]195                    coverageRatio = (coveredEvents * 1000) / allEventsCovered;
[1423]196                }
[1494]197               
198                eventCoverageRatios[i++] = coverageRatio;
[1891]199                info.setCount(TaskMetric.EVENT_COVERAGE_RATIO, coverageRatio);
[1423]200            }
201           
[1494]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               
[1891]213                info.setCount(TaskMetric.EVENT_COVERAGE_QUANTILE, quantile);
[1494]214            }
215           
[1423]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            }*/
[1287]225        }
[1423]226       
[1287]227    }
228
229    /**
230     * <p>
[1423]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.
[1216]234     * </p>
[1423]235     *
236     * @author Patrick Harms
[557]237     */
[1423]238    private static class TaskModelIndex {
[557]239
[1423]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         */
[1891]254        private int[] handleTaskInstance(ITaskInstance taskInstance) {
[1423]255            int eventTaskInstancesCovered = 0;
256            int depth = 0;
257           
258            if (taskInstance instanceof ITaskInstanceList) {
259                for (ITaskInstance child : (ITaskInstanceList) taskInstance) {
[1891]260                    int[] measures = handleTaskInstance(child);
[1423]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
[1891]269                    ensureTaskInfo(((IIteration) taskInstance.getTask()).getMarkedTask());
[1423]270                }
271            }
272            else if (taskInstance instanceof ISelectionInstance) {
273                ITaskInstance child = ((ISelectionInstance) taskInstance).getChild();
[1891]274                int[] measures = handleTaskInstance(child);
[1423]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()) {
[1891]280                    ensureTaskInfo(otherChildTask);
[1423]281                }
282            }
283            else if (taskInstance instanceof IOptionalInstance) {
284                ITaskInstance child = ((IOptionalInstance) taskInstance).getChild();
285                if (child != null) {
[1891]286                    int[] measures = handleTaskInstance(child);
[1423]287                    eventTaskInstancesCovered += measures[0];
288                    depth = Math.max(depth, measures[1]);
289                }
290                else {
291                    // ensure also empty task infos for unselected variants
[1891]292                    ensureTaskInfo(((IOptional) taskInstance.getTask()).getMarkedTask());
[1423]293                }
294            }
295            else if (taskInstance instanceof IEventTaskInstance) {
296                eventTaskInstancesCovered = 1;
297            }
298           
299            depth++;
300           
[1891]301            ensureTaskInfo(taskInstance.getTask(), eventTaskInstancesCovered, depth);
[1423]302           
303            return new int[] { eventTaskInstancesCovered, depth };
[557]304        }
[1423]305       
306        /**
307         * <p>
308         * internal convenience method to build the task model during initialization
309         * </p>
310         */
[1891]311        private void ensureTaskInfo(ITask task) {
312            ensureTaskInfo(task, 0, 0);
[1423]313           
314            if (task instanceof IStructuringTemporalRelationship) {
315                for (ITask child : ((IStructuringTemporalRelationship) task).getChildren()) {
[1891]316                    ensureTaskInfo(child);
[1423]317                }
318            }
319            else if (task instanceof IMarkingTemporalRelationship) {
[1891]320                ensureTaskInfo(((IMarkingTemporalRelationship) task).getMarkedTask());
[1423]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);
[557]338
[1423]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               
[1891]346                taskInfo.setCount(TaskMetric.DEPTH, getDepth(task));
[1423]347            }
[1287]348
[1891]349            taskInfo.increaseCount(TaskMetric.COUNT, 1);
350            taskInfo.increaseCount(TaskMetric.EVENT_COVERAGE, eventTaskInstancesCovered);
[1423]351
[1891]352            taskInfo.setCount(TaskMetric.DEPTH, depth);
[1423]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;
[1146]363            }
[1423]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            }
[557]377        }
[1423]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            }
[1287]397        }*/
[1423]398
[439]399    }
400
[1423]401
[439]402}
Note: See TracBrowser for help on using the repository browser.