001/* Join matrices provided in sequence. 002 003 Copyright (c) 2007-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.data.IntToken; 031import ptolemy.data.MatrixToken; 032import ptolemy.data.expr.Parameter; 033import ptolemy.data.type.BaseType; 034import ptolemy.kernel.CompositeEntity; 035import ptolemy.kernel.util.Attribute; 036import ptolemy.kernel.util.IllegalActionException; 037import ptolemy.kernel.util.NameDuplicationException; 038 039/////////////////////////////////////////////////////////////////// 040//// MatrixJoin 041 042/** 043 This actor joins matrices into a single matrix by tiling. 044 It reads N*M input matrices from the input port, where N is 045 the value of the <i>rows</i> parameter, and M is 046 the value of the <i>columns</i> parameter. The matrices 047 read are arranged left-to-right, 048 top-to-bottom, in a raster scan pattern. 049 For example, if <i>rows</i> = <i>columns</i> = 2, then on 050 each firing, four matrices, A, B, C, D, will be read from 051 the input channel. Assuming A is the first one read, then 052 the output matrix will be a matrix arranged as follows: 053 <pre> 054 A B 055 C D 056 </pre> 057 The size of the output depends on the matrices in the top row 058 and left column. That is, in the above examples, the number of 059 columns in the output will equal the sum of the number of columns 060 in A and B. The number of rows will equal the sum of the number 061 of rows in A and C. The matrices are tiled in raster-scan order, 062 first A, then B, then C, and then D. Gaps are zero filled, 063 and overlaps are overwritten, where later matrices in the raster-scan 064 order overwrite earlier matrices. For example, if B has more rows 065 than A, then the bottom rows of B will be overwritten by rows of D. 066 <p> 067 068 @author Edward Lee 069 @version $Id$ 070 @since Ptolemy II 6.1 071 @Pt.ProposedRating Yellow (eal) 072 @Pt.AcceptedRating Red (neuendor) 073 */ 074public class MatrixJoin 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 MatrixJoin(CompositeEntity container, String name) 084 throws NameDuplicationException, IllegalActionException { 085 super(container, name); 086 087 // Set parameters. 088 columns = new Parameter(this, "columns"); 089 columns.setTypeEquals(BaseType.INT); 090 columns.setExpression("1"); 091 rows = new Parameter(this, "rows"); 092 rows.setTypeEquals(BaseType.INT); 093 rows.setExpression("1"); 094 095 input_tokenConsumptionRate.setExpression("rows * columns"); 096 } 097 098 /////////////////////////////////////////////////////////////////// 099 //// parameters //// 100 101 /** The number of matrices to arrange left to right on the output. 102 * This is an integer that defaults to 1. 103 */ 104 public Parameter columns; 105 106 /** The number of matrices to arrange top to bottom on the output. 107 * This is an integer that defaults to 1. 108 */ 109 public Parameter rows; 110 111 /////////////////////////////////////////////////////////////////// 112 //// public methods //// 113 114 /** Ensure that the rows and columns parameters are both positive. 115 * @param attribute The attribute that has changed. 116 * @exception IllegalActionException If the parameters are out of range. 117 */ 118 @Override 119 public void attributeChanged(Attribute attribute) 120 throws IllegalActionException { 121 if (attribute == columns) { 122 int columnsValue = ((IntToken) columns.getToken()).intValue(); 123 if (columnsValue <= 0) { 124 throw new IllegalActionException(this, 125 "Invalid number of columns: " + columnsValue); 126 } 127 } else if (attribute == rows) { 128 int rowsValue = ((IntToken) rows.getToken()).intValue(); 129 if (rowsValue <= 0) { 130 throw new IllegalActionException(this, 131 "Invalid number of rows: " + rowsValue); 132 } 133 } 134 super.attributeChanged(attribute); 135 } 136 137 /** Consume the inputs and produce the output matrix. 138 * @exception IllegalActionException If not enough tokens are available. 139 */ 140 @Override 141 public void fire() throws IllegalActionException { 142 super.fire(); 143 int numberOfColumns = ((IntToken) columns.getToken()).intValue(); 144 int numberOfRows = ((IntToken) rows.getToken()).intValue(); 145 MatrixToken[][] result = new MatrixToken[numberOfRows][numberOfColumns]; 146 for (int i = 0; i < numberOfRows; i++) { 147 for (int j = 0; j < numberOfColumns; j++) { 148 result[i][j] = (MatrixToken) input.get(0); 149 } 150 } 151 ; 152 output.send(0, result[0][0].join(result)); 153 } 154 155 /** Return true if each input channel has enough tokens for this actor to 156 * fire. The number of tokens required is the value of the <i>columns</i> parameter. 157 * @return boolean True if there are enough tokens at the input port 158 * for this actor to fire. 159 * @exception IllegalActionException If the hasToken() query to the 160 * input port throws it. 161 * @see ptolemy.actor.IOPort#hasToken(int, int) 162 */ 163 @Override 164 public boolean prefire() throws IllegalActionException { 165 int columnsValue = ((IntToken) columns.getToken()).intValue(); 166 int rowsValue = ((IntToken) rows.getToken()).intValue(); 167 if (!input.hasToken(0, rowsValue * columnsValue)) { 168 if (_debugging) { 169 _debug("Called prefire(), which returns false."); 170 } 171 return false; 172 } else { 173 return super.prefire(); 174 } 175 } 176}