Ticket #11379: trac_11379_color_issue-sl.patch

File trac_11379_color_issue-sl.patch, 14.4 KB (added by slabbe, 10 years ago)

Applies over the correction patch.

  • sage/combinat/tiling.py

    # HG changeset patch
    # User Sebastien Labbe <slabqc at gmail.com>
    # Date 1308186891 25200
    # Node ID 075159ed1d9c962d568c9c66377a05a56a4d5379
    # Parent  cf455f591acc4183bdb6079db398db3f2301b9b6
    #11379: fixing a color issue when pieces are reusable
    
    diff --git a/sage/combinat/tiling.py b/sage/combinat/tiling.py
    a b Donald Knuth [1] considered the problem  
    159159    sage: T.number_of_solutions()                      #not tested
    160160    212
    161161
     162Animation of Donald Knuth's dancing links
     163-----------------------------------------
     164
     165::
     166
     167    sage: from sage.combinat.tiling import Polyomino, TilingSolver
     168    sage: Y = Polyomino([(0,0),(1,0),(2,0),(3,0),(2,1)], color='yellow')
     169    sage: T = TilingSolver([Y], box=(15,15), reusable=True, reflection=True)
     170    sage: a = T.animate(stop=40)            # long time
     171    sage: a                                 # long time
     172    Animation with 40 frames
     173    sage: a.show()                          # not tested
     174
     1755d Easy Example
     176---------------
     177
     178Here is a 5d example. Let's try to fill the `2 \times 2 \times 2 \times 2
     179\times 2` rectangle with reusable `1 \times 1 \times 1 \times 1 \times 1`
     180rectangles. Obviously, there is one solution::
     181
     182    sage: from sage.combinat.tiling import Polyomino, TilingSolver
     183    sage: p = Polyomino([(0,0,0,0,0)])
     184    sage: T = TilingSolver([p], box=(2,2,2,2,2), reusable=True)
     185    sage: rows = T.rows()                               # long time (3s)
     186    sage: rows                                          # long time (fast)
     187    [[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30], [31]]
     188    sage: T.number_of_solutions()                       # long time (fast)
     189    1
     190
    162191REFERENCES:
    163192
    164193- [1] Knuth, Donald (2000). "Dancing links". `arXiv:cs/0011047
    from sage.plot.plot import Graphics 
    182211from sage.plot.polygon import polygon
    183212from sage.modules.free_module_element import vector
    184213from sage.plot.plot3d.platonic import cube
     214from sage.plot.animate import Animation
    185215from sage.misc.mrange import xmrange
    186216
    187217############################
    class TilingSolver(SageObject): 
    900930        if not self._rotation and self._reflection:
    901931            raise NotImplementedError, "When reflection is allowed and rotation is not allowed"
    902932        self._reusable = reusable
     933        self._starting_rows = None    # the starting row of each piece
    903934
    904935    def __repr__(self):
    905936        r"""
    class TilingSolver(SageObject): 
    11151146        """
    11161147        coord_to_int = self.coord_to_int_dict()
    11171148        rows = []
     1149        self._starting_rows = []
    11181150        for i,p in enumerate(self._pieces):
     1151            self._starting_rows.append(len(rows))
    11191152            if self._rotation and self._reflection:
    11201153                it = p.translated_orthogonals(self._box, orientation_preserving=False)
    11211154            elif self._rotation and not self._reflection:
    class TilingSolver(SageObject): 
    11301163            else:
    11311164                for q in it:
    11321165                    rows.append([i] + [coord_to_int[coord] for coord in q])
     1166        self._starting_rows.append(len(rows))
    11331167        if verbose:
    11341168            print "Number of rows : %s" % len(rows)
    11351169            print "Number of distinct rows : %s" % len(set(tuple(sorted(row)) for row in rows))
    11361170        return rows
    11371171
     1172    def nrows_per_piece(self):
     1173        r"""
     1174        Return the number of rows necessary by each piece.
     1175
     1176        OUPUT:
     1177
     1178            list
     1179
     1180        EXAMPLES::
     1181
     1182            sage: from sage.games.quantumino import QuantuminoSolver
     1183            sage: q = QuantuminoSolver(0)
     1184            sage: T = q.tiling_solver()
     1185            sage: T.nrows_per_piece()                           # long time (10s)
     1186            [360, 360, 360, 360, 360, 180, 180, 672, 672, 360, 360, 180, 180, 360, 360, 180]
     1187        """
     1188        if self._starting_rows is None:
     1189            rows = self.rows()
     1190        L = self._starting_rows
     1191        return [L[i+1] - L[i] for i in xrange(len(L)-1)]
     1192
    11381193    def dlx_solver(self):
    11391194        r"""
    11401195        Return the sage DLX solver of that 3D tiling problem.
    class TilingSolver(SageObject): 
    11841239        while x.search() == 1:
    11851240            yield x.get_solution()
    11861241
    1187     def dlx_partial_solutions(self):
     1242    def dlx_common_part_solutions(self):
    11881243        r"""
    11891244        Return an iterator over the row indices of solutions and of partial
    11901245        solutions, i.e. the common part of two consecutive solutions.
    class TilingSolver(SageObject): 
    12051260            sage: T = TilingSolver([p,q,r], box=(1,1,6))
    12061261            sage: list(T.dlx_solutions())
    12071262            [[0, 7, 14], [0, 12, 10], [6, 13, 5], [6, 14, 2], [11, 9, 5], [11, 10, 3]]
    1208             sage: list(T.dlx_partial_solutions())
     1263            sage: list(T.dlx_common_part_solutions())
    12091264            [[0, 7, 14], [0], [0, 12, 10], [], [6, 13, 5], [6], [6, 14, 2], [], [11, 9, 5], [11], [11, 10, 3]]
    12101265        """
    12111266        it = self.dlx_solutions()
    class TilingSolver(SageObject): 
    12191274                    common.append(a)
    12201275            yield common
    12211276
    1222     def solve(self, include_partial=False):
     1277    def dlx_incremental_solutions(self):
     1278        r"""
     1279        Return an iterator over the row indices of the incremental
     1280        solutions.
     1281       
     1282        Between two incremental solution, either one piece is added or one
     1283        piece is removed.
     1284       
     1285        The purpose is to illustrate the backtracking and construct an
     1286        animation of the evolution of solutions.
     1287
     1288        OUPUT:
     1289
     1290            iterator
     1291
     1292        EXAMPLES::
     1293
     1294            sage: from sage.combinat.tiling import TilingSolver, Polyomino
     1295            sage: p = Polyomino([(0,0,0)])
     1296            sage: q = Polyomino([(0,0,0), (0,0,1)])
     1297            sage: r = Polyomino([(0,0,0), (0,0,1), (0,0,2)])
     1298            sage: T = TilingSolver([p,q,r], box=(1,1,6))
     1299            sage: list(T.dlx_solutions())
     1300            [[0, 7, 14], [0, 12, 10], [6, 13, 5], [6, 14, 2], [11, 9, 5], [11, 10, 3]]
     1301            sage: list(T.dlx_incremental_solutions())
     1302            [[0, 7, 14], [0, 7], [0], [0, 12], [0, 12, 10], [0, 12], [0], [], [6], [6, 13], [6, 13, 5], [6, 13], [6], [6, 14], [6, 14, 2], [6, 14], [6], [], [11], [11, 9], [11, 9, 5], [11, 9], [11], [11, 10], [11, 10, 3]]
     1303        """
     1304        it = self.dlx_solutions()
     1305        B = it.next()
     1306        while True:
     1307            yield B
     1308            A, B = B, it.next()
     1309            common = []
     1310            for i in reversed(xrange(len(A))):
     1311                if A[i] == B[i]:
     1312                    break
     1313                else:
     1314                    yield A[:i]
     1315            else:
     1316                i -= 1
     1317            for j in xrange(i+2, len(A)):
     1318                yield B[:j]
     1319
     1320    def solve(self, partial=None):
    12231321        r"""
    12241322        Returns an iterator of list of 3D polyominoes that are an exact
    12251323        cover of the box.
    12261324
    12271325        INPUT:
    12281326
    1229         - ``include_partial`` - boolean (optional, default: ``False``),
    1230           whether to include partial (incomplete) solutions, i.e. the
    1231           common part between two consecutive solutions.
     1327        - ``partial`` - string (optional, default: ``None``), whether to
     1328          include partial (incomplete) solutions. It can be one of the
     1329          following:
     1330         
     1331          - ``None`` - include only complete solution
     1332          - ``'common'`` - common part between two consecutive solutions
     1333          - ``'incremental'`` - one piece change at a time
    12321334       
    12331335        OUTPUT:
    12341336
    class TilingSolver(SageObject): 
    12571359
    12581360        Including the partial solutions::
    12591361
    1260             sage: it = T.solve(include_partial=True)
     1362            sage: it = T.solve(partial='common')
    12611363            sage: for p in it.next(): p
    12621364            Polyomino: [(0, 0, 0)], Color: gray
    12631365            Polyomino: [(0, 0, 1), (0, 0, 2)], Color: gray
    class TilingSolver(SageObject): 
    12741376            Polyomino: [(0, 0, 2), (0, 0, 3), (0, 0, 4)], Color: gray
    12751377            Polyomino: [(0, 0, 5)], Color: gray
    12761378
     1379        Colors are preserved when the polyomino can be reused::
     1380
     1381            sage: p = Polyomino([(0,0,0)], color='yellow')
     1382            sage: q = Polyomino([(0,0,0), (0,0,1)], color='yellow')
     1383            sage: r = Polyomino([(0,0,0), (0,0,1), (0,0,2)], color='yellow')
     1384            sage: T = TilingSolver([p,q,r], box=(1,1,6), reusable=True)
     1385            sage: it = T.solve()
     1386            sage: for p in it.next(): p
     1387            Polyomino: [(0, 0, 0)], Color: yellow
     1388            Polyomino: [(0, 0, 1)], Color: yellow
     1389            Polyomino: [(0, 0, 2)], Color: yellow
     1390            Polyomino: [(0, 0, 3)], Color: yellow
     1391            Polyomino: [(0, 0, 4)], Color: yellow
     1392            Polyomino: [(0, 0, 5)], Color: yellow
     1393
    12771394        TESTS::
    12781395
    12791396            sage: T = TilingSolver([p,q,r], box=(1,1,7))
    class TilingSolver(SageObject): 
    12871404            raise StopIteration
    12881405        int_to_coord = self.int_to_coord_dict()
    12891406        rows = self.rows()
    1290         if include_partial:
    1291             it = self.dlx_partial_solutions()
     1407        if partial is None:
     1408            it = self.dlx_solutions()
     1409        elif partial == 'common':
     1410            it = self.dlx_common_part_solutions()
     1411        elif partial == 'incremental':
     1412            it = self.dlx_incremental_solutions()
    12921413        else:
    1293             it = self.dlx_solutions()
     1414            raise ValueError("Unknown value for partial (=%s)" % partial)
    12941415        for solution in it:
    12951416            pentos = []
    12961417            for row_number in solution:
    12971418                row = rows[row_number]
    12981419                if self._reusable:
     1420                    no = -1
     1421                    while self._starting_rows[no] < row_number:
     1422                        no += 1
    12991423                    coords = [int_to_coord[i] for i in row]
    1300                     p = Polyomino(coords)
     1424                    p = Polyomino(coords, color=self._pieces[no].color())
    13011425                else:
    13021426                    no = row[0]
    13031427                    coords = [int_to_coord[i] for i in row[1:]]
    class TilingSolver(SageObject): 
    13371461            N += 1
    13381462        return N
    13391463
     1464    def animate(self, partial='incremental', stop=None):
     1465        r"""
     1466        Return an animation of evolving solutions.
     1467
     1468        INPUT:
     1469
     1470        - ``partial`` - string (optional, default: ``None``), whether to
     1471          include partial (incomplete) solutions. It can be one of the
     1472          following:
     1473         
     1474          - ``None`` - include only complete solution
     1475          - ``'common'`` - common part between two consecutive solutions
     1476          - ``'incremental'`` - one piece change at a time
     1477
     1478        - ``stop`` - integer (optional, default:``None``), number of frames
     1479       
     1480        EXAMPLES::
     1481
     1482            sage: from sage.combinat.tiling import Polyomino, TilingSolver
     1483            sage: y = Polyomino([(0,0),(1,0),(2,0),(3,0),(2,1)], color='yellow')
     1484            sage: T = TilingSolver([y], box=(5,10), reusable=True, reflection=True)
     1485            sage: a = T.animate()                   # long time (2s)
     1486            sage: a                                 # long time (2s)
     1487            Animation with 42 frames
     1488            sage: a.show()                          # not tested
     1489
     1490        ::
     1491
     1492            sage: a = T.animate('common')                   # not tested
     1493            sage: a                                         # not tested
     1494            Animation with 19 frames
     1495
     1496        Without partial solutions::
     1497
     1498            sage: a = T.animate(None)                       # not tested
     1499            sage: a                                         # not tested
     1500            Animation with 10 frames
     1501
     1502        Limit the number of frames::
     1503
     1504            sage: a = T.animate('incremental', 13)          # not tested
     1505            sage: a                                         # not tested
     1506            Animation with 13 frames
     1507        """
     1508        dimension = len(self._box)
     1509        if dimension == 2:
     1510            it = self.solve(partial=partial)
     1511            it = itertools.islice(it, stop)
     1512            L = [sum([piece.show2d() for piece in solution], Graphics()) for solution in it]
     1513            xmax, ymax = self._box
     1514            a = Animation(L, xmin=0, ymin=0, xmax=xmax, ymax=ymax, aspect_ratio=1)
     1515            return a
     1516        elif dimension == 3:
     1517            raise NotImplementedError("Animation must be implemented in Jmol first")
     1518        else:
     1519            raise NotImplementedError("Dimension must be 2 or 3 in order to make an animation")
     1520
  • sage/games/quantumino.py

    diff --git a/sage/games/quantumino.py b/sage/games/quantumino.py
    a b class QuantuminoSolver(SageObject): 
    448448        pieces = pentaminos[:self._aside] + pentaminos[self._aside+1:]
    449449        return TilingSolver(pieces, box=self._box)
    450450
    451     def solve(self, include_partial=False):
     451    def solve(self, partial=None):
    452452        r"""
    453453        Return an iterator over the solutions where one of the pentamino is
    454454        put aside.
    455455
    456456        INPUT:
    457457
    458         - ``include_partial`` - boolean (optional, default: ``False``),
    459           whether to include partial (incomplete) solutions, i.e. the
    460           common part between two consecutive solutions.
     458        - ``partial`` - string (optional, default: ``None``), whether to
     459          include partial (incomplete) solutions. It can be one of the
     460          following:
     461         
     462          - ``None`` - include only complete solution
     463          - ``'common'`` - common part between two consecutive solutions
     464          - ``'incremental'`` - one piece change at a time
    461465
    462466        OUTPUT:
    463467
    class QuantuminoSolver(SageObject): 
    507511        With the partial solutions included, one can see the evolution
    508512        between consecutive solutions (an animation would be better)::
    509513
    510             sage: it = QuantuminoSolver(0).solve(include_partial=True)
     514            sage: it = QuantuminoSolver(0).solve(partial='common')
    511515            sage: it.next().show3d()               # not tested (2s)
    512516            sage: it.next().show3d()               # not tested (< 1s)
    513517            sage: it.next().show3d()               # not tested (< 1s)
    class QuantuminoSolver(SageObject): 
    540544        """
    541545        T = self.tiling_solver()
    542546        aside = pentaminos[self._aside]
    543         for pentos in T.solve(include_partial=include_partial):
     547        for pentos in T.solve(partial=partial):
    544548            yield QuantuminoState(pentos, aside)
    545549
    546550    def number_of_solutions(self):