[kepler-dev] Re: [kepler-cvs] kepler/src/org/sdm/spa ArrayToSequence.java

Stephen Andrew Neuendorffer neuendor at eecs.berkeley.edu
Tue Jul 6 15:52:57 PDT 2004


There is always a tension between 'write a new actor' and 'cobble together 
existing actors'.
Without saying which is better, I'll show how you could have done this 
without writing any Java code:
I'll ignore the reset, to make it a little simpler and allow this to be 
built using SDF, instead of something more
complex.  Although it is sometimes a mindbend, building simple actors like 
this using dataflow can be
like a warmup exercise for building more complex dataflow models.

Accumulate is like a SampleDelay actor, in a feedback loop with an adder.

<relation name="relation" class="ptolemy.actor.TypedIORelation">
</relation>
<relation name="relation2" class="ptolemy.actor.TypedIORelation">
     <vertex name="vertex1" value="[285.0, 210.0]">
     </vertex>
</relation>
<entity name="AddSubtract" class="ptolemy.actor.lib.AddSubtract">
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[230.0, 210.0]">
     </property>
</entity>
<port name="port" class="ptolemy.actor.TypedIOPort">
     <property name="input"/>
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[140.0, 200.0]">
     </property>
</port>
<property name="SDF Director" class="ptolemy.domains.sdf.kernel.SDFDirector">
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[175.0, 145.0]">
     </property>
</property>
<relation name="relation4" class="ptolemy.actor.TypedIORelation">
     <vertex name="vertex1" value="[360.0, 275.0]">
     </vertex>
</relation>
<port name="port2" class="ptolemy.actor.TypedIOPort">
     <property name="output"/>
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[400.0, 210.0]">
     </property>
</port>
<entity name="SampleDelay" class="ptolemy.domains.sdf.lib.SampleDelay">
     <property name="_icon" class="ptolemy.vergil.icon.BoxedValueIcon">
         <property name="attributeName" 
class="ptolemy.kernel.util.StringAttribute" value="initialOutputs">
         </property>
         <property name="displayWidth" class="ptolemy.data.expr.Parameter" 
value="20">
         </property>
     </property>
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[315.0, 245.0]">
     </property>
</entity>
     <link port="port" relation="relation"/>
     <link port="port2" relation="relation2"/>
     <link port="AddSubtract.plus" relation="relation"/>
     <link port="AddSubtract.minus" relation="relation4"/>
     <link port="AddSubtract.output" relation="relation2"/>
     <link port="SampleDelay.input" relation="relation2"/>
     <link port="SampleDelay.output" relation="relation4"/>


Depending on where you tap the output, you will get either a first output 
of zero, or a first output equal to the first input.
If you tap in such a place where the first output is always zero (with the 
SampleDelay connected directly to the output port),
then SDF is smart enough to recognize this and output the zero during 
initialization.

<relation name="relation" class="ptolemy.actor.TypedIORelation">
</relation>
<relation name="relation2" class="ptolemy.actor.TypedIORelation">
     <vertex name="vertex1" value="[285.0, 210.0]">
     </vertex>
</relation>
<entity name="AddSubtract" class="ptolemy.actor.lib.AddSubtract">
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[230.0, 210.0]">
     </property>
</entity>
<property name="SDF Director" class="ptolemy.domains.sdf.kernel.SDFDirector">
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[175.0, 145.0]">
     </property>
</property>
<port name="port" class="ptolemy.actor.TypedIOPort">
     <property name="input"/>
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[140.0, 200.0]">
     </property>
</port>
<relation name="relation4" class="ptolemy.actor.TypedIORelation">
     <vertex name="vertex1" value="[360.0, 275.0]">
     </vertex>
</relation>
<port name="port2" class="ptolemy.actor.TypedIOPort">
     <property name="output"/>
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[400.0, 275.0]">
     </property>
</port>
<entity name="SampleDelay" class="ptolemy.domains.sdf.lib.SampleDelay">
     <property name="_icon" class="ptolemy.vergil.icon.BoxedValueIcon">
         <property name="attributeName" 
class="ptolemy.kernel.util.StringAttribute" value="initialOutputs">
         </property>
         <property name="displayWidth" class="ptolemy.data.expr.Parameter" 
value="20">
         </property>
     </property>
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[315.0, 245.0]">
     </property>
</entity>
     <link port="port" relation="relation"/>
     <link port="port2" relation="relation4"/>
     <link port="AddSubtract.plus" relation="relation"/>
     <link port="AddSubtract.minus" relation="relation4"/>
     <link port="AddSubtract.output" relation="relation2"/>
     <link port="SampleDelay.input" relation="relation2"/>
     <link port="SampleDelay.output" relation="relation4"/>

Interestingly enough, if you take an Accumulate actor and feed it's output 
into a SampleDelay, then the first output will
always be zero, and it will break feedback loops!  This is behaviorally 
identical as the previous example, at the expense of duplication of state.
This is a form of what is called retiming in the hardware design world.

<relation name="relation" class="ptolemy.actor.TypedIORelation">
</relation>
<relation name="relation2" class="ptolemy.actor.TypedIORelation">
     <vertex name="vertex1" value="[285.0, 210.0]">
     </vertex>
</relation>
<relation name="relation3" class="ptolemy.actor.TypedIORelation">
</relation>
<entity name="AddSubtract" class="ptolemy.actor.lib.AddSubtract">
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[230.0, 210.0]">
     </property>
</entity>
<port name="port" class="ptolemy.actor.TypedIOPort">
     <property name="input"/>
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[140.0, 200.0]">
     </property>
</port>
<property name="SDF Director" class="ptolemy.domains.sdf.kernel.SDFDirector">
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[175.0, 145.0]">
     </property>
</property>
<relation name="relation4" class="ptolemy.actor.TypedIORelation">
     <vertex name="vertex1" value="[360.0, 275.0]">
     </vertex>
</relation>
<entity name="SampleDelay2" class="ptolemy.domains.sdf.lib.SampleDelay">
     <property name="_icon" class="ptolemy.vergil.icon.BoxedValueIcon">
         <property name="attributeName" 
class="ptolemy.kernel.util.StringAttribute" value="initialOutputs">
         </property>
         <property name="displayWidth" class="ptolemy.data.expr.Parameter" 
value="20">
         </property>
     </property>
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[415.0, 210.0]">
     </property>
</entity>
<port name="port2" class="ptolemy.actor.TypedIOPort">
     <property name="output"/>
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[500.0, 210.0]">
     </property>
</port>
<entity name="SampleDelay" class="ptolemy.domains.sdf.lib.SampleDelay">
     <property name="_icon" class="ptolemy.vergil.icon.BoxedValueIcon">
         <property name="attributeName" 
class="ptolemy.kernel.util.StringAttribute" value="initialOutputs">
         </property>
         <property name="displayWidth" class="ptolemy.data.expr.Parameter" 
value="20">
         </property>
     </property>
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[315.0, 245.0]">
     </property>
</entity>
     <link port="port" relation="relation"/>
     <link port="port2" relation="relation3"/>
     <link port="AddSubtract.plus" relation="relation"/>
     <link port="AddSubtract.minus" relation="relation4"/>
     <link port="AddSubtract.output" relation="relation2"/>
     <link port="SampleDelay.input" relation="relation2"/>
     <link port="SampleDelay.output" relation="relation4"/>
     <link port="SampleDelay2.input" relation="relation2"/>
     <link port="SampleDelay2.output" relation="relation3"/>

As near as I can tell, you could implement your count actor as the 
following (disregarding the reset input, which makes it more 
complex...  Implementing reset could be done in an SR model)

<entity name="Const" class="ptolemy.actor.lib.Const">
     <doc>Create a constant sequence</doc>
     <property name="_icon" class="ptolemy.vergil.icon.BoxedValueIcon">
         <property name="attributeName" 
class="ptolemy.kernel.util.StringAttribute" value="value">
         </property>
         <property name="displayWidth" class="ptolemy.data.expr.Parameter" 
value="60">
         </property>
     </property>
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[210.0, 200.0]">
     </property>
</entity>
<relation name="relation" class="ptolemy.actor.TypedIORelation">
</relation>
<relation name="relation2" class="ptolemy.actor.TypedIORelation">
</relation>
<entity name="Accumulator" class="ptolemy.actor.lib.Accumulator">
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[305.0, 210.0]">
     </property>
</entity>
<relation name="relation3" class="ptolemy.actor.TypedIORelation">
</relation>
<relation name="relation4" class="ptolemy.actor.TypedIORelation">
</relation>
<property name="SDF Director" class="ptolemy.domains.sdf.kernel.SDFDirector">
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[175.0, 145.0]">
     </property>
</property>
<port name="port" class="ptolemy.actor.TypedIOPort">
     <property name="input"/>
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[140.0, 200.0]">
     </property>
</port>
<entity name="SampleDelay2" class="ptolemy.domains.sdf.lib.SampleDelay">
     <property name="_icon" class="ptolemy.vergil.icon.BoxedValueIcon">
         <property name="attributeName" 
class="ptolemy.kernel.util.StringAttribute" value="initialOutputs">
         </property>
         <property name="displayWidth" class="ptolemy.data.expr.Parameter" 
value="20">
         </property>
     </property>
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[385.0, 210.0]">
     </property>
</entity>
<port name="port2" class="ptolemy.actor.TypedIOPort">
     <property name="output"/>
     <property name="_location" class="ptolemy.kernel.util.Location" 
value="[470.0, 210.0]">
     </property>
</port>
     <link port="port" relation="relation"/>
     <link port="port2" relation="relation3"/>
     <link port="SampleDelay2.input" relation="relation4"/>
     <link port="SampleDelay2.output" relation="relation3"/>
     <link port="Const.output" relation="relation2"/>
     <link port="Const.trigger" relation="relation"/>
     <link port="Accumulator.input" relation="relation2"/>
     <link port="Accumulator.output" relation="relation4"/>


At 03:24 PM 7/6/2004, xiaowen wrote:
>Hi Tobin,
>
>I'll freely admit that org.sdm.spa.Count is something of a hack.  Let me 
>explain what I want it to do, then ask for suggestions of how it could be 
>better implemented, whether with ptolemy.actors.lib.Accumulator instead or 
>using another method =)
>
>Inside the PIW workflow, there's a point where we want to select the first 
>two elements of a sequence that fit a certain criteria.  The general flow 
>goes like this:
>
>[sequence of tokens, outputted one by one]
>
>-->
>
>[Discard if we've already chosen two]
>
>-->
>
>[Discard if it doesn't fit other criteria]
>
>-->
>
>[Update count if the token passes]
>
>
>This process takes place for multiple sets of sequences.
>
>
>Because of this, we need an actor that's capable of keeping track of a 
>count, and being able to reset the count when a new sequence starts.
>
>
>Let me trace through what org.sdm.spa.Count does at run time.
>
>When an element arrives to be processed, org.sdm.spa.Count outputs the 
>current count, whereupon a decision is made whether to discard the 
>token.  If the token isn't discarded, then it's submitted to further 
>actors that determine whether it fits other criteria.  At the end of this, 
>org.sdm.spa.Count is notified of whether the token passed, and if it did, 
>then the internal count is updated.
>
>We don't want the processing of the tokens to overlap because processing 
>one token to figure out whether it passes is fairly expensive in this 
>workflow.  So the workflow must wait until it knows whether the previous 
>token passed the test and the count has been updated before it starts 
>processing the next token.
>
>So there's a one-to-one correspondence between the output count tokens 
>sent by org.sdm.spa.Count and the input update tokens.  However, the 
>output token is sent _before_ it receives the input token.  And the 
>sending and receiving of them are kept synchronized so that a count is 
>_not_ sent out until it receives notification of the fate of the previous 
>token.  This is how the actor helps to ensure that the processing of one 
>element doesn't occur until we're done processing the previous 
>element.  Since we're operating in the PN domain, actors that expect a 
>count from org.sdm.spa.Count will hang until they receive it.
>
>Thus org.sdm.spa.Count serves a two-fold purpose:
>
>1. keep the count
>2. keep the synchronization
>
>
>ptolemy.actors.lib.Accumulator expects both the reset token and the input 
>token before it sends out an output token.  This is not interchangeable 
>with org.sdm.spa.Count because I need it to output a count _before_ it 
>receives the input token.  Perhaps the way to use 
>ptolemy.actor.lib.Accumulator would be to send it a token in the input 
>port when a sequence starts, and discard the last notification for each 
>sequence.  It would be a bit messy, but could work.  What do you think?
>
>
>Hopefully, I got the main idea across and why I needed this actor.  If 
>something's not clear please ask.  Also, will you please suggest 
>alternative ways of implementing this?
>
>
>Thanks!
>Xiaowen
>
>
>Tobin Fricke wrote:
>>On Fri, 2 Jul 2004, Stephen Andrew Neuendorffer wrote:
>>
>>>Out of curiosity: Why do you think you need this?
>>>An array in Ptolemy always has elements of the same type.
>>
>>Likewise, how does orb.sdm.spa.Count differ from
>>ptolemy.actors.lib.Accumulator?
>>I think the behavior that lead to org.sdm.apa.ArrayToSequence is similar
>>to the problem I have with my ObjectToRecord actor (described earlier).
>>It is "tempting" to circumvent the type system, but I'd rather not do
>>that.
>>Tobin
>>_______________________________________________
>>kepler-dev mailing list
>>kepler-dev at ecoinformatics.org
>>http://www.ecoinformatics.org/mailman/listinfo/kepler-dev
>
>_______________________________________________
>kepler-dev mailing list
>kepler-dev at ecoinformatics.org
>http://www.ecoinformatics.org/mailman/listinfo/kepler-dev





More information about the Kepler-dev mailing list