Skip to content
Snippets Groups Projects
Commit 500c61ff authored by Guilhem Gamard's avatar Guilhem Gamard
Browse files

First draft

parent 35425efa
No related branches found
No related tags found
No related merge requests found
#!/usr/bin/env python3
import collections
import copy
from collections import deque
from copy import deepcopy
from functools import reduce
from itertools import count
import tkinter as TK
......@@ -8,6 +8,19 @@ import tkinter as TK
# ################################################################
# General utilities
class Gensym:
"""
Poor man's closure to generate unique names.
"""
def __init__(self, prefix="g", seq=count()):
self.prefix = prefix
self.seq = seq
def __call__(self):
return "{}{}".format(self.prefix, next(self.seq))
gensym = Gensym()
# gensym() returns successively "g0", "g1", "g2", etc.
def dict_filter(dictionary, keys):
"""
Return a subdictionary of `dictionary` comprising only the given `keys`.
......@@ -21,6 +34,9 @@ def integers(n):
return list(range(n))
def flatten(l):
"""
Given a list of list, return the list of elements of sublists.
"""
return [item for sublist in l for item in sublist]
# ################################################################
......@@ -32,6 +48,7 @@ class Node:
Constructor fields:
name -- Any hashable value, used for printing and identification
(must be unique inside an AN or all hell breaks loose)
update_func -- Update Function; it must take one parameter: a dictionary
mapping name of neighbours to their values
dependencies -- List of dependency names (other nodes' names)
......@@ -40,7 +57,6 @@ class Node:
Other fields:
state -- Curent value of the node
"""
def __init__(self, name, update_func=None, dependencies=[], init_state=0):
self.name = name
self.update_func = update_func
......@@ -55,8 +71,7 @@ class Node:
self.dependencies.append(new_dependency)
def update(self, neigh_vals):
f = self.update_func
self.state = f(neigh_vals)
self.state = self.update_func(neigh_vals)
def __repr__(self):
return "{{node {}: {}}}".format(self.name, self.state)
......@@ -90,11 +105,11 @@ class AN:
written to `_nodes`.
"""
def __init__(self, nodes={}, update_mode=[], history_len=10):
def __init__(self, nodes={}, update_mode=[], history_len=100):
self.nodes = nodes
self.update_mode = update_mode
self.up = 0
self.history = collections.deque(maxlen=history_len)
self.history = deque(maxlen=history_len)
# ################################################################
......@@ -138,7 +153,7 @@ class AN:
@history_len.setter
def history_len(self, new_history_len):
new_history = collections.deque(new_history_len)
new_history = deque(maxlen=new_history_len)
for i in range(min(new_history_len, self.history_len)):
new_history.append(self.history[-(i+1)])
self.history = new_history
......@@ -154,28 +169,26 @@ class AN:
def reset_state(self):
"""Set each node to its initial value, and the up to 0."""
new_nodes = self._nodes.copy()
new_nodes = deepcopy(self._nodes)
for node in new_nodes:
node.reset_state()
self.history.append(self._nodes)
self._nodes = new_nodes
self.up = 0
def update(self):
"""Update the AN once."""
new_nodes = copy.deepcopy(self._nodes)
new_nodes = deepcopy(self._nodes)
for n in self.update_mode[self.up]:
local_view = dict_filter(self.state, self._nodes[n].dependencies)
new_nodes[n].update(local_view)
self.history.append(self.nodes)
self.history.append(self._nodes)
self._nodes = new_nodes
self.up += 1
def unupdate(self):
"""Roll back one step of the AN, within limits of history_len."""
self._nodes = copy.deepcopy(self.history.pop())
self._nodes = self.history.pop()
self.up -= 1
def run(self, steps):
......@@ -220,7 +233,7 @@ def is_block_seq(mode):
def block_seq(mode):
"""
Checks that `mode` is block-sequential. If so, return it.
If not, raise a ValueError exception. Useful for functoinal programming.
If not, raise a ValueError exception. Useful for functional programming.
"""
if not is_block_seq(mode): raise ValueError()
return mode
......@@ -228,12 +241,12 @@ def block_seq(mode):
def periodic_mode(mode):
"""
The identity function, with another name.
Useful for functionnal programming.
Useful for functional programming.
"""
return mode
# ################################################################
# Trivial nodes
# Node construction
def node_fixpoint(name, init_val=0):
"""
......@@ -302,7 +315,7 @@ def cycle(signs, init_vals=None, update_mode=None):
return AN(nodes, update_mode)
# ################################################################
# And-not symmetric networks
# And-not networks
def land(b1, b2):
"""Like `and`, but a function (usable with `reduce`)"""
......@@ -311,7 +324,7 @@ def land(b1, b2):
def and_not_update_func(dep_list):
"""
Return an update function for a node in an and_not network.
If dep_list is [1, -2, 3, -4], the node has positive neighbours 1, 3
If dep_list is [1, -2, 3, -4], then the node has positive neighbours 1, 3
and negative neighbours 2, 4.
"""
def node_update_func(args):
......@@ -341,11 +354,12 @@ def and_not(dep_lists, init_vals, update_mode):
"""
nodes = []
for (dep_list, init_val, i) in zip(dep_lists[1:], init_vals[1:], count(1)):
update_func = ant_not_update_func(dep_list)
print("{} {} {}".format(dep_list, init_val, i))
update_func = and_not_update_func(dep_list)
deps = [abs(d) for d in dep_list]
node = Node(i, update_func, deps, init_val)
nodes.append(node)
return AN(nodes[1:], update_mode)
return AN(nodes, update_mode)
# ################################################################
......@@ -375,27 +389,3 @@ example_update = [
[],
]
# ################################################################
def button_press(event):
print("clicked at ({},{})".format(event.x, event.y))
def button_release(event):
print("Released at ({},{})".format(event.x, event.y))
def main():
window = Tk()
window.title("SIMulateur de Réseau d'Automates")
canvas = Canvas(window)
canvas.create_rectangle(128, 64, 32, 32,
outline="#ff0000", fill="#aaaaaa")
canvas.bind("<Button-1>", button_press)
canvas.bind("<ButtonRelease-1>", button_release)
canvas.pack(fill=BOTH, expand=1)
window.mainloop()
if __name__ == '__main__':
main()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment