001/* A Slicer, which functions as a decoder of the LineCoder
002 of complex type.
003
004 Copyright (c) 2003-2014 The Regents of the University of California.
005 All rights reserved.
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the above
009 copyright notice and the following two paragraphs appear in all copies
010 of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024
025 PT_COPYRIGHT_VERSION_2
026 COPYRIGHTENDKEY
027
028 */
029package ptolemy.actor.lib.comm;
030
031import ptolemy.actor.lib.Transformer;
032import ptolemy.data.ArrayToken;
033import ptolemy.data.BooleanToken;
034import ptolemy.data.ComplexToken;
035import ptolemy.data.IntToken;
036import ptolemy.data.expr.Parameter;
037import ptolemy.data.type.ArrayType;
038import ptolemy.data.type.BaseType;
039import ptolemy.kernel.CompositeEntity;
040import ptolemy.kernel.util.IllegalActionException;
041import ptolemy.kernel.util.NameDuplicationException;
042import ptolemy.kernel.util.Workspace;
043import ptolemy.math.Complex;
044
045///////////////////////////////////////////////////////////////////
046//// Slicer
047
048/**
049 The Slicer functions as a decoder of the LineCoder. The parameter
050 <i>table</i> and <i>wordLength</i> has the same meaning as in LineCoder,
051 except that the type of <i>table</i> is constrained to an ArrayToken
052 of complex numbers. On each firing, the Slicer consumes one complex
053 token from its input port and computes the Euclidean distance between
054 the input data and the elements in the Slicer. The actor produces
055 <i>wordLength</i> booleans on each firing. The values of these booleans
056 correspond to the index of the entry that minimizes the distance. For
057 example, if the first entry minimizes the distance, then all of these
058 values are <i>false</i>. If the second entry minimizes the distance,
059 then only the first boolean is true.
060
061 @author Ye Zhou
062 @version $Id$
063 @since Ptolemy II 4.0
064 @Pt.ProposedRating Red (zhouye)
065 @Pt.AcceptedRating Red (cxh)
066 */
067public class Slicer extends Transformer {
068    /** Construct an actor with the given container and name.
069     *  @param container The container.
070     *  @param name The name of this actor.
071     *  @exception IllegalActionException If the actor cannot be contained
072     *   by the proposed container.
073     *  @exception NameDuplicationException If the container already has an
074     *   actor with this name.
075     */
076    public Slicer(CompositeEntity container, String name)
077            throws NameDuplicationException, IllegalActionException {
078        super(container, name);
079
080        input.setTypeEquals(BaseType.COMPLEX);
081        new Parameter(input, "tokenConsumptionRate", new IntToken(1));
082        output.setTypeEquals(BaseType.BOOLEAN);
083        _outputRate = new Parameter(output, "tokenProductionRate",
084                new IntToken(1));
085
086        table = new Parameter(this, "table");
087        table.setTypeEquals(new ArrayType(BaseType.COMPLEX));
088        table.setExpression("{-1.0, 1.0}");
089
090        //attributeChanged(table);
091        wordLength = new Parameter(this, "wordLength", new IntToken(1));
092        wordLength.setTypeEquals(BaseType.INT);
093    }
094
095    ///////////////////////////////////////////////////////////////////
096    ////                         public variables                  ////
097
098    /** The code table.  It is an array token of complex type.
099     *  The number of values in this array must be at least
100     *  2<sup><i>wordLength</i></sup>, or an exception
101     *  will be thrown. Its default value is {-1.0, 1.0}.
102     */
103    public Parameter table;
104
105    /** The word length is the number of boolean output that
106     *  are produced on each firing.  Its value is an IntToken,
107     *  with default value one.
108     */
109    public Parameter wordLength;
110
111    ///////////////////////////////////////////////////////////////////
112    ////                         public methods                    ////
113
114    /** Clone the actor into the specified workspace.
115     *  @param workspace The workspace for the new object.
116     *  @return A new actor.
117     *  @exception CloneNotSupportedException If a derived class contains
118     *   an attribute that cannot be cloned.
119     */
120    @Override
121    public Object clone(Workspace workspace) throws CloneNotSupportedException {
122        Slicer newObject = (Slicer) super.clone(workspace);
123
124        newObject._outputRate = (Parameter) newObject
125                .getAttribute("_outputRate");
126        return newObject;
127    }
128
129    /** Consume the inputs and produce the corresponding symbol.
130     *  @exception IllegalActionException If a runtime type error occurs.
131     */
132    @Override
133    public void fire() throws IllegalActionException {
134        super.fire();
135
136        ComplexToken inputToken = (ComplexToken) input.get(0);
137        int index = 0;
138        double distance = _computeEuclideanDistance(_table[0],
139                inputToken.complexValue());
140
141        for (int i = 1; i < _size; i++) {
142            double tempDistance = _computeEuclideanDistance(_table[i],
143                    inputToken.complexValue());
144
145            if (tempDistance < distance) {
146                index = i;
147                distance = tempDistance;
148            }
149        }
150
151        BooleanToken[] result = new BooleanToken[_wordLength];
152
153        for (int i = 0; i < _wordLength; i++) {
154            result[i] = new BooleanToken((index & 1) == 1);
155            index = index >> 1;
156        }
157
158        output.broadcast(result, _wordLength);
159    }
160
161    /** Set up the production constant.
162     *  @exception IllegalActionException If the length of the table is not
163     *   a power of two.
164     */
165    @Override
166    public void preinitialize() throws IllegalActionException {
167        super.preinitialize();
168
169        // FIXME: Handle mutations.
170        _wordLength = ((IntToken) wordLength.getToken()).intValue();
171        _outputRate.setToken(new IntToken(_wordLength));
172
173        ArrayToken tableToken = (ArrayToken) table.getToken();
174        _size = 1 << _wordLength;
175
176        if (tableToken.length() < _size) {
177            /*
178             throw new IllegalActionException(this, "Table parameter must " +
179             "have at least " + _size + " entries, but only has " +
180             tableToken.length());
181             */
182            _size = tableToken.length();
183        }
184
185        _table = new Complex[_size];
186
187        for (int i = 0; i < _size; i++) {
188            _table[i] = ((ComplexToken) tableToken.getElement(i))
189                    .complexValue();
190        }
191    }
192
193    /** Compute the Euclidean distance between two complex numbers.
194     *  @param x The first complex number.
195     *  @param y The second complex number.
196     *  @return The distance.
197     */
198    private double _computeEuclideanDistance(Complex x, Complex y) {
199        Complex z = x.subtract(y);
200        return z.magnitude();
201    }
202
203    ///////////////////////////////////////////////////////////////////
204    ////                         private variables                 ////
205    // Local cache of these parameter values.
206    private int _wordLength;
207
208    private int _size;
209
210    private Complex[] _table;
211
212    // Production rate of the output port.
213    private Parameter _outputRate;
214}