Fully packed loops - Combinatorics

Skip to content
Back to top
View this page
Edit this page

# Fully packed loops

AUTHORS:

- Vincent Knight, James Campbell, Kevin Dilks, Emily Gunawan (2015): Initial version

- Vincent Delecroix (2017): cleaning and enhanced plotting function

class sage.combinat.fully_packed_loop.FullyPackedLoop(parent, generator)

  Bases: `Element`

  A class for fully packed loops.

  A fully packed loop is a collection of non-intersecting lattice paths on a square grid such that every vertex is part of some path, and the paths are either closed internal loops or have endpoints corresponding to alternate points on the boundary [Pro2001]. They are known to be in bijection with alternating sign matrices.

  See also

  `AlternatingSignMatrix`

  To each fully packed loop, we assign a link pattern, which is the non-crossing matching attained by seeing which points on the boundary are connected by open paths in the fully packed loop.

  We can create a fully packed loop using the corresponding alternating sign matrix and also extract the link pattern:

  Sage

      sage: A = AlternatingSignMatrix([[0, 0, 1], [0, 1, 0], [1, 0, 0]])
      sage: fpl = FullyPackedLoop(A)
      sage: fpl.link_pattern()
      [(1, 4), (2, 3), (5, 6)]
      sage: fpl
         │         │
         │         │
         + ── +    +
              │    │
              │    │
      ── +    +    + ──
         │    │
         │    │
         +    + ── +
         │         │
         │         │
      sage: B = AlternatingSignMatrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
      sage: fplb = FullyPackedLoop(B)
      sage: fplb.link_pattern()
      [(1, 6), (2, 5), (3, 4)]
      sage: fplb
         │         │
         │         │
         +    + ── +
         │    │
         │    │
      ── +    +    + ──
              │    │
              │    │
         + ── +    +
         │         │
         │         │

  Python

      >>> from sage.all import *
      >>> A = AlternatingSignMatrix([[Integer(0), Integer(0), Integer(1)], [Integer(0), Integer(1), Integer(0)], [Integer(1), Integer(0), Integer(0)]])
      >>> fpl = FullyPackedLoop(A)
      >>> fpl.link_pattern()
      [(1, 4), (2, 3), (5, 6)]
      >>> fpl
         │         │
         │         │
         + ── +    +
              │    │
              │    │
      ── +    +    + ──
         │    │
         │    │
         +    + ── +
         │         │
         │         │
      >>> B = AlternatingSignMatrix([[Integer(1), Integer(0), Integer(0)], [Integer(0), Integer(1), Integer(0)], [Integer(0), Integer(0), Integer(1)]])
      >>> fplb = FullyPackedLoop(B)
      >>> fplb.link_pattern()
      [(1, 6), (2, 5), (3, 4)]
      >>> fplb
         │         │
         │         │
         +    + ── +
         │    │
         │    │
      ── +    +    + ──
              │    │
              │    │
         + ── +    +
         │         │
         │         │

  The class also has a plot method:

  Sage

      sage: fpl.plot()                                                                # needs sage.plot
      Graphics object consisting of 3 graphics primitives

  [Python]

      >>> from sage.all import *
      >>> fpl.plot()                                                                # needs sage.plot
      Graphics object consisting of 3 graphics primitives

  which gives:

  Note that we can also create a fully packed loop from a six vertex model configuration:

  Sage

      sage: S = SixVertexModel(3, boundary_conditions='ice').from_alternating_sign_matrix(A)
      sage: S
          ^    ^    ^
          |    |    |
      --> # -> # -> # <--
          ^    ^    |
          |    |    V
      --> # -> # <- # <--
          ^    |    |
          |    V    V
      --> # <- # <- # <--
          |    |    |
          V    V    V
      sage: fpl = FullyPackedLoop(S)
      sage: fpl
         │         │
         │         │
         + ── +    +
              │    │
              │    │
      ── +    +    + ──
         │    │
         │    │
         +    + ── +
         │         │
         │         │

  Python

      >>> from sage.all import *
      >>> S = SixVertexModel(Integer(3), boundary_conditions='ice').from_alternating_sign_matrix(A)
      >>> S
          ^    ^    ^
          |    |    |
      --> # -> # -> # <--
          ^    ^    |
          |    |    V
      --> # -> # <- # <--
          ^    |    |
          |    V    V
      --> # <- # <- # <--
          |    |    |
          V    V    V
      >>> fpl = FullyPackedLoop(S)
      >>> fpl
         │         │
         │         │
         + ── +    +
              │    │
              │    │
      ── +    +    + ──
         │    │
         │    │
         +    + ── +
         │         │
         │         │

  Once we have a fully packed loop we can obtain the corresponding alternating sign matrix:

  Sage

      sage: fpl.to_alternating_sign_matrix()
      [0 0 1]
      [0 1 0]
      [1 0 0]

  [Python]

      >>> from sage.all import *
      >>> fpl.to_alternating_sign_matrix()
      [0 0 1]
      [0 1 0]
      [1 0 0]

  Here are some more examples using bigger ASMs:

  Sage

      sage: A = AlternatingSignMatrix([[0,1,0,0],[0,0,1,0],[1,-1,0,1],[0,1,0,0]])
      sage: S = SixVertexModel(4, boundary_conditions='ice').from_alternating_sign_matrix(A)
      sage: fpl = FullyPackedLoop(S)
      sage: fpl.link_pattern()
      [(1, 2), (3, 6), (4, 5), (7, 8)]
      sage: fpl
         │         │
         │         │
         + ── + ── +    + ──
                        │
                        │
      ── +    + ── + ── +
         │    │
         │    │
         +    +    + ── + ──
         │    │    │
         │    │    │
      ── +    +    + ── +
              │         │
              │         │

      sage: m = AlternatingSignMatrix([[0,0,1,0,0,0],
      ....:                            [1,0,-1,0,1,0],
      ....:                            [0,0,0,1,0,0],
      ....:                            [0,1,0,0,-1,1],
      ....:                            [0,0,0,0,1,0],
      ....:                            [0,0,1,0,0,0]])
      sage: fpl = FullyPackedLoop(m)
      sage: fpl.link_pattern()
      [(1, 12), (2, 7), (3, 4), (5, 6), (8, 9), (10, 11)]
      sage: fpl
         │         │         │
         │         │         │
         + ── +    +    + ── +    + ──
              │    │    │         │
              │    │    │         │
      ── + ── +    +    + ── + ── +
                   │
                   │
         + ── +    + ── + ── +    + ──
         │    │              │    │
         │    │              │    │
      ── +    +    + ── +    +    +
              │    │    │    │    │
              │    │    │    │    │
         + ── +    + ── +    +    + ──
         │                   │
         │                   │
      ── +    + ── + ── +    + ── +
              │         │         │
              │         │         │

      sage: m = AlternatingSignMatrix([[0,1,0,0,0,0,0],
      ....:                            [1,-1,0,0,1,0,0],
      ....:                            [0,0,0,1,0,0,0],
      ....:                            [0,1,0,0,-1,1,0],
      ....:                            [0,0,0,0,1,0,0],
      ....:                            [0,0,1,0,-1,0,1],
      ....:                            [0,0,0,0,1,0,0]])
      sage: fpl = FullyPackedLoop(m)
      sage: fpl.link_pattern()
      [(1, 2), (3, 4), (5, 6), (7, 8), (9, 14), (10, 11), (12, 13)]
      sage: fpl
         │         │         │         │
         │         │         │         │
         + ── + ── +    + ── +    + ── +
                        │         │
                        │         │
      ── + ── + ── +    + ── + ── +    + ──
                   │                   │
                   │                   │
         + ── +    + ── + ── +    + ── +
         │    │              │    │
         │    │              │    │
      ── +    +    + ── +    +    +    + ──
              │    │    │    │    │    │
              │    │    │    │    │    │
         + ── +    + ── +    +    + ── +
         │                   │
         │                   │
      ── +    + ── + ── +    +    + ── + ──
              │         │    │    │
              │         │    │    │
         + ── +    + ── +    +    + ── +
         │         │         │         │
         │         │         │         │

  Python

      >>> from sage.all import *
      >>> A = AlternatingSignMatrix([[Integer(0),Integer(1),Integer(0),Integer(0)],[Integer(0),Integer(0),Integer(1),Integer(0)],[Integer(1),-Integer(1),Integer(0),Integer(1)],[Integer(0),Integer(1),Integer(0),Integer(0)]])
      >>> S = SixVertexModel(Integer(4), boundary_conditions='ice').from_alternating_sign_matrix(A)
      >>> fpl = FullyPackedLoop(S)
      >>> fpl.link_pattern()
      [(1, 2), (3, 6), (4, 5), (7, 8)]
      >>> fpl
         │         │
         │         │
         + ── + ── +    + ──
                        │
                        │
      ── +    + ── + ── +
         │    │
         │    │
         +    +    + ── + ──
         │    │    │
         │    │    │
      ── +    +    + ── +
              │         │
              │         │

      >>> m = AlternatingSignMatrix([[Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),Integer(0)],
      ...                            [Integer(1),Integer(0),-Integer(1),Integer(0),Integer(1),Integer(0)],
      ...                            [Integer(0),Integer(0),Integer(0),Integer(1),Integer(0),Integer(0)],
      ...                            [Integer(0),Integer(1),Integer(0),Integer(0),-Integer(1),Integer(1)],
      ...                            [Integer(0),Integer(0),Integer(0),Integer(0),Integer(1),Integer(0)],
      ...                            [Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),Integer(0)]])
      >>> fpl = FullyPackedLoop(m)
      >>> fpl.link_pattern()
      [(1, 12), (2, 7), (3, 4), (5, 6), (8, 9), (10, 11)]
      >>> fpl
         │         │         │
         │         │         │
         + ── +    +    + ── +    + ──
              │    │    │         │
              │    │    │         │
      ── + ── +    +    + ── + ── +
                   │
                   │
         + ── +    + ── + ── +    + ──
         │    │              │    │
         │    │              │    │
      ── +    +    + ── +    +    +
              │    │    │    │    │
              │    │    │    │    │
         + ── +    + ── +    +    + ──
         │                   │
         │                   │
      ── +    + ── + ── +    + ── +
              │         │         │
              │         │         │

      >>> m = AlternatingSignMatrix([[Integer(0),Integer(1),Integer(0),Integer(0),Integer(0),Integer(0),Integer(0)],
      ...                            [Integer(1),-Integer(1),Integer(0),Integer(0),Integer(1),Integer(0),Integer(0)],
      ...                            [Integer(0),Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),Integer(0)],
      ...                            [Integer(0),Integer(1),Integer(0),Integer(0),-Integer(1),Integer(1),Integer(0)],
      ...                            [Integer(0),Integer(0),Integer(0),Integer(0),Integer(1),Integer(0),Integer(0)],
      ...                            [Integer(0),Integer(0),Integer(1),Integer(0),-Integer(1),Integer(0),Integer(1)],
      ...                            [Integer(0),Integer(0),Integer(0),Integer(0),Integer(1),Integer(0),Integer(0)]])
      >>> fpl = FullyPackedLoop(m)
      >>> fpl.link_pattern()
      [(1, 2), (3, 4), (5, 6), (7, 8), (9, 14), (10, 11), (12, 13)]
      >>> fpl
         │         │         │         │
         │         │         │         │
         + ── + ── +    + ── +    + ── +
                        │         │
                        │         │
      ── + ── + ── +    + ── + ── +    + ──
                   │                   │
                   │                   │
         + ── +    + ── + ── +    + ── +
         │    │              │    │
         │    │              │    │
      ── +    +    + ── +    +    +    + ──
              │    │    │    │    │    │
              │    │    │    │    │    │
         + ── +    + ── +    +    + ── +
         │                   │
         │                   │
      ── +    + ── + ── +    +    + ── + ──
              │         │    │    │
              │         │    │    │
         + ── +    + ── +    +    + ── +
         │         │         │         │
         │         │         │         │

  Gyration on an alternating sign matrix/fully packed loop `fpl` of the link pattern corresponding to `fpl`:

  Sage

      sage: ASMs = AlternatingSignMatrices(3).list()
      sage: ncp = FullyPackedLoop(ASMs[1]).link_pattern() # fpl's gyration orbit size is 2
      sage: rotated_ncp=[]
      sage: for a, b in ncp:
      ....:     for i in range(5):
      ....:         a,b=a%6+1,b%6+1;
      ....:     rotated_ncp.append((a,b))
      sage: PerfectMatching(ASMs[1].gyration().to_fully_packed_loop().link_pattern()) ==\
      ....:     PerfectMatching(rotated_ncp)
      True

      sage: fpl = FullyPackedLoop(ASMs[0])
      sage: ncp = fpl.link_pattern() # fpl's gyration size is 3
      sage: rotated_ncp=[]
      sage: for a, b in ncp:
      ....:     for i in range(5):
      ....:         a,b=a%6+1,b%6+1;
      ....:     rotated_ncp.append((a,b))
      sage: PerfectMatching(ASMs[0].gyration().to_fully_packed_loop().link_pattern()) ==\
      ....:     PerfectMatching(rotated_ncp)
      True

      sage: mat = AlternatingSignMatrix([[0,0,1,0,0,0,0],[1,0,-1,0,1,0,0],
      ....:     [0,0,1,0,0,0,0],[0,1,-1,0,0,1,0],[0,0,1,0,0,0,0],[0,0,0,1,0,0,0],[0,0,0,0,0,0,1]])
      sage: fpl = FullyPackedLoop(mat) # n=7
      sage: ncp = fpl.link_pattern()
      sage: rotated_ncp=[]
      sage: for a, b in ncp:
      ....:     for i in range(13):
      ....:         a,b=a%14+1,b%14+1;
      ....:     rotated_ncp.append((a,b))
      sage: PerfectMatching(mat.gyration().to_fully_packed_loop().link_pattern()) ==\
      ....:     PerfectMatching(rotated_ncp)
      True

      sage: mat = AlternatingSignMatrix([[0,0,0,1,0,0], [0,0,1,-1,1,0],
      ....:     [0,1,0,0,-1,1], [1,0,-1,1,0,0], [0,0,1,0,0,0], [0,0,0,0,1,0]])
      sage: fpl = FullyPackedLoop(mat) # n =6
      sage: ncp = fpl.link_pattern()
      sage: rotated_ncp=[]
      sage: for a, b in ncp:
      ....:     for i in range(11):
      ....:         a,b=a%12+1,b%12+1;
      ....:     rotated_ncp.append((a,b))
      sage: PerfectMatching(mat.gyration().to_fully_packed_loop().link_pattern()) ==\
      ....:     PerfectMatching(rotated_ncp)
      True

  [Python]

      >>> from sage.all import *
      >>> ASMs = AlternatingSignMatrices(Integer(3)).list()
      >>> ncp = FullyPackedLoop(ASMs[Integer(1)]).link_pattern() # fpl's gyration orbit size is 2
      >>> rotated_ncp=[]
      >>> for a, b in ncp:
      ...     for i in range(Integer(5)):
      ...         a,b=a%Integer(6)+Integer(1),b%Integer(6)+Integer(1);
      ...     rotated_ncp.append((a,b))
      >>> PerfectMatching(ASMs[Integer(1)].gyration().to_fully_packed_loop().link_pattern()) ==    PerfectMatching(rotated_ncp)
      True

      >>> fpl = FullyPackedLoop(ASMs[Integer(0)])
      >>> ncp = fpl.link_pattern() # fpl's gyration size is 3
      >>> rotated_ncp=[]
      >>> for a, b in ncp:
      ...     for i in range(Integer(5)):
      ...         a,b=a%Integer(6)+Integer(1),b%Integer(6)+Integer(1);
      ...     rotated_ncp.append((a,b))
      >>> PerfectMatching(ASMs[Integer(0)].gyration().to_fully_packed_loop().link_pattern()) ==    PerfectMatching(rotated_ncp)
      True

      >>> mat = AlternatingSignMatrix([[Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),Integer(0),Integer(0)],[Integer(1),Integer(0),-Integer(1),Integer(0),Integer(1),Integer(0),Integer(0)],
      ...     [Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),Integer(0),Integer(0)],[Integer(0),Integer(1),-Integer(1),Integer(0),Integer(0),Integer(1),Integer(0)],[Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),Integer(0),Integer(0)],[Integer(0),Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),Integer(0)],[Integer(0),Integer(0),Integer(0),Integer(0),Integer(0),Integer(0),Integer(1)]])
      >>> fpl = FullyPackedLoop(mat) # n=7
      >>> ncp = fpl.link_pattern()
      >>> rotated_ncp=[]
      >>> for a, b in ncp:
      ...     for i in range(Integer(13)):
      ...         a,b=a%Integer(14)+Integer(1),b%Integer(14)+Integer(1);
      ...     rotated_ncp.append((a,b))
      >>> PerfectMatching(mat.gyration().to_fully_packed_loop().link_pattern()) ==    PerfectMatching(rotated_ncp)
      True

      >>> mat = AlternatingSignMatrix([[Integer(0),Integer(0),Integer(0),Integer(1),Integer(0),Integer(0)], [Integer(0),Integer(0),Integer(1),-Integer(1),Integer(1),Integer(0)],
      ...     [Integer(0),Integer(1),Integer(0),Integer(0),-Integer(1),Integer(1)], [Integer(1),Integer(0),-Integer(1),Integer(1),Integer(0),Integer(0)], [Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),Integer(0)], [Integer(0),Integer(0),Integer(0),Integer(0),Integer(1),Integer(0)]])
      >>> fpl = FullyPackedLoop(mat) # n =6
      >>> ncp = fpl.link_pattern()
      >>> rotated_ncp=[]
      >>> for a, b in ncp:
      ...     for i in range(Integer(11)):
      ...         a,b=a%Integer(12)+Integer(1),b%Integer(12)+Integer(1);
      ...     rotated_ncp.append((a,b))
      >>> PerfectMatching(mat.gyration().to_fully_packed_loop().link_pattern()) ==    PerfectMatching(rotated_ncp)
      True

  More examples:

  We can initiate a fully packed loop using an alternating sign matrix:

  Sage

      sage: A = AlternatingSignMatrix([[0, 0, 1], [0, 1, 0], [1, 0, 0]])
      sage: fpl = FullyPackedLoop(A)
      sage: fpl
          │         │
          │         │
          + ── +    +
               │    │
               │    │
       ── +    +    + ──
          │    │
          │    │
          +    + ── +
          │         │
          │         │
      sage: FullyPackedLoops(3)(A) == fpl
      True

  Python

      >>> from sage.all import *
      >>> A = AlternatingSignMatrix([[Integer(0), Integer(0), Integer(1)], [Integer(0), Integer(1), Integer(0)], [Integer(1), Integer(0), Integer(0)]])
      >>> fpl = FullyPackedLoop(A)
      >>> fpl
          │         │
          │         │
          + ── +    +
               │    │
               │    │
       ── +    +    + ──
          │    │
          │    │
          +    + ── +
          │         │
          │         │
      >>> FullyPackedLoops(Integer(3))(A) == fpl
      True

  We can also input a matrix:

  Sage

      sage: FullyPackedLoop([[0, 0, 1], [0, 1, 0], [1, 0, 0]])
          │         │
          │         │
          + ── +    +
               │    │
               │    │
       ── +    +    + ──
          │    │
          │    │
          +    + ── +
          │         │
          │         │
      sage: FullyPackedLoop([[0, 0, 1], [0, 1, 0], [1, 0, 0]]) ==\
      ....: FullyPackedLoops(3)([[0, 0, 1], [0, 1, 0], [1, 0, 0]])
      True

  [Python]

      >>> from sage.all import *
      >>> FullyPackedLoop([[Integer(0), Integer(0), Integer(1)], [Integer(0), Integer(1), Integer(0)], [Integer(1), Integer(0), Integer(0)]])
          │         │
          │         │
          + ── +    +
               │    │
               │    │
       ── +    +    + ──
          │    │
          │    │
          +    + ── +
          │         │
          │         │
      >>> FullyPackedLoop([[Integer(0), Integer(0), Integer(1)], [Integer(0), Integer(1), Integer(0)], [Integer(1), Integer(0), Integer(0)]]) ==FullyPackedLoops(Integer(3))([[Integer(0), Integer(0), Integer(1)], [Integer(0), Integer(1), Integer(0)], [Integer(1), Integer(0), Integer(0)]])
      True

  Otherwise we initiate a fully packed loop using a six vertex model:

  Sage

      sage: S = SixVertexModel(3, boundary_conditions='ice').from_alternating_sign_matrix(A)
      sage: fpl = FullyPackedLoop(S)
      sage: fpl
          │         │
          │         │
          + ── +    +
               │    │
               │    │
       ── +    +    + ──
          │    │
          │    │
          +    + ── +
          │         │
          │         │

      sage: FullyPackedLoops(3)(S) == FullyPackedLoop(S)
      True

      sage: fpl.six_vertex_model().to_alternating_sign_matrix()
      [0 0 1]
      [0 1 0]
      [1 0 0]

  Python

      >>> from sage.all import *
      >>> S = SixVertexModel(Integer(3), boundary_conditions='ice').from_alternating_sign_matrix(A)
      >>> fpl = FullyPackedLoop(S)
      >>> fpl
          │         │
          │         │
          + ── +    +
               │    │
               │    │
       ── +    +    + ──
          │    │
          │    │
          +    + ── +
          │         │
          │         │

      >>> FullyPackedLoops(Integer(3))(S) == FullyPackedLoop(S)
      True

      >>> fpl.six_vertex_model().to_alternating_sign_matrix()
      [0 0 1]
      [0 1 0]
      [1 0 0]

  We can also input the matrix associated to a six vertex model:

  Sage

      sage: SixVertexModel(2)([[3,1],[5,3]])
          ^    ^
          |    |
      --> # <- # <--
          |    ^
          V    |
      --> # -> # <--
          |    |
          V    V

      sage: FullyPackedLoop([[3,1],[5,3]])
          │
          │
          +    + ──
          │    │
          │    │
       ── +    +
               │
               │

      sage: FullyPackedLoops(2)([[3,1],[5,3]]) == FullyPackedLoop([[3,1],[5,3]])
      True

  [Python]

      >>> from sage.all import *
      >>> SixVertexModel(Integer(2))([[Integer(3),Integer(1)],[Integer(5),Integer(3)]])
          ^    ^
          |    |
      --> # <- # <--
          |    ^
          V    |
      --> # -> # <--
          |    |
          V    V

      >>> FullyPackedLoop([[Integer(3),Integer(1)],[Integer(5),Integer(3)]])
          │
          │
          +    + ──
          │    │
          │    │
       ── +    +
               │
               │

      >>> FullyPackedLoops(Integer(2))([[Integer(3),Integer(1)],[Integer(5),Integer(3)]]) == FullyPackedLoop([[Integer(3),Integer(1)],[Integer(5),Integer(3)]])
      True

  Note that the matrix corresponding to a six vertex model without the ice boundary condition is not allowed:

  Sage

      sage: SixVertexModel(2)([[3,1],[5,5]])
          ^    ^
          |    |
      --> # <- # <--
          |    ^
          V    V
      --> # -> # -->
          |    |
          V    V

      sage: FullyPackedLoop([[3,1],[5,5]])
      Traceback (most recent call last):
      ...
      ValueError: invalid alternating sign matrix

      sage: FullyPackedLoops(2)([[3,1],[5,5]])
      Traceback (most recent call last):
      ...
      ValueError: invalid alternating sign matrix

  Python

      >>> from sage.all import *
      >>> SixVertexModel(Integer(2))([[Integer(3),Integer(1)],[Integer(5),Integer(5)]])
          ^    ^
          |    |
      --> # <- # <--
          |    ^
          V    V
      --> # -> # -->
          |    |
          V    V

      >>> FullyPackedLoop([[Integer(3),Integer(1)],[Integer(5),Integer(5)]])
      Traceback (most recent call last):
      ...
      ValueError: invalid alternating sign matrix

      >>> FullyPackedLoops(Integer(2))([[Integer(3),Integer(1)],[Integer(5),Integer(5)]])
      Traceback (most recent call last):
      ...
      ValueError: invalid alternating sign matrix

  Note that if anything else is used to generate the fully packed loop an error will occur:

  Sage

      sage: fpl = FullyPackedLoop(5)
      Traceback (most recent call last):
      ...
      ValueError: invalid alternating sign matrix

      sage: fpl = FullyPackedLoop((1, 2, 3))
      Traceback (most recent call last):
      ...
      ValueError: the alternating sign matrices must be square

      sage: SVM = SixVertexModel(3)[0]
      sage: FullyPackedLoop(SVM)
      Traceback (most recent call last):
      ...
      ValueError: invalid alternating sign matrix

  [Python]

      >>> from sage.all import *
      >>> fpl = FullyPackedLoop(Integer(5))
      Traceback (most recent call last):
      ...
      ValueError: invalid alternating sign matrix

      >>> fpl = FullyPackedLoop((Integer(1), Integer(2), Integer(3)))
      Traceback (most recent call last):
      ...
      ValueError: the alternating sign matrices must be square

      >>> SVM = SixVertexModel(Integer(3))[Integer(0)]
      >>> FullyPackedLoop(SVM)
      Traceback (most recent call last):
      ...
      ValueError: invalid alternating sign matrix

  REFERENCES:

  - [Pro2001]

  - [Str2015]

  gyration()

    Return the fully packed loop obtained by applying gyration to the alternating sign matrix in bijection with `self`.

    Gyration was first defined in [Wie2000] as an action on fully-packed loops.

    EXAMPLES:

    Sage

        sage: A = AlternatingSignMatrix([[1, 0, 0],[0, 1, 0],[0, 0, 1]])
        sage: fpl = FullyPackedLoop(A)
        sage: fpl.gyration().to_alternating_sign_matrix()
        [0 0 1]
        [0 1 0]
        [1 0 0]
        sage: asm = AlternatingSignMatrix([[0, 0, 1],[1, 0, 0],[0, 1, 0]])
        sage: f = FullyPackedLoop(asm)
        sage: f.gyration().to_alternating_sign_matrix()
        [0 1 0]
        [0 0 1]
        [1 0 0]

    Python

        >>> from sage.all import *
        >>> A = AlternatingSignMatrix([[Integer(1), Integer(0), Integer(0)],[Integer(0), Integer(1), Integer(0)],[Integer(0), Integer(0), Integer(1)]])
        >>> fpl = FullyPackedLoop(A)
        >>> fpl.gyration().to_alternating_sign_matrix()
        [0 0 1]
        [0 1 0]
        [1 0 0]
        >>> asm = AlternatingSignMatrix([[Integer(0), Integer(0), Integer(1)],[Integer(1), Integer(0), Integer(0)],[Integer(0), Integer(1), Integer(0)]])
        >>> f = FullyPackedLoop(asm)
        >>> f.gyration().to_alternating_sign_matrix()
        [0 1 0]
        [0 0 1]
        [1 0 0]

  link_pattern()

    Return a link pattern corresponding to a fully packed loop.

    Here we define a link pattern \(LP\) to be a partition of the list \([1, ..., 2k]\) into 2-element sets (such a partition is also known as a perfect matching) such that the following non-crossing condition holds: Let the numbers \(1, ..., 2k\) be written on the perimeter of a circle. For every 2-element set \((a,b)\) of the partition \(LP\), draw an arc linking the two numbers \(a\) and \(b\). We say that \(LP\) is non-crossing if every arc can be drawn so that no two arcs intersect.

    Since every endpoint of a fully packed loop \(fpl\) is connected to a different endpoint, there is a natural surjection from the fully packed loops on an nxn grid onto the link patterns on the list \([1, \dots, 2n]\). The pairs of connected endpoints of a fully packed loop \(fpl\) correspond to the 2-element tuples of the corresponding link pattern.

    See also

    `PerfectMatching`

    Note

    by convention, we choose the top left vertex to be even. See [Pro2001] and [Str2015].

    EXAMPLES:

    We can extract the underlying link pattern (a non-crossing partition) from a fully packed loop:

    Sage

        sage: A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]])
        sage: fpl = FullyPackedLoop(A)
        sage: fpl.link_pattern()
        [(1, 2), (3, 6), (4, 5)]

        sage: B = AlternatingSignMatrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
        sage: fpl = FullyPackedLoop(B)
        sage: fpl.link_pattern()
        [(1, 6), (2, 5), (3, 4)]

    Python

        >>> from sage.all import *
        >>> A = AlternatingSignMatrix([[Integer(0), Integer(1), Integer(0)], [Integer(1), -Integer(1), Integer(1)], [Integer(0), Integer(1), Integer(0)]])
        >>> fpl = FullyPackedLoop(A)
        >>> fpl.link_pattern()
        [(1, 2), (3, 6), (4, 5)]

        >>> B = AlternatingSignMatrix([[Integer(1), Integer(0), Integer(0)], [Integer(0), Integer(1), Integer(0)], [Integer(0), Integer(0), Integer(1)]])
        >>> fpl = FullyPackedLoop(B)
        >>> fpl.link_pattern()
        [(1, 6), (2, 5), (3, 4)]

    Gyration on an alternating sign matrix/fully packed loop `fpl` corresponds to a rotation (i.e. a becomes a-1 mod 2n) of the link pattern corresponding to `fpl`:

    Sage

        sage: ASMs = AlternatingSignMatrices(3).list()
        sage: ncp = FullyPackedLoop(ASMs[1]).link_pattern()
        sage: rotated_ncp=[]
        sage: for a, b in ncp:
        ....:     for i in range(5):
        ....:         a,b=a%6+1,b%6+1;
        ....:     rotated_ncp.append((a,b))
        sage: PerfectMatching(ASMs[1].gyration().to_fully_packed_loop().link_pattern()) ==\
        ....:     PerfectMatching(rotated_ncp)
        True

        sage: fpl = FullyPackedLoop(ASMs[0])
        sage: ncp = fpl.link_pattern()
        sage: rotated_ncp=[]
        sage: for a, b in ncp:
        ....:     for i in range(5):
        ....:         a,b=a%6+1,b%6+1;
        ....:     rotated_ncp.append((a,b))
        sage: PerfectMatching(ASMs[0].gyration().to_fully_packed_loop().link_pattern()) ==\
        ....:     PerfectMatching(rotated_ncp)
        True

        sage: mat = AlternatingSignMatrix([[0,0,1,0,0,0,0],[1,0,-1,0,1,0,0],[0,0,1,0,0,0,0],
        ....:     [0,1,-1,0,0,1,0],[0,0,1,0,0,0,0],[0,0,0,1,0,0,0],[0,0,0,0,0,0,1]])
        sage: fpl = FullyPackedLoop(mat) # n=7
        sage: ncp = fpl.link_pattern()
        sage: rotated_ncp=[]
        sage: for a, b in ncp:
        ....:     for i in range(13):
        ....:         a,b=a%14+1,b%14+1;
        ....:     rotated_ncp.append((a,b))
        sage: PerfectMatching(mat.gyration().to_fully_packed_loop().link_pattern()) ==\
        ....:     PerfectMatching(rotated_ncp)
        True

        sage: mat = AlternatingSignMatrix([[0,0,0,1,0,0], [0,0,1,-1,1,0], [0,1,0,0,-1,1], [1,0,-1,1,0,0],
        ....:     [0,0,1,0,0,0], [0,0,0,0,1,0]])
        sage: fpl = FullyPackedLoop(mat)
        sage: ncp = fpl.link_pattern()
        sage: rotated_ncp=[]
        sage: for a, b in ncp:
        ....:     for i in range(11):
        ....:         a,b=a%12+1,b%12+1;
        ....:     rotated_ncp.append((a,b))
        sage: PerfectMatching(mat.gyration().to_fully_packed_loop().link_pattern()) ==\
        ....:     PerfectMatching(rotated_ncp)
        True

    [Python]

        >>> from sage.all import *
        >>> ASMs = AlternatingSignMatrices(Integer(3)).list()
        >>> ncp = FullyPackedLoop(ASMs[Integer(1)]).link_pattern()
        >>> rotated_ncp=[]
        >>> for a, b in ncp:
        ...     for i in range(Integer(5)):
        ...         a,b=a%Integer(6)+Integer(1),b%Integer(6)+Integer(1);
        ...     rotated_ncp.append((a,b))
        >>> PerfectMatching(ASMs[Integer(1)].gyration().to_fully_packed_loop().link_pattern()) ==    PerfectMatching(rotated_ncp)
        True

        >>> fpl = FullyPackedLoop(ASMs[Integer(0)])
        >>> ncp = fpl.link_pattern()
        >>> rotated_ncp=[]
        >>> for a, b in ncp:
        ...     for i in range(Integer(5)):
        ...         a,b=a%Integer(6)+Integer(1),b%Integer(6)+Integer(1);
        ...     rotated_ncp.append((a,b))
        >>> PerfectMatching(ASMs[Integer(0)].gyration().to_fully_packed_loop().link_pattern()) ==    PerfectMatching(rotated_ncp)
        True

        >>> mat = AlternatingSignMatrix([[Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),Integer(0),Integer(0)],[Integer(1),Integer(0),-Integer(1),Integer(0),Integer(1),Integer(0),Integer(0)],[Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),Integer(0),Integer(0)],
        ...     [Integer(0),Integer(1),-Integer(1),Integer(0),Integer(0),Integer(1),Integer(0)],[Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),Integer(0),Integer(0)],[Integer(0),Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),Integer(0)],[Integer(0),Integer(0),Integer(0),Integer(0),Integer(0),Integer(0),Integer(1)]])
        >>> fpl = FullyPackedLoop(mat) # n=7
        >>> ncp = fpl.link_pattern()
        >>> rotated_ncp=[]
        >>> for a, b in ncp:
        ...     for i in range(Integer(13)):
        ...         a,b=a%Integer(14)+Integer(1),b%Integer(14)+Integer(1);
        ...     rotated_ncp.append((a,b))
        >>> PerfectMatching(mat.gyration().to_fully_packed_loop().link_pattern()) ==    PerfectMatching(rotated_ncp)
        True

        >>> mat = AlternatingSignMatrix([[Integer(0),Integer(0),Integer(0),Integer(1),Integer(0),Integer(0)], [Integer(0),Integer(0),Integer(1),-Integer(1),Integer(1),Integer(0)], [Integer(0),Integer(1),Integer(0),Integer(0),-Integer(1),Integer(1)], [Integer(1),Integer(0),-Integer(1),Integer(1),Integer(0),Integer(0)],
        ...     [Integer(0),Integer(0),Integer(1),Integer(0),Integer(0),Integer(0)], [Integer(0),Integer(0),Integer(0),Integer(0),Integer(1),Integer(0)]])
        >>> fpl = FullyPackedLoop(mat)
        >>> ncp = fpl.link_pattern()
        >>> rotated_ncp=[]
        >>> for a, b in ncp:
        ...     for i in range(Integer(11)):
        ...         a,b=a%Integer(12)+Integer(1),b%Integer(12)+Integer(1);
        ...     rotated_ncp.append((a,b))
        >>> PerfectMatching(mat.gyration().to_fully_packed_loop().link_pattern()) ==    PerfectMatching(rotated_ncp)
        True

  plot(link=True, loop=True, loop_fill=False, **options)

    Return a graphical object of the Fully Packed Loop.

    Each option can be specified separately for links (the curves that join boundary points) and the loops. In order to do so, you need to prefix its name with either `'link_'` or `'loop_'`. As an example, setting `color='red'` will color both links and loops in red while setting `link_color='red'` will only apply the color option for the links.

    INPUT:

    - `link`, `loop` – boolean (default: `True`); whether to plot the links or the loops

    - `color`, `link_color`, `loop_color` – (optional) string or RGB triple

    - `colors`, `link_colors`, `loop_colors` – (optional) list of colors

    - `color_map`, `link_color_map`, `loop_color_map` – (string, optional) a name of a matplotlib color map for the link or the loop

    - `link_color_randomize` – boolean (default: `False`); when `link_colors` or `link_color_map` is specified it randomizes its order. Setting this option to `True` makes it unlikely to have two neighboring links with the same color.

    - `loop_fill` – boolean (default: `False`); whether to fill the interior of the loops

    EXAMPLES:

    To plot the fully packed loop associated to the following alternating sign matrix

    \[\begin{split}\begin{pmatrix} 0&1&1 \\ 1&-1&1 \\ 0&1&0 \end{pmatrix}\end{split}\]

    simply do:

    Sage

        sage: A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]])
        sage: fpl = FullyPackedLoop(A)
        sage: fpl.plot()                                                            # needs sage.plot
        Graphics object consisting of 3 graphics primitives

    Python

        >>> from sage.all import *
        >>> A = AlternatingSignMatrix([[Integer(0), Integer(1), Integer(0)], [Integer(1), -Integer(1), Integer(1)], [Integer(0), Integer(1), Integer(0)]])
        >>> fpl = FullyPackedLoop(A)
        >>> fpl.plot()                                                            # needs sage.plot
        Graphics object consisting of 3 graphics primitives

    The resulting graphics is as follows

    You can also have the three links in different colors with:

    Sage

        sage: A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]])
        sage: fpl = FullyPackedLoop(A)
        sage: fpl.plot(link_color_map='rainbow')                                    # needs sage.plot
        Graphics object consisting of 3 graphics primitives

    [Python]

        >>> from sage.all import *
        >>> A = AlternatingSignMatrix([[Integer(0), Integer(1), Integer(0)], [Integer(1), -Integer(1), Integer(1)], [Integer(0), Integer(1), Integer(0)]])
        >>> fpl = FullyPackedLoop(A)
        >>> fpl.plot(link_color_map='rainbow')                                    # needs sage.plot
        Graphics object consisting of 3 graphics primitives

    You can plot the 42 fully packed loops of size \(4 \times 4\) using:

    Sage

        sage: G = [fpl.plot(link_color_map='winter', loop_color='black')            # needs sage.plot
        ....:      for fpl in FullyPackedLoops(4)]
        sage: graphics_array(G, 7, 6)                                               # needs sage.plot
        Graphics Array of size 7 x 6

    Python

        >>> from sage.all import *
        >>> G = [fpl.plot(link_color_map='winter', loop_color='black')            # needs sage.plot
        ...      for fpl in FullyPackedLoops(Integer(4))]
        >>> graphics_array(G, Integer(7), Integer(6))                                               # needs sage.plot
        Graphics Array of size 7 x 6

    Here is an example of a \(20 \times 20\) fully packed loop:

    Sage

        sage: s = "00000000000+0000000000000000+00-0+00000000000+00-00+0-+00000\
        ....: 0000+-00+00-+00000000+00-0000+0000-+00000000+000-0+0-+0-+000\
        ....: 000+-000+-00+0000000+-+-000+00-+0-000+000+-000+-0+0000000-0+\
        ....: 0000+0-+0-+00000-+00000+-+0-0+-00+0000000000+-0000+0-00+0000\
        ....: 000000+0-000+000000000000000+0000-00+00000000+0000-000+00000\
        ....: 00+0-00+0000000000000000+-0000+000000-+000000+00-0000+-00+00\
        ....: 00000000+-0000+00000000000000+0000000000"
        sage: a = matrix(20, [{'0':0, '+':1, '-': -1}[i] for i in s])
        sage: fpl = FullyPackedLoop(a)
        sage: fpl.plot(loop_fill=True, loop_color_map='rainbow')                    # needs sage.plot
        Graphics object consisting of 27 graphics primitives

    [Python]

        >>> from sage.all import *
        >>> s = "00000000000+0000000000000000+00-0+00000000000+00-00+0-+00000\
        ... 0000+-00+00-+00000000+00-0000+0000-+00000000+000-0+0-+0-+000\
        ... 000+-000+-00+0000000+-+-000+00-+0-000+000+-000+-0+0000000-0+\
        ... 0000+0-+0-+00000-+00000+-+0-0+-00+0000000000+-0000+0-00+0000\
        ... 000000+0-000+000000000000000+0000-00+00000000+0000-000+00000\
        ... 00+0-00+0000000000000000+-0000+000000-+000000+00-0000+-00+00\
        ... 00000000+-0000+00000000000000+0000000000"
        >>> a = matrix(Integer(20), [{'0':Integer(0), '+':Integer(1), '-': -Integer(1)}[i] for i in s])
        >>> fpl = FullyPackedLoop(a)
        >>> fpl.plot(loop_fill=True, loop_color_map='rainbow')                    # needs sage.plot
        Graphics object consisting of 27 graphics primitives

  six_vertex_model()

    Return the underlying six vertex model configuration.

    EXAMPLES:

    Sage

        sage: B = AlternatingSignMatrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
        sage: fpl = FullyPackedLoop(B)
        sage: fpl
           │         │
           │         │
           +    + ── +
           │    │
           │    │
        ── +    +    + ──
                │    │
                │    │
           + ── +    +
           │         │
           │         │
        sage: fpl.six_vertex_model()
            ^    ^    ^
            |    |    |
        --> # <- # <- # <--
            |    ^    ^
            V    |    |
        --> # -> # <- # <--
            |    |    ^
            V    V    |
        --> # -> # -> # <--
            |    |    |
            V    V    V

    Python

        >>> from sage.all import *
        >>> B = AlternatingSignMatrix([[Integer(1), Integer(0), Integer(0)], [Integer(0), Integer(1), Integer(0)], [Integer(0), Integer(0), Integer(1)]])
        >>> fpl = FullyPackedLoop(B)
        >>> fpl
           │         │
           │         │
           +    + ── +
           │    │
           │    │
        ── +    +    + ──
                │    │
                │    │
           + ── +    +
           │         │
           │         │
        >>> fpl.six_vertex_model()
            ^    ^    ^
            |    |    |
        --> # <- # <- # <--
            |    ^    ^
            V    |    |
        --> # -> # <- # <--
            |    |    ^
            V    V    |
        --> # -> # -> # <--
            |    |    |
            V    V    V

  to_alternating_sign_matrix()

    Return the alternating sign matrix corresponding to this class.

    See also

    `AlternatingSignMatrix`

    EXAMPLES:

    Sage

        sage: A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]])
        sage: S = SixVertexModel(3, boundary_conditions='ice').from_alternating_sign_matrix(A)
        sage: fpl = FullyPackedLoop(S)
        sage: fpl.to_alternating_sign_matrix()
        [ 0  1  0]
        [ 1 -1  1]
        [ 0  1  0]
        sage: A = AlternatingSignMatrix([[0,1,0,0],[0,0,1,0],[1,-1,0,1],[0,1,0,0]])
        sage: S = SixVertexModel(4, boundary_conditions='ice').from_alternating_sign_matrix(A)
        sage: fpl = FullyPackedLoop(S)
        sage: fpl.to_alternating_sign_matrix()
        [ 0  1  0  0]
        [ 0  0  1  0]
        [ 1 -1  0  1]
        [ 0  1  0  0]

    Python

        >>> from sage.all import *
        >>> A = AlternatingSignMatrix([[Integer(0), Integer(1), Integer(0)], [Integer(1), -Integer(1), Integer(1)], [Integer(0), Integer(1), Integer(0)]])
        >>> S = SixVertexModel(Integer(3), boundary_conditions='ice').from_alternating_sign_matrix(A)
        >>> fpl = FullyPackedLoop(S)
        >>> fpl.to_alternating_sign_matrix()
        [ 0  1  0]
        [ 1 -1  1]
        [ 0  1  0]
        >>> A = AlternatingSignMatrix([[Integer(0),Integer(1),Integer(0),Integer(0)],[Integer(0),Integer(0),Integer(1),Integer(0)],[Integer(1),-Integer(1),Integer(0),Integer(1)],[Integer(0),Integer(1),Integer(0),Integer(0)]])
        >>> S = SixVertexModel(Integer(4), boundary_conditions='ice').from_alternating_sign_matrix(A)
        >>> fpl = FullyPackedLoop(S)
        >>> fpl.to_alternating_sign_matrix()
        [ 0  1  0  0]
        [ 0  0  1  0]
        [ 1 -1  0  1]
        [ 0  1  0  0]

class sage.combinat.fully_packed_loop.FullyPackedLoops(n)

  Bases: `Parent`, `UniqueRepresentation`

  Class of all fully packed loops on an \(n \times n\) grid.

  They are known to be in bijection with alternating sign matrices.

  See also

  `AlternatingSignMatrices`

  INPUT:

  - `n` – the number of row (and column) or grid

  EXAMPLES:

  This will create an instance to manipulate the fully packed loops of size 3:

  Sage

      sage: FPLs = FullyPackedLoops(3)
      sage: FPLs
      Fully packed loops on a 3x3 grid
      sage: FPLs.cardinality()
      7

  Python

      >>> from sage.all import *
      >>> FPLs = FullyPackedLoops(Integer(3))
      >>> FPLs
      Fully packed loops on a 3x3 grid
      >>> FPLs.cardinality()
      7

  When using the square ice model, it is known that the number of configurations is equal to the number of alternating sign matrices:

  Sage

      sage: M = FullyPackedLoops(1)
      sage: len(M)
      1
      sage: M = FullyPackedLoops(4)
      sage: len(M)
      42
      sage: all(len(SixVertexModel(n, boundary_conditions='ice'))
      ....:     == FullyPackedLoops(n).cardinality() for n in range(1, 7))
      True

  [Python]

      >>> from sage.all import *
      >>> M = FullyPackedLoops(Integer(1))
      >>> len(M)
      1
      >>> M = FullyPackedLoops(Integer(4))
      >>> len(M)
      42
      >>> all(len(SixVertexModel(n, boundary_conditions='ice'))
      ...     == FullyPackedLoops(n).cardinality() for n in range(Integer(1), Integer(7)))
      True

  Element

    alias of `FullyPackedLoop`

  cardinality()

    Return the cardinality of `self`.

    The number of fully packed loops on \(n \times n\) grid

    \[\prod_{k=0}^{n-1} \frac{(3k+1)!}{(n+k)!} = \frac{1! 4! 7! 10! \cdots (3n-2)!}{n! (n+1)! (n+2)! (n+3)! \cdots (2n-1)!}.\]

    EXAMPLES:

    Sage

        sage: [AlternatingSignMatrices(n).cardinality() for n in range(10)]
        [1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460]

    Python

        >>> from sage.all import *
        >>> [AlternatingSignMatrices(n).cardinality() for n in range(Integer(10))]
        [1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460]

  size()

    Return the size of the matrices in `self`.