Sandpiles¶
Functions and classes for mathematical sandpiles.
Version: 2.4
AUTHOR:
- David Perkinson (June 4, 2015) Upgraded from version 2.3 to 2.4. 
MAJOR CHANGES
- Eliminated dependence on 4ti2, substituting the use of Polyhedron methods. Thus, no optional packages are necessary. 
- Fixed bug in - Sandpile.__init__so that now multigraphs are handled correctly.
- Created - sandpilesto handle examples of Sandpiles in analogy with- graphs,- simplicial_complexes, and- polytopes. In the process, we implemented a much faster way of producing the sandpile grid graph.
- Added support for open and closed sandpile Markov chains. 
- Added support for Weierstrass points. 
- Implemented the Cori-Le Borgne algorithm for computing ranks of divisors on complete graphs. 
NEW METHODS
Sandpile: avalanche_polynomial, genus, group_gens, help, jacobian_representatives, markov_chain, picard_representatives, smith_form, stable_configs, stationary_density, tutte_polynomial.
SandpileConfig: burst_size, help.
SandpileDivisor: help, is_linearly_equivalent, is_q_reduced, is_weierstrass_pt, polytope, polytope_integer_pts, q_reduced, rank, simulate_threshold, stabilize, weierstrass_div, weierstrass_gap_seq, weierstrass_pts, weierstrass_rank_seq.
MINOR CHANGES
- The - sinkargument to- Sandpile.__init__now defaults to the first vertex.
- A SandpileConfig or SandpileDivisor may now be multiplied by an integer. 
- Sped up - __add__method for SandpileConfig and SandpileDivisor.
- Enhanced string representation of a Sandpile (via - _repr_and the- namemethods).
- Recurrents for complete graphs and cycle graphs are computed more quickly. 
- The stabilization code for SandpileConfig has been made more efficient. 
- Added optional probability distribution arguments to - add_randommethods.
- Marshall Hampton (2010-1-10) modified for inclusion as a module within Sage library. 
- David Perkinson (2010-12-14) added show3d(), fixed bug in resolution(), replaced elementary_divisors() with invariant_factors(), added show() for SandpileConfig and SandpileDivisor. 
- David Perkinson (2010-9-18): removed is_undirected, added show(), added verbose arguments to several functions to display SandpileConfigs and divisors as lists of integers 
- David Perkinson (2010-12-19): created separate SandpileConfig, SandpileDivisor, and Sandpile classes 
- David Perkinson (2009-07-15): switched to using config_to_list instead of .values(), thus fixing a few bugs when not using integer labels for vertices. 
- David Perkinson (2009): many undocumented improvements 
- David Perkinson (2008-12-27): initial version 
EXAMPLES:
For general help, enter Sandpile.help(), SandpileConfig.help(), and
SandpileDivisor.help().  Miscellaneous examples appear below.
A weighted directed graph given as a Python dictionary:
sage: from sage.sandpiles import *
sage: g = {0: {},
....:      1: {0: 1, 2: 1, 3: 1},
....:      2: {1: 1, 3: 1, 4: 1},
....:      3: {1: 1, 2: 1, 4: 1},
....:      4: {2: 1, 3: 1}}
>>> from sage.all import *
>>> from sage.sandpiles import *
>>> g = {Integer(0): {},
...      Integer(1): {Integer(0): Integer(1), Integer(2): Integer(1), Integer(3): Integer(1)},
...      Integer(2): {Integer(1): Integer(1), Integer(3): Integer(1), Integer(4): Integer(1)},
...      Integer(3): {Integer(1): Integer(1), Integer(2): Integer(1), Integer(4): Integer(1)},
...      Integer(4): {Integer(2): Integer(1), Integer(3): Integer(1)}}
The associated sandpile with 0 chosen as the sink:
sage: S = Sandpile(g,0)
>>> from sage.all import *
>>> S = Sandpile(g,Integer(0))
Or just:
sage: S = Sandpile(g)
>>> from sage.all import *
>>> S = Sandpile(g)
A picture of the graph:
sage: S.show()                              # long time                             # needs sage.plot
>>> from sage.all import *
>>> S.show()                              # long time                             # needs sage.plot
The relevant Laplacian matrices:
sage: S.laplacian()
[ 0  0  0  0  0]
[-1  3 -1 -1  0]
[ 0 -1  3 -1 -1]
[ 0 -1 -1  3 -1]
[ 0  0 -1 -1  2]
sage: S.reduced_laplacian()
[ 3 -1 -1  0]
[-1  3 -1 -1]
[-1 -1  3 -1]
[ 0 -1 -1  2]
>>> from sage.all import *
>>> S.laplacian()
[ 0  0  0  0  0]
[-1  3 -1 -1  0]
[ 0 -1  3 -1 -1]
[ 0 -1 -1  3 -1]
[ 0  0 -1 -1  2]
>>> S.reduced_laplacian()
[ 3 -1 -1  0]
[-1  3 -1 -1]
[-1 -1  3 -1]
[ 0 -1 -1  2]
The number of elements of the sandpile group for S:
sage: S.group_order()
8
>>> from sage.all import *
>>> S.group_order()
8
The structure of the sandpile group:
sage: S.invariant_factors()
[1, 1, 1, 8]
>>> from sage.all import *
>>> S.invariant_factors()
[1, 1, 1, 8]
The elements of the sandpile group for S:
sage: S.recurrents()
[{1: 2, 2: 2, 3: 2, 4: 1},
 {1: 2, 2: 2, 3: 2, 4: 0},
 {1: 2, 2: 1, 3: 2, 4: 0},
 {1: 2, 2: 2, 3: 0, 4: 1},
 {1: 2, 2: 0, 3: 2, 4: 1},
 {1: 2, 2: 2, 3: 1, 4: 0},
 {1: 2, 2: 1, 3: 2, 4: 1},
 {1: 2, 2: 2, 3: 1, 4: 1}]
>>> from sage.all import *
>>> S.recurrents()
[{1: 2, 2: 2, 3: 2, 4: 1},
 {1: 2, 2: 2, 3: 2, 4: 0},
 {1: 2, 2: 1, 3: 2, 4: 0},
 {1: 2, 2: 2, 3: 0, 4: 1},
 {1: 2, 2: 0, 3: 2, 4: 1},
 {1: 2, 2: 2, 3: 1, 4: 0},
 {1: 2, 2: 1, 3: 2, 4: 1},
 {1: 2, 2: 2, 3: 1, 4: 1}]
The maximal stable element (2 grains of sand on vertices 1, 2, and 3, and 1 grain of sand on vertex 4:
sage: S.max_stable()
{1: 2, 2: 2, 3: 2, 4: 1}
sage: S.max_stable().values()
[2, 2, 2, 1]
>>> from sage.all import *
>>> S.max_stable()
{1: 2, 2: 2, 3: 2, 4: 1}
>>> S.max_stable().values()
[2, 2, 2, 1]
The identity of the sandpile group for S:
sage: S.identity()
{1: 2, 2: 2, 3: 2, 4: 0}
>>> from sage.all import *
>>> S.identity()
{1: 2, 2: 2, 3: 2, 4: 0}
An arbitrary sandpile configuration:
sage: c = SandpileConfig(S,[1,0,4,-3])
sage: c.equivalent_recurrent()
{1: 2, 2: 2, 3: 2, 4: 0}
>>> from sage.all import *
>>> c = SandpileConfig(S,[Integer(1),Integer(0),Integer(4),-Integer(3)])
>>> c.equivalent_recurrent()
{1: 2, 2: 2, 3: 2, 4: 0}
Some group operations:
sage: m = S.max_stable()
sage: i = S.identity()
sage: m.values()
[2, 2, 2, 1]
sage: i.values()
[2, 2, 2, 0]
sage: m + i    # coordinate-wise sum
{1: 4, 2: 4, 3: 4, 4: 1}
sage: m - i
{1: 0, 2: 0, 3: 0, 4: 1}
sage: m & i  # add, then stabilize
{1: 2, 2: 2, 3: 2, 4: 1}
sage: e = m + m
sage: e
{1: 4, 2: 4, 3: 4, 4: 2}
sage: ~e   # stabilize
{1: 2, 2: 2, 3: 2, 4: 0}
sage: a = -m
sage: a & m
{1: 0, 2: 0, 3: 0, 4: 0}
sage: a * m   # add, then find the equivalent recurrent
{1: 2, 2: 2, 3: 2, 4: 0}
sage: a^3  # a*a*a
{1: 2, 2: 2, 3: 2, 4: 1}
sage: a^(-1) == m
True
sage: a < m  # every coordinate of a is < that of m
True
>>> from sage.all import *
>>> m = S.max_stable()
>>> i = S.identity()
>>> m.values()
[2, 2, 2, 1]
>>> i.values()
[2, 2, 2, 0]
>>> m + i    # coordinate-wise sum
{1: 4, 2: 4, 3: 4, 4: 1}
>>> m - i
{1: 0, 2: 0, 3: 0, 4: 1}
>>> m & i  # add, then stabilize
{1: 2, 2: 2, 3: 2, 4: 1}
>>> e = m + m
>>> e
{1: 4, 2: 4, 3: 4, 4: 2}
>>> ~e   # stabilize
{1: 2, 2: 2, 3: 2, 4: 0}
>>> a = -m
>>> a & m
{1: 0, 2: 0, 3: 0, 4: 0}
>>> a * m   # add, then find the equivalent recurrent
{1: 2, 2: 2, 3: 2, 4: 0}
>>> a**Integer(3)  # a*a*a
{1: 2, 2: 2, 3: 2, 4: 1}
>>> a**(-Integer(1)) == m
True
>>> a < m  # every coordinate of a is < that of m
True
Firing an unstable vertex returns resulting configuration:
sage: c = S.max_stable() + S.identity()
sage: c.fire_vertex(1)
{1: 1, 2: 5, 3: 5, 4: 1}
sage: c
{1: 4, 2: 4, 3: 4, 4: 1}
>>> from sage.all import *
>>> c = S.max_stable() + S.identity()
>>> c.fire_vertex(Integer(1))
{1: 1, 2: 5, 3: 5, 4: 1}
>>> c
{1: 4, 2: 4, 3: 4, 4: 1}
Fire all unstable vertices:
sage: c.unstable()
[1, 2, 3]
sage: c.fire_unstable()
{1: 3, 2: 3, 3: 3, 4: 3}
>>> from sage.all import *
>>> c.unstable()
[1, 2, 3]
>>> c.fire_unstable()
{1: 3, 2: 3, 3: 3, 4: 3}
Stabilize c, returning the resulting configuration and the firing vector:
sage: c.stabilize(True)
[{1: 2, 2: 2, 3: 2, 4: 1}, {1: 6, 2: 8, 3: 8, 4: 8}]
sage: c
{1: 4, 2: 4, 3: 4, 4: 1}
sage: S.max_stable() & S.identity() == c.stabilize()
True
>>> from sage.all import *
>>> c.stabilize(True)
[{1: 2, 2: 2, 3: 2, 4: 1}, {1: 6, 2: 8, 3: 8, 4: 8}]
>>> c
{1: 4, 2: 4, 3: 4, 4: 1}
>>> S.max_stable() & S.identity() == c.stabilize()
True
The number of superstable configurations of each degree:
sage: S.h_vector()
[1, 3, 4]
sage: S.postulation()
2
>>> from sage.all import *
>>> S.h_vector()
[1, 3, 4]
>>> S.postulation()
2
the saturated homogeneous toppling ideal:
sage: S.ideal()                                                                     # needs sage.libs.singular
Ideal (x1 - x0, x3*x2 - x0^2, x4^2 - x0^2, x2^3 - x4*x3*x0,
       x4*x2^2 - x3^2*x0, x3^3 - x4*x2*x0, x4*x3^2 - x2^2*x0) of
 Multivariate Polynomial Ring in x4, x3, x2, x1, x0 over Rational Field
>>> from sage.all import *
>>> S.ideal()                                                                     # needs sage.libs.singular
Ideal (x1 - x0, x3*x2 - x0^2, x4^2 - x0^2, x2^3 - x4*x3*x0,
       x4*x2^2 - x3^2*x0, x3^3 - x4*x2*x0, x4*x3^2 - x2^2*x0) of
 Multivariate Polynomial Ring in x4, x3, x2, x1, x0 over Rational Field
its minimal free resolution:
sage: S.resolution()                                                                # needs sage.libs.singular
'R^1 <-- R^7 <-- R^15 <-- R^13 <-- R^4'
>>> from sage.all import *
>>> S.resolution()                                                                # needs sage.libs.singular
'R^1 <-- R^7 <-- R^15 <-- R^13 <-- R^4'
and its Betti numbers:
sage: S.betti()                                                                     # needs sage.libs.singular
           0     1     2     3     4
------------------------------------
    0:     1     1     -     -     -
    1:     -     2     2     -     -
    2:     -     4    13    13     4
------------------------------------
total:     1     7    15    13     4
>>> from sage.all import *
>>> S.betti()                                                                     # needs sage.libs.singular
           0     1     2     3     4
------------------------------------
    0:     1     1     -     -     -
    1:     -     2     2     -     -
    2:     -     4    13    13     4
------------------------------------
total:     1     7    15    13     4
Some various ways of creating Sandpiles:
sage: S = sandpiles.Complete(4) # for more options enter ``sandpile.TAB``
sage: S = sandpiles.Wheel(6)
>>> from sage.all import *
>>> S = sandpiles.Complete(Integer(4)) # for more options enter ``sandpile.TAB``
>>> S = sandpiles.Wheel(Integer(6))
A multidigraph with loops (vertices 0, 1, 2; for example, there is a directed edge from vertex 2 to vertex 1 of weight 3, which can be thought of as three directed edges of the form (2,3). There is also a single loop at vertex 2 and an edge (2,0) of weight 2):
sage: S = Sandpile({0:[1,2], 1:[0,0,2], 2:[0,0,1,1,1,2], 3:[2]})
>>> from sage.all import *
>>> S = Sandpile({Integer(0):[Integer(1),Integer(2)], Integer(1):[Integer(0),Integer(0),Integer(2)], Integer(2):[Integer(0),Integer(0),Integer(1),Integer(1),Integer(1),Integer(2)], Integer(3):[Integer(2)]})
Using the graph library (vertex 1 is specified as the sink; omitting this would make the sink vertex 0 by default):
sage: S = Sandpile(graphs.PetersenGraph(),1)
>>> from sage.all import *
>>> S = Sandpile(graphs.PetersenGraph(),Integer(1))
Distribution of avalanche sizes:
sage: S = sandpiles.Grid(10,10)
sage: m = S.max_stable()
sage: a = []
sage: for i in range(1000):
....:     m = m.add_random()
....:     m, f = m.stabilize(True)
....:     a.append(sum(f.values()))
sage: # needs sage.plot
sage: p = list_plot([[log(i + 1), log(a.count(i))]
....:                for i in [0..max(a)] if a.count(i)])
sage: p.axes_labels(['log(N)', 'log(D(N))'])
sage: t = text("Distribution of avalanche sizes", (2,2), rgbcolor=(1,0,0))
sage: show(p + t, axes_labels=['log(N)', 'log(D(N))'])      # long time
>>> from sage.all import *
>>> S = sandpiles.Grid(Integer(10),Integer(10))
>>> m = S.max_stable()
>>> a = []
>>> for i in range(Integer(1000)):
...     m = m.add_random()
...     m, f = m.stabilize(True)
...     a.append(sum(f.values()))
>>> # needs sage.plot
>>> p = list_plot([[log(i + Integer(1)), log(a.count(i))]
...                for i in (ellipsis_range(Integer(0),Ellipsis,max(a))) if a.count(i)])
>>> p.axes_labels(['log(N)', 'log(D(N))'])
>>> t = text("Distribution of avalanche sizes", (Integer(2),Integer(2)), rgbcolor=(Integer(1),Integer(0),Integer(0)))
>>> show(p + t, axes_labels=['log(N)', 'log(D(N))'])      # long time
Working with sandpile divisors:
sage: S = sandpiles.Complete(4)
sage: D = SandpileDivisor(S, [0,0,0,5])
sage: E = D.stabilize(); E
{0: 1, 1: 1, 2: 1, 3: 2}
sage: D.is_linearly_equivalent(E)
True
sage: D.q_reduced()
{0: 4, 1: 0, 2: 0, 3: 1}
sage: S = sandpiles.Complete(4)
sage: D = SandpileDivisor(S, [0,0,0,5])
sage: E = D.stabilize(); E
{0: 1, 1: 1, 2: 1, 3: 2}
sage: D.is_linearly_equivalent(E)
True
sage: D.q_reduced()
{0: 4, 1: 0, 2: 0, 3: 1}
sage: D.rank()
2
sage: # needs sage.geometry.polyhedron
sage: sorted(D.effective_div(), key=str)
[{0: 0, 1: 0, 2: 0, 3: 5},
 {0: 0, 1: 0, 2: 4, 3: 1},
 {0: 0, 1: 4, 2: 0, 3: 1},
 {0: 1, 1: 1, 2: 1, 3: 2},
 {0: 4, 1: 0, 2: 0, 3: 1}]
sage: sorted(D.effective_div(False))
[[0, 0, 0, 5], [0, 0, 4, 1], [0, 4, 0, 1], [1, 1, 1, 2], [4, 0, 0, 1]]
sage: D.rank()
2
sage: D.rank(True)
(2, {0: 2, 1: 1, 2: 0, 3: 0})
sage: E = D.rank(True)[1]  # E proves the rank is not 3
sage: E.values()
[2, 1, 0, 0]
sage: E.deg()
3
sage: rank(D - E)
-1
sage: (D - E).effective_div()
[]
sage: D.weierstrass_pts()
(0, 1, 2, 3)
sage: D.weierstrass_rank_seq(0)
(2, 1, 0, 0, 0, -1)
sage: D.weierstrass_pts()
(0, 1, 2, 3)
sage: D.weierstrass_rank_seq(0)
(2, 1, 0, 0, 0, -1)
>>> from sage.all import *
>>> S = sandpiles.Complete(Integer(4))
>>> D = SandpileDivisor(S, [Integer(0),Integer(0),Integer(0),Integer(5)])
>>> E = D.stabilize(); E
{0: 1, 1: 1, 2: 1, 3: 2}
>>> D.is_linearly_equivalent(E)
True
>>> D.q_reduced()
{0: 4, 1: 0, 2: 0, 3: 1}
>>> S = sandpiles.Complete(Integer(4))
>>> D = SandpileDivisor(S, [Integer(0),Integer(0),Integer(0),Integer(5)])
>>> E = D.stabilize(); E
{0: 1, 1: 1, 2: 1, 3: 2}
>>> D.is_linearly_equivalent(E)
True
>>> D.q_reduced()
{0: 4, 1: 0, 2: 0, 3: 1}
>>> D.rank()
2
>>> # needs sage.geometry.polyhedron
>>> sorted(D.effective_div(), key=str)
[{0: 0, 1: 0, 2: 0, 3: 5},
 {0: 0, 1: 0, 2: 4, 3: 1},
 {0: 0, 1: 4, 2: 0, 3: 1},
 {0: 1, 1: 1, 2: 1, 3: 2},
 {0: 4, 1: 0, 2: 0, 3: 1}]
>>> sorted(D.effective_div(False))
[[0, 0, 0, 5], [0, 0, 4, 1], [0, 4, 0, 1], [1, 1, 1, 2], [4, 0, 0, 1]]
>>> D.rank()
2
>>> D.rank(True)
(2, {0: 2, 1: 1, 2: 0, 3: 0})
>>> E = D.rank(True)[Integer(1)]  # E proves the rank is not 3
>>> E.values()
[2, 1, 0, 0]
>>> E.deg()
3
>>> rank(D - E)
-1
>>> (D - E).effective_div()
[]
>>> D.weierstrass_pts()
(0, 1, 2, 3)
>>> D.weierstrass_rank_seq(Integer(0))
(2, 1, 0, 0, 0, -1)
>>> D.weierstrass_pts()
(0, 1, 2, 3)
>>> D.weierstrass_rank_seq(Integer(0))
(2, 1, 0, 0, 0, -1)
- class sage.sandpiles.sandpile.Sandpile(g, sink=None)[source]¶
- Bases: - DiGraph- Class for Dhar’s abelian sandpile model. - all_k_config(k)[source]¶
- The constant configuration with all values set to \(k\). - INPUT: - k– integer
 - OUTPUT: SandpileConfig - EXAMPLES: - sage: s = sandpiles.Diamond() sage: s.all_k_config(7) {1: 7, 2: 7, 3: 7} - >>> from sage.all import * >>> s = sandpiles.Diamond() >>> s.all_k_config(Integer(7)) {1: 7, 2: 7, 3: 7} 
 - all_k_div(k)[source]¶
- The divisor with all values set to \(k\). - INPUT: - k– integer
 - OUTPUT: SandpileDivisor - EXAMPLES: - sage: S = sandpiles.House() sage: S.all_k_div(7) {0: 7, 1: 7, 2: 7, 3: 7, 4: 7} - >>> from sage.all import * >>> S = sandpiles.House() >>> S.all_k_div(Integer(7)) {0: 7, 1: 7, 2: 7, 3: 7, 4: 7} 
 - avalanche_polynomial(multivariable=True)[source]¶
- The avalanche polynomial. See NOTE for details. - INPUT: - multivariable– boolean (default:- True)
 - OUTPUT: polynomial - EXAMPLES: - sage: s = sandpiles.Complete(4) sage: s.avalanche_polynomial() # needs sage.combinat 9*x0*x1*x2 + 2*x0*x1 + 2*x0*x2 + 2*x1*x2 + 3*x0 + 3*x1 + 3*x2 + 24 sage: s.avalanche_polynomial(False) # needs sage.combinat 9*x0^3 + 6*x0^2 + 9*x0 + 24 - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(4)) >>> s.avalanche_polynomial() # needs sage.combinat 9*x0*x1*x2 + 2*x0*x1 + 2*x0*x2 + 2*x1*x2 + 3*x0 + 3*x1 + 3*x2 + 24 >>> s.avalanche_polynomial(False) # needs sage.combinat 9*x0^3 + 6*x0^2 + 9*x0 + 24 - Note - For each nonsink vertex \(v\), let \(x_v\) be an indeterminate. If \((r,v)\) is a pair consisting of a recurrent \(r\) and nonsink vertex \(v\), then for each nonsink vertex \(w\), let \(n_w\) be the number of times vertex \(w\) fires in the stabilization of \(r + v\). Let \(M(r,v)\) be the monomial \(\prod_w x_w^{n_w}\), i.e., the exponent records the vector of \(n_w\) as \(w\) ranges over the nonsink vertices. The avalanche polynomial is then the sum of \(M(r,v)\) as \(r\) ranges over the recurrents and \(v\) ranges over the nonsink vertices. If - multivariableis- False, then set all the indeterminates equal to each other (and, thus, only count the number of vertex firings in the stabilizations, forgetting which particular vertices fired).
 - betti(verbose=True)[source]¶
- The Betti table for the homogeneous toppling ideal. If - verboseis- True, it prints the standard Betti table, otherwise, it returns a less formatted table.- INPUT: - verbose– boolean (default:- True)
 - OUTPUT: Betti numbers for the sandpile - EXAMPLES: - sage: S = sandpiles.Diamond() sage: S.betti() # needs sage.libs.singular 0 1 2 3 ------------------------------ 0: 1 - - - 1: - 2 - - 2: - 4 9 4 ------------------------------ total: 1 6 9 4 sage: S.betti(False) # needs sage.libs.singular [1, 6, 9, 4] - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> S.betti() # needs sage.libs.singular 0 1 2 3 ------------------------------ 0: 1 - - - 1: - 2 - - 2: - 4 9 4 ------------------------------ total: 1 6 9 4 >>> S.betti(False) # needs sage.libs.singular [1, 6, 9, 4] 
 - betti_complexes()[source]¶
- The support-complexes with non-trivial homology. (See NOTE.) - OUTPUT: list (of pairs [divisors, corresponding simplicial complex]) - EXAMPLES: - sage: # needs sage.geometry.polyhedron sage: S = Sandpile({0:{},1:{0: 1, 2: 1, 3: 4},2:{3: 5},3:{1: 1, 2: 1}},0) sage: p = S.betti_complexes() sage: p[0] [{0: -8, 1: 5, 2: 4, 3: 1}, Simplicial complex with vertex set (1, 2, 3) and facets {(3,), (1, 2)}] sage: S.resolution() # needs sage.libs.singular 'R^1 <-- R^5 <-- R^5 <-- R^1' sage: S.betti() # needs sage.libs.singular 0 1 2 3 ------------------------------ 0: 1 - - - 1: - 5 5 - 2: - - - 1 ------------------------------ total: 1 5 5 1 sage: len(p) 11 sage: p[0][1].homology() {0: Z, 1: 0} sage: p[-1][1].homology() {0: 0, 1: 0, 2: Z} - >>> from sage.all import * >>> # needs sage.geometry.polyhedron >>> S = Sandpile({Integer(0):{},Integer(1):{Integer(0): Integer(1), Integer(2): Integer(1), Integer(3): Integer(4)},Integer(2):{Integer(3): Integer(5)},Integer(3):{Integer(1): Integer(1), Integer(2): Integer(1)}},Integer(0)) >>> p = S.betti_complexes() >>> p[Integer(0)] [{0: -8, 1: 5, 2: 4, 3: 1}, Simplicial complex with vertex set (1, 2, 3) and facets {(3,), (1, 2)}] >>> S.resolution() # needs sage.libs.singular 'R^1 <-- R^5 <-- R^5 <-- R^1' >>> S.betti() # needs sage.libs.singular 0 1 2 3 ------------------------------ 0: 1 - - - 1: - 5 5 - 2: - - - 1 ------------------------------ total: 1 5 5 1 >>> len(p) 11 >>> p[Integer(0)][Integer(1)].homology() {0: Z, 1: 0} >>> p[-Integer(1)][Integer(1)].homology() {0: 0, 1: 0, 2: Z} - Note - A - support-complexis the simplicial complex formed from the supports of the divisors in a linear system.
 - burning_config()[source]¶
- The minimal burning configuration. - OUTPUT: - dict (configuration) - EXAMPLES: - sage: g = {0:{},1:{0:1,3:1,4:1},2:{0:1,3:1,5:1}, ....: 3:{2:1,5:1},4:{1:1,3:1},5:{2:1,3:1}} sage: S = Sandpile(g,0) sage: S.burning_config() {1: 2, 2: 0, 3: 1, 4: 1, 5: 0} sage: S.burning_config().values() [2, 0, 1, 1, 0] sage: S.burning_script() {1: 1, 2: 3, 3: 5, 4: 1, 5: 4} sage: script = S.burning_script().values() sage: script [1, 3, 5, 1, 4] sage: matrix(script)*S.reduced_laplacian() [2 0 1 1 0] - >>> from sage.all import * >>> g = {Integer(0):{},Integer(1):{Integer(0):Integer(1),Integer(3):Integer(1),Integer(4):Integer(1)},Integer(2):{Integer(0):Integer(1),Integer(3):Integer(1),Integer(5):Integer(1)}, ... Integer(3):{Integer(2):Integer(1),Integer(5):Integer(1)},Integer(4):{Integer(1):Integer(1),Integer(3):Integer(1)},Integer(5):{Integer(2):Integer(1),Integer(3):Integer(1)}} >>> S = Sandpile(g,Integer(0)) >>> S.burning_config() {1: 2, 2: 0, 3: 1, 4: 1, 5: 0} >>> S.burning_config().values() [2, 0, 1, 1, 0] >>> S.burning_script() {1: 1, 2: 3, 3: 5, 4: 1, 5: 4} >>> script = S.burning_script().values() >>> script [1, 3, 5, 1, 4] >>> matrix(script)*S.reduced_laplacian() [2 0 1 1 0] - Note - The burning configuration and script are computed using a modified version of Speer’s script algorithm. This is a generalization to directed multigraphs of Dhar’s burning algorithm. - A burning configuration is a nonnegative integer-linear combination of the rows of the reduced Laplacian matrix having nonnegative entries and such that every vertex has a path from some vertex in its support. The corresponding burning script gives the integer-linear combination needed to obtain the burning configuration. So if \(b\) is the burning configuration, \(\sigma\) is its script, and \(\tilde{L}\) is the reduced Laplacian, then \(\sigma\cdot \tilde{L} = b\). The minimal burning configuration is the one with the minimal script (its components are no larger than the components of any other script for a burning configuration). - The following are equivalent for a configuration \(c\) with burning configuration \(b\) having script \(\sigma\): - \(c\) is recurrent; 
- \(c+b\) stabilizes to \(c\); 
- the firing vector for the stabilization of \(c+b\) is \(\sigma\). 
 
 - burning_script()[source]¶
- A script for the minimal burning configuration. - OUTPUT: dictionary - EXAMPLES: - sage: g = {0:{},1:{0:1,3:1,4:1},2:{0:1,3:1,5:1}, ....: 3:{2:1,5:1},4:{1:1,3:1},5:{2:1,3:1}} sage: S = Sandpile(g,0) sage: S.burning_config() {1: 2, 2: 0, 3: 1, 4: 1, 5: 0} sage: S.burning_config().values() [2, 0, 1, 1, 0] sage: S.burning_script() {1: 1, 2: 3, 3: 5, 4: 1, 5: 4} sage: script = S.burning_script().values() sage: script [1, 3, 5, 1, 4] sage: matrix(script)*S.reduced_laplacian() [2 0 1 1 0] - >>> from sage.all import * >>> g = {Integer(0):{},Integer(1):{Integer(0):Integer(1),Integer(3):Integer(1),Integer(4):Integer(1)},Integer(2):{Integer(0):Integer(1),Integer(3):Integer(1),Integer(5):Integer(1)}, ... Integer(3):{Integer(2):Integer(1),Integer(5):Integer(1)},Integer(4):{Integer(1):Integer(1),Integer(3):Integer(1)},Integer(5):{Integer(2):Integer(1),Integer(3):Integer(1)}} >>> S = Sandpile(g,Integer(0)) >>> S.burning_config() {1: 2, 2: 0, 3: 1, 4: 1, 5: 0} >>> S.burning_config().values() [2, 0, 1, 1, 0] >>> S.burning_script() {1: 1, 2: 3, 3: 5, 4: 1, 5: 4} >>> script = S.burning_script().values() >>> script [1, 3, 5, 1, 4] >>> matrix(script)*S.reduced_laplacian() [2 0 1 1 0] - Note - The burning configuration and script are computed using a modified version of Speer’s script algorithm. This is a generalization to directed multigraphs of Dhar’s burning algorithm. - A burning configuration is a nonnegative integer-linear combination of the rows of the reduced Laplacian matrix having nonnegative entries and such that every vertex has a path from some vertex in its support. The corresponding burning script gives the integer-linear combination needed to obtain the burning configuration. So if \(b\) is the burning configuration, \(s\) is its script, and \(L_{\mathrm{red}}\) is the reduced Laplacian, then \(s\cdot L_{\mathrm{red}}= b\). The minimal burning configuration is the one with the minimal script (its components are no larger than the components of any other script for a burning configuration). - The following are equivalent for a configuration \(c\) with burning configuration \(b\) having script \(s\): - \(c\) is recurrent; 
- \(c+b\) stabilizes to \(c\); 
- the firing vector for the stabilization of \(c+b\) is \(s\). 
 
 - canonical_divisor()[source]¶
- The canonical divisor. This is the divisor with \(\deg(v)-2\) grains of sand on each vertex (not counting loops). Only for undirected graphs. - OUTPUT: SandpileDivisor - EXAMPLES: - sage: S = sandpiles.Complete(4) sage: S.canonical_divisor() {0: 1, 1: 1, 2: 1, 3: 1} sage: s = Sandpile({0:[1,1],1:[0,0,1,1,1]},0) sage: s.canonical_divisor() # loops are disregarded {0: 0, 1: 0} - >>> from sage.all import * >>> S = sandpiles.Complete(Integer(4)) >>> S.canonical_divisor() {0: 1, 1: 1, 2: 1, 3: 1} >>> s = Sandpile({Integer(0):[Integer(1),Integer(1)],Integer(1):[Integer(0),Integer(0),Integer(1),Integer(1),Integer(1)]},Integer(0)) >>> s.canonical_divisor() # loops are disregarded {0: 0, 1: 0} - Warning - The underlying graph must be undirected. 
 - dict()[source]¶
- A dictionary of dictionaries representing a directed graph. - OUTPUT: dictionary - EXAMPLES: - sage: S = sandpiles.Diamond() sage: S.dict() {0: {1: 1, 2: 1}, 1: {0: 1, 2: 1, 3: 1}, 2: {0: 1, 1: 1, 3: 1}, 3: {1: 1, 2: 1}} sage: S.sink() 0 - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> S.dict() {0: {1: 1, 2: 1}, 1: {0: 1, 2: 1, 3: 1}, 2: {0: 1, 1: 1, 3: 1}, 3: {1: 1, 2: 1}} >>> S.sink() 0 
 - genus()[source]¶
- The genus: (# non-loop edges) - (# vertices) + 1. - This is only defined for undirected graphs. - OUTPUT: integer - EXAMPLES: - sage: sandpiles.Complete(4).genus() 3 sage: sandpiles.Cycle(5).genus() 1 - >>> from sage.all import * >>> sandpiles.Complete(Integer(4)).genus() 3 >>> sandpiles.Cycle(Integer(5)).genus() 1 
 - groebner()[source]¶
- A Groebner basis for the homogeneous toppling ideal. It is computed with respect to the standard sandpile ordering (see - ring).- OUTPUT: Groebner basis - EXAMPLES: - sage: S = sandpiles.Diamond() sage: S.groebner() # needs sage.libs.singular [x3*x2^2 - x1^2*x0, x2^3 - x3*x1*x0, x3*x1^2 - x2^2*x0, x1^3 - x3*x2*x0, x3^2 - x0^2, x2*x1 - x0^2] - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> S.groebner() # needs sage.libs.singular [x3*x2^2 - x1^2*x0, x2^3 - x3*x1*x0, x3*x1^2 - x2^2*x0, x1^3 - x3*x2*x0, x3^2 - x0^2, x2*x1 - x0^2] 
 - group_gens(verbose=True)[source]¶
- A minimal list of generators for the sandpile group. - If - verboseis- Falsethen the generators are represented as lists of integers.- INPUT: - verbose– boolean (default:- True)
 - OUTPUT: - list of SandpileConfig (or of lists of integers if - verboseis- False)- EXAMPLES: - sage: s = sandpiles.Cycle(5) sage: s.group_gens() [{1: 0, 2: 1, 3: 1, 4: 1}] sage: s.group_gens()[0].order() 5 sage: s = sandpiles.Complete(5) sage: s.group_gens(False) [[2, 3, 2, 2], [2, 2, 3, 2], [2, 2, 2, 3]] sage: [i.order() for i in s.group_gens()] [5, 5, 5] sage: s.invariant_factors() [1, 5, 5, 5] - >>> from sage.all import * >>> s = sandpiles.Cycle(Integer(5)) >>> s.group_gens() [{1: 0, 2: 1, 3: 1, 4: 1}] >>> s.group_gens()[Integer(0)].order() 5 >>> s = sandpiles.Complete(Integer(5)) >>> s.group_gens(False) [[2, 3, 2, 2], [2, 2, 3, 2], [2, 2, 2, 3]] >>> [i.order() for i in s.group_gens()] [5, 5, 5] >>> s.invariant_factors() [1, 5, 5, 5] 
 - group_order()[source]¶
- The size of the sandpile group. - OUTPUT: integer - EXAMPLES: - sage: S = sandpiles.House() sage: S.group_order() 11 - >>> from sage.all import * >>> S = sandpiles.House() >>> S.group_order() 11 
 - h_vector()[source]¶
- The number of superstable configurations in each degree. Equivalently, this is the list of first differences of the Hilbert function of the (homogeneous) toppling ideal. - OUTPUT: list of nonnegative integers - EXAMPLES: - sage: s = sandpiles.Grid(2,2) sage: s.hilbert_function() [1, 5, 15, 35, 66, 106, 146, 178, 192] sage: s.h_vector() [1, 4, 10, 20, 31, 40, 40, 32, 14] - >>> from sage.all import * >>> s = sandpiles.Grid(Integer(2),Integer(2)) >>> s.hilbert_function() [1, 5, 15, 35, 66, 106, 146, 178, 192] >>> s.h_vector() [1, 4, 10, 20, 31, 40, 40, 32, 14] 
 - static help(verbose=True)[source]¶
- List of Sandpile-specific methods (not inherited from - Graph). If- verbose, include short descriptions.- INPUT: - verbose– boolean (default:- True)
 - OUTPUT: printed string - EXAMPLES: - sage: Sandpile.help() # long time For detailed help with any method FOO listed below, enter "Sandpile.FOO?" or enter "S.FOO?" for any Sandpile S. all_k_config -- The constant configuration with all values set to k. all_k_div -- The divisor with all values set to k. avalanche_polynomial -- The avalanche polynomial. betti -- The Betti table for the homogeneous toppling ideal. betti_complexes -- The support-complexes with non-trivial homology. burning_config -- The minimal burning configuration. burning_script -- A script for the minimal burning configuration. canonical_divisor -- The canonical divisor. dict -- A dictionary of dictionaries representing a directed graph. genus -- The genus: (# non-loop edges) - (# vertices) + 1. groebner -- A Groebner basis for the homogeneous toppling ideal. group_gens -- A minimal list of generators for the sandpile group. group_order -- The size of the sandpile group. h_vector -- The number of superstable configurations in each degree. help -- List of Sandpile-specific methods (not inherited from ...Graph...). hilbert_function -- The Hilbert function of the homogeneous toppling ideal. ideal -- The saturated homogeneous toppling ideal. identity -- The identity configuration. in_degree -- The in-degree of a vertex or a list of all in-degrees. invariant_factors -- The invariant factors of the sandpile group. is_undirected -- Is the underlying graph undirected? jacobian_representatives -- Representatives for the elements of the Jacobian group. laplacian -- The Laplacian matrix of the graph. markov_chain -- The sandpile Markov chain for configurations or divisors. max_stable -- The maximal stable configuration. max_stable_div -- The maximal stable divisor. max_superstables -- The maximal superstable configurations. min_recurrents -- The minimal recurrent elements. nonsink_vertices -- The nonsink vertices. nonspecial_divisors -- The nonspecial divisors. out_degree -- The out-degree of a vertex or a list of all out-degrees. picard_representatives -- Representatives of the divisor classes of degree d in the Picard group. points -- Generators for the multiplicative group of zeros of the sandpile ideal. postulation -- The postulation number of the toppling ideal. recurrents -- The recurrent configurations. reduced_laplacian -- The reduced Laplacian matrix of the graph. reorder_vertices -- A copy of the sandpile with vertex names permuted. resolution -- A minimal free resolution of the homogeneous toppling ideal. ring -- The ring containing the homogeneous toppling ideal. show -- Draw the underlying graph. show3d -- Draw the underlying graph. sink -- The sink vertex. smith_form -- The Smith normal form for the Laplacian. solve -- Approximations of the complex affine zeros of the sandpile ideal. stable_configs -- Generator for all stable configurations. stationary_density -- The stationary density of the sandpile. superstables -- The superstable configurations. symmetric_recurrents -- The symmetric recurrent configurations. tutte_polynomial -- The Tutte polynomial of the underlying graph. unsaturated_ideal -- The unsaturated, homogeneous toppling ideal. version -- The version number of Sage Sandpiles. zero_config -- The all-zero configuration. zero_div -- The all-zero divisor. - >>> from sage.all import * >>> Sandpile.help() # long time For detailed help with any method FOO listed below, enter "Sandpile.FOO?" or enter "S.FOO?" for any Sandpile S. <BLANKLINE> all_k_config -- The constant configuration with all values set to k. all_k_div -- The divisor with all values set to k. avalanche_polynomial -- The avalanche polynomial. betti -- The Betti table for the homogeneous toppling ideal. betti_complexes -- The support-complexes with non-trivial homology. burning_config -- The minimal burning configuration. burning_script -- A script for the minimal burning configuration. canonical_divisor -- The canonical divisor. dict -- A dictionary of dictionaries representing a directed graph. genus -- The genus: (# non-loop edges) - (# vertices) + 1. groebner -- A Groebner basis for the homogeneous toppling ideal. group_gens -- A minimal list of generators for the sandpile group. group_order -- The size of the sandpile group. h_vector -- The number of superstable configurations in each degree. help -- List of Sandpile-specific methods (not inherited from ...Graph...). hilbert_function -- The Hilbert function of the homogeneous toppling ideal. ideal -- The saturated homogeneous toppling ideal. identity -- The identity configuration. in_degree -- The in-degree of a vertex or a list of all in-degrees. invariant_factors -- The invariant factors of the sandpile group. is_undirected -- Is the underlying graph undirected? jacobian_representatives -- Representatives for the elements of the Jacobian group. laplacian -- The Laplacian matrix of the graph. markov_chain -- The sandpile Markov chain for configurations or divisors. max_stable -- The maximal stable configuration. max_stable_div -- The maximal stable divisor. max_superstables -- The maximal superstable configurations. min_recurrents -- The minimal recurrent elements. nonsink_vertices -- The nonsink vertices. nonspecial_divisors -- The nonspecial divisors. out_degree -- The out-degree of a vertex or a list of all out-degrees. picard_representatives -- Representatives of the divisor classes of degree d in the Picard group. points -- Generators for the multiplicative group of zeros of the sandpile ideal. postulation -- The postulation number of the toppling ideal. recurrents -- The recurrent configurations. reduced_laplacian -- The reduced Laplacian matrix of the graph. reorder_vertices -- A copy of the sandpile with vertex names permuted. resolution -- A minimal free resolution of the homogeneous toppling ideal. ring -- The ring containing the homogeneous toppling ideal. show -- Draw the underlying graph. show3d -- Draw the underlying graph. sink -- The sink vertex. smith_form -- The Smith normal form for the Laplacian. solve -- Approximations of the complex affine zeros of the sandpile ideal. stable_configs -- Generator for all stable configurations. stationary_density -- The stationary density of the sandpile. superstables -- The superstable configurations. symmetric_recurrents -- The symmetric recurrent configurations. tutte_polynomial -- The Tutte polynomial of the underlying graph. unsaturated_ideal -- The unsaturated, homogeneous toppling ideal. version -- The version number of Sage Sandpiles. zero_config -- The all-zero configuration. zero_div -- The all-zero divisor. 
 - hilbert_function()[source]¶
- The Hilbert function of the homogeneous toppling ideal. - OUTPUT: list of nonnegative integers - EXAMPLES: - sage: s = sandpiles.Wheel(5) sage: s.hilbert_function() [1, 5, 15, 31, 45] sage: s.h_vector() [1, 4, 10, 16, 14] - >>> from sage.all import * >>> s = sandpiles.Wheel(Integer(5)) >>> s.hilbert_function() [1, 5, 15, 31, 45] >>> s.h_vector() [1, 4, 10, 16, 14] 
 - ideal(gens=False)[source]¶
- The saturated homogeneous toppling ideal. If - gensis- True, the generators for the ideal are returned instead.- INPUT: - gens– boolean (default:- False)
 - OUTPUT: ideal or, optionally, the generators of an ideal - EXAMPLES: - sage: S = sandpiles.Diamond() sage: S.ideal() # needs sage.libs.singular Ideal (x2*x1 - x0^2, x3^2 - x0^2, x1^3 - x3*x2*x0, x3*x1^2 - x2^2*x0, x2^3 - x3*x1*x0, x3*x2^2 - x1^2*x0) of Multivariate Polynomial Ring in x3, x2, x1, x0 over Rational Field sage: S.ideal(True) # needs sage.libs.singular [x2*x1 - x0^2, x3^2 - x0^2, x1^3 - x3*x2*x0, x3*x1^2 - x2^2*x0, x2^3 - x3*x1*x0, x3*x2^2 - x1^2*x0] sage: S.ideal().gens() # another way to get the generators # needs sage.libs.singular [x2*x1 - x0^2, x3^2 - x0^2, x1^3 - x3*x2*x0, x3*x1^2 - x2^2*x0, x2^3 - x3*x1*x0, x3*x2^2 - x1^2*x0] - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> S.ideal() # needs sage.libs.singular Ideal (x2*x1 - x0^2, x3^2 - x0^2, x1^3 - x3*x2*x0, x3*x1^2 - x2^2*x0, x2^3 - x3*x1*x0, x3*x2^2 - x1^2*x0) of Multivariate Polynomial Ring in x3, x2, x1, x0 over Rational Field >>> S.ideal(True) # needs sage.libs.singular [x2*x1 - x0^2, x3^2 - x0^2, x1^3 - x3*x2*x0, x3*x1^2 - x2^2*x0, x2^3 - x3*x1*x0, x3*x2^2 - x1^2*x0] >>> S.ideal().gens() # another way to get the generators # needs sage.libs.singular [x2*x1 - x0^2, x3^2 - x0^2, x1^3 - x3*x2*x0, x3*x1^2 - x2^2*x0, x2^3 - x3*x1*x0, x3*x2^2 - x1^2*x0] 
 - identity(verbose=True)[source]¶
- The identity configuration. - If - verboseis- False, the configuration is converted to a list of integers.- INPUT: - verbose– boolean (default:- True)
 - OUTPUT: SandpileConfig or a list of integers - EXAMPLES: - sage: s = sandpiles.Diamond() sage: s.identity() {1: 2, 2: 2, 3: 0} sage: s.identity(False) [2, 2, 0] sage: s.identity() & s.max_stable() == s.max_stable() True - >>> from sage.all import * >>> s = sandpiles.Diamond() >>> s.identity() {1: 2, 2: 2, 3: 0} >>> s.identity(False) [2, 2, 0] >>> s.identity() & s.max_stable() == s.max_stable() True 
 - in_degree(v=None)[source]¶
- The in-degree of a vertex or a list of all in-degrees. - INPUT: - v– (optional) vertex name
 - OUTPUT: integer or dict - EXAMPLES: - sage: s = sandpiles.House() sage: s.in_degree() {0: 2, 1: 2, 2: 3, 3: 3, 4: 2} sage: s.in_degree(2) 3 - >>> from sage.all import * >>> s = sandpiles.House() >>> s.in_degree() {0: 2, 1: 2, 2: 3, 3: 3, 4: 2} >>> s.in_degree(Integer(2)) 3 
 - invariant_factors()[source]¶
- The invariant factors of the sandpile group. - OUTPUT: list of integers - EXAMPLES: - sage: s = sandpiles.Grid(2,2) sage: s.invariant_factors() [1, 1, 8, 24] - >>> from sage.all import * >>> s = sandpiles.Grid(Integer(2),Integer(2)) >>> s.invariant_factors() [1, 1, 8, 24] 
 - is_undirected()[source]¶
- Is the underlying graph undirected? - Trueif \((u,v)\) is and edge if and only if \((v,u)\) is an edge, each edge with the same weight.- OUTPUT: boolean - EXAMPLES: - sage: sandpiles.Complete(4).is_undirected() True sage: s = Sandpile({0:[1,2], 1:[0,2], 2:[0]}, 0) sage: s.is_undirected() False - >>> from sage.all import * >>> sandpiles.Complete(Integer(4)).is_undirected() True >>> s = Sandpile({Integer(0):[Integer(1),Integer(2)], Integer(1):[Integer(0),Integer(2)], Integer(2):[Integer(0)]}, Integer(0)) >>> s.is_undirected() False 
 - jacobian_representatives(verbose=True)[source]¶
- Representatives for the elements of the Jacobian group. If - verboseis- False, then lists representing the divisors are returned.- INPUT: - verbose– boolean (default:- True)
 - OUTPUT: list of SandpileDivisor (or of lists representing divisors) - EXAMPLES: - For an undirected graph, divisors of the form - s - deg(s)*sinkas- svaries over the superstables forms a distinct set of representatives for the Jacobian group.:- sage: s = sandpiles.Complete(3) sage: s.superstables(False) # needs sage.combinat [[0, 0], [0, 1], [1, 0]] sage: s.jacobian_representatives(False) # needs sage.combinat [[0, 0, 0], [-1, 0, 1], [-1, 1, 0]] - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(3)) >>> s.superstables(False) # needs sage.combinat [[0, 0], [0, 1], [1, 0]] >>> s.jacobian_representatives(False) # needs sage.combinat [[0, 0, 0], [-1, 0, 1], [-1, 1, 0]] - If the graph is directed, the representatives described above may by equivalent modulo the rowspan of the Laplacian matrix: - sage: s = Sandpile({0: {1: 1, 2: 2}, 1: {0: 2, 2: 4}, 2: {0: 4, 1: 2}},0) sage: s.group_order() 28 sage: s.jacobian_representatives() # needs sage.symbolic [{0: -5, 1: 3, 2: 2}, {0: -4, 1: 3, 2: 1}] - >>> from sage.all import * >>> s = Sandpile({Integer(0): {Integer(1): Integer(1), Integer(2): Integer(2)}, Integer(1): {Integer(0): Integer(2), Integer(2): Integer(4)}, Integer(2): {Integer(0): Integer(4), Integer(1): Integer(2)}},Integer(0)) >>> s.group_order() 28 >>> s.jacobian_representatives() # needs sage.symbolic [{0: -5, 1: 3, 2: 2}, {0: -4, 1: 3, 2: 1}] - Let \(\tau\) be the nonnegative generator of the kernel of the transpose of the Laplacian, and let \(\tau_s\) be its sink component, then the sandpile group is isomorphic to the direct sum of the cyclic group of order \(\tau_s\) and the Jacobian group. In the example above, we have: - sage: s.laplacian().left_kernel() Free module of degree 3 and rank 1 over Integer Ring Echelon basis matrix: [14 5 8] - >>> from sage.all import * >>> s.laplacian().left_kernel() Free module of degree 3 and rank 1 over Integer Ring Echelon basis matrix: [14 5 8] - Note - The Jacobian group is the set of all divisors of degree zero modulo the integer rowspan of the Laplacian matrix. 
 - laplacian()[source]¶
- The Laplacian matrix of the graph. - Its rows encode the vertex firing rules. - OUTPUT: matrix - EXAMPLES: - sage: G = sandpiles.Diamond() sage: G.laplacian() [ 2 -1 -1 0] [-1 3 -1 -1] [-1 -1 3 -1] [ 0 -1 -1 2] - >>> from sage.all import * >>> G = sandpiles.Diamond() >>> G.laplacian() [ 2 -1 -1 0] [-1 3 -1 -1] [-1 -1 3 -1] [ 0 -1 -1 2] - Warning - The function - laplacian_matrixshould be avoided. It returns the indegree version of the Laplacian.
 - markov_chain(state, distrib=None)[source]¶
- The sandpile Markov chain for configurations or divisors. The chain starts at - state. See NOTE for details.- INPUT: - state– SandpileConfig, SandpileDivisor, or list representing one of these
- distrib– (optional) list of nonnegative numbers summing to 1 (representing a prob. dist.)
 - OUTPUT: generator for Markov chain (see NOTE) - EXAMPLES: - sage: s = sandpiles.Complete(4) sage: m = s.markov_chain([0,0,0]) sage: next(m) # random {1: 0, 2: 0, 3: 0} sage: next(m).values() # random [0, 0, 0] sage: next(m).values() # random [0, 0, 0] sage: next(m).values() # random [0, 0, 0] sage: next(m).values() # random [0, 1, 0] sage: next(m).values() # random [0, 2, 0] sage: next(m).values() # random [0, 2, 1] sage: next(m).values() # random [1, 2, 1] sage: next(m).values() # random [2, 2, 1] sage: m = s.markov_chain(s.zero_div(), [0.1,0.1,0.1,0.7]) sage: next(m).values() # random [0, 0, 0, 1] sage: next(m).values() # random [0, 0, 1, 1] sage: next(m).values() # random [0, 0, 1, 2] sage: next(m).values() # random [1, 1, 2, 0] sage: next(m).values() # random [1, 1, 2, 1] sage: next(m).values() # random [1, 1, 2, 2] sage: next(m).values() # random [1, 1, 2, 3] sage: next(m).values() # random [1, 1, 2, 4] sage: next(m).values() # random [1, 1, 3, 4] - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(4)) >>> m = s.markov_chain([Integer(0),Integer(0),Integer(0)]) >>> next(m) # random {1: 0, 2: 0, 3: 0} >>> next(m).values() # random [0, 0, 0] >>> next(m).values() # random [0, 0, 0] >>> next(m).values() # random [0, 0, 0] >>> next(m).values() # random [0, 1, 0] >>> next(m).values() # random [0, 2, 0] >>> next(m).values() # random [0, 2, 1] >>> next(m).values() # random [1, 2, 1] >>> next(m).values() # random [2, 2, 1] >>> m = s.markov_chain(s.zero_div(), [RealNumber('0.1'),RealNumber('0.1'),RealNumber('0.1'),RealNumber('0.7')]) >>> next(m).values() # random [0, 0, 0, 1] >>> next(m).values() # random [0, 0, 1, 1] >>> next(m).values() # random [0, 0, 1, 2] >>> next(m).values() # random [1, 1, 2, 0] >>> next(m).values() # random [1, 1, 2, 1] >>> next(m).values() # random [1, 1, 2, 2] >>> next(m).values() # random [1, 1, 2, 3] >>> next(m).values() # random [1, 1, 2, 4] >>> next(m).values() # random [1, 1, 3, 4] - Note - The - closed sandpile Markov chainhas state space consisting of the configurations on a sandpile. It transitions from a state by choosing a vertex at random (according to the probability distribution- distrib), dropping a grain of sand at that vertex, and stabilizing. If the chosen vertex is the sink, the chain stays at the current state.- The - open sandpile Markov chainhas state space consisting of the recurrent elements, i.e., the state space is the sandpile group. It transitions from the configuration \(c\) by choosing a vertex \(v\) at random according to- distrib. The next state is the stabilization of \(c+v\). If \(v\) is the sink vertex, then the stabilization of \(c+v\) is defined to be \(c\).- Note that in either case, if - distribis specified, its length is equal to the total number of vertices (including the sink).- REFERENCES: 
 - max_stable()[source]¶
- The maximal stable configuration. - OUTPUT: SandpileConfig (the maximal stable configuration) - EXAMPLES: - sage: S = sandpiles.House() sage: S.max_stable() {1: 1, 2: 2, 3: 2, 4: 1} - >>> from sage.all import * >>> S = sandpiles.House() >>> S.max_stable() {1: 1, 2: 2, 3: 2, 4: 1} 
 - max_stable_div()[source]¶
- The maximal stable divisor. - OUTPUT: - SandpileDivisor (the maximal stable divisor) - EXAMPLES: - sage: s = sandpiles.Diamond() sage: s.max_stable_div() {0: 1, 1: 2, 2: 2, 3: 1} sage: s.out_degree() {0: 2, 1: 3, 2: 3, 3: 2} - >>> from sage.all import * >>> s = sandpiles.Diamond() >>> s.max_stable_div() {0: 1, 1: 2, 2: 2, 3: 1} >>> s.out_degree() {0: 2, 1: 3, 2: 3, 3: 2} 
 - max_superstables(verbose=True)[source]¶
- The maximal superstable configurations. If the underlying graph is undirected, these are the superstables of highest degree. If - verboseis- False, the configurations are converted to lists of integers.- INPUT: - verbose– boolean (default:- True)
 - OUTPUT: tuple of SandpileConfig - EXAMPLES: - sage: s = sandpiles.Diamond() sage: s.superstables(False) [[0, 0, 0], [0, 0, 1], [1, 0, 1], [0, 2, 0], [2, 0, 0], [0, 1, 1], [1, 0, 0], [0, 1, 0]] sage: s.max_superstables(False) [[1, 0, 1], [0, 2, 0], [2, 0, 0], [0, 1, 1]] sage: s.h_vector() [1, 3, 4] - >>> from sage.all import * >>> s = sandpiles.Diamond() >>> s.superstables(False) [[0, 0, 0], [0, 0, 1], [1, 0, 1], [0, 2, 0], [2, 0, 0], [0, 1, 1], [1, 0, 0], [0, 1, 0]] >>> s.max_superstables(False) [[1, 0, 1], [0, 2, 0], [2, 0, 0], [0, 1, 1]] >>> s.h_vector() [1, 3, 4] 
 - min_recurrents(verbose=True)[source]¶
- The minimal recurrent elements. If the underlying graph is undirected, these are the recurrent elements of least degree. If - verboseis- False, the configurations are converted to lists of integers.- INPUT: - verbose– boolean (default:- True)
 - OUTPUT: list of SandpileConfig - EXAMPLES: - sage: s = sandpiles.Diamond() sage: s.recurrents(False) [[2, 2, 1], [2, 2, 0], [1, 2, 0], [2, 0, 1], [0, 2, 1], [2, 1, 0], [1, 2, 1], [2, 1, 1]] sage: s.min_recurrents(False) [[1, 2, 0], [2, 0, 1], [0, 2, 1], [2, 1, 0]] sage: [i.deg() for i in s.recurrents()] [5, 4, 3, 3, 3, 3, 4, 4] - >>> from sage.all import * >>> s = sandpiles.Diamond() >>> s.recurrents(False) [[2, 2, 1], [2, 2, 0], [1, 2, 0], [2, 0, 1], [0, 2, 1], [2, 1, 0], [1, 2, 1], [2, 1, 1]] >>> s.min_recurrents(False) [[1, 2, 0], [2, 0, 1], [0, 2, 1], [2, 1, 0]] >>> [i.deg() for i in s.recurrents()] [5, 4, 3, 3, 3, 3, 4, 4] 
 - nonsink_vertices()[source]¶
- The nonsink vertices. - OUTPUT: list of vertices - EXAMPLES: - sage: s = sandpiles.Grid(2,3) sage: s.nonsink_vertices() [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3)] - >>> from sage.all import * >>> s = sandpiles.Grid(Integer(2),Integer(3)) >>> s.nonsink_vertices() [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3)] 
 - nonspecial_divisors(verbose=True)[source]¶
- The nonspecial divisors. Only for undirected graphs. (See NOTE.) - INPUT: - verbose– boolean (default:- True)
 - OUTPUT: list (of divisors) - EXAMPLES: - sage: # needs sage.combinat sage: S = sandpiles.Complete(4) sage: ns = S.nonspecial_divisors() sage: D = ns[0] sage: D.values() # needs sage.symbolic [-1, 0, 1, 2] sage: D.deg() # needs sage.symbolic 2 sage: [i.effective_div() for i in ns] [[], [], [], [], [], []] - >>> from sage.all import * >>> # needs sage.combinat >>> S = sandpiles.Complete(Integer(4)) >>> ns = S.nonspecial_divisors() >>> D = ns[Integer(0)] >>> D.values() # needs sage.symbolic [-1, 0, 1, 2] >>> D.deg() # needs sage.symbolic 2 >>> [i.effective_div() for i in ns] [[], [], [], [], [], []] - Note - The “nonspecial divisors” are those divisors of degree \(g-1\) with empty linear system. The term is only defined for undirected graphs. Here, \(g = |E| - |V| + 1\) is the genus of the graph (not counting loops as part of \(|E|\)). If - verboseis- False, the divisors are converted to lists of integers.- Warning - The underlying graph must be undirected. 
 - out_degree(v=None)[source]¶
- The out-degree of a vertex or a list of all out-degrees. - INPUT: - v– (optional) vertex name
 - OUTPUT: integer or dict - EXAMPLES: - sage: s = sandpiles.House() sage: s.out_degree() {0: 2, 1: 2, 2: 3, 3: 3, 4: 2} sage: s.out_degree(2) 3 - >>> from sage.all import * >>> s = sandpiles.House() >>> s.out_degree() {0: 2, 1: 2, 2: 3, 3: 3, 4: 2} >>> s.out_degree(Integer(2)) 3 
 - picard_representatives(d, verbose=True)[source]¶
- Representatives of the divisor classes of degree \(d\) in the Picard group. - (Also see the documentation for - jacobian_representatives.)- INPUT: - d– integer
- verbose– boolean (default:- True)
 - OUTPUT: slist of SandpileDivisors (or lists representing divisors) - EXAMPLES: - sage: s = sandpiles.Complete(3) sage: s.superstables(False) # needs sage.combinat [[0, 0], [0, 1], [1, 0]] sage: s.jacobian_representatives(False) # needs sage.combinat [[0, 0, 0], [-1, 0, 1], [-1, 1, 0]] sage: s.picard_representatives(3,False) # needs sage.combinat [[3, 0, 0], [2, 0, 1], [2, 1, 0]] - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(3)) >>> s.superstables(False) # needs sage.combinat [[0, 0], [0, 1], [1, 0]] >>> s.jacobian_representatives(False) # needs sage.combinat [[0, 0, 0], [-1, 0, 1], [-1, 1, 0]] >>> s.picard_representatives(Integer(3),False) # needs sage.combinat [[3, 0, 0], [2, 0, 1], [2, 1, 0]] 
 - points()[source]¶
- Generators for the multiplicative group of zeros of the sandpile ideal. - OUTPUT: list of complex numbers - EXAMPLES: - The sandpile group in this example is cyclic, and hence there is a single generator for the group of solutions. - sage: S = sandpiles.Complete(4) sage: S.points() # needs sage.symbolic [[-I, I, 1], [-I, 1, I]] - >>> from sage.all import * >>> S = sandpiles.Complete(Integer(4)) >>> S.points() # needs sage.symbolic [[-I, I, 1], [-I, 1, I]] 
 - postulation()[source]¶
- The postulation number of the toppling ideal. This is the largest weight of a superstable configuration of the graph. - OUTPUT: nonnegative integer - EXAMPLES: - sage: s = sandpiles.Complete(4) sage: s.postulation() # needs sage.combinat 3 - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(4)) >>> s.postulation() # needs sage.combinat 3 
 - recurrents(verbose=True)[source]¶
- The recurrent configurations. If - verboseis- False, the configurations are converted to lists of integers.- INPUT: - verbose– boolean (default:- True)
 - OUTPUT: list of recurrent configurations - EXAMPLES: - sage: r = Sandpile(graphs.HouseXGraph(),0).recurrents() sage: r[:3] [{1: 2, 2: 3, 3: 3, 4: 1}, {1: 1, 2: 3, 3: 3, 4: 0}, {1: 1, 2: 3, 3: 3, 4: 1}] sage: sandpiles.Complete(4).recurrents(False) # needs sage.combinat [[2, 2, 2], [2, 2, 1], [2, 1, 2], [1, 2, 2], [2, 2, 0], [2, 0, 2], [0, 2, 2], [2, 1, 1], [1, 2, 1], [1, 1, 2], [2, 1, 0], [2, 0, 1], [1, 2, 0], [1, 0, 2], [0, 2, 1], [0, 1, 2]] sage: sandpiles.Cycle(4).recurrents(False) [[1, 1, 1], [0, 1, 1], [1, 0, 1], [1, 1, 0]] - >>> from sage.all import * >>> r = Sandpile(graphs.HouseXGraph(),Integer(0)).recurrents() >>> r[:Integer(3)] [{1: 2, 2: 3, 3: 3, 4: 1}, {1: 1, 2: 3, 3: 3, 4: 0}, {1: 1, 2: 3, 3: 3, 4: 1}] >>> sandpiles.Complete(Integer(4)).recurrents(False) # needs sage.combinat [[2, 2, 2], [2, 2, 1], [2, 1, 2], [1, 2, 2], [2, 2, 0], [2, 0, 2], [0, 2, 2], [2, 1, 1], [1, 2, 1], [1, 1, 2], [2, 1, 0], [2, 0, 1], [1, 2, 0], [1, 0, 2], [0, 2, 1], [0, 1, 2]] >>> sandpiles.Cycle(Integer(4)).recurrents(False) [[1, 1, 1], [0, 1, 1], [1, 0, 1], [1, 1, 0]] 
 - reduced_laplacian()[source]¶
- The reduced Laplacian matrix of the graph. - OUTPUT: matrix - EXAMPLES: - sage: S = sandpiles.Diamond() sage: S.laplacian() [ 2 -1 -1 0] [-1 3 -1 -1] [-1 -1 3 -1] [ 0 -1 -1 2] sage: S.reduced_laplacian() [ 3 -1 -1] [-1 3 -1] [-1 -1 2] - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> S.laplacian() [ 2 -1 -1 0] [-1 3 -1 -1] [-1 -1 3 -1] [ 0 -1 -1 2] >>> S.reduced_laplacian() [ 3 -1 -1] [-1 3 -1] [-1 -1 2] - Note - This is the Laplacian matrix with the row and column indexed by the sink vertex removed. 
 - reorder_vertices()[source]¶
- A copy of the sandpile with vertex names permuted. - After reordering, vertex \(u\) comes before vertex \(v\) in the list of vertices if \(u\) is closer to the sink. - OUTPUT: Sandpile - EXAMPLES: - sage: S = Sandpile({0:[1], 2:[0,1], 1:[2]}) sage: S.dict() {0: {1: 1}, 1: {2: 1}, 2: {0: 1, 1: 1}} sage: T = S.reorder_vertices() - >>> from sage.all import * >>> S = Sandpile({Integer(0):[Integer(1)], Integer(2):[Integer(0),Integer(1)], Integer(1):[Integer(2)]}) >>> S.dict() {0: {1: 1}, 1: {2: 1}, 2: {0: 1, 1: 1}} >>> T = S.reorder_vertices() - The vertices 1 and 2 have been swapped: - sage: T.dict() {0: {1: 1}, 1: {0: 1, 2: 1}, 2: {0: 1}} - >>> from sage.all import * >>> T.dict() {0: {1: 1}, 1: {0: 1, 2: 1}, 2: {0: 1}} 
 - resolution(verbose=False)[source]¶
- A minimal free resolution of the homogeneous toppling ideal. - If - verboseis- True, then all of the mappings are returned. Otherwise, the resolution is summarized.- INPUT: - verbose– boolean (default:- False)
 - OUTPUT: free resolution of the toppling ideal - EXAMPLES: - sage: # needs sage.libs.singular sage: S = Sandpile({0: {}, 1: {0: 1, 2: 1, 3: 4}, 2: {3: 5}, 3: {1: 1, 2: 1}},0) sage: S.resolution() # a Gorenstein sandpile graph 'R^1 <-- R^5 <-- R^5 <-- R^1' sage: S.resolution(True) [ [ x1^2 - x3*x0 x3*x1 - x2*x0 x3^2 - x2*x1 x2*x3 - x0^2 x2^2 - x1*x0], [ x3 x2 0 x0 0] [ x2^2 - x1*x0] [-x1 -x3 x2 0 -x0] [-x2*x3 + x0^2] [ x0 x1 0 x2 0] [-x3^2 + x2*x1] [ 0 0 -x1 -x3 x2] [x3*x1 - x2*x0] [ 0 0 x0 x1 -x3], [ x1^2 - x3*x0] ] sage: r = S.resolution(True) sage: r[0]*r[1] [0 0 0 0 0] sage: r[1]*r[2] [0] [0] [0] [0] [0] - >>> from sage.all import * >>> # needs sage.libs.singular >>> S = Sandpile({Integer(0): {}, Integer(1): {Integer(0): Integer(1), Integer(2): Integer(1), Integer(3): Integer(4)}, Integer(2): {Integer(3): Integer(5)}, Integer(3): {Integer(1): Integer(1), Integer(2): Integer(1)}},Integer(0)) >>> S.resolution() # a Gorenstein sandpile graph 'R^1 <-- R^5 <-- R^5 <-- R^1' >>> S.resolution(True) [ [ x1^2 - x3*x0 x3*x1 - x2*x0 x3^2 - x2*x1 x2*x3 - x0^2 x2^2 - x1*x0], <BLANKLINE> [ x3 x2 0 x0 0] [ x2^2 - x1*x0] [-x1 -x3 x2 0 -x0] [-x2*x3 + x0^2] [ x0 x1 0 x2 0] [-x3^2 + x2*x1] [ 0 0 -x1 -x3 x2] [x3*x1 - x2*x0] [ 0 0 x0 x1 -x3], [ x1^2 - x3*x0] ] >>> r = S.resolution(True) >>> r[Integer(0)]*r[Integer(1)] [0 0 0 0 0] >>> r[Integer(1)]*r[Integer(2)] [0] [0] [0] [0] [0] 
 - ring()[source]¶
- The ring containing the homogeneous toppling ideal. - OUTPUT: ring - EXAMPLES: - sage: S = sandpiles.Diamond() sage: S.ring() Multivariate Polynomial Ring in x3, x2, x1, x0 over Rational Field sage: S.ring().gens() (x3, x2, x1, x0) - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> S.ring() Multivariate Polynomial Ring in x3, x2, x1, x0 over Rational Field >>> S.ring().gens() (x3, x2, x1, x0) - Note - The indeterminate - xicorresponds to the \(i\)-th vertex as listed my the method- vertices. The term-ordering is degrevlex with indeterminates ordered according to their distance from the sink (larger indeterminates are further from the sink).
 - show(**kwds)[source]¶
- Draw the underlying graph. - INPUT: - kwds– (optional) arguments passed to the show method for Graph or DiGraph
 - EXAMPLES: - sage: S = Sandpile({0:[], 1:[0,3,4], 2:[0,3,5], 3:[2,5], 4:[1,1], 5:[2,4]}) sage: S.show() # needs sage.plot sage: S.show(graph_border=True, edge_labels=True) # needs sage.plot - >>> from sage.all import * >>> S = Sandpile({Integer(0):[], Integer(1):[Integer(0),Integer(3),Integer(4)], Integer(2):[Integer(0),Integer(3),Integer(5)], Integer(3):[Integer(2),Integer(5)], Integer(4):[Integer(1),Integer(1)], Integer(5):[Integer(2),Integer(4)]}) >>> S.show() # needs sage.plot >>> S.show(graph_border=True, edge_labels=True) # needs sage.plot 
 - show3d(**kwds)[source]¶
- Draw the underlying graph. - INPUT: - kwds– (optional) arguments passed to the show method for Graph or DiGraph
 - EXAMPLES: - sage: S = sandpiles.House() sage: S.show3d() # long time # needs sage.plot - >>> from sage.all import * >>> S = sandpiles.House() >>> S.show3d() # long time # needs sage.plot 
 - sink()[source]¶
- The sink vertex. - OUTPUT: sink vertex - EXAMPLES: - sage: G = sandpiles.House() sage: G.sink() 0 sage: H = sandpiles.Grid(2,2) sage: H.sink() (0, 0) sage: type(H.sink()) <... 'tuple'> - >>> from sage.all import * >>> G = sandpiles.House() >>> G.sink() 0 >>> H = sandpiles.Grid(Integer(2),Integer(2)) >>> H.sink() (0, 0) >>> type(H.sink()) <... 'tuple'> 
 - smith_form()[source]¶
- The Smith normal form for the Laplacian. In detail: a list of integer matrices \(D, U, V\) such that \(ULV = D\) where \(L\) is the transpose of the Laplacian, \(D\) is diagonal, and \(U\) and \(V\) are invertible over the integers. - OUTPUT: list of integer matrices - EXAMPLES: - sage: s = sandpiles.Complete(4) sage: D,U,V = s.smith_form() sage: D [1 0 0 0] [0 4 0 0] [0 0 4 0] [0 0 0 0] sage: U*s.laplacian()*V == D # Laplacian symmetric => transpose not necessary True - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(4)) >>> D,U,V = s.smith_form() >>> D [1 0 0 0] [0 4 0 0] [0 0 4 0] [0 0 0 0] >>> U*s.laplacian()*V == D # Laplacian symmetric => transpose not necessary True 
 - solve()[source]¶
- Approximations of the complex affine zeros of the sandpile ideal. - OUTPUT: list of complex numbers - EXAMPLES: - sage: S = Sandpile({0: {}, 1: {2: 2}, 2: {0: 4, 1: 1}}, 0) sage: Z = S.solve(); Z # needs sage.libs.singular [[-0.707107000000000 + 0.707107000000000*I, 0.707107000000000 - 0.707107000000000*I], [-0.707107000000000 - 0.707107000000000*I, 0.707107000000000 + 0.707107000000000*I], [-I, -I], [I, I], [0.707107000000000 + 0.707107000000000*I, -0.707107000000000 - 0.707107000000000*I], [0.707107000000000 - 0.707107000000000*I, -0.707107000000000 + 0.707107000000000*I], [1, 1], [-1, -1]] sage: len(Z) # needs sage.libs.singular 8 sage: S.group_order() 8 - >>> from sage.all import * >>> S = Sandpile({Integer(0): {}, Integer(1): {Integer(2): Integer(2)}, Integer(2): {Integer(0): Integer(4), Integer(1): Integer(1)}}, Integer(0)) >>> Z = S.solve(); Z # needs sage.libs.singular [[-0.707107000000000 + 0.707107000000000*I, 0.707107000000000 - 0.707107000000000*I], [-0.707107000000000 - 0.707107000000000*I, 0.707107000000000 + 0.707107000000000*I], [-I, -I], [I, I], [0.707107000000000 + 0.707107000000000*I, -0.707107000000000 - 0.707107000000000*I], [0.707107000000000 - 0.707107000000000*I, -0.707107000000000 + 0.707107000000000*I], [1, 1], [-1, -1]] >>> len(Z) # needs sage.libs.singular 8 >>> S.group_order() 8 - Note - The solutions form a multiplicative group isomorphic to the sandpile group. Generators for this group are given exactly by - points().
 - stable_configs(smax=None)[source]¶
- Generator for all stable configurations. - If - smaxis provided, then the generator gives all stable configurations less than or equal to- smax. If- smaxdoes not represent a stable configuration, then each component of- smaxis replaced by the corresponding component of the maximal stable configuration.- INPUT: - smax– (optional) SandpileConfig or list representing a SandpileConfig
 - OUTPUT: generator for all stable configurations - EXAMPLES: - sage: s = sandpiles.Complete(3) sage: a = s.stable_configs() sage: next(a) # needs sage.combinat {1: 0, 2: 0} sage: [i.values() for i in a] # needs sage.combinat [[0, 1], [1, 0], [1, 1]] sage: b = s.stable_configs([1,0]) sage: list(b) # needs sage.combinat [{1: 0, 2: 0}, {1: 1, 2: 0}] - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(3)) >>> a = s.stable_configs() >>> next(a) # needs sage.combinat {1: 0, 2: 0} >>> [i.values() for i in a] # needs sage.combinat [[0, 1], [1, 0], [1, 1]] >>> b = s.stable_configs([Integer(1),Integer(0)]) >>> list(b) # needs sage.combinat [{1: 0, 2: 0}, {1: 1, 2: 0}] 
 - stationary_density()[source]¶
- The stationary density of the sandpile. - OUTPUT: rational number - EXAMPLES: - sage: s = sandpiles.Complete(3) sage: s.stationary_density() 10/9 sage: # needs sage.combinat sage: s = Sandpile(digraphs.DeBruijn(2,2),'00') sage: s.stationary_density() 9/8 - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(3)) >>> s.stationary_density() 10/9 >>> # needs sage.combinat >>> s = Sandpile(digraphs.DeBruijn(Integer(2),Integer(2)),'00') >>> s.stationary_density() 9/8 - Note - The stationary density of a sandpile is the sum \(\sum_c (\deg(c) + \deg(s))\) where \(\deg(s)\) is the degree of the sink and the sum is over all recurrent configurations. - REFERENCES: 
 - superstables(verbose=True)[source]¶
- The superstable configurations. If - verboseis- False, the configurations are converted to lists of integers. Superstables for undirected graphs are also known as- G-parking functions.- INPUT: - verbose– boolean (default:- True)
 - OUTPUT: list of SandpileConfig - EXAMPLES: - sage: sp = Sandpile(graphs.HouseXGraph(),0).superstables() sage: sp[:3] [{1: 0, 2: 0, 3: 0, 4: 0}, {1: 1, 2: 0, 3: 0, 4: 1}, {1: 1, 2: 0, 3: 0, 4: 0}] sage: sandpiles.Complete(4).superstables(False) # needs sage.combinat [[0, 0, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 0, 2], [0, 2, 0], [2, 0, 0], [0, 1, 1], [1, 0, 1], [1, 1, 0], [0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]] sage: sandpiles.Cycle(4).superstables(False) [[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]] - >>> from sage.all import * >>> sp = Sandpile(graphs.HouseXGraph(),Integer(0)).superstables() >>> sp[:Integer(3)] [{1: 0, 2: 0, 3: 0, 4: 0}, {1: 1, 2: 0, 3: 0, 4: 1}, {1: 1, 2: 0, 3: 0, 4: 0}] >>> sandpiles.Complete(Integer(4)).superstables(False) # needs sage.combinat [[0, 0, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 0, 2], [0, 2, 0], [2, 0, 0], [0, 1, 1], [1, 0, 1], [1, 1, 0], [0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]] >>> sandpiles.Cycle(Integer(4)).superstables(False) [[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]] 
 - symmetric_recurrents(orbits)[source]¶
- The symmetric recurrent configurations. - INPUT: - orbits– list of lists partitioning the vertices
 - OUTPUT: list of recurrent configurations - EXAMPLES: - sage: S = Sandpile({0: {}, ....: 1: {0: 1, 2: 1, 3: 1}, ....: 2: {1: 1, 3: 1, 4: 1}, ....: 3: {1: 1, 2: 1, 4: 1}, ....: 4: {2: 1, 3: 1}}) sage: S.symmetric_recurrents([[1],[2,3],[4]]) [{1: 2, 2: 2, 3: 2, 4: 1}, {1: 2, 2: 2, 3: 2, 4: 0}] sage: S.recurrents() [{1: 2, 2: 2, 3: 2, 4: 1}, {1: 2, 2: 2, 3: 2, 4: 0}, {1: 2, 2: 1, 3: 2, 4: 0}, {1: 2, 2: 2, 3: 0, 4: 1}, {1: 2, 2: 0, 3: 2, 4: 1}, {1: 2, 2: 2, 3: 1, 4: 0}, {1: 2, 2: 1, 3: 2, 4: 1}, {1: 2, 2: 2, 3: 1, 4: 1}] - >>> from sage.all import * >>> S = Sandpile({Integer(0): {}, ... Integer(1): {Integer(0): Integer(1), Integer(2): Integer(1), Integer(3): Integer(1)}, ... Integer(2): {Integer(1): Integer(1), Integer(3): Integer(1), Integer(4): Integer(1)}, ... Integer(3): {Integer(1): Integer(1), Integer(2): Integer(1), Integer(4): Integer(1)}, ... Integer(4): {Integer(2): Integer(1), Integer(3): Integer(1)}}) >>> S.symmetric_recurrents([[Integer(1)],[Integer(2),Integer(3)],[Integer(4)]]) [{1: 2, 2: 2, 3: 2, 4: 1}, {1: 2, 2: 2, 3: 2, 4: 0}] >>> S.recurrents() [{1: 2, 2: 2, 3: 2, 4: 1}, {1: 2, 2: 2, 3: 2, 4: 0}, {1: 2, 2: 1, 3: 2, 4: 0}, {1: 2, 2: 2, 3: 0, 4: 1}, {1: 2, 2: 0, 3: 2, 4: 1}, {1: 2, 2: 2, 3: 1, 4: 0}, {1: 2, 2: 1, 3: 2, 4: 1}, {1: 2, 2: 2, 3: 1, 4: 1}] - Note - The user is responsible for ensuring that the list of orbits comes from a group of symmetries of the underlying graph. 
 - tutte_polynomial()[source]¶
- The Tutte polynomial of the underlying graph. Only defined for undirected sandpile graphs. - OUTPUT: polynomial - EXAMPLES: - sage: s = sandpiles.Complete(4) sage: s.tutte_polynomial() x^3 + y^3 + 3*x^2 + 4*x*y + 3*y^2 + 2*x + 2*y sage: s.tutte_polynomial().subs(x=1) y^3 + 3*y^2 + 6*y + 6 sage: s.tutte_polynomial().subs(x=1).coefficients() == s.h_vector() # needs sage.combinat True - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(4)) >>> s.tutte_polynomial() x^3 + y^3 + 3*x^2 + 4*x*y + 3*y^2 + 2*x + 2*y >>> s.tutte_polynomial().subs(x=Integer(1)) y^3 + 3*y^2 + 6*y + 6 >>> s.tutte_polynomial().subs(x=Integer(1)).coefficients() == s.h_vector() # needs sage.combinat True 
 - unsaturated_ideal()[source]¶
- The unsaturated, homogeneous toppling ideal. - OUTPUT: ideal - EXAMPLES: - sage: S = sandpiles.Diamond() sage: S.unsaturated_ideal().gens() [x1^3 - x3*x2*x0, x2^3 - x3*x1*x0, x3^2 - x2*x1] sage: S.ideal().gens() # needs sage.libs.singular [x2*x1 - x0^2, x3^2 - x0^2, x1^3 - x3*x2*x0, x3*x1^2 - x2^2*x0, x2^3 - x3*x1*x0, x3*x2^2 - x1^2*x0] - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> S.unsaturated_ideal().gens() [x1^3 - x3*x2*x0, x2^3 - x3*x1*x0, x3^2 - x2*x1] >>> S.ideal().gens() # needs sage.libs.singular [x2*x1 - x0^2, x3^2 - x0^2, x1^3 - x3*x2*x0, x3*x1^2 - x2^2*x0, x2^3 - x3*x1*x0, x3*x2^2 - x1^2*x0] 
 - static version()[source]¶
- The version number of Sage Sandpiles. - OUTPUT: string - EXAMPLES: - sage: Sandpile.version() Sage Sandpiles Version 2.4 sage: S = sandpiles.Complete(3) sage: S.version() Sage Sandpiles Version 2.4 - >>> from sage.all import * >>> Sandpile.version() Sage Sandpiles Version 2.4 >>> S = sandpiles.Complete(Integer(3)) >>> S.version() Sage Sandpiles Version 2.4 
 
- class sage.sandpiles.sandpile.SandpileConfig(S, c)[source]¶
- Bases: - dict- Class for configurations on a sandpile. - add_random(distrib=None)[source]¶
- Add one grain of sand to a random vertex. - Optionally, a probability distribution, - distrib, may be placed on the vertices or the nonsink vertices.- See NOTE for details. - INPUT: - distrib– (optional) list of nonnegative numbers summing to 1 (representing a prob. dist.)
 - OUTPUT: SandpileConfig - EXAMPLES: - sage: s = sandpiles.Complete(4) sage: c = s.zero_config() sage: c.add_random() # random {1: 0, 2: 1, 3: 0} sage: c {1: 0, 2: 0, 3: 0} sage: c.add_random([0.1,0.1,0.8]) # random {1: 0, 2: 0, 3: 1} sage: c.add_random([0.7,0.1,0.1,0.1]) # random {1: 0, 2: 0, 3: 0} - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(4)) >>> c = s.zero_config() >>> c.add_random() # random {1: 0, 2: 1, 3: 0} >>> c {1: 0, 2: 0, 3: 0} >>> c.add_random([RealNumber('0.1'),RealNumber('0.1'),RealNumber('0.8')]) # random {1: 0, 2: 0, 3: 1} >>> c.add_random([RealNumber('0.7'),RealNumber('0.1'),RealNumber('0.1'),RealNumber('0.1')]) # random {1: 0, 2: 0, 3: 0} - We compute the “sizes” of the avalanches caused by adding random grains of sand to the maximal stable configuration on a grid graph. The function - stabilize()returns the firing vector of the stabilization, a dictionary whose values say how many times each vertex fires in the stabilization.:- sage: S = sandpiles.Grid(10,10) sage: m = S.max_stable() sage: a = [] sage: for i in range(1000): ....: m = m.add_random() ....: m, f = m.stabilize(True) ....: a.append(sum(f.values())) sage: # needs sage.plot sage: p = list_plot([[log(i + 1), log(a.count(i))] ....: for i in [0..max(a)] if a.count(i)]) sage: p.axes_labels(['log(N)', 'log(D(N))']) sage: t = text("Distribution of avalanche sizes", (2,2), rgbcolor=(1,0,0)) sage: show(p + t, axes_labels=['log(N)', 'log(D(N))']) # long time - >>> from sage.all import * >>> S = sandpiles.Grid(Integer(10),Integer(10)) >>> m = S.max_stable() >>> a = [] >>> for i in range(Integer(1000)): ... m = m.add_random() ... m, f = m.stabilize(True) ... a.append(sum(f.values())) >>> # needs sage.plot >>> p = list_plot([[log(i + Integer(1)), log(a.count(i))] ... for i in (ellipsis_range(Integer(0),Ellipsis,max(a))) if a.count(i)]) >>> p.axes_labels(['log(N)', 'log(D(N))']) >>> t = text("Distribution of avalanche sizes", (Integer(2),Integer(2)), rgbcolor=(Integer(1),Integer(0),Integer(0))) >>> show(p + t, axes_labels=['log(N)', 'log(D(N))']) # long time - Note - If - distribis- None, then the probability is the uniform probability on the nonsink vertices. Otherwise, there are two possibilities:- (i) the length of - distribis equal to the number of vertices, and- distribrepresents a probability distribution on all of the vertices. In that case, the sink may be chosen at random, in which case, the configuration is unchanged.- (ii) Otherwise, the length of - distribmust be equal to the number of nonsink vertices, and- distribrepresents a probability distribution on the nonsink vertices.- Warning - If - distrib != None, the user is responsible for assuring the sum of its entries is 1 and that its length is equal to the number of sink vertices or the number of nonsink vertices.
 - burst_size(v)[source]¶
- The burst size of the configuration with respect to the given vertex. - INPUT: - v– vertex
 - OUTPUT: integer - EXAMPLES: - sage: s = sandpiles.Diamond() sage: [i.burst_size(0) for i in s.recurrents()] [1, 1, 1, 1, 1, 1, 1, 1] sage: [i.burst_size(1) for i in s.recurrents()] [0, 0, 1, 2, 1, 2, 0, 2] - >>> from sage.all import * >>> s = sandpiles.Diamond() >>> [i.burst_size(Integer(0)) for i in s.recurrents()] [1, 1, 1, 1, 1, 1, 1, 1] >>> [i.burst_size(Integer(1)) for i in s.recurrents()] [0, 0, 1, 2, 1, 2, 0, 2] - Note - To define - c.burst(v), if \(v\) is not the sink, let \(c'\) be the unique recurrent for which the stabilization of \(c' + v\) is \(c\). The burst size is then the amount of sand that goes into the sink during this stabilization. If \(v\) is the sink, the burst size is defined to be 1.- REFERENCES: 
 - deg()[source]¶
- The degree of the configuration. - OUTPUT: integer - EXAMPLES: - sage: S = sandpiles.Complete(3) sage: c = SandpileConfig(S, [1,2]) sage: c.deg() 3 - >>> from sage.all import * >>> S = sandpiles.Complete(Integer(3)) >>> c = SandpileConfig(S, [Integer(1),Integer(2)]) >>> c.deg() 3 
 - dualize()[source]¶
- The difference with the maximal stable configuration. - OUTPUT: SandpileConfig - EXAMPLES: - sage: S = sandpiles.Cycle(3) sage: c = SandpileConfig(S, [1,2]) sage: S.max_stable() {1: 1, 2: 1} sage: c.dualize() {1: 0, 2: -1} sage: S.max_stable() - c == c.dualize() True - >>> from sage.all import * >>> S = sandpiles.Cycle(Integer(3)) >>> c = SandpileConfig(S, [Integer(1),Integer(2)]) >>> S.max_stable() {1: 1, 2: 1} >>> c.dualize() {1: 0, 2: -1} >>> S.max_stable() - c == c.dualize() True 
 - equivalent_recurrent(with_firing_vector=False)[source]¶
- The recurrent configuration equivalent to the given configuration. Optionally, return the corresponding firing vector. - INPUT: - with_firing_vector– boolean (default:- False)
 - OUTPUT: SandpileConfig or [SandpileConfig, firing_vector] - EXAMPLES: - sage: S = sandpiles.Diamond() sage: c = SandpileConfig(S, [0,0,0]) sage: c.equivalent_recurrent() == S.identity() True sage: x = c.equivalent_recurrent(True) sage: r = vector([x[0][v] for v in S.nonsink_vertices()]) sage: f = vector([x[1][v] for v in S.nonsink_vertices()]) sage: cv = vector(c.values()) sage: r == cv - f*S.reduced_laplacian() True - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> c = SandpileConfig(S, [Integer(0),Integer(0),Integer(0)]) >>> c.equivalent_recurrent() == S.identity() True >>> x = c.equivalent_recurrent(True) >>> r = vector([x[Integer(0)][v] for v in S.nonsink_vertices()]) >>> f = vector([x[Integer(1)][v] for v in S.nonsink_vertices()]) >>> cv = vector(c.values()) >>> r == cv - f*S.reduced_laplacian() True - Note - Let \(L\) be the reduced Laplacian, \(c\) the initial configuration, \(r\) the returned configuration, and \(f\) the firing vector. Then \(r = c - f\cdot L\). 
 - equivalent_superstable(with_firing_vector=False)[source]¶
- The equivalent superstable configuration. Optionally, return the corresponding firing vector. - INPUT: - with_firing_vector– boolean (default:- False)
 - OUTPUT: SandpileConfig or [SandpileConfig, firing_vector] - EXAMPLES: - sage: S = sandpiles.Diamond() sage: m = S.max_stable() sage: m.equivalent_superstable().is_superstable() True sage: x = m.equivalent_superstable(True) sage: s = vector(x[0].values()) sage: f = vector(x[1].values()) sage: mv = vector(m.values()) sage: s == mv - f*S.reduced_laplacian() True - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> m = S.max_stable() >>> m.equivalent_superstable().is_superstable() True >>> x = m.equivalent_superstable(True) >>> s = vector(x[Integer(0)].values()) >>> f = vector(x[Integer(1)].values()) >>> mv = vector(m.values()) >>> s == mv - f*S.reduced_laplacian() True - Note - Let \(L\) be the reduced Laplacian, \(c\) the initial configuration, \(s\) the returned configuration, and \(f\) the firing vector. Then \(s = c - f\cdot L\). 
 - fire_script(sigma)[source]¶
- Fire the given script. In other words, fire each vertex the number of times indicated by - sigma.- INPUT: - sigma– SandpileConfig or (list or dict representing a SandpileConfig)
 - OUTPUT: SandpileConfig - EXAMPLES: - sage: S = sandpiles.Cycle(4) sage: c = SandpileConfig(S, [1,2,3]) sage: c.unstable() [2, 3] sage: c.fire_script(SandpileConfig(S,[0,1,1])) {1: 2, 2: 1, 3: 2} sage: c.fire_script(SandpileConfig(S,[2,0,0])) == c.fire_vertex(1).fire_vertex(1) True - >>> from sage.all import * >>> S = sandpiles.Cycle(Integer(4)) >>> c = SandpileConfig(S, [Integer(1),Integer(2),Integer(3)]) >>> c.unstable() [2, 3] >>> c.fire_script(SandpileConfig(S,[Integer(0),Integer(1),Integer(1)])) {1: 2, 2: 1, 3: 2} >>> c.fire_script(SandpileConfig(S,[Integer(2),Integer(0),Integer(0)])) == c.fire_vertex(Integer(1)).fire_vertex(Integer(1)) True 
 - fire_unstable()[source]¶
- Fire all unstable vertices. - OUTPUT: SandpileConfig - EXAMPLES: - sage: S = sandpiles.Cycle(4) sage: c = SandpileConfig(S, [1,2,3]) sage: c.fire_unstable() {1: 2, 2: 1, 3: 2} - >>> from sage.all import * >>> S = sandpiles.Cycle(Integer(4)) >>> c = SandpileConfig(S, [Integer(1),Integer(2),Integer(3)]) >>> c.fire_unstable() {1: 2, 2: 1, 3: 2} 
 - fire_vertex(v)[source]¶
- Fire the given vertex. - INPUT: - v– vertex
 - OUTPUT: SandpileConfig - EXAMPLES: - sage: S = sandpiles.Cycle(3) sage: c = SandpileConfig(S, [1,2]) sage: c.fire_vertex(2) {1: 2, 2: 0} - >>> from sage.all import * >>> S = sandpiles.Cycle(Integer(3)) >>> c = SandpileConfig(S, [Integer(1),Integer(2)]) >>> c.fire_vertex(Integer(2)) {1: 2, 2: 0} 
 - static help(verbose=True)[source]¶
- List of SandpileConfig methods. - If - verbose, include short descriptions.- INPUT: - verbose– boolean (default:- True)
 - OUTPUT: printed string - EXAMPLES: - sage: SandpileConfig.help() Shortcuts for SandpileConfig operations: ~c -- stabilize c & d -- add and stabilize c * c -- add and find equivalent recurrent c^k -- add k times and find equivalent recurrent (taking inverse if k is negative) For detailed help with any method FOO listed below, enter "SandpileConfig.FOO?" or enter "c.FOO?" for any SandpileConfig c. add_random -- Add one grain of sand to a random vertex. burst_size -- The burst size of the configuration with respect to the given vertex. deg -- The degree of the configuration. dualize -- The difference with the maximal stable configuration. equivalent_recurrent -- The recurrent configuration equivalent to the given configuration. equivalent_superstable -- The equivalent superstable configuration. fire_script -- Fire the given script. fire_unstable -- Fire all unstable vertices. fire_vertex -- Fire the given vertex. help -- List of SandpileConfig methods. is_recurrent -- Return whether the configuration is recurrent. is_stable -- Return whether the configuration is stable. is_superstable -- Return whether the configuration is superstable. is_symmetric -- Return whether the configuration is symmetric. order -- The order of the equivalent recurrent element. sandpile -- The configuration's underlying sandpile. show -- Show the configuration. stabilize -- The stabilized configuration. support -- The vertices containing sand. unstable -- The unstable vertices. values -- The values of the configuration as a list. - >>> from sage.all import * >>> SandpileConfig.help() Shortcuts for SandpileConfig operations: ~c -- stabilize c & d -- add and stabilize c * c -- add and find equivalent recurrent c^k -- add k times and find equivalent recurrent (taking inverse if k is negative) <BLANKLINE> For detailed help with any method FOO listed below, enter "SandpileConfig.FOO?" or enter "c.FOO?" for any SandpileConfig c. <BLANKLINE> add_random -- Add one grain of sand to a random vertex. burst_size -- The burst size of the configuration with respect to the given vertex. deg -- The degree of the configuration. dualize -- The difference with the maximal stable configuration. equivalent_recurrent -- The recurrent configuration equivalent to the given configuration. equivalent_superstable -- The equivalent superstable configuration. fire_script -- Fire the given script. fire_unstable -- Fire all unstable vertices. fire_vertex -- Fire the given vertex. help -- List of SandpileConfig methods. is_recurrent -- Return whether the configuration is recurrent. is_stable -- Return whether the configuration is stable. is_superstable -- Return whether the configuration is superstable. is_symmetric -- Return whether the configuration is symmetric. order -- The order of the equivalent recurrent element. sandpile -- The configuration's underlying sandpile. show -- Show the configuration. stabilize -- The stabilized configuration. support -- The vertices containing sand. unstable -- The unstable vertices. values -- The values of the configuration as a list. 
 - is_recurrent()[source]¶
- Return whether the configuration is recurrent. - OUTPUT: boolean - EXAMPLES: - sage: S = sandpiles.Diamond() sage: S.identity().is_recurrent() True sage: S.zero_config().is_recurrent() False - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> S.identity().is_recurrent() True >>> S.zero_config().is_recurrent() False 
 - is_stable()[source]¶
- Return whether the configuration is stable. - OUTPUT: boolean - EXAMPLES: - sage: S = sandpiles.Diamond() sage: S.max_stable().is_stable() True sage: (2*S.max_stable()).is_stable() False sage: (S.max_stable() & S.max_stable()).is_stable() True - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> S.max_stable().is_stable() True >>> (Integer(2)*S.max_stable()).is_stable() False >>> (S.max_stable() & S.max_stable()).is_stable() True 
 - is_superstable()[source]¶
- Return whether the configuration is superstable. - OUTPUT: boolean - EXAMPLES: - sage: S = sandpiles.Diamond() sage: S.zero_config().is_superstable() True - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> S.zero_config().is_superstable() True 
 - is_symmetric(orbits)[source]¶
- Return whether the configuration is symmetric. Return - Trueif the values of the configuration are constant over the vertices in each sublist of- orbits.- INPUT: - orbits– list of lists of vertices
 - OUTPUT: boolean - EXAMPLES: - sage: S = Sandpile({0: {}, ....: 1: {0: 1, 2: 1, 3: 1}, ....: 2: {1: 1, 3: 1, 4: 1}, ....: 3: {1: 1, 2: 1, 4: 1}, ....: 4: {2: 1, 3: 1}}) sage: c = SandpileConfig(S, [1, 2, 2, 3]) sage: c.is_symmetric([[2,3]]) True - >>> from sage.all import * >>> S = Sandpile({Integer(0): {}, ... Integer(1): {Integer(0): Integer(1), Integer(2): Integer(1), Integer(3): Integer(1)}, ... Integer(2): {Integer(1): Integer(1), Integer(3): Integer(1), Integer(4): Integer(1)}, ... Integer(3): {Integer(1): Integer(1), Integer(2): Integer(1), Integer(4): Integer(1)}, ... Integer(4): {Integer(2): Integer(1), Integer(3): Integer(1)}}) >>> c = SandpileConfig(S, [Integer(1), Integer(2), Integer(2), Integer(3)]) >>> c.is_symmetric([[Integer(2),Integer(3)]]) True 
 - order()[source]¶
- The order of the equivalent recurrent element. - OUTPUT: integer - EXAMPLES: - sage: S = sandpiles.Diamond() sage: c = SandpileConfig(S,[2,0,1]) sage: c.order() 4 sage: ~(c + c + c + c) == S.identity() True sage: c = SandpileConfig(S,[1,1,0]) sage: c.order() 1 sage: c.is_recurrent() False sage: c.equivalent_recurrent() == S.identity() True - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> c = SandpileConfig(S,[Integer(2),Integer(0),Integer(1)]) >>> c.order() 4 >>> ~(c + c + c + c) == S.identity() True >>> c = SandpileConfig(S,[Integer(1),Integer(1),Integer(0)]) >>> c.order() 1 >>> c.is_recurrent() False >>> c.equivalent_recurrent() == S.identity() True 
 - sandpile()[source]¶
- The configuration’s underlying sandpile. - OUTPUT: Sandpile - EXAMPLES: - sage: S = sandpiles.Diamond() sage: c = S.identity() sage: c.sandpile() Diamond sandpile graph: 4 vertices, sink = 0 sage: c.sandpile() == S True - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> c = S.identity() >>> c.sandpile() Diamond sandpile graph: 4 vertices, sink = 0 >>> c.sandpile() == S True 
 - show(sink=True, colors=True, heights=False, directed=None, **kwds)[source]¶
- Show the configuration. - INPUT: - sink– boolean (default:- True); whether to show the sink
- colors– boolean (default:- True); whether to color-code the amount of sand on each vertex
- heights– boolean (default:- False); whether to label each vertex with the amount of sand
- directed– (optional) whether to draw directed edges
- kwds– (optional) arguments passed to the show method for Graph
 - EXAMPLES: - sage: S = sandpiles.Diamond() sage: c = S.identity() sage: c.show() # needs sage.plot sage: c.show(directed=False) # needs sage.plot sage: c.show(sink=False, colors=False, heights=True) # needs sage.plot - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> c = S.identity() >>> c.show() # needs sage.plot >>> c.show(directed=False) # needs sage.plot >>> c.show(sink=False, colors=False, heights=True) # needs sage.plot 
 - stabilize(with_firing_vector=False)[source]¶
- The stabilized configuration. Optionally returns the corresponding firing vector. - INPUT: - with_firing_vector– boolean (default:- False)
 - OUTPUT: - SandpileConfigor- [SandpileConfig, firing_vector]- EXAMPLES: - sage: S = sandpiles.House() sage: c = 2*S.max_stable() sage: c._set_stabilize() sage: '_stabilize' in c.__dict__ True sage: S = sandpiles.House() sage: c = S.max_stable() + S.identity() sage: c.stabilize(True) [{1: 1, 2: 2, 3: 2, 4: 1}, {1: 2, 2: 2, 3: 3, 4: 3}] sage: S.max_stable() & S.identity() == c.stabilize() True sage: ~c == c.stabilize() True - >>> from sage.all import * >>> S = sandpiles.House() >>> c = Integer(2)*S.max_stable() >>> c._set_stabilize() >>> '_stabilize' in c.__dict__ True >>> S = sandpiles.House() >>> c = S.max_stable() + S.identity() >>> c.stabilize(True) [{1: 1, 2: 2, 3: 2, 4: 1}, {1: 2, 2: 2, 3: 3, 4: 3}] >>> S.max_stable() & S.identity() == c.stabilize() True >>> ~c == c.stabilize() True 
 - support()[source]¶
- The vertices containing sand. - OUTPUT: list - support of the configuration - EXAMPLES: - sage: S = sandpiles.Diamond() sage: c = S.identity() sage: c {1: 2, 2: 2, 3: 0} sage: c.support() [1, 2] - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> c = S.identity() >>> c {1: 2, 2: 2, 3: 0} >>> c.support() [1, 2] 
 - unstable()[source]¶
- The unstable vertices. - OUTPUT: list of vertices - EXAMPLES: - sage: S = sandpiles.Cycle(4) sage: c = SandpileConfig(S, [1,2,3]) sage: c.unstable() [2, 3] - >>> from sage.all import * >>> S = sandpiles.Cycle(Integer(4)) >>> c = SandpileConfig(S, [Integer(1),Integer(2),Integer(3)]) >>> c.unstable() [2, 3] 
 - values()[source]¶
- The values of the configuration as a list. - The list is sorted in the order of the vertices. - OUTPUT: list of integers - EXAMPLES: - sage: S = Sandpile({'a':['c','b'], 'b':['c','a'], 'c':['a']},'a') sage: c = SandpileConfig(S, {'b':1, 'c':2}) sage: c {'b': 1, 'c': 2} sage: c.values() [1, 2] sage: S.nonsink_vertices() ['b', 'c'] - >>> from sage.all import * >>> S = Sandpile({'a':['c','b'], 'b':['c','a'], 'c':['a']},'a') >>> c = SandpileConfig(S, {'b':Integer(1), 'c':Integer(2)}) >>> c {'b': 1, 'c': 2} >>> c.values() [1, 2] >>> S.nonsink_vertices() ['b', 'c'] 
 
- class sage.sandpiles.sandpile.SandpileDivisor(S, D)[source]¶
- Bases: - dict- Class for divisors on a sandpile. - Dcomplex()[source]¶
- The support-complex. (See NOTE.) - OUTPUT: simplicial complex - EXAMPLES: - sage: # needs sage.geometry.polyhedron sage: S = sandpiles.House() sage: p = SandpileDivisor(S, [1,2,1,0,0]).Dcomplex() sage: p.homology() {0: 0, 1: Z x Z, 2: 0} sage: p.f_vector() [1, 5, 10, 4] sage: p.betti() {0: 1, 1: 2, 2: 0} - >>> from sage.all import * >>> # needs sage.geometry.polyhedron >>> S = sandpiles.House() >>> p = SandpileDivisor(S, [Integer(1),Integer(2),Integer(1),Integer(0),Integer(0)]).Dcomplex() >>> p.homology() {0: 0, 1: Z x Z, 2: 0} >>> p.f_vector() [1, 5, 10, 4] >>> p.betti() {0: 1, 1: 2, 2: 0} - Note - The “support-complex” is the simplicial complex determined by the supports of the linearly equivalent effective divisors. 
 - add_random(distrib=None)[source]¶
- Add one grain of sand to a random vertex. - INPUT: - distrib– (optional) list of nonnegative numbers representing a probability distribution on the vertices
 - OUTPUT: SandpileDivisor - EXAMPLES: - sage: s = sandpiles.Complete(4) sage: D = s.zero_div() sage: D.add_random() # random {0: 0, 1: 0, 2: 1, 3: 0} sage: D.add_random([0.1,0.1,0.1,0.7]) # random {0: 0, 1: 0, 2: 0, 3: 1} - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(4)) >>> D = s.zero_div() >>> D.add_random() # random {0: 0, 1: 0, 2: 1, 3: 0} >>> D.add_random([RealNumber('0.1'),RealNumber('0.1'),RealNumber('0.1'),RealNumber('0.7')]) # random {0: 0, 1: 0, 2: 0, 3: 1} - Warning - If - distribis not- None, the user is responsible for assuring the sum of its entries is 1.
 - betti()[source]¶
- The Betti numbers for the support-complex. (See NOTE.) - OUTPUT: dictionary of integers - EXAMPLES: - sage: S = sandpiles.Cycle(3) sage: D = SandpileDivisor(S, [2,0,1]) sage: D.betti() # needs sage.geometry.polyhedron {0: 1, 1: 1} - >>> from sage.all import * >>> S = sandpiles.Cycle(Integer(3)) >>> D = SandpileDivisor(S, [Integer(2),Integer(0),Integer(1)]) >>> D.betti() # needs sage.geometry.polyhedron {0: 1, 1: 1} - Note - The “support-complex” is the simplicial complex determined by the supports of the linearly equivalent effective divisors. 
 - deg()[source]¶
- The degree of the divisor. - OUTPUT: integer - EXAMPLES: - sage: S = sandpiles.Cycle(3) sage: D = SandpileDivisor(S, [1,2,3]) sage: D.deg() 6 - >>> from sage.all import * >>> S = sandpiles.Cycle(Integer(3)) >>> D = SandpileDivisor(S, [Integer(1),Integer(2),Integer(3)]) >>> D.deg() 6 
 - dualize()[source]¶
- The difference with the maximal stable divisor. - OUTPUT: SandpileDivisor - EXAMPLES: - sage: S = sandpiles.Cycle(3) sage: D = SandpileDivisor(S, [1,2,3]) sage: D.dualize() {0: 0, 1: -1, 2: -2} sage: S.max_stable_div() - D == D.dualize() True - >>> from sage.all import * >>> S = sandpiles.Cycle(Integer(3)) >>> D = SandpileDivisor(S, [Integer(1),Integer(2),Integer(3)]) >>> D.dualize() {0: 0, 1: -1, 2: -2} >>> S.max_stable_div() - D == D.dualize() True 
 - effective_div(verbose=True, with_firing_vectors=False)[source]¶
- All linearly equivalent effective divisors. If - verboseis- False, the divisors are converted to lists of integers. If- with_firing_vectorsis- Truethen a list of firing vectors is also given, each of which prescribes the vertices to be fired in order to obtain an effective divisor.- INPUT: - verbose– boolean (default:- True)
- with_firing_vectors– boolean (default:- False)
 - OUTPUT: list (of divisors) - EXAMPLES: - sage: # needs sage.geometry.polyhedron sage: s = sandpiles.Complete(4) sage: D = SandpileDivisor(s,[4,2,0,0]) sage: sorted(D.effective_div(), key=str) [{0: 0, 1: 2, 2: 0, 3: 4}, {0: 0, 1: 2, 2: 4, 3: 0}, {0: 0, 1: 6, 2: 0, 3: 0}, {0: 1, 1: 3, 2: 1, 3: 1}, {0: 2, 1: 0, 2: 2, 3: 2}, {0: 4, 1: 2, 2: 0, 3: 0}] sage: sorted(D.effective_div(False)) [[0, 2, 0, 4], [0, 2, 4, 0], [0, 6, 0, 0], [1, 3, 1, 1], [2, 0, 2, 2], [4, 2, 0, 0]] sage: sorted(D.effective_div(with_firing_vectors=True), key=str) [({0: 0, 1: 2, 2: 0, 3: 4}, (0, -1, -1, -2)), ({0: 0, 1: 2, 2: 4, 3: 0}, (0, -1, -2, -1)), ({0: 0, 1: 6, 2: 0, 3: 0}, (0, -2, -1, -1)), ({0: 1, 1: 3, 2: 1, 3: 1}, (0, -1, -1, -1)), ({0: 2, 1: 0, 2: 2, 3: 2}, (0, 0, -1, -1)), ({0: 4, 1: 2, 2: 0, 3: 0}, (0, 0, 0, 0))] sage: a = _[2] sage: a[0].values() [0, 6, 0, 0] sage: vector(D.values()) - s.laplacian()*a[1] (0, 6, 0, 0) sage: sorted(D.effective_div(False, True)) [([0, 2, 0, 4], (0, -1, -1, -2)), ([0, 2, 4, 0], (0, -1, -2, -1)), ([0, 6, 0, 0], (0, -2, -1, -1)), ([1, 3, 1, 1], (0, -1, -1, -1)), ([2, 0, 2, 2], (0, 0, -1, -1)), ([4, 2, 0, 0], (0, 0, 0, 0))] sage: D = SandpileDivisor(s,[-1,0,0,0]) sage: D.effective_div(False,True) [] - >>> from sage.all import * >>> # needs sage.geometry.polyhedron >>> s = sandpiles.Complete(Integer(4)) >>> D = SandpileDivisor(s,[Integer(4),Integer(2),Integer(0),Integer(0)]) >>> sorted(D.effective_div(), key=str) [{0: 0, 1: 2, 2: 0, 3: 4}, {0: 0, 1: 2, 2: 4, 3: 0}, {0: 0, 1: 6, 2: 0, 3: 0}, {0: 1, 1: 3, 2: 1, 3: 1}, {0: 2, 1: 0, 2: 2, 3: 2}, {0: 4, 1: 2, 2: 0, 3: 0}] >>> sorted(D.effective_div(False)) [[0, 2, 0, 4], [0, 2, 4, 0], [0, 6, 0, 0], [1, 3, 1, 1], [2, 0, 2, 2], [4, 2, 0, 0]] >>> sorted(D.effective_div(with_firing_vectors=True), key=str) [({0: 0, 1: 2, 2: 0, 3: 4}, (0, -1, -1, -2)), ({0: 0, 1: 2, 2: 4, 3: 0}, (0, -1, -2, -1)), ({0: 0, 1: 6, 2: 0, 3: 0}, (0, -2, -1, -1)), ({0: 1, 1: 3, 2: 1, 3: 1}, (0, -1, -1, -1)), ({0: 2, 1: 0, 2: 2, 3: 2}, (0, 0, -1, -1)), ({0: 4, 1: 2, 2: 0, 3: 0}, (0, 0, 0, 0))] >>> a = _[Integer(2)] >>> a[Integer(0)].values() [0, 6, 0, 0] >>> vector(D.values()) - s.laplacian()*a[Integer(1)] (0, 6, 0, 0) >>> sorted(D.effective_div(False, True)) [([0, 2, 0, 4], (0, -1, -1, -2)), ([0, 2, 4, 0], (0, -1, -2, -1)), ([0, 6, 0, 0], (0, -2, -1, -1)), ([1, 3, 1, 1], (0, -1, -1, -1)), ([2, 0, 2, 2], (0, 0, -1, -1)), ([4, 2, 0, 0], (0, 0, 0, 0))] >>> D = SandpileDivisor(s,[-Integer(1),Integer(0),Integer(0),Integer(0)]) >>> D.effective_div(False,True) [] 
 - fire_script(sigma)[source]¶
- Fire the given script. In other words, fire each vertex the number of times indicated by - sigma.- INPUT: - sigma– SandpileDivisor or (list or dict representing a SandpileDivisor)
 - OUTPUT: SandpileDivisor - EXAMPLES: - sage: S = sandpiles.Cycle(3) sage: D = SandpileDivisor(S, [1,2,3]) sage: D.unstable() [1, 2] sage: D.fire_script([0,1,1]) {0: 3, 1: 1, 2: 2} sage: D.fire_script(SandpileDivisor(S,[2,0,0])) == D.fire_vertex(0).fire_vertex(0) True - >>> from sage.all import * >>> S = sandpiles.Cycle(Integer(3)) >>> D = SandpileDivisor(S, [Integer(1),Integer(2),Integer(3)]) >>> D.unstable() [1, 2] >>> D.fire_script([Integer(0),Integer(1),Integer(1)]) {0: 3, 1: 1, 2: 2} >>> D.fire_script(SandpileDivisor(S,[Integer(2),Integer(0),Integer(0)])) == D.fire_vertex(Integer(0)).fire_vertex(Integer(0)) True 
 - fire_unstable()[source]¶
- Fire all unstable vertices. - OUTPUT: SandpileDivisor - EXAMPLES: - sage: S = sandpiles.Cycle(3) sage: D = SandpileDivisor(S, [1,2,3]) sage: D.fire_unstable() {0: 3, 1: 1, 2: 2} - >>> from sage.all import * >>> S = sandpiles.Cycle(Integer(3)) >>> D = SandpileDivisor(S, [Integer(1),Integer(2),Integer(3)]) >>> D.fire_unstable() {0: 3, 1: 1, 2: 2} 
 - fire_vertex(v)[source]¶
- Fire the given vertex. - INPUT: - v– vertex
 - OUTPUT: SandpileDivisor - EXAMPLES: - sage: S = sandpiles.Cycle(3) sage: D = SandpileDivisor(S, [1,2,3]) sage: D.fire_vertex(1) {0: 2, 1: 0, 2: 4} - >>> from sage.all import * >>> S = sandpiles.Cycle(Integer(3)) >>> D = SandpileDivisor(S, [Integer(1),Integer(2),Integer(3)]) >>> D.fire_vertex(Integer(1)) {0: 2, 1: 0, 2: 4} 
 - static help(verbose=True)[source]¶
- List of SandpileDivisor methods. If - verbose, include short descriptions.- INPUT: - verbose– boolean (default:- True)
 - OUTPUT: printed string - EXAMPLES: - sage: SandpileDivisor.help() For detailed help with any method FOO listed below, enter "SandpileDivisor.FOO?" or enter "D.FOO?" for any SandpileDivisor D. Dcomplex -- The support-complex. add_random -- Add one grain of sand to a random vertex. betti -- The Betti numbers for the support-complex. deg -- The degree of the divisor. dualize -- The difference with the maximal stable divisor. effective_div -- All linearly equivalent effective divisors. fire_script -- Fire the given script. fire_unstable -- Fire all unstable vertices. fire_vertex -- Fire the given vertex. help -- List of SandpileDivisor methods. is_alive -- Return whether the divisor is stabilizable. is_linearly_equivalent -- Return whether the given divisor is linearly equivalent. is_q_reduced -- Return whether the divisor is q-reduced. is_symmetric -- Return whether the divisor is symmetric. is_weierstrass_pt -- Return whether the given vertex is a Weierstrass point. polytope -- The polytope determining the complete linear system. polytope_integer_pts -- The integer points inside divisor's polytope. q_reduced -- The linearly equivalent q-reduced divisor. rank -- The rank of the divisor. sandpile -- The divisor's underlying sandpile. show -- Show the divisor. simulate_threshold -- The first unstabilizable divisor in the closed Markov chain. stabilize -- The stabilization of the divisor. support -- List of vertices at which the divisor is nonzero. unstable -- The unstable vertices. values -- The values of the divisor as a list. weierstrass_div -- The Weierstrass divisor. weierstrass_gap_seq -- The Weierstrass gap sequence at the given vertex. weierstrass_pts -- The Weierstrass points (vertices). weierstrass_rank_seq -- The Weierstrass rank sequence at the given vertex. - >>> from sage.all import * >>> SandpileDivisor.help() For detailed help with any method FOO listed below, enter "SandpileDivisor.FOO?" or enter "D.FOO?" for any SandpileDivisor D. <BLANKLINE> Dcomplex -- The support-complex. add_random -- Add one grain of sand to a random vertex. betti -- The Betti numbers for the support-complex. deg -- The degree of the divisor. dualize -- The difference with the maximal stable divisor. effective_div -- All linearly equivalent effective divisors. fire_script -- Fire the given script. fire_unstable -- Fire all unstable vertices. fire_vertex -- Fire the given vertex. help -- List of SandpileDivisor methods. is_alive -- Return whether the divisor is stabilizable. is_linearly_equivalent -- Return whether the given divisor is linearly equivalent. is_q_reduced -- Return whether the divisor is q-reduced. is_symmetric -- Return whether the divisor is symmetric. is_weierstrass_pt -- Return whether the given vertex is a Weierstrass point. polytope -- The polytope determining the complete linear system. polytope_integer_pts -- The integer points inside divisor's polytope. q_reduced -- The linearly equivalent q-reduced divisor. rank -- The rank of the divisor. sandpile -- The divisor's underlying sandpile. show -- Show the divisor. simulate_threshold -- The first unstabilizable divisor in the closed Markov chain. stabilize -- The stabilization of the divisor. support -- List of vertices at which the divisor is nonzero. unstable -- The unstable vertices. values -- The values of the divisor as a list. weierstrass_div -- The Weierstrass divisor. weierstrass_gap_seq -- The Weierstrass gap sequence at the given vertex. weierstrass_pts -- The Weierstrass points (vertices). weierstrass_rank_seq -- The Weierstrass rank sequence at the given vertex. 
 - is_alive(cycle=False)[source]¶
- Return whether the divisor is stabilizable. In other words, will the divisor stabilize under repeated firings of all unstable vertices? Optionally returns the resulting cycle. - INPUT: - cycle– boolean (default:- False)
 - OUTPUT: boolean or optionally, a list of SandpileDivisors - EXAMPLES: - sage: S = sandpiles.Complete(4) sage: D = SandpileDivisor(S, {0: 4, 1: 3, 2: 3, 3: 2}) sage: D.is_alive() True sage: D.is_alive(True) [{0: 4, 1: 3, 2: 3, 3: 2}, {0: 3, 1: 2, 2: 2, 3: 5}, {0: 1, 1: 4, 2: 4, 3: 3}] - >>> from sage.all import * >>> S = sandpiles.Complete(Integer(4)) >>> D = SandpileDivisor(S, {Integer(0): Integer(4), Integer(1): Integer(3), Integer(2): Integer(3), Integer(3): Integer(2)}) >>> D.is_alive() True >>> D.is_alive(True) [{0: 4, 1: 3, 2: 3, 3: 2}, {0: 3, 1: 2, 2: 2, 3: 5}, {0: 1, 1: 4, 2: 4, 3: 3}] 
 - is_linearly_equivalent(D, with_firing_vector=False)[source]¶
- Return whether the given divisor is linearly equivalent. Optionally, returns the firing vector. (See NOTE.) - INPUT: - D– SandpileDivisor or list, tuple, etc. representing a divisor
- with_firing_vector– boolean (default:- False)
 - OUTPUT: boolean or integer vector - EXAMPLES: - sage: s = sandpiles.Complete(3) sage: D = SandpileDivisor(s,[2,0,0]) sage: D.is_linearly_equivalent([0,1,1]) True sage: D.is_linearly_equivalent([0,1,1],True) (0, -1, -1) sage: v = vector(D.is_linearly_equivalent([0,1,1],True)) sage: vector(D.values()) - s.laplacian()*v (0, 1, 1) sage: D.is_linearly_equivalent([0,0,0]) False sage: D.is_linearly_equivalent([0,0,0],True) () - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(3)) >>> D = SandpileDivisor(s,[Integer(2),Integer(0),Integer(0)]) >>> D.is_linearly_equivalent([Integer(0),Integer(1),Integer(1)]) True >>> D.is_linearly_equivalent([Integer(0),Integer(1),Integer(1)],True) (0, -1, -1) >>> v = vector(D.is_linearly_equivalent([Integer(0),Integer(1),Integer(1)],True)) >>> vector(D.values()) - s.laplacian()*v (0, 1, 1) >>> D.is_linearly_equivalent([Integer(0),Integer(0),Integer(0)]) False >>> D.is_linearly_equivalent([Integer(0),Integer(0),Integer(0)],True) () - Note - If - with_firing_vectoris- False, returns either- Trueor- False.
- If - with_firing_vectoris- Truethen: (i) if- selfis linearly equivalent to \(D\), returns a vector \(v\) such that- self - v*self.laplacian().transpose() = D. Otherwise, (ii) if- selfis not linearly equivalent to \(D\), the output is the empty vector,- ().
 
 - is_q_reduced()[source]¶
- Return whether the divisor is \(q\)-reduced. This would mean that \(self = c + kq\) where \(c\) is superstable, \(k\) is an integer, and \(q\) is the sink vertex. - OUTPUT: boolean - EXAMPLES: - sage: s = sandpiles.Complete(4) sage: D = SandpileDivisor(s,[2,-3,2,0]) sage: D.is_q_reduced() False sage: SandpileDivisor(s,[10,0,1,2]).is_q_reduced() True - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(4)) >>> D = SandpileDivisor(s,[Integer(2),-Integer(3),Integer(2),Integer(0)]) >>> D.is_q_reduced() False >>> SandpileDivisor(s,[Integer(10),Integer(0),Integer(1),Integer(2)]).is_q_reduced() True - For undirected or, more generally, Eulerian graphs, \(q\)-reduced divisors are linearly equivalent if and only if they are equal. The same does not hold for general directed graphs: - sage: s = Sandpile({0:[1],1:[1,1]}) sage: D = SandpileDivisor(s,[-1,1]) sage: Z = s.zero_div() sage: D.is_q_reduced() True sage: Z.is_q_reduced() True sage: D == Z False sage: D.is_linearly_equivalent(Z) True - >>> from sage.all import * >>> s = Sandpile({Integer(0):[Integer(1)],Integer(1):[Integer(1),Integer(1)]}) >>> D = SandpileDivisor(s,[-Integer(1),Integer(1)]) >>> Z = s.zero_div() >>> D.is_q_reduced() True >>> Z.is_q_reduced() True >>> D == Z False >>> D.is_linearly_equivalent(Z) True 
 - is_symmetric(orbits)[source]¶
- Return whether the divisor is symmetric. Return - Trueif the values of the configuration are constant over the vertices in each sublist of- orbits.- INPUT: - orbits– list of lists of vertices
 - OUTPUT: boolean - EXAMPLES: - sage: S = sandpiles.House() sage: S.dict() {0: {1: 1, 2: 1}, 1: {0: 1, 3: 1}, 2: {0: 1, 3: 1, 4: 1}, 3: {1: 1, 2: 1, 4: 1}, 4: {2: 1, 3: 1}} sage: D = SandpileDivisor(S, [0,0,1,1,3]) sage: D.is_symmetric([[2,3], [4]]) True - >>> from sage.all import * >>> S = sandpiles.House() >>> S.dict() {0: {1: 1, 2: 1}, 1: {0: 1, 3: 1}, 2: {0: 1, 3: 1, 4: 1}, 3: {1: 1, 2: 1, 4: 1}, 4: {2: 1, 3: 1}} >>> D = SandpileDivisor(S, [Integer(0),Integer(0),Integer(1),Integer(1),Integer(3)]) >>> D.is_symmetric([[Integer(2),Integer(3)], [Integer(4)]]) True 
 - is_weierstrass_pt(v='sink')[source]¶
- Return whether the given vertex is a Weierstrass point. - INPUT: - v– (default:- sink) vertex
 - OUTPUT: boolean - EXAMPLES: - sage: # needs sage.geometry.polyhedron sage: s = sandpiles.House() sage: K = s.canonical_divisor() sage: K.weierstrass_rank_seq() # sequence at the sink vertex, 0 (1, 0, -1) sage: K.is_weierstrass_pt() False sage: K.weierstrass_rank_seq(4) (1, 0, 0, -1) sage: K.is_weierstrass_pt(4) True - >>> from sage.all import * >>> # needs sage.geometry.polyhedron >>> s = sandpiles.House() >>> K = s.canonical_divisor() >>> K.weierstrass_rank_seq() # sequence at the sink vertex, 0 (1, 0, -1) >>> K.is_weierstrass_pt() False >>> K.weierstrass_rank_seq(Integer(4)) (1, 0, 0, -1) >>> K.is_weierstrass_pt(Integer(4)) True - Note - The vertex \(v\) is a (generalized) Weierstrass point for divisor \(D\) if the sequence of ranks \(r(D - nv)\) for \(n = 0, 1, 2, \dots\) is not \(r(D), r(D)-1, \dots, 0, -1, -1, \dots\) 
 - polytope()[source]¶
- The polytope determining the complete linear system. - OUTPUT: polytope - EXAMPLES: - sage: # needs sage.geometry.polyhedron sage: s = sandpiles.Complete(4) sage: D = SandpileDivisor(s,[4,2,0,0]) sage: p = D.polytope() sage: p.inequalities() (An inequality (-3, 1, 1) x + 2 >= 0, An inequality (1, 1, 1) x + 4 >= 0, An inequality (1, -3, 1) x + 0 >= 0, An inequality (1, 1, -3) x + 0 >= 0) sage: D = SandpileDivisor(s,[-1,0,0,0]) sage: D.polytope() The empty polyhedron in QQ^3 - >>> from sage.all import * >>> # needs sage.geometry.polyhedron >>> s = sandpiles.Complete(Integer(4)) >>> D = SandpileDivisor(s,[Integer(4),Integer(2),Integer(0),Integer(0)]) >>> p = D.polytope() >>> p.inequalities() (An inequality (-3, 1, 1) x + 2 >= 0, An inequality (1, 1, 1) x + 4 >= 0, An inequality (1, -3, 1) x + 0 >= 0, An inequality (1, 1, -3) x + 0 >= 0) >>> D = SandpileDivisor(s,[-Integer(1),Integer(0),Integer(0),Integer(0)]) >>> D.polytope() The empty polyhedron in QQ^3 - Note - For a divisor \(D\), this is the intersection of (i) the polyhedron determined by the system of inequalities \(L^t x \leq D\) where \(L^t\) is the transpose of the Laplacian with (ii) the hyperplane \(x_{\mathrm{sink\_vertex}} = 0\). The polytope is thought of as sitting in \((n-1)\)-dimensional Euclidean space where \(n\) is the number of vertices. 
 - polytope_integer_pts()[source]¶
- The integer points inside divisor’s polytope. The polytope referred to here is the one determining the divisor’s complete linear system (see the documentation for - polytope).- OUTPUT: tuple of integer vectors - EXAMPLES: - sage: s = sandpiles.Complete(4) sage: D = SandpileDivisor(s,[4,2,0,0]) sage: sorted(D.polytope_integer_pts()) # needs sage.geometry.polyhedron [(-2, -1, -1), (-1, -2, -1), (-1, -1, -2), (-1, -1, -1), (0, -1, -1), (0, 0, 0)] sage: D = SandpileDivisor(s,[-1,0,0,0]) sage: D.polytope_integer_pts() # needs sage.geometry.polyhedron () - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(4)) >>> D = SandpileDivisor(s,[Integer(4),Integer(2),Integer(0),Integer(0)]) >>> sorted(D.polytope_integer_pts()) # needs sage.geometry.polyhedron [(-2, -1, -1), (-1, -2, -1), (-1, -1, -2), (-1, -1, -1), (0, -1, -1), (0, 0, 0)] >>> D = SandpileDivisor(s,[-Integer(1),Integer(0),Integer(0),Integer(0)]) >>> D.polytope_integer_pts() # needs sage.geometry.polyhedron () 
 - q_reduced(verbose=True)[source]¶
- The linearly equivalent \(q\)-reduced divisor. - INPUT: - verbose– boolean (default:- True)
 - OUTPUT: SandpileDivisor or list representing SandpileDivisor - EXAMPLES: - sage: s = sandpiles.Complete(4) sage: D = SandpileDivisor(s,[2,-3,2,0]) sage: D.q_reduced() {0: -2, 1: 1, 2: 2, 3: 0} sage: D.q_reduced(False) [-2, 1, 2, 0] - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(4)) >>> D = SandpileDivisor(s,[Integer(2),-Integer(3),Integer(2),Integer(0)]) >>> D.q_reduced() {0: -2, 1: 1, 2: 2, 3: 0} >>> D.q_reduced(False) [-2, 1, 2, 0] - Note - The divisor \(D\) is \(qreduced if `D = c + kq\) where \(c\) is superstable, \(k\) is an integer, and \(q\) is the sink. 
 - rank(with_witness=False)[source]¶
- The rank of the divisor. Optionally returns an effective divisor \(E\) such that \(D - E\) is not winnable (has an empty complete linear system). - INPUT: - with_witness– boolean (default:- False)
 - OUTPUT: integer or (integer, SandpileDivisor) - EXAMPLES: - sage: # needs sage.geometry.polyhedron sage: S = sandpiles.Complete(4) sage: D = SandpileDivisor(S,[4,2,0,0]) sage: D.rank() 3 sage: D.rank(True) (3, {0: 3, 1: 0, 2: 1, 3: 0}) sage: E = _[1] sage: (D - E).rank() # needs sage.rings.number_field -1 Riemann-Roch theorem:: sage: # needs sage.geometry.polyhedron sage: D.rank() - (S.canonical_divisor()-D).rank() == D.deg() + 1 - S.genus() True Riemann-Roch theorem:: sage: # needs sage.geometry.polyhedron sage: D.rank() - (S.canonical_divisor()-D).rank() == D.deg() + 1 - S.genus() True sage: S = Sandpile({0:[1,1,1,2],1:[0,0,0,1,1,1,2,2],2:[2,2,1,1,0]},0) # multigraph with loops sage: D = SandpileDivisor(S,[4,2,0]) sage: D.rank(True) (2, {0: 1, 1: 1, 2: 1}) sage: S = Sandpile({0:[1,2], 1:[0,2,2], 2: [0,1]},0) # directed graph sage: S.is_undirected() False sage: D = SandpileDivisor(S,[0,2,0]) sage: D.effective_div() [{0: 0, 1: 2, 2: 0}, {0: 2, 1: 0, 2: 0}] sage: D.rank(True) (0, {0: 0, 1: 0, 2: 1}) sage: E = D.rank(True)[1] sage: (D - E).effective_div() # needs sage.rings.number_field [] - Note - The rank of a divisor \(D\) is -1 if \(D\) is not linearly equivalent to an effective divisor (i.e., the dollar game represented by \(D\) is unwinnable). Otherwise, the rank of \(D\) is the largest integer \(r\) such that \(D - E\) is linearly equivalent to an effective divisor for all effective divisors \(E\) with \(\deg(E) = r\). 
 - sandpile()[source]¶
- The divisor’s underlying sandpile. - OUTPUT: Sandpile - EXAMPLES: - sage: S = sandpiles.Diamond() sage: D = SandpileDivisor(S,[1,-2,0,3]) sage: D.sandpile() Diamond sandpile graph: 4 vertices, sink = 0 sage: D.sandpile() == S True - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> D = SandpileDivisor(S,[Integer(1),-Integer(2),Integer(0),Integer(3)]) >>> D.sandpile() Diamond sandpile graph: 4 vertices, sink = 0 >>> D.sandpile() == S True 
 - show(heights=True, directed=None, **kwds)[source]¶
- Show the divisor. - INPUT: - heights– boolean (default:- True); whether to label each vertex with the amount of sand
- directed– (optional) whether to draw directed edges
- kwds– (optional) arguments passed to the show method for Graph
 - EXAMPLES: - sage: S = sandpiles.Diamond() sage: D = SandpileDivisor(S, [1,-2,0,2]) sage: D.show(graph_border=True, vertex_size=700, directed=False) # needs sage.plot - >>> from sage.all import * >>> S = sandpiles.Diamond() >>> D = SandpileDivisor(S, [Integer(1),-Integer(2),Integer(0),Integer(2)]) >>> D.show(graph_border=True, vertex_size=Integer(700), directed=False) # needs sage.plot 
 - simulate_threshold(distrib=None)[source]¶
- The first unstabilizable divisor in the closed Markov chain. (See NOTE.) - INPUT: - distrib– (optional) list of nonnegative numbers representing a probability distribution on the vertices
 - OUTPUT: SandpileDivisor - EXAMPLES: - sage: s = sandpiles.Complete(4) sage: D = s.zero_div() sage: D.simulate_threshold() # random {0: 2, 1: 3, 2: 1, 3: 2} sage: n(mean([D.simulate_threshold().deg() for _ in range(10)])) # random 7.10000000000000 sage: n(s.stationary_density()*s.num_verts()) 6.93750000000000 - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(4)) >>> D = s.zero_div() >>> D.simulate_threshold() # random {0: 2, 1: 3, 2: 1, 3: 2} >>> n(mean([D.simulate_threshold().deg() for _ in range(Integer(10))])) # random 7.10000000000000 >>> n(s.stationary_density()*s.num_verts()) 6.93750000000000 - Note - Starting at - self, repeatedly choose a vertex and add a grain of sand to it. Return the first unstabilizable divisor that is reached. Also see the- markov_chainmethod for the underlying sandpile.
 - stabilize(with_firing_vector=False)[source]¶
- The stabilization of the divisor. If not stabilizable, return an error. - INPUT: - with_firing_vector– boolean (default:- False)
 - EXAMPLES: - sage: s = sandpiles.Complete(4) sage: D = SandpileDivisor(s,[0,3,0,0]) sage: D.stabilize() {0: 1, 1: 0, 2: 1, 3: 1} sage: D.stabilize(with_firing_vector=True) [{0: 1, 1: 0, 2: 1, 3: 1}, {0: 0, 1: 1, 2: 0, 3: 0}] - >>> from sage.all import * >>> s = sandpiles.Complete(Integer(4)) >>> D = SandpileDivisor(s,[Integer(0),Integer(3),Integer(0),Integer(0)]) >>> D.stabilize() {0: 1, 1: 0, 2: 1, 3: 1} >>> D.stabilize(with_firing_vector=True) [{0: 1, 1: 0, 2: 1, 3: 1}, {0: 0, 1: 1, 2: 0, 3: 0}] 
 - support()[source]¶
- List of vertices at which the divisor is nonzero. - OUTPUT: list representing the support of the divisor - EXAMPLES: - sage: S = sandpiles.Cycle(4) sage: D = SandpileDivisor(S, [0,0,1,1]) sage: D.support() [2, 3] sage: S.vertices(sort=True) [0, 1, 2, 3] - >>> from sage.all import * >>> S = sandpiles.Cycle(Integer(4)) >>> D = SandpileDivisor(S, [Integer(0),Integer(0),Integer(1),Integer(1)]) >>> D.support() [2, 3] >>> S.vertices(sort=True) [0, 1, 2, 3] 
 - unstable()[source]¶
- The unstable vertices. - OUTPUT: list of vertices - EXAMPLES: - sage: S = sandpiles.Cycle(3) sage: D = SandpileDivisor(S, [1,2,3]) sage: D.unstable() [1, 2] - >>> from sage.all import * >>> S = sandpiles.Cycle(Integer(3)) >>> D = SandpileDivisor(S, [Integer(1),Integer(2),Integer(3)]) >>> D.unstable() [1, 2] 
 - values()[source]¶
- The values of the divisor as a list. - The list is sorted in the order of the vertices. - OUTPUT: list of integers - boolean - EXAMPLES: - sage: S = Sandpile({'a':['c','b'], 'b':['c','a'], 'c':['a']},'a') sage: D = SandpileDivisor(S, {'a':0, 'b':1, 'c':2}) sage: D {'a': 0, 'b': 1, 'c': 2} sage: D.values() [0, 1, 2] sage: S.vertices(sort=True) ['a', 'b', 'c'] - >>> from sage.all import * >>> S = Sandpile({'a':['c','b'], 'b':['c','a'], 'c':['a']},'a') >>> D = SandpileDivisor(S, {'a':Integer(0), 'b':Integer(1), 'c':Integer(2)}) >>> D {'a': 0, 'b': 1, 'c': 2} >>> D.values() [0, 1, 2] >>> S.vertices(sort=True) ['a', 'b', 'c'] 
 - weierstrass_div(verbose=True)[source]¶
- The Weierstrass divisor. Its value at a vertex is the weight of that vertex as a Weierstrass point. (See - SandpileDivisor.weierstrass_gap_seq.)- INPUT: - verbose– boolean (default:- True)
 - OUTPUT: SandpileDivisor - EXAMPLES: - sage: s = sandpiles.Diamond() sage: D = SandpileDivisor(s,[4,2,1,0]) sage: [D.weierstrass_rank_seq(v) for v in s] # needs sage.geometry.polyhedron [(5, 4, 3, 2, 1, 0, 0, -1), (5, 4, 3, 2, 1, 0, -1), (5, 4, 3, 2, 1, 0, 0, 0, -1), (5, 4, 3, 2, 1, 0, 0, -1)] sage: D.weierstrass_div() # needs sage.geometry.polyhedron {0: 1, 1: 0, 2: 2, 3: 1} sage: k5 = sandpiles.Complete(5) sage: K = k5.canonical_divisor() sage: K.weierstrass_div() {0: 9, 1: 9, 2: 9, 3: 9, 4: 9} - >>> from sage.all import * >>> s = sandpiles.Diamond() >>> D = SandpileDivisor(s,[Integer(4),Integer(2),Integer(1),Integer(0)]) >>> [D.weierstrass_rank_seq(v) for v in s] # needs sage.geometry.polyhedron [(5, 4, 3, 2, 1, 0, 0, -1), (5, 4, 3, 2, 1, 0, -1), (5, 4, 3, 2, 1, 0, 0, 0, -1), (5, 4, 3, 2, 1, 0, 0, -1)] >>> D.weierstrass_div() # needs sage.geometry.polyhedron {0: 1, 1: 0, 2: 2, 3: 1} >>> k5 = sandpiles.Complete(Integer(5)) >>> K = k5.canonical_divisor() >>> K.weierstrass_div() {0: 9, 1: 9, 2: 9, 3: 9, 4: 9} 
 - weierstrass_gap_seq(v='sink', weight=True)[source]¶
- The Weierstrass gap sequence at the given vertex. If - weightis- True, then also compute the weight of each gap value.- INPUT: - v– (default:- sink) vertex
- weight– boolean (default:- True)
 - OUTPUT: list or (list of list) of integers - EXAMPLES: - sage: # needs sage.geometry.polyhedron sage: s = sandpiles.Cycle(4) sage: D = SandpileDivisor(s,[2,0,0,0]) sage: [D.weierstrass_gap_seq(v,False) for v in s.vertices(sort=True)] [(1, 3), (1, 2), (1, 3), (1, 2)] sage: [D.weierstrass_gap_seq(v) for v in s.vertices(sort=True)] [((1, 3), 1), ((1, 2), 0), ((1, 3), 1), ((1, 2), 0)] sage: D.weierstrass_gap_seq() # gap sequence at sink vertex, 0 ((1, 3), 1) sage: D.weierstrass_rank_seq() # rank sequence at the sink vertex (1, 0, 0, -1) - >>> from sage.all import * >>> # needs sage.geometry.polyhedron >>> s = sandpiles.Cycle(Integer(4)) >>> D = SandpileDivisor(s,[Integer(2),Integer(0),Integer(0),Integer(0)]) >>> [D.weierstrass_gap_seq(v,False) for v in s.vertices(sort=True)] [(1, 3), (1, 2), (1, 3), (1, 2)] >>> [D.weierstrass_gap_seq(v) for v in s.vertices(sort=True)] [((1, 3), 1), ((1, 2), 0), ((1, 3), 1), ((1, 2), 0)] >>> D.weierstrass_gap_seq() # gap sequence at sink vertex, 0 ((1, 3), 1) >>> D.weierstrass_rank_seq() # rank sequence at the sink vertex (1, 0, 0, -1) - Note - The integer \(k\) is a Weierstrass gap for the divisor \(D\) at vertex \(v\) if the rank of \(D - (k-1)v\) does not equal the rank of \(D - kv\). Let \(r\) be the rank of \(D\) and let \(k_i\) be the \(i\)-th gap at \(v\). The Weierstrass weight of \(v\) for \(D\) is the sum of \((k_i - i)\) as \(i\) ranges from \(1\) to \(r + 1\). It measure the difference between the sequence \(r, r - 1, ..., 0, -1, -1, ...\) and the rank sequence \(\mathrm{rank}(D), \mathrm{rank}(D - v), \mathrm{rank}(D - 2v), \dots\) 
 - weierstrass_pts(with_rank_seq=False)[source]¶
- The Weierstrass points (vertices). Optionally, return the corresponding rank sequences. - INPUT: - with_rank_seq– boolean (default:- False)
 - OUTPUT: tuple of vertices or list of (vertex, rank sequence) - EXAMPLES: - sage: s = sandpiles.House() sage: K = s.canonical_divisor() sage: K.weierstrass_pts() # needs sage.geometry.polyhedron (4,) sage: K.weierstrass_pts(True) # needs sage.geometry.polyhedron [(4, (1, 0, 0, -1))] - >>> from sage.all import * >>> s = sandpiles.House() >>> K = s.canonical_divisor() >>> K.weierstrass_pts() # needs sage.geometry.polyhedron (4,) >>> K.weierstrass_pts(True) # needs sage.geometry.polyhedron [(4, (1, 0, 0, -1))] - Note - The vertex \(v\) is a (generalized) Weierstrass point for divisor \(D\) if the sequence of ranks \(r(D - nv)\) for \(n = 0, 1, 2, \dots`\) is not \(r(D), r(D)-1, \dots, 0, -1, -1, \dots\) 
 - weierstrass_rank_seq(v='sink')[source]¶
- The Weierstrass rank sequence at the given vertex. Computes the rank of the divisor \(D - nv\) starting with \(n=0\) and ending when the rank is \(-1\). - INPUT: - v– (default:- sink) vertex
 - OUTPUT: tuple of int - EXAMPLES: - sage: s = sandpiles.House() sage: K = s.canonical_divisor() sage: [K.weierstrass_rank_seq(v) for v in s.vertices(sort=True)] # needs sage.geometry.polyhedron [(1, 0, -1), (1, 0, -1), (1, 0, -1), (1, 0, -1), (1, 0, 0, -1)] - >>> from sage.all import * >>> s = sandpiles.House() >>> K = s.canonical_divisor() >>> [K.weierstrass_rank_seq(v) for v in s.vertices(sort=True)] # needs sage.geometry.polyhedron [(1, 0, -1), (1, 0, -1), (1, 0, -1), (1, 0, -1), (1, 0, 0, -1)] 
 
- sage.sandpiles.sandpile.admissible_partitions(S, k)[source]¶
- The partitions of the vertices of \(S\) into \(k\) parts, each of which is connected. - INPUT: - S– Sandpile
- k– integer
 - OUTPUT: partitions - EXAMPLES: - sage: from sage.sandpiles.sandpile import admissible_partitions sage: from sage.sandpiles.sandpile import partition_sandpile sage: S = sandpiles.Cycle(4) sage: P = [list(admissible_partitions(S, i)) for i in [2,3,4]] # needs sage.combinat sage: P # needs sage.combinat [[{{0, 2, 3}, {1}}, {{0, 3}, {1, 2}}, {{0, 1, 3}, {2}}, {{0}, {1, 2, 3}}, {{0, 1}, {2, 3}}, {{0, 1, 2}, {3}}], [{{0, 3}, {1}, {2}}, {{0}, {1}, {2, 3}}, {{0}, {1, 2}, {3}}, {{0, 1}, {2}, {3}}], [{{0}, {1}, {2}, {3}}]] sage: for p in P: # needs sage.combinat ....: sum([partition_sandpile(S, i).betti(verbose=False)[-1] for i in p]) 6 8 3 sage: S.betti() # needs sage.libs.singular 0 1 2 3 ------------------------------ 0: 1 - - - 1: - 6 8 3 ------------------------------ total: 1 6 8 3 - >>> from sage.all import * >>> from sage.sandpiles.sandpile import admissible_partitions >>> from sage.sandpiles.sandpile import partition_sandpile >>> S = sandpiles.Cycle(Integer(4)) >>> P = [list(admissible_partitions(S, i)) for i in [Integer(2),Integer(3),Integer(4)]] # needs sage.combinat >>> P # needs sage.combinat [[{{0, 2, 3}, {1}}, {{0, 3}, {1, 2}}, {{0, 1, 3}, {2}}, {{0}, {1, 2, 3}}, {{0, 1}, {2, 3}}, {{0, 1, 2}, {3}}], [{{0, 3}, {1}, {2}}, {{0}, {1}, {2, 3}}, {{0}, {1, 2}, {3}}, {{0, 1}, {2}, {3}}], [{{0}, {1}, {2}, {3}}]] >>> for p in P: # needs sage.combinat ... sum([partition_sandpile(S, i).betti(verbose=False)[-Integer(1)] for i in p]) 6 8 3 >>> S.betti() # needs sage.libs.singular 0 1 2 3 ------------------------------ 0: 1 - - - 1: - 6 8 3 ------------------------------ total: 1 6 8 3 
- sage.sandpiles.sandpile.aztec_sandpile(n)[source]¶
- The aztec diamond graph. - INPUT: - n– integer
 - OUTPUT: dictionary for the aztec diamond graph - EXAMPLES: - sage: from sage.sandpiles.sandpile import aztec_sandpile sage: T = aztec_sandpile(2) sage: sorted(len(v) for u, v in T.items()) [3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 8] sage: Sandpile(T,(0, 0)).group_order() 4542720 - >>> from sage.all import * >>> from sage.sandpiles.sandpile import aztec_sandpile >>> T = aztec_sandpile(Integer(2)) >>> sorted(len(v) for u, v in T.items()) [3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 8] >>> Sandpile(T,(Integer(0), Integer(0))).group_order() 4542720 - Note - This is the aztec diamond graph with a sink vertex added. Boundary vertices have edges to the sink so that each vertex has degree 4. 
- sage.sandpiles.sandpile.firing_graph(S, eff)[source]¶
- Create a digraph with divisors as vertices and edges between two divisors \(D\) and \(E\) if firing a single vertex in \(D\) gives \(E\). - INPUT: - S– Sandpile
- eff– list of divisors
 - OUTPUT: DiGraph - EXAMPLES: - sage: S = sandpiles.Cycle(6) sage: D = SandpileDivisor(S, [1,1,1,1,2,0]) sage: eff = D.effective_div() # needs sage.geometry.polyhedron sage: firing_graph(S, eff).show3d(edge_size=.005, # long time, needs sage.geometry.polyhedron sage.plot ....: vertex_size=0.01) - >>> from sage.all import * >>> S = sandpiles.Cycle(Integer(6)) >>> D = SandpileDivisor(S, [Integer(1),Integer(1),Integer(1),Integer(1),Integer(2),Integer(0)]) >>> eff = D.effective_div() # needs sage.geometry.polyhedron >>> firing_graph(S, eff).show3d(edge_size=RealNumber('.005'), # long time, needs sage.geometry.polyhedron sage.plot ... vertex_size=RealNumber('0.01')) 
- sage.sandpiles.sandpile.glue_graphs(g, h, glue_g, glue_h)[source]¶
- Glue two graphs together. - INPUT: - g,- h– dictionaries for directed multigraphs
- glue_h,- glue_g– dictionaries for a vertex
 - OUTPUT: dictionary for a directed multigraph - EXAMPLES: - sage: from sage.sandpiles.sandpile import glue_graphs sage: x = {0: {}, 1: {0: 1}, 2: {0: 1, 1: 1}, 3: {0: 1, 1: 1, 2: 1}} sage: y = {0: {}, 1: {0: 2}, 2: {1: 2}, 3: {0: 1, 2: 1}} sage: glue_x = {1: 1, 3: 2} sage: glue_y = {0: 1, 1: 2, 3: 1} sage: z = glue_graphs(x,y,glue_x,glue_y); z {'sink': {}, 'x0': {'sink': 1, 'x1': 1, 'x3': 2, 'y1': 2, 'y3': 1}, 'x1': {'x0': 1}, 'x2': {'x0': 1, 'x1': 1}, 'x3': {'x0': 1, 'x1': 1, 'x2': 1}, 'y1': {'sink': 2}, 'y2': {'y1': 2}, 'y3': {'sink': 1, 'y2': 1}} sage: S = Sandpile(z,'sink') sage: S.h_vector() [1, 6, 17, 31, 41, 41, 31, 17, 6, 1] sage: S.resolution() # needs sage.libs.singular 'R^1 <-- R^7 <-- R^21 <-- R^35 <-- R^35 <-- R^21 <-- R^7 <-- R^1' - >>> from sage.all import * >>> from sage.sandpiles.sandpile import glue_graphs >>> x = {Integer(0): {}, Integer(1): {Integer(0): Integer(1)}, Integer(2): {Integer(0): Integer(1), Integer(1): Integer(1)}, Integer(3): {Integer(0): Integer(1), Integer(1): Integer(1), Integer(2): Integer(1)}} >>> y = {Integer(0): {}, Integer(1): {Integer(0): Integer(2)}, Integer(2): {Integer(1): Integer(2)}, Integer(3): {Integer(0): Integer(1), Integer(2): Integer(1)}} >>> glue_x = {Integer(1): Integer(1), Integer(3): Integer(2)} >>> glue_y = {Integer(0): Integer(1), Integer(1): Integer(2), Integer(3): Integer(1)} >>> z = glue_graphs(x,y,glue_x,glue_y); z {'sink': {}, 'x0': {'sink': 1, 'x1': 1, 'x3': 2, 'y1': 2, 'y3': 1}, 'x1': {'x0': 1}, 'x2': {'x0': 1, 'x1': 1}, 'x3': {'x0': 1, 'x1': 1, 'x2': 1}, 'y1': {'sink': 2}, 'y2': {'y1': 2}, 'y3': {'sink': 1, 'y2': 1}} >>> S = Sandpile(z,'sink') >>> S.h_vector() [1, 6, 17, 31, 41, 41, 31, 17, 6, 1] >>> S.resolution() # needs sage.libs.singular 'R^1 <-- R^7 <-- R^21 <-- R^35 <-- R^35 <-- R^21 <-- R^7 <-- R^1' - Note - This method makes a dictionary for a graph by combining those for \(g\) and \(h\). The sink of \(g\) is replaced by a vertex that is connected to the vertices of \(g\) as specified by - glue_gthe vertices of \(h\) as specified in- glue_h. The sink of the glued graph is- 'sink'.- Both - glue_gand- glue_hare dictionaries with entries of the form- v:wwhere- vis the vertex to be connected to and- wis the weight of the connecting edge.
- sage.sandpiles.sandpile.min_cycles(G, v)[source]¶
- Minimal length cycles in the digraph \(G\) starting at vertex \(v\). - INPUT: - G– DiGraph
- v– vertex of- G
 - OUTPUT: list of lists of vertices - EXAMPLES: - sage: from sage.sandpiles.sandpile import min_cycles, sandlib sage: T = sandlib('gor') sage: [min_cycles(T, i) for i in T.vertices(sort=True)] [[], [[1, 3]], [[2, 3, 1], [2, 3]], [[3, 1], [3, 2]]] - >>> from sage.all import * >>> from sage.sandpiles.sandpile import min_cycles, sandlib >>> T = sandlib('gor') >>> [min_cycles(T, i) for i in T.vertices(sort=True)] [[], [[1, 3]], [[2, 3, 1], [2, 3]], [[3, 1], [3, 2]]] 
- sage.sandpiles.sandpile.parallel_firing_graph(S, eff)[source]¶
- Create a digraph with divisors as vertices and edges between two divisors \(D\) and \(E\) if firing all unstable vertices in \(D\) gives \(E\). - INPUT: - S– Sandpile
- eff– list of divisors
 - OUTPUT: DiGraph - EXAMPLES: - sage: S = sandpiles.Cycle(6) sage: D = SandpileDivisor(S, [1,1,1,1,2,0]) sage: eff = D.effective_div() # needs sage.geometry.polyhedron sage: parallel_firing_graph(S, eff).show3d(edge_size=.005, # long time, needs sage.geometry.polyhedron sage.plot ....: vertex_size=0.01) - >>> from sage.all import * >>> S = sandpiles.Cycle(Integer(6)) >>> D = SandpileDivisor(S, [Integer(1),Integer(1),Integer(1),Integer(1),Integer(2),Integer(0)]) >>> eff = D.effective_div() # needs sage.geometry.polyhedron >>> parallel_firing_graph(S, eff).show3d(edge_size=RealNumber('.005'), # long time, needs sage.geometry.polyhedron sage.plot ... vertex_size=RealNumber('0.01')) 
- sage.sandpiles.sandpile.partition_sandpile(S, p)[source]¶
- Each set of vertices in \(p\) is regarded as a single vertex, with and edge between \(A\) and \(B\) if some element of \(A\) is connected by an edge to some element of \(B\) in \(S\). - INPUT: - S– Sandpile
- p– partition of the vertices of- S
 - OUTPUT: Sandpile - EXAMPLES: - sage: from sage.sandpiles.sandpile import admissible_partitions, partition_sandpile sage: S = sandpiles.Cycle(4) sage: P = [list(admissible_partitions(S, i)) for i in [2,3,4]] # needs sage.combinat sage: for p in P: # needs sage.combinat ....: sum([partition_sandpile(S, i).betti(verbose=False)[-1] for i in p]) 6 8 3 sage: S.betti() # needs sage.libs.singular 0 1 2 3 ------------------------------ 0: 1 - - - 1: - 6 8 3 ------------------------------ total: 1 6 8 3 - >>> from sage.all import * >>> from sage.sandpiles.sandpile import admissible_partitions, partition_sandpile >>> S = sandpiles.Cycle(Integer(4)) >>> P = [list(admissible_partitions(S, i)) for i in [Integer(2),Integer(3),Integer(4)]] # needs sage.combinat >>> for p in P: # needs sage.combinat ... sum([partition_sandpile(S, i).betti(verbose=False)[-Integer(1)] for i in p]) 6 8 3 >>> S.betti() # needs sage.libs.singular 0 1 2 3 ------------------------------ 0: 1 - - - 1: - 6 8 3 ------------------------------ total: 1 6 8 3 
- sage.sandpiles.sandpile.sandlib(selector=None)[source]¶
- Return the sandpile identified by - selector. If no argument is given, a description of the sandpiles in the sandlib is printed.- INPUT: - selector– (optional) identifier or None
 - OUTPUT: Sandpile or description - EXAMPLES: - sage: from sage.sandpiles.sandpile import sandlib sage: sandlib() Sandpiles in the sandlib: ci1 : complete intersection, non-DAG but equivalent to a DAG generic : generic digraph with 6 vertices genus2 : Undirected graph of genus 2 gor : Gorenstein but not a complete intersection kite : generic undirected graphs with 5 vertices riemann-roch1 : directed graph with postulation 9 and 3 maximal weight superstables riemann-roch2 : directed graph with a superstable not majorized by a maximal superstable sage: S = sandlib('gor') sage: S.resolution() # needs sage.libs.singular 'R^1 <-- R^5 <-- R^5 <-- R^1' - >>> from sage.all import * >>> from sage.sandpiles.sandpile import sandlib >>> sandlib() Sandpiles in the sandlib: ci1 : complete intersection, non-DAG but equivalent to a DAG generic : generic digraph with 6 vertices genus2 : Undirected graph of genus 2 gor : Gorenstein but not a complete intersection kite : generic undirected graphs with 5 vertices riemann-roch1 : directed graph with postulation 9 and 3 maximal weight superstables riemann-roch2 : directed graph with a superstable not majorized by a maximal superstable >>> S = sandlib('gor') >>> S.resolution() # needs sage.libs.singular 'R^1 <-- R^5 <-- R^5 <-- R^1' 
- sage.sandpiles.sandpile.triangle_sandpile(n)[source]¶
- A triangular sandpile. Each nonsink vertex has out-degree six. The vertices on the boundary of the triangle are connected to the sink. - INPUT: - n– integer
 - OUTPUT: Sandpile - EXAMPLES: - sage: from sage.sandpiles.sandpile import triangle_sandpile sage: T = triangle_sandpile(5) sage: T.group_order() 135418115000 - >>> from sage.all import * >>> from sage.sandpiles.sandpile import triangle_sandpile >>> T = triangle_sandpile(Integer(5)) >>> T.group_order() 135418115000 
- sage.sandpiles.sandpile.wilmes_algorithm(M)[source]¶
- Compute an integer matrix \(L\) with the same integer row span as \(M\) and such that \(L\) is the reduced Laplacian of a directed multigraph. - INPUT: - M– square integer matrix of full rank
 - OUTPUT: integer matrix ( - L)- EXAMPLES: - sage: from sage.sandpiles.sandpile import wilmes_algorithm sage: P = matrix([[2,3,-7,-3],[5,2,-5,5],[8,2,5,4],[-5,-9,6,6]]) sage: wilmes_algorithm(P) [ 3279 -79 -1599 -1600] [ -1 1539 -136 -1402] [ 0 -1 1650 -1649] [ 0 0 -1658 1658] - >>> from sage.all import * >>> from sage.sandpiles.sandpile import wilmes_algorithm >>> P = matrix([[Integer(2),Integer(3),-Integer(7),-Integer(3)],[Integer(5),Integer(2),-Integer(5),Integer(5)],[Integer(8),Integer(2),Integer(5),Integer(4)],[-Integer(5),-Integer(9),Integer(6),Integer(6)]]) >>> wilmes_algorithm(P) [ 3279 -79 -1599 -1600] [ -1 1539 -136 -1402] [ 0 -1 1650 -1649] [ 0 0 -1658 1658] - REFERENCES: