]> hydra-www.ietfng.org Git - dyna2/commitdiff
added force-directed layout (with a small hack for random numbers).
authortimv <tim.f.vieira@gmail.com>
Fri, 7 Jun 2013 22:17:44 +0000 (18:17 -0400)
committertimv <tim.f.vieira@gmail.com>
Fri, 7 Jun 2013 22:17:44 +0000 (18:17 -0400)
use FIFO priorities added argument for runing post-processing scripts.

examples/force.dyna [new file with mode: 0644]
src/Dyna/Backend/Python/Backend.hs
src/Dyna/Backend/Python/chart.py
src/Dyna/Backend/Python/interpreter.py
src/Dyna/Backend/Python/repl.py

diff --git a/examples/force.dyna b/examples/force.dyna
new file mode 100644 (file)
index 0000000..5f83159
--- /dev/null
@@ -0,0 +1,63 @@
+% Try to use the force to lay out a few nodes
+
+% Kamada-Kawai force directed layout
+% http://graphael.cs.arizona.edu/papers/graphael_final.pdf
+
+% distance between U and V at time T.
+dist(U,V,T) := (x(U,T) - x(V,T))**2 + (y(U,T) - y(V,T))**2
+   for true is (T < niter).   % restrict to niter iterations.
+
+% all pairs shortest path.
+shortestpath(U,U) min= 0 for node(U).
+shortestpath(U,V) min= shortestpath(U,W) + edge(W,V).
+
+% "the unit edge length"
+edgelen := 5.0.
+
+f(U,V,T) := true is (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)).
+
+a := 0.15.
+niter := 100.
+
+% should `a` be negative?
+x(U,T) += a * forceX(U,T-1).
+y(U,T) += a * forceY(U,T-1).
+
+edge("a", "b") := 1.
+edge("a", "c") := 1.
+edge("a", "d") := 1.
+edge("a", "e") := 1.
+edge("b", "h") := 1.
+edge("b", "i") := 1.
+edge("b", "j") := 1.
+edge("e", "f") := 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("c",0) += uniform(0,1).  y("c",0) += uniform(0,1).
+x("d",0) += uniform(0,1).  y("d",0) += uniform(0,1).
+x("e",0) += uniform(0,1).  y("e",0) += uniform(0,1).
+x("f",0) += uniform(0,1).  y("f",0) += uniform(0,1).
+x("g",0) += uniform(0,1).  y("g",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)).
+
+% import pylab aspl
+% for U,V,_ in edge:
+%     pl.plot([x[U], x[V]],
+%             [y[U], y[V]])
index bc4b7c31c9a499b613ba98c6edfbc9415496d1d8..85103c86a5ad803afc5b4e8998c9695bc41d1d09 100644 (file)
@@ -134,11 +134,13 @@ constants = go
   go ("%",2)     = Just $ PDBS $ infixOp "%"
   go ("+",2)     = Just $ PDBS $ infixOp "+"
 
-  go ("mod",2)   = Just $ PDBS $ call "mod"
+  go ("mod",2)   = Just $ PDBS $ infixOp "%"
   go ("abs",1)   = Just $ PDBS $ call "abs"
   go ("log",1)   = Just $ PDBS $ call "log"
   go ("exp",1)   = Just $ PDBS $ call "exp"
 
+  go ("uniform", _) = Just $ PDBS $ call "uniform"
+
   go ("<=",2)    = Just $ PDBS $ infixOp "<="
   go ("<",2)     = Just $ PDBS $ infixOp "<"
   go ("=",2)     = Just $ PDBS $ infixOp "="
index 70b8868986a41e791d32966bff8883a18ec47dc5..632a9bb9ec8299aa4184d8a8542dc798b7ea2337 100644 (file)
@@ -29,6 +29,12 @@ class Term(object):
             return fn
         return '%s(%s)' % (fn, ','.join(map(_repr, self.args)))
 
+    def __getstate__(self):
+        return (self.fn, self.args, self.value, self.aggregator)
+
+    def __setstate__(self, state):
+        (self.fn, self.args, self.value, self.aggregator) = state
+
     __add__ = __sub__ = __mul__ = notimplemented
 
 
@@ -62,7 +68,7 @@ class Chart(object):
 
     def __getitem__(self, s):
         assert len(s) == self.arity + 1, \
-            'item width mismatch: arity %s, item %s' % (self.arity, len(s))
+            'Chart %r: item width mismatch: arity %s, item %s' % (self.name, self.arity, len(s))
 
         args, val = s[:-1], s[-1]
 
index 7346956254d8f688547bccda481df1255b240008..fbdf4a0ce1b41eb34066a76c5992b6cebfab369c 100644 (file)
@@ -4,11 +4,20 @@
 MISC
 ====
 
+ - TODO: dyna rules for chart display or visualization via viz_chart. Rules will
+   use string formatting or python eval magic.
+
+ - TODO: catch compiler errors (for example, ^C while compiling results in a
+   "Compiler panic!  This is almost assuredly not your fault!...").
+
+ - TODO: dynac should provide routines for building terms. We can hack something
+   together with anf output.
+
  - TODO: faster charts (dynamic argument types? jason's trie data structure)
 
  - TODO: write all files to ~/.dyna
 
- - TODO: `None` does not propagate, eventually it will becase of the `?` prefix
+ - TODO: `None` does not propagate, eventually it will because of the `?` prefix
    operator.
 
  - TODO: (@nwf) String quoting (see example/stringquote.py)
@@ -52,8 +61,8 @@ MISC
 
     - approximate deletion ("buckets"), find the nearest neighbor and delete it.
 
-    - hybrid: maintain streaming sum and the bag check periodically for quality
-      and null.
+    - hybrid: maintain streaming sum parallel to the BAggregator and check
+      periodically for quality and null.
 
     - numeric approximations, stream folding (fails to get null)
 
@@ -61,6 +70,16 @@ MISC
       named with numeric values of variables.
 
 
+JUST FOR FUN
+============
+
+ - overload everything so that values maintain provenance and we can inspect the
+   entire fine-grained circuit.
+
+ - play around with python modules uncertainties (error propagation and
+   gradients), look into tools for dimensional analysis.
+
+
 What is null?
 =============
 
@@ -97,6 +116,7 @@ from utils import ip, red, green, blue, magenta, yellow, \
 from prioritydict import prioritydict
 from config import dotdynadir, dynahome
 
+from time import time
 
 class AggregatorConflict(Exception):
     def __init__(self, key, expected, got):
@@ -231,7 +251,8 @@ class Interpreter(object):
         """
 
         # and now, for something truely horrendous -- look up an item by it's
-        # string value!
+        # string value! This could fail because of whitespace or trivial
+        # formatting differences.
         items = {}
         for c in self.chart.values():
             for i in c.intern.values():
@@ -239,48 +260,44 @@ class Interpreter(object):
         try:
             item = items[item]
         except KeyError:
-            print 'item not found.'
+            print 'item not found. This could be because of a trivial formatting differences...'
             return
 
         print item
 
-        while item.value:
-            print item.value
-            self.emit(item, item.value, None, sys.maxint, delete=True)
-            self.go()
+        self.emit(item, item.value, None, sys.maxint, delete=True)
+        self.go()
 
     def retract_rule(self, idx):
         "Retract rule and all of it's edges."
         assert isinstance(idx, str)
-
         try:
             rule = self.rules.pop(idx)
         except KeyError:
             print 'Rule %s not found.' % idx
             return
-
         # Step 1: remove update handlers
-        print 'removing rule', rule
-        print '  removing updaters'
         for u in rule.updaters:
-            print '    ', u.__doc__
-            deleted = False
             for hs in self.updaters.values():
                 for i, h in enumerate(hs):
                     if u is h:
                         del hs[i]
-                        assert not u in hs
-                        deleted = True
-            assert deleted, 'should always find handler.'
-        deleted = False
-
+                        break
+                else:
+                    assert False, "failed to find updater."
         # Step 2: run initializer in delete mode
         rule.init(emit=self.delete_emit)
-
         # Step 3; go!
         self.go()
 
     def go(self):
+        try:
+            self._go()
+        except KeyboardInterrupt:   # TODO: need to be safer in some parts of the code.
+            print '^C'
+            self.dump_charts()
+
+    def _go(self):
         "the main loop"
 
         changed = {}
@@ -390,7 +407,8 @@ class Interpreter(object):
             item.aggregator.dec(val, ruleix, variables)
         else:
             item.aggregator.inc(val, ruleix, variables)
-        self.agenda[item] = 0   # everything is high priority
+#        self.agenda[item] = 0   # everything is high priority
+        self.agenda[item] = time()
 
     def repl(self, hist):
         import repl
@@ -413,9 +431,11 @@ class Interpreter(object):
             print >> self.trace, magenta % 'Loading new code'
             print >> self.trace, yellow % h.read()
 
+        from numpy.random import uniform
+
         env = {'_initializers': [], '_updaters': [], '_agg_decl': {},
                'chart': self.chart, 'build': self.build, 'peel': peel,
-               'parser_state': None}
+               'parser_state': None, 'uniform': uniform}
 
         # load generated code.
         execfile(filename, env)
@@ -501,6 +521,8 @@ def main():
     parser.add_argument('-o', dest='output', help='Output chart.')
     parser.add_argument('--draw', action='store_true',
                         help='Output html page with hypergraph and chart.')
+    parser.add_argument('--postprocess', type=file,
+                        help='run post-processing script.')
 
     argv = parser.parse_args()
 
@@ -546,6 +568,9 @@ def main():
     if argv.draw:
         interp.draw()
 
+    if argv.postprocess is not None:
+        execfile(argv.postprocess.name, {'interp': interp})
+
 
 if __name__ == '__main__':
     main()
index 34e60a1548f1ff4a73a3ef9bd58e4513208d74b4..e3e2bf8951ac400a1341b6127f9b8997f5b03188 100644 (file)
@@ -6,6 +6,7 @@ from interpreter import AggregatorConflict
 from config import dotdynadir
 import debug
 
+
 class REPL(cmd.Cmd, object):
 
     def __init__(self, interp, hist):