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}