Abelian sandpile model/Identity: Difference between revisions
→Python :: Functional: Added a display function to sugar test outputs. Added a full cascade sequence.
(→Python :: Functional: Added a display function to sugar test outputs. Added a full cascade sequence.) |
|||
Line 934:
<lang python>'''Abelian Sandpile'''
from itertools import takewhile
from functools import reduce
from operator import add
Line 942 ⟶ 944:
'''Tests of cascades and additions'''
s0 = [[4, 3, 3], [3, 1, 2], [0, 2, 3]]
series = list(cascadeSeries(s0))
s1 = [[1, 2, 0], [2, 1, 1], [0, 1, 3]]
s2 = [[2, 1, 3], [1, 0, 1], [0, 1, 0]]
Line 949 ⟶ 952:
for expr in [
'Cascaded outcome:',
(':', xs) for xs in series[1:]
]
),
'',
f's1 + s2 == s2 + s1 -> {addSand(s1)(s2) == addSand(s2)(s1)}',
('+', cascaded(s2)),
('=', addSand(s1)(s2))
]),
'',
showSandPiles([
(' ', s2),
('+', cascaded(s1)),
('=', addSand(s2)(s1))
]),
'',
f's3 + s3_id == s3 -> {addSand(s3)(s3_id) == s3}',
('+', s3_id),
('=', s3)
]),
'',
f's3_id + s3_id == s3_id -> {addSand(s3_id)(s3_id) == s3_id}',
('+', s3_id),
('=', addSand(s3_id)(s3_id))
]),
]:
print(expr)
Line 992 ⟶ 1,014:
xs = list(rows)
w = len(xs)
def p(xs):▼
return all(x <= w for x in xs)▼
return list(chunksOf(w)(
until(
nextState(w)
)(
concat(xs)
)
))
# cascadeSeries :: [[Int]] -> [[[Int]]]
def cascadeSeries(rows):
'''The sequence of states from a given
sand pile to a stable condition.
'''
xs = list(rows)
w = len(xs)
series = iterate(nextState(w))(
concat(rows)
)
return list(map(
compose(list, chunksOf(w)),
takewhile(
series
)
)) + [list(chunksOf(w)(next(series)))]
Line 1,038 ⟶ 1,077:
)
return go
# ------------------------ DISPLAY -------------------------
# showSandPiles :: [(String, [[Int]])] -> String
def showSandPiles(pairs):
'''Indented multi-line representation
of a sequence of matrixes, delimited
by preceding operators or indents.
'''
return '\n'.join([
' '.join([' '.join(map(str, seq)) for seq in tpl])
for tpl in zip(*[
zip(
*[list(str(pfx).center(len(rows)))]
+ list(zip(*rows))
)
for (pfx, rows) in pairs
])
])
Line 1,054 ⟶ 1,113:
) if 0 < n else None
return go
# compose :: ((a -> a), ...) -> (a -> a)
def compose(*fs):
'''Composition, from right to left,
of a series of functions.
'''
def go(f, g):
def fg(x):
return f(g(x))
return fg
return reduce(go, fs, lambda x: x)
Line 1,075 ⟶ 1,147:
None
)
return go
# iterate :: (a -> a) -> a -> Gen [a]
def iterate(f):
'''An infinite list of repeated
applications of f to x.
'''
v = x
while True:
yield v
v = f(v)
return go
Line 1,098 ⟶ 1,183:
{{Out}}
<pre>Cascaded outcome:
0 2 3 0 2 3 0 2 3 0 2 3 1 2 3
s1 + s2 == s2 + s1 -> True
0 1 3 0 1 0 0 2 3
2 1 3 1 2 0 3 3 3
1 0 1 + 2 1 1 = 3 1 2
0 1 0 0 1 3 0 2 3
s3 + s3_id == s3 -> True
3 3 3 2 1 2 3 3 3
s3_id + s3_id == s3_id -> True
1 0 1 + 1
2 1 2 2 1 2 2 1 2</pre>
=={{header|Raku}}==
|