001/* An actor that applies a function over each element of a sequence. 002 003 Copyright (c) 2004-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.hoc; 029 030import java.util.Iterator; 031 032import ptolemy.actor.TypedAtomicActor; 033import ptolemy.actor.TypedIOPort; 034import ptolemy.actor.parameters.PortParameter; 035import ptolemy.actor.util.DFUtilities; 036import ptolemy.data.ArrayToken; 037import ptolemy.data.FunctionToken; 038import ptolemy.data.Token; 039import ptolemy.data.type.ArrayType; 040import ptolemy.data.type.FunctionType; 041import ptolemy.data.type.Type; 042import ptolemy.kernel.CompositeEntity; 043import ptolemy.kernel.util.IllegalActionException; 044import ptolemy.kernel.util.NameDuplicationException; 045 046/////////////////////////////////////////////////////////////////// 047//// ApplyFunctionOverSequence 048 049/** 050 Apply a function over one or more input sequences. 051 This actor will collect tokens from each input port into arrays 052 and, when enough input tokens have arrived, pass those arrays 053 to the function specified either at the <i>function</i> parameter 054 or the port. 055 <p> 056 To use this actor, create any number of input ports, add 057 a parameter named <i>tokenConsumptionRate</i> to each input 058 port, and set the value of this parameter to the number 059 of tokens that you would like to be collected into an 060 array for each function application. Also, create 061 and set a parameter named <i>tokenProductionRate</i> 062 in the output port. (If <i>tokenConsumptionRate</i> 063 or <i>tokenProductionRate</i> are not defined, then they 064 will be assumed to have value one). 065 Then define a function that takes as many array-valued 066 arguments as there are input ports and returns an 067 array-valued result. For example, the following function 068 will compute the FFT of the input array using the FFT() 069 function in the expression language: 070 <pre> 071 function(x:{double}) abs(FFT(x, 8)) 072 </pre> 073 Note that if the <i>tokenConsumptionRate</i> of a port is 074 changed during the execution of the model, the change is 075 ignored until the next execution of the model. 076 077 @author Steve Neuendorffer (Contributor: Edward A. Lee) 078 @deprecated Use SequenceToArray followed by ApplyFunction. 079 @version $Id$ 080 @since Ptolemy II 4.1 081 @Pt.ProposedRating Green (neuendor) 082 @Pt.AcceptedRating Yellow (neuendor) 083 @see ptolemy.actor.lib.hoc.ApplyFunction 084 */ 085@Deprecated 086public class ApplyFunctionOverSequence extends TypedAtomicActor { 087 /** Construct an actor with the given container and name. 088 * @param container The container. 089 * @param name The name of this actor. 090 * @exception IllegalActionException If the actor cannot be contained 091 * by the proposed container. 092 * @exception NameDuplicationException If the container already has an 093 * actor with this name. 094 */ 095 public ApplyFunctionOverSequence(CompositeEntity container, String name) 096 throws NameDuplicationException, IllegalActionException { 097 super(container, name); 098 output = new TypedIOPort(this, "output", false, true); 099 function = new PortParameter(this, "function"); 100 } 101 102 /////////////////////////////////////////////////////////////////// 103 //// public variables //// 104 105 /** The input port for function definition. The type of this port is 106 * undeclared, but to have this actor work, the designer has to provide 107 * a matched function token for it. 108 * Note: The reason that we don't declare the type for it is because 109 * currently there is not cast supported in the FunctionType class. 110 * we'll fix this later. 111 */ 112 public PortParameter function; 113 114 /** The output port. 115 */ 116 public TypedIOPort output; 117 118 /////////////////////////////////////////////////////////////////// 119 //// public methods //// 120 121 /** Consume the inputs, apply the function, and produce the result. 122 * @exception IllegalActionException If a runtime type error occurs. 123 */ 124 @Override 125 public void fire() throws IllegalActionException { 126 super.fire(); 127 128 // Update the function parameterPort. 129 function.update(); 130 131 FunctionToken functionValue = (FunctionToken) function.getToken(); 132 Token[] arguments = new Token[inputPortList().size() - 1]; 133 int i = 0; 134 Iterator ports = inputPortList().iterator(); 135 136 // Skip the function port. 137 ports.next(); 138 139 while (ports.hasNext()) { 140 TypedIOPort port = (TypedIOPort) ports.next(); 141 142 if (_rate[i] == -1) { 143 arguments[i] = port.get(0); 144 } else { 145 Token[] tokens = port.get(0, _rate[i]); 146 arguments[i] = new ArrayToken(port.getType(), tokens); 147 } 148 149 i++; 150 } 151 152 Token result = functionValue.apply(arguments); 153 154 if (_outputRate == -1) { 155 output.broadcast(result); 156 } else { 157 // FIXME: Check size. 158 ArrayToken resultArray = (ArrayToken) result; 159 output.broadcast(resultArray.arrayValue(), resultArray.length()); 160 } 161 } 162 163 /** Return true if the input ports have enough tokens. 164 * @exception IllegalActionException Not thrown in this base class. 165 */ 166 @Override 167 public boolean prefire() throws IllegalActionException { 168 super.prefire(); 169 170 Iterator ports = inputPortList().iterator(); 171 int i = 0; 172 173 // Skip the function port. 174 ports.next(); 175 176 while (ports.hasNext()) { 177 TypedIOPort port = (TypedIOPort) ports.next(); 178 179 if (_rate[i] == -1) { 180 if (!port.hasToken(0)) { 181 return false; 182 } 183 } else { 184 if (!port.hasToken(0, _rate[i])) { 185 return false; 186 } 187 } 188 } 189 190 return true; 191 } 192 193 /** Preinitialize the actor. Set the type of the ports based on 194 * the type of the function parameter. 195 */ 196 @Override 197 public void preinitialize() throws IllegalActionException { 198 super.preinitialize(); 199 200 FunctionType type = (FunctionType) function.getType(); 201 202 if (type.getReturnType() instanceof ArrayType) { 203 output.setTypeEquals( 204 ((ArrayType) type.getReturnType()).getElementType()); 205 _outputRate = DFUtilities.getTokenProductionRate(output); 206 } else { 207 output.setTypeEquals(type.getReturnType()); 208 _outputRate = -1; 209 } 210 211 int i = 0; 212 _rate = new int[inputPortList().size() - 1]; 213 214 Iterator ports = inputPortList().iterator(); 215 216 // Skip the function port. 217 ports.next(); 218 219 while (ports.hasNext()) { 220 TypedIOPort port = (TypedIOPort) ports.next(); 221 Type portType = type.getArgType(i); 222 223 if (portType instanceof ArrayType) { 224 port.setTypeEquals(((ArrayType) portType).getElementType()); 225 _rate[i] = DFUtilities.getTokenConsumptionRate(port); 226 } else { 227 port.setTypeEquals(portType); 228 _rate[i] = -1; 229 } 230 231 i++; 232 } 233 } 234 235 private int _outputRate; 236 237 private int[] _rate; 238}