Commits

Volker Braun committed c894aa3

fan isomorphism fix

Comments (0)

Files changed (16)

14291_reviewer.patch

-# HG changeset patch
-# User Dmitrii Pasechnik <dimpase@gmail.com>
-# Date 1363712673 -28800
-# Node ID c88f77f5b975d7eb044a979c1feaaf8091821131
-# Parent  7bf0ce3fbbc7422dd5c98b3abc4067186469aac8
-reviewer patch, adding moar actions
-
-diff --git a/sage/groups/perm_gps/permgroup.py b/sage/groups/perm_gps/permgroup.py
---- a/sage/groups/perm_gps/permgroup.py
-+++ b/sage/groups/perm_gps/permgroup.py
-@@ -96,6 +96,8 @@
- 
- - Javier Lopez Pena (2013): Added conjugacy classes.
- 
-+- Nathann Cohen, Dmitrii Pasechnik (2013): Added non-default actions.
-+
- REFERENCES:
- 
- - Cameron, P., Permutation Groups. New York: Cambridge University
-@@ -1039,7 +1041,7 @@
-     def orbits(self):
-         """
-         Returns the orbits of the elements of the domain under the
--        group action.
-+        default group action.
-         
-         EXAMPLES::
-         
-@@ -1066,21 +1068,26 @@
-         return [[self._domain_from_gap[x] for x in orbit] for orbit in
-                 self._gap_().Orbits(self._domain_gap()).sage()]
- 
-+    supported_actions = ["OnPoints", "OnTuples", "OnSets", "OnPairs", "OnSetsSets", 
-+                "OnSetsDisjointSets", "OnSetsTuples", "OnTuplesSets", "OnTuplesTuples"]
-+
-     @cached_method
-     def orbit(self, point, action = "OnPoints"):
-         """
--        Return the orbit of a point (or set, or tuple) under the group action.
-+        Return the orbit of a point under the group action in the list
-+        `self.supported_actions`. 
-+        These are taken from `http://www.gap-system.org/Manuals/doc/ref/chap41.html`_. 
- 
-         INPUT:
- 
--        - ``point`` -- can be a point or a tuple of points, depending on the
--          action to be considered.
--
--        - ``action`` (string) -- when ``point`` is a tuple of points, this
--          variable defines whether the group is to be considered as acting on
--          tuples (``action="ontuples"``) or acting on sets
--          (``action="onsets"``). It is set to ``"onpoints"`` by default. See
--          below for examples.
-+        - ``point`` -- can be a point or any of the list above, depending on the
-+          action to be considered. Note that sets should be "canonical", i.e. their
-+          members must be sorted w.r.t. to the default order on them.
-+
-+        - ``action`` (string) -- if ``point`` is a tuple (of tuples) of points, this
-+          variable describes how the group is acting. The list of possibilites is 
-+          is given by  `self.supported_actions`.
-+          It is set to ``"OnPoints"`` by default. See below for examples.
- 
-         EXAMPLES::
- 
-@@ -1104,6 +1111,13 @@
- 
-             sage: S3.orbit((1,2), action = "OnTuples")
-             [[1, 2], [2, 3], [2, 1], [3, 1], [1, 3], [3, 2]]
-+        
-+        Action of `S_4` on sets of disjoint sets::
-+
-+            sage: S4 = groups.permutation.Symmetric(4)
-+            sage: S4.orbit(((1,2),(3,4)), action = "OnSetsDisjointSets")
-+            [[[1, 2], [3, 4]], [[1, 4], [2, 3]], [[1, 3], [2, 4]]]
-+
-         """
-         if action == "OnPoints":
-             try:
-@@ -1115,12 +1129,55 @@
-                                  "argument explicitly.")
-             return [self._domain_from_gap[x] for x in self._gap_().Orbit(point).sage()]
- 
--        elif action in ["OnTuples", "OnSets"]:
--            points = [self._domain_to_gap[x] for x in point]
--            orbits = self._gap_().Orbit(points, action).sage()
--            return [[self._domain_from_gap[x] for x in o] for o in orbits]
-+        elif action in self.supported_actions:
-+            if action in ['OnTuples', 'OnSets', 'OnPairs']:
-+                points = [self._domain_to_gap[x] for x in point]
-+                orbits = self._gap_().Orbit(points, action).sage()
-+                return [[self._domain_from_gap[x] for x in o] for o in orbits]
-+            else:
-+                points = [[self._domain_to_gap[x] for x in p] for p in point]
-+                orbits = self._gap_().Orbit(points, action).sage()
-+                return [[[self._domain_from_gap[x] for x in p] for p in o] 
-+                        for o in orbits]
-+
-         else:
--            raise ValueError("'action' can only take values among 'OnPoints', 'OnTuples' or 'OnSets'.")
-+            raise ValueError("'action' can only take values among "+
-+                             self.supported_actions)
-+
-+    def action(self, domain, action = "OnPoints"):
-+        """
-+        Return the permutation group induced by self acting on domain.
-+        
-+        INPUT:
-+
-+        - ``domain`` -- the list of things for which GAP knows how to compute
-+          the action of the permutation group. For instance it can be obtained by
-+          calling :meth:`orbit`. 
-+
-+        - ``action`` (string) -- the action on domain. Need not be limited to 
-+          `self.supported_actions`.
-+          It is set to ``"OnPoints"`` by default. See below for examples.
-+
-+        EXAMPLES::
-+
-+            Action of `S_5` on 2-subsets::
-+
-+            sage: S5 = groups.permutation.Symmetric(5)
-+            sage: o10 = S5.orbit((1,2), action = "OnSets")
-+            sage: S5_10 = S5.action(o10, action = "OnSets"); S5_10
-+            Permutation Group with generators [(2,4)(6,9)(7,10), (1,2,3,5,7)(4,6,8,9,10)]
-+            
-+            Non-faithful action of `S_4` on sets of disjoint sets::
-+
-+            sage: S4 = groups.permutation.Symmetric(4)
-+            sage: o3 = S4.orbit(((1,2),(3,4)), action = "OnSetsDisjointSets")
-+            sage: S3 = S4.action(o3,  "OnSetsDisjointSets"); S3
-+            Permutation Group with generators [(2,3), (1,2)]
-+            sage: S3.order()
-+            6
-+
-+        """
-+        return PermutationGroup(gap_group = self._gap_().Action(domain, action))
- 
-     def transversals(self, point):
-         """

14370_ipython_nocolors_v2.patch

+# HG changeset patch
+# User Jeroen Demeyer <jdemeyer@cage.ugent.be>
+# Date 1364425365 25200
+# Node ID c6325005a42361e89c58d17a9515eec68e092def
+# Parent  e9d7892a23ebeb4ec48fb3270bd0913229ea328f
+Disable IPython colors in doctests; unset TERM when doctesting the doctester
+
+diff --git a/sage/doctest/forker.py b/sage/doctest/forker.py
+--- a/sage/doctest/forker.py
++++ b/sage/doctest/forker.py
+@@ -78,6 +78,10 @@
+     import sage.misc.displayhook
+     sys.displayhook = sage.misc.displayhook.DisplayHook(sys.displayhook)
+ 
++    # Disable IPython colors during doctests
++    from sage.misc.interpreter import DEFAULT_SAGE_CONFIG
++    DEFAULT_SAGE_CONFIG['TerminalInteractiveShell']['colors'] = 'NoColor'
++
+     # We import readline before forking, otherwise Pdb doesn't work
+     # os OS X: http://trac.sagemath.org/sage_trac/ticket/14289
+     import readline
+diff --git a/sage/doctest/test.py b/sage/doctest/test.py
+--- a/sage/doctest/test.py
++++ b/sage/doctest/test.py
+@@ -11,10 +11,19 @@
+     sage: import time
+     sage: from sage.env import SAGE_SRC
+     sage: tests_dir = os.path.join(SAGE_SRC, 'sage', 'doctest', 'tests')
++    sage: tests_env = dict(os.environ)
++
++Unset :envvar:`TERM` when running doctests, see :trac:`14370`::
++
++    sage: try:
++    ....:     del tests_env['TERM']
++    ....: except KeyError:
++    ....:     pass
++    sage: kwds = {'cwd': tests_dir, 'env':tests_env}
+ 
+ Check that :trac:`2235` has been fixed::
+ 
+-    sage: subprocess.call(["sage", "-t", "longtime.rst"], cwd=tests_dir)  # long time
++    sage: subprocess.call(["sage", "-t", "longtime.rst"], **kwds)  # long time
+     Running doctests...
+     Doctesting 1 file.
+     sage -t longtime.rst
+@@ -24,7 +33,7 @@
+     ----------------------------------------------------------------------
+     ...
+     0
+-    sage: subprocess.call(["sage", "-t", "-l", "longtime.rst"], cwd=tests_dir)  # long time
++    sage: subprocess.call(["sage", "-t", "-l", "longtime.rst"], **kwds)  # long time
+     Running doctests...
+     Doctesting 1 file.
+     sage -t --long longtime.rst
+@@ -37,7 +46,7 @@
+ 
+ Test the ``--initial`` option::
+ 
+-    sage: subprocess.call(["sage", "-t", "-i", "initial.rst"], cwd=tests_dir)  # long time
++    sage: subprocess.call(["sage", "-t", "-i", "initial.rst"], **kwds)  # long time
+     Running doctests...
+     Doctesting 1 file.
+     sage -t initial.rst
+@@ -67,9 +76,10 @@
+ 
+ Test a timeout using the ``SAGE_TIMEOUT`` environment variable::
+ 
+-    sage: env = dict(os.environ)
+-    sage: env['SAGE_TIMEOUT'] = "3"
+-    sage: subprocess.call(["sage", "-t", "99seconds.rst"], cwd=tests_dir, env=env)  # long time
++    sage: from copy import deepcopy
++    sage: kwds2 = deepcopy(kwds)
++    sage: kwds2['env']['SAGE_TIMEOUT'] = "3"
++    sage: subprocess.call(["sage", "-t", "99seconds.rst"], **kwds2)  # long time
+     Running doctests...
+     Doctesting 1 file.
+     sage -t 99seconds.rst
+@@ -85,7 +95,7 @@
+ 
+ Test handling of ``KeyboardInterrupt``s in doctests::
+ 
+-    sage: subprocess.call(["sage", "-t", "keyboardinterrupt.rst"], cwd=tests_dir)  # long time
++    sage: subprocess.call(["sage", "-t", "keyboardinterrupt.rst"], **kwds)  # long time
+     Running doctests...
+     Doctesting 1 file.
+     sage -t keyboardinterrupt.rst
+@@ -107,7 +117,7 @@
+ 
+ Interrupt the doctester::
+ 
+-    sage: subprocess.call(["sage", "-t", "interrupt.rst"], cwd=tests_dir)  # long time
++    sage: subprocess.call(["sage", "-t", "interrupt.rst"], **kwds)  # long time
+     Running doctests...
+     Doctesting 1 file.
+     sage -t interrupt.rst
+@@ -123,10 +133,11 @@
+ doesn't hurt::
+ 
+     sage: F = tmp_filename()
+-    sage: env = dict(os.environ)
+-    sage: env['DOCTEST_TEST_PID_FILE'] = F  # Doctester will write its PID in this file
++    sage: from copy import deepcopy
++    sage: kwds2 = deepcopy(kwds)
++    sage: kwds2['env']['DOCTEST_TEST_PID_FILE'] = F  # Doctester will write its PID in this file
+     sage: subprocess.call(["sage", "-tp", "1000000", "--timeout=120",  # long time
+-    ....:     "99seconds.rst", "interrupt_diehard.rst"], cwd=tests_dir, env=env)
++    ....:     "99seconds.rst", "interrupt_diehard.rst"], **kwds2)
+     Running doctests...
+     Doctesting 2 files using 1000000 threads.
+     Killing test 99seconds.rst
+@@ -152,7 +163,7 @@
+ 
+ Test a doctest failing with ``abort()``::
+ 
+-    sage: subprocess.call(["sage", "-t", "abort.rst"], cwd=tests_dir)  # long time
++    sage: subprocess.call(["sage", "-t", "abort.rst"], **kwds)  # long time
+     Running doctests...
+     Doctesting 1 file.
+     sage -t abort.rst
+@@ -176,7 +187,7 @@
+ 
+ A different kind of crash::
+ 
+-    sage: subprocess.call(["sage", "-t", "fail_and_die.rst"], cwd=tests_dir)  # long time
++    sage: subprocess.call(["sage", "-t", "fail_and_die.rst"], **kwds)  # long time
+     Running doctests...
+     Doctesting 1 file.
+     sage -t fail_and_die.rst
+@@ -200,7 +211,7 @@
+ 
+ Test running under gdb, without and with a timeout::
+ 
+-    sage: subprocess.call(["sage", "-t", "--gdb", "1second.rst"], cwd=tests_dir, stdin=open(os.devnull))  # long time, optional: gdb
++    sage: subprocess.call(["sage", "-t", "--gdb", "1second.rst"], stdin=open(os.devnull), **kwds)  # long time, optional: gdb
+     exec gdb ...
+     Running doctests...
+     Doctesting 1 file.
+@@ -211,7 +222,7 @@
+     ----------------------------------------------------------------------
+     ...
+     0
+-    sage: subprocess.call(["sage", "-t", "--gdb", "-T" "5", "99seconds.rst"], cwd=tests_dir, stdin=open(os.devnull))  # long time, optional: gdb
++    sage: subprocess.call(["sage", "-t", "--gdb", "-T" "5", "99seconds.rst"], stdin=open(os.devnull), **kwds)  # long time, optional: gdb
+     exec gdb ...
+     Running doctests...
+     Doctesting 1 file.
+@@ -220,7 +231,7 @@
+ 
+ Test the ``--show-skipped`` option::
+ 
+-    sage: subprocess.call(["sage", "-t", "--show-skipped", "show_skipped.rst"], cwd=tests_dir)  # long time
++    sage: subprocess.call(["sage", "-t", "--show-skipped", "show_skipped.rst"], **kwds)  # long time
+     Running doctests ...
+     Doctesting 1 file.
+     sage -t show_skipped.rst
+@@ -238,7 +249,7 @@
+ 
+ Optional tests are run correctly::
+ 
+-    sage: subprocess.call(["sage", "-t", "--long", "--show-skipped", "--optional=sage,gap", "show_skipped.rst"], cwd=tests_dir)  # long time
++    sage: subprocess.call(["sage", "-t", "--long", "--show-skipped", "--optional=sage,gap", "show_skipped.rst"], **kwds)  # long time
+     Running doctests ...
+     Doctesting 1 file.
+     sage -t --long show_skipped.rst
+diff --git a/sage/misc/interpreter.py b/sage/misc/interpreter.py
+--- a/sage/misc/interpreter.py
++++ b/sage/misc/interpreter.py
+@@ -559,6 +559,10 @@
+     :class:`InterfaceShellTransformer` to transform the input into the
+     appropriate ``interface.eval(...)`` input.
+ 
++    INPUT:
++
++    - ``interface`` -- A Sage ``PExpect`` interface instance.
++
+     EXAMPLES::
+ 
+         sage: from sage.misc.interpreter import interface_shell_embed

14370_run_doctests_fix.patch

+# HG changeset patch
+# Parent 010330a94f0321abb9f7952342d71b1e13d605c5
+
+Also unset color in the ipython config during run_doctest (for spawned
+subshells)
+
+diff --git a/sage/doctest/control.py b/sage/doctest/control.py
+--- a/sage/doctest/control.py
++++ b/sage/doctest/control.py
+@@ -900,11 +900,15 @@
+     if not save_dtmode:
+         IP = get_ipython()
+         old_color = IP.colors
+-        IP.run_line_magic('colors','NoColor')
++        IP.run_line_magic('colors', 'NoColor')
++        old_config_color = IP.config.TerminalInteractiveShell.colors
++        IP.config.TerminalInteractiveShell.colors = 'NoColor'
+ 
+     try:
+         DC.run()
+     finally:
+         sage.plot.plot.DOCTEST_MODE = save_dtmode
+         if not save_dtmode:
+-            IP.run_line_magic('colors',old_color)
++            IP.run_line_magic('colors', old_color)
++            IP.config.TerminalInteractiveShell.colors = old_config_color
++
+trac_13194_polytope_fan_construct.patch
+trac_14394_face_fan_bug.patch
+trac_14394_reviewer.patch
 trac_14375_ansi_escapes_indication.patch
 trac_14187_lazy_import_test.patch
 trac_14014_libgap_cyclotomic_matrix.patch
 trac_14014_parents_for_matrix_groups.patch
 trac_14014_parents_group_dependents.patch
 trac_14014_iterator.patch
-trac_13194_polytope_fan_construct.patch
 trac_12892_orbit_closure_morphism.patch
 trac_14353_fan_cone_intersection.patch
 trac_14353_factor_fan_morphism.patch
 trac_12900_Demazure_roots.patch
 trac_xxxx_fiber_divisor_graph.patch
 trac_14357_lazy_everywhere.patch
-trac_14291.patch
-14291_reviewer.patch
-trac_14291-rev2.patch
+trac_14291-v2.patch
 trac_14319.patch
+trac_14319-from_list_to_domain.patch
 trac_14319_fix_fan_isomorphism.patch
+trac_14319_temp_workaround.patch
 trac_12553_ppl_count_points.patch
 trac_12553_ppl_lattice_polytope.patch
 trac_12553_palp_database.patch
 trac_3416_jacobians.patch
 trac_3416_fixes.patch
 trac_13826_star_imports_race.patch
+14370_ipython_nocolors_v2.patch
+14370_run_doctests_fix.patch
+trac_x_fan_sage_input.patch
 trac_14201_ppl_doctest_fixes.patch
 trac_14015_affine_group.patch
 trac_x_matrix_groups.patch

trac_12553_ppl_lattice_polytope.patch

 # HG changeset patch
-# Parent 5f313ba8af428f45db2b59cbb9ef04caf40fa1f6
+# Parent ce1cfc8597499af7ee2372acd8001cb408114f8f
 # HG changeset patch
 # Parent 1e07db38ea8e6c690f661456ccc9db71e07fae78
 
 new file mode 100644
 --- /dev/null
 +++ b/sage/geometry/polyhedron/ppl_lattice_polytope.py
-@@ -0,0 +1,941 @@
+@@ -0,0 +1,963 @@
 +"""
 +Fast Lattice Polytopes using PPL.
 +
 +
 +        INPUT:
 +
-+        - ``polytopes`` a tuple/list/iterable of subsets of the integral points of ``self``.
++        - ``polytopes`` a tuple/list/iterable of subsets of the
++          integral points of ``self``.
 +
 +        OUTPUT:
 +
-+        Representatives of the point sets modulo the :meth:`lattice_automorphism_group` of ``self``.
++        Representatives of the point sets modulo the
++        :meth:`lattice_automorphism_group` of ``self``.
 +
 +        EXAMPLES::
 +
 +        for ps in pointsets:
 +            points.update(ps)
 +        points = tuple(points)
-+        Aut = self.lattice_automorphism_group(points)
++        Aut = self.lattice_automorphism_group(points, 
++                                              point_labels=tuple(range(len(points))))
 +        indexsets = set([ frozenset([points.index(p) for p in ps]) for ps in pointsets ])
 +        orbits = []
 +        while len(indexsets)>0:
 +            idx = indexsets.pop()
 +            orbits.append(frozenset([points[i] for i in idx]))
 +            for g in Aut:
-+                g_idx = frozenset([g(i+1)-1 for i in idx])
++                g_idx = frozenset([g(i) for i in idx])
 +                indexsets.difference_update([g_idx])
 +        return tuple(orbits)
 +
 +        return True
 +
 +    @cached_method
-+    def restricted_automorphism_group(self):
++    def restricted_automorphism_group(self, vertex_labels=None):
 +        r"""
 +        Return the restricted automorphism group.
 +
 +        permutations of vertices. If the polytope is full-dimensional,
 +        it is equal to the full (unrestricted) automorphism group.
 +
++        INPUT:
++
++        - ``vertex_labels`` -- a tuple or ``None`` (default). The
++          labels of the vertices that will be used in the output
++          permutation group. By default, the vertices are used
++          themselves.
++
 +        OUTPUT:
 +
 +        A
-+        :class:`PermutationGroup<sage.groups.perm_gps.permgroup.PermutationGroup_generic>`.
-+
-+        Note that in Sage, permutation groups always act on positive
-+        integers while ``self.minimized_generators()`` is indexed by
-+        nonnegative integers. The indexing of the permutation group is
-+        chosen to be shifted by ``+1``.
++        :class:`PermutationGroup<sage.groups.perm_gps.permgroup.PermutationGroup_generic>`
++        acting on the vertices (or the ``vertex_labels``, if
++        specified).
 +
 +        REFERENCES:
 +
 +        EXAMPLES::
 +
 +            sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL
++            sage: Z3square = LatticePolytope_PPL((0,0), (1,2), (2,1), (3,3))
++            sage: Z3square.restricted_automorphism_group(vertex_labels=(1,2,3,4))
++            Permutation Group with generators [(2,3), (1,2)(3,4), (1,4)]
++            sage: G = Z3square.restricted_automorphism_group(); G
++            Permutation Group with generators [((1,2),(2,1)),
++            ((0,0),(1,2))((2,1),(3,3)), ((0,0),(3,3))]
++            sage: tuple(G.domain()) == Z3square.vertices()
++            True
++            sage: G.orbit(Z3square.vertices()[0])
++            [(0, 0), (1, 2), (3, 3), (2, 1)]
++
 +            sage: cell24 = LatticePolytope_PPL(
 +            ...   (1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1),(1,-1,-1,1),(0,0,-1,1),
 +            ...   (0,-1,0,1),(-1,0,0,1),(1,0,0,-1),(0,1,0,-1),(0,0,1,-1),(-1,1,1,-1),
 +            ...   (1,-1,-1,0),(0,0,-1,0),(0,-1,0,0),(-1,0,0,0),(1,-1,0,0),(1,0,-1,0),
 +            ...   (0,1,1,-1),(-1,1,1,0),(-1,1,0,0),(-1,0,1,0),(0,-1,-1,1),(0,0,0,-1))
-+
-+
-+            sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL
-+            sage: Z3square = LatticePolytope_PPL((0,0), (1,2), (2,1), (3,3))
-+            sage: Z3square.restricted_automorphism_group()
-+            Permutation Group with generators [(2,3), (1,2)(3,4), (1,4)]
++            sage: cell24.restricted_automorphism_group().cardinality()
++            1152
 +        """
 +        if not self.is_full_dimensional():
-+            return self.affine_lattice_polytope().restricted_automorphism_group()
-+
++            return self.affine_lattice_polytope().\
++                restricted_automorphism_group(vertex_labels=vertex_labels)
++        if vertex_labels is None:
++            vertex_labels = self.vertices()
 +        from sage.groups.perm_gps.permgroup import PermutationGroup
 +        from sage.graphs.graph import Graph
 +        # good coordinates for the vertices
 +            for j in range(i+1,len(v_list)):
 +                v_i = v_list[i]
 +                v_j = v_list[j]
-+                G.add_edge(i,j, v_i * Qinv * v_j)
-+        group, node_dict = G.automorphism_group(edge_labels=True, translation=True)
-+
-+        # Relabel the permutation group
-+        perm_to_vertex = dict( (i,v+1) for v,i in node_dict.items() )
-+        group = PermutationGroup([ [ tuple([ perm_to_vertex[i] for i in cycle ])
-+                                     for cycle in generator.cycle_tuples() ]
-+                                   for generator in group.gens() ])
-+        return group
++                G.add_edge(vertex_labels[i], vertex_labels[j], v_i * Qinv * v_j)
++        return G.automorphism_group(edge_labels=True)
 +
 +    @cached_method
-+    def lattice_automorphism_group(self, points=None):
++    def lattice_automorphism_group(self, points=None, point_labels=None):
 +        """
 +        The integral subgroup of the restricted automorphism group.
 +
 +        INPUT:
 +
-+        - ``points`` -- A list of coordinate vectors or ``None``
++        - ``points`` -- A tuple of coordinate vectors or ``None``
 +          (default). If specified, the points must form complete
-+          orbits under the lattice automorphism group.
++          orbits under the lattice automorphism group. If ``None`` all
++          vertices are used.
++
++        - ``point_labels`` -- A tuple of labels for the ``points`` or
++          ``None`` (default). These will be used as labels for the do
++          permutation group. If ``None`` the ``points`` will be used
++          themselves.
 +
 +        OUTPUT:
 +
-+        The integral subgroup of the restricted automorphism group.
-+
-+        If ``points`` are specified, the permutation group acting on
-+        them is returned.
++        The integral subgroup of the restricted automorphism group
++        acting on the given ``points``, or all vertices if not
++        specified.
 +
 +        EXAMPLES::
 +
 +            sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL
 +            sage: Z3square = LatticePolytope_PPL((0,0), (1,2), (2,1), (3,3))
-+            sage: Z3square.restricted_automorphism_group()
++            sage: Z3square.lattice_automorphism_group()
++            Permutation Group with generators [(), ((1,2),(2,1)),
++            ((0,0),(3,3)), ((0,0),(3,3))((1,2),(2,1))]
++
++            sage: G1 = Z3square.lattice_automorphism_group(point_labels=(1,2,3,4));  G1
++            Permutation Group with generators [(), (2,3), (1,4), (1,4)(2,3)]
++            sage: G1.cardinality()
++            4
++
++            sage: G2 = Z3square.restricted_automorphism_group(vertex_labels=(1,2,3,4)); G2
 +            Permutation Group with generators [(2,3), (1,2)(3,4), (1,4)]
-+            sage: len(_)
++            sage: G2.cardinality()
 +            8
 +
-+            sage: Z3square.lattice_automorphism_group()
-+            Permutation Group with generators [(), (2,3), (1,4), (1,4)(2,3)]
-+            sage: len(_)
-+            4
-+
 +            sage: points = Z3square.integral_points();  points
 +            ((0, 0), (1, 1), (1, 2), (2, 1), (2, 2), (3, 3))
-+            sage: Z3square.lattice_automorphism_group(points)
++            sage: Z3square.lattice_automorphism_group(points, point_labels=(1,2,3,4,5,6))
 +            Permutation Group with generators [(), (3,4), (1,6)(2,5), (1,6)(2,5)(3,4)]
 +        """
 +        if not self.is_full_dimensional():
 +            return self.affine_lattice_polytope().lattice_automorphism_group()
 +
-+        if points is not None:
-+            points = [ vector(ZZ, [1]+v.list()) for v in points ]
-+
++        if points is None:
++            points = self.vertices()
++        if point_labels is None:
++            point_labels = tuple(points)
++        points = [ vector(ZZ, [1]+v.list()) for v in points ]
++        map(lambda x:x.set_immutable(), points)
++        
 +        vertices = [ vector(ZZ, [1]+v.list()) for v in self.vertices() ]
 +        pivots = matrix(ZZ, vertices).pivot_rows()
 +        basis = matrix(ZZ, [ vertices[i] for i in pivots ])
 +        from sage.groups.perm_gps.permgroup import PermutationGroup
 +        from sage.groups.perm_gps.permgroup_element import PermutationGroupElement
 +        lattice_gens = []
-+        for g in self.restricted_automorphism_group():
-+            image = matrix(ZZ, [ vertices[g(i+1)-1] for i in pivots ])
++        G = self.restricted_automorphism_group(
++            vertex_labels=tuple(range(len(vertices))))
++        for g in G:
++            image = matrix(ZZ, [ vertices[g(i)] for i in pivots ])
 +            m = basis_inverse*image
 +            if m not in Mat_ZZ:
 +                continue
-+            if points is None:
-+                lattice_gens.append(g)
-+            else:
-+                perm_list = [ points.index(points[i]*m)+1 for i in range(0,len(points))]
-+                lattice_gens.append(PermutationGroupElement(perm_list))
-+        return PermutationGroup(lattice_gens)
++            perm_list = [ point_labels[points.index(p*m)] 
++                          for p in points ]
++            lattice_gens.append(perm_list)
++        return PermutationGroup(lattice_gens, domain=point_labels)
 +
 +
 +
 diff --git a/sage/libs/ppl.pyx b/sage/libs/ppl.pyx
 --- a/sage/libs/ppl.pyx
 +++ b/sage/libs/ppl.pyx
-@@ -147,6 +147,7 @@
+@@ -148,6 +148,7 @@
  #                  http://www.gnu.org/licenses/
  #*****************************************************************************
  
 +from sage.structure.sage_object cimport SageObject
  from sage.libs.gmp.mpz cimport mpz_t, mpz_set
  from sage.rings.integer cimport Integer
- 
-@@ -162,7 +163,6 @@
+ from sage.rings.rational import Rational
+@@ -164,7 +165,6 @@
  #  - solve linear program
  # These can only be triggered by methods in the Polyhedron class
  # they need to be wrapped in sig_on() / sig_off()
  ####################################################
  cdef extern from "gmpxx.h":
      cdef cppclass mpz_class:
-@@ -429,7 +429,7 @@
+@@ -466,7 +466,7 @@
  
  
  ### Forward declarations ###########################
  cdef class Variable(object)
  cdef class Linear_Expression(object)
  cdef class Generator(object)
-@@ -450,7 +450,7 @@
+@@ -486,7 +486,7 @@
  ####################################################
  ### _mutable_or_immutable ##########################
  ####################################################
      r"""
      A base class for mutable or immutable objects.
  
-@@ -620,7 +620,7 @@
+@@ -1190,7 +1190,7 @@
          raise NotImplementedError, 'The Polyhedron class is abstract, you must not instantiate it.'
  
  
          """
          Return a string representation.
  
-@@ -633,14 +633,14 @@
+@@ -1203,14 +1203,14 @@
              sage: from sage.libs.ppl import Variable, C_Polyhedron
              sage: x = Variable(0)
              sage: y = Variable(1)
              'The space-filling polyhedron in QQ^3'
          """
          dim = self.affine_dimension()
-@@ -4579,6 +4579,23 @@
+@@ -5150,6 +5150,23 @@
          """
          return self.thisptr.OK()
  
  
      def __iter__(self):
          """
-@@ -5555,6 +5572,22 @@
+@@ -6126,6 +6143,22 @@
          """
          return self.thisptr.OK()
  

trac_13084_ppl_lattice_polygon.patch

 # HG changeset patch
-# Parent dac1ba6098042b9adabfd4f1f952689131ddfdda
+# Parent 5a5aa7236629bc42c5a159e36c7553c6e0c5ae9b
 
 Special functionality for PPL-based lattice polygons
 
      @cached_method
      def is_full_dimensional(self):
          """
-@@ -936,6 +1012,157 @@
-                 lattice_gens.append(PermutationGroupElement(perm_list))
-         return PermutationGroup(lattice_gens)
+@@ -958,6 +1034,157 @@
+             lattice_gens.append(perm_list)
+         return PermutationGroup(lattice_gens, domain=point_labels)
  
 +    def sub_polytope_generator(self):
 +        """
 diff --git a/sage/libs/ppl.pyx b/sage/libs/ppl.pyx
 --- a/sage/libs/ppl.pyx
 +++ b/sage/libs/ppl.pyx
-@@ -4613,6 +4613,47 @@
+@@ -5184,6 +5184,47 @@
          return Generator_System_iterator(self)
  
  
      def __repr__(self):
          r"""
          Return a string representation of the generator system.
-@@ -5607,6 +5648,46 @@
+@@ -6178,6 +6219,46 @@
          return Constraint_System_iterator(self)
  
  

trac_14291-rev2.patch

-# HG changeset patch
-# User Nathann Cohen <nathann.cohen@gmail.com>
-# Date 1363731554 -3600
-# Node ID c3b2b152c65064ab245e4ad7d9d108b66161e427
-# Parent  2e980ea8d962d06b92cb2170a5965cd65d6fefcf
-Orbits of tuples and sets -- documentation
-
-diff --git a/sage/groups/perm_gps/permgroup.py b/sage/groups/perm_gps/permgroup.py
---- a/sage/groups/perm_gps/permgroup.py
-+++ b/sage/groups/perm_gps/permgroup.py
-@@ -1068,15 +1068,17 @@
-         return [[self._domain_from_gap[x] for x in orbit] for orbit in
-                 self._gap_().Orbits(self._domain_gap()).sage()]
- 
--    supported_actions = ["OnPoints", "OnTuples", "OnSets", "OnPairs", "OnSetsSets", 
-+    supported_actions = ["OnPoints", "OnTuples", "OnSets", "OnPairs", "OnSetsSets",
-                 "OnSetsDisjointSets", "OnSetsTuples", "OnTuplesSets", "OnTuplesTuples"]
- 
-     @cached_method
-     def orbit(self, point, action = "OnPoints"):
-         """
--        Return the orbit of a point under the group action in the list
--        `self.supported_actions`. 
--        These are taken from `http://www.gap-system.org/Manuals/doc/ref/chap41.html`_. 
-+        Return the orbit of a point under a group action.
-+
-+        All actions available through this method can be obtained from
-+        `self.supported_actions`. They are taken from GAP's list
-+        `http://www.gap-system.org/Manuals/doc/ref/chap41.html`_.
- 
-         INPUT:
- 
-@@ -1085,7 +1087,7 @@
-           members must be sorted w.r.t. to the default order on them.
- 
-         - ``action`` (string) -- if ``point`` is a tuple (of tuples) of points, this
--          variable describes how the group is acting. The list of possibilites is 
-+          variable describes how the group is acting. The list of possibilites is
-           is given by  `self.supported_actions`.
-           It is set to ``"OnPoints"`` by default. See below for examples.
- 
-@@ -1111,7 +1113,7 @@
- 
-             sage: S3.orbit((1,2), action = "OnTuples")
-             [[1, 2], [2, 3], [2, 1], [3, 1], [1, 3], [3, 2]]
--        
-+
-         Action of `S_4` on sets of disjoint sets::
- 
-             sage: S4 = groups.permutation.Symmetric(4)
-@@ -1137,7 +1139,7 @@
-             else:
-                 points = [[self._domain_to_gap[x] for x in p] for p in point]
-                 orbits = self._gap_().Orbit(points, action).sage()
--                return [[[self._domain_from_gap[x] for x in p] for p in o] 
-+                return [[[self._domain_from_gap[x] for x in p] for p in o]
-                         for o in orbits]
- 
-         else:
-@@ -1147,27 +1149,31 @@
-     def action(self, domain, action = "OnPoints"):
-         """
-         Return the permutation group induced by self acting on domain.
--        
-+
-+        All actions available through this method can be obtained from
-+        `self.supported_actions`. They are taken from GAP's list
-+        `http://www.gap-system.org/Manuals/doc/ref/chap41.html`_.
-+
-         INPUT:
- 
-         - ``domain`` -- the list of things for which GAP knows how to compute
-           the action of the permutation group. For instance it can be obtained by
--          calling :meth:`orbit`. 
--
--        - ``action`` (string) -- the action on domain. Need not be limited to 
-+          calling :meth:`orbit`.
-+
-+        - ``action`` (string) -- the action on domain. Need not be limited to
-           `self.supported_actions`.
-           It is set to ``"OnPoints"`` by default. See below for examples.
- 
--        EXAMPLES::
--
--            Action of `S_5` on 2-subsets::
-+        EXAMPLES:
-+
-+        Action of `S_5` on 2-subsets::
- 
-             sage: S5 = groups.permutation.Symmetric(5)
-             sage: o10 = S5.orbit((1,2), action = "OnSets")
-             sage: S5_10 = S5.action(o10, action = "OnSets"); S5_10
-             Permutation Group with generators [(2,4)(6,9)(7,10), (1,2,3,5,7)(4,6,8,9,10)]
--            
--            Non-faithful action of `S_4` on sets of disjoint sets::
-+
-+        Non-faithful action of `S_4` on sets of disjoint sets::
- 
-             sage: S4 = groups.permutation.Symmetric(4)
-             sage: o3 = S4.orbit(((1,2),(3,4)), action = "OnSetsDisjointSets")

trac_14291-v2.patch

+# HG changeset patch
+# User Nathann Cohen <nathann.cohen@gmail.com>
+# Date 1363519490 -3600
+# Node ID d06a5ef48d94261e86589a2ee91363e9ae62112d
+# Parent  5ede04e6bce52102dca9323a193a09257b1dc027
+Orbits of more than just points in PermutationGroup.orbit
+
+diff --git a/sage/groups/perm_gps/permgroup.py b/sage/groups/perm_gps/permgroup.py
+--- a/sage/groups/perm_gps/permgroup.py
++++ b/sage/groups/perm_gps/permgroup.py
+@@ -1039,11 +1039,11 @@
+     def orbits(self):
+         """
+         Returns the orbits of the elements of the domain under the
+-        group action.
+-        
++        default group action.
++
+         EXAMPLES::
+-        
+-            sage: G = PermutationGroup([ [(3,4)], [(1,3)] ]) 
++
++            sage: G = PermutationGroup([ [(3,4)], [(1,3)] ])
+             sage: G.orbits()
+             [[1, 3, 4], [2]]
+             sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]])
+@@ -1053,12 +1053,12 @@
+             sage: G = PermutationGroup([ [('c','d')], [('a','c')],[('b',)]])
+             sage: G.orbits()
+             [['a', 'c', 'd'], ['b']]
+-        
++
+         The answer is cached::
+-        
++
+             sage: G.orbits() is G.orbits()
+-            True           
+-        
++            True
++
+         AUTHORS:
+ 
+         - Nathan Dunfield
+@@ -1067,9 +1067,25 @@
+                 self._gap_().Orbits(self._domain_gap()).sage()]
+ 
+     @cached_method
+-    def orbit(self, point):
++    def orbit(self, point, action = "OnPoints"):
+         """
+-        Return the orbit of the given point under the group action.
++        Return the orbit of a point under a group action.
++
++        INPUT:
++
++        - ``point`` -- can be a point or any of the list above, depending on the
++          action to be considered.
++
++        - ``action`` (string) -- if ``point`` is an element from the domain, a
++          tuple of elements of the domain, a tuple of tuples [...], this
++          variable describes how the group is acting.
++
++          The actions currently available through this method are "OnPoints",
++          "OnTuples", "OnSets", "OnPairs", "OnSetsSets", "OnSetsDisjointSets",
++          "OnSetsTuples", "OnTuplesSets", "OnTuplesTuples". They are taken from
++          GAP's list `http://www.gap-system.org/Manuals/doc/ref/chap41.html`_.
++
++          It is set to ``"OnPoints"`` by default. See below for examples.
+ 
+         EXAMPLES::
+ 
+@@ -1077,37 +1093,114 @@
+             sage: G.orbit(3)
+             [3, 4, 1]
+             sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]])
+-            sage: G.orbit(3)                                                 
++            sage: G.orbit(3)
+             [3, 4, 10, 1, 2]
+-
+             sage: G = PermutationGroup([ [('c','d')], [('a','c')] ])
+             sage: G.orbit('a')
+             ['a', 'c', 'd']
+-        """ 
+-        point = self._domain_to_gap[point]
+-        return [self._domain_from_gap[x] for x in self._gap_().Orbit(point).sage()]
+-    
++
++        Action of `S_3` on sets::
++
++            sage: S3 = groups.permutation.Symmetric(3)
++            sage: S3.orbit((1,2), action = "OnSets")
++            [[1, 2], [2, 3], [1, 3]]
++
++        On tuples::
++
++            sage: S3.orbit((1,2), action = "OnTuples")
++            [[1, 2], [2, 3], [2, 1], [3, 1], [1, 3], [3, 2]]
++
++        Action of `S_4` on sets of disjoint sets::
++
++            sage: S4 = groups.permutation.Symmetric(4)
++            sage: S4.orbit(((1,2),(3,4)), action = "OnSetsDisjointSets")
++            [[[1, 2], [3, 4]],
++             [[1, 4], [2, 3]],
++             [[1, 3], [2, 4]]]
++
++        Action of `S_4` (on a nonstandard domain) on tuples of sets::
++
++            sage: S4 = PermutationGroup([ [('c','d')], [('a','c')], [('a','b')] ])
++            sage: S4.orbit((('a','c'),('b','d')),"OnTuplesSets")
++            [[['a', 'c'], ['b', 'd']], [['a', 'd'], ['b', 'c']],
++             [['b', 'c'], ['a', 'd']], [['b', 'd'], ['a', 'c']],
++             [['c', 'd'], ['a', 'b']], [['a', 'b'], ['c', 'd']]]
++
++        Action of `S_4` (on a very nonstandard domain) on tuples of sets::
++
++            sage: S4 = PermutationGroup([ [((11,(12,13)),'d')], [((12,(12,11)),(11,(12,13)))], [((12,(12,11)),'b')] ])
++            sage: S4.orbit((( (11,(12,13)), (12,(12,11))),('b','d')),"OnTuplesSets")
++            [[[(11, (12, 13)), (12, (12, 11))], ['b', 'd']],
++             [['d', (12, (12, 11))], ['b', (11, (12, 13))]],
++             [['b', (11, (12, 13))], ['d', (12, (12, 11))]],
++             [['d', (11, (12, 13))], ['b', (12, (12, 11))]],
++             [['b', 'd'], [(11, (12, 13)), (12, (12, 11))]],
++             [['b', (12, (12, 11))], ['d', (11, (12, 13))]]]
++
++        """
++        def input_to_gap(x, depth, sort):
++            if depth:
++                ans = [input_to_gap(xx,depth-1,sort) for xx in x]
++                if depth == 1 and sort:
++                    ans.sort()
++                return ans
++            else:
++                return self._domain_to_gap[x]
++
++        def gap_to_output(x, depth):
++            if depth:
++                return [gap_to_output(xx,depth-1) for xx in x]
++            else:
++                return self._domain_from_gap[x]
++
++        sort = False
++
++        actions = {
++            "OnPoints"           : {"depth" : 0, "sort" : False},
++            "OnSets"             : {"depth" : 1, "sort" : True},
++            "OnTuples"           : {"depth" : 1, "sort" : False},
++            "OnTuples"           : {"depth" : 1, "sort" : False},
++            "OnSetsSets"         : {"depth" : 2, "sort" : True},
++            "OnSetsDisjointSets" : {"depth" : 2, "sort" : True},
++            "OnTuplesSets"       : {"depth" : 2, "sort" : True},
++            "OnTuplesTuples"     : {"depth" : 2, "sort" : False},
++            "OnTuplesTuples"     : {"depth" : 2, "sort" : False}
++            }
++        try:
++            params = actions[action]
++        except KeyError:
++            raise ValueError("This action is not implemented (yet?).")
++
++        try:
++            point = input_to_gap(point, **params)
++        except KeyError:
++            raise ValueError("One element does not seem to be part of the domain.")
++
++        ans = self._gap_().Orbit(point, action).sage()
++
++        return gap_to_output(ans, params['depth']+1)
++
+     def transversals(self, point):
+         """
+-        If G is a permutation group acting on the set `X = \{1, 2, ...., n\}` 
+-        and H is the stabilizer subgroup of <integer>, a right 
+-        (respectively left) transversal is a set containing exactly 
+-        one element from each right (respectively left) coset of H. This 
+-        method returns a right transversal of ``self`` by the stabilizer 
++        If G is a permutation group acting on the set `X = \{1, 2, ...., n\}`
++        and H is the stabilizer subgroup of <integer>, a right
++        (respectively left) transversal is a set containing exactly
++        one element from each right (respectively left) coset of H. This
++        method returns a right transversal of ``self`` by the stabilizer
+         of ``self`` on <integer> position.
+ 
+         EXAMPLES::
+ 
+-            sage: G = PermutationGroup([ [(3,4)], [(1,3)] ])           
++            sage: G = PermutationGroup([ [(3,4)], [(1,3)] ])
+             sage: G.transversals(1)
+             [(), (1,3,4), (1,4,3)]
+             sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]])
+-            sage: G.transversals(1)                                    
++            sage: G.transversals(1)
+             [(), (1,2)(3,4), (1,3,2,10,4), (1,4,2,10,3), (1,10,4,3,2)]
+ 
+             sage: G = PermutationGroup([ [('c','d')], [('a','c')] ])
+             sage: G.transversals('a')
+-            [(), ('a','c','d'), ('a','d','c')]            
++            [(), ('a','c','d'), ('a','d','c')]
+         """
+         G = self._gap_()
+         return [self(G.RepresentativeAction(self._domain_to_gap[point], self._domain_to_gap[i]))
+@@ -1128,7 +1221,7 @@
+             sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]])
+             sage: G.stabilizer(10)
+             Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4,10)]) generated by [(2,3,4), (1,2)(3,4)]
+-            sage: G.stabilizer(1) 
++            sage: G.stabilizer(1)
+             Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4,10)]) generated by [(2,3)(4,10), (2,10,4)]
+             sage: G = PermutationGroup([[(2,3,4)],[(6,7)]])
+             sage: G.stabilizer(1)

trac_14291.patch

-# HG changeset patch
-# User Nathann Cohen <nathann.cohen@gmail.com>
-# Date 1363519490 -3600
-# Node ID 884c704285a3d36daabcf5a4bfb64b3270defe46
-# Parent  a706b13de29b1153214c78d11f94b2c30090c88d
-Orbits of tuples and sets
-
-diff --git a/sage/groups/perm_gps/permgroup.py b/sage/groups/perm_gps/permgroup.py
---- a/sage/groups/perm_gps/permgroup.py
-+++ b/sage/groups/perm_gps/permgroup.py
-@@ -1067,9 +1067,20 @@
-                 self._gap_().Orbits(self._domain_gap()).sage()]
- 
-     @cached_method
--    def orbit(self, point):
-+    def orbit(self, point, action = "OnPoints"):
-         """
--        Return the orbit of the given point under the group action.
-+        Return the orbit of a point (or set, or tuple) under the group action.
-+
-+        INPUT:
-+
-+        - ``point`` -- can be a point or a tuple of points, depending on the
-+          action to be considered.
-+
-+        - ``action`` (string) -- when ``point`` is a tuple of points, this
-+          variable defines whether the group is to be considered as acting on
-+          tuples (``action="ontuples"``) or acting on sets
-+          (``action="onsets"``). It is set to ``"onpoints"`` by default. See
-+          below for examples.
- 
-         EXAMPLES::
- 
-@@ -1077,37 +1088,61 @@
-             sage: G.orbit(3)
-             [3, 4, 1]
-             sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]])
--            sage: G.orbit(3)                                                 
-+            sage: G.orbit(3)
-             [3, 4, 10, 1, 2]
--
-             sage: G = PermutationGroup([ [('c','d')], [('a','c')] ])
-             sage: G.orbit('a')
-             ['a', 'c', 'd']
--        """ 
--        point = self._domain_to_gap[point]
--        return [self._domain_from_gap[x] for x in self._gap_().Orbit(point).sage()]
--    
-+
-+        Action of `S_3` on sets::
-+
-+            sage: S3 = groups.permutation.Symmetric(3)
-+            sage: S3.orbit((1,2), action = "OnSets")
-+            [[1, 2], [2, 3], [1, 3]]
-+
-+        On tuples::
-+
-+            sage: S3.orbit((1,2), action = "OnTuples")
-+            [[1, 2], [2, 3], [2, 1], [3, 1], [1, 3], [3, 2]]
-+        """
-+        if action == "OnPoints":
-+            try:
-+                point = self._domain_to_gap[point]
-+            except KeyError:
-+                raise ValueError("The point given as argument does not seem to "+
-+                                 "exist. If you want to compute an action on sets "+
-+                                 "of tuples you *must* define the 'action' "+
-+                                 "argument explicitly.")
-+            return [self._domain_from_gap[x] for x in self._gap_().Orbit(point).sage()]
-+
-+        elif action in ["OnTuples", "OnSets"]:
-+            points = [self._domain_to_gap[x] for x in point]
-+            orbits = self._gap_().Orbit(points, action).sage()
-+            return [[self._domain_from_gap[x] for x in o] for o in orbits]
-+        else:
-+            raise ValueError("'action' can only take values among 'OnPoints', 'OnTuples' or 'OnSets'.")
-+
-     def transversals(self, point):
-         """
--        If G is a permutation group acting on the set `X = \{1, 2, ...., n\}` 
--        and H is the stabilizer subgroup of <integer>, a right 
--        (respectively left) transversal is a set containing exactly 
--        one element from each right (respectively left) coset of H. This 
--        method returns a right transversal of ``self`` by the stabilizer 
-+        If G is a permutation group acting on the set `X = \{1, 2, ...., n\}`
-+        and H is the stabilizer subgroup of <integer>, a right
-+        (respectively left) transversal is a set containing exactly
-+        one element from each right (respectively left) coset of H. This
-+        method returns a right transversal of ``self`` by the stabilizer
-         of ``self`` on <integer> position.
- 
-         EXAMPLES::
- 
--            sage: G = PermutationGroup([ [(3,4)], [(1,3)] ])           
-+            sage: G = PermutationGroup([ [(3,4)], [(1,3)] ])
-             sage: G.transversals(1)
-             [(), (1,3,4), (1,4,3)]
-             sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]])
--            sage: G.transversals(1)                                    
-+            sage: G.transversals(1)
-             [(), (1,2)(3,4), (1,3,2,10,4), (1,4,2,10,3), (1,10,4,3,2)]
- 
-             sage: G = PermutationGroup([ [('c','d')], [('a','c')] ])
-             sage: G.transversals('a')
--            [(), ('a','c','d'), ('a','d','c')]            
-+            [(), ('a','c','d'), ('a','d','c')]
-         """
-         G = self._gap_()
-         return [self(G.RepresentativeAction(self._domain_to_gap[point], self._domain_to_gap[i]))
-@@ -1128,7 +1163,7 @@
-             sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3,4,10)]])
-             sage: G.stabilizer(10)
-             Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4,10)]) generated by [(2,3,4), (1,2)(3,4)]
--            sage: G.stabilizer(1) 
-+            sage: G.stabilizer(1)
-             Subgroup of (Permutation Group with generators [(1,2)(3,4), (1,2,3,4,10)]) generated by [(2,3)(4,10), (2,10,4)]
-             sage: G = PermutationGroup([[(2,3,4)],[(6,7)]])
-             sage: G.stabilizer(1)

trac_14319-from_list_to_domain.patch

+# HG changeset patch
+# User Nathann Cohen <nathann.cohen@gmail.com>
+# Date 1364034315 -3600
+# Node ID 0996caa09bb4446bab9272984cabc14d9a47c01a
+# Parent  9ba68ffc259df41d694855a2646c6db8c56a40f5
+Renames permgroup_element.list() to domain()
+
+diff --git a/sage/graphs/generic_graph.py b/sage/graphs/generic_graph.py
+--- a/sage/graphs/generic_graph.py
++++ b/sage/graphs/generic_graph.py
+@@ -15919,6 +15919,7 @@
+ 
+         Relabeling using a Sage permutation::
+ 
++            sage: G = graphs.PathGraph(3)
+             sage: from sage.groups.perm_gps.permgroup_named import SymmetricGroup
+             sage: S = SymmetricGroup(3)
+             sage: gamma = S('(1,2)')
+@@ -16051,11 +16052,10 @@
+         elif isinstance(perm, PermutationGroupElement):
+             n = self.order()
+             ddict = {}
+-            llist = perm.list()
+             for i in xrange(1,n):
+-                ddict[i] = llist[i-1]%n
++                ddict[i] = perm(i)%n
+             if n > 0:
+-                ddict[0] = llist[n-1]%n
++                ddict[0] = perm(n)%n
+             perm = ddict
+ 
+         elif callable(perm):
+diff --git a/sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx b/sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx
+--- a/sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx
++++ b/sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx
+@@ -224,7 +224,7 @@
+         sage: gens = [[1,2,3,0]]
+         sage: reps = []
+         sage: for p in SymmetricGroup(4):
+-        ...     p = [a-1 for a in p.list()]
++        ...     p = [p(i)-1 for i in range(1,5)]
+         ...     r = coset_rep(p, gens)
+         ...     if r not in reps:
+         ...         reps.append(r)
+@@ -233,7 +233,7 @@
+         sage: gens = [[1,0,2,3],[0,1,3,2]]
+         sage: reps = []
+         sage: for p in SymmetricGroup(4):
+-        ...     p = [a-1 for a in p.list()]
++        ...     p = [p(i)-1 for i in range(1,5)]
+         ...     r = coset_rep(p, gens)
+         ...     if r not in reps:
+         ...         reps.append(r)
+@@ -242,7 +242,7 @@
+         sage: gens = [[1,2,0,3]]
+         sage: reps = []
+         sage: for p in SymmetricGroup(4):
+-        ...     p = [a-1 for a in p.list()]
++        ...     p = [p(i)-1 for i in range(1,5)]
+         ...     r = coset_rep(p, gens)
+         ...     if r not in reps:
+         ...         reps.append(r)
+diff --git a/sage/groups/perm_gps/partn_ref/data_structures_pyx.pxi b/sage/groups/perm_gps/partn_ref/data_structures_pyx.pxi
+--- a/sage/groups/perm_gps/partn_ref/data_structures_pyx.pxi
++++ b/sage/groups/perm_gps/partn_ref/data_structures_pyx.pxi
+@@ -1803,9 +1803,9 @@
+                 raise AssertionError
+             if test_contains:
+                 for i from 0 <= i < 3:
+-                    permy = G.random_element().list()
++                    permy = G.random_element()
+                     for j from 0 <= j < n:
+-                        perm[j] = permy[j]-1
++                        perm[j] = permy(j+1)-1
+                     if not SC_contains(SC, 0, perm, 0):
+                         print "FAIL", L
+                         print 'element', permy
+diff --git a/sage/groups/perm_gps/partn_ref/double_coset.pyx b/sage/groups/perm_gps/partn_ref/double_coset.pyx
+--- a/sage/groups/perm_gps/partn_ref/double_coset.pyx
++++ b/sage/groups/perm_gps/partn_ref/double_coset.pyx
+@@ -128,7 +128,7 @@
+         sage: gens = [[1,2,3,0]]
+         sage: reps = [[0,1,2,3]]
+         sage: for p in SymmetricGroup(4):
+-        ...     p = [a-1 for a in p.list()]
++        ...     p = [p(i)-1 for i in range(1,5)]
+         ...     found = False
+         ...     for r in reps:
+         ...         if coset_eq(p, r, gens):
+@@ -141,7 +141,7 @@
+         sage: gens = [[1,0,2,3],[0,1,3,2]]
+         sage: reps = [[0,1,2,3]]
+         sage: for p in SymmetricGroup(4):
+-        ...     p = [a-1 for a in p.list()]
++        ...     p = [p(i)-1 for i in range(1,5)]
+         ...     found = False
+         ...     for r in reps:
+         ...         if coset_eq(p, r, gens):
+@@ -154,7 +154,7 @@
+         sage: gens = [[1,2,0,3]]
+         sage: reps = [[0,1,2,3]]
+         sage: for p in SymmetricGroup(4):
+-        ...     p = [a-1 for a in p.list()]
++        ...     p = [p(i)-1 for i in range(1,5)]
+         ...     found = False
+         ...     for r in reps:
+         ...         if coset_eq(p, r, gens):
+diff --git a/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx b/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx
+--- a/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx
++++ b/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx
+@@ -901,7 +901,7 @@
+                 seen[i] = 1
+         return partition
+     else:
+-        n = len(gamma.list())
++        n = len(gamma.domain())
+         l = []
+         for i in range(1,n+1):
+             orb = gamma.orbit(i)
+diff --git a/sage/groups/perm_gps/permgroup_element.pxd b/sage/groups/perm_gps/permgroup_element.pxd
+--- a/sage/groups/perm_gps/permgroup_element.pxd
++++ b/sage/groups/perm_gps/permgroup_element.pxd
+@@ -10,7 +10,7 @@
+     cdef __tuple
+     cdef PermutationGroupElement _new_c(self)
+     cpdef _gap_list(self)
+-    cpdef list(self)
++    cpdef domain(self)
+     cdef public __custom_name
+     cpdef list _act_on_list_on_position(self, list x)
+     cpdef ClonableIntArray _act_on_array_on_position(self, ClonableIntArray x)
+diff --git a/sage/groups/perm_gps/permgroup_element.pyx b/sage/groups/perm_gps/permgroup_element.pyx
+--- a/sage/groups/perm_gps/permgroup_element.pyx
++++ b/sage/groups/perm_gps/permgroup_element.pyx
+@@ -67,6 +67,7 @@
+ from sage.interfaces.all import gap, is_GapElement, is_ExpectElement
+ from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
+ import sage.structure.coerce as coerce
++from sage.misc.superseded import deprecated_function_alias
+ 
+ import operator
+ 
+@@ -497,7 +498,7 @@
+            sage: func(*args)
+            (1,2,3)(4,5)
+         """
+-        return make_permgroup_element_v2, (self._parent, self.list(), self._parent.domain())
++        return make_permgroup_element_v2, (self._parent, self.domain(), self._parent.domain())
+         
+     cdef PermutationGroupElement _new_c(self):
+         cdef PermutationGroupElement other = PY_NEW_SAME_TYPE(self)
+@@ -917,23 +918,24 @@
+         from sage.combinat.permutation import Permutation
+         return Permutation(self._gap_list()).cycle_string()
+ 
+-    cpdef list(self):
++    list = deprecated_function_alias(14319, domain)
++
++    cpdef domain(self):
+         """
+-        Returns list of the images of the integers from 1 to n under this
+-        permutation as a list of Python ints.
+-        
++        Returns the domain of self.
++
+         EXAMPLES::
+-        
++
+             sage: G = SymmetricGroup(4)
+             sage: x = G([2,1,4,3]); x
+             (1,2)(3,4)
+-            sage: v = x.list(); v
++            sage: v = x.domain(); v
+             [2, 1, 4, 3]
+             sage: type(v[0])
+             <type 'int'>
+             sage: x = G([2,1]); x
+             (1,2)
+-            sage: x.list()
++            sage: x.domain()
+             [2, 1, 3, 4]
+ 
+         TESTS::
+@@ -941,7 +943,7 @@
+             sage: S = SymmetricGroup(0)
+             sage: x = S.one(); x
+             ()
+-            sage: x.list()
++            sage: x.domain()
+             []
+         """
+         cdef int i
+@@ -991,7 +993,7 @@
+             ('b', 'a')
+         """
+         if self.__tuple is None:
+-            self.__tuple = tuple(self.list())
++            self.__tuple = tuple(self.domain())
+         return self.__tuple
+ 
+     def dict(self):
 # HG changeset patch
 # User Nathann Cohen <nathann.cohen@gmail.com>
 # Date 1363778759 -3600
-# Node ID 8da8ff917556464499eecade3c96c492a1697e0b
-# Parent  5ed65b2c5b5f06692f6b1c9d0e3df2014b740263
+# Node ID 61d2f7c4dc97766aaa4100ea59eb4822f14530ac
+# Parent  acd941f2d1f5e8fcb0de1fa369236dba02664f04
 Graph Automorphism group with labeled vertices
 
 diff --git a/sage/geometry/fan_isomorphism.py b/sage/geometry/fan_isomorphism.py
 diff --git a/sage/geometry/polyhedron/base.py b/sage/geometry/polyhedron/base.py
 --- a/sage/geometry/polyhedron/base.py
 +++ b/sage/geometry/polyhedron/base.py
-@@ -3815,16 +3815,9 @@
+@@ -3891,16 +3891,9 @@
          for edge in self.vertex_graph().edges():
              i = edge[0]
              j = edge[1]
          self._combinatorial_automorphism_group = group
          return group
  
-@@ -4075,16 +4068,9 @@
+@@ -4151,16 +4144,9 @@
                  v_i = v_list[i]
                  v_j = v_list[j]
                  c_ij = rational_approximation( v_i * Qinv * v_j )
 diff --git a/sage/graphs/generic_graph.py b/sage/graphs/generic_graph.py
 --- a/sage/graphs/generic_graph.py
 +++ b/sage/graphs/generic_graph.py
-@@ -16181,62 +16181,60 @@
+@@ -10624,8 +10624,7 @@
+ 
+         # The automorphism group, the translation between the vertices of self
+         # and 1..n, and the orbits.
+-        ag, tr, orbits = self.automorphism_group([self.vertices()],
+-                          translation = True,
++        ag, orbits = self.automorphism_group([self.vertices()],
+                           order=False,
+                           return_group=True,
+                           orbits=True)
+@@ -10634,9 +10633,6 @@
+         if len(orbits) != 1:
+             return (False, None) if certificate else False
+ 
+-        # From 1..n to the vertices of self
+-        trr = {v:k for k,v in tr.iteritems()}
+-
+         # We go through all conjugacy classes of the automorphism
+         # group, and only keep the cycles of length n
+         for e in ag.conjugacy_classes_representatives():
+@@ -10657,8 +10653,8 @@
+             # add it to the list.
+             parameters = []
+             cycle = cycles[0]
+-            u = trr[cycle[0]]
+-            integers = [i for i,v in enumerate(cycle) if self.has_edge(u,trr[v])]
++            u = cycle[0]
++            integers = [i for i,v in enumerate(cycle) if self.has_edge(u,v)]
+             certif_list.append((self.order(),integers))
+ 
+         if not certificate:
+@@ -16310,62 +16306,60 @@
          result = coarsest_equitable_refinement(CG, partition, G._directed)
          return [[perm_from[b] for b in cell] for cell in result]
  
              sage: C = graphs.CubeGraph(4)
              sage: G = C.automorphism_group()
              sage: M = G.character_table() # random order of rows, thus abs() below
-@@ -16244,9 +16242,9 @@
+@@ -16373,9 +16367,9 @@
              712483534798848
              sage: G.order()
              384
              sage: D = graphs.DodecahedralGraph()
              sage: G = D.automorphism_group()
              sage: A5 = AlternatingGroup(5)
-@@ -16254,58 +16252,56 @@
+@@ -16383,58 +16377,56 @@
              sage: H = A5.direct_product(Z2)[0] #see documentation for direct_product to explain the [0]
              sage: G.is_isomorphic(H)
              True
              sage: G = graphs.PetersenGraph()
              sage: G.automorphism_group(return_group=False, orbits=True)
              [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]
-@@ -16326,8 +16322,25 @@
+@@ -16455,8 +16447,25 @@
              ...
              KeyError: 6
  
          from sage.groups.perm_gps.permgroup import PermutationGroup
          dig = (self._directed or self.has_loops())
          if partition is None:
-@@ -16394,7 +16407,8 @@
+@@ -16523,7 +16532,8 @@
                  HB.add_edge(u,v,None,self._directed)
              GC = HB._cg
              partition = [[G_to[v] for v in cell] for cell in partition]
                  A = search_tree(GC, partition, dict_rep=True, lab=False, dig=dig, verbosity=verbosity, order=order)
                  if order:
                      a,b,c = A
-@@ -16408,14 +16422,22 @@
+@@ -16537,14 +16547,22 @@
                  a = search_tree(GC, partition, dict_rep=False, lab=False, dig=dig, verbosity=verbosity, order=order)
                  if order:
                      a,c = a
 diff --git a/sage/groups/perm_gps/permgroup.py b/sage/groups/perm_gps/permgroup.py
 --- a/sage/groups/perm_gps/permgroup.py
 +++ b/sage/groups/perm_gps/permgroup.py
-@@ -2696,7 +2696,8 @@
+@@ -2794,7 +2794,8 @@
          Now the full blocks::
  
              sage: ag.blocks_all(representatives = False)

trac_14319_fix_fan_isomorphism.patch

 # HG changeset patch
-# Parent 9ad78e8eedf80ad30c83f5942f07a600b7468c77
+# Parent a79a31a3136ca71ab2ad35a0ce89d75a2eeae93a
 
 Fix bug in fan isomorphism check and improve doctesting
 
 diff --git a/sage/geometry/fan.py b/sage/geometry/fan.py
 --- a/sage/geometry/fan.py
 +++ b/sage/geometry/fan.py
-@@ -2554,7 +2554,7 @@
+@@ -2683,7 +2683,7 @@
  
          EXAMPLES::
  
          sage: cones = [(0,1), (1,2), (2,3), (3,0)]
          sage: fan1 = Fan(cones, rays)
  
+@@ -193,6 +230,13 @@
+         Traceback (most recent call last):
+         ...
+         FanNotIsomorphicError
++
++        sage: fan1 = Fan(cones=[[1,3,4,5],[0,1,2,3],[2,3,4],[0,1,5]],
++        ...              rays=[(-1,-1,0),(-1,-1,3),(-1,1,-1),(-1,3,-1),(0,2,-1),(1,-1,1)])
++        sage: fan2 = Fan(cones=[[0,2,3,5],[0,1,4,5],[0,1,2],[3,4,5]],
++        ...              rays=[(-1,-1,-1),(-1,-1,0),(-1,1,-1),(0,2,-1),(1,-1,1),(3,-1,-1)])
++        sage: fan1.is_isomorphic(fan2)
++        True
+     """
+     generator = fan_isomorphism_generator(fan1, fan2)
+     try:

trac_14319_temp_workaround.patch

+# HG changeset patch
+# Parent 974d0e106ae0a1eb817cdbe76686998d74f2c326
+
+diff --git a/sage/geometry/fan_isomorphism.py b/sage/geometry/fan_isomorphism.py
+--- a/sage/geometry/fan_isomorphism.py
++++ b/sage/geometry/fan_isomorphism.py
+@@ -160,7 +160,12 @@
+         for cone in fan2.generating_cones() )
+ 
+     # iterate over all graph isomorphisms graph1 -> graph2
+-    for perm in graph2.automorphism_group(edge_labels=True):
++    Aut = graph2.automorphism_group(edge_labels=True)
++    if Aut.cardinality() == 1:
++        from sage.groups.perm_gps.permgroup import PermutationGroup
++        Aut = PermutationGroup([()], domain=fan2(1))
++        
++    for perm in Aut:  #graph2.automorphism_group(edge_labels=True):
+         # find a candidate m that maps fan1_basis to the image rays under the graph isomorphism
+         fan2_pivot_cones = [ perm(graph_iso[c]) for c in fan1_pivot_cones ]
+         fan2_pivot_rays = fan2.rays([ c.ambient_ray_indices()[0] for c in fan2_pivot_cones  ])

trac_14394_face_fan_bug.patch

+# HG changeset patch
+# Parent bbc9ecdb4494b6660c1cd072584e051d2d6a6e62
+
+Better input checking for FaceFan
+
+diff --git a/sage/geometry/fan.py b/sage/geometry/fan.py
+--- a/sage/geometry/fan.py
++++ b/sage/geometry/fan.py
+@@ -601,7 +601,10 @@
+     - ``polytope`` -- a :func:`polytope
+       <sage.geometry.polyhedron.constructor.Polyhedron>` over `\QQ` or
+       a :class:`lattice polytope
+-      <sage.geometry.lattice_polytope.LatticePolytopeClass>`.
++      <sage.geometry.lattice_polytope.LatticePolytopeClass>`. A (not
++      necessarily full-dimensional) polytope contaning the origin in
++      its :meth:`relative interior
++      <sage.geometry.polyhedron.base.Polyhedron_base.relative_interior_contains>`.
+ 
+     - ``lattice`` -- :class:`ToricLattice
+       <sage.geometry.toric_lattice.ToricLatticeFactory>`, `\ZZ^n`, or any
+@@ -665,6 +668,12 @@
+         sage: FaceFan(interval_in_QQ2).generating_cones()
+         (1-d cone of Rational polyhedral fan in 2-d lattice N, 
+          1-d cone of Rational polyhedral fan in 2-d lattice N)
++
++        sage: FaceFan(Polyhedron([(-1,0), (1,0), (0,1)])) # origin on facet
++        Traceback (most recent call last):
++        ...
++        ValueError: face fans are defined only for
++        polytopes containing the origin as an interior point!
+     """
+     from sage.geometry.lattice_polytope import is_LatticePolytope
+     interior_point_error = ValueError(
+@@ -676,7 +685,9 @@
+         cones = (facet.vertices() for facet in polytope.facets())
+         rays = polytope.vertices().columns(copy=False)
+     else:
+-        if not (polytope.is_compact() and polytope.contains(polytope.ambient_space().zero())):
++        origin = polytope.ambient_space().zero()
++        if not (polytope.is_compact() and 
++                polytope.relative_interior_contains(origin)):
+             raise interior_point_error
+         cones = [ [ v.index() for v in facet.incident() ]
+                   for facet in polytope.inequalities() ]
+@@ -695,7 +706,9 @@
+     - ``polytope`` -- a :func:`polytope
+       <sage.geometry.polyhedron.constructor.Polyhedron>` over `\QQ`
+       or:class:`lattice polytope
+-      <sage.geometry.lattice_polytope.LatticePolytopeClass>`.
++      <sage.geometry.lattice_polytope.LatticePolytopeClass>`. A
++      full-dimensional polytope containing the origin as an interior
++      point.
+ 
+     - ``lattice`` -- :class:`ToricLattice
+       <sage.geometry.toric_lattice.ToricLatticeFactory>`, `\ZZ^n`, or any

trac_14394_reviewer.patch

+# HG changeset patch
+# User Andrey Novoseltsev <novoselt@gmail.com>
+# Date 1364881023 21600
+# Node ID 8d16c45427d45f4b3c19c3a5ee618f062818c00c
+# Parent  144c26a1c5f127cf5b3b79b405973448f2b39d0f
+Reviewers tweaks to FaceFan and NormalFan.
+
+diff --git a/sage/geometry/fan.py b/sage/geometry/fan.py
+--- a/sage/geometry/fan.py
++++ b/sage/geometry/fan.py
+@@ -594,7 +594,7 @@
+ 
+ def FaceFan(polytope, lattice=None):
+     r"""
+-    Construct the face fan of the given lattice ``polytope``.
++    Construct the face fan of the given rational ``polytope``.
+ 
+     INPUT:
+ 
+@@ -692,23 +692,21 @@
+         cones = [ [ v.index() for v in facet.incident() ]
+                   for facet in polytope.inequalities() ]
+         rays = map(vector, polytope.vertices())
+-    fan = Fan(cones, rays, lattice=lattice, check=False)
+-    fan._is_complete = polytope.dim() == polytope.ambient_dim()
++    fan = Fan(cones, rays, lattice=lattice, check=False,
++              is_complete=(polytope.dim() == polytope.ambient_dim()))
+     return fan
+ 
+ 
+ def NormalFan(polytope, lattice=None):
+     r"""
+-    Construct the normal fan of the given lattice ``polytope``.
++    Construct the normal fan of the given rational ``polytope``.
+ 
+     INPUT:
+ 
+-    - ``polytope`` -- a :func:`polytope
++    - ``polytope`` -- a full-dimensional :func:`polytope
+       <sage.geometry.polyhedron.constructor.Polyhedron>` over `\QQ`
+       or:class:`lattice polytope
+-      <sage.geometry.lattice_polytope.LatticePolytopeClass>`. A
+-      full-dimensional polytope containing the origin as an interior
+-      point.
++      <sage.geometry.lattice_polytope.LatticePolytopeClass>`.
+ 
+     - ``lattice`` -- :class:`ToricLattice
+       <sage.geometry.toric_lattice.ToricLatticeFactory>`, `\ZZ^n`, or any
+@@ -769,12 +767,12 @@
+         cones = (vertex.facets() for vertex in polytope.faces(dim=0))
+     else:
+         if not polytope.is_compact():
+-            raise ValueError('the normal fan is only defined for polytopes (compact polyhedra).')
++            raise NotImplementedError('the normal fan is only supported for polytopes (compact polyhedra).')
+         cones = [ [ ieq.index() for ieq in vertex.incident() ]
+                   for vertex in polytope.vertices() ]
+         rays =[ ieq.A() for ieq in polytope.inequalities() ]
+-    fan = Fan(cones, rays, lattice=lattice, check=False)
+-    fan._is_complete = polytope.dim() == polytope.ambient_dim()
++    fan = Fan(cones, rays, lattice=lattice, check=False,
++              is_complete=(polytope.dim() == polytope.ambient_dim()))
+     return fan
+ 
+ 

trac_x_fan_sage_input.patch

+# HG changeset patch
+# Parent 73e2049f64202d0f800c9a4dc6e5369926d55f3d
+
+diff --git a/sage/geometry/cone.py b/sage/geometry/cone.py
+--- a/sage/geometry/cone.py
++++ b/sage/geometry/cone.py
+@@ -1366,6 +1366,20 @@
+             self._PPL_C_Polyhedron = PPL
+             self._PPL_C_Polyhedron.set_immutable()
+ 
++    def _sage_input_(self, sib, coerced):
++        """
++        Return Sage command to reconstruct ``self``.
++
++        See :mod:`sage.misc.sage_input` for details.
++
++        EXAMPLES::
++
++            sage: cone = Cone([(1,0), (1,1)])
++            sage: sage_input(cone)
++            Cone([(1, 0), (1, 1)])
++        """
++        return sib.name('Cone')([sib(tuple(r)) for r in self.rays()])
++
+     def _PPL_cone(self):
+         r"""
+         Returns the Parma Polyhedra Library (PPL) representation of the cone.
+diff --git a/sage/geometry/fan.py b/sage/geometry/fan.py
+--- a/sage/geometry/fan.py
++++ b/sage/geometry/fan.py
+@@ -1144,6 +1144,22 @@
+         if virtual_rays is not None:
+             self._virtual_rays = PointCollection(virtual_rays, self.lattice())
+ 
++    def _sage_input_(self, sib, coerced):
++        """
++        Return Sage command to reconstruct ``self``.
++        
++        See :mod:`sage.misc.sage_input` for details.
++
++        EXAMPLES::
++
++            sage: fan = Fan([Cone([(1,0), (1,1)]), Cone([(-1,-1)])])
++            sage: sage_input(fan)
++            Fan(cones=[[0, 1], [2]], rays=[(1, 0), (1, 1), (-1, -1)])
++       """
++        cones = [map(ZZ, c.ambient_ray_indices()) for c in self.generating_cones()]
++        rays = [sib(tuple(r)) for r in self.rays()]
++        return sib.name('Fan')(cones=cones, rays=rays)
++
+     def __call__(self, dim=None, codim=None):
+         r"""
+         Return the specified cones of ``self``.