// Copyright 2012 Georg-August-Universität Göttingen, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package de.ugoe.cs.autoquest.tasktrees.treeimpl; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask; import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance; import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration; import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance; import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship; import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptional; import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptionalInstance; import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection; import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance; import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstanceList; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInfo; import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession; import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskMetric; /** *
* this is the default implementation of the interface {@link ITaskModel}. It * does not do anything fancy except implementing the interface. It also calculates on * initialisations the measures for diverse metrics of the task belonging to the model *
* * @author Patrick Harms */ class TaskModel implements ITaskModel { /** ** default serial version UID *
*/ private static final long serialVersionUID = 1L; /** ** all metrics calculated by this type of task model *
*/ private static final TaskMetric[] taskMetrics = new TaskMetric[] { TaskMetric.COUNT, TaskMetric.DEPTH, TaskMetric.EVENT_COVERAGE, TaskMetric.EVENT_COVERAGE_RATIO, TaskMetric.EVENT_COVERAGE_QUANTILE }; /** ** the user sessions belonging to the model *
*/ private List* index for effectively accessing the model and calculating statistics about it *
*/ private transient TaskModelIndex index = null; /** ** initializes the task model with the user sessions out of which the tasks are extracted *
* * @param userSessions as described */ TaskModel(List* internal convenience method that initializes the internal index and calculates all measures * for metrics available for the tasks *
*/ private synchronized void ensureInitialized() { if (index == null) { index = new TaskModelIndex(); for (IUserSession session : this.userSessions) { for (ITaskInstance taskInstance : session) { index.handleTaskInstance(taskInstance, null); } } // count all events covered int allEventsCovered = 0; Collection* the index of task infos used internally. The index is created once and while that filled * with task infos for each observed task containing all measures for metrics belonging * to the tasks. *
* * @author Patrick Harms */ private static class TaskModelIndex { /** ** the tasks contained in the user session belonging to the model as well as statistical * infos about them *
*/ private Map* called on initialization to fill the index with infos about the given task instance * as well as to calculate the appropriate metrics *
*/ private int[] handleTaskInstance(ITaskInstance taskInstance, ITask context) { int eventTaskInstancesCovered = 0; int depth = 0; if (taskInstance instanceof ITaskInstanceList) { for (ITaskInstance child : (ITaskInstanceList) taskInstance) { int[] measures = handleTaskInstance(child, taskInstance.getTask()); eventTaskInstancesCovered += measures[0]; depth = Math.max(depth, measures[1]); } if ((((ITaskInstanceList) taskInstance).size() == 0) && (taskInstance instanceof IIterationInstance)) { // ensure also empty task infos for unselected variants ensureTaskInfo(((IIteration) taskInstance.getTask()).getMarkedTask(), context); } } else if (taskInstance instanceof ISelectionInstance) { ITaskInstance child = ((ISelectionInstance) taskInstance).getChild(); int[] measures = handleTaskInstance(child, taskInstance.getTask()); eventTaskInstancesCovered += measures[0]; depth = Math.max(depth, measures[1]); // ensure also empty task infos for unselected variants for (ITask otherChildTask : ((ISelection) taskInstance.getTask()).getChildren()) { ensureTaskInfo(otherChildTask, context); } } else if (taskInstance instanceof IOptionalInstance) { ITaskInstance child = ((IOptionalInstance) taskInstance).getChild(); if (child != null) { int[] measures = handleTaskInstance(child, taskInstance.getTask()); eventTaskInstancesCovered += measures[0]; depth = Math.max(depth, measures[1]); } else { // ensure also empty task infos for unselected variants ensureTaskInfo(((IOptional) taskInstance.getTask()).getMarkedTask(), context); } } else if (taskInstance instanceof IEventTaskInstance) { eventTaskInstancesCovered = 1; } depth++; ensureTaskInfo(taskInstance.getTask(), context, eventTaskInstancesCovered, depth); return new int[] { eventTaskInstancesCovered, depth }; } /** ** internal convenience method to build the task model during initialization *
*/ private void ensureTaskInfo(ITask task, ITask context) { ensureTaskInfo(task, context, 0, 0); if (task instanceof IStructuringTemporalRelationship) { for (ITask child : ((IStructuringTemporalRelationship) task).getChildren()) { ensureTaskInfo(child, task); } } else if (task instanceof IMarkingTemporalRelationship) { ensureTaskInfo(((IMarkingTemporalRelationship) task).getMarkedTask(), task); } } /** ** internal convenience method to build the task model during initialization. Adds a new * task info object to the map for the provided task and fills it with measures. If there * are already some task infos for the task, the contained measures are updated according * to the parameters. *
*/ private void ensureTaskInfo(ITask task, ITask context, int eventTaskInstancesCovered, int depth) { TaskInfo taskInfo = taskMap.get(task); if (taskInfo == null) { taskInfo = new TaskInfo(task); taskInfo.addMeasure(TaskMetric.COUNT); taskInfo.addMeasure(TaskMetric.EVENT_COVERAGE); taskInfo.addMeasure(TaskMetric.DEPTH); taskMap.put(task, taskInfo); taskInfo.setCount(TaskMetric.DEPTH, null, getDepth(task)); } taskInfo.increaseCount(TaskMetric.COUNT, context, 1); taskInfo.increaseCount(TaskMetric.EVENT_COVERAGE, context, eventTaskInstancesCovered); taskInfo.setCount(TaskMetric.DEPTH, context, depth); } /** ** internal convenience method to calculate the maximum depth of a task *
*/ private int getDepth(ITask task) { if (task instanceof IMarkingTemporalRelationship) { return getDepth(((IMarkingTemporalRelationship) task).getMarkedTask()) + 1; } else if (task instanceof IStructuringTemporalRelationship) { int maxDepth = 0; for (ITask child : ((IStructuringTemporalRelationship) task).getChildren()) { maxDepth = Math.max(maxDepth, getDepth(child)); } return maxDepth + 1; } else { // event tasks return 1; } } /** * */ /*private void dumpToCSV(PrintStream out) { out.println("taskid;depth;count;eventcoverage;eventcoverageratio"); for (Map.Entry