Abelian sandpile model/Identity: Difference between revisions

Content added Content deleted
(→‎Python :: Functional: Added a display function to sugar test outputs. Added a full cascade sequence.)
Line 934: Line 934:
<lang python>'''Abelian Sandpile'''
<lang python>'''Abelian Sandpile'''


from itertools import takewhile
from functools import reduce
from operator import add
from operator import add


Line 942: Line 944:
'''Tests of cascades and additions'''
'''Tests of cascades and additions'''
s0 = [[4, 3, 3], [3, 1, 2], [0, 2, 3]]
s0 = [[4, 3, 3], [3, 1, 2], [0, 2, 3]]
series = list(cascadeSeries(s0))
s1 = [[1, 2, 0], [2, 1, 1], [0, 1, 3]]
s1 = [[1, 2, 0], [2, 1, 1], [0, 1, 3]]
s2 = [[2, 1, 3], [1, 0, 1], [0, 1, 0]]
s2 = [[2, 1, 3], [1, 0, 1], [0, 1, 0]]
Line 949: Line 952:
for expr in [
for expr in [
'Cascaded outcome:',
'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 == s2 + s1 -> {addSand(s1)(s2) == addSand(s2)(s1)}',
f's1 + s2: {addSand(s1)(s2)}',
showSandPiles([
f's2 + s1: {addSand(s2)(s1)}',
(' ', 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 == s3 -> {addSand(s3)(s3_id) == s3}',
f's3 + s3_id: {addSand(s3)(s3_id)}',
showSandPiles([
f' s3: {s3}',
(' ', s3),
('+', s3_id),
('=', s3)
]),
'',
'',
f's3_id + s3_id == s3_id -> {addSand(s3_id)(s3_id) == s3_id}',
f's3_id + s3_id == s3_id -> {addSand(s3_id)(s3_id) == s3_id}',
f's3_id + s3_id: {addSand(s3_id)(s3_id)}',
showSandPiles([
f' s3_id: {s3_id}',
(' ', s3_id),
('+', s3_id),
('=', addSand(s3_id)(s3_id))
]),

]:
]:
print(expr)
print(expr)
Line 992: Line 1,014:
xs = list(rows)
xs = list(rows)
w = len(xs)
w = len(xs)

def p(xs):
return all(x <= w for x in xs)
return list(chunksOf(w)(
return list(chunksOf(w)(
until(p)(
until(lambda ys: all(y <= w for y in ys))(
nextState(w)
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(
lambda ys: any(y > w for y in ys),
series
)
)) + [list(chunksOf(w)(next(series)))]




Line 1,038: Line 1,077:
)
)
return go
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: Line 1,113:
) if 0 < n else None
) if 0 < n else None
return go
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: Line 1,147:
None
None
)
)
return go


# iterate :: (a -> a) -> a -> Gen [a]
def iterate(f):
'''An infinite list of repeated
applications of f to x.
'''
def go(x):
v = x
while True:
yield v
v = f(v)
return go
return go


Line 1,098: Line 1,183:
{{Out}}
{{Out}}
<pre>Cascaded outcome:
<pre>Cascaded outcome:
[[4, 3, 3], [3, 1, 2], [0, 2, 3]]
4 3 3 0 4 3 1 0 4 1 1 0 2 1 0
-> [[2, 1, 0], [0, 3, 3], [1, 2, 3]]
3 1 2 : 4 1 2 : 4 2 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 == s2 + s1 -> True
s1 + s2: [[3, 3, 3], [3, 1, 2], [0, 2, 3]]
1 2 0 2 1 3 3 3 3
s2 + s1: [[3, 3, 3], [3, 1, 2], [0, 2, 3]]
2 1 1 + 1 0 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 == s3 -> True
s3 + s3_id: [[3, 3, 3], [3, 3, 3], [3, 3, 3]]
3 3 3 2 1 2 3 3 3
s3: [[3, 3, 3], [3, 3, 3], [3, 3, 3]]
3 3 3 + 1 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 == s3_id -> True
s3_id + s3_id: [[2, 1, 2], [1, 0, 1], [2, 1, 2]]
2 1 2 2 1 2 2 1 2
s3_id: [[2, 1, 2], [1, 0, 1], [2, 1, 2]]</pre>
1 0 1 + 1 0 1 = 1 0 1
2 1 2 2 1 2 2 1 2</pre>


=={{header|Raku}}==
=={{header|Raku}}==