001/* A polymorphic multiplier/divider.
002
003 Copyright (c) 1997-2015 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.Token;
033import ptolemy.kernel.CompositeEntity;
034import ptolemy.kernel.util.IllegalActionException;
035import ptolemy.kernel.util.NameDuplicationException;
036
037///////////////////////////////////////////////////////////////////
038//// MultiplyDivide
039
040/**
041
042 <p>A polymorphic multiplier and/or divider.  This adder has two input
043 ports, both of which are multiports, and one output port, which is
044 not.  The types on the ports are undeclared and will be resolved by
045 the type resolution mechanism. Data that arrives on the input port
046 named <i>multiply</i> will be multiplied, and data that arrives on
047 the input port named <i>divide</i> will be divided.  Any token type
048 supporting multiplication and division can be used.  In most
049 domains, either input port can be left unconnected.  Thus, to get a
050 simple multiplier (with no division), just leave the <i>divide</i>
051 input unconnected.
052 </p>
053 <p>
054 Currently, the type system is quite liberal about the resolved
055 types it will permit at the inputs. In particular, it may permit
056 the <i>multiply</i> and <i>divide</i> inputs to resolve to types
057 that cannot in fact be multiplied or divided.  In these cases, a
058 run-time error will occur.  In the future, we hope that the type
059 system will intercept such errors before run time.
060 </p>
061 <p>
062 This actor does not require that each input channel have a token
063 upon firing. It will multiply or divide available tokens at the
064 inputs and ignore the channels that do not have tokens.  It
065 consumes at most one input token from each port.  If no input
066 tokens are available on the <i>multiply</i> inputs, then a
067 numerator of one is assumed for the division operations.  The "one"
068 is obtained by calling the one() method of the first token seen at
069 the <i>divide</i> input.  If no input tokens are available at all,
070 then no output is produced.
071 </p>
072
073 @author Edward A. Lee
074 @version $Id$
075 @since Ptolemy II 0.3
076 @Pt.ProposedRating Green (eal)
077 @Pt.AcceptedRating Green (bilung)
078 */
079public class MultiplyDivide extends TypedAtomicActor {
080    /** Construct an actor in the specified container with the specified
081     *  name.
082     *  @param container The container.
083     *  @param name The name of this actor within the container.
084     *  @exception IllegalActionException If the actor cannot be contained
085     *   by the proposed container.
086     *  @exception NameDuplicationException If the name coincides with
087     *   an actor already in the container.
088     */
089    public MultiplyDivide(CompositeEntity container, String name)
090            throws IllegalActionException, NameDuplicationException {
091        super(container, name);
092        multiply = new TypedIOPort(this, "multiply", true, false);
093        multiply.setMultiport(true);
094        divide = new TypedIOPort(this, "divide", true, false);
095        divide.setMultiport(true);
096        output = new TypedIOPort(this, "output", false, true);
097        _attachText("_iconDescription", "<svg>\n" + "<rect x=\"-20\" y=\"-20\" "
098                + "width=\"40\" height=\"40\" " + "style=\"fill:white\"/>\n"
099                + "<line x1=\"-15\" y1=\"-15\" x2=\"-5\" y2=\"-5\"/>"
100                + "<line x1=\"-15\" y1=\"-5\" x2=\"-5\" y2=\"-15\"/>"
101                + "<line x1=\"-15\" y1=\"10\" x2=\"-5\" y2=\"10\"/>"
102                + "<circle cx=\"-10\" cy=\"6\" r=\"1\""
103                + "style=\"fill:black\"/>\n"
104                + "<circle cx=\"-10\" cy=\"14\" r=\"1\""
105                + "style=\"fill:black\"/>\n" + "</svg>\n");
106    }
107
108    ///////////////////////////////////////////////////////////////////
109    ////                     ports and parameters                  ////
110
111    /** Input for tokens to be divided.  This is a multiport, and its
112     *  type is inferred from the connections.
113     */
114    public TypedIOPort divide;
115
116    /** Output port.  The type is inferred from the connections.
117     */
118    public TypedIOPort output;
119
120    /** Input for tokens to be multiplied.  This is a multiport, and its
121     *  type is inferred from the connections.
122     */
123    public TypedIOPort multiply;
124
125    ///////////////////////////////////////////////////////////////////
126    ////                         public methods                    ////
127
128    /** If there is at least one token on the input ports, multiply
129     *  tokens from the <i>multiply</i> port, divide by tokens from
130     *  the <i>divide</i> port, and send the result to the output
131     *  port. At most one token is read from each channel, so if more
132     *  than one token is pending, the rest are left for future
133     *  firings.  If none of the input channels has a token, do
134     *  nothing.  If none of the multiply channels have tokens, then
135     *  the tokens on the divide channels are divided into a one token
136     *  of the same type as the denominator.
137     *
138     *  @exception IllegalActionException If there is no director,
139     *   or if multiplication and division are not supported by the
140     *   available tokens.
141     */
142    @Override
143    public void fire() throws IllegalActionException {
144        super.fire();
145        Token numerator = null;
146        try {
147            for (int i = 0; i < multiply.getWidth(); i++) {
148                if (multiply.hasToken(i)) {
149                    if (numerator == null) {
150                        numerator = multiply.get(i);
151                    } else {
152                        numerator = numerator.multiply(multiply.get(i));
153                    }
154                }
155            }
156
157            Token denominator = null;
158
159            for (int i = 0; i < divide.getWidth(); i++) {
160                if (divide.hasToken(i)) {
161                    if (denominator == null) {
162                        denominator = divide.get(i);
163                    } else {
164                        denominator = denominator.multiply(divide.get(i));
165                    }
166                }
167            }
168
169            if (numerator == null) {
170                if (denominator == null) {
171                    return;
172                }
173
174                // For the benefit of copernicus, this means that
175                // numerator always has the same type.
176                numerator = multiply.getType().convert(denominator.one());
177            }
178
179            if (denominator != null) {
180                numerator = numerator.divide(denominator);
181            }
182        } catch (Exception e) {
183            throw new IllegalActionException(this, e.getCause(),
184                    e.getMessage());
185        }
186
187        output.send(0, numerator);
188    }
189}