Repository: sympy/sympy

Issue:
Slow import of polyhedron
This line makes up 20% of the time taken to import sympy:
https://github.com/sympy/sympy/blob/84db1c1d5939f51a7d6d1f67888a31444b90e4ed/sympy/combinatorics/polyhedron.py#L825-L827

I'm not sure what it is doing that is slow but I think there should be a way to statically encode whatever it is that is calculated there.

Discussion:

Patch:
diff --git a/sympy/combinatorics/polyhedron.py b/sympy/combinatorics/polyhedron.py
index 0141ec69e7..ccb8ac72b3 100644
--- a/sympy/combinatorics/polyhedron.py
+++ b/sympy/combinatorics/polyhedron.py
@@ -807,10 +807,10 @@ def _string_to_perm(s):
         _dodeca_pgroup)
 
     icosahedron_faces = [
-        [0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 1, 5],
-        [1, 6, 7], [1, 2, 7], [2, 7, 8], [2, 3, 8], [3, 8, 9],
-        [3, 4, 9], [4, 9, 10 ], [4, 5, 10], [5, 6, 10], [1, 5, 6],
-        [6, 7, 11], [7, 8, 11], [8, 9, 11], [9, 10, 11], [6, 10, 11]]
+        (0, 1, 2), (0, 2, 3), (0, 3, 4), (0, 4, 5), (0, 1, 5),
+        (1, 6, 7), (1, 2, 7), (2, 7, 8), (2, 3, 8), (3, 8, 9),
+        (3, 4, 9), (4, 9, 10), (4, 5, 10), (5, 6, 10), (1, 5, 6),
+        (6, 7, 11), (7, 8, 11), (8, 9, 11), (9, 10, 11), (6, 10, 11)]
 
     icosahedron = Polyhedron(
         range(12),
@@ -822,6 +822,190 @@ def _string_to_perm(s):
         tetrahedron_faces, cube_faces, octahedron_faces,
         dodecahedron_faces, icosahedron_faces)
 
-(tetrahedron, cube, octahedron, dodecahedron, icosahedron,
-tetrahedron_faces, cube_faces, octahedron_faces,
-dodecahedron_faces, icosahedron_faces) = _pgroup_calcs()
+# -----------------------------------------------------------------------
+#   Standard Polyhedron groups
+#
+#   These are generated using _pgroup_calcs() above. However to save
+#   import time we encode them explicitly here.
+# -----------------------------------------------------------------------
+
+tetrahedron = Polyhedron(
+    Tuple(0, 1, 2, 3),
+    Tuple(
+        Tuple(0, 1, 2),
+        Tuple(0, 2, 3),
+        Tuple(0, 1, 3),
+        Tuple(1, 2, 3)),
+    Tuple(
+        Perm(1, 2, 3),
+        Perm(3)(0, 1, 2),
+        Perm(0, 3, 2),
+        Perm(0, 3, 1),
+        Perm(0, 1)(2, 3),
+        Perm(0, 2)(1, 3),
+        Perm(0, 3)(1, 2)
+    ))
+
+cube = Polyhedron(
+    Tuple(0, 1, 2, 3, 4, 5, 6, 7),
+    Tuple(
+        Tuple(0, 1, 2, 3),
+        Tuple(0, 1, 5, 4),
+        Tuple(1, 2, 6, 5),
+        Tuple(2, 3, 7, 6),
+        Tuple(0, 3, 7, 4),
+        Tuple(4, 5, 6, 7)),
+    Tuple(
+        Perm(0, 1, 2, 3)(4, 5, 6, 7),
+        Perm(0, 4, 5, 1)(2, 3, 7, 6),
+        Perm(0, 4, 7, 3)(1, 5, 6, 2),
+        Perm(0, 1)(2, 4)(3, 5)(6, 7),
+        Perm(0, 6)(1, 2)(3, 5)(4, 7),
+        Perm(0, 6)(1, 7)(2, 3)(4, 5),
+        Perm(0, 3)(1, 7)(2, 4)(5, 6),
+        Perm(0, 4)(1, 7)(2, 6)(3, 5),
+        Perm(0, 6)(1, 5)(2, 4)(3, 7),
+        Perm(1, 3, 4)(2, 7, 5),
+        Perm(7)(0, 5, 2)(3, 4, 6),
+        Perm(0, 5, 7)(1, 6, 3),
+        Perm(0, 7, 2)(1, 4, 6)))
+
+octahedron = Polyhedron(
+    Tuple(0, 1, 2, 3, 4, 5),
+    Tuple(
+        Tuple(0, 1, 2),
+        Tuple(0, 2, 3),
+        Tuple(0, 3, 4),
+        Tuple(0, 1, 4),
+        Tuple(1, 2, 5),
+        Tuple(2, 3, 5),
+        Tuple(3, 4, 5),
+        Tuple(1, 4, 5)),
+    Tuple(
+        Perm(5)(1, 2, 3, 4),
+        Perm(0, 4, 5, 2),
+        Perm(0, 1, 5, 3),
+        Perm(0, 1)(2, 4)(3, 5),
+        Perm(0, 2)(1, 3)(4, 5),
+        Perm(0, 3)(1, 5)(2, 4),
+        Perm(0, 4)(1, 3)(2, 5),
+        Perm(0, 5)(1, 4)(2, 3),
+        Perm(0, 5)(1, 2)(3, 4),
+        Perm(0, 4, 1)(2, 3, 5),
+        Perm(0, 1, 2)(3, 4, 5),
+        Perm(0, 2, 3)(1, 5, 4),
+        Perm(0, 4, 3)(1, 5, 2)))
+
+dodecahedron = Polyhedron(
+    Tuple(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19),
+    Tuple(
+        Tuple(0, 1, 2, 3, 4),
+        Tuple(0, 1, 6, 10, 5),
+        Tuple(1, 2, 7, 11, 6),
+        Tuple(2, 3, 8, 12, 7),
+        Tuple(3, 4, 9, 13, 8),
+        Tuple(0, 4, 9, 14, 5),
+        Tuple(5, 10, 16, 15, 14),
+        Tuple(6, 10, 16, 17, 11),
+        Tuple(7, 11, 17, 18, 12),
+        Tuple(8, 12, 18, 19, 13),
+        Tuple(9, 13, 19, 15, 14),
+        Tuple(15, 16, 17, 18, 19)),
+    Tuple(
+        Perm(0, 1, 2, 3, 4)(5, 6, 7, 8, 9)(10, 11, 12, 13, 14)(15, 16, 17, 18, 19),
+        Perm(0, 5, 10, 6, 1)(2, 4, 14, 16, 11)(3, 9, 15, 17, 7)(8, 13, 19, 18, 12),
+        Perm(0, 10, 17, 12, 3)(1, 6, 11, 7, 2)(4, 5, 16, 18, 8)(9, 14, 15, 19, 13),
+        Perm(0, 6, 17, 19, 9)(1, 11, 18, 13, 4)(2, 7, 12, 8, 3)(5, 10, 16, 15, 14),
+        Perm(0, 2, 12, 19, 14)(1, 7, 18, 15, 5)(3, 8, 13, 9, 4)(6, 11, 17, 16, 10),
+        Perm(0, 4, 9, 14, 5)(1, 3, 13, 15, 10)(2, 8, 19, 16, 6)(7, 12, 18, 17, 11),
+        Perm(0, 1)(2, 5)(3, 10)(4, 6)(7, 14)(8, 16)(9, 11)(12, 15)(13, 17)(18, 19),
+        Perm(0, 7)(1, 2)(3, 6)(4, 11)(5, 12)(8, 10)(9, 17)(13, 16)(14, 18)(15, 19),
+        Perm(0, 12)(1, 8)(2, 3)(4, 7)(5, 18)(6, 13)(9, 11)(10, 19)(14, 17)(15, 16),
+        Perm(0, 8)(1, 13)(2, 9)(3, 4)(5, 12)(6, 19)(7, 14)(10, 18)(11, 15)(16, 17),
+        Perm(0, 4)(1, 9)(2, 14)(3, 5)(6, 13)(7, 15)(8, 10)(11, 19)(12, 16)(17, 18),
+        Perm(0, 5)(1, 14)(2, 15)(3, 16)(4, 10)(6, 9)(7, 19)(8, 17)(11, 13)(12, 18),
+        Perm(0, 11)(1, 6)(2, 10)(3, 16)(4, 17)(5, 7)(8, 15)(9, 18)(12, 14)(13, 19),
+        Perm(0, 18)(1, 12)(2, 7)(3, 11)(4, 17)(5, 19)(6, 8)(9, 16)(10, 13)(14, 15),
+        Perm(0, 18)(1, 19)(2, 13)(3, 8)(4, 12)(5, 17)(6, 15)(7, 9)(10, 16)(11, 14),
+        Perm(0, 13)(1, 19)(2, 15)(3, 14)(4, 9)(5, 8)(6, 18)(7, 16)(10, 12)(11, 17),
+        Perm(0, 16)(1, 15)(2, 19)(3, 18)(4, 17)(5, 10)(6, 14)(7, 13)(8, 12)(9, 11),
+        Perm(0, 18)(1, 17)(2, 16)(3, 15)(4, 19)(5, 12)(6, 11)(7, 10)(8, 14)(9, 13),
+        Perm(0, 15)(1, 19)(2, 18)(3, 17)(4, 16)(5, 14)(6, 13)(7, 12)(8, 11)(9, 10),
+        Perm(0, 17)(1, 16)(2, 15)(3, 19)(4, 18)(5, 11)(6, 10)(7, 14)(8, 13)(9, 12),
+        Perm(0, 19)(1, 18)(2, 17)(3, 16)(4, 15)(5, 13)(6, 12)(7, 11)(8, 10)(9, 14),
+        Perm(1, 4, 5)(2, 9, 10)(3, 14, 6)(7, 13, 16)(8, 15, 11)(12, 19, 17),
+        Perm(19)(0, 6, 2)(3, 5, 11)(4, 10, 7)(8, 14, 17)(9, 16, 12)(13, 15, 18),
+        Perm(0, 11, 8)(1, 7, 3)(4, 6, 12)(5, 17, 13)(9, 10, 18)(14, 16, 19),
+        Perm(0, 7, 13)(1, 12, 9)(2, 8, 4)(5, 11, 19)(6, 18, 14)(10, 17, 15),
+        Perm(0, 3, 9)(1, 8, 14)(2, 13, 5)(6, 12, 15)(7, 19, 10)(11, 18, 16),
+        Perm(0, 14, 10)(1, 9, 16)(2, 13, 17)(3, 19, 11)(4, 15, 6)(7, 8, 18),
+        Perm(0, 16, 7)(1, 10, 11)(2, 5, 17)(3, 14, 18)(4, 15, 12)(8, 9, 19),
+        Perm(0, 16, 13)(1, 17, 8)(2, 11, 12)(3, 6, 18)(4, 10, 19)(5, 15, 9),
+        Perm(0, 11, 15)(1, 17, 14)(2, 18, 9)(3, 12, 13)(4, 7, 19)(5, 6, 16),
+        Perm(0, 8, 15)(1, 12, 16)(2, 18, 10)(3, 19, 5)(4, 13, 14)(6, 7, 17)))
+
+icosahedron = Polyhedron(
+    Tuple(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
+    Tuple(
+        Tuple(0, 1, 2),
+        Tuple(0, 2, 3),
+        Tuple(0, 3, 4),
+        Tuple(0, 4, 5),
+        Tuple(0, 1, 5),
+        Tuple(1, 6, 7),
+        Tuple(1, 2, 7),
+        Tuple(2, 7, 8),
+        Tuple(2, 3, 8),
+        Tuple(3, 8, 9),
+        Tuple(3, 4, 9),
+        Tuple(4, 9, 10),
+        Tuple(4, 5, 10),
+        Tuple(5, 6, 10),
+        Tuple(1, 5, 6),
+        Tuple(6, 7, 11),
+        Tuple(7, 8, 11),
+        Tuple(8, 9, 11),
+        Tuple(9, 10, 11),
+        Tuple(6, 10, 11)),
+    Tuple(
+        Perm(11)(1, 2, 3, 4, 5)(6, 7, 8, 9, 10),
+        Perm(0, 5, 6, 7, 2)(3, 4, 10, 11, 8),
+        Perm(0, 1, 7, 8, 3)(4, 5, 6, 11, 9),
+        Perm(0, 2, 8, 9, 4)(1, 7, 11, 10, 5),
+        Perm(0, 3, 9, 10, 5)(1, 2, 8, 11, 6),
+        Perm(0, 4, 10, 6, 1)(2, 3, 9, 11, 7),
+        Perm(0, 1)(2, 5)(3, 6)(4, 7)(8, 10)(9, 11),
+        Perm(0, 2)(1, 3)(4, 7)(5, 8)(6, 9)(10, 11),
+        Perm(0, 3)(1, 9)(2, 4)(5, 8)(6, 11)(7, 10),
+        Perm(0, 4)(1, 9)(2, 10)(3, 5)(6, 8)(7, 11),
+        Perm(0, 5)(1, 4)(2, 10)(3, 6)(7, 9)(8, 11),
+        Perm(0, 6)(1, 5)(2, 10)(3, 11)(4, 7)(8, 9),
+        Perm(0, 7)(1, 2)(3, 6)(4, 11)(5, 8)(9, 10),
+        Perm(0, 8)(1, 9)(2, 3)(4, 7)(5, 11)(6, 10),
+        Perm(0, 9)(1, 11)(2, 10)(3, 4)(5, 8)(6, 7),
+        Perm(0, 10)(1, 9)(2, 11)(3, 6)(4, 5)(7, 8),
+        Perm(0, 11)(1, 6)(2, 10)(3, 9)(4, 8)(5, 7),
+        Perm(0, 11)(1, 8)(2, 7)(3, 6)(4, 10)(5, 9),
+        Perm(0, 11)(1, 10)(2, 9)(3, 8)(4, 7)(5, 6),
+        Perm(0, 11)(1, 7)(2, 6)(3, 10)(4, 9)(5, 8),
+        Perm(0, 11)(1, 9)(2, 8)(3, 7)(4, 6)(5, 10),
+        Perm(0, 5, 1)(2, 4, 6)(3, 10, 7)(8, 9, 11),
+        Perm(0, 1, 2)(3, 5, 7)(4, 6, 8)(9, 10, 11),
+        Perm(0, 2, 3)(1, 8, 4)(5, 7, 9)(6, 11, 10),
+        Perm(0, 3, 4)(1, 8, 10)(2, 9, 5)(6, 7, 11),
+        Perm(0, 4, 5)(1, 3, 10)(2, 9, 6)(7, 8, 11),
+        Perm(0, 10, 7)(1, 5, 6)(2, 4, 11)(3, 9, 8),
+        Perm(0, 6, 8)(1, 7, 2)(3, 5, 11)(4, 10, 9),
+        Perm(0, 7, 9)(1, 11, 4)(2, 8, 3)(5, 6, 10),
+        Perm(0, 8, 10)(1, 7, 6)(2, 11, 5)(3, 9, 4),
+        Perm(0, 9, 6)(1, 3, 11)(2, 8, 7)(4, 10, 5)))
+
+tetrahedron_faces = list(tuple(arg) for arg in tetrahedron.faces)
+
+cube_faces = list(tuple(arg) for arg in cube.faces)
+
+octahedron_faces = list(tuple(arg) for arg in octahedron.faces)
+
+dodecahedron_faces = list(tuple(arg) for arg in dodecahedron.faces)
+
+icosahedron_faces = list(tuple(arg) for arg in icosahedron.faces)
diff --git a/sympy/printing/repr.py b/sympy/printing/repr.py
index e6d0f1b32e..11000f351b 100644
--- a/sympy/printing/repr.py
+++ b/sympy/printing/repr.py
@@ -56,6 +56,9 @@ def _print_Add(self, expr, order=None):
     def _print_Cycle(self, expr):
         return expr.__repr__()
 
+    def _print_Permutation(self, expr):
+        return expr.__repr__()
+
     def _print_Function(self, expr):
         r = self._print(expr.func)
         r += '(%s)' % ', '.join([self._print(a) for a in expr.args])


Test patch:
diff --git a/sympy/combinatorics/tests/test_polyhedron.py b/sympy/combinatorics/tests/test_polyhedron.py
index 1b842b043e..835324bb3e 100644
--- a/sympy/combinatorics/tests/test_polyhedron.py
+++ b/sympy/combinatorics/tests/test_polyhedron.py
@@ -83,3 +83,24 @@ def check(h, size, rpt, target):
         (3, 4, 4, 5, 5),
             (12, 24, 24, 60, 60)):
         check(h, size, rpt, target)
+
+
+def test_pgroups():
+    from sympy.combinatorics.polyhedron import (tetrahedron, cube, octahedron,
+            dodecahedron, icosahedron, tetrahedron_faces, cube_faces,
+            octahedron_faces, dodecahedron_faces, icosahedron_faces)
+    from sympy.combinatorics.polyhedron import _pgroup_calcs
+    (tetrahedron2, cube2, octahedron2, dodecahedron2, icosahedron2,
+     tetrahedron_faces2, cube_faces2, octahedron_faces2,
+     dodecahedron_faces2, icosahedron_faces2) = _pgroup_calcs()
+
+    assert tetrahedron == tetrahedron2
+    assert cube == cube2
+    assert octahedron == octahedron2
+    assert dodecahedron == dodecahedron2
+    assert icosahedron == icosahedron2
+    assert sorted(map(sorted, tetrahedron_faces)) == sorted(map(sorted, tetrahedron_faces2))
+    assert sorted(cube_faces) == sorted(cube_faces2)
+    assert sorted(octahedron_faces) == sorted(octahedron_faces2)
+    assert sorted(dodecahedron_faces) == sorted(dodecahedron_faces2)
+    assert sorted(icosahedron_faces) == sorted(icosahedron_faces2)
diff --git a/sympy/printing/tests/test_repr.py b/sympy/printing/tests/test_repr.py
index ed5c3dc6cc..dc9ce7bb58 100644
--- a/sympy/printing/tests/test_repr.py
+++ b/sympy/printing/tests/test_repr.py
@@ -2,6 +2,7 @@
 from sympy import (symbols, Function, Integer, Matrix, Abs,
     Rational, Float, S, WildFunction, ImmutableDenseMatrix, sin, true, false, ones,
     sqrt, root, AlgebraicNumber, Symbol, Dummy, Wild, MatrixSymbol)
+from sympy.combinatorics import Cycle, Permutation
 from sympy.core.compatibility import exec_
 from sympy.geometry import Point, Ellipse
 from sympy.printing import srepr
@@ -17,15 +18,21 @@
 exec_("from sympy import *", ENV)
 
 
-def sT(expr, string):
+def sT(expr, string, import_stmt=None):
     """
     sT := sreprTest
 
     Tests that srepr delivers the expected string and that
     the condition eval(srepr(expr))==expr holds.
     """
+    if import_stmt is None:
+        ENV2 = ENV
+    else:
+        ENV2 = ENV.copy()
+        exec_(import_stmt, ENV2)
+
     assert srepr(expr) == string
-    assert eval(string, ENV) == expr
+    assert eval(string, ENV2) == expr
 
 
 def test_printmethod():
@@ -275,6 +282,7 @@ def test_Naturals0():
 def test_Reals():
     sT(S.Reals, "Reals")
 
+
 def test_matrix_expressions():
     n = symbols('n', integer=True)
     A = MatrixSymbol("A", n, n)
@@ -282,3 +290,16 @@ def test_matrix_expressions():
     sT(A, "MatrixSymbol(Symbol('A'), Symbol('n', integer=True), Symbol('n', integer=True))")
     sT(A*B, "MatMul(MatrixSymbol(Symbol('A'), Symbol('n', integer=True), Symbol('n', integer=True)), MatrixSymbol(Symbol('B'), Symbol('n', integer=True), Symbol('n', integer=True)))")
     sT(A + B, "MatAdd(MatrixSymbol(Symbol('A'), Symbol('n', integer=True), Symbol('n', integer=True)), MatrixSymbol(Symbol('B'), Symbol('n', integer=True), Symbol('n', integer=True)))")
+
+
+def test_Cycle():
+    # FIXME: sT fails because Cycle is not immutable and calling srepr(Cycle(1, 2))
+    # adds keys to the Cycle dict (GH-17661)
+    #import_stmt = "from sympy.combinatorics import Cycle"
+    #sT(Cycle(1, 2), "Cycle(1, 2)", import_stmt)
+    assert srepr(Cycle(1, 2)) == "Cycle(1, 2)"
+
+
+def test_Permutation():
+    import_stmt = "from sympy.combinatorics import Permutation"
+    sT(Permutation(1, 2), "Permutation(1, 2)", import_stmt)