001/* Output an initial token during initialize(), then pass through.
002
003 @Copyright (c) 1998-2015 The Regents of the University of California.
004 All rights reserved.
005
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
009 above copyright notice and the following two paragraphs appear in all
010 copies 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 */
028package ptolemy.domains.sdf.lib;
029
030import java.util.HashSet;
031import java.util.Set;
032
033import ptolemy.data.ArrayToken;
034import ptolemy.data.Token;
035import ptolemy.data.expr.Parameter;
036import ptolemy.data.type.ArrayType;
037import ptolemy.graph.Inequality;
038import ptolemy.kernel.CompositeEntity;
039import ptolemy.kernel.util.Attribute;
040import ptolemy.kernel.util.IllegalActionException;
041import ptolemy.kernel.util.InternalErrorException;
042import ptolemy.kernel.util.NameDuplicationException;
043import ptolemy.kernel.util.Workspace;
044
045///////////////////////////////////////////////////////////////////
046//// SampleDelay
047
048/**
049 This actor outputs a set of initial tokens during the initialize()
050 method, and subsequently passes the input tokens to the output.
051 It is used to break dependency cycles in directed loops of SDF models.
052 This actor declares an initial production parameter in its output port
053 that is used by the SDF scheduler to properly schedule the model, and
054 the initial outputs permit the computation to get started. The
055 default value for the <i>initialOutputs</i> parameter causes a
056 single integer token with value zero to be produced in
057 initialize().
058
059 @author Steve Neuendorffer, Edward A. Lee
060 @version $Id$
061 @since Ptolemy II 1.0
062 @Pt.ProposedRating Yellow (eal)
063 @Pt.AcceptedRating Yellow (neuendor)
064 */
065public class SampleDelay extends SDFTransformer {
066    /** Construct an actor with the given container and name.
067     *  @param container The container.
068     *  @param name The name of this actor.
069     *  @exception IllegalActionException If the actor cannot be contained
070     *   by the proposed container.
071     *  @exception NameDuplicationException If the container already has an
072     *   actor with this name.
073     */
074    public SampleDelay(CompositeEntity container, String name)
075            throws IllegalActionException, NameDuplicationException {
076        super(container, name);
077
078        initialOutputs = new Parameter(this, "initialOutputs");
079        initialOutputs.setExpression("{0}");
080        initialOutputs.setTypeAtLeast(ArrayType.ARRAY_BOTTOM);
081
082        output_tokenInitProduction.setExpression("initialOutputs.length()");
083
084        // set type constraints.
085        output.setTypeAtLeast(ArrayType.elementType(initialOutputs));
086        output.setTypeAtLeast(input);
087    }
088
089    ///////////////////////////////////////////////////////////////////
090    ////                     ports and parameters                  ////
091
092    /** The values that will be produced in the initialize method.
093     *  This parameter must contain an ArrayToken.
094     *  It defaults to contain a single zero-valued integer token.
095     *  Changes to this parameter after initialize() has been invoked
096     *  are ignored until the next execution of the model.
097     */
098    public Parameter initialOutputs;
099
100    ///////////////////////////////////////////////////////////////////
101    ////                         public methods                    ////
102
103    /** Override the base class to allow type changes on
104     *  <i>initialOutputs</i>.
105     *  @exception IllegalActionException If type changes are not
106     *   allowed on the specified attribute.
107     */
108    @Override
109    public void attributeTypeChanged(Attribute attribute)
110            throws IllegalActionException {
111        if (attribute != initialOutputs) {
112            super.attributeTypeChanged(attribute);
113        } else {
114            _typesValid = false; // Set flag to invalidate cached type constraints
115        }
116    }
117
118    /** Clone the actor into the specified workspace. This calls the
119     *  base class and then resets the type constraints.
120     *  @param workspace The workspace for the new object.
121     *  @return A new actor.
122     *  @exception CloneNotSupportedException If a derived class contains
123     *   an attribute that cannot be cloned.
124     */
125    @Override
126    public Object clone(Workspace workspace) throws CloneNotSupportedException {
127        SampleDelay newObject = (SampleDelay) super.clone(workspace);
128
129        // set the type constraints
130        try {
131            newObject.output.setTypeAtLeast(
132                    ArrayType.elementType(newObject.initialOutputs));
133        } catch (IllegalActionException e) {
134            throw new InternalErrorException(e);
135        }
136        newObject.output.setTypeAtLeast(newObject.input);
137
138        return newObject;
139    }
140
141    /** Read exactly one input token and send it to the output.
142     *  @exception IllegalActionException If the get() or send() methods
143     *   of the ports throw it.
144     */
145    @Override
146    public void fire() throws IllegalActionException {
147        super.fire();
148
149        Token message = input.get(0);
150        output.send(0, message);
151    }
152
153    /** Produce on the output a sequence tokens, one for each element
154     *  of the <i>initialOutputs</i> parameter (which is an array).
155     *  @exception IllegalActionException If the send() method
156     *   of the output port throws it.
157     */
158    @Override
159    public void initialize() throws IllegalActionException {
160        super.initialize();
161        output.send(0, _outputsArray.arrayValue(), _outputsArray.length());
162    }
163
164    /** Check that the <i>initialOutputs</i> parameter contains an
165     *  array token.  Set the <i>tokenInitProduction</i> parameter of
166     *  the output port to the length of the value of <i>initialOutputs</i>
167     *  Note that the value and type <i>initialOutputs</i> are observed
168     *  only here.  If the value or type change during execution
169     *  of the model, the change will not take effect until the next
170     *  execution.
171     *
172     *  @exception IllegalActionException If <i>initialOutputs</i> parameter
173     *   is invalid, or if the base class throws it.
174     */
175    @Override
176    public void preinitialize() throws IllegalActionException {
177        super.preinitialize();
178
179        Token contents = initialOutputs.getToken();
180
181        if (!(contents instanceof ArrayToken)) {
182            throw new IllegalActionException(this, "InitialOutputs was "
183                    + contents + " which is not an" + " array token.");
184        }
185
186        _outputsArray = (ArrayToken) contents;
187
188        getDirector().invalidateResolvedTypes();
189    }
190
191    /** Sets up backward type constraint that sets output &le; input
192     *  if backward type inference is enabled.
193     *  @return A set of Inequalities.
194     */
195    @Override
196    protected Set<Inequality> _customTypeConstraints() {
197        Set<Inequality> result = new HashSet<Inequality>();
198        if (isBackwardTypeInferenceEnabled()) {
199            result.add(
200                    new Inequality(output.getTypeTerm(), input.getTypeTerm()));
201        }
202        return result;
203    }
204
205    ///////////////////////////////////////////////////////////////////
206    ////                         private variables                 ////
207    // The outputs to be produced in the initialize method.
208    private ArrayToken _outputsArray;
209}