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:',
f' {s0}',showSandPiles(
f'-> {cascaded [(s0)}' ', series[0])] + [
(':', xs) for xs in series[1:]
]
),
'',
f's1 + s2 == s2 + s1 -> {addSand(s1)(s2) == addSand(s2)(s1)}',
f's1 + s2: {addSandshowSandPiles(s1)(s2)}',[
f's2 + s1: {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}',
f's3 + s3_id: {addSandshowSandPiles(s3)(s3_id)}',[
f' (' ', s3: {s3}'),
('+', s3_id),
('=', s3)
]),
'',
f's3_id + s3_id == s3_id -> {addSand(s3_id)(s3_id) == s3_id}',
f's3_id + s3_id: {addSandshowSandPiles(s3_id)(s3_id)}',[
f' (' ', 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(plambda ys: all(y <= w for y in ys))(
nextState(w)
)(concat(xs))
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(
return all lambda ys: any(xy <=> w for xy in xsys),
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.
'''
def pgo(xsx):
v = x
while True:
yield v
v = f(v)
return go
 
Line 1,098 ⟶ 1,183:
{{Out}}
<pre>Cascaded outcome:
[[4, 3, 3], [ 0 4 3, 1, 2],0 4 1 1 [0, 2, 3]]1 0
-> [[3 1 2, : 4 1, 0],2 [0,: 3,4 3],2 [1,2 : 4 2, 3]] : 0 3 3
0 2 3 0 2 3 0 2 3 0 2 3 1 2 3
 
s1 + s2 == s2 + s1 -> True
s1 + s2:1 [[3,2 3,0 3], [3, 2 1, 2],3 [0, 2, 3]] 3 3
s2 + s1:2 [[3,1 3,1 3], [3,+ 1, 2], [0, 2,1 = 3]] 1 2
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
s3 + s3_id: [[3, 3, 3], [3, 3, 3],2 1 2 [3, 3, 3]]
s3: [[3, 3, 3], [3,+ 3,1 3],0 1 = [3, 3, 3]]
3 3 3 2 1 2 3 3 3
 
s3_id + s3_id == s3_id -> True
s3_id + s3_id: [[2, 1, 2], [1, 0, 2 1], [2, 2 1, 2]]
1 0 1 + 1 s3_id: [[2,0 1, 2],= [1, 0, 1], [2, 1, 2]]</pre>
2 1 2 2 1 2 2 1 2</pre>
 
=={{header|Raku}}==
9,659

edits