Ticket #12384: 12384v2.patch

File 12384v2.patch, 117.4 KB (added by davidloeffler, 8 years ago)

Apply only this patch

  • sage/combinat/e_one_star.py

    # HG changeset patch
    # User David Roe <roed@math.harvard.edu>
    # Date 1327885515 28800
    # Node ID 565bc6447def921dc0d30ef98f7f6f31b14e7383
    # Parent  5b248150523745a5ce9a6b556907b3c73414a3aa
    #12384: removes all carriage returns from sage/combinat/e_one_star.py
    
    diff --git a/sage/combinat/e_one_star.py b/sage/combinat/e_one_star.py
    a b  
    1 r"""
    2 Substitutions over unit cube faces (Rauzy fractals)
    3 
    4 This module implements the `E_1^*(\sigma)` substitution
    5 associated with a one-dimensional substitution `\sigma`,
    6 that acts on unit faces of dimension `(d-1)` in `\RR^d`.
    7 
    8 This module defines the following classes and functions:
    9 
    10 - ``Face`` - a class to model a face
    11 
    12 - ``Patch`` - a class to model a finite set of faces
    13 
    14 - ``E1Star`` - a class to model the `E_1^*(\sigma)` application
    15   defined by the substitution sigma
    16 
    17 See the documentation of these objects for more information.
    18 
    19 The convention for the choice of the unit faces and the
    20 definition of `E_1^*(\sigma)` varies from article to article.
    21 Here, unit faces are defined by
    22 
    23 .. MATH::
    24 
    25     \begin{array}{ccc}
    26     \,[x, 1]^* & = & \{x + \lambda e_2 + \mu e_3 : \lambda, \mu \in [0,1]\} \\
    27     \,[x, 2]^* & = & \{x + \lambda e_1 + \mu e_3 : \lambda, \mu \in [0,1]\} \\
    28     \,[x, 3]^* & = & \{x + \lambda e_1 + \mu e_2 : \lambda, \mu \in [0,1]\}
    29     \end{array}
    30 
    31 and the dual substitution `E_1^*(\sigma)` is defined by
    32 
    33 .. MATH::
    34 
    35     E_1^*(\sigma)([x,i]^*) =
    36     \bigcup_{k = 1,2,3} \; \bigcup_{s | \sigma(k) = pis}
    37     [M^{-1}(x + \ell(s)), k]^*,
    38 
    39 where `\ell(s)` is the abelianized of `s`, and `M` is the matrix of `\sigma`.
    40 
    41 AUTHORS:
    42 
    43 - Franco Saliola (2009): initial version
    44 - Vincent Delecroix, Timo Jolivet, Stepan Starosta, Sebastien Labbe (2010-05): redesign
    45 - Timo Jolivet (2010-08, 2010-09, 2011): redesign
    46 
    47 REFERENCES:
    48 
    49 .. [AI] P. Arnoux, S. Ito,
    50    Pisot substitutions and Rauzy fractals,
    51    Bull. Belg. Math. Soc. 8 (2), 2001, pp. 181--207
    52 
    53 .. [SAI] Y. Sano, P. Arnoux, S. Ito,
    54    Higher dimensional extensions of substitutions and their dual maps,
    55    J. Anal. Math. 83, 2001, pp. 183--206
    56 
    57 EXAMPLES:
    58 
    59 We start by drawing a simple three-face patch::
    60 
    61     sage: from sage.combinat.e_one_star import E1Star, Face, Patch
    62     sage: x = [Face((0,0,0),1), Face((0,0,0),2), Face((0,0,0),3)]
    63     sage: P = Patch(x)
    64     sage: P
    65     Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*]
    66     sage: P.plot()                   #not tested
    67 
    68 We apply a substitution to this patch, and draw the result::
    69 
    70     sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    71     sage: E = E1Star(sigma)
    72     sage: E(P)
    73     Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*, [(0, 1, -1), 2]*, [(1, 0, -1), 1]*]
    74     sage: E(P).plot()                #not tested
    75 
    76 .. NOTE::
    77 
    78     - The type of a face is given by an integer in ``[1, ..., d]``
    79       where ``d`` is the length of the vector of the face.
    80 
    81     - The alphabet of the domain and the codomain of `\sigma` must be
    82       equal, and they must be of the form ``[1, ..., d]``, where ``d``
    83       is a positive integer corresponding to the length of the vectors
    84       of the faces on which `E_1^*(\sigma)` will act.
    85 
    86 ::
    87 
    88     sage: P = Patch([Face((0,0,0),1), Face((0,0,0),2), Face((0,0,0),3)])
    89     sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    90     sage: E = E1Star(sigma)
    91     sage: E(P)
    92     Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*, [(0, 1, -1), 2]*, [(1, 0, -1), 1]*]
    93 
    94 The application of an ``E1Star`` substitution assigns to each new face the color of its preimage.
    95 The ``repaint`` method allows us to repaint the faces of a patch.
    96 A single color can also be assigned to every face, by specifying a list of a single color::
    97 
    98     sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    99     sage: P = E(P, 5)
    100     sage: P.repaint(['green'])
    101     sage: P.plot()                   #not tested
    102 
    103 A list of colors allows us to color the faces sequentially::
    104 
    105     sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    106     sage: P = E(P)
    107     sage: P.repaint(['red', 'yellow', 'green', 'blue', 'black'])
    108     sage: P = E(P, 3)
    109     sage: P.plot()                   #not tested
    110 
    111 All the color schemes from ``matplotlib.cm.datad.keys()`` can be used::
    112 
    113     sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    114     sage: P.repaint(cmap='summer')
    115     sage: P = E(P, 3)
    116     sage: P.plot()                   #not tested
    117     sage: P.repaint(cmap='hsv')
    118     sage: P = E(P, 2)
    119     sage: P.plot()                   #not tested
    120 
    121 It is also possible to specify a dictionary to color the faces according to their type::
    122 
    123     sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    124     sage: P = E(P, 5)
    125     sage: P.repaint({1:(0.7, 0.7, 0.7), 2:(0.5,0.5,0.5), 3:(0.3,0.3,0.3)})
    126     sage: P.plot()                   #not tested
    127     sage: P.repaint({1:'red', 2:'yellow', 3:'green'})
    128     sage: P.plot()                   #not tested
    129 
    130 Let us look at a nice big patch in 3D::
    131 
    132     sage: sigma = WordMorphism({1:[1,2], 2:[3], 3:[1]})
    133     sage: E = E1Star(sigma)
    134     sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    135     sage: P = P + P.translate([-1,1,0])
    136     sage: P = E(P, 11)
    137     sage: P.plot3d()                 #not tested
    138 
    139 Plotting with TikZ pictures is possible::
    140 
    141     sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    142     sage: s = P.plot_tikz()
    143     sage: print s                    #not tested
    144     \begin{tikzpicture}
    145     [x={(-0.216506cm,-0.125000cm)}, y={(0.216506cm,-0.125000cm)}, z={(0.000000cm,0.250000cm)}]
    146     \definecolor{facecolor}{rgb}{0.000,1.000,0.000}
    147     \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
    148     (0, 0, 0) -- (0, 0, 1) -- (1, 0, 1) -- (1, 0, 0) -- cycle;
    149     \definecolor{facecolor}{rgb}{1.000,0.000,0.000}
    150     \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
    151     (0, 0, 0) -- (0, 1, 0) -- (0, 1, 1) -- (0, 0, 1) -- cycle;
    152     \definecolor{facecolor}{rgb}{0.000,0.000,1.000}
    153     \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
    154     (0, 0, 0) -- (1, 0, 0) -- (1, 1, 0) -- (0, 1, 0) -- cycle;
    155     \end{tikzpicture}
    156 
    157 Plotting patches made of unit segments instead of unit faces::
    158 
    159     sage: P = Patch([Face([0,0], 1), Face([0,0], 2)])
    160     sage: E = E1Star(WordMorphism({1:[1,2],2:[1]}))
    161     sage: F = E1Star(WordMorphism({1:[1,1,2],2:[2,1]}))
    162     sage: E(P,5).plot()
    163     sage: F(P,3).plot()
    164 
    165 Everything works in any dimension (except for the plotting features
    166 which only work in dimension two or three)::
    167 
    168     sage: P = Patch([Face((0,0,0,0),1), Face((0,0,0,0),4)])
    169     sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1,4], 4:[1]})
    170     sage: E = E1Star(sigma)
    171     sage: E(P)
    172     Patch: [[(0, 0, 0, 0), 3]*, [(0, 0, 0, 0), 4]*, [(0, 0, 1, -1), 3]*, [(0, 1, 0, -1), 2]*, [(1, 0, 0, -1), 1]*]
    173 
    174 ::
    175 
    176     sage: sigma = WordMorphism({1:[1,2],2:[1,3],3:[1,4],4:[1,5],5:[1,6],6:[1,7],7:[1,8],8:[1,9],9:[1,10],10:[1,11],11:[1,12],12:[1]})
    177     sage: E = E1Star(sigma)
    178     sage: E
    179     E_1^*(WordMorphism: 1->12, 10->1,11, 11->1,12, 12->1, 2->13, 3->14, 4->15, 5->16, 6->17, 7->18, 8->19, 9->1,10)
    180     sage: P = Patch([Face((0,0,0,0,0,0,0,0,0,0,0,0),t) for t in [1,2,3]])
    181     sage: for x in sorted(list(E(P)), key=lambda x : (x.vector(),x.type())): print x
    182     [(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 1]*
    183     [(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 2]*
    184     [(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 12]*
    185     [(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1), 11]*
    186     [(0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1), 10]*
    187     [(0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1), 9]*
    188     [(0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1), 8]*
    189     [(0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1), 7]*
    190     [(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1), 6]*
    191     [(0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, -1), 5]*
    192     [(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1), 4]*
    193     [(0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1), 3]*
    194     [(0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1), 2]*
    195     [(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1), 1]*
    196 """
    197 #*****************************************************************************
    198 #       Copyright (C) 2010 Franco Saliola <saliola@gmail.com>
    199 #                          Vincent Delecroix <20100.delecroix@gmail.com>
    200 #                          Timo Jolivet <timo.jolivet@gmail.com>
    201 #                          Stepan Starosta <stepan.starosta@gmail.com>
    202 #                          Sebastien Labbe <slabqc at gmail.com>
    203 #
    204 #  Distributed under the terms of the GNU General Public License (GPL)
    205 #  as published by the Free Software Foundation; either version 2 of
    206 #  the License, or (at your option) any later version.
    207 #                  http://www.gnu.org/licenses/
    208 #*****************************************************************************
    209 from sage.misc.functional import det
    210 from sage.structure.sage_object import SageObject
    211 from sage.combinat.words.morphism import WordMorphism
    212 from sage.matrix.constructor import matrix
    213 from sage.modules.free_module_element import vector
    214 from sage.plot.plot import Graphics
    215 from sage.plot.plot import rainbow
    216 from sage.plot.colors import Color
    217 from sage.plot.polygon import polygon
    218 from sage.plot.line import line
    219 from sage.rings.integer_ring import ZZ
    220 from sage.misc.latex import LatexExpr
    221 from sage.misc.lazy_attribute import lazy_attribute
    222 from sage.misc.cachefunc import cached_method
    223 
    224 # matplotlib color maps, loaded on-demand
    225 cm = None
    226 
    227 class Face(SageObject):
    228     r"""
    229     A class to model a unit face of arbitrary dimension.
    230 
    231     A unit face in dimension `d` is represented by
    232     a `d`-dimensional vector ``v`` and a type ``t`` in `\{1, \ldots, d\}`.
    233     The type of the face corresponds to the canonical unit vector
    234     to which the face is orthogonal.
    235     The optional ``color`` argument is used in plotting functions.
    236 
    237     INPUT:
    238 
    239     - ``v`` - tuple of integers
    240     - ``t`` - integer in ``[1, ..., len(v)]``, type of the face. The face of type `i`
    241       is orthogonal to the canonical vector `e_i`.
    242     - ``color`` - color (optional, default: ``None``) color of the face,
    243       used for plotting only. If ``None``, its value is guessed from the
    244       face type.
    245 
    246     EXAMPLES::
    247 
    248         sage: from sage.combinat.e_one_star import Face
    249         sage: f = Face((0,2,0), 3)
    250         sage: f.vector()
    251         (0, 2, 0)
    252         sage: f.type()
    253         3
    254 
    255     ::
    256 
    257         sage: f = Face((0,2,0), 3, color=(0.5, 0.5, 0.5))
    258         sage: f.color()
    259         RGB color (0.5, 0.5, 0.5)
    260     """
    261     def __init__(self, v, t, color=None):
    262         r"""
    263         Face constructor. See class doc for more information.
    264 
    265         EXAMPLES::
    266 
    267             sage: from sage.combinat.e_one_star import Face
    268             sage: f = Face((0,2,0), 3)
    269             sage: f.vector()
    270             (0, 2, 0)
    271             sage: f.type()
    272             3
    273 
    274         TEST:
    275 
    276         We test that types can be given by an int (see #10699)::
    277 
    278             sage: f = Face((0,2,0), int(1))
    279         """
    280         self._vector = (ZZ**len(v))(v)
    281         self._vector.set_immutable()
    282 
    283         if not((t in ZZ) and 1 <= t <= len(v)):
    284             raise ValueError, 'The type must be an integer between 1 and len(v)'
    285         self._type = t
    286 
    287         if color is None:
    288             if self._type == 1:
    289                 color = Color((1,0,0))
    290             elif self._type == 2:
    291                 color = Color((0,1,0))
    292             elif self._type == 3:
    293                 color = Color((0,0,1))
    294             else:
    295                 color = Color()
    296         self._color = Color(color)
    297 
    298     def __repr__(self):
    299         r"""
    300         String representation of a face.
    301 
    302         EXAMPLES::
    303 
    304             sage: from sage.combinat.e_one_star import Face
    305             sage: f = Face((0,0,0,3), 3)
    306             sage: f
    307             [(0, 0, 0, 3), 3]*
    308 
    309         ::
    310 
    311             sage: f = Face((0,0,0,3), 3)
    312             sage: f
    313             [(0, 0, 0, 3), 3]*
    314         """
    315         return "[%s, %s]*"%(self.vector(), self.type())
    316 
    317     def __eq__(self, other):
    318         r"""
    319         Equality of faces.
    320 
    321         EXAMPLES::
    322 
    323             sage: from sage.combinat.e_one_star import Face
    324             sage: f = Face((0,0,0,3), 3)
    325             sage: g = Face((0,0,0,3), 3)
    326             sage: f == g
    327             True
    328         """
    329         return (isinstance(other, Face) and
    330                 self.vector() == other.vector() and
    331                 self.type() == other.type() )
    332 
    333     def __cmp__(self, other):
    334         r"""
    335         Compare self and other, returning -1, 0, or 1, depending on if
    336         self < other, self == other, or self > other, respectively.
    337 
    338         The vectors of the faces are first compared,
    339         and the types of the faces are compared if the vectors are equal.
    340 
    341         EXAMPLES::
    342 
    343             sage: from sage.combinat.e_one_star import Face
    344             sage: Face([-2,1,0], 2) < Face([-1,2,2],3)
    345             True
    346             sage: Face([-2,1,0], 2) < Face([-2,1,0],3)
    347             True
    348             sage: Face([-2,1,0], 2) < Face([-2,1,0],2)
    349             False
    350         """
    351         v1 = self.vector()
    352         v2 = other.vector()
    353         t1 = self.type()
    354         t2 = other.type()
    355 
    356         if v1 < v2:
    357             return -1
    358         elif v1 > v2:
    359             return 1
    360         else:
    361             return t1.__cmp__(t2)
    362 
    363     def __hash__(self):
    364         r"""
    365         EXAMPLES::
    366 
    367             sage: from sage.combinat.e_one_star import Face
    368             sage: f = Face((0,0,0,3), 3)
    369             sage: g = Face((0,0,0,3), 3)
    370             sage: hash(f) == hash(g)
    371             True
    372         """
    373         return hash((self.vector(), self.type()))
    374 
    375     def __add__(self, other):
    376         r"""
    377         Addition of self with a Face, a Patch or a finite iterable of faces.
    378 
    379         INPUT:
    380 
    381         - ``other`` - a Patch or a Face or a finite iterable of faces
    382 
    383         EXAMPLES::
    384 
    385             sage: from sage.combinat.e_one_star import Face, Patch
    386             sage: f = Face([0,0,0], 3)
    387             sage: g = Face([0,1,-1], 2)
    388             sage: f + g
    389             Patch: [[(0, 0, 0), 3]*, [(0, 1, -1), 2]*]
    390             sage: P = Patch([Face([0,0,0], 1), Face([0,0,0], 2)])
    391             sage: f + P
    392             Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*]
    393 
    394         Adding a finite iterable of faces::
    395 
    396             sage: from sage.combinat.e_one_star import Face
    397             sage: f = Face([0,0,0], 3)
    398             sage: f + [f,f]
    399             Patch: [[(0, 0, 0), 3]*]
    400         """
    401         if isinstance(other, Face):
    402             return Patch([self, other])
    403         else:
    404             return Patch(other).union(self)
    405 
    406     def vector(self):
    407         r"""
    408         Return the vector of the face.
    409 
    410         EXAMPLES::
    411 
    412             sage: from sage.combinat.e_one_star import Face
    413             sage: f = Face((0,2,0), 3)
    414             sage: f.vector()
    415             (0, 2, 0)
    416         """
    417         return self._vector
    418 
    419     def type(self):
    420         r"""
    421         Returns the type of the face.
    422 
    423         EXAMPLES::
    424 
    425             sage: from sage.combinat.e_one_star import Face
    426             sage: f = Face((0,2,0), 3)
    427             sage: f.type()
    428             3
    429 
    430         ::
    431 
    432             sage: f = Face((0,2,0), 3)
    433             sage: f.type()
    434             3
    435         """
    436         return self._type
    437 
    438     def color(self, color=None):
    439         r"""
    440         Returns or change the color of the face.
    441 
    442         INPUT:
    443 
    444         - ``color`` - string, rgb tuple, color (optional, default: ``None``)
    445           the new color to assign to the face. If ``None``, it returns the
    446           color of the face.
    447 
    448         OUTPUT:
    449 
    450             color
    451 
    452         EXAMPLES::
    453 
    454             sage: from sage.combinat.e_one_star import Face
    455             sage: f = Face((0,2,0), 3)
    456             sage: f.color()
    457             RGB color (0.0, 0.0, 1.0)
    458             sage: f.color('red')
    459             sage: f.color()
    460             RGB color (1.0, 0.0, 0.0)
    461 
    462         """
    463         if color is None:
    464             return self._color
    465         else:
    466             self._color = Color(color)
    467 
    468     def _plot(self, projmat, face_contour, opacity):
    469         r"""
    470         Returns a 2D graphic object representing the face.
    471 
    472         INPUT:
    473 
    474         - ``projmat`` - 2*3 projection matrix (used only for faces in three dimensions)
    475         - ``face_contour`` - dict, maps the face type to vectors describing
    476           the contour of unit faces (used only for faces in three dimensions)
    477         - ``opacity`` - the alpha value for the color of the face
    478 
    479         OUTPUT:
    480 
    481             2D graphic object
    482 
    483         EXAMPLES::
    484 
    485             sage: from sage.combinat.e_one_star import Face
    486             sage: f = Face((0,0,3), 3)
    487             sage: projmat = matrix(2, [-1.7320508075688772*0.5, 1.7320508075688772*0.5, 0, -0.5, -0.5, 1])
    488             sage: face_contour = {}
    489             sage: face_contour[1] = map(vector, [(0,0,0),(0,1,0),(0,1,1),(0,0,1)]) 
    490             sage: face_contour[2] = map(vector, [(0,0,0),(0,0,1),(1,0,1),(1,0,0)]) 
    491             sage: face_contour[3] = map(vector, [(0,0,0),(1,0,0),(1,1,0),(0,1,0)])
    492             sage: G = f._plot(projmat, face_contour, 0.75)
    493 
    494         ::
    495 
    496             sage: f = Face((0,0), 2)
    497             sage: f._plot(None, None, 1)
    498         """
    499         v = self.vector()
    500         t = self.type()
    501         G = Graphics()
    502 
    503         if len(v) == 2:
    504             if t == 1:
    505                 G += line([v, v + vector([0,1])], rgbcolor=self.color(), thickness=1.5, alpha=opacity)
    506             elif t == 2:
    507                 G += line([v, v + vector([1,0])], rgbcolor=self.color(), thickness=1.5, alpha=opacity)
    508 
    509         elif len(v) == 3:
    510             G += polygon([projmat*(u+v) for u in face_contour[t]], alpha=opacity,
    511                    thickness=1, rgbcolor=self.color())
    512 
    513         else:
    514             raise NotImplementedError, "Plotting is implemented only for patches in two or three dimensions."
    515 
    516         return G
    517 
    518     def _plot3d(self, face_contour):
    519         r"""
    520         3D reprensentation of a unit face (Jmol).
    521 
    522         INPUT:
    523 
    524         - ``face_contour`` - dict, maps the face type to vectors describing
    525           the contour of unit faces
    526 
    527         EXAMPLES::
    528 
    529             sage: from sage.combinat.e_one_star import Face
    530             sage: f = Face((0,0,3), 3)
    531             sage: face_contour = {1: map(vector, [(0,0,0),(0,1,0),(0,1,1),(0,0,1)]), 2: map(vector, [(0,0,0),(0,0,1),(1,0,1),(1,0,0)]), 3: map(vector, [(0,0,0),(1,0,0),(1,1,0),(0,1,0)])}
    532             sage: G = f._plot3d(face_contour)      #not tested
    533         """
    534         v = self.vector()
    535         t = self.type()
    536         c = self.color()
    537         G = polygon([u+v for u in face_contour[t]], rgbcolor=c)
    538         return G
    539 
    540 class Patch(SageObject):
    541     r"""
    542     A class to model a collection of faces. A patch is represented by an immutable set of Faces.
    543 
    544     .. NOTE::
    545 
    546         The dimension of a patch is the length of the vectors of the faces in the patch,
    547         which is assumed to be the same for every face in the patch.
    548 
    549     .. NOTE::
    550 
    551         Since version 4.7.1, Patches are immutable, except for the colors of the faces,
    552         which are not taken into account for equality tests and hash functions.
    553 
    554     INPUT:
    555 
    556     - ``faces`` - finite iterable of faces
    557     - ``face_contour`` - dict (optional, default:``None``) maps the face
    558       type to vectors describing the contour of unit faces. If None,
    559       defaults contour are assumed for faces of type 1, 2, 3 or 1, 2, 3.
    560       Used in plotting methods only.
    561 
    562     EXAMPLES::
    563 
    564         sage: from sage.combinat.e_one_star import Face, Patch
    565         sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    566         sage: P
    567         Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*]
    568 
    569     ::
    570 
    571         sage: face_contour = {}
    572         sage: face_contour[1] = map(vector, [(0,0,0),(0,1,0),(0,1,1),(0,0,1)])
    573         sage: face_contour[2] = map(vector, [(0,0,0),(0,0,1),(1,0,1),(1,0,0)])
    574         sage: face_contour[3] = map(vector, [(0,0,0),(1,0,0),(1,1,0),(0,1,0)])
    575         sage: Patch([Face((0,0,0),t) for t in [1,2,3]], face_contour=face_contour)
    576         Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*]
    577     """
    578     def __init__(self, faces, face_contour=None):
    579         r"""
    580         Constructor of a patch (set of faces). See class doc for more information.
    581 
    582         EXAMPLES::
    583 
    584             sage: from sage.combinat.e_one_star import Face, Patch
    585             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    586             sage: P
    587             Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*]
    588 
    589         TEST:
    590 
    591         We test that colors are not anymore mixed up between Patches (see #11255)::
    592 
    593             sage: P = Patch([Face([0,0,0],2)])
    594             sage: Q = Patch(P)
    595             sage: next(iter(P)).color()
    596             RGB color (0.0, 1.0, 0.0)
    597             sage: next(iter(Q)).color('yellow')
    598             sage: next(iter(P)).color()
    599             RGB color (0.0, 1.0, 0.0)
    600 
    601         """
    602         self._faces = frozenset(Face(f.vector(), f.type(), f.color()) for f in faces)
    603 
    604         try:
    605             f0 = next(iter(self._faces))
    606         except StopIteration:
    607             self._dimension = None
    608         else:
    609             self._dimension = len(f0.vector())
    610 
    611         if not face_contour is None:
    612             self._face_contour = face_contour
    613 
    614         else:
    615             self._face_contour = {
    616                     1: map(vector, [(0,0,0),(0,1,0),(0,1,1),(0,0,1)]),
    617                     2: map(vector, [(0,0,0),(0,0,1),(1,0,1),(1,0,0)]),
    618                     3: map(vector, [(0,0,0),(1,0,0),(1,1,0),(0,1,0)])
    619             }
    620 
    621     def __eq__(self, other):
    622         r"""
    623         Equality test for Patch.
    624 
    625         INPUT:
    626 
    627         - ``other`` - an object
    628 
    629         EXAMPLES::
    630 
    631             sage: from sage.combinat.e_one_star import E1Star, Face, Patch
    632             sage: P = Patch([Face((0,0,0),1), Face((0,0,0),2), Face((0,0,0),3)])
    633             sage: Q = Patch([Face((0,1,0),1), Face((0,0,0),3)])
    634             sage: P == P
    635             True
    636             sage: P == Q
    637             False
    638             sage: P == 4
    639             False
    640 
    641         ::
    642 
    643             sage: s = WordMorphism({1:[1,3], 2:[1,2,3], 3:[3]})
    644             sage: t = WordMorphism({1:[1,2,3], 2:[2,3], 3:[3]})
    645             sage: P = Patch([Face((0,0,0), 1), Face((0,0,0), 2), Face((0,0,0), 3)])
    646             sage: E1Star(s)(P) == E1Star(t)(P)
    647             False
    648             sage: E1Star(s*t)(P) == E1Star(t)(E1Star(s)(P))
    649             True
    650         """
    651         return (isinstance(other, Patch) and self._faces == other._faces)
    652 
    653     def __hash__(self):
    654         r"""
    655         Hash function of Patch.
    656 
    657         EXAMPLES::
    658 
    659             sage: from sage.combinat.e_one_star import Face, Patch
    660             sage: x = [Face((0,0,0),t) for t in [1,2,3]]
    661             sage: P = Patch(x)
    662             sage: hash(P)      #random
    663             -4839605361791007520
    664 
    665         TEST:
    666 
    667         We test that two equal patches have the same hash (see #11255)::
    668 
    669             sage: P = Patch([Face([0,0,0],1), Face([0,0,0],2)])
    670             sage: Q = Patch([Face([0,0,0],2), Face([0,0,0],1)])
    671             sage: P == Q
    672             True
    673             sage: hash(P) == hash(Q)
    674             True
    675 
    676         Changing the color does not affect the hash value::
    677 
    678             sage: p = Patch([Face((0,0,0), t) for t in [1,2,3]])
    679             sage: H1 = hash(p)
    680             sage: p.repaint(['blue'])
    681             sage: H2 = hash(p)
    682             sage: H1 == H2
    683             True
    684         """
    685         return hash(self._faces)
    686 
    687     def __len__(self):
    688         r"""
    689         Returns the number of faces contained in the patch.
    690 
    691         OUPUT:
    692 
    693             integer
    694 
    695         EXAMPLES::
    696 
    697             sage: from sage.combinat.e_one_star import Face, Patch
    698             sage: x = [Face((0,0,0),t) for t in [1,2,3]]
    699             sage: P = Patch(x)
    700             sage: len(P)       #indirect doctest
    701             3
    702         """
    703         return len(self._faces)
    704 
    705     def __iter__(self):
    706         r"""
    707         Return an iterator over the faces of the patch.
    708 
    709         OUTPUT:
    710 
    711             iterator
    712 
    713         EXAMPLES::
    714 
    715             sage: from sage.combinat.e_one_star import Face, Patch
    716             sage: x = [Face((0,0,0),t) for t in [1,2,3]]
    717             sage: P = Patch(x)
    718             sage: it = iter(P)
    719             sage: type(it.next())
    720             <class 'sage.combinat.e_one_star.Face'>
    721             sage: type(it.next())
    722             <class 'sage.combinat.e_one_star.Face'>
    723             sage: type(it.next())
    724             <class 'sage.combinat.e_one_star.Face'>
    725             sage: type(it.next())
    726             Traceback (most recent call last):
    727             ...
    728             StopIteration
    729         """
    730         return iter(self._faces)
    731 
    732     def __add__(self, other):
    733         r"""
    734         Addition of patches (union).
    735 
    736         INPUT:
    737 
    738         - ``other`` - a Patch or a Face or a finite iterable of faces
    739 
    740         EXAMPLES::
    741 
    742             sage: from sage.combinat.e_one_star import Face, Patch
    743             sage: P = Patch([Face([0,0,0], 1), Face([0,0,0], 2)])
    744             sage: Q = P.translate([1,-1,0])
    745             sage: P + Q
    746             Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(1, -1, 0), 1]*, [(1, -1, 0), 2]*]
    747             sage: P + Face([0,0,0],3)
    748             Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*]
    749             sage: P + [Face([0,0,0],3), Face([1,1,1],2)]
    750             Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*, [(1, 1, 1), 2]*]
    751         """
    752         return self.union(other)
    753 
    754     def __sub__(self, other):
    755         r"""
    756         Subtraction of patches (difference).
    757 
    758         INPUT:
    759 
    760         - ``other`` - a Patch or a Face or a finite iterable of faces
    761 
    762         EXAMPLES::
    763 
    764             sage: from sage.combinat.e_one_star import Face, Patch
    765             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    766             sage: P - Face([0,0,0],2)
    767             Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 3]*]
    768             sage: P - P
    769             Patch: []
    770         """
    771         return self.difference(other)
    772 
    773     def __repr__(self):
    774         r"""
    775         String representation of a patch.
    776 
    777         Displays all the faces if there less than 20,
    778         otherwise displays only the number of faces.
    779 
    780         EXAMPLES::
    781 
    782             sage: from sage.combinat.e_one_star import Face, Patch
    783             sage: x = [Face((0,0,0),t) for t in [1,2,3]]
    784             sage: P = Patch(x)
    785             sage: P
    786             Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*]
    787 
    788         ::
    789 
    790             sage: x = [Face((0,0,a),1) for a in range(25)]
    791             sage: P = Patch(x)
    792             sage: P
    793             Patch of 25 faces
    794         """
    795         if len(self) <= 20:
    796             L = list(self)
    797             L.sort(key=lambda x : (x.vector(),x.type()))
    798             return "Patch: %s"%L
    799         else:
    800             return "Patch of %s faces"%len(self)
    801 
    802     def add(self, other):
    803         r"""
    804         Returns a Patch consisting of the union of self and other.
    805 
    806         INPUT:
    807 
    808         - ``other`` - a Patch or a Face or a finite iterable of faces
    809 
    810         EXAMPLES::
    811 
    812             sage: from sage.combinat.e_one_star import Face, Patch
    813             sage: P = Patch([Face((0,0,0),1), Face((0,0,0),2)])
    814             sage: P.add(Face((1,2,3), 3))   #not tested
    815             Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(1, 2, 3), 3]*]
    816             sage: P.add([Face((1,2,3), 3), Face((2,3,3), 2)])   #not tested
    817             Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(1, 2, 3), 3]*, [(2, 3, 3), 2]*]
    818         """
    819         from sage.misc.misc import deprecation
    820         deprecation("Objects sage.combinat.e_one_star.Patch " + \
    821                     "are immutable since Sage-4.7.1. " + \
    822                     "Use the usual addition (P + Q) or use the Patch.union method.")
    823         return self.union(other)
    824 
    825     def union(self, other):
    826         r"""
    827         Returns a Patch consisting of the union of self and other.
    828 
    829         INPUT:
    830 
    831         - ``other`` - a Patch or a Face or a finite iterable of faces
    832 
    833         EXAMPLES::
    834 
    835             sage: from sage.combinat.e_one_star import Face, Patch
    836             sage: P = Patch([Face((0,0,0),1), Face((0,0,0),2)])
    837             sage: P.union(Face((1,2,3), 3))
    838             Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(1, 2, 3), 3]*]
    839             sage: P.union([Face((1,2,3), 3), Face((2,3,3), 2)])
    840             Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(1, 2, 3), 3]*, [(2, 3, 3), 2]*]
    841         """
    842         if isinstance(other, Face):
    843             return Patch(self._faces.union([other]))
    844         else:
    845             return Patch(self._faces.union(other))
    846 
    847     def difference(self, other):
    848         r"""
    849         Returns the difference of self and other.
    850 
    851         INPUT:
    852 
    853         - ``other`` - a finite iterable of faces or a single face
    854 
    855         EXAMPLES::
    856 
    857             sage: from sage.combinat.e_one_star import Face, Patch
    858             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    859             sage: P.difference(Face([0,0,0],2))
    860             Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 3]*]
    861             sage: P.difference(P)
    862             Patch: []
    863         """
    864         if isinstance(other, Face):
    865             return Patch(self._faces.difference([other]))
    866         else:
    867             return Patch(self._faces.difference(other))
    868 
    869     def dimension(self):
    870         r"""
    871         Returns the dimension of the vectors of the faces of self
    872 
    873         It returns ``None`` if self is the empty patch.
    874 
    875         The dimension of a patch is the length of the vectors of the faces in the patch,
    876         which is assumed to be the same for every face in the patch.
    877 
    878         EXAMPLES::
    879 
    880             sage: from sage.combinat.e_one_star import Face, Patch
    881             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    882             sage: P.dimension()
    883             3
    884 
    885         TESTS::
    886 
    887             sage: from sage.combinat.e_one_star import Patch
    888             sage: p = Patch([])
    889             sage: p.dimension() is None
    890             True
    891 
    892         It works when the patch is created from an iterator::
    893 
    894             sage: p = Patch(Face((0,0,0),t) for t in [1,2,3])
    895             sage: p.dimension()
    896             3
    897         """
    898         return self._dimension
    899 
    900     def faces_of_vector(self, v):
    901         r"""
    902         Returns a list of the faces whose vector is ``v``.
    903 
    904         INPUT:
    905 
    906         - ``v`` - a vector
    907 
    908         EXAMPLES::
    909 
    910             sage: from sage.combinat.e_one_star import Face, Patch
    911             sage: P = Patch([Face((0,0,0),1), Face((1,2,0),3), Face((1,2,0),1)])
    912             sage: P.faces_of_vector([1,2,0])
    913             [[(1, 2, 0), 3]*, [(1, 2, 0), 1]*]
    914         """
    915         v = vector(v)
    916         return [f for f in self if f.vector() == v]
    917 
    918     def faces_of_type(self, t):
    919         r"""
    920         Returns a list of the faces that have type ``t``.
    921 
    922         INPUT:
    923 
    924         - ``t`` - integer or any other type
    925 
    926         EXAMPLES::
    927 
    928             sage: from sage.combinat.e_one_star import Face, Patch
    929             sage: P = Patch([Face((0,0,0),1), Face((1,2,0),3), Face((1,2,0),1)])
    930             sage: P.faces_of_type(1)
    931             [[(0, 0, 0), 1]*, [(1, 2, 0), 1]*]
    932         """
    933         return [f for f in self if f.type() == t]
    934 
    935     def faces_of_color(self, color):
    936         r"""
    937         Returns a list of the faces that have the given color.
    938 
    939         INPUT:
    940 
    941         - ``color`` - color
    942 
    943         EXAMPLES::
    944 
    945             sage: from sage.combinat.e_one_star import Face, Patch
    946             sage: P = Patch([Face((0,0,0),1, 'red'), Face((1,2,0),3, 'blue'), Face((1,2,0),1, 'red')])
    947             sage: P.faces_of_color('red')
    948             [[(0, 0, 0), 1]*, [(1, 2, 0), 1]*]
    949         """
    950         color = tuple(Color(color))
    951         return [f for f in self if tuple(f.color()) == color]
    952 
    953     def translate(self, v):
    954         r"""
    955         Returns a translated copy of self by vector ``v``.
    956 
    957         INPUT:
    958 
    959         - ``v`` - vector or tuple
    960 
    961         EXAMPLES::
    962 
    963             sage: from sage.combinat.e_one_star import Face, Patch
    964             sage: P = Patch([Face((0,0,0),1), Face((1,2,0),3), Face((1,2,0),1)])
    965             sage: P.translate([-1,-2,0])
    966             Patch: [[(-1, -2, 0), 1]*, [(0, 0, 0), 1]*, [(0, 0, 0), 3]*]
    967         """
    968         v = vector(v)
    969         return Patch(Face(f.vector()+v, f.type(), f.color()) for f in self)
    970 
    971     def occurrences_of(self, other):
    972         r"""
    973         Returns all positions at which other appears in self, that is,
    974         all vectors v such that ``set(other.translate(v)) <= set(self)``.
    975 
    976         INPUT:
    977 
    978         - ``other`` - a Patch
    979 
    980         OUTPUT:
    981 
    982             a list of vectors
    983 
    984         EXAMPLES::
    985 
    986             sage: from sage.combinat.e_one_star import Face, Patch, E1Star
    987             sage: P = Patch([Face([0,0,0], 1), Face([0,0,0], 2), Face([0,0,0], 3)])
    988             sage: Q = Patch([Face([0,0,0], 1), Face([0,0,0], 2)])
    989             sage: P.occurrences_of(Q)
    990             [(0, 0, 0)]
    991             sage: Q = Q.translate([1,2,3])
    992             sage: P.occurrences_of(Q)
    993             [(-1, -2, -3)]
    994 
    995         ::
    996 
    997             sage: E = E1Star(WordMorphism({1:[1,2], 2:[1,3], 3:[1]}))
    998             sage: P = Patch([Face([0,0,0], 1), Face([0,0,0], 2), Face([0,0,0], 3)])
    999             sage: P = E(P,4)
    1000             sage: Q = Patch([Face([0,0,0], 1), Face([0,0,0], 2)])
    1001             sage: L = P.occurrences_of(Q)
    1002             sage: sorted(L)
    1003             [(0, 0, 0), (0, 0, 1), (0, 1, -1), (1, 0, -1), (1, 1, -3), (1, 1, -2)]
    1004         """
    1005         f0 = next(iter(other))
    1006         x = f0.vector()
    1007         t = f0.type()
    1008         L = self.faces_of_type(t)
    1009         positions = []
    1010         for f in L:
    1011             y = f.vector()
    1012             if other.translate(y-x)._faces.issubset(self._faces):
    1013                 positions.append(y-x)
    1014         return positions
    1015 
    1016     def apply_substitution(self, E, iterations=1):
    1017         r"""
    1018         Returns the image of self by the E1Star substitution ``E``.
    1019 
    1020         The color of every new face in the image is given the same color as its preimage.
    1021 
    1022         INPUT:
    1023 
    1024         - ``E`` - an instance of the ``E1Star`` class. Its domain alphabet must
    1025           be of the same size as the dimension of the ambient space of the
    1026           faces.
    1027         - ``iterations`` - integer (optional, default: 1)
    1028           number of times the substitution E is applied
    1029 
    1030         EXAMPLES::
    1031 
    1032             sage: from sage.combinat.e_one_star import E1Star, Face, Patch
    1033             sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1034             sage: E = E1Star(sigma)
    1035             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    1036             sage: P.apply_substitution(E,6)     #not tested
    1037             Patch of 105 faces
    1038         """
    1039         if not isinstance(E, E1Star):
    1040             raise TypeError, "E must be an instance of E1Star"
    1041 
    1042         from sage.misc.misc import deprecation
    1043         deprecation("Objects sage.combinat.e_one_star.Patch " + \
    1044                     "are immutable since Sage-4.7.1. " + \
    1045                     "Use the usual calling method of E1Star (E(P)).")
    1046         return E(self, iterations=iterations)
    1047 
    1048     def repaint(self, cmap='Set1'):
    1049         r"""
    1050         Repaints all the faces of self from the given color map.
    1051 
    1052         This only changes the colors of the faces of self.
    1053 
    1054         INPUT:
    1055 
    1056         -  ``cmap`` - color map (default: ``'Set1'``). It can be one of the
    1057            following :
    1058 
    1059            - string - A coloring map. For available coloring map names type:
    1060              ``sorted(colormaps)``
    1061            - list - a list of colors to assign cyclically to the faces.
    1062              A list of a single color colors all the faces with the same color.
    1063            - dict - a dict of face types mapped to colors, to color the
    1064              faces according to their type.
    1065            - ``{}``, the empty dict - shorcut for
    1066              ``{1:'red', 2:'green', 3:'blue'}``.
    1067 
    1068         EXAMPLES:
    1069 
    1070         Using a color map::
    1071 
    1072             sage: from sage.combinat.e_one_star import Face, Patch
    1073             sage: color = (0, 0, 0)
    1074             sage: P = Patch([Face((0,0,0),t,color) for t in [1,2,3]])
    1075             sage: for f in P: f.color()
    1076             RGB color (0.0, 0.0, 0.0)
    1077             RGB color (0.0, 0.0, 0.0)
    1078             RGB color (0.0, 0.0, 0.0)
    1079             sage: P.repaint()
    1080             sage: next(iter(P)).color()    #random
    1081             RGB color (0.498..., 0.432..., 0.522...)
    1082 
    1083         Using a list of colors::
    1084 
    1085             sage: P = Patch([Face((0,0,0),t,color) for t in [1,2,3]])
    1086             sage: P.repaint([(0.9, 0.9, 0.9), (0.65,0.65,0.65), (0.4,0.4,0.4)])
    1087             sage: for f in P: f.color()
    1088             RGB color (0.9, 0.9, 0.9)
    1089             RGB color (0.65, 0.65, 0.65)
    1090             RGB color (0.4, 0.4, 0.4)
    1091 
    1092         Using a dictionary to color faces according to their type::
    1093 
    1094             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    1095             sage: P.repaint({1:'black', 2:'yellow', 3:'green'})
    1096             sage: P.plot()                   #not tested
    1097             sage: P.repaint({})
    1098             sage: P.plot()                   #not tested
    1099         """
    1100         if cmap == {}:
    1101             cmap = {1: 'red', 2:'green', 3:'blue'}
    1102 
    1103         if isinstance(cmap, dict):
    1104             for f in self:
    1105                 f.color(cmap[f.type()])
    1106 
    1107         elif isinstance(cmap, list):
    1108             L = len(cmap)
    1109             for i, f in enumerate(self):
    1110                 f.color(cmap[i % L])
    1111 
    1112         elif isinstance(cmap, str):
    1113             # matplotlib color maps
    1114             global cm
    1115             if not cm:
    1116                 from matplotlib import cm
    1117 
    1118             if not cmap in cm.datad.keys():
    1119                 raise RuntimeError("Color map %s not known (type sorted(colors) for valid names)" % cmap)
    1120             cmap = cm.__dict__[cmap]
    1121             dim = float(len(self))
    1122             for i,f in enumerate(self):
    1123                 f.color(cmap(i/dim)[:3])
    1124 
    1125         else:
    1126             raise TypeError, "Type of cmap (=%s) must be dict, list or str" %cmap
    1127 
    1128     def plot(self, projmat=None, opacity=0.75):
    1129         r"""
    1130         Returns a 2D graphic object depicting the patch.
    1131 
    1132         INPUT:
    1133 
    1134         - ``projmat`` - matrix (optional, default: ``None``) the projection
    1135           matrix. Its number of lines must be two. Its number of columns
    1136           must equal the dimension of the ambient space of the faces. If
    1137           ``None``, the isometric projection is used by default.
    1138 
    1139         - ``opacity`` - float between ``0`` and ``1`` (optional, default: ``0.75``)
    1140           opacity of the the face
    1141 
    1142         .. WARNING::
    1143 
    1144             Plotting is implemented only for patches in two or three dimensions.
    1145 
    1146         EXAMPLES::
    1147 
    1148             sage: from sage.combinat.e_one_star import E1Star, Face, Patch
    1149             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    1150             sage: P.plot()
    1151 
    1152         ::
    1153 
    1154             sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1155             sage: E = E1Star(sigma)
    1156             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    1157             sage: P = E(P, 5)
    1158             sage: P.plot()
    1159 
    1160         Plot with a different projection matrix::
    1161 
    1162             sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1163             sage: E = E1Star(sigma)
    1164             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    1165             sage: M = matrix(2, 3, [1,0,-1,0.3,1,-3])
    1166             sage: P = E(P, 3)
    1167             sage: P.plot(projmat=M)
    1168 
    1169         Plot patches made of unit segments::
    1170 
    1171             sage: P = Patch([Face([0,0], 1), Face([0,0], 2)])
    1172             sage: E = E1Star(WordMorphism({1:[1,2],2:[1]}))
    1173             sage: F = E1Star(WordMorphism({1:[1,1,2],2:[2,1]}))
    1174             sage: E(P,5).plot()
    1175             sage: F(P,3).plot()
    1176         """
    1177         if self.dimension() == 2:
    1178             G = Graphics()
    1179             for face in self:
    1180                 G += face._plot(None, None, 1)
    1181             G.set_aspect_ratio(1)
    1182             return G
    1183 
    1184         if self.dimension() == 3:
    1185             if projmat == None:
    1186                 projmat = matrix(2, [-1.7320508075688772*0.5, 1.7320508075688772*0.5, 0, -0.5, -0.5, 1])
    1187 
    1188             G = Graphics()
    1189             for face in self:
    1190                 G += face._plot(projmat, self._face_contour, opacity)
    1191             G.set_aspect_ratio(1)
    1192             return G
    1193 
    1194         else:
    1195             raise NotImplementedError, "Plotting is implemented only for patches in two or three dimensions."
    1196 
    1197     def plot3d(self):
    1198         r"""
    1199         Returns a 3D graphics object depicting the patch.
    1200 
    1201         .. WARNING::
    1202 
    1203             3D plotting is implemented only for patches in three dimensions.
    1204 
    1205         EXAMPLES::
    1206 
    1207             sage: from sage.combinat.e_one_star import E1Star, Face, Patch
    1208             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    1209             sage: P.plot3d()                #not tested
    1210 
    1211         ::
    1212 
    1213             sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1214             sage: E = E1Star(sigma)
    1215             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    1216             sage: P = E(P, 5)
    1217             sage: P.repaint()
    1218             sage: P.plot3d()                #not tested
    1219         """
    1220         if self.dimension() != 3:
    1221             raise NotImplementedError, "3D plotting is implemented only for patches in three dimensions."
    1222 
    1223         face_list = [face._plot3d(self._face_contour) for face in self]
    1224         G = sum(face_list)
    1225         return G
    1226 
    1227     def plot_tikz(self, projmat=None, print_tikz_env=True, edgecolor='black',
    1228             scale=0.25, drawzero=False, extra_code_before='', extra_code_after=''):
    1229         r"""
    1230         Returns a string containing some TikZ code to be included into
    1231         a LaTeX document, depicting the patch.
    1232 
    1233         .. WARNING::
    1234 
    1235             Tikz Plotting is implemented only for patches in three dimensions.
    1236 
    1237         INPUT:
    1238 
    1239         - ``projmat`` - matrix (optional, default: ``None``) the projection
    1240           matrix. Its number of lines must be two. Its number of columns
    1241           must equal the dimension of the ambient space of the faces. If
    1242           ``None``, the isometric projection is used by default.
    1243         - ``print_tikz_env`` - bool (optional, default: ``True``) if ``True``,
    1244           the tikzpicture environment are printed
    1245         - ``edgecolor`` - string (optional, default: ``'black'``) either
    1246           ``'black'`` or ``'facecolor'`` (color of unit face edges)
    1247         - ``scale`` - real number (optional, default: ``0.25``) scaling
    1248           constant for the whole figure
    1249         - ``drawzero`` - bool (optional, default: ``False``) if ``True``,
    1250           mark the origin by a black dot
    1251         - ``extra_code_before`` - string (optional, default: ``''``) extra code to
    1252           include in the tikz picture
    1253         - ``extra_code_after`` - string (optional, default: ``''``) extra code to
    1254           include in the tikz picture
    1255 
    1256         EXAMPLES::
    1257 
    1258             sage: from sage.combinat.e_one_star import E1Star, Face, Patch
    1259             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    1260             sage: s = P.plot_tikz()
    1261             sage: len(s)
    1262             602
    1263             sage: print s       #not tested
    1264             \begin{tikzpicture}
    1265             [x={(-0.216506cm,-0.125000cm)}, y={(0.216506cm,-0.125000cm)}, z={(0.000000cm,0.250000cm)}]
    1266             \definecolor{facecolor}{rgb}{0.000,1.000,0.000}
    1267             \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
    1268             (0, 0, 0) -- (0, 0, 1) -- (1, 0, 1) -- (1, 0, 0) -- cycle;
    1269             \definecolor{facecolor}{rgb}{1.000,0.000,0.000}
    1270             \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
    1271             (0, 0, 0) -- (0, 1, 0) -- (0, 1, 1) -- (0, 0, 1) -- cycle;
    1272             \definecolor{facecolor}{rgb}{0.000,0.000,1.000}
    1273             \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
    1274             (0, 0, 0) -- (1, 0, 0) -- (1, 1, 0) -- (0, 1, 0) -- cycle;
    1275             \end{tikzpicture}
    1276 
    1277         ::
    1278 
    1279             sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1280             sage: E = E1Star(sigma)
    1281             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    1282             sage: P = E(P, 4)
    1283             sage: from sage.misc.latex import latex             #not tested
    1284             sage: latex.add_to_preamble('\\usepackage{tikz}')   #not tested
    1285             sage: view(P, tightpage=true)                       #not tested
    1286 
    1287         Plot using shades of gray (useful for article figures)::
    1288 
    1289             sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1290             sage: E = E1Star(sigma)
    1291             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    1292             sage: P.repaint([(0.9, 0.9, 0.9), (0.65,0.65,0.65), (0.4,0.4,0.4)])
    1293             sage: P = E(P, 4)
    1294             sage: s = P.plot_tikz()
    1295 
    1296         Plotting with various options::
    1297 
    1298             sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1299             sage: E = E1Star(sigma)
    1300             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    1301             sage: M = matrix(2, 3, map(float, [1,0,-0.7071,0,1,-0.7071]))
    1302             sage: P = E(P, 3)
    1303             sage: s = P.plot_tikz(projmat=M, edgecolor='facecolor', scale=0.6, drawzero=True)
    1304 
    1305         Adding X, Y, Z axes using the extra code feature::
    1306 
    1307             sage: length = 1.5
    1308             sage: space = 0.3
    1309             sage: axes = ''
    1310             sage: axes += "\\draw[->, thick, black] (0,0,0) -- (%s, 0, 0);\n" % length
    1311             sage: axes += "\\draw[->, thick, black] (0,0,0) -- (0, %s, 0);\n" % length
    1312             sage: axes += "\\node at (%s,0,0) {$x$};\n" % (length + space)
    1313             sage: axes += "\\node at (0,%s,0) {$y$};\n" % (length + space)
    1314             sage: axes += "\\node at (0,0,%s) {$z$};\n" % (length + space)
    1315             sage: axes += "\\draw[->, thick, black] (0,0,0) -- (0, 0, %s);\n" % length
    1316             sage: cube = Patch([Face((0,0,0),1), Face((0,0,0),2), Face((0,0,0),3)])
    1317             sage: options = dict(scale=0.5,drawzero=True,extra_code_before=axes)
    1318             sage: s = cube.plot_tikz(**options)
    1319             sage: len(s)
    1320             986
    1321             sage: print s   #not tested
    1322             \begin{tikzpicture}
    1323             [x={(-0.433013cm,-0.250000cm)}, y={(0.433013cm,-0.250000cm)}, z={(0.000000cm,0.500000cm)}]
    1324             \draw[->, thick, black] (0,0,0) -- (1.50000000000000, 0, 0);
    1325             \draw[->, thick, black] (0,0,0) -- (0, 1.50000000000000, 0);
    1326             \node at (1.80000000000000,0,0) {$x$};
    1327             \node at (0,1.80000000000000,0) {$y$};
    1328             \node at (0,0,1.80000000000000) {$z$};
    1329             \draw[->, thick, black] (0,0,0) -- (0, 0, 1.50000000000000);
    1330             \definecolor{facecolor}{rgb}{0.000,1.000,0.000}
    1331             \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
    1332             (0, 0, 0) -- (0, 0, 1) -- (1, 0, 1) -- (1, 0, 0) -- cycle;
    1333             \definecolor{facecolor}{rgb}{1.000,0.000,0.000}
    1334             \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
    1335             (0, 0, 0) -- (0, 1, 0) -- (0, 1, 1) -- (0, 0, 1) -- cycle;
    1336             \definecolor{facecolor}{rgb}{0.000,0.000,1.000}
    1337             \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
    1338             (0, 0, 0) -- (1, 0, 0) -- (1, 1, 0) -- (0, 1, 0) -- cycle;
    1339             \node[circle,fill=black,draw=black,minimum size=1.5mm,inner sep=0pt] at (0,0,0) {};
    1340             \end{tikzpicture}
    1341         """
    1342         if self.dimension() != 3:
    1343             raise NotImplementedError, "Tikz Plotting is implemented only for patches in three dimensions."
    1344 
    1345         if projmat == None:
    1346             projmat = matrix(2, [-1.7320508075688772*0.5, 1.7320508075688772*0.5, 0, -0.5, -0.5, 1])*scale
    1347 
    1348         e1 = projmat*vector([1,0,0])
    1349         e2 = projmat*vector([0,1,0])
    1350         e3 = projmat*vector([0,0,1])
    1351         face_contour = self._face_contour
    1352         color = ()
    1353 
    1354         # string s contains the TiKZ code of the patch
    1355         s = ''
    1356 
    1357         if print_tikz_env:
    1358             s += '\\begin{tikzpicture}\n'
    1359             s += '[x={(%fcm,%fcm)}, y={(%fcm,%fcm)}, z={(%fcm,%fcm)}]\n'%(e1[0], e1[1], e2[0], e2[1], e3[0], e3[1])
    1360 
    1361         s += extra_code_before
    1362 
    1363         for f in self:
    1364             t = f.type()
    1365             x, y, z = f.vector()
    1366 
    1367             if tuple(color) != tuple(f.color()): #tuple is needed, comparison for RGB fails
    1368                 color = f.color()
    1369                 s += '\\definecolor{facecolor}{rgb}{%.3f,%.3f,%.3f}\n'%(color[0], color[1], color[2])
    1370 
    1371             s += '\\fill[fill=facecolor, draw=%s, shift={(%d,%d,%d)}]\n'%(edgecolor, x, y, z)
    1372             s += ' -- '.join(map(str, face_contour[t])) + ' -- cycle;\n'
    1373 
    1374         s += extra_code_after
    1375 
    1376         if drawzero:
    1377             s += '\\node[circle,fill=black,draw=black,minimum size=1.5mm,inner sep=0pt] at (0,0,0) {};\n'
    1378 
    1379         if print_tikz_env:
    1380             s += '\\end{tikzpicture}'
    1381 
    1382         return LatexExpr(s)
    1383 
    1384     _latex_ = plot_tikz
    1385 
    1386 class E1Star(SageObject):
    1387     r"""
    1388     A class to model the `E_1^*(\sigma)` map associated with
    1389     a unimodular substitution `\sigma`.
    1390 
    1391     INPUT:
    1392 
    1393     - ``sigma`` - unimodular ``WordMorphism``, i.e. such that its incidence
    1394       matrix has determinant `\pm 1`.
    1395 
    1396     - ``method`` - 'prefix' or 'suffix' (optional, default: 'suffix')
    1397       Enables to use an alternative definition `E_1^*(\sigma)` substitutions,
    1398       where the abelianized of the prefix` is used instead of the suffix.
    1399 
    1400     .. NOTE::
    1401 
    1402         The alphabet of the domain and the codomain of `\sigma` must be
    1403         equal, and they must be of the form ``[1, ..., d]``, where ``d``
    1404         is a positive integer corresponding to the length of the vectors
    1405         of the faces on which `E_1^*(\sigma)` will act.
    1406 
    1407     EXAMPLES::
    1408 
    1409         sage: from sage.combinat.e_one_star import E1Star, Face, Patch
    1410         sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    1411         sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1412         sage: E = E1Star(sigma)
    1413         sage: E(P)
    1414         Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*, [(0, 1, -1), 2]*, [(1, 0, -1), 1]*]
    1415 
    1416     ::
    1417 
    1418         sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    1419         sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1420         sage: E = E1Star(sigma, method='prefix')
    1421         sage: E(P)
    1422         Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*, [(0, 0, 1), 1]*, [(0, 0, 1), 2]*]
    1423 
    1424     ::
    1425 
    1426         sage: x = [Face((0,0,0,0),1), Face((0,0,0,0),4)]
    1427         sage: P = Patch(x)
    1428         sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1,4], 4:[1]})
    1429         sage: E = E1Star(sigma)
    1430         sage: E(P)
    1431         Patch: [[(0, 0, 0, 0), 3]*, [(0, 0, 0, 0), 4]*, [(0, 0, 1, -1), 3]*, [(0, 1, 0, -1), 2]*, [(1, 0, 0, -1), 1]*]
    1432     """
    1433     def __init__(self, sigma, method='suffix'):
    1434         r"""
    1435         E1Star constructor. See class doc for more information.
    1436 
    1437         EXAMPLES::
    1438 
    1439             sage: from sage.combinat.e_one_star import E1Star, Face, Patch
    1440             sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1441             sage: E = E1Star(sigma)
    1442             sage: E
    1443             E_1^*(WordMorphism: 1->12, 2->13, 3->1)
    1444         """
    1445         if not isinstance(sigma, WordMorphism):
    1446             raise TypeError, "sigma (=%s) must be an instance of WordMorphism"%sigma
    1447 
    1448         if sigma.domain().alphabet() != sigma.codomain().alphabet():
    1449             raise ValueError, "The domain and codomain of (%s) must be the same."%sigma
    1450 
    1451         if abs(det(matrix(sigma))) != 1:
    1452             raise ValueError, "The substitution (%s) must be unimodular."%sigma
    1453 
    1454         first_letter = sigma.codomain().alphabet()[0]
    1455         if not (first_letter in ZZ) or (first_letter < 1):
    1456             raise ValueError, "The substitution (%s) must be defined on positive integers."%sigma
    1457 
    1458         self._sigma = WordMorphism(sigma)
    1459         self._d = self._sigma.domain().size_of_alphabet()
    1460 
    1461         # self._base_iter is a base for the iteration of the application of self on set
    1462         # of faces. (Exploits the linearity of `E_1^*(\sigma)` to optimize computation.)
    1463         alphabet = self._sigma.domain().alphabet()
    1464         X = {}
    1465         for k in alphabet:
    1466             subst_im = self._sigma.image(k)
    1467             for n, letter in enumerate(subst_im):
    1468                 if method == 'suffix':
    1469                     image_word = subst_im[n+1:]
    1470                 elif method == 'prefix':
    1471                     image_word = subst_im[:n]
    1472                 else:
    1473                     raise ValueError, "Option 'method' can only be 'prefix' or 'suffix'."
    1474                 if not letter in X:
    1475                     X[letter] = []
    1476                 v = self.inverse_matrix()*vector(image_word.parikh_vector())
    1477                 X[letter].append((v, k))
    1478         self._base_iter = X
    1479 
    1480     def __eq__(self, other):
    1481         r"""
    1482         Equality test for E1Star morphisms.
    1483 
    1484         INPUT:
    1485 
    1486         - ``other`` - an object
    1487 
    1488         EXAMPLES::
    1489 
    1490             sage: from sage.combinat.e_one_star import E1Star, Face, Patch
    1491             sage: s = WordMorphism({1:[1,3], 2:[1,2,3], 3:[3]})
    1492             sage: t = WordMorphism({1:[1,2,3], 2:[2,3], 3:[3]})
    1493             sage: S = E1Star(s)
    1494             sage: T = E1Star(t)
    1495             sage: S == T
    1496             False
    1497             sage: S2 = E1Star(s, method='prefix')
    1498             sage: S == S2
    1499             False
    1500         """
    1501         return (isinstance(other, E1Star) and self._base_iter == other._base_iter)
    1502 
    1503     def __call__(self, patch, iterations=1):
    1504         r"""
    1505         Applies a generalized substitution to a Patch; this returns a new object.
    1506 
    1507         The color of every new face in the image is given the same color as its preimage.
    1508 
    1509         INPUT:
    1510 
    1511         - ``patch`` - a patch
    1512         - ``iterations`` - integer (optional, default: 1) number of iterations
    1513 
    1514         OUTPUT:
    1515 
    1516             a patch
    1517 
    1518         EXAMPLES::
    1519 
    1520             sage: from sage.combinat.e_one_star import E1Star, Face, Patch
    1521             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    1522             sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1523             sage: E = E1Star(sigma)
    1524             sage: E(P)
    1525             Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*, [(0, 1, -1), 2]*, [(1, 0, -1), 1]*]
    1526             sage: E(P, iterations=4)
    1527             Patch of 31 faces
    1528 
    1529         TEST:
    1530 
    1531         We test that iterations=0 works (see #10699)::
    1532 
    1533             sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
    1534             sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1535             sage: E = E1Star(sigma)
    1536             sage: E(P, iterations=0)
    1537             Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*]
    1538         """
    1539         if iterations == 0:
    1540             return Patch(patch)
    1541         elif iterations < 0:
    1542             raise ValueError, "iterations (=%s) must be >= 0." % iterations
    1543         else:
    1544             old_faces = patch
    1545             for i in xrange(iterations):
    1546                 new_faces = []
    1547                 for f in old_faces:
    1548                     new_faces.extend(self._call_on_face(f, color=f.color()))
    1549                 old_faces = new_faces
    1550             return Patch(new_faces)
    1551 
    1552     def __mul__(self, other):
    1553         r"""
    1554         Return the product of self and other.
    1555 
    1556         The product satisfies the following rule :
    1557         `E_1^*(\sigma\circ\sigma') = E_1^*(\sigma')` \circ  E_1^*(\sigma)`
    1558 
    1559         INPUT:
    1560 
    1561         - ``other`` - an instance of E1Star
    1562 
    1563         OUTPUT:
    1564 
    1565             an instance of E1Star
    1566 
    1567         EXAMPLES::
    1568 
    1569             sage: from sage.combinat.e_one_star import E1Star, Face, Patch
    1570             sage: s = WordMorphism({1:[2],2:[3],3:[1,2]})
    1571             sage: t = WordMorphism({1:[1,3,1],2:[1],3:[1,1,3,2]})
    1572             sage: E1Star(s) * E1Star(t)
    1573             E_1^*(WordMorphism: 1->1, 2->1132, 3->1311)
    1574             sage: E1Star(t * s)
    1575             E_1^*(WordMorphism: 1->1, 2->1132, 3->1311)
    1576         """
    1577         if not isinstance(other, E1Star):
    1578             raise TypeError, "other (=%s) must be an instance of E1Star" % other
    1579         return E1Star(other.sigma() * self.sigma())
    1580 
    1581     def __repr__(self):
    1582         r"""
    1583         String representation of a patch.
    1584 
    1585         EXAMPLES::
    1586 
    1587             sage: from sage.combinat.e_one_star import E1Star, Face, Patch
    1588             sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1589             sage: E = E1Star(sigma)
    1590             sage: E
    1591             E_1^*(WordMorphism: 1->12, 2->13, 3->1)
    1592         """
    1593         return "E_1^*(%s)" % str(self._sigma)
    1594 
    1595     def _call_on_face(self, face, color=None):
    1596         r"""
    1597         Returns an iterator of faces obtained by applying self on the face.
    1598 
    1599         INPUT:
    1600 
    1601         - ``face`` - a face
    1602         - ``color`` - string, RGB tuple or color, (optional, default: None)
    1603           RGB color
    1604 
    1605         OUTPUT:
    1606 
    1607             iterator of faces
    1608 
    1609         EXAMPLES::
    1610 
    1611             sage: from sage.combinat.e_one_star import E1Star, Face, Patch
    1612             sage: f = Face((0,2,0), 1)
    1613             sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1614             sage: E = E1Star(sigma)
    1615             sage: list(E._call_on_face(f))
    1616             [[(3, 0, -3), 1]*, [(2, 1, -3), 2]*, [(2, 0, -2), 3]*]
    1617         """
    1618         if len(face.vector()) != self._d:
    1619             raise ValueError, "The dimension of the faces must be equal to the size of the alphabet of the substitution."
    1620         x_new = self.inverse_matrix() * face.vector()
    1621         t = face.type()
    1622         return (Face(x_new + v, k, color=color) for v, k in self._base_iter[t])
    1623 
    1624     @cached_method
    1625     def matrix(self):
    1626         r"""
    1627         Returns the matrix associated with self.
    1628 
    1629         EXAMPLES::
    1630 
    1631             sage: from sage.combinat.e_one_star import E1Star, Face, Patch
    1632             sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1633             sage: E = E1Star(sigma)
    1634             sage: E.matrix()
    1635             [1 1 1]
    1636             [1 0 0]
    1637             [0 1 0]
    1638         """
    1639         return self._sigma.incidence_matrix()
    1640 
    1641     @cached_method
    1642     def inverse_matrix(self):
    1643         r"""
    1644         Returns the inverse of the matrix associated with self.
    1645 
    1646         EXAMPLES::
    1647 
    1648             sage: from sage.combinat.e_one_star import E1Star, Face, Patch
    1649             sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1650             sage: E = E1Star(sigma)
    1651             sage: E.inverse_matrix()
    1652             [ 0  1  0]
    1653             [ 0  0  1]
    1654             [ 1 -1 -1]
    1655 
    1656         """
    1657         return self.matrix().inverse()
    1658 
    1659     def sigma(self):
    1660         r"""
    1661         Returns the ``WordMorphism`` associated with self.
    1662 
    1663         EXAMPLES::
    1664 
    1665             sage: from sage.combinat.e_one_star import E1Star, Face, Patch
    1666             sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
    1667             sage: E = E1Star(sigma)
    1668             sage: print E.sigma()
    1669             WordMorphism: 1->12, 2->13, 3->1
    1670         """
    1671         return self._sigma
    1672 
     1r"""
     2Substitutions over unit cube faces (Rauzy fractals)
     3
     4This module implements the `E_1^*(\sigma)` substitution
     5associated with a one-dimensional substitution `\sigma`,
     6that acts on unit faces of dimension `(d-1)` in `\RR^d`.
     7
     8This module defines the following classes and functions:
     9
     10- ``Face`` - a class to model a face
     11
     12- ``Patch`` - a class to model a finite set of faces
     13
     14- ``E1Star`` - a class to model the `E_1^*(\sigma)` application
     15  defined by the substitution sigma
     16
     17See the documentation of these objects for more information.
     18
     19The convention for the choice of the unit faces and the
     20definition of `E_1^*(\sigma)` varies from article to article.
     21Here, unit faces are defined by
     22
     23.. MATH::
     24
     25    \begin{array}{ccc}
     26    \,[x, 1]^* & = & \{x + \lambda e_2 + \mu e_3 : \lambda, \mu \in [0,1]\} \\
     27    \,[x, 2]^* & = & \{x + \lambda e_1 + \mu e_3 : \lambda, \mu \in [0,1]\} \\
     28    \,[x, 3]^* & = & \{x + \lambda e_1 + \mu e_2 : \lambda, \mu \in [0,1]\}
     29    \end{array}
     30
     31and the dual substitution `E_1^*(\sigma)` is defined by
     32
     33.. MATH::
     34
     35    E_1^*(\sigma)([x,i]^*) =
     36    \bigcup_{k = 1,2,3} \; \bigcup_{s | \sigma(k) = pis}
     37    [M^{-1}(x + \ell(s)), k]^*,
     38
     39where `\ell(s)` is the abelianized of `s`, and `M` is the matrix of `\sigma`.
     40
     41AUTHORS:
     42
     43- Franco Saliola (2009): initial version
     44- Vincent Delecroix, Timo Jolivet, Stepan Starosta, Sebastien Labbe (2010-05): redesign
     45- Timo Jolivet (2010-08, 2010-09, 2011): redesign
     46
     47REFERENCES:
     48
     49.. [AI] P. Arnoux, S. Ito,
     50   Pisot substitutions and Rauzy fractals,
     51   Bull. Belg. Math. Soc. 8 (2), 2001, pp. 181--207
     52
     53.. [SAI] Y. Sano, P. Arnoux, S. Ito,
     54   Higher dimensional extensions of substitutions and their dual maps,
     55   J. Anal. Math. 83, 2001, pp. 183--206
     56
     57EXAMPLES:
     58
     59We start by drawing a simple three-face patch::
     60
     61    sage: from sage.combinat.e_one_star import E1Star, Face, Patch
     62    sage: x = [Face((0,0,0),1), Face((0,0,0),2), Face((0,0,0),3)]
     63    sage: P = Patch(x)
     64    sage: P
     65    Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*]
     66    sage: P.plot()                   #not tested
     67
     68We apply a substitution to this patch, and draw the result::
     69
     70    sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     71    sage: E = E1Star(sigma)
     72    sage: E(P)
     73    Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*, [(0, 1, -1), 2]*, [(1, 0, -1), 1]*]
     74    sage: E(P).plot()                #not tested
     75
     76.. NOTE::
     77
     78    - The type of a face is given by an integer in ``[1, ..., d]``
     79      where ``d`` is the length of the vector of the face.
     80
     81    - The alphabet of the domain and the codomain of `\sigma` must be
     82      equal, and they must be of the form ``[1, ..., d]``, where ``d``
     83      is a positive integer corresponding to the length of the vectors
     84      of the faces on which `E_1^*(\sigma)` will act.
     85
     86::
     87
     88    sage: P = Patch([Face((0,0,0),1), Face((0,0,0),2), Face((0,0,0),3)])
     89    sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     90    sage: E = E1Star(sigma)
     91    sage: E(P)
     92    Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*, [(0, 1, -1), 2]*, [(1, 0, -1), 1]*]
     93
     94The application of an ``E1Star`` substitution assigns to each new face the color of its preimage.
     95The ``repaint`` method allows us to repaint the faces of a patch.
     96A single color can also be assigned to every face, by specifying a list of a single color::
     97
     98    sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     99    sage: P = E(P, 5)
     100    sage: P.repaint(['green'])
     101    sage: P.plot()                   #not tested
     102
     103A list of colors allows us to color the faces sequentially::
     104
     105    sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     106    sage: P = E(P)
     107    sage: P.repaint(['red', 'yellow', 'green', 'blue', 'black'])
     108    sage: P = E(P, 3)
     109    sage: P.plot()                   #not tested
     110
     111All the color schemes from ``matplotlib.cm.datad.keys()`` can be used::
     112
     113    sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     114    sage: P.repaint(cmap='summer')
     115    sage: P = E(P, 3)
     116    sage: P.plot()                   #not tested
     117    sage: P.repaint(cmap='hsv')
     118    sage: P = E(P, 2)
     119    sage: P.plot()                   #not tested
     120
     121It is also possible to specify a dictionary to color the faces according to their type::
     122
     123    sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     124    sage: P = E(P, 5)
     125    sage: P.repaint({1:(0.7, 0.7, 0.7), 2:(0.5,0.5,0.5), 3:(0.3,0.3,0.3)})
     126    sage: P.plot()                   #not tested
     127    sage: P.repaint({1:'red', 2:'yellow', 3:'green'})
     128    sage: P.plot()                   #not tested
     129
     130Let us look at a nice big patch in 3D::
     131
     132    sage: sigma = WordMorphism({1:[1,2], 2:[3], 3:[1]})
     133    sage: E = E1Star(sigma)
     134    sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     135    sage: P = P + P.translate([-1,1,0])
     136    sage: P = E(P, 11)
     137    sage: P.plot3d()                 #not tested
     138
     139Plotting with TikZ pictures is possible::
     140
     141    sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     142    sage: s = P.plot_tikz()
     143    sage: print s                    #not tested
     144    \begin{tikzpicture}
     145    [x={(-0.216506cm,-0.125000cm)}, y={(0.216506cm,-0.125000cm)}, z={(0.000000cm,0.250000cm)}]
     146    \definecolor{facecolor}{rgb}{0.000,1.000,0.000}
     147    \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
     148    (0, 0, 0) -- (0, 0, 1) -- (1, 0, 1) -- (1, 0, 0) -- cycle;
     149    \definecolor{facecolor}{rgb}{1.000,0.000,0.000}
     150    \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
     151    (0, 0, 0) -- (0, 1, 0) -- (0, 1, 1) -- (0, 0, 1) -- cycle;
     152    \definecolor{facecolor}{rgb}{0.000,0.000,1.000}
     153    \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
     154    (0, 0, 0) -- (1, 0, 0) -- (1, 1, 0) -- (0, 1, 0) -- cycle;
     155    \end{tikzpicture}
     156
     157Plotting patches made of unit segments instead of unit faces::
     158
     159    sage: P = Patch([Face([0,0], 1), Face([0,0], 2)])
     160    sage: E = E1Star(WordMorphism({1:[1,2],2:[1]}))
     161    sage: F = E1Star(WordMorphism({1:[1,1,2],2:[2,1]}))
     162    sage: E(P,5).plot()
     163    sage: F(P,3).plot()
     164
     165Everything works in any dimension (except for the plotting features
     166which only work in dimension two or three)::
     167
     168    sage: P = Patch([Face((0,0,0,0),1), Face((0,0,0,0),4)])
     169    sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1,4], 4:[1]})
     170    sage: E = E1Star(sigma)
     171    sage: E(P)
     172    Patch: [[(0, 0, 0, 0), 3]*, [(0, 0, 0, 0), 4]*, [(0, 0, 1, -1), 3]*, [(0, 1, 0, -1), 2]*, [(1, 0, 0, -1), 1]*]
     173
     174::
     175
     176    sage: sigma = WordMorphism({1:[1,2],2:[1,3],3:[1,4],4:[1,5],5:[1,6],6:[1,7],7:[1,8],8:[1,9],9:[1,10],10:[1,11],11:[1,12],12:[1]})
     177    sage: E = E1Star(sigma)
     178    sage: E
     179    E_1^*(WordMorphism: 1->12, 10->1,11, 11->1,12, 12->1, 2->13, 3->14, 4->15, 5->16, 6->17, 7->18, 8->19, 9->1,10)
     180    sage: P = Patch([Face((0,0,0,0,0,0,0,0,0,0,0,0),t) for t in [1,2,3]])
     181    sage: for x in sorted(list(E(P)), key=lambda x : (x.vector(),x.type())): print x
     182    [(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 1]*
     183    [(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 2]*
     184    [(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 12]*
     185    [(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1), 11]*
     186    [(0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1), 10]*
     187    [(0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1), 9]*
     188    [(0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1), 8]*
     189    [(0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1), 7]*
     190    [(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1), 6]*
     191    [(0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, -1), 5]*
     192    [(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1), 4]*
     193    [(0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1), 3]*
     194    [(0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1), 2]*
     195    [(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1), 1]*
     196"""
     197#*****************************************************************************
     198#       Copyright (C) 2010 Franco Saliola <saliola@gmail.com>
     199#                          Vincent Delecroix <20100.delecroix@gmail.com>
     200#                          Timo Jolivet <timo.jolivet@gmail.com>
     201#                          Stepan Starosta <stepan.starosta@gmail.com>
     202#                          Sebastien Labbe <slabqc at gmail.com>
     203#
     204#  Distributed under the terms of the GNU General Public License (GPL)
     205#  as published by the Free Software Foundation; either version 2 of
     206#  the License, or (at your option) any later version.
     207#                  http://www.gnu.org/licenses/
     208#*****************************************************************************
     209from sage.misc.functional import det
     210from sage.structure.sage_object import SageObject
     211from sage.combinat.words.morphism import WordMorphism
     212from sage.matrix.constructor import matrix
     213from sage.modules.free_module_element import vector
     214from sage.plot.plot import Graphics
     215from sage.plot.plot import rainbow
     216from sage.plot.colors import Color
     217from sage.plot.polygon import polygon
     218from sage.plot.line import line
     219from sage.rings.integer_ring import ZZ
     220from sage.misc.latex import LatexExpr
     221from sage.misc.lazy_attribute import lazy_attribute
     222from sage.misc.cachefunc import cached_method
     223
     224# matplotlib color maps, loaded on-demand
     225cm = None
     226
     227class Face(SageObject):
     228    r"""
     229    A class to model a unit face of arbitrary dimension.
     230
     231    A unit face in dimension `d` is represented by
     232    a `d`-dimensional vector ``v`` and a type ``t`` in `\{1, \ldots, d\}`.
     233    The type of the face corresponds to the canonical unit vector
     234    to which the face is orthogonal.
     235    The optional ``color`` argument is used in plotting functions.
     236
     237    INPUT:
     238
     239    - ``v`` - tuple of integers
     240    - ``t`` - integer in ``[1, ..., len(v)]``, type of the face. The face of type `i`
     241      is orthogonal to the canonical vector `e_i`.
     242    - ``color`` - color (optional, default: ``None``) color of the face,
     243      used for plotting only. If ``None``, its value is guessed from the
     244      face type.
     245
     246    EXAMPLES::
     247
     248        sage: from sage.combinat.e_one_star import Face
     249        sage: f = Face((0,2,0), 3)
     250        sage: f.vector()
     251        (0, 2, 0)
     252        sage: f.type()
     253        3
     254
     255    ::
     256
     257        sage: f = Face((0,2,0), 3, color=(0.5, 0.5, 0.5))
     258        sage: f.color()
     259        RGB color (0.5, 0.5, 0.5)
     260    """
     261    def __init__(self, v, t, color=None):
     262        r"""
     263        Face constructor. See class doc for more information.
     264
     265        EXAMPLES::
     266
     267            sage: from sage.combinat.e_one_star import Face
     268            sage: f = Face((0,2,0), 3)
     269            sage: f.vector()
     270            (0, 2, 0)
     271            sage: f.type()
     272            3
     273
     274        TEST:
     275
     276        We test that types can be given by an int (see #10699)::
     277
     278            sage: f = Face((0,2,0), int(1))
     279        """
     280        self._vector = (ZZ**len(v))(v)
     281        self._vector.set_immutable()
     282
     283        if not((t in ZZ) and 1 <= t <= len(v)):
     284            raise ValueError, 'The type must be an integer between 1 and len(v)'
     285        self._type = t
     286
     287        if color is None:
     288            if self._type == 1:
     289                color = Color((1,0,0))
     290            elif self._type == 2:
     291                color = Color((0,1,0))
     292            elif self._type == 3:
     293                color = Color((0,0,1))
     294            else:
     295                color = Color()
     296        self._color = Color(color)
     297
     298    def __repr__(self):
     299        r"""
     300        String representation of a face.
     301
     302        EXAMPLES::
     303
     304            sage: from sage.combinat.e_one_star import Face
     305            sage: f = Face((0,0,0,3), 3)
     306            sage: f
     307            [(0, 0, 0, 3), 3]*
     308
     309        ::
     310
     311            sage: f = Face((0,0,0,3), 3)
     312            sage: f
     313            [(0, 0, 0, 3), 3]*
     314        """
     315        return "[%s, %s]*"%(self.vector(), self.type())
     316
     317    def __eq__(self, other):
     318        r"""
     319        Equality of faces.
     320
     321        EXAMPLES::
     322
     323            sage: from sage.combinat.e_one_star import Face
     324            sage: f = Face((0,0,0,3), 3)
     325            sage: g = Face((0,0,0,3), 3)
     326            sage: f == g
     327            True
     328        """
     329        return (isinstance(other, Face) and
     330                self.vector() == other.vector() and
     331                self.type() == other.type() )
     332
     333    def __cmp__(self, other):
     334        r"""
     335        Compare self and other, returning -1, 0, or 1, depending on if
     336        self < other, self == other, or self > other, respectively.
     337
     338        The vectors of the faces are first compared,
     339        and the types of the faces are compared if the vectors are equal.
     340
     341        EXAMPLES::
     342
     343            sage: from sage.combinat.e_one_star import Face
     344            sage: Face([-2,1,0], 2) < Face([-1,2,2],3)
     345            True
     346            sage: Face([-2,1,0], 2) < Face([-2,1,0],3)
     347            True
     348            sage: Face([-2,1,0], 2) < Face([-2,1,0],2)
     349            False
     350        """
     351        v1 = self.vector()
     352        v2 = other.vector()
     353        t1 = self.type()
     354        t2 = other.type()
     355
     356        if v1 < v2:
     357            return -1
     358        elif v1 > v2:
     359            return 1
     360        else:
     361            return t1.__cmp__(t2)
     362
     363    def __hash__(self):
     364        r"""
     365        EXAMPLES::
     366
     367            sage: from sage.combinat.e_one_star import Face
     368            sage: f = Face((0,0,0,3), 3)
     369            sage: g = Face((0,0,0,3), 3)
     370            sage: hash(f) == hash(g)
     371            True
     372        """
     373        return hash((self.vector(), self.type()))
     374
     375    def __add__(self, other):
     376        r"""
     377        Addition of self with a Face, a Patch or a finite iterable of faces.
     378
     379        INPUT:
     380
     381        - ``other`` - a Patch or a Face or a finite iterable of faces
     382
     383        EXAMPLES::
     384
     385            sage: from sage.combinat.e_one_star import Face, Patch
     386            sage: f = Face([0,0,0], 3)
     387            sage: g = Face([0,1,-1], 2)
     388            sage: f + g
     389            Patch: [[(0, 0, 0), 3]*, [(0, 1, -1), 2]*]
     390            sage: P = Patch([Face([0,0,0], 1), Face([0,0,0], 2)])
     391            sage: f + P
     392            Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*]
     393
     394        Adding a finite iterable of faces::
     395
     396            sage: from sage.combinat.e_one_star import Face
     397            sage: f = Face([0,0,0], 3)
     398            sage: f + [f,f]
     399            Patch: [[(0, 0, 0), 3]*]
     400        """
     401        if isinstance(other, Face):
     402            return Patch([self, other])
     403        else:
     404            return Patch(other).union(self)
     405
     406    def vector(self):
     407        r"""
     408        Return the vector of the face.
     409
     410        EXAMPLES::
     411
     412            sage: from sage.combinat.e_one_star import Face
     413            sage: f = Face((0,2,0), 3)
     414            sage: f.vector()
     415            (0, 2, 0)
     416        """
     417        return self._vector
     418
     419    def type(self):
     420        r"""
     421        Returns the type of the face.
     422
     423        EXAMPLES::
     424
     425            sage: from sage.combinat.e_one_star import Face
     426            sage: f = Face((0,2,0), 3)
     427            sage: f.type()
     428            3
     429
     430        ::
     431
     432            sage: f = Face((0,2,0), 3)
     433            sage: f.type()
     434            3
     435        """
     436        return self._type
     437
     438    def color(self, color=None):
     439        r"""
     440        Returns or change the color of the face.
     441
     442        INPUT:
     443
     444        - ``color`` - string, rgb tuple, color (optional, default: ``None``)
     445          the new color to assign to the face. If ``None``, it returns the
     446          color of the face.
     447
     448        OUTPUT:
     449
     450            color
     451
     452        EXAMPLES::
     453
     454            sage: from sage.combinat.e_one_star import Face
     455            sage: f = Face((0,2,0), 3)
     456            sage: f.color()
     457            RGB color (0.0, 0.0, 1.0)
     458            sage: f.color('red')
     459            sage: f.color()
     460            RGB color (1.0, 0.0, 0.0)
     461
     462        """
     463        if color is None:
     464            return self._color
     465        else:
     466            self._color = Color(color)
     467
     468    def _plot(self, projmat, face_contour, opacity):
     469        r"""
     470        Returns a 2D graphic object representing the face.
     471
     472        INPUT:
     473
     474        - ``projmat`` - 2*3 projection matrix (used only for faces in three dimensions)
     475        - ``face_contour`` - dict, maps the face type to vectors describing
     476          the contour of unit faces (used only for faces in three dimensions)
     477        - ``opacity`` - the alpha value for the color of the face
     478
     479        OUTPUT:
     480
     481            2D graphic object
     482
     483        EXAMPLES::
     484
     485            sage: from sage.combinat.e_one_star import Face
     486            sage: f = Face((0,0,3), 3)
     487            sage: projmat = matrix(2, [-1.7320508075688772*0.5, 1.7320508075688772*0.5, 0, -0.5, -0.5, 1])
     488            sage: face_contour = {}
     489            sage: face_contour[1] = map(vector, [(0,0,0),(0,1,0),(0,1,1),(0,0,1)])
     490            sage: face_contour[2] = map(vector, [(0,0,0),(0,0,1),(1,0,1),(1,0,0)])
     491            sage: face_contour[3] = map(vector, [(0,0,0),(1,0,0),(1,1,0),(0,1,0)])
     492            sage: G = f._plot(projmat, face_contour, 0.75)
     493
     494        ::
     495
     496            sage: f = Face((0,0), 2)
     497            sage: f._plot(None, None, 1)
     498        """
     499        v = self.vector()
     500        t = self.type()
     501        G = Graphics()
     502
     503        if len(v) == 2:
     504            if t == 1:
     505                G += line([v, v + vector([0,1])], rgbcolor=self.color(), thickness=1.5, alpha=opacity)
     506            elif t == 2:
     507                G += line([v, v + vector([1,0])], rgbcolor=self.color(), thickness=1.5, alpha=opacity)
     508
     509        elif len(v) == 3:
     510            G += polygon([projmat*(u+v) for u in face_contour[t]], alpha=opacity,
     511                   thickness=1, rgbcolor=self.color())
     512
     513        else:
     514            raise NotImplementedError, "Plotting is implemented only for patches in two or three dimensions."
     515
     516        return G
     517
     518    def _plot3d(self, face_contour):
     519        r"""
     520        3D reprensentation of a unit face (Jmol).
     521
     522        INPUT:
     523
     524        - ``face_contour`` - dict, maps the face type to vectors describing
     525          the contour of unit faces
     526
     527        EXAMPLES::
     528
     529            sage: from sage.combinat.e_one_star import Face
     530            sage: f = Face((0,0,3), 3)
     531            sage: face_contour = {1: map(vector, [(0,0,0),(0,1,0),(0,1,1),(0,0,1)]), 2: map(vector, [(0,0,0),(0,0,1),(1,0,1),(1,0,0)]), 3: map(vector, [(0,0,0),(1,0,0),(1,1,0),(0,1,0)])}
     532            sage: G = f._plot3d(face_contour)      #not tested
     533        """
     534        v = self.vector()
     535        t = self.type()
     536        c = self.color()
     537        G = polygon([u+v for u in face_contour[t]], rgbcolor=c)
     538        return G
     539
     540class Patch(SageObject):
     541    r"""
     542    A class to model a collection of faces. A patch is represented by an immutable set of Faces.
     543
     544    .. NOTE::
     545
     546        The dimension of a patch is the length of the vectors of the faces in the patch,
     547        which is assumed to be the same for every face in the patch.
     548
     549    .. NOTE::
     550
     551        Since version 4.7.1, Patches are immutable, except for the colors of the faces,
     552        which are not taken into account for equality tests and hash functions.
     553
     554    INPUT:
     555
     556    - ``faces`` - finite iterable of faces
     557    - ``face_contour`` - dict (optional, default:``None``) maps the face
     558      type to vectors describing the contour of unit faces. If None,
     559      defaults contour are assumed for faces of type 1, 2, 3 or 1, 2, 3.
     560      Used in plotting methods only.
     561
     562    EXAMPLES::
     563
     564        sage: from sage.combinat.e_one_star import Face, Patch
     565        sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     566        sage: P
     567        Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*]
     568
     569    ::
     570
     571        sage: face_contour = {}
     572        sage: face_contour[1] = map(vector, [(0,0,0),(0,1,0),(0,1,1),(0,0,1)])
     573        sage: face_contour[2] = map(vector, [(0,0,0),(0,0,1),(1,0,1),(1,0,0)])
     574        sage: face_contour[3] = map(vector, [(0,0,0),(1,0,0),(1,1,0),(0,1,0)])
     575        sage: Patch([Face((0,0,0),t) for t in [1,2,3]], face_contour=face_contour)
     576        Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*]
     577    """
     578    def __init__(self, faces, face_contour=None):
     579        r"""
     580        Constructor of a patch (set of faces). See class doc for more information.
     581
     582        EXAMPLES::
     583
     584            sage: from sage.combinat.e_one_star import Face, Patch
     585            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     586            sage: P
     587            Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*]
     588
     589        TEST:
     590
     591        We test that colors are not anymore mixed up between Patches (see #11255)::
     592
     593            sage: P = Patch([Face([0,0,0],2)])
     594            sage: Q = Patch(P)
     595            sage: next(iter(P)).color()
     596            RGB color (0.0, 1.0, 0.0)
     597            sage: next(iter(Q)).color('yellow')
     598            sage: next(iter(P)).color()
     599            RGB color (0.0, 1.0, 0.0)
     600
     601        """
     602        self._faces = frozenset(Face(f.vector(), f.type(), f.color()) for f in faces)
     603
     604        try:
     605            f0 = next(iter(self._faces))
     606        except StopIteration:
     607            self._dimension = None
     608        else:
     609            self._dimension = len(f0.vector())
     610
     611        if not face_contour is None:
     612            self._face_contour = face_contour
     613
     614        else:
     615            self._face_contour = {
     616                    1: map(vector, [(0,0,0),(0,1,0),(0,1,1),(0,0,1)]),
     617                    2: map(vector, [(0,0,0),(0,0,1),(1,0,1),(1,0,0)]),
     618                    3: map(vector, [(0,0,0),(1,0,0),(1,1,0),(0,1,0)])
     619            }
     620
     621    def __eq__(self, other):
     622        r"""
     623        Equality test for Patch.
     624
     625        INPUT:
     626
     627        - ``other`` - an object
     628
     629        EXAMPLES::
     630
     631            sage: from sage.combinat.e_one_star import E1Star, Face, Patch
     632            sage: P = Patch([Face((0,0,0),1), Face((0,0,0),2), Face((0,0,0),3)])
     633            sage: Q = Patch([Face((0,1,0),1), Face((0,0,0),3)])
     634            sage: P == P
     635            True
     636            sage: P == Q
     637            False
     638            sage: P == 4
     639            False
     640
     641        ::
     642
     643            sage: s = WordMorphism({1:[1,3], 2:[1,2,3], 3:[3]})
     644            sage: t = WordMorphism({1:[1,2,3], 2:[2,3], 3:[3]})
     645            sage: P = Patch([Face((0,0,0), 1), Face((0,0,0), 2), Face((0,0,0), 3)])
     646            sage: E1Star(s)(P) == E1Star(t)(P)
     647            False
     648            sage: E1Star(s*t)(P) == E1Star(t)(E1Star(s)(P))
     649            True
     650        """
     651        return (isinstance(other, Patch) and self._faces == other._faces)
     652
     653    def __hash__(self):
     654        r"""
     655        Hash function of Patch.
     656
     657        EXAMPLES::
     658
     659            sage: from sage.combinat.e_one_star import Face, Patch
     660            sage: x = [Face((0,0,0),t) for t in [1,2,3]]
     661            sage: P = Patch(x)
     662            sage: hash(P)      #random
     663            -4839605361791007520
     664
     665        TEST:
     666
     667        We test that two equal patches have the same hash (see #11255)::
     668
     669            sage: P = Patch([Face([0,0,0],1), Face([0,0,0],2)])
     670            sage: Q = Patch([Face([0,0,0],2), Face([0,0,0],1)])
     671            sage: P == Q
     672            True
     673            sage: hash(P) == hash(Q)
     674            True
     675
     676        Changing the color does not affect the hash value::
     677
     678            sage: p = Patch([Face((0,0,0), t) for t in [1,2,3]])
     679            sage: H1 = hash(p)
     680            sage: p.repaint(['blue'])
     681            sage: H2 = hash(p)
     682            sage: H1 == H2
     683            True
     684        """
     685        return hash(self._faces)
     686
     687    def __len__(self):
     688        r"""
     689        Returns the number of faces contained in the patch.
     690
     691        OUPUT:
     692
     693            integer
     694
     695        EXAMPLES::
     696
     697            sage: from sage.combinat.e_one_star import Face, Patch
     698            sage: x = [Face((0,0,0),t) for t in [1,2,3]]
     699            sage: P = Patch(x)
     700            sage: len(P)       #indirect doctest
     701            3
     702        """
     703        return len(self._faces)
     704
     705    def __iter__(self):
     706        r"""
     707        Return an iterator over the faces of the patch.
     708
     709        OUTPUT:
     710
     711            iterator
     712
     713        EXAMPLES::
     714
     715            sage: from sage.combinat.e_one_star import Face, Patch
     716            sage: x = [Face((0,0,0),t) for t in [1,2,3]]
     717            sage: P = Patch(x)
     718            sage: it = iter(P)
     719            sage: type(it.next())
     720            <class 'sage.combinat.e_one_star.Face'>
     721            sage: type(it.next())
     722            <class 'sage.combinat.e_one_star.Face'>
     723            sage: type(it.next())
     724            <class 'sage.combinat.e_one_star.Face'>
     725            sage: type(it.next())
     726            Traceback (most recent call last):
     727            ...
     728            StopIteration
     729        """
     730        return iter(self._faces)
     731
     732    def __add__(self, other):
     733        r"""
     734        Addition of patches (union).
     735
     736        INPUT:
     737
     738        - ``other`` - a Patch or a Face or a finite iterable of faces
     739
     740        EXAMPLES::
     741
     742            sage: from sage.combinat.e_one_star import Face, Patch
     743            sage: P = Patch([Face([0,0,0], 1), Face([0,0,0], 2)])
     744            sage: Q = P.translate([1,-1,0])
     745            sage: P + Q
     746            Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(1, -1, 0), 1]*, [(1, -1, 0), 2]*]
     747            sage: P + Face([0,0,0],3)
     748            Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*]
     749            sage: P + [Face([0,0,0],3), Face([1,1,1],2)]
     750            Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*, [(1, 1, 1), 2]*]
     751        """
     752        return self.union(other)
     753
     754    def __sub__(self, other):
     755        r"""
     756        Subtraction of patches (difference).
     757
     758        INPUT:
     759
     760        - ``other`` - a Patch or a Face or a finite iterable of faces
     761
     762        EXAMPLES::
     763
     764            sage: from sage.combinat.e_one_star import Face, Patch
     765            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     766            sage: P - Face([0,0,0],2)
     767            Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 3]*]
     768            sage: P - P
     769            Patch: []
     770        """
     771        return self.difference(other)
     772
     773    def __repr__(self):
     774        r"""
     775        String representation of a patch.
     776
     777        Displays all the faces if there less than 20,
     778        otherwise displays only the number of faces.
     779
     780        EXAMPLES::
     781
     782            sage: from sage.combinat.e_one_star import Face, Patch
     783            sage: x = [Face((0,0,0),t) for t in [1,2,3]]
     784            sage: P = Patch(x)
     785            sage: P
     786            Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*]
     787
     788        ::
     789
     790            sage: x = [Face((0,0,a),1) for a in range(25)]
     791            sage: P = Patch(x)
     792            sage: P
     793            Patch of 25 faces
     794        """
     795        if len(self) <= 20:
     796            L = list(self)
     797            L.sort(key=lambda x : (x.vector(),x.type()))
     798            return "Patch: %s"%L
     799        else:
     800            return "Patch of %s faces"%len(self)
     801
     802    def add(self, other):
     803        r"""
     804        Returns a Patch consisting of the union of self and other.
     805
     806        INPUT:
     807
     808        - ``other`` - a Patch or a Face or a finite iterable of faces
     809
     810        EXAMPLES::
     811
     812            sage: from sage.combinat.e_one_star import Face, Patch
     813            sage: P = Patch([Face((0,0,0),1), Face((0,0,0),2)])
     814            sage: P.add(Face((1,2,3), 3))   #not tested
     815            Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(1, 2, 3), 3]*]
     816            sage: P.add([Face((1,2,3), 3), Face((2,3,3), 2)])   #not tested
     817            Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(1, 2, 3), 3]*, [(2, 3, 3), 2]*]
     818        """
     819        from sage.misc.misc import deprecation
     820        deprecation("Objects sage.combinat.e_one_star.Patch " + \
     821                    "are immutable since Sage-4.7.1. " + \
     822                    "Use the usual addition (P + Q) or use the Patch.union method.")
     823        return self.union(other)
     824
     825    def union(self, other):
     826        r"""
     827        Returns a Patch consisting of the union of self and other.
     828
     829        INPUT:
     830
     831        - ``other`` - a Patch or a Face or a finite iterable of faces
     832
     833        EXAMPLES::
     834
     835            sage: from sage.combinat.e_one_star import Face, Patch
     836            sage: P = Patch([Face((0,0,0),1), Face((0,0,0),2)])
     837            sage: P.union(Face((1,2,3), 3))
     838            Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(1, 2, 3), 3]*]
     839            sage: P.union([Face((1,2,3), 3), Face((2,3,3), 2)])
     840            Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(1, 2, 3), 3]*, [(2, 3, 3), 2]*]
     841        """
     842        if isinstance(other, Face):
     843            return Patch(self._faces.union([other]))
     844        else:
     845            return Patch(self._faces.union(other))
     846
     847    def difference(self, other):
     848        r"""
     849        Returns the difference of self and other.
     850
     851        INPUT:
     852
     853        - ``other`` - a finite iterable of faces or a single face
     854
     855        EXAMPLES::
     856
     857            sage: from sage.combinat.e_one_star import Face, Patch
     858            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     859            sage: P.difference(Face([0,0,0],2))
     860            Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 3]*]
     861            sage: P.difference(P)
     862            Patch: []
     863        """
     864        if isinstance(other, Face):
     865            return Patch(self._faces.difference([other]))
     866        else:
     867            return Patch(self._faces.difference(other))
     868
     869    def dimension(self):
     870        r"""
     871        Returns the dimension of the vectors of the faces of self
     872
     873        It returns ``None`` if self is the empty patch.
     874
     875        The dimension of a patch is the length of the vectors of the faces in the patch,
     876        which is assumed to be the same for every face in the patch.
     877
     878        EXAMPLES::
     879
     880            sage: from sage.combinat.e_one_star import Face, Patch
     881            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     882            sage: P.dimension()
     883            3
     884
     885        TESTS::
     886
     887            sage: from sage.combinat.e_one_star import Patch
     888            sage: p = Patch([])
     889            sage: p.dimension() is None
     890            True
     891
     892        It works when the patch is created from an iterator::
     893
     894            sage: p = Patch(Face((0,0,0),t) for t in [1,2,3])
     895            sage: p.dimension()
     896            3
     897        """
     898        return self._dimension
     899
     900    def faces_of_vector(self, v):
     901        r"""
     902        Returns a list of the faces whose vector is ``v``.
     903
     904        INPUT:
     905
     906        - ``v`` - a vector
     907
     908        EXAMPLES::
     909
     910            sage: from sage.combinat.e_one_star import Face, Patch
     911            sage: P = Patch([Face((0,0,0),1), Face((1,2,0),3), Face((1,2,0),1)])
     912            sage: P.faces_of_vector([1,2,0])
     913            [[(1, 2, 0), 3]*, [(1, 2, 0), 1]*]
     914        """
     915        v = vector(v)
     916        return [f for f in self if f.vector() == v]
     917
     918    def faces_of_type(self, t):
     919        r"""
     920        Returns a list of the faces that have type ``t``.
     921
     922        INPUT:
     923
     924        - ``t`` - integer or any other type
     925
     926        EXAMPLES::
     927
     928            sage: from sage.combinat.e_one_star import Face, Patch
     929            sage: P = Patch([Face((0,0,0),1), Face((1,2,0),3), Face((1,2,0),1)])
     930            sage: P.faces_of_type(1)
     931            [[(0, 0, 0), 1]*, [(1, 2, 0), 1]*]
     932        """
     933        return [f for f in self if f.type() == t]
     934
     935    def faces_of_color(self, color):
     936        r"""
     937        Returns a list of the faces that have the given color.
     938
     939        INPUT:
     940
     941        - ``color`` - color
     942
     943        EXAMPLES::
     944
     945            sage: from sage.combinat.e_one_star import Face, Patch
     946            sage: P = Patch([Face((0,0,0),1, 'red'), Face((1,2,0),3, 'blue'), Face((1,2,0),1, 'red')])
     947            sage: P.faces_of_color('red')
     948            [[(0, 0, 0), 1]*, [(1, 2, 0), 1]*]
     949        """
     950        color = tuple(Color(color))
     951        return [f for f in self if tuple(f.color()) == color]
     952
     953    def translate(self, v):
     954        r"""
     955        Returns a translated copy of self by vector ``v``.
     956
     957        INPUT:
     958
     959        - ``v`` - vector or tuple
     960
     961        EXAMPLES::
     962
     963            sage: from sage.combinat.e_one_star import Face, Patch
     964            sage: P = Patch([Face((0,0,0),1), Face((1,2,0),3), Face((1,2,0),1)])
     965            sage: P.translate([-1,-2,0])
     966            Patch: [[(-1, -2, 0), 1]*, [(0, 0, 0), 1]*, [(0, 0, 0), 3]*]
     967        """
     968        v = vector(v)
     969        return Patch(Face(f.vector()+v, f.type(), f.color()) for f in self)
     970
     971    def occurrences_of(self, other):
     972        r"""
     973        Returns all positions at which other appears in self, that is,
     974        all vectors v such that ``set(other.translate(v)) <= set(self)``.
     975
     976        INPUT:
     977
     978        - ``other`` - a Patch
     979
     980        OUTPUT:
     981
     982            a list of vectors
     983
     984        EXAMPLES::
     985
     986            sage: from sage.combinat.e_one_star import Face, Patch, E1Star
     987            sage: P = Patch([Face([0,0,0], 1), Face([0,0,0], 2), Face([0,0,0], 3)])
     988            sage: Q = Patch([Face([0,0,0], 1), Face([0,0,0], 2)])
     989            sage: P.occurrences_of(Q)
     990            [(0, 0, 0)]
     991            sage: Q = Q.translate([1,2,3])
     992            sage: P.occurrences_of(Q)
     993            [(-1, -2, -3)]
     994
     995        ::
     996
     997            sage: E = E1Star(WordMorphism({1:[1,2], 2:[1,3], 3:[1]}))
     998            sage: P = Patch([Face([0,0,0], 1), Face([0,0,0], 2), Face([0,0,0], 3)])
     999            sage: P = E(P,4)
     1000            sage: Q = Patch([Face([0,0,0], 1), Face([0,0,0], 2)])
     1001            sage: L = P.occurrences_of(Q)
     1002            sage: sorted(L)
     1003            [(0, 0, 0), (0, 0, 1), (0, 1, -1), (1, 0, -1), (1, 1, -3), (1, 1, -2)]
     1004        """
     1005        f0 = next(iter(other))
     1006        x = f0.vector()
     1007        t = f0.type()
     1008        L = self.faces_of_type(t)
     1009        positions = []
     1010        for f in L:
     1011            y = f.vector()
     1012            if other.translate(y-x)._faces.issubset(self._faces):
     1013                positions.append(y-x)
     1014        return positions
     1015
     1016    def apply_substitution(self, E, iterations=1):
     1017        r"""
     1018        Returns the image of self by the E1Star substitution ``E``.
     1019
     1020        The color of every new face in the image is given the same color as its preimage.
     1021
     1022        INPUT:
     1023
     1024        - ``E`` - an instance of the ``E1Star`` class. Its domain alphabet must
     1025          be of the same size as the dimension of the ambient space of the
     1026          faces.
     1027        - ``iterations`` - integer (optional, default: 1)
     1028          number of times the substitution E is applied
     1029
     1030        EXAMPLES::
     1031
     1032            sage: from sage.combinat.e_one_star import E1Star, Face, Patch
     1033            sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1034            sage: E = E1Star(sigma)
     1035            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     1036            sage: P.apply_substitution(E,6)     #not tested
     1037            Patch of 105 faces
     1038        """
     1039        if not isinstance(E, E1Star):
     1040            raise TypeError, "E must be an instance of E1Star"
     1041
     1042        from sage.misc.misc import deprecation
     1043        deprecation("Objects sage.combinat.e_one_star.Patch " + \
     1044                    "are immutable since Sage-4.7.1. " + \
     1045                    "Use the usual calling method of E1Star (E(P)).")
     1046        return E(self, iterations=iterations)
     1047
     1048    def repaint(self, cmap='Set1'):
     1049        r"""
     1050        Repaints all the faces of self from the given color map.
     1051
     1052        This only changes the colors of the faces of self.
     1053
     1054        INPUT:
     1055
     1056        -  ``cmap`` - color map (default: ``'Set1'``). It can be one of the
     1057           following :
     1058
     1059           - string - A coloring map. For available coloring map names type:
     1060             ``sorted(colormaps)``
     1061           - list - a list of colors to assign cyclically to the faces.
     1062             A list of a single color colors all the faces with the same color.
     1063           - dict - a dict of face types mapped to colors, to color the
     1064             faces according to their type.
     1065           - ``{}``, the empty dict - shorcut for
     1066             ``{1:'red', 2:'green', 3:'blue'}``.
     1067
     1068        EXAMPLES:
     1069
     1070        Using a color map::
     1071
     1072            sage: from sage.combinat.e_one_star import Face, Patch
     1073            sage: color = (0, 0, 0)
     1074            sage: P = Patch([Face((0,0,0),t,color) for t in [1,2,3]])
     1075            sage: for f in P: f.color()
     1076            RGB color (0.0, 0.0, 0.0)
     1077            RGB color (0.0, 0.0, 0.0)
     1078            RGB color (0.0, 0.0, 0.0)
     1079            sage: P.repaint()
     1080            sage: next(iter(P)).color()    #random
     1081            RGB color (0.498..., 0.432..., 0.522...)
     1082
     1083        Using a list of colors::
     1084
     1085            sage: P = Patch([Face((0,0,0),t,color) for t in [1,2,3]])
     1086            sage: P.repaint([(0.9, 0.9, 0.9), (0.65,0.65,0.65), (0.4,0.4,0.4)])
     1087            sage: for f in P: f.color()
     1088            RGB color (0.9, 0.9, 0.9)
     1089            RGB color (0.65, 0.65, 0.65)
     1090            RGB color (0.4, 0.4, 0.4)
     1091
     1092        Using a dictionary to color faces according to their type::
     1093
     1094            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     1095            sage: P.repaint({1:'black', 2:'yellow', 3:'green'})
     1096            sage: P.plot()                   #not tested
     1097            sage: P.repaint({})
     1098            sage: P.plot()                   #not tested
     1099        """
     1100        if cmap == {}:
     1101            cmap = {1: 'red', 2:'green', 3:'blue'}
     1102
     1103        if isinstance(cmap, dict):
     1104            for f in self:
     1105                f.color(cmap[f.type()])
     1106
     1107        elif isinstance(cmap, list):
     1108            L = len(cmap)
     1109            for i, f in enumerate(self):
     1110                f.color(cmap[i % L])
     1111
     1112        elif isinstance(cmap, str):
     1113            # matplotlib color maps
     1114            global cm
     1115            if not cm:
     1116                from matplotlib import cm
     1117
     1118            if not cmap in cm.datad.keys():
     1119                raise RuntimeError("Color map %s not known (type sorted(colors) for valid names)" % cmap)
     1120            cmap = cm.__dict__[cmap]
     1121            dim = float(len(self))
     1122            for i,f in enumerate(self):
     1123                f.color(cmap(i/dim)[:3])
     1124
     1125        else:
     1126            raise TypeError, "Type of cmap (=%s) must be dict, list or str" %cmap
     1127
     1128    def plot(self, projmat=None, opacity=0.75):
     1129        r"""
     1130        Returns a 2D graphic object depicting the patch.
     1131
     1132        INPUT:
     1133
     1134        - ``projmat`` - matrix (optional, default: ``None``) the projection
     1135          matrix. Its number of lines must be two. Its number of columns
     1136          must equal the dimension of the ambient space of the faces. If
     1137          ``None``, the isometric projection is used by default.
     1138
     1139        - ``opacity`` - float between ``0`` and ``1`` (optional, default: ``0.75``)
     1140          opacity of the the face
     1141
     1142        .. WARNING::
     1143
     1144            Plotting is implemented only for patches in two or three dimensions.
     1145
     1146        EXAMPLES::
     1147
     1148            sage: from sage.combinat.e_one_star import E1Star, Face, Patch
     1149            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     1150            sage: P.plot()
     1151
     1152        ::
     1153
     1154            sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1155            sage: E = E1Star(sigma)
     1156            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     1157            sage: P = E(P, 5)
     1158            sage: P.plot()
     1159
     1160        Plot with a different projection matrix::
     1161
     1162            sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1163            sage: E = E1Star(sigma)
     1164            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     1165            sage: M = matrix(2, 3, [1,0,-1,0.3,1,-3])
     1166            sage: P = E(P, 3)
     1167            sage: P.plot(projmat=M)
     1168
     1169        Plot patches made of unit segments::
     1170
     1171            sage: P = Patch([Face([0,0], 1), Face([0,0], 2)])
     1172            sage: E = E1Star(WordMorphism({1:[1,2],2:[1]}))
     1173            sage: F = E1Star(WordMorphism({1:[1,1,2],2:[2,1]}))
     1174            sage: E(P,5).plot()
     1175            sage: F(P,3).plot()
     1176        """
     1177        if self.dimension() == 2:
     1178            G = Graphics()
     1179            for face in self:
     1180                G += face._plot(None, None, 1)
     1181            G.set_aspect_ratio(1)
     1182            return G
     1183
     1184        if self.dimension() == 3:
     1185            if projmat == None:
     1186                projmat = matrix(2, [-1.7320508075688772*0.5, 1.7320508075688772*0.5, 0, -0.5, -0.5, 1])
     1187
     1188            G = Graphics()
     1189            for face in self:
     1190                G += face._plot(projmat, self._face_contour, opacity)
     1191            G.set_aspect_ratio(1)
     1192            return G
     1193
     1194        else:
     1195            raise NotImplementedError, "Plotting is implemented only for patches in two or three dimensions."
     1196
     1197    def plot3d(self):
     1198        r"""
     1199        Returns a 3D graphics object depicting the patch.
     1200
     1201        .. WARNING::
     1202
     1203            3D plotting is implemented only for patches in three dimensions.
     1204
     1205        EXAMPLES::
     1206
     1207            sage: from sage.combinat.e_one_star import E1Star, Face, Patch
     1208            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     1209            sage: P.plot3d()                #not tested
     1210
     1211        ::
     1212
     1213            sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1214            sage: E = E1Star(sigma)
     1215            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     1216            sage: P = E(P, 5)
     1217            sage: P.repaint()
     1218            sage: P.plot3d()                #not tested
     1219        """
     1220        if self.dimension() != 3:
     1221            raise NotImplementedError, "3D plotting is implemented only for patches in three dimensions."
     1222
     1223        face_list = [face._plot3d(self._face_contour) for face in self]
     1224        G = sum(face_list)
     1225        return G
     1226
     1227    def plot_tikz(self, projmat=None, print_tikz_env=True, edgecolor='black',
     1228            scale=0.25, drawzero=False, extra_code_before='', extra_code_after=''):
     1229        r"""
     1230        Returns a string containing some TikZ code to be included into
     1231        a LaTeX document, depicting the patch.
     1232
     1233        .. WARNING::
     1234
     1235            Tikz Plotting is implemented only for patches in three dimensions.
     1236
     1237        INPUT:
     1238
     1239        - ``projmat`` - matrix (optional, default: ``None``) the projection
     1240          matrix. Its number of lines must be two. Its number of columns
     1241          must equal the dimension of the ambient space of the faces. If
     1242          ``None``, the isometric projection is used by default.
     1243        - ``print_tikz_env`` - bool (optional, default: ``True``) if ``True``,
     1244          the tikzpicture environment are printed
     1245        - ``edgecolor`` - string (optional, default: ``'black'``) either
     1246          ``'black'`` or ``'facecolor'`` (color of unit face edges)
     1247        - ``scale`` - real number (optional, default: ``0.25``) scaling
     1248          constant for the whole figure
     1249        - ``drawzero`` - bool (optional, default: ``False``) if ``True``,
     1250          mark the origin by a black dot
     1251        - ``extra_code_before`` - string (optional, default: ``''``) extra code to
     1252          include in the tikz picture
     1253        - ``extra_code_after`` - string (optional, default: ``''``) extra code to
     1254          include in the tikz picture
     1255
     1256        EXAMPLES::
     1257
     1258            sage: from sage.combinat.e_one_star import E1Star, Face, Patch
     1259            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     1260            sage: s = P.plot_tikz()
     1261            sage: len(s)
     1262            602
     1263            sage: print s       #not tested
     1264            \begin{tikzpicture}
     1265            [x={(-0.216506cm,-0.125000cm)}, y={(0.216506cm,-0.125000cm)}, z={(0.000000cm,0.250000cm)}]
     1266            \definecolor{facecolor}{rgb}{0.000,1.000,0.000}
     1267            \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
     1268            (0, 0, 0) -- (0, 0, 1) -- (1, 0, 1) -- (1, 0, 0) -- cycle;
     1269            \definecolor{facecolor}{rgb}{1.000,0.000,0.000}
     1270            \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
     1271            (0, 0, 0) -- (0, 1, 0) -- (0, 1, 1) -- (0, 0, 1) -- cycle;
     1272            \definecolor{facecolor}{rgb}{0.000,0.000,1.000}
     1273            \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
     1274            (0, 0, 0) -- (1, 0, 0) -- (1, 1, 0) -- (0, 1, 0) -- cycle;
     1275            \end{tikzpicture}
     1276
     1277        ::
     1278
     1279            sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1280            sage: E = E1Star(sigma)
     1281            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     1282            sage: P = E(P, 4)
     1283            sage: from sage.misc.latex import latex             #not tested
     1284            sage: latex.add_to_preamble('\\usepackage{tikz}')   #not tested
     1285            sage: view(P, tightpage=true)                       #not tested
     1286
     1287        Plot using shades of gray (useful for article figures)::
     1288
     1289            sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1290            sage: E = E1Star(sigma)
     1291            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     1292            sage: P.repaint([(0.9, 0.9, 0.9), (0.65,0.65,0.65), (0.4,0.4,0.4)])
     1293            sage: P = E(P, 4)
     1294            sage: s = P.plot_tikz()
     1295
     1296        Plotting with various options::
     1297
     1298            sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1299            sage: E = E1Star(sigma)
     1300            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     1301            sage: M = matrix(2, 3, map(float, [1,0,-0.7071,0,1,-0.7071]))
     1302            sage: P = E(P, 3)
     1303            sage: s = P.plot_tikz(projmat=M, edgecolor='facecolor', scale=0.6, drawzero=True)
     1304
     1305        Adding X, Y, Z axes using the extra code feature::
     1306
     1307            sage: length = 1.5
     1308            sage: space = 0.3
     1309            sage: axes = ''
     1310            sage: axes += "\\draw[->, thick, black] (0,0,0) -- (%s, 0, 0);\n" % length
     1311            sage: axes += "\\draw[->, thick, black] (0,0,0) -- (0, %s, 0);\n" % length
     1312            sage: axes += "\\node at (%s,0,0) {$x$};\n" % (length + space)
     1313            sage: axes += "\\node at (0,%s,0) {$y$};\n" % (length + space)
     1314            sage: axes += "\\node at (0,0,%s) {$z$};\n" % (length + space)
     1315            sage: axes += "\\draw[->, thick, black] (0,0,0) -- (0, 0, %s);\n" % length
     1316            sage: cube = Patch([Face((0,0,0),1), Face((0,0,0),2), Face((0,0,0),3)])
     1317            sage: options = dict(scale=0.5,drawzero=True,extra_code_before=axes)
     1318            sage: s = cube.plot_tikz(**options)
     1319            sage: len(s)
     1320            986
     1321            sage: print s   #not tested
     1322            \begin{tikzpicture}
     1323            [x={(-0.433013cm,-0.250000cm)}, y={(0.433013cm,-0.250000cm)}, z={(0.000000cm,0.500000cm)}]
     1324            \draw[->, thick, black] (0,0,0) -- (1.50000000000000, 0, 0);
     1325            \draw[->, thick, black] (0,0,0) -- (0, 1.50000000000000, 0);
     1326            \node at (1.80000000000000,0,0) {$x$};
     1327            \node at (0,1.80000000000000,0) {$y$};
     1328            \node at (0,0,1.80000000000000) {$z$};
     1329            \draw[->, thick, black] (0,0,0) -- (0, 0, 1.50000000000000);
     1330            \definecolor{facecolor}{rgb}{0.000,1.000,0.000}
     1331            \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
     1332            (0, 0, 0) -- (0, 0, 1) -- (1, 0, 1) -- (1, 0, 0) -- cycle;
     1333            \definecolor{facecolor}{rgb}{1.000,0.000,0.000}
     1334            \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
     1335            (0, 0, 0) -- (0, 1, 0) -- (0, 1, 1) -- (0, 0, 1) -- cycle;
     1336            \definecolor{facecolor}{rgb}{0.000,0.000,1.000}
     1337            \fill[fill=facecolor, draw=black, shift={(0,0,0)}]
     1338            (0, 0, 0) -- (1, 0, 0) -- (1, 1, 0) -- (0, 1, 0) -- cycle;
     1339            \node[circle,fill=black,draw=black,minimum size=1.5mm,inner sep=0pt] at (0,0,0) {};
     1340            \end{tikzpicture}
     1341        """
     1342        if self.dimension() != 3:
     1343            raise NotImplementedError, "Tikz Plotting is implemented only for patches in three dimensions."
     1344
     1345        if projmat == None:
     1346            projmat = matrix(2, [-1.7320508075688772*0.5, 1.7320508075688772*0.5, 0, -0.5, -0.5, 1])*scale
     1347
     1348        e1 = projmat*vector([1,0,0])
     1349        e2 = projmat*vector([0,1,0])
     1350        e3 = projmat*vector([0,0,1])
     1351        face_contour = self._face_contour
     1352        color = ()
     1353
     1354        # string s contains the TiKZ code of the patch
     1355        s = ''
     1356
     1357        if print_tikz_env:
     1358            s += '\\begin{tikzpicture}\n'
     1359            s += '[x={(%fcm,%fcm)}, y={(%fcm,%fcm)}, z={(%fcm,%fcm)}]\n'%(e1[0], e1[1], e2[0], e2[1], e3[0], e3[1])
     1360
     1361        s += extra_code_before
     1362
     1363        for f in self:
     1364            t = f.type()
     1365            x, y, z = f.vector()
     1366
     1367            if tuple(color) != tuple(f.color()): #tuple is needed, comparison for RGB fails
     1368                color = f.color()
     1369                s += '\\definecolor{facecolor}{rgb}{%.3f,%.3f,%.3f}\n'%(color[0], color[1], color[2])
     1370
     1371            s += '\\fill[fill=facecolor, draw=%s, shift={(%d,%d,%d)}]\n'%(edgecolor, x, y, z)
     1372            s += ' -- '.join(map(str, face_contour[t])) + ' -- cycle;\n'
     1373
     1374        s += extra_code_after
     1375
     1376        if drawzero:
     1377            s += '\\node[circle,fill=black,draw=black,minimum size=1.5mm,inner sep=0pt] at (0,0,0) {};\n'
     1378
     1379        if print_tikz_env:
     1380            s += '\\end{tikzpicture}'
     1381
     1382        return LatexExpr(s)
     1383
     1384    _latex_ = plot_tikz
     1385
     1386class E1Star(SageObject):
     1387    r"""
     1388    A class to model the `E_1^*(\sigma)` map associated with
     1389    a unimodular substitution `\sigma`.
     1390
     1391    INPUT:
     1392
     1393    - ``sigma`` - unimodular ``WordMorphism``, i.e. such that its incidence
     1394      matrix has determinant `\pm 1`.
     1395
     1396    - ``method`` - 'prefix' or 'suffix' (optional, default: 'suffix')
     1397      Enables to use an alternative definition `E_1^*(\sigma)` substitutions,
     1398      where the abelianized of the prefix` is used instead of the suffix.
     1399
     1400    .. NOTE::
     1401
     1402        The alphabet of the domain and the codomain of `\sigma` must be
     1403        equal, and they must be of the form ``[1, ..., d]``, where ``d``
     1404        is a positive integer corresponding to the length of the vectors
     1405        of the faces on which `E_1^*(\sigma)` will act.
     1406
     1407    EXAMPLES::
     1408
     1409        sage: from sage.combinat.e_one_star import E1Star, Face, Patch
     1410        sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     1411        sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1412        sage: E = E1Star(sigma)
     1413        sage: E(P)
     1414        Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*, [(0, 1, -1), 2]*, [(1, 0, -1), 1]*]
     1415
     1416    ::
     1417
     1418        sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     1419        sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1420        sage: E = E1Star(sigma, method='prefix')
     1421        sage: E(P)
     1422        Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*, [(0, 0, 1), 1]*, [(0, 0, 1), 2]*]
     1423
     1424    ::
     1425
     1426        sage: x = [Face((0,0,0,0),1), Face((0,0,0,0),4)]
     1427        sage: P = Patch(x)
     1428        sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1,4], 4:[1]})
     1429        sage: E = E1Star(sigma)
     1430        sage: E(P)
     1431        Patch: [[(0, 0, 0, 0), 3]*, [(0, 0, 0, 0), 4]*, [(0, 0, 1, -1), 3]*, [(0, 1, 0, -1), 2]*, [(1, 0, 0, -1), 1]*]
     1432    """
     1433    def __init__(self, sigma, method='suffix'):
     1434        r"""
     1435        E1Star constructor. See class doc for more information.
     1436
     1437        EXAMPLES::
     1438
     1439            sage: from sage.combinat.e_one_star import E1Star, Face, Patch
     1440            sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1441            sage: E = E1Star(sigma)
     1442            sage: E
     1443            E_1^*(WordMorphism: 1->12, 2->13, 3->1)
     1444        """
     1445        if not isinstance(sigma, WordMorphism):
     1446            raise TypeError, "sigma (=%s) must be an instance of WordMorphism"%sigma
     1447
     1448        if sigma.domain().alphabet() != sigma.codomain().alphabet():
     1449            raise ValueError, "The domain and codomain of (%s) must be the same."%sigma
     1450
     1451        if abs(det(matrix(sigma))) != 1:
     1452            raise ValueError, "The substitution (%s) must be unimodular."%sigma
     1453
     1454        first_letter = sigma.codomain().alphabet()[0]
     1455        if not (first_letter in ZZ) or (first_letter < 1):
     1456            raise ValueError, "The substitution (%s) must be defined on positive integers."%sigma
     1457
     1458        self._sigma = WordMorphism(sigma)
     1459        self._d = self._sigma.domain().size_of_alphabet()
     1460
     1461        # self._base_iter is a base for the iteration of the application of self on set
     1462        # of faces. (Exploits the linearity of `E_1^*(\sigma)` to optimize computation.)
     1463        alphabet = self._sigma.domain().alphabet()
     1464        X = {}
     1465        for k in alphabet:
     1466            subst_im = self._sigma.image(k)
     1467            for n, letter in enumerate(subst_im):
     1468                if method == 'suffix':
     1469                    image_word = subst_im[n+1:]
     1470                elif method == 'prefix':
     1471                    image_word = subst_im[:n]
     1472                else:
     1473                    raise ValueError, "Option 'method' can only be 'prefix' or 'suffix'."
     1474                if not letter in X:
     1475                    X[letter] = []
     1476                v = self.inverse_matrix()*vector(image_word.parikh_vector())
     1477                X[letter].append((v, k))
     1478        self._base_iter = X
     1479
     1480    def __eq__(self, other):
     1481        r"""
     1482        Equality test for E1Star morphisms.
     1483
     1484        INPUT:
     1485
     1486        - ``other`` - an object
     1487
     1488        EXAMPLES::
     1489
     1490            sage: from sage.combinat.e_one_star import E1Star, Face, Patch
     1491            sage: s = WordMorphism({1:[1,3], 2:[1,2,3], 3:[3]})
     1492            sage: t = WordMorphism({1:[1,2,3], 2:[2,3], 3:[3]})
     1493            sage: S = E1Star(s)
     1494            sage: T = E1Star(t)
     1495            sage: S == T
     1496            False
     1497            sage: S2 = E1Star(s, method='prefix')
     1498            sage: S == S2
     1499            False
     1500        """
     1501        return (isinstance(other, E1Star) and self._base_iter == other._base_iter)
     1502
     1503    def __call__(self, patch, iterations=1):
     1504        r"""
     1505        Applies a generalized substitution to a Patch; this returns a new object.
     1506
     1507        The color of every new face in the image is given the same color as its preimage.
     1508
     1509        INPUT:
     1510
     1511        - ``patch`` - a patch
     1512        - ``iterations`` - integer (optional, default: 1) number of iterations
     1513
     1514        OUTPUT:
     1515
     1516            a patch
     1517
     1518        EXAMPLES::
     1519
     1520            sage: from sage.combinat.e_one_star import E1Star, Face, Patch
     1521            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     1522            sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1523            sage: E = E1Star(sigma)
     1524            sage: E(P)
     1525            Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*, [(0, 1, -1), 2]*, [(1, 0, -1), 1]*]
     1526            sage: E(P, iterations=4)
     1527            Patch of 31 faces
     1528
     1529        TEST:
     1530
     1531        We test that iterations=0 works (see #10699)::
     1532
     1533            sage: P = Patch([Face((0,0,0),t) for t in [1,2,3]])
     1534            sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1535            sage: E = E1Star(sigma)
     1536            sage: E(P, iterations=0)
     1537            Patch: [[(0, 0, 0), 1]*, [(0, 0, 0), 2]*, [(0, 0, 0), 3]*]
     1538        """
     1539        if iterations == 0:
     1540            return Patch(patch)
     1541        elif iterations < 0:
     1542            raise ValueError, "iterations (=%s) must be >= 0." % iterations
     1543        else:
     1544            old_faces = patch
     1545            for i in xrange(iterations):
     1546                new_faces = []
     1547                for f in old_faces:
     1548                    new_faces.extend(self._call_on_face(f, color=f.color()))
     1549                old_faces = new_faces
     1550            return Patch(new_faces)
     1551
     1552    def __mul__(self, other):
     1553        r"""
     1554        Return the product of self and other.
     1555
     1556        The product satisfies the following rule :
     1557        `E_1^*(\sigma\circ\sigma') = E_1^*(\sigma')` \circ  E_1^*(\sigma)`
     1558
     1559        INPUT:
     1560
     1561        - ``other`` - an instance of E1Star
     1562
     1563        OUTPUT:
     1564
     1565            an instance of E1Star
     1566
     1567        EXAMPLES::
     1568
     1569            sage: from sage.combinat.e_one_star import E1Star, Face, Patch
     1570            sage: s = WordMorphism({1:[2],2:[3],3:[1,2]})
     1571            sage: t = WordMorphism({1:[1,3,1],2:[1],3:[1,1,3,2]})
     1572            sage: E1Star(s) * E1Star(t)
     1573            E_1^*(WordMorphism: 1->1, 2->1132, 3->1311)
     1574            sage: E1Star(t * s)
     1575            E_1^*(WordMorphism: 1->1, 2->1132, 3->1311)
     1576        """
     1577        if not isinstance(other, E1Star):
     1578            raise TypeError, "other (=%s) must be an instance of E1Star" % other
     1579        return E1Star(other.sigma() * self.sigma())
     1580
     1581    def __repr__(self):
     1582        r"""
     1583        String representation of a patch.
     1584
     1585        EXAMPLES::
     1586
     1587            sage: from sage.combinat.e_one_star import E1Star, Face, Patch
     1588            sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1589            sage: E = E1Star(sigma)
     1590            sage: E
     1591            E_1^*(WordMorphism: 1->12, 2->13, 3->1)
     1592        """
     1593        return "E_1^*(%s)" % str(self._sigma)
     1594
     1595    def _call_on_face(self, face, color=None):
     1596        r"""
     1597        Returns an iterator of faces obtained by applying self on the face.
     1598
     1599        INPUT:
     1600
     1601        - ``face`` - a face
     1602        - ``color`` - string, RGB tuple or color, (optional, default: None)
     1603          RGB color
     1604
     1605        OUTPUT:
     1606
     1607            iterator of faces
     1608
     1609        EXAMPLES::
     1610
     1611            sage: from sage.combinat.e_one_star import E1Star, Face, Patch
     1612            sage: f = Face((0,2,0), 1)
     1613            sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1614            sage: E = E1Star(sigma)
     1615            sage: list(E._call_on_face(f))
     1616            [[(3, 0, -3), 1]*, [(2, 1, -3), 2]*, [(2, 0, -2), 3]*]
     1617        """
     1618        if len(face.vector()) != self._d:
     1619            raise ValueError, "The dimension of the faces must be equal to the size of the alphabet of the substitution."
     1620        x_new = self.inverse_matrix() * face.vector()
     1621        t = face.type()
     1622        return (Face(x_new + v, k, color=color) for v, k in self._base_iter[t])
     1623
     1624    @cached_method
     1625    def matrix(self):
     1626        r"""
     1627        Returns the matrix associated with self.
     1628
     1629        EXAMPLES::
     1630
     1631            sage: from sage.combinat.e_one_star import E1Star, Face, Patch
     1632            sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1633            sage: E = E1Star(sigma)
     1634            sage: E.matrix()
     1635            [1 1 1]
     1636            [1 0 0]
     1637            [0 1 0]
     1638        """
     1639        return self._sigma.incidence_matrix()
     1640
     1641    @cached_method
     1642    def inverse_matrix(self):
     1643        r"""
     1644        Returns the inverse of the matrix associated with self.
     1645
     1646        EXAMPLES::
     1647
     1648            sage: from sage.combinat.e_one_star import E1Star, Face, Patch
     1649            sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1650            sage: E = E1Star(sigma)
     1651            sage: E.inverse_matrix()
     1652            [ 0  1  0]
     1653            [ 0  0  1]
     1654            [ 1 -1 -1]
     1655
     1656        """
     1657        return self.matrix().inverse()
     1658
     1659    def sigma(self):
     1660        r"""
     1661        Returns the ``WordMorphism`` associated with self.
     1662
     1663        EXAMPLES::
     1664
     1665            sage: from sage.combinat.e_one_star import E1Star, Face, Patch
     1666            sage: sigma = WordMorphism({1:[1,2], 2:[1,3], 3:[1]})
     1667            sage: E = E1Star(sigma)
     1668            sage: print E.sigma()
     1669            WordMorphism: 1->12, 2->13, 3->1
     1670        """
     1671        return self._sigma
     1672