Task: Abelian sandpile model_Identity




Go: package main

import (
    "fmt"
    "strconv"
    "strings"
)

type sandpile struct{ a [9]int }

var neighbors = [][]int{
    {1, 3}, {0, 2, 4}, {1, 5}, {0, 4, 6}, {1, 3, 5, 7}, {2, 4, 8}, {3, 7}, {4, 6, 8}, {5, 7},
}


func newSandpile(a [9]int) *sandpile { return &sandpile{a} }

func (s *sandpile) plus(other *sandpile) *sandpile {
    b := [9]int{}
    for i := 0; i < 9; i++ {
        b[i] = s.a[i] + other.a[i]
    }
    return &sandpile{b}
}

func (s *sandpile) isStable() bool {
    for _, e := range s.a {
        if e > 3 {
            return false
        }
    }
    return true
}


func (s *sandpile) topple() {
    for i := 0; i < 9; i++ {
        if s.a[i] > 3 {
            s.a[i] -= 4
            for _, j := range neighbors[i] {
                s.a[j]++
            }
            return
        }
    }
}

func (s *sandpile) String() string {
    var sb strings.Builder
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            sb.WriteString(strconv.Itoa(s.a[3*i+j]) + " ")
        }
        sb.WriteString("\n")
    }
    return sb.String()
}

func main() {
    fmt.Println("Avalanche of topplings:\n")
    s4 := newSandpile([9]int{4, 3, 3, 3, 1, 2, 0, 2, 3})
    fmt.Println(s4)
    for !s4.isStable() {
        s4.topple()
        fmt.Println(s4)
    }

    fmt.Println("Commutative additions:\n")
    s1 := newSandpile([9]int{1, 2, 0, 2, 1, 1, 0, 1, 3})
    s2 := newSandpile([9]int{2, 1, 3, 1, 0, 1, 0, 1, 0})
    s3_a := s1.plus(s2)
    for !s3_a.isStable() {
        s3_a.topple()
    }
    s3_b := s2.plus(s1)
    for !s3_b.isStable() {
        s3_b.topple()
    }
    fmt.Printf("%s\nplus\n\n%s\nequals\n\n%s\n", s1, s2, s3_a)
    fmt.Printf("and\n\n%s\nplus\n\n%s\nalso equals\n\n%s\n", s2, s1, s3_b)

    fmt.Println("Addition of identity sandpile:\n")
    s3 := newSandpile([9]int{3, 3, 3, 3, 3, 3, 3, 3, 3})
    s3_id := newSandpile([9]int{2, 1, 2, 1, 0, 1, 2, 1, 2})
    s4 = s3.plus(s3_id)
    for !s4.isStable() {
        s4.topple()
    }
    fmt.Printf("%s\nplus\n\n%s\nequals\n\n%s\n", s3, s3_id, s4)

    fmt.Println("Addition of identities:\n")
    s5 := s3_id.plus(s3_id)
    for !s5.isStable() {
        s5.topple()
    }
    fmt.Printf("%s\nplus\n\n%s\nequals\n\n%s", s3_id, s3_id, s5)
}




Python: from itertools import product
from collections import defaultdict


class Sandpile():
    def __init__(self, gridtext):
        array = [int(x) for x in gridtext.strip().split()]
        self.grid = defaultdict(int,
                                {(i //3, i % 3): x 
                                 for i, x in enumerate(array)})

    _border = set((r, c) 
                  for r, c in product(range(-1, 4), repeat=2) 
                  if not 0 <= r <= 2 or not 0 <= c <= 2
                  )
    _cell_coords = list(product(range(3), repeat=2))
    
    def topple(self):
        g = self.grid
        for r, c in self._cell_coords:
            if g[(r, c)] >= 4:
                g[(r - 1, c)] += 1
                g[(r + 1, c)] += 1
                g[(r, c - 1)] += 1
                g[(r, c + 1)] += 1
                g[(r, c)] -= 4
                return True
        return False
    
    def stabilise(self):
        while self.topple():
            pass
        
        g = self.grid
        for row_col in self._border.intersection(g.keys()):
            del g[row_col]
        return self
    
    __pos__ = stabilise     
    
    def __eq__(self, other):
        g = self.grid
        return all(g[row_col] == other.grid[row_col]
                   for row_col in self._cell_coords)

    def __add__(self, other):
        g = self.grid
        ans = Sandpile("")
        for row_col in self._cell_coords:
            ans.grid[row_col] = g[row_col] + other.grid[row_col]
        return ans.stabilise()
       
    def __str__(self):
        g, txt = self.grid, []
        for row in range(3):
            txt.append(' '.join(str(g[(row, col)]) 
                                for col in range(3)))
        return '\n'.join(txt)
    
    def __repr__(self):
        return f'{self.__class__.__name__}()'
        

unstable = Sandpile()
s1 = Sandpile()
s2 = Sandpile()
s3 = Sandpile("3 3 3  3 3 3  3 3 3")
s3_id = Sandpile("2 1 2  1 0 1  2 1 2")