/******************************************************************************* * CogTool Copyright Notice and Distribution Terms * CogTool 1.3, Copyright (c) 2005-2013 Carnegie Mellon University * This software is distributed under the terms of the FSF Lesser * Gnu Public License (see LGPL.txt). * * CogTool is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * CogTool is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with CogTool; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * CogTool makes use of several third-party components, with the * following notices: * * Eclipse SWT version 3.448 * Eclipse GEF Draw2D version 3.2.1 * * Unless otherwise indicated, all Content made available by the Eclipse * Foundation is provided to you under the terms and conditions of the Eclipse * Public License Version 1.0 ("EPL"). A copy of the EPL is provided with this * Content and is also available at http://www.eclipse.org/legal/epl-v10.html. * * CLISP version 2.38 * * Copyright (c) Sam Steingold, Bruno Haible 2001-2006 * This software is distributed under the terms of the FSF Gnu Public License. * See COPYRIGHT file in clisp installation folder for more information. * * ACT-R 6.0 * * Copyright (c) 1998-2007 Dan Bothell, Mike Byrne, Christian Lebiere & * John R Anderson. * This software is distributed under the terms of the FSF Lesser * Gnu Public License (see LGPL.txt). * * Apache Jakarta Commons-Lang 2.1 * * This product contains software developed by the Apache Software Foundation * (http://www.apache.org/) * * jopt-simple version 1.0 * * Copyright (c) 2004-2013 Paul R. Holser, Jr. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Mozilla XULRunner 1.9.0.5 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (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.mozilla.org/MPL/. * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * The J2SE(TM) Java Runtime Environment version 5.0 * * Copyright 2009 Sun Microsystems, Inc., 4150 * Network Circle, Santa Clara, California 95054, U.S.A. All * rights reserved. U.S. * See the LICENSE file in the jre folder for more information. ******************************************************************************/ package edu.cmu.cs.hcii.cogtool; import java.text.NumberFormat; import java.util.Iterator; import java.util.List; import java.util.Locale; import edu.cmu.cs.hcii.cogtool.model.APredictionResult; import edu.cmu.cs.hcii.cogtool.model.AUndertaking; import edu.cmu.cs.hcii.cogtool.model.CognitiveModelGenerator; import edu.cmu.cs.hcii.cogtool.model.Demonstration; import edu.cmu.cs.hcii.cogtool.model.Design; import edu.cmu.cs.hcii.cogtool.model.GroupNature; import edu.cmu.cs.hcii.cogtool.model.IPredictionAlgo; import edu.cmu.cs.hcii.cogtool.model.Project; import edu.cmu.cs.hcii.cogtool.model.TaskApplication; import edu.cmu.cs.hcii.cogtool.model.TaskGroup; import edu.cmu.cs.hcii.cogtool.model.TimePredictionResult; import edu.cmu.cs.hcii.cogtool.util.SWTStringUtil; import edu.cmu.cs.hcii.cogtool.util.StringUtil; /** * Shared policy for computing the display of a APredictionResult */ public class ResultDisplayPolicy { public static final String WITH_SECS = " s"; public static final String NO_SECS = ""; // Prevent instantiation private ResultDisplayPolicy() { } // Set up output format private static NumberFormat cellNumberFormat; static { cellNumberFormat = NumberFormat.getInstance(Locale.US); // NOTE: numberformat drops any "hanging" zeros by default // Depends on locale of course } private static void updateDigits() { int n = CogToolPref.DISPLAY_DIGITS.getInt(); cellNumberFormat.setMaximumFractionDigits(n); cellNumberFormat.setMinimumFractionDigits(n); } /** * For calculating task timing. */ protected static double getComputationResult(APredictionResult result) { if ((result != null) && (result instanceof TimePredictionResult)) { return ((TimePredictionResult) result).getTaskTime(); } return TimePredictionResult.UNSET_TIME; } public static String getTaskApplicationCell(Project project, TaskApplication taskApp, CognitiveModelGenerator gen, boolean forCell, String withSecs) { if ((gen == null) || (taskApp == null) || ((! taskApp.hasComputedResult()) && (! taskApp.hasComputableScript())) || (taskApp.getScript(gen) == null)) { // Does not have a TaskApp or // has a TaskApp, but no Script for the current algorithm return ""; } Demonstration demo = taskApp.getDemonstration(); IPredictionAlgo alg = taskApp.determineActiveAlgorithm(project); APredictionResult r = taskApp.getResult(gen, alg); int resultState = (r == null) ? APredictionResult.NOT_COMPUTED : r.getResultState(); // "" means no task application or no computable script for algorithm // -- means the demo is valid and current, but not computed // (><) means result is being computed // NN means computed and the demonstration is valid and current // XX means the computation failed and the demo is valid and current // ?? means the demonstration is invalid or script needs regeneration if (forCell) { if (demo.isInvalid() || demo.isObsolete()) { return "?? "; } if ((resultState == APredictionResult.NOT_COMPUTED) || (alg.requiresDemonstration() && ! demo.isStartFrameChosen())) { // No result yet computed for the associated script return "-- "; } if (resultState == APredictionResult.COMPUTATION_IN_PROGRESS) { // Result is being computed return "(><) "; } if (resultState == APredictionResult.COMPUTE_FAILED) { // Has a result for this algorithm, but it failed return "XX "; } double timing = getComputationResult(r); if (timing < 0.0) { return "~~"; } updateDigits(); String result = cellNumberFormat.format(timing); if (CogToolPref.KLM_RESULT_RANGE.getBoolean() && withSecs != null && withSecs.length() > 0) { result += " (" + cellNumberFormat.format(0.9 * timing); result += ", " + cellNumberFormat.format(1.1 * timing); result += ")"; } result += withSecs; return result; // return (timing >= 0.0) //// ? (cellNumberFormat.format(timing) + withSecs) // ? (cellNumberFormat.format(timing) + withSecs + " \u00B110%") // : "~~"; } // Long form task application state descriptions, used for tooltips // "" means no task application or no computable script for alg // -- / "" means computable, not computed, and demo is valid // -- / X means not computed and demo is invalid // -- / ? means not computed and script needs regeneration // NN / "" means computed and demo is valid // NN / X means computed and demo is invalid // NN / ? means computed and script needs regeneration // ## / "" means computation failed and demo is valid // ## / X means computation failed and demo is invalid // ## / ? means computation failed, script needs regeneration // (><) / ... means result is being computed // ~~ / ... means result resulted in a negative number (??) String demoState; if (demo.isInvalid()) { demoState = " / INVALID"; // " / X "; } else if (demo.isObsolete()) { demoState = " / OBSOLETE"; // " / ? "; } else { demoState = ""; // " / "; } if ((resultState == APredictionResult.NOT_COMPUTED) || ! demo.isStartFrameChosen()) { // No result yet computed for the associated script return "NOT COMPUTED" /* "--" */ + demoState; } if (resultState == APredictionResult.COMPUTE_FAILED) { // Has a result for this algo, but it failed return "COMPUTE FAILED" /* "##" */ + demoState; } if (resultState == APredictionResult.COMPUTATION_IN_PROGRESS) { // Result is being computed return "BEING COMPUTED" /* "(><)" */ + demoState; } double timing = getComputationResult(r); updateDigits(); return (timing >= 0.0) ? (cellNumberFormat.format(timing) + withSecs + demoState) : ("~~" + demoState); } // getTaskApplicationCell /** * Recursively computes value of script results on a particular design * for tasks within a group. * * @param group the group whose resVal to calculate * @param d the design whose script results should be used here * @return the recursive value of script results on design d * for tasks in the given TaskGroup; -1.0 if the group is empty */ public static double computeGroup(Project project, TaskGroup group, Design d) { List<AUndertaking> children = group.getUndertakings(); if (children.size() == 0) { // trivial case return TimePredictionResult.UNSET_TIME; } GroupNature nature = group.getNature(); boolean validReturnValue = false; double returnValue = 0.0d; double meanDivisor = 0.0d; for (AUndertaking child : children) { double stepValue = TimePredictionResult.UNSET_TIME; if (child.isTaskGroup()) { // recursive (TaskGroup) case stepValue = computeGroup(project, (TaskGroup) child, d); } else { // terminal case TaskApplication ta = project.getTaskApplication(child, d); if (ta != null) { APredictionResult result = ta.getResult(ta.getFirstModelGenerator(), ta.determineActiveAlgorithm(project)); stepValue = getComputationResult(result); } } if ((nature == GroupNature.SUM) || (nature == GroupNature.MEAN)) { if (stepValue != TimePredictionResult.UNSET_TIME) { returnValue += stepValue; meanDivisor += 1.0d; validReturnValue = true; } } else if (nature == GroupNature.MIN) { if ((stepValue != TimePredictionResult.UNSET_TIME) && ((stepValue < returnValue) || (! validReturnValue))) { returnValue = stepValue; validReturnValue = true; } } else if (nature == GroupNature.MAX) { if (stepValue > returnValue) { returnValue = stepValue; validReturnValue = true; } } } if (validReturnValue) { if ((nature == GroupNature.MEAN) && (meanDivisor != 0.0d)) { returnValue /= meanDivisor; } return returnValue; } return TimePredictionResult.UNSET_TIME; } // computeGroup public static String[] getTaskRowStrings(Project project, AUndertaking undertaking, String withSecs) { return getTaskRowStrings(project, undertaking, withSecs, null); } public static String[] getTaskRowStrings(Project project, AUndertaking undertaking, String withSecs, int[] designOrder) { List<Design> projectDesigns = project.getDesigns(); // Add 1 since the initial column is not a design. String[] entries = new String[projectDesigns.size() + 1]; entries[0] = SWTStringUtil.insertEllipsis(undertaking.getName(), 300, StringUtil.EQUAL, SWTStringUtil.DEFAULT_FONT); Iterator<Design> designIter = projectDesigns.iterator(); int index = 1; // advance index to "First result" position if (undertaking.isTaskGroup()) { // TODO: Store group results instead of recomputing? TaskGroup group = (TaskGroup) undertaking; while (designIter.hasNext()) { Design d = designIter.next(); double result = computeGroup(project, group, d); updateDigits(); String formattedResult = (result == TimePredictionResult.UNSET_TIME) ? "?" : (cellNumberFormat.format(result) + withSecs); int entryIndex = (designOrder != null) ? designOrder[index++] : index++; entries[entryIndex] = group.getNature().toString() + ": " + formattedResult; } } else { while (designIter.hasNext()) { Design d = designIter.next(); TaskApplication ta = project.getTaskApplication(undertaking, d); int entryIndex = (designOrder != null) ? designOrder[index++] : index++; CognitiveModelGenerator gen = null; if (ta != null) { gen = ta.getFirstModelGenerator(); } entries[entryIndex] = getTaskApplicationCell(project, ta, gen, true, withSecs); } } return entries; } }