001/* An actor that outputs the minimum 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//// Minimum
042
043/**
044 Read at most one token from each input channel and broadcast the one with the
045 least value to the <i>minimumValue</i> output.
046 In addition, broadcast the channel number of the minimum 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
050 is the one with the minimum 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 Minimum 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 Minimum(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        minimumValue = new TypedIOPort(this, "minimumValue", 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        minimumValue.setMultiport(true);
084        input.setTypeAtMost(BaseType.SCALAR);
085        minimumValue.setTypeAtLeast(input);
086        minimumValue.setDefaultWidth(1);
087
088        channelNumber = new TypedIOPort(this, "channelNumber", false, true);
089
090        /* Note that the output ports need not be multiports since all output
091         * channels carry the same data. Using multiports this way is not
092         * recommended, so please do not emulate this design in your own actors.
093         * Changing this actor to the recommended design would break existing
094         * models, so we leave it as is.
095         */
096        channelNumber.setMultiport(true);
097        channelNumber.setTypeEquals(BaseType.INT);
098        channelNumber.setDefaultWidth(1);
099    }
100
101    ///////////////////////////////////////////////////////////////////
102    ////                     ports and parameters                  ////
103
104    /** The input port.  This is required to be a scalar type.
105     */
106    public TypedIOPort input;
107
108    /** The output port for the minimum value. The type of this
109     *  output is constrained to be at least the type of the input.
110     */
111    public TypedIOPort minimumValue;
112
113    /** The output port for the channel number. The type of this
114     *  output is an integer.
115     */
116    public TypedIOPort channelNumber;
117
118    ///////////////////////////////////////////////////////////////////
119    ////                         public methods                    ////
120
121    /** Clone the actor into the specified workspace. This calls the
122     *  base class and then sets the type constraints.
123     *  @param workspace The workspace for the new object.
124     *  @return A new actor.
125     *  @exception CloneNotSupportedException If a derived class has
126     *   an attribute that cannot be cloned.
127     */
128    @Override
129    public Object clone(Workspace workspace) throws CloneNotSupportedException {
130        Minimum newObject = (Minimum) super.clone(workspace);
131        newObject.input.setTypeAtMost(BaseType.SCALAR);
132        newObject.minimumValue.setTypeAtLeast(newObject.input);
133        newObject.channelNumber.setTypeEquals(BaseType.INT);
134        return newObject;
135    }
136
137    /** Read at most one token from each input channel and send the one
138     *  with the least value to the output.  If there is no input, then
139     *  produce no output.
140     *  @exception IllegalActionException If there is no director.
141     */
142    @Override
143    public void fire() throws IllegalActionException {
144        super.fire();
145        ScalarToken result = null;
146        ScalarToken resultMagnitude = null;
147        ScalarToken inMagnitude = null;
148        int channelNum = -1;
149
150        for (int i = 0; i < input.getWidth(); i++) {
151            if (input.hasToken(i)) {
152                ScalarToken in = (ScalarToken) input.get(i);
153
154                if (in.getType().equals(BaseType.COMPLEX)) {
155                    // If we have a complex, we use the absolute value
156                    // for comparison, but save output the initial input
157                    // for output at the end.
158                    inMagnitude = in.absolute();
159                } else {
160                    inMagnitude = in;
161                }
162
163                if (result == null) {
164                    result = in;
165                    resultMagnitude = inMagnitude;
166                    channelNum = i;
167                } else {
168                    if (inMagnitude.isLessThan(resultMagnitude)
169                            .booleanValue() == true) {
170                        result = in;
171                        resultMagnitude = inMagnitude;
172                        channelNum = i;
173                    }
174                }
175            }
176        }
177
178        if (result != null) {
179            minimumValue.broadcast(result);
180            channelNumber.broadcast(new IntToken(channelNum));
181        }
182    }
183}