001/* An actor that outputs the maximum of all the inputs.
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.actor.lib;
029
030import ptolemy.actor.TypedAtomicActor;
031import ptolemy.actor.TypedIOPort;
032import ptolemy.data.IntToken;
033import ptolemy.data.ScalarToken;
034import ptolemy.data.type.BaseType;
035import ptolemy.kernel.CompositeEntity;
036import ptolemy.kernel.util.IllegalActionException;
037import ptolemy.kernel.util.NameDuplicationException;
038import ptolemy.kernel.util.Workspace;
039
040///////////////////////////////////////////////////////////////////
041//// Maximum
042
043/**
044 Read at most one token from each input channel and broadcast the one with the
045 greatest value to the <i>maximumValue</i> output.
046 In addition, broadcast the channel number of the maximum on
047 the <i>channelNumber</i> output port.  Either output port may be
048 left unconnected if you do not need its results.
049 This actor works with any scalar token. For ComplexToken, the output is
050 the one with the maximum magnitude.
051 The input port is a multiport.
052
053 @author Edward A. Lee
054 @version $Id$
055 @since Ptolemy II 0.3
056 @Pt.ProposedRating Yellow (eal)
057 @Pt.AcceptedRating Yellow (yuhong)
058 */
059public class Maximum extends TypedAtomicActor {
060    /** Construct an actor with the given container and name.
061     *  @param container The container.
062     *  @param name The name of this actor.
063     *  @exception IllegalActionException If the actor cannot be contained
064     *   by the proposed container.
065     *  @exception NameDuplicationException If the container already has an
066     *   actor with this name.
067     */
068    public Maximum(CompositeEntity container, String name)
069            throws NameDuplicationException, IllegalActionException {
070        super(container, name);
071
072        input = new TypedIOPort(this, "input", true, false);
073        input.setMultiport(true);
074
075        maximumValue = new TypedIOPort(this, "maximumValue", false, true);
076
077        /* Note that the output ports need not be multiports since all output
078         * channels carry the same data. Using multiports this way is not
079         * recommended, so please do not emulate this design in your own actors.
080         * Changing this actor to the recommended design would break existing
081         * models, so we leave it as is.
082         */
083        maximumValue.setMultiport(true);
084
085        maximumValue.setTypeAtLeast(input);
086        maximumValue.setDefaultWidth(1);
087
088        input.setTypeAtMost(BaseType.SCALAR);
089
090        channelNumber = new TypedIOPort(this, "channelNumber", false, true);
091
092        /* Note that the output ports need not be multiports since all output
093         * channels carry the same data. Using multiports this way is not
094         * recommended, so please do not emulate this design in your own actors.
095         * Changing this actor to the recommended design would break existing
096         * models, so we leave it as is.
097         */
098        channelNumber.setMultiport(true);
099        channelNumber.setTypeEquals(BaseType.INT);
100        channelNumber.setDefaultWidth(1);
101    }
102
103    ///////////////////////////////////////////////////////////////////
104    ////                     ports and parameters                  ////
105
106    /** The input port.  This is required to be a scalar type.
107     */
108    public TypedIOPort input;
109
110    /** The output port for the maximum value.
111     */
112    public TypedIOPort maximumValue;
113
114    /** The output port for the channel number. The type of this
115     *  output is an integer.
116     */
117    public TypedIOPort channelNumber;
118
119    ///////////////////////////////////////////////////////////////////
120    ////                         public methods                    ////
121
122    /** Clone the actor into the specified workspace. This calls the
123     *  base class and then sets the type constraints.
124     *  @param workspace The workspace for the new object.
125     *  @return A new actor.
126     *  @exception CloneNotSupportedException If a derived class has
127     *   an attribute that cannot be cloned.
128     */
129    @Override
130    public Object clone(Workspace workspace) throws CloneNotSupportedException {
131        Maximum newObject = (Maximum) super.clone(workspace);
132        newObject.input.setTypeAtMost(BaseType.SCALAR);
133        newObject.maximumValue.setTypeAtLeast(newObject.input);
134        newObject.channelNumber.setTypeEquals(BaseType.INT);
135        return newObject;
136    }
137
138    /** Read at most one token from each input channel and broadcast the one
139     *  with the largest value to the <i>maximumValue</i>output.
140     *  In addition, broadcast its channel number to the <i>channelNumber</i>
141     *  output.  If there is no input, then produce no output.
142     *  @exception IllegalActionException If there is no director.
143     */
144    @Override
145    public void fire() throws IllegalActionException {
146        super.fire();
147        ScalarToken result = null;
148        ScalarToken resultMagnitude = null;
149        ScalarToken inMagnitude = null;
150        int channelNum = -1;
151
152        for (int i = 0; i < input.getWidth(); i++) {
153            if (input.hasToken(i)) {
154                ScalarToken in = (ScalarToken) input.get(i);
155
156                if (in.getType().equals(BaseType.COMPLEX)) {
157                    // If we have a complex, we use the absolute value
158                    // for comparison, but save output the initial input
159                    // for output at the end.
160                    inMagnitude = in.absolute();
161                } else {
162                    inMagnitude = in;
163                }
164
165                if (result == null) {
166                    result = in;
167                    resultMagnitude = inMagnitude;
168                    channelNum = i;
169                } else {
170                    if (inMagnitude.isGreaterThan(resultMagnitude)
171                            .booleanValue() == true) {
172                        result = in;
173                        resultMagnitude = inMagnitude;
174                        channelNum = i;
175                    }
176                }
177            }
178        }
179
180        if (result != null) {
181            maximumValue.broadcast(result);
182            channelNumber.broadcast(new IntToken(channelNum));
183        }
184    }
185}