001/* Read ArrayTokens and send their elements to the output. 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 java.util.HashSet; 031import java.util.Set; 032 033import ptolemy.actor.util.ArrayOfTypesFunction; 034import ptolemy.data.ArrayToken; 035import ptolemy.data.BooleanToken; 036import ptolemy.data.IntToken; 037import ptolemy.data.Token; 038import ptolemy.data.expr.Parameter; 039import ptolemy.data.type.ArrayType; 040import ptolemy.data.type.BaseType; 041import ptolemy.graph.Inequality; 042import ptolemy.kernel.CompositeEntity; 043import ptolemy.kernel.util.Attribute; 044import ptolemy.kernel.util.IllegalActionException; 045import ptolemy.kernel.util.InternalErrorException; 046import ptolemy.kernel.util.NameDuplicationException; 047import ptolemy.kernel.util.Workspace; 048 049/////////////////////////////////////////////////////////////////// 050//// ArrayToSequence 051 052/** 053 <p>This actor reads an array at the input and writes the array elements 054 as a sequence to the output. The parameter <i>arrayLength</i> can be 055 used to specify the length of arrays that the actor will accept. 056 If the <i>enforceArrayLength</i> parameter true, then if an input 057 array does not match <i>arrayLength</i>, the fire() method will throw 058 an exception. This feature is important in domains, such as SDF, 059 that do static scheduling based on production and consumption 060 rates. For other domains, such as DE and PN, the <i>enforceArrayLength</i> 061 parameter can be set to false, in which case the <i>arrayLength</i> 062 parameter will be ignored.</p> 063 <p> 064 This actor is polymorphic. It can accept ArrayTokens with any element 065 type and send out tokens corresponding to that type. 066 </p> 067 068 @author Yuhong Xiong, Marten Lohstroh 069 @version $Id$ 070 @since Ptolemy II 0.4 071 @Pt.ProposedRating Yellow (yuhong) 072 @Pt.AcceptedRating Yellow (neuendor) 073 */ 074public class ArrayToSequence extends SDFTransformer { 075 /** Construct an actor with the given container and name. 076 * @param container The container. 077 * @param name The name of this actor. 078 * @exception IllegalActionException If the actor cannot be contained 079 * by the proposed container. 080 * @exception NameDuplicationException If the container already has an 081 * actor with this name. 082 */ 083 public ArrayToSequence(CompositeEntity container, String name) 084 throws NameDuplicationException, IllegalActionException { 085 super(container, name); 086 087 // Set type constraints. 088 output.setTypeAtLeast(ArrayType.elementType(input)); 089 090 // Set parameters. 091 arrayLength = new Parameter(this, "arrayLength"); 092 arrayLength.setExpression("1"); 093 enforceArrayLength = new Parameter(this, "enforceArrayLength"); 094 enforceArrayLength.setExpression("true"); 095 enforceArrayLength.setTypeEquals(BaseType.BOOLEAN); 096 097 output_tokenProductionRate.setExpression("arrayLength"); 098 099 // Set the icon. 100 _attachText("_iconDescription", 101 "<svg>\n" + "<polygon points=\"-15,-15 15,15 15,-15 -15,15\" " 102 + "style=\"fill:white\"/>\n" + "</svg>\n"); 103 } 104 105 /////////////////////////////////////////////////////////////////// 106 //// parameters //// 107 108 /** The size of the input array. This is an integer that defaults 109 * to 1. 110 */ 111 public Parameter arrayLength; 112 113 /** If true, then enforce the <i>arrayLength</i> parameter by 114 * throwing an exception if it is violated. This is a boolean 115 * that defaults to true. 116 */ 117 public Parameter enforceArrayLength; 118 119 /////////////////////////////////////////////////////////////////// 120 //// public methods //// 121 122 /** If the argument is the <i>arrayLength</i> parameter, then 123 * check to make sure its value is not negative. 124 * @param attribute The attribute that has changed. 125 * @exception IllegalActionException If the parameters are out of range. 126 */ 127 @Override 128 public void attributeChanged(Attribute attribute) 129 throws IllegalActionException { 130 if (attribute == arrayLength) { 131 int rate = ((IntToken) arrayLength.getToken()).intValue(); 132 133 if (rate < 0) { 134 throw new IllegalActionException(this, 135 "Invalid arrayLength: " + rate); 136 } 137 } else { 138 super.attributeChanged(attribute); 139 } 140 } 141 142 /** Clone the actor into the specified workspace. This calls the 143 * base class and then creates new ports and parameters. 144 * @param workspace The workspace for the new object. 145 * @return A new actor. 146 * @exception CloneNotSupportedException If a derived class contains 147 * an attribute that cannot be cloned. 148 */ 149 @Override 150 public Object clone(Workspace workspace) throws CloneNotSupportedException { 151 ArrayToSequence newObject = (ArrayToSequence) super.clone(workspace); 152 try { 153 newObject.output 154 .setTypeAtLeast(ArrayType.elementType(newObject.input)); 155 } catch (IllegalActionException e) { 156 throw new InternalErrorException(e); 157 } 158 return newObject; 159 } 160 161 /** Consume the input ArrayToken and produce the outputs. 162 * @exception IllegalActionException If a runtime type conflict occurs. 163 */ 164 @Override 165 public void fire() throws IllegalActionException { 166 super.fire(); 167 168 ArrayToken token = (ArrayToken) input.get(0); 169 int rate = ((IntToken) arrayLength.getToken()).intValue(); 170 boolean enforce = ((BooleanToken) enforceArrayLength.getToken()) 171 .booleanValue(); 172 173 if (enforce && token.length() != rate) { 174 throw new IllegalActionException(this, 175 "The " + "number of elements in the input ArrayToken (" 176 + token.length() 177 + ") is not the same as the arrayLength " 178 + "parameter (" + rate + ")."); 179 } 180 181 Token[] elements = token.arrayValue(); 182 183 // We no longer send the complete array all at once, since this might in 184 // for example PN lead to larger buffer sizes than strictly necessary. 185 // output.send(0, elements, elements.length); 186 187 for (Token newToken : elements) { 188 output.send(0, newToken); 189 } 190 } 191 192 /////////////////////////////////////////////////////////////////// 193 //// protected methods //// 194 195 /** Do not establish the usual default type constraints. Instead, the type 196 * of the output port is constrained to be no less than the type of the 197 * elements of the input array (set in the constructor of this class). 198 */ 199 @Override 200 protected Set<Inequality> _defaultTypeConstraints() { 201 return null; 202 } 203 204 /** Add a type constraint for backward type inference that forces 205 * the input to be an array of which the elements have a type 206 * greater than or equal to the output port. If the 207 * <i>enforceArrayLength</i> parameter is set to true, the input 208 * is also forced to have a length equal to the <i>arrayLength</i> 209 * parameter. 210 * If backward type inference is disabled, this method returns 211 * an empty set. 212 * @see ArrayOfTypesFunction 213 * @return A set of inequalities. 214 */ 215 @Override 216 protected Set<Inequality> _customTypeConstraints() { 217 Set<Inequality> result = new HashSet<Inequality>(); 218 219 if (isBackwardTypeInferenceEnabled()) { 220 try { 221 // constrain the input to be an array of a type greater 222 // than or equal to the type of the output (for backward 223 // type inference) 224 if (((BooleanToken) enforceArrayLength.getToken()) 225 .booleanValue()) { 226 result.add( 227 new Inequality( 228 new ArrayOfTypesFunction(output, 229 ((IntToken) arrayLength.getToken()) 230 .intValue()), 231 input.getTypeTerm())); 232 } else { 233 result.add(new Inequality(new ArrayOfTypesFunction(output), 234 input.getTypeTerm())); 235 } 236 237 } catch (IllegalActionException e) { 238 // this should not happen 239 e.printStackTrace(); 240 } 241 } 242 return result; 243 } 244 245}