Skip to content

Commit ab96863

Browse files
committed
initial commit
0 parents  commit ab96863

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2465
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
__pycache__/
2+
models
3+
.vscode
4+
.noseids
5+
nosetests.xml

.gitlab-ci.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
build:
2+
tags:
3+
- Ubuntu1804-64bit
4+
script:
5+
- sudo apt-get -y update
6+
- sudo apt-get -y install python3-pip libcairo2-dev
7+
- cd /builds/mgeilen/cmtrace
8+
- bash ./ci/script/test.sh
9+
artifacts:
10+
expire_in: 14d
11+
when: always
12+
paths:
13+
- /builds/mgeilen/cmtrace/packages/cmtrace/cmtrace/test/output/

package/cmtrace/.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
build
2+
3+
# Compiled python modules.
4+
*.pyc
5+
6+
# Setuptools distribution folder.
7+
/dist/
8+
9+
# Python egg metadata, regenerated from source files by setuptools.
10+
/*.egg-info
11+
.eggs

package/cmtrace/MANIFEST.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
include example/trace.xml
2+
include example/settings.yaml

package/cmtrace/cmtrace/__init__.py

Whitespace-only changes.

package/cmtrace/cmtrace/dataflow/__init__.py

Whitespace-only changes.
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"""Class Actor Represents an actor in a dataflow graph"""
2+
3+
from cmtrace.dataflow.maxplus import mpplus, mpmax, mpmax2, trace, MPMINUSINF, output_sequence
4+
5+
class Actor:
6+
"""Represents an actor in a dataflow graph"""
7+
def __init__(self, name, actdelay, scenario=None):
8+
self.name = name
9+
self.delay = actdelay
10+
self.inputs = dict()
11+
self.primary_inputs = []
12+
self.state_inputs = dict()
13+
self.firings = []
14+
self.scenario = scenario
15+
16+
def add_channel_input(self, actor, initial_tokens=0, arcdelay=0, initial_time=MPMINUSINF):
17+
"""add a channel input dependency to another actor, including
18+
a time-offset arcdelay"""
19+
self.inputs[actor.name] = (actor, initial_tokens, arcdelay, initial_time)
20+
21+
def add_state_input(self, state, tokendelay=0, arcdelay=0):
22+
"""Add a dependency on a state token for an SADF graph"""
23+
self.state_inputs[state.name] = (state, tokendelay, arcdelay)
24+
return
25+
26+
def add_primary_input(self, priminput):
27+
"""Add dependency to a primary input to the graph."""
28+
self.primary_inputs.append(priminput)
29+
30+
def completions(self):
31+
"""returns the current completion times of the actor"""
32+
# add the actor delay to the firing times
33+
return mpplus(self.firings, self.delay)
34+
35+
def firing_intervals(self):
36+
""" Return a list of (start,end) pairs for all firings """
37+
return [(f, f+self.delay) for f in self.firings]
38+
39+
def update_firings(self):
40+
"""Recomput the firings of the actor based on its input dependencies.
41+
Returns a boolean indicating if the computed firings remained the same."""
42+
oldfirings = len(self.firings)
43+
traces = []
44+
# collect all the incoming channels
45+
for i, (act, tok, arcdel, tokinit) in self.inputs.items():
46+
traces.append(output_sequence(act.completions(), tok, arcdel, tokinit))
47+
# collect traces for all primary inputs
48+
for i in self.primary_inputs:
49+
traces.append(i)
50+
if len(traces) == 0:
51+
raise Exception("Actor must have inputs")
52+
53+
# determine the firings
54+
self.firings = mpmax(*traces)
55+
return oldfirings == len(self.firings)
56+
57+
def set_scenario(self, scenario):
58+
"""set the scenario in which the actor is active"""
59+
self.scenario = scenario
60+
61+
def update_firings_sadf(self, scen_seq):
62+
"""Recomput the firings of the SADF actor based on its input dependencies.
63+
Returns a boolean indicating if the computed firings remained the same."""
64+
# update the actor firings
65+
oldfirings = len(self.firings)
66+
67+
# primary inputs
68+
# assume for the moment that primary inputs are active in only one scenario!
69+
# hack to deal with absence of primary inputs. Should be an infinitely
70+
# long sequence of minus inf.
71+
if len(self.primary_inputs) > 0:
72+
self.firings = mpmax(*self.primary_inputs)
73+
else:
74+
self.firings = [MPMINUSINF] * len(scen_seq)
75+
76+
# state_inputs
77+
for _, (state, tokdel, arcdel) in self.state_inputs.items():
78+
if self.scenario is None:
79+
raise Exception("SADF actor has no scenario.")
80+
splicedfirings = state.spliced_firings(scen_seq, self.scenario, tokdel)
81+
self.firings = mpmax2(self.firings, mpplus(splicedfirings, arcdel))
82+
83+
# channel inputs
84+
for _, (act, tok, arcdel, tokinit) in self.inputs.items():
85+
self.firings = mpmax2(self.firings, output_sequence(act.completions(), tok, arcdel, tokinit))
86+
87+
return oldfirings == len(self.firings)
88+
89+
90+
def get_trace(self, tracelength):
91+
"""Get a string representation of the actor's execution trace."""
92+
return trace(self.firings, self.delay, tracelength)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""Implements the denotational semantics of open datflow models."""
2+
3+
def compute_fixpoint(actors):
4+
"""Perform the Kahn fix-point computation of the SDF semantics."""
5+
fixpoint = False
6+
# continue till a fixpoint is reached
7+
while not fixpoint:
8+
fixpoint = True
9+
for actor in actors:
10+
res = actor.update_firings()
11+
# do not combine this line with the above, because and is lazy
12+
fixpoint = fixpoint and res
13+
14+
15+
def compute_fixpoint_sadf(scen_seq, actors, states):
16+
"""Perform the Kahn fix-point computation of the SADF semantics."""
17+
fixpoint = False
18+
# continue till a fixpoint is reached
19+
while not fixpoint:
20+
fixpoint = True
21+
# splice traces across scenarios following the scenario sequence
22+
# update the actors in all scenarios
23+
for actor in actors:
24+
# update actor a
25+
res = actor.update_firings_sadf(scen_seq)
26+
# do not combine this line with the above, because and is lazy
27+
fixpoint = fixpoint and res
28+
# update the states
29+
for state in states:
30+
res = state.update_state_sadf(scen_seq)
31+
fixpoint = fixpoint and res
32+
33+
return
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""A library for maxplus algebra and signals."""
2+
3+
from functools import reduce
4+
5+
6+
# quick and dirty implementation of MPMINUSINFINITY
7+
MPMINUSINF = -1000
8+
MPMINUSTHRESHOLD = MPMINUSINF >> 1
9+
10+
# special value to denote the infinitely long sequence of MINUSINF values
11+
# the neutral element of max over sequences.
12+
ZEROSEQ = -1
13+
14+
def delay(events, number_of_tokens, initial_time=MPMINUSINF):
15+
"""Delay an event sequence by n tokens. n may be negative, in which case tokens will be removed."""
16+
if number_of_tokens >= 0:
17+
return initialtokens(number_of_tokens, initial_time) + events
18+
else:
19+
return events[-number_of_tokens:]
20+
21+
22+
def initialtokens(number_of_tokens, initial_time=MPMINUSINF):
23+
"""
24+
Return an event sequence of the given length with -infty values, or a specific value
25+
passed as the second argument
26+
"""
27+
return [initial_time] * number_of_tokens
28+
29+
def mpmax2(seq1, seq2):
30+
"""Compute the max operation on two event sequences."""
31+
return list(map(lambda l: max(l), zip(seq1, seq2)))
32+
33+
34+
def mpmax(*args):
35+
"""Compute the max operation on an arbitrary number of sequences"""
36+
if len(args) == 0:
37+
return ZEROSEQ
38+
return reduce(lambda s1, s2: mpmax2(s1, s2), args)
39+
40+
def mpplus(seq, timedelay):
41+
"""Add a time delay to a sequence"""
42+
return [x+timedelay for x in seq]
43+
44+
def output_sequence(input_sequence, initial_tokens, arcdelay, initial_time=MPMINUSINF):
45+
"""Apply a token delay and a time delay to a sequence"""
46+
return mpplus(delay(input_sequence, initial_tokens, initial_time), arcdelay)
47+
48+
def trace(seq, duration, tracelen):
49+
"""Create a string representation of an execution trace of the
50+
given length with starting times in seq, with firings of the given duration. """
51+
tracestr = ''
52+
newseq = list(seq) + [1000]
53+
for k in range(tracelen):
54+
if len(newseq) == 0:
55+
return tracestr
56+
while newseq[0]+duration <= k:
57+
newseq = newseq[1:]
58+
if k < newseq[0]:
59+
tracestr += '-'
60+
else:
61+
tracestr += '*'
62+
return tracestr
63+
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""Class State Represents the SADF graph state inbetween scenarios"""
2+
from cmtrace.dataflow.maxplus import delay
3+
4+
class State:
5+
"""Represents the SADF graph state inbetween scenarios"""
6+
7+
def __init__(self, name, input_scenarios, output_scenarios):
8+
self.input_scenarios = input_scenarios
9+
self.output_scenarios = output_scenarios
10+
self.name = name
11+
self.providers = dict()
12+
self.firings = []
13+
14+
def set_provider(self, scenario, actor):
15+
"""Set the actor that provides the state in the given scenario"""
16+
# production in scenarion is done by actor at the end of its firing
17+
self.providers[scenario] = actor
18+
return
19+
20+
def spliced_firings(self, scen_seq, scen, tokdel):
21+
"""return the firings, spliced for scenario scen in sequence scen_seq.
22+
"""
23+
del_firings = delay(self.firings, tokdel)
24+
kix = mix = 0
25+
splice = []
26+
while mix < len(del_firings) and kix < len(scen_seq):
27+
if scen_seq[kix] in self.input_scenarios:
28+
if scen_seq[kix] == scen:
29+
splice.append(del_firings[mix])
30+
mix += 1
31+
kix += 1
32+
return splice
33+
34+
def update_state_sadf(self, scen_seq):
35+
"""Update the state from the state providers for the given scenario sequence.
36+
Return a boolean indicating if the sequence remained the same."""
37+
old_firings = len(self.firings)
38+
prov_firings = dict()
39+
indices = dict()
40+
for scenario, actor in self.providers.items():
41+
prov_firings[scenario] = actor.completions()
42+
indices[scenario] = 0
43+
self.firings = []
44+
for (k, _) in enumerate(scen_seq):
45+
# if the current scenario outputs to this state
46+
if scen_seq[k] in self.output_scenarios:
47+
scenario = scen_seq[k]
48+
# if there are no more remaining events
49+
if indices[scenario] >= len(prov_firings[scenario]):
50+
# then the output stops here
51+
break
52+
# otherwise add the event
53+
self.firings.append(prov_firings[scenario][indices[scenario]])
54+
# update the index for the scenario
55+
indices[scenario] += 1
56+
return old_firings == len(self.firings)

0 commit comments

Comments
 (0)