Franck Pommereau

Merge branch 'andy' of https://forge.ibisc.univ-evry.fr/jdelahous/snakes into andy

1 +#!/usr/bin/env python
2 +import snakes.utils.andy.main as andymain
3 +andymain.main()
1 +# entities: tuple of name of the entities, initial level, tuple of decays 0
2 +# denotes unbounded decay (omega)
3 +# examples:
4 +# entities = ( ('B',4, (0,2,2,2,3)), ('P',0, (0,0)), ('C',0, (0,0)),
5 +# ('G',0, (0,0)) )
6 +# entities = ( ('Sugar',1, (0,2)), ('Aspartame',0, (0,2)),
7 +# ('Glycemia',2, (0,2,2,2)), ('Glucagon',0, (0,2)),
8 +# ('Insulin',0,(0,2,2)) )
9 +
10 +entities = ( ('s1',0, (0,1)), ('s2',0, (0,1)), ('s3',0, (0,1)) )
11 +
12 +# Activities: Tuple of (activators, inhibitors, results, duration)
13 +# activators, inhibitors are dictionaries of pairs
14 +# (entity, level)
15 +# results are dictionaries of pairs (entity, +z)
16 +
17 +# potential activities examples:
18 +# potential = ( (dict([('P',0)]),dict([('P',1)]),dict([('P',1)]),0),
19 +# (dict([('P',1)]),dict(),dict([('P',-1)]),0),
20 +# (dict([('C',0)]),dict([('C',1)]),dict([('C',1)]),0),
21 +# (dict([('C',1)]),dict(),dict([('C',-1)]),0),
22 +# (dict([('G',0)]),dict([('G',1)]),dict([('G',1)]),0),
23 +# (dict([('G',1)]),dict(),dict([('G',-1)]),0) )
24 +# potential = ( (dict([('Sugar',1)]),dict(),
25 +# dict([('Insulin',1),('Glycemia',1)]),0),
26 +# (dict([('Aspartame',1)]),dict(),dict([('Insulin',1)]),0),
27 +# (dict(),dict([('Glycemia',1)]),dict([('Glucagon',1)]),0),
28 +# (dict([('Glycemia',3)]),dict(),dict([('Insulin',1)]),0),
29 +# (dict([('Insulin',2)]),dict(),dict([('Glycemia',-1)]),0),
30 +# (dict([('Insulin',1),('Glycemia',3)]), dict(),
31 +# dict([('Glycemia',-1)]),0),
32 +# (dict([('Insulin',1)]),dict([('Glycemia',2)]),
33 +# dict([('Glycemia',-1)]),0),
34 +# (dict([('Glucagon',1)]),dict(),dict([('Glycemia',+1)]),0)
35 +# )
36 +
37 +potential = ( (dict(), dict([('s1',1)]), dict([('s2',1)]), 1),
38 + (dict(), dict([('s2',1)]), dict([('s3',1)]), 1),
39 + (dict(), dict([('s3',1)]), dict([('s1',1)]), 1) )
40 +
41 +# obligatory activities examples:
42 +# obligatory = ( (dict([('P',1)]),dict(),dict([('B',1)]),1),
43 +# (dict([('C',1)]),dict(),dict([('B',-1)]),3),
44 +# (dict([('G',1)]),dict(),dict([('B',-2)]),3))
45 +
46 +obligatory = ()
47 +
1 +"""This package features the Andy compiler, this is mainly a
2 +command-line tool but it can be called also from Python. The API is
3 +very simple and mimics the command line interface
4 +
5 +### Function `snakes.utils.andy.main.main` ###
6 +
7 + :::python
8 + def main (args=sys.argv[1:]) : ...
9 +
10 +Entry point of the compiler
11 +
12 +##### Call API #####
13 +
14 + * `list args`:
15 + * `return PetriNet`:
16 +
17 +##### Exceptions #####
18 +
19 + * `DeclarationError`: when
20 + * `CompilationError`: when
21 +
22 +"""
23 +
24 +# apidoc stop
25 +from snakes import SnakesError
26 +
27 +class CompilationError (SnakesError) :
28 + pass
29 +
30 +class DeclarationError (SnakesError) :
31 + pass
This diff is collapsed. Click to expand it.
1 +import sys, optparse, os.path, webbrowser
2 +import pdb, traceback
3 +import snakes.plugins
4 +from snakes.utils.andy import CompilationError, DeclarationError
5 +from snakes.utils.andy.simul import Simulator, AndySimulator
6 +from snakes.utils.andy.andy import andy2snakes
7 +from snakes.utils.simul.html import json
8 +
9 +##
10 +## error messages
11 +##
12 +
13 +options = None
14 +
15 +ERR_ARG = 1
16 +ERR_OPT = 2
17 +ERR_IO = 3
18 +ERR_PARSE = 4
19 +ERR_PLUGIN = 5
20 +ERR_COMPILE = 6
21 +ERR_OUTPUT = 7
22 +ERR_BUG = 255
23 +
24 +def log (message) :
25 + sys.stdout.write("andy: %s\n" % message.strip())
26 + sys.stdout.flush()
27 +
28 +def err (message) :
29 + sys.stderr.write("andy: %s\n" % message.strip())
30 + sys.stderr.flush()
31 +
32 +def die (code, message=None) :
33 + global options
34 + if message :
35 + err(message)
36 + if options.debug :
37 + pdb.post_mortem(sys.exc_info()[2])
38 + else :
39 + sys.exit(code)
40 +
41 +def bug () :
42 + global options
43 + sys.stderr.write("""
44 + ********************************************************************
45 + *** An unexpected error ocurred. Please report this bug to ***
46 + *** <franck.pommereau@gmail.com>, together with the execution ***
47 + *** trace below and, if possible, a stripped-down version of the ***
48 + *** ABCD source code that caused this bug. Thank you for your ***
49 + *** help in improving SNAKES! ***
50 + ********************************************************************
51 +
52 +""")
53 + traceback.print_exc()
54 + if options.debug :
55 + pdb.post_mortem(sys.exc_info()[2])
56 + else :
57 + sys.exit(ERR_BUG)
58 +
59 +##
60 +## options parsing
61 +##
62 +
63 +gv_engines = ("dot", "neato", "twopi", "circo", "fdp")
64 +
65 +opt = optparse.OptionParser(prog="andy",
66 + usage="%prog [OPTION]... FILE")
67 +opt.add_option("-l", "--load",
68 + dest="plugins", action="append", default=[],
69 + help="load plugin (this option can be repeated)",
70 + metavar="PLUGIN")
71 +opt.add_option("-p", "--pnml",
72 + dest="pnml", action="store", default=None,
73 + help="save net as PNML",
74 + metavar="OUTFILE")
75 +for engine in gv_engines :
76 + opt.add_option("-" + engine[0], "--" + engine,
77 + dest="gv" + engine, action="store", default=None,
78 + help="draw net using '%s' (from GraphViz)" % engine,
79 + metavar="OUTFILE")
80 +opt.add_option("--debug",
81 + dest="debug", action="store_true", default=False,
82 + help="launch debugger on compiler error (default: no)")
83 +opt.add_option("-s", "--simul",
84 + dest="simul", action="store_true", default=False,
85 + help="launch interactive code simulator")
86 +opt.add_option("--headless",
87 + dest="headless", action="store", default=None,
88 + help="headless code simulator, with saved parameters",
89 + metavar="JSONFILE")
90 +opt.add_option("--port",
91 + dest="port", action="store", default=8000, type=int,
92 + help="port on which the simulator server runs",
93 + metavar="PORT")
94 +
95 +def getopts (args) :
96 + global options, andy, tmp
97 + (options, args) = opt.parse_args(args)
98 + plugins = []
99 + for p in options.plugins :
100 + plugins.extend(t.strip() for t in p.split(","))
101 + if "labels" not in plugins :
102 + plugins.append("labels")
103 + for engine in gv_engines :
104 + gvopt = getattr(options, "gv%s" % engine)
105 + if gvopt and "gv" not in plugins :
106 + plugins.append("gv")
107 + break
108 + if (options.simul) and "gv" not in plugins :
109 + plugins.append("gv")
110 + options.plugins = plugins
111 + if len(args) < 1 :
112 + err("no input file provided")
113 + opt.print_help()
114 + die(ERR_ARG)
115 + elif len(args) > 1 :
116 + err("more than one input file provided")
117 + opt.print_help()
118 + die(ERR_ARG)
119 + andy = args[0]
120 + if options.pnml == andy :
121 + err("input file also used as output (--pnml)")
122 + opt.print_help()
123 + die(ERR_ARG)
124 + for engine in gv_engines :
125 + if getattr(options, "gv%s" % engine) == andy :
126 + err("input file also used as output (--%s)" % engine)
127 + opt.print_help()
128 + die(ERR_ARG)
129 +
130 +##
131 +## drawing nets
132 +##
133 +
134 +def draw (net, target, engine="dot") :
135 + try :
136 + return net.draw(target, engine=engine)
137 + except :
138 + die(ERR_OUTPUT, str(sys.exc_info()[1]))
139 +
140 +##
141 +## save pnml
142 +##
143 +
144 +def save_pnml (net, target) :
145 + try :
146 + out = open(target, "w")
147 + out.write(snk.dumps(net))
148 + out.close()
149 + except :
150 + die(ERR_OUTPUT, str(sys.exc_info()[1]))
151 +
152 +##
153 +## simulator (not standalone)
154 +##
155 +
156 +def simulate (entities, potential, obligatory, filename='<string>') :
157 + global options, snk
158 + getopts(["--simul", filename])
159 + snk = snakes.plugins.load(options.plugins, "snakes.nets", "snk")
160 + net = andy2snakes(snk, entities, potential, obligatory)
161 + net.label(srcfile=filename, snakes=snk)
162 + return AndySimulator(net)
163 +
164 +##
165 +## main
166 +##
167 +
168 +def main (args=sys.argv[1:]) :
169 + global options, snk
170 + # get options
171 + try:
172 + getopts(args)
173 + except SystemExit :
174 + raise
175 + except :
176 + die(ERR_OPT, str(sys.exc_info()[1]))
177 + # read andy spec
178 + try:
179 + env = {}
180 + execfile(andy, env)
181 + del env['__builtins__']
182 + except:
183 + die(ERR_IO, "could not read input file %r" % andy)
184 + # compile to net
185 + dirname = os.path.dirname(andy)
186 + if dirname and dirname not in sys.path :
187 + sys.path.append(dirname)
188 + elif "." not in sys.path :
189 + sys.path.append(".")
190 + try :
191 + snk = snakes.plugins.load(options.plugins, "snakes.nets", "snk")
192 + except :
193 + die(ERR_PLUGIN, str(sys.exc_info()[1]))
194 +
195 + try:
196 + net = andy2snakes(snk, env['entities'], env['potential'],
197 + env['obligatory'])
198 + except:
199 + bug()
200 +
201 + # output
202 + if options.pnml :
203 + save_pnml(net, options.pnml)
204 + for engine in gv_engines :
205 + target = getattr(options, "gv%s" % engine)
206 + if target :
207 + draw(net, target, engine)
208 + trace, lineno = [], None
209 + if options.simul :
210 + try :
211 + simul = Simulator(net, options.port)
212 + except :
213 + bug()
214 + simul.start()
215 + if options.headless :
216 + with open(options.headless, "w") as out :
217 + out.write(json({"res" : "%sr" % simul.url,
218 + "url" : simul.url,
219 + "key" : simul.server.httpd.key,
220 + "host" : "127.0.0.1",
221 + "port" : simul.port}))
222 + else :
223 + webbrowser.open(simul.url)
224 + simul.wait()
225 + elif trace :
226 + if lineno is None :
227 + print("unsafe execution:")
228 + else :
229 + asserts = dict((a.lineno, a) for a in net.label("asserts"))
230 + print("line %s, %r failed:"
231 + % (lineno, asserts[lineno].st.source()))
232 + for trans, mode in trace :
233 + print(" %s %s" % (trans, mode))
234 + return net
235 +
236 +if __name__ == "__main__" :
237 + main()
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
1 +<!DOCTYPE html>
2 +<html>
3 +<head>
4 + <link type="text/css" href="r/css/bootstrap-theme.css" rel="stylesheet"/>
5 + <link type="text/css" href="r/css/bootstrap.css" rel="stylesheet"/>
6 + <script src="r/js/jquery.min.js"></script>
7 + <script src="r/js/jquery.periodic.js"></script>
8 + <script src="r/js/bootstrap.min.js"></script>
9 + <script src="r/js/d3.min.js"></script>
10 + <script src="r/js/simulator.js"></script>
11 + <style>
12 + path { stroke: steelblue;
13 + stroke-width: 2;
14 + fill: none; }
15 + line { stroke: black; }
16 + text { font-family: Arial;
17 + font-size: 9pt; }
18 + </style>
19 +</head>
20 +<body>
21 + <header class="navbar navbar-static-top">
22 + <nav class="navbar navbar-default" role="navigation">
23 + <div class="container-fluid">
24 + <div class="navbar-header">
25 + <button type="button" class="navbar-toggle"
26 + data-toggle="collapse"
27 + data-target="#bs-example-navbar-collapse-6">
28 + <span class="sr-only">Toggle navigation</span>
29 + </button>
30 + <a class="navbar-brand" href="#">Simulation SNAKES</a>
31 + </div>
32 + <div class="collapse navbar-collapse"
33 + id="bs-example-navbar-collapse-6">
34 + <ul class="nav navbar-nav" id="nav_sim">
35 + <li><a id="ui-reset">Reset Simulation</a></li>
36 + <li><a id="ui-quit">Stop Simulation</a></li>
37 + <li><a id="ui-help">Help</a></li>
38 + </ul>
39 + </div><!-- /.navbar-collapse -->
40 + </div>
41 + </nav>
42 + </header>
43 + <!-- model to be simulated -->
44 + %(model)s
45 +
46 + <!-- information about the simulator -->
47 + <div aria-hidden="true" aria-labelledby="myModalLabel" class="modal fade"
48 + id="about" role="dialog" tabindex="-1">
49 + <div class="modal-dialog">
50 + <div class="modal-content">
51 + <div class="modal-header">
52 + <button aria-hidden="true" class="close"
53 + data-dismiss="modal" type="button">x</button>
54 + <h4 class="modal-title" id="myModalLabel">Petri Net</h4>
55 + </div>
56 + <div class="modal-body">
57 + <p>
58 + <span class="title">Andy simulator is part of the
59 + SNAKES toolkit</span><br />
60 + (C) 2014 Franck Pommereau
61 + </p>
62 + <p>
63 + <a href="http://www.ibisc.univ-evry.fr/~fpommereau/SNAKES"
64 + target="_blank">SNAKES homepage</a>
65 + </p>
66 + </div>
67 + <div class="modal-footer">
68 + <button class="btn btn-default" data-dismiss="modal"
69 + type="button">Close</button>
70 + </div>
71 + </div>
72 + </div>
73 + </div>
74 + <script>
75 + $(document).ready(function(){
76 + $.simisc({ "nav":{ "about": { "text": "About",
77 + "attr": { "id":"ui-about",
78 + "data-toggle": "modal",
79 + "data-target": "#about"
80 + } } },
81 + "graph": { "color": { "y":"red",
82 + "x":"blue" } } });
83 + });
84 + </script>
85 +</body>
86 +</html>
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
1 +/*!
2 + * jQuery periodic plugin
3 + *
4 + * Copyright 2010, Tom Anderson
5 + * Dual licensed under the MIT or GPL Version 2 licenses.
6 + *
7 + */
8 +
9 +$.periodic = function (options, callback) {
10 +
11 + // if the first argument is a function then assume the options aren't being passed
12 + if (jQuery.isFunction(options)) {
13 + callback = options;
14 + options = {};
15 + }
16 +
17 + // Merge passed settings with default values
18 + var settings = jQuery.extend({}, jQuery.periodic.defaults, {
19 + ajax_complete : ajaxComplete,
20 + increment : increment,
21 + reset : reset,
22 + cancel : cancel
23 + }, options);
24 +
25 + // bookkeeping variables
26 + settings.cur_period = settings.period;
27 + settings.tid = false;
28 + var prev_ajax_response = '';
29 +
30 + run();
31 +
32 + // return settings so user can tweak them externally
33 + return settings;
34 +
35 + // run (or restart if already running) the looping construct
36 + function run() {
37 + // clear/stop existing timer (multiple calls to run() won't result in multiple timers)
38 + cancel();
39 + // let it rip!
40 + settings.tid = setTimeout(function() {
41 + // set the context (this) for the callback to the settings object
42 + callback.call(settings);
43 +
44 + // compute the next value for cur_period
45 + increment();
46 +
47 + // queue up the next run
48 + if(settings.tid)
49 + run();
50 + }, settings.cur_period);
51 + }
52 +
53 + // utility function for use with ajax calls
54 + function ajaxComplete(xhr, status) {
55 + if (status === 'success' && prev_ajax_response !== xhr.responseText) {
56 + // reset the period whenever the response changes
57 + prev_ajax_response = xhr.responseText;
58 + reset();
59 + }
60 + }
61 +
62 + // compute the next delay
63 + function increment() {
64 + settings.cur_period *= settings.decay;
65 + if (settings.cur_period < settings.period) {
66 + // don't let it drop below the minimum
67 + reset();
68 + } else if (settings.cur_period > settings.max_period) {
69 + settings.cur_period = settings.max_period;
70 + if (settings.on_max !== undefined) {
71 + // call the user-supplied callback if we reach max_period
72 + settings.on_max.call(settings);
73 + }
74 + }
75 + }
76 +
77 + function reset() {
78 + settings.cur_period = settings.period;
79 + // restart with the new timeout
80 + run();
81 + }
82 +
83 + function cancel() {
84 + clearTimeout(settings.tid);
85 + settings.tid = null;
86 + }
87 +
88 + // other functions we might want to implement
89 + function pause() {}
90 + function resume() {}
91 + function log() {}
92 +};
93 +
94 +jQuery.periodic.defaults = {
95 + period : 4000, // 4 sec.
96 + max_period : 1800000, // 30 min.
97 + decay : 1.5, // time period multiplier
98 + on_max : undefined // called if max_period is reached
99 +};
...\ No newline at end of file ...\ No newline at end of file
This diff is collapsed. Click to expand it.
1 +<div class="container-fluid">
2 +<div class="row">
3 + <div class="col-md-1"></div>
4 + <div class="col-md-10">
5 + <div class="page-header">
6 + <h1><tt>Andy Simulator</tt> <small> powered by SNAKES</small></h1>
7 + </div>
8 +
9 + <div class="row">
10 + <h3>Player</h3>
11 + <div id="player">&nbsp;</div>
12 + </div>
13 + <div class="row">
14 + <h3>Modes</h3>
15 + <div id="modes">&nbsp;</div>
16 + </div>
17 + <div class="row">
18 + <h3>Net Graph</h3>
19 + <div id="graph">&nbsp;</div>
20 + </div>
21 + <div class="row">
22 + <div id="trace_zone">&nbsp;</div>
23 + </div>
24 + <div class="row">
25 + <h3>Command Panel</h3>
26 + <div id="Command_center">&nbsp;</div>
27 + </div>
28 + </div>
29 + <div class="col-md-1"></div>
30 +</div>
31 +</div>
1 +from snakes.utils.simul import BaseSimulator, BaseHTTPSimulator
2 +
3 +class AndySimulator (BaseSimulator) :
4 + def getstate (self, state) :
5 + ret = BaseSimulator.getstate(self, state)
6 + marking = self.states[state]
7 + ret["variables"] = dict((place, tokens.items()[0])
8 + for place, tokens in marking.items())
9 + ret["groups"] = ["timed", "even", "odd"]
10 + modes = []
11 + for i, (trans, binding) in enumerate(marking.modes) :
12 + if (state + i) % 5 == 0 :
13 + groups = ["timed"]
14 + else :
15 + groups = []
16 + modes.append(
17 + {"state" : state,
18 + "mode" : i,
19 + "html" : "%s (%s)" % (trans.name[7:], binding),
20 + "groups" : groups + ["odd" if (state % 2) else "even"]
21 + })
22 + ret["modes"] = [{"select": "#modes", "items": modes}]
23 + return ret
24 +
25 +#class Simulator (BaseHTTPSimulator) :
26 +# def __init__ (self, **system) :
27 +# simul = AndySimulator(**system)
28 +# BaseHTTPSimulator.__init__(self, simulator=simul)
29 +
30 +class Simulator (BaseHTTPSimulator) :
31 + def __init__ (self, net, port) :
32 + simul = AndySimulator(net)
33 + BaseHTTPSimulator.__init__(self, net, simulator=simul, port=port)
34 +# def init_model (self) :
35 +# return self.res["model.html"] % self.simul.info
36 +# def init_ui (self) :
37 +# return BaseHTTPSimulator.init_ui(self)[:-1] + [{
38 +# "label" : "Show net",
39 +# "id" : "ui-shownet",
40 +# "href" : "#",
41 +# "script" : "dialog($('#model .petrinet').html())"
42 +# }]
43 +