001/* Bundle a sequence of N by M input tokens into a matrix. 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.domains.sdf.lib; 029 030import ptolemy.actor.TypedIOPort; 031import ptolemy.data.IntToken; 032import ptolemy.data.MatrixToken; 033import ptolemy.data.Token; 034import ptolemy.data.expr.Parameter; 035import ptolemy.data.type.BaseType; 036import ptolemy.data.type.MatrixType; 037import ptolemy.data.type.MonotonicFunction; 038import ptolemy.data.type.Type; 039import ptolemy.graph.InequalityTerm; 040import ptolemy.kernel.CompositeEntity; 041import ptolemy.kernel.util.Attribute; 042import ptolemy.kernel.util.IllegalActionException; 043import ptolemy.kernel.util.NameDuplicationException; 044import ptolemy.kernel.util.Workspace; 045 046/////////////////////////////////////////////////////////////////// 047//// SequenceToMatrix 048 049/** 050 This actor bundles a specified number of input tokens into a matrix. 051 On each firing, it reads <i>rows</i> times <i>columns</i> input tokens 052 and writes one output matrix token with the specified number of rows 053 and columns. 054 This actor is polymorphic. It can accept inputs of any scalar type 055 that has a corresponding matrix type. 056 <p> 057 058 @author Edward Lee 059 @version $Id$ 060 @since Ptolemy II 0.4 061 @Pt.ProposedRating Yellow (eal) 062 @Pt.AcceptedRating Red (neuendor) 063 */ 064public class SequenceToMatrix extends SDFTransformer { 065 /** Construct an actor with the given container and name. 066 * @param container The container. 067 * @param name The name of this actor. 068 * @exception IllegalActionException If the actor cannot be contained 069 * by the proposed container. 070 * @exception NameDuplicationException If the container already has an 071 * actor with this name. 072 */ 073 public SequenceToMatrix(CompositeEntity container, String name) 074 throws NameDuplicationException, IllegalActionException { 075 super(container, name); 076 077 output.setTypeAtLeast(new FunctionTerm(input)); 078 079 // Set parameters. 080 rows = new Parameter(this, "rows"); 081 rows.setExpression("1"); 082 columns = new Parameter(this, "columns"); 083 columns.setExpression("1"); 084 085 input_tokenConsumptionRate.setExpression("rows * columns"); 086 087 // Set the icon. 088 _attachText("_iconDescription", 089 "<svg>\n" + "<polygon points=\"-15,-15 15,15 15,-15 -15,15\" " 090 + "style=\"fill:white\"/>\n" + "</svg>\n"); 091 } 092 093 /////////////////////////////////////////////////////////////////// 094 //// parameters //// 095 096 /** The number of rows in the output. This is an integer that defaults 097 * to 1. 098 */ 099 public Parameter rows; 100 101 /** The number of columns in the output. This is an integer that defaults 102 * to 1. 103 */ 104 public Parameter columns; 105 106 /////////////////////////////////////////////////////////////////// 107 //// public methods //// 108 109 /** Ensure that the rows and columns parameters are both positive. 110 * @param attribute The attribute that has changed. 111 * @exception IllegalActionException If the parameters are out of range. 112 */ 113 @Override 114 public void attributeChanged(Attribute attribute) 115 throws IllegalActionException { 116 if (attribute == rows) { 117 if (rows.getToken() != null) { 118 int rowsValue = ((IntToken) rows.getToken()).intValue(); 119 120 if (rowsValue <= 0) { 121 throw new IllegalActionException(this, 122 "Invalid number of rows: " + rowsValue); 123 } 124 } 125 } else if (attribute == columns) { 126 if (columns.getToken() != null) { 127 int columnsValue = ((IntToken) columns.getToken()).intValue(); 128 129 if (columnsValue <= 0) { 130 throw new IllegalActionException(this, 131 "Invalid number of columns: " + columnsValue); 132 } 133 } 134 } 135 136 super.attributeChanged(attribute); 137 } 138 139 /** Clone the actor into the specified workspace. This calls the 140 * base class and then sets the type constraints. 141 * @param workspace The workspace for the new object. 142 * @return A new actor. 143 * @exception CloneNotSupportedException If a derived class has 144 * an attribute that cannot be cloned. 145 */ 146 @Override 147 public Object clone(Workspace workspace) throws CloneNotSupportedException { 148 SequenceToMatrix newObject = (SequenceToMatrix) super.clone(workspace); 149 newObject.output.setTypeAtLeast(new FunctionTerm(newObject.input)); 150 return newObject; 151 } 152 153 /** Consume the inputs and produce the output matrix. 154 * @exception IllegalActionException If not enough tokens are available. 155 */ 156 @Override 157 public void fire() throws IllegalActionException { 158 super.fire(); 159 160 int rowsValue = ((IntToken) rows.getToken()).intValue(); 161 int columnsValue = ((IntToken) columns.getToken()).intValue(); 162 int length = rowsValue * columnsValue; 163 Token[] valueArray = input.get(0, length); 164 165 Token outputToken = MatrixToken.arrayToMatrix(input.getType(), 166 valueArray, rowsValue, columnsValue); 167 output.send(0, outputToken); 168 } 169 170 /** Return true if the input port has enough tokens for this actor to 171 * fire. The number of tokens required is the product of the 172 * values of the <i>rows</i> and <i>columns</i> parameters. 173 * @return boolean True if there are enough tokens at the input port 174 * for this actor to fire. 175 * @exception IllegalActionException If the hasToken() query to the 176 * input port throws it. 177 * @see ptolemy.actor.IOPort#hasToken(int, int) 178 */ 179 @Override 180 public boolean prefire() throws IllegalActionException { 181 int rowsValue = ((IntToken) rows.getToken()).intValue(); 182 int columnsValue = ((IntToken) columns.getToken()).intValue(); 183 int length = rowsValue * columnsValue; 184 185 if (!input.hasToken(0, length)) { 186 if (_debugging) { 187 _debug("Called prefire(), which returns false."); 188 } 189 190 return false; 191 } else { 192 return super.prefire(); 193 } 194 } 195 196 /////////////////////////////////////////////////////////////////// 197 //// inner classes //// 198 199 /** A monotonic function of the input port type. The result of the 200 * function is a matrix type with elements that are the same as 201 * the input type. If there is no such matrix type, then the 202 * result is unknown. 203 */ 204 private static class FunctionTerm extends MonotonicFunction { 205 206 // FindBugs suggests making this class static so as to decrease 207 // the size of instances and avoid dangling references. 208 209 /** The constructor takes a port argument so that the clone() 210 * method can construct an instance of this class for the 211 * input port on the clone. 212 * @param port The port 213 */ 214 private FunctionTerm(TypedIOPort port) { 215 _port = port; 216 } 217 218 /////////////////////////////////////////////////////////////// 219 //// public inner methods //// 220 221 /** Return the function result. 222 * @return A Type. 223 */ 224 @Override 225 public Object getValue() { 226 Type inputType = _port.getType(); 227 228 try { 229 return MatrixType.getMatrixTypeForElementType(inputType); 230 } catch (IllegalActionException ex) { 231 return BaseType.UNKNOWN; 232 } 233 } 234 235 /** Return the variables in this term. If the type of the input port 236 * is a variable, return a one element array containing the 237 * InequalityTerm of that port; otherwise, return an array of zero 238 * length. 239 * @return An array of InequalityTerm. 240 */ 241 @Override 242 public InequalityTerm[] getVariables() { 243 if (_port.getTypeTerm().isSettable()) { 244 InequalityTerm[] variable = new InequalityTerm[1]; 245 variable[0] = _port.getTypeTerm(); 246 return variable; 247 } else { 248 return new InequalityTerm[0]; 249 } 250 } 251 252 /////////////////////////////////////////////////////////////// 253 //// private inner variable //// 254 private TypedIOPort _port; 255 } 256}