shortestpath(U,U) min= 0 for node(U).
shortestpath(U,V) min= shortestpath(U,W) + edge(W,V).
-% "the unit edge length"
-edgelen := 4.0.
-
+% Compute attractive-replusive forces
f(U,V,T) := (U != V), dist(U,V,T) / (shortestpath(U,V) * edgelen) - 1.
-
forceX(V,T) += f(U,V,T) * (x(U,T) - x(V,T)).
forceY(V,T) += f(U,V,T) * (y(U,T) - y(V,T)).
+% Constants
a := 0.15.
-niter := 100.
+niter := 200.
+edgelen := 4.0. % "the unit edge length"
% should `a` be negative?
x(U,T) += a * forceX(U,T-1).
y(U,T) += a * forceY(U,T-1).
+% make graph symmetric.
+edge(A,B) := 1 for edge(B,A).
+
+% collect nodes.
+node(U) := true for edge(U,_).
+node(U) := true for edge(_,U).
+
+% pack x and y into a tuple
+pos(U,T) := tuple(x(U, T), y(U, T)).
+
+% visualization
+frame(T, Item) := node(Name), Item is &text(Name, pos(Name, T)).
+frame(T, Item) := edge(U,V), Item is &line(pos(U, T), pos(V, T)).
+
+% declare some edges
edge("a", "b") := 1.
edge("a", "c") := 1.
edge("a", "d") := 1.
edge("e", "g") := 1.
edge("a", "i") := 1.
-edge(A,B) := 1 for edge(B,A). % make graph symmetric.
-
-% collect nodes.
-node(U) := true for edge(U,_).
-node(U) := true for edge(_,U).
-
% randomly initialize node positions.
x("a",0) += uniform(0,1). y("a",0) += uniform(0,1).
x("b",0) += uniform(0,1). y("b",0) += uniform(0,1).
x("h",0) += uniform(0,1). y("h",0) += uniform(0,1).
x("i",0) += uniform(0,1). y("i",0) += uniform(0,1).
x("j",0) += uniform(0,1). y("j",0) += uniform(0,1).
-
-pos(U,T) := tuple(x(U, T), y(U, T)).
class BAggregator(Counter, Aggregator):
+ def __init__(self):
+ super(BAggregator, self).__init__()
def inc(self, val, ruleix, variables):
self[val] += 1
def dec(self, val, ruleix, variables):
-import pylab as pl
-from matplotlib.animation import FuncAnimation
-from collections import defaultdict
+"""
+Postprocessor for animated visualization of basic elements such as lines and
+text.
-def g(nodes, edges, t, ax, interp):
- ax.cla()
- ax.set_title(t)
- ax.set_xlim(-2,2)
- ax.set_ylim(-2,2)
+We look for the following patterns in the dynabase
- pos = defaultdict(lambda: (0,0))
- pos.update({node: p for _, (node, _), p in interp.chart['pos/2'][:,t,:]})
+ visual element
+ v
+ frame(T, &text(String, tuple(X, Y))).
+ ^
+ time index
- for u,v in edges:
- if u < v:
- (a,b), (c,d) = pos[u], pos[v]
- ax.plot([a,c], [b,d])
+Frames should have value true. The example above places a text element reading
+`String` at position `(X,Y)` in a frame at time `T`. This element can be
+specified by dyna rule.
+"""
- for s in nodes:
- x,y = pos[s]
- ax.text(x,y,s)
+import pylab as pl
+from matplotlib.animation import FuncAnimation
+from collections import defaultdict
-def animate(interp):
- [(_, _, niter)] = interp.chart['niter/0'][:,]
+def main(interp):
- nodes = [name for _, [name], _ in interp.chart['node/1'][:,:]]
- edges = [(u,v) for _, [u,v] ,_ in interp.chart['edge/2'][:,:,:]]
+ frame = defaultdict(list)
+ for _, [t, item], val in interp.chart['frame/2'][:,:,:]:
+ if val:
+ frame[t].append(item)
+
+ nframes = max(frame)
+
+ def draw_frame(t):
+ ax.cla()
+ ax.set_title(t)
+ ax.set_xlim(-2,2) # TODO: this isn't right...
+ ax.set_ylim(-2,2)
+ if t not in frame:
+ print 'frame', t, 'missing.'
+ for item in frame[t]:
+ if item.fn == 'line/2':
+ [(a,b), (c,d)] = item.args
+ ax.plot([a,c], [b,d], color='b', alpha=0.5)
+ elif item.fn == 'text/2':
+ (s,(x,y)) = item.args
+ ax.text(x,y,s)
+ else:
+ print 'dont know how to render', item
fig = pl.figure()
ax = pl.axes()
print 'creating animation..'
- anim = FuncAnimation(fig, lambda t: g(nodes, edges, t % niter, ax, interp), frames=niter)
+ anim = FuncAnimation(fig, draw_frame, frames=nframes)
print 'saving...'
anim.save('examples/force.dyna.mp4', fps=30, extra_args=['-vcodec', 'libx264'])
print 'wrote examples/force.dyna.mp4'
-
-
-def main(interp):
- animate(interp)
import os, cmd, readline
import debug, interpreter
-from utils import DynaCompilerError, DynaInitializerException, ip, crash_handler
+from utils import DynaCompilerError, DynaInitializerException, ip
from chart import _repr
from config import dotdynadir
except KeyboardInterrupt:
# Catch Control-C and resume REPL.
print '^C'
- self.cmdloop()
- except:
- # report uncatch exception.
- crash_handler()
+ self.cmdloop()
finally:
readline.write_history_file(self.hist)
raise DynaCompilerError(stderr)
-def crash_handler():
- exception_handler(*sys.exc_info())
-
-
def exception_handler(etype, evalue, tb):
# once for the log file.
with file(dotdynadir / 'crash.log', 'wb') as crashreport:
- h = VerboseTB(color_scheme='Linux', call_pdb=False,
+ h = VerboseTB(color_scheme='Linux',
+ call_pdb=False,
ostream=crashreport,
- long_header=True, include_vars=True,
+ long_header=True,
+ include_vars=True,
check_cache=None)
h(etype, evalue, tb)
# once for the user
- h = VerboseTB(color_scheme='Linux', call_pdb=False, ostream=None,
- tb_offset=0, long_header=False, include_vars=True,
+ h = VerboseTB(color_scheme='Linux',
+ call_pdb=False,
+ ostream=None,
+ tb_offset=0,
+ long_header=False,
+ include_vars=False,
check_cache=None)
h(etype, evalue, tb)