Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
SimRA
Manage
Activity
Members
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Model registry
Analyze
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Guilhem Gamard
SimRA
Commits
d6aac2de
Commit
d6aac2de
authored
5 years ago
by
Guilhem Gamard
Browse files
Options
Downloads
Patches
Plain Diff
Fix docstrings, impl AN.__iter__ & AN.__call__
parent
95cfdba3
No related branches found
No related tags found
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
simra.py
+47
-34
47 additions, 34 deletions
simra.py
with
47 additions
and
34 deletions
simra.py
+
47
−
34
View file @
d6aac2de
...
@@ -4,42 +4,45 @@ import collections
...
@@ -4,42 +4,45 @@ import collections
flatten
=
lambda
l
:
[
item
for
sublist
in
l
for
item
in
sublist
]
flatten
=
lambda
l
:
[
item
for
sublist
in
l
for
item
in
sublist
]
# TODO: History should also store UP
# TODO: Store and enforce node dependencies
class
Mergeable_dict
(
dict
):
class
Mergeable_dict
(
dict
):
"""
Like dict, except that foo += bar update all entries of foo with the
"""
corresponding values in bar. This requires that bar.keys() is a subset of
Subclass of dict, except that mergeable_dict += dict shall update all
foo.keys(), otherwise IndexError is raised.
"""
entries of foo with the corresponding values in bar.
This requires that bar.keys() is a subset of foo.keys(), otherwise
IndexError is raised.
"""
def
__iadd__
(
self
,
other
):
def
__iadd__
(
self
,
other
):
for
k
in
other
.
keys
():
for
k
in
other
.
keys
():
if
not
k
in
self
.
keys
():
raise
IndexError
()
if
not
k
in
self
.
keys
():
raise
IndexError
()
self
[
k
]
=
other
[
k
]
self
[
k
]
=
other
[
k
]
return
self
return
self
# BUG: changing the UP manually (not inc/dec) will break the assumption
# that an.unstep(); an.step() is no-op.
# The other way around, an.step(); an.unstep() is always working though.
class
AN
:
class
AN
:
"""
"""
An automata network.
An automata network.
Fields:
Fields:
nodes -- a set node
"
names
"
, that can be arbitrary (hashable) values
nodes -- set node
"
names
"
, that can be arbitrary (hashable) values
dependencies -- a dict mapping nodes to lists/sets of nodes, on which it
dependencies -- dict mapping nodes to lists/sets of nodes, encoding the
depends for the update
dependency graph of the network
update_funcs -- a dict mapping nodes to functions ; each function takes a
update_funcs -- dict mapping nodes to functions; each function takes a
dictionary (neighbour node→current value) as a unique
dictionary (neighbour node→current value) as sole argument
parameter
(it is possible to do my_an.update_funcs += dict to merge
(it is possible to do my_an.update_funcs += dict to merge
in a dictionary, i.e. to change the functions of only some
in a dictionary, i.e. to change the functions of only some
nodes)
nodes)
update_mode --
a
list of sets (or list of lists) interpreted as a
update_mode -- list of sets (or list of lists) interpreted as a
periodic
periodic
update mode
update mode
init_state --
a
dict
from
nodes to values, that tells which values
should
init_state -- dict
mapping
nodes to values, that tells which values
be used when the network is (re)initialized
should
be used when the network is (re)initialized
state --
a
dict nodes→values holding the current state (value of each
state -- dict nodes→values holding the current state (value of each
node) of the network
node) of the network
history --
a
circular buffer of the last self.history_len states
history -- circular buffer of the last self.history_len states
traversed by the network
traversed by the network
up --
(
Update Pointer
) is
an index for self.update_mode
; it
up -- Update Pointer
;
an index for self.update_mode; it
“points” to the next update to do
“points” to the next update to do
"""
"""
def
__init__
(
self
,
nodes
,
dependencies
,
update_funcs
,
update_mode
,
init_state
=
None
,
history_len
=
10
):
def
__init__
(
self
,
nodes
,
dependencies
,
update_funcs
,
update_mode
,
init_state
=
None
,
history_len
=
10
):
...
@@ -47,7 +50,7 @@ class AN:
...
@@ -47,7 +50,7 @@ class AN:
self
.
dependencies
=
dependencies
self
.
dependencies
=
dependencies
self
.
update_funcs
=
update_funcs
self
.
update_funcs
=
update_funcs
self
.
update_mode
=
update_mode
self
.
update_mode
=
update_mode
self
.
init_state
=
init_state
self
.
init_state
=
init_state
# None is properly handled by a property
self
.
reinit_state
()
# Sets self.state, self.up
self
.
reinit_state
()
# Sets self.state, self.up
self
.
history
=
collections
.
deque
(
maxlen
=
history_len
)
self
.
history
=
collections
.
deque
(
maxlen
=
history_len
)
...
@@ -66,7 +69,7 @@ class AN:
...
@@ -66,7 +69,7 @@ class AN:
def
set_multiple_update_funcs
(
self
,
new_update_funcs
):
def
set_multiple_update_funcs
(
self
,
new_update_funcs
):
"""
"""
If update_funcs is a dictionary node
->
function, change the update
If update_funcs is a dictionary node
→
function, change the update
function of each node to the corresponding function. All nodes in
function of each node to the corresponding function. All nodes in
update_funcs.keys() need to exist; but not all nodes from the network
update_funcs.keys() need to exist; but not all nodes from the network
need to be changed by this operation.
need to be changed by this operation.
...
@@ -96,17 +99,17 @@ class AN:
...
@@ -96,17 +99,17 @@ class AN:
return
self
.
_update_mode
return
self
.
_update_mode
@update_mode.setter
@update_mode.setter
def
update_mode
(
self
,
update_mode
):
def
update_mode
(
self
,
new_
update_mode
):
"""
"""
Change the update mode.
Change the update mode.
update_mode needs to be a list of sets (or list of lists) and is
update_mode needs to be a list of sets (or list of lists) and is
interpreted as a periodic update mode.
interpreted as a periodic update mode.
Changing the update_mode clears the state history to ensure that
This resets up to 0 and clears the history as side-effects.
an.unstep() followed an.step() is no-op (or raises an exception).
"""
"""
if
not
set
(
flatten
(
update_mode
)).
issubset
(
self
.
nodes
):
if
not
set
(
flatten
(
new_
update_mode
)).
issubset
(
self
.
nodes
):
raise
ValueError
(
"
update_mode tries to update a nonexistent node
"
)
raise
ValueError
(
"
update_mode tries to update a nonexistent node
"
)
self
.
_update_mode
=
update_mode
self
.
_update_mode
=
new_update_mode
self
.
up
=
0
self
.
history
.
clear
()
self
.
history
.
clear
()
@property
@property
...
@@ -114,7 +117,7 @@ class AN:
...
@@ -114,7 +117,7 @@ class AN:
return
self
.
_init_state
return
self
.
_init_state
@init_state.setter
@init_state.setter
def
init_state
(
self
,
init_state
):
def
init_state
(
self
,
new_
init_state
):
"""
"""
Change initial state.
Change initial state.
Initial state is used when reinitializing the network.
Initial state is used when reinitializing the network.
...
@@ -122,11 +125,11 @@ class AN:
...
@@ -122,11 +125,11 @@ class AN:
must be a dictionary node->value, where init_state.keys() is equal to
must be a dictionary node->value, where init_state.keys() is equal to
the set of nodes of the network.
the set of nodes of the network.
"""
"""
if
init_state
:
if
new_
init_state
:
if
set
(
init_state
.
keys
())
!=
self
.
nodes
:
if
set
(
new_
init_state
.
keys
())
!=
self
.
nodes
:
raise
ValueError
(
"
init_state either misses state for a node
or has a sate for a nonexistent node
"
)
raise
ValueError
(
"
""
init_state either misses state for a node
else
:
or has a sate for a nonexistent node
"""
)
self
.
_init_state
=
init_state
.
copy
()
self
.
_init_state
=
new_
init_state
.
copy
()
else
:
else
:
self
.
_init_state
=
{}
self
.
_init_state
=
{}
for
n
in
self
.
nodes
:
for
n
in
self
.
nodes
:
...
@@ -147,7 +150,7 @@ class AN:
...
@@ -147,7 +150,7 @@ class AN:
@history_len.setter
@history_len.setter
def
history_len
(
self
,
new_history_len
):
def
history_len
(
self
,
new_history_len
):
new_history
=
collections
.
deque
(
new_history_len
)
new_history
=
collections
.
deque
(
new_history_len
)
for
i
in
range
(
min
(
history_len
,
self
.
history_len
)):
for
i
in
range
(
min
(
new_
history_len
,
self
.
history_len
)):
new_history
.
append
(
self
.
history
[
-
(
i
+
1
)])
new_history
.
append
(
self
.
history
[
-
(
i
+
1
)])
self
.
history
=
new_history
self
.
history
=
new_history
...
@@ -165,7 +168,8 @@ class AN:
...
@@ -165,7 +168,8 @@ class AN:
def
step
(
self
):
def
step
(
self
):
"""
Execute one step of the AN.
"""
"""
Execute one step of the AN.
"""
new_state
=
self
.
state
.
copy
()
new_state
=
self
.
state
.
copy
()
for
n
in
self
.
update_mode
[
self
.
up
]:
for
node
in
self
.
update_mode
[
self
.
up
]:
local_view
=
dict
((
neighbour
,
self
.
state
[
neighbour
])
for
neighbour
in
self
.
dependencies
[
node
])
new_state
[
n
]
=
(
self
.
update_func
[
n
])(
self
.
state
)
new_state
[
n
]
=
(
self
.
update_func
[
n
])(
self
.
state
)
self
.
history
.
append
(
self
.
state
)
self
.
history
.
append
(
self
.
state
)
...
@@ -184,6 +188,15 @@ class AN:
...
@@ -184,6 +188,15 @@ class AN:
# ################################################################
# ################################################################
def
__iter__
(
self
):
return
self
.
nodes
def
__call__
(
self
):
self
.
step
()
return
self
.
state
.
copy
()
# ################################################################
def
button_press
(
event
):
def
button_press
(
event
):
print
(
"
clicked at ({},{})
"
.
format
(
event
.
x
,
event
.
y
))
print
(
"
clicked at ({},{})
"
.
format
(
event
.
x
,
event
.
y
))
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment