001/* An actor that outputs the absolute value of the input. 002 003 Copyright (c) 1998-2014 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 027 */ 028package ptolemy.actor.lib; 029 030import ptolemy.actor.TypedIOPort; 031import ptolemy.data.ArrayToken; 032import ptolemy.data.ScalarToken; 033import ptolemy.data.Token; 034import ptolemy.data.type.ArrayType; 035import ptolemy.data.type.BaseType; 036import ptolemy.data.type.MonotonicFunction; 037import ptolemy.data.type.Type; 038import ptolemy.graph.InequalityTerm; 039import ptolemy.kernel.CompositeEntity; 040import ptolemy.kernel.util.IllegalActionException; 041import ptolemy.kernel.util.NameDuplicationException; 042import ptolemy.kernel.util.Workspace; 043 044/////////////////////////////////////////////////////////////////// 045//// AbsoluteValue 046 047/** 048 Produce an output token on each firing with a value that is 049 equal to the absolute value of the input. The input can have any 050 scalar type, or it can be an array of scalars (or an array of arrays 051 of scalars, etc.). If the input type is not Complex, the output has the 052 same type as the input. If the input type is Complex, the output 053 type is Double, in which case, the output value is the magnitude 054 of the input complex. 055 056 @author Edward A. Lee 057 @version $Id$ 058 @since Ptolemy II 0.3 059 @Pt.ProposedRating Yellow (eal) 060 @Pt.AcceptedRating Yellow (yuhong) 061 */ 062public class AbsoluteValue extends Transformer { 063 /** Construct an actor with the given container and name. 064 * @param container The container. 065 * @param name The name of this actor. 066 * @exception IllegalActionException If the actor cannot be contained 067 * by the proposed container. 068 * @exception NameDuplicationException If the container already has an 069 * actor with this name. 070 */ 071 public AbsoluteValue(CompositeEntity container, String name) 072 throws NameDuplicationException, IllegalActionException { 073 super(container, name); 074 075 output.setTypeAtLeast(new TypeOfAbsoluteValue(input)); 076 // FIXME: This actor accepts a rather complicated set 077 // of input types. Is there a way to express the constraints? 078 // input.setTypeAtMost(BaseType.SCALAR); 079 // Also, type constraints do not propagate backwards from 080 // the output to the input. 081 } 082 083 /////////////////////////////////////////////////////////////////// 084 //// public methods //// 085 086 /** Clone the actor into the specified workspace. This calls the 087 * base class and then sets the type constraints. 088 * @param workspace The workspace for the new object. 089 * @return A new actor. 090 * @exception CloneNotSupportedException If a derived class has 091 * an attribute that cannot be cloned. 092 */ 093 @Override 094 public Object clone(Workspace workspace) throws CloneNotSupportedException { 095 AbsoluteValue newObject = (AbsoluteValue) super.clone(workspace); 096 newObject.output 097 .setTypeAtLeast(new TypeOfAbsoluteValue(newObject.input)); 098 return newObject; 099 } 100 101 /** Compute the absolute value of the input. If there is no input, then 102 * produce no output. 103 * @exception IllegalActionException If there is no director. 104 */ 105 @Override 106 public void fire() throws IllegalActionException { 107 super.fire(); 108 if (input.hasToken(0)) { 109 output.send(0, _absoluteValue(input.get(0))); 110 } 111 } 112 113 /////////////////////////////////////////////////////////////////// 114 //// private methods //// 115 116 /** If the argument type is an array, then return an array 117 * type with element types recursively defined by this method. 118 * Otherwise, if the argument type is complex, then return 119 * double. Otherwise, return the argument type. 120 * @return The absolute value of the input. 121 * @exception IllegalActionException If there is no absolute value 122 * operation for the specified token. 123 */ 124 private Token _absoluteValue(Token input) throws IllegalActionException { 125 if (input instanceof ArrayToken) { 126 int length = ((ArrayToken) input).length(); 127 Token[] result = new Token[length]; 128 for (int i = 0; i < length; i++) { 129 result[i] = _absoluteValue(((ArrayToken) input).getElement(i)); 130 } 131 return new ArrayToken(result); 132 } else if (input instanceof ScalarToken) { 133 return ((ScalarToken) input).absolute(); 134 } else { 135 throw new IllegalActionException(this, 136 "AbsoluteValue only accepts scalar inputs or arrays of scalars."); 137 } 138 } 139 140 /////////////////////////////////////////////////////////////////// 141 //// inner classes //// 142 143 /** This class implements a monotonic function of the input port 144 * type. It returns the type of the absolute value of the input 145 * port type. If the input type is an array, then the function 146 * returns an array type with element types recursively defined 147 * by this same function. 148 * Otherwise, if the port type is complex, then return 149 * double. Otherwise, return the port 150 * type. 151 */ 152 private static class TypeOfAbsoluteValue extends MonotonicFunction { 153 154 // FindBugs suggested making this class a static inner class: 155 // 156 // "This class is an inner class, but does not use its embedded 157 // reference to the object which created it. This reference makes 158 // the instances of the class larger, and may keep the reference 159 // to the creator object alive longer than necessary. If 160 // possible, the class should be made into a static inner class." 161 162 // The constructor takes a port argument so that the clone() 163 // method can construct an instance of this class for the 164 // input port on the clone. 165 private TypeOfAbsoluteValue(TypedIOPort port) { 166 _port = port; 167 } 168 169 /////////////////////////////////////////////////////////////// 170 //// public inner methods //// 171 172 /** Return the function result. 173 * @return A Type. 174 */ 175 @Override 176 public Object getValue() { 177 return _outputType(_port.getType()); 178 } 179 180 /** Return the variables in this term. If the type of the input port 181 * is a variable, return a one element array containing the 182 * InequalityTerm of that port; otherwise, return an array of zero 183 * length. 184 * @return An array of InequalityTerm. 185 */ 186 @Override 187 public InequalityTerm[] getVariables() { 188 if (_port.getTypeTerm().isSettable()) { 189 InequalityTerm[] variable = new InequalityTerm[1]; 190 variable[0] = _port.getTypeTerm(); 191 return variable; 192 } else { 193 return new InequalityTerm[0]; 194 } 195 } 196 197 /////////////////////////////////////////////////////////////// 198 //// private inner methods //// 199 200 /** If the argument type is an array, then return an array 201 * type with element types recursively defined by this method. 202 * Otherwise, if the argument type is complex, then return 203 * double. Otherwise, return the argument type. 204 * @return A Type. 205 */ 206 private Type _outputType(Type inputType) { 207 if (inputType == BaseType.COMPLEX) { 208 return BaseType.DOUBLE; 209 } else if (inputType instanceof ArrayType) { 210 Type elementType = ((ArrayType) inputType).getElementType(); 211 return new ArrayType(_outputType(elementType)); 212 } else { 213 return inputType; 214 } 215 } 216 217 /////////////////////////////////////////////////////////////// 218 //// private inner variable //// 219 private TypedIOPort _port; 220 } 221}