Skip to content
Browse files

Polyhedron: cyclic clash; polyhedra have pgroups; Basic.copy

named_groups uses cyclic so the function in permutations was
changed to full_cyclic_form0 and one_based was changed to
cyclic_form1; these are more descriptive and consistent with
the method name (cyclic_form).

All pre-defined polyhedra come with pgroups that are checked
to cover all orientations.

Docstrings have been expanded.

The _canonical function was renamed minlex but it was kept
in the polyhedron file; it is potentially useful for iterables
or geometry.

Unused imports were deleted.

The copy method was added to Basic to allow a copy to be
made of an object that implements in-place changes.
  • Loading branch information...
1 parent 3c49022 commit 052f6fe223aaf5229bfa9e090e8dd0c9cf5a3f6e @smichr committed Aug 22, 2012
View
2 sympy/combinatorics/generators.py
@@ -1,5 +1,5 @@
from sympy.combinatorics.permutations import Permutation
-from sympy.combinatorics.permutations import cyclic as perm_cyclic
+from sympy.combinatorics.permutations import full_cyclic_form0 as perm_cyclic
from sympy.utilities.iterables import variations, rotate_left
def symmetric(n):
View
42 sympy/combinatorics/permutations.py
@@ -7,26 +7,28 @@
import random
-def cyclic(cyclic_form1, n):
- """Convert from 1-based cyclic-form to 0-based cyclic form after
- filling in any missing singletons (up to ``n``).
+def full_cyclic_form0(cyclic_form1, n):
+ """Convert from a 1-based permutation in cycle notation
+ to 0-based cyclic form after filling in any missing
+ singletons (up to ``n``).
If any element in the cycles is greater than n, singletons will
- be missing from the cyclic form returned.
+ be missing from the returned permutation.
- >>> from sympy.combinatorics.permutations import cyclic
+ >>> from sympy.combinatorics.permutations import full_cyclic_form0
>>> a = [(1, 2, 3)]
- >>> cyclic(a, 5)
+ >>> full_cyclic_form0(a, 5)
[[0, 1, 2], [3], [4]]
>>> a = [(1, 2, 3), (4, 5)]
- >>> cyclic(a, 5)
+ >>> full_cyclic_form0(a, 5)
[[0, 1, 2], [3, 4]]
- >>> cyclic([[4, 5]], 2)
+ >>> full_cyclic_form0([[4, 5]], 2)
[[3, 4], [0], [1]]
See Also
========
- one_based
+
+ cyclic_form1
"""
rv = []
@@ -38,34 +40,36 @@ def cyclic(cyclic_form1, n):
rv.extend([[i] for i in sorted(need)])
return rv
-def one_based(cyclic_form0, singletons=False):
+def cyclic_form1(cyclic_form0, singletons=False):
"""Return a cyclic form in 1-based cyclic form, omitting singletons
if ``singleton`` is False (default).
Examples
========
- >>> from sympy.combinatorics.permutations import Permutation
- >>> from sympy.combinatorics.permutations import one_based, cyclic
- >>> one_based([[0, 1], [2]])
+ >>> from sympy.combinatorics.permutations import (Permutation,
+ ... cyclic_form1, full_cyclic_form0)
+ ...
+ >>> cyclic_form1([[0, 1], [2]])
[[1, 2]]
- >>> one_based([[0, 1], [2]], singletons=True)
+ >>> cyclic_form1([[0, 1], [2]], singletons=True)
[[1, 2], [3]]
- >>> p = Permutation(cyclic([(2, 3, 4)], 5))
+ >>> p = Permutation(full_cyclic_form0([(2, 3, 4)], 5))
>>> p.reduced_cyclic_form
[[1, 2, 3]]
>>> p.cyclic_form
[[1, 2, 3], [0], [4]]
>>> c = _
- >>> one_based(c)
+ >>> cyclic_form1(c)
[[2, 3, 4]]
- >>> one_based(c, True)
+ >>> cyclic_form1(c, True)
[[2, 3, 4], [1], [5]]
See Also
========
- cyclic
+
+ full_cyclic_form0
"""
min = 1 + (not bool(singletons))
@@ -121,7 +125,7 @@ def _af_mul(*a):
See Also
========
- Permutation, _af_mul
+ Permutation
"""
if not a:
raise ValueError("No element")
View
352 sympy/combinatorics/polyhedron.py
@@ -2,12 +2,21 @@
from sympy.core.sympify import sympify
from sympy.combinatorics import Permutation
from sympy.utilities.misc import default_sort_key
-from sympy.utilities.iterables import rotate_left, has_variety
-
-from random import choice
-
-def _canonical(face):
- """Return the face in canonical order."""
+from sympy.utilities.iterables import rotate_left, has_variety, is_sequence
+from sympy.utilities.randtest import _randrange
+
+def minlex(face):
+ """Return the face in canonical order: smallest first with
+ direction (perhaps reversed) such that the next smallest comes next.
+
+ Examples
+ ========
+ >>> from sympy.combinatorics.polyhedron import minlex
+ >>> minlex((1, 0, 2))
+ (0, 1, 2)
+ >>> minlex((1, 2, 0))
+ (0, 1, 2)
+ """
face = list(face)
small = min(face)
i = face.index(small)
@@ -173,19 +182,91 @@ def __new__(cls, corners, faces=[], pgroups=[]):
>>> _ in all and _ == sequentially
True
- Note
- ====
+ Notes
+ =====
+
+ It is not necessary to enter any permutations, nor is necessary to
+ enter a complete set of transforations. In fact, two permutations
+ (corresponding to a rotation on an axis through a vertex and face
+ and another for the rotation through a different vertex or from
+ one edge to the opposite edge) are sufficient to generate all
+ orientations. For simplicity of presentation, consider a square --
+ not a cube -- with vertices 1, 2, 3, and 4:
+
+ 1-----2 We could think of axes of rotation being:
+ | | 1) through the face
+ | | 2) from midpoint 1-2 to 3-4 or 1-3 to 2-4
+ 3-----4 3) lines 1-4 or 2-3
+
+
+ To determine how to write the permutations, imagine 4 cameras, one at
+ each corner:
+
+ A B A B
+ 1-----2 1-----3 vertex index:
+ | | | | 1 0
+ | | | | 2 1
+ 3-----4 2-----4 3 2
+ C D C D 4 3
+
+ original after rotation
+ along 1-4
+
+ A diagonal and a face axis will be chosen for the "permutation group"
+ from which any orientation can be constructed.
+
+ >>> pgroup = []
+
+ Imagine rotating clockwise when viewing 1-4 from camera A. The new
+ orientation is (in camera-order): 1, 3, 2, 4 so the permutation is
+ given using the *indices* of the vertices as:
+
+ >>> pgroup.append(Permutation((0, 2, 1, 3)))
+
+ Now imagine rotating clockwise when looking down an axis entering the
+ center of the square as viewed. The new camera-order would be
+ 3, 1, 4, 2 so the permutation is (using indices):
+
+ >>> pgroup.append(Permutation((2, 0, 3, 1)))
+
+ The square can now be constructed:
+ ** use real-world labels for the vertices, entering them in
+ camera order
+ ** for the faces we use zero-based indices of the vertices
+ in *edge-order* as the face is traversed; neither the
+ direction nor the starting point matter -- the faces are
+ only used to define edges (if so desired).
+
+ >>> square = Polyhedron((1, 2, 3, 4), [(0, 1, 3, 2)], pgroup)
+
+ To rotate the square a single permutation we can do:
+
+ >>> sq = square.copy()
+ >>> sq.rotate(square.pgroups[0]); sq.corners
+ (1, 3, 2, 4)
+
+ To use more than one permutation (or to use one permutation more
+ than once) it is more convenient to use the make_perm method:
+
+ >>> p011 = square.make_perm([0,1,1]) # diag flip and 2 rotations
+ >>> sq = square.copy()
+ >>> sq.rotate(p011); sq.corners
+ (4, 2, 3, 1)
+
+
+ Predefined Polyhedra
+ ====================
For convenience, the vertices and faces are defined for the following
- standard solids (but the allowed transformations are not provided).
+ standard solids along with a permutation group for transformations.
When the polyhedron is oriented as indicated below, the vertices in
a given horizontal plane are numbered in ccw direction, starting from
the vertex that will give the lowest indices in a given face. (In the
net of the vertices, indices preceded by "-" indicate replication of
the lhs index in the net.)
- tetrahedron
- -----------
+ tetrahedron, tetrahedron_faces
+ ------------------------------
4 vertices (vertex up) net:
@@ -196,8 +277,8 @@ def __new__(cls, corners, faces=[], pgroups=[]):
(0,1,2) (0,2,3) (0,3,1) (1,2,3)
- cube
- ----
+ cube, cube_faces
+ ----------------
8 vertices (face up) net:
@@ -210,8 +291,8 @@ def __new__(cls, corners, faces=[], pgroups=[]):
(0,1,5,4) (1,2,6,5) (2,3,7,6) (0,3,7,4)
(4,5,6,7)
- octahedron
- ----------
+ octahedron, octahedron_faces
+ ----------------------------
6 vertices (vertex up) net:
@@ -224,8 +305,25 @@ def __new__(cls, corners, faces=[], pgroups=[]):
(0,1,2) (0,2,3) (0,3,4) (0,1,4)
(1,2,5) (2,3,5) (3,4,5) (1,4,5)
- dodecahedron
- ------------
+ dodecahedron, dodecahedron_faces
+ --------------------------------
+
+ 20 vertices (vertex up) net:
+
+ 0 1 2 3 4 -0
+ 5 6 7 8 9 -5
+ 14 10 11 12 13-14
+ 15 16 17 18 19-15
+
+ 12 faces:
+
+ (0,1,2,3,4)
+ (0,1,6,10,5) (1,2,7,11,6) (2,3,8,12,7) (3,4,9,13,8) (0,4,9,14,5)
+ (5,10,16,15,14) (6,10,16,17,11) (7,11,17,18,12) (8,12,18,19,13) (9,13,19,15,14)
+ (15,16,17,18,19)
+
+ icosahedron, icosahedron_faces
+ ------------------------------
12 vertices (face up) net:
@@ -241,34 +339,15 @@ def __new__(cls, corners, faces=[], pgroups=[]):
(2,6,7) (3,7,8) (4,8,9) (5,9,10) (1,6,10)
(6,7,11,) (7,8,11) (8,9,11) (9,10,11) (6,10,11)
- icosahedron
- -----------
-
- 20 vertices (vertex up) net:
-
- 0 1 2 3 4 -0
- 5 6 7 8 9 -5
- 10 11 12 13 14-10
- 15 16 17 18 19-15
-
- 12 faces:
-
- (0,1,2,3,4)
- (0,1,6,11,5) (1,2,7,12,6) (2,3,8,13,7) (3,4,9,14,8) (0,4,9,10,5)
- (5,10,15,16,11) (6,11,16,17,12) (7,12,17,18,13) (8,13,18,19,14)
- (9,10,15,19,14)
- (15,16,17,18,19)
-
>>> from sympy.combinatorics.polyhedron import cube
- >>> Polyhedron(*cube).edges
+ >>> cube.edges
{(0, 1), (0, 3), (0, 4), '...', (4, 7), (5, 6), (6, 7)}
If you want to use letters or other names for the corners you
can still use the pre-calculated faces:
- >>> _, faces = cube
>>> corners = list('abcdefgh')
- >>> Polyhedron(corners, faces).corners
+ >>> Polyhedron(corners, cube.faces).corners
(a, b, c, d, e, f, g, h)
References
@@ -277,7 +356,7 @@ def __new__(cls, corners, faces=[], pgroups=[]):
[1] www.ocf.berkeley.edu/~wwu/articles/platonicsolids.pdf
"""
- faces = [_canonical(f) for f in faces]
+ faces = [minlex(f) for f in faces]
corners, faces, pgroups = args = \
[Tuple(*a) for a in (corners, faces, pgroups)]
obj = Basic.__new__(cls, *args)
@@ -362,12 +441,13 @@ def make_perm(self, n, seed=None):
"""
Multiply ``n`` randomly selected permutations from
pgroups together, starting with the identity
- permutation.
+ permutation. If ``n`` is a list of integers, those
+ integers will be used to select the permutations.
``seed`` is used to set the seed for the random selection
of permutations from pgroups. If this is a list of integers,
the corresponding permutations from pgroups will be selected
- in the order give.
+ in the order give. This is mainly used for testing purposes.
Examples
========
@@ -379,9 +459,14 @@ def make_perm(self, n, seed=None):
Permutation([1, 0, 3, 2])
>>> h.make_perm(3, [0, 1, 0])
Permutation([2, 0, 3, 1])
+ >>> h.make_perm([0, 1, 0])
+ Permutation([2, 0, 3, 1])
"""
- from sympy.utilities.randtest import _randrange
+ if is_sequence(n):
+ if is_sequence(seed):
+ raise ValueError('If n is a sequence, seed should be None')
+ n, seed = len(n), n
randrange = _randrange(seed)
# start with the identity permutation
@@ -402,11 +487,17 @@ def rotate(self, perm):
========
>>> from sympy.combinatorics import Polyhedron, Permutation
- >>> h = Polyhedron(list('abcde'))
- >>> h.rotate(Permutation([3, 0, 1, 2, 4]))
+ >>> shadow = h = Polyhedron(list('abcde'))
+ >>> p = Permutation([3, 0, 1, 2, 4])
+ >>> h.rotate(p)
>>> h.corners
(d, a, b, c, e)
-
+ >>> _ == shadow.corners
+ True
+ >>> copy = h.copy()
+ >>> h.rotate(p)
+ >>> h.corners == copy.corners
+ False
"""
if perm.size != self.size:
raise ValueError("The size of the permutation and polyhedron must match.")
@@ -415,24 +506,153 @@ def rotate(self, perm):
temp.append(self.corners[perm.array_form[i]])
self._corners = tuple(temp)
-tetrahedron = ([0, 1, 2, 3],[[0, 1, 2], [0, 2, 3], [0, 3, 1], [1, 2, 3]])
-cube = ([0, 1, 2, 3, 4, 5, 6, 7], [
- [0, 1, 2, 3],
- [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [0, 3, 7, 4],
- [4, 5, 6, 7]])
-octahedron = ([0, 1, 2, 3, 4, 5], [
- [0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 1, 4],
- [1, 2, 5], [2, 3, 5], [3, 4, 5], [1, 4, 5]])
-icosahedron = ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [
- [0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 1, 5],
- [1, 2, 6], [2, 3, 7], [3, 4, 8], [4, 5, 9], [1, 5, 10],
- [2, 6, 7], [3, 7, 8], [4, 8, 9], [5, 9, 10], [1, 6, 10],
- [6, 7, 11], [7, 8, 11], [8, 9, 11], [9, 10, 11], [6, 10, 11]])
-dodecahedron = ([0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
- 10, 11, 12, 13, 14, 15, 16, 17, 18, 19], [
- [0, 1, 2, 3, 4],
- [0, 1, 6, 11, 5], [1, 2, 7, 12, 6], [2, 3, 8, 13, 7],
- [3, 4, 9, 14, 8], [0, 4, 9, 10, 5],
- [5, 10, 15, 16, 11], [6, 11, 16, 17, 12], [7, 12, 17, 18, 13],
- [8, 13, 18, 19, 14], [9, 10, 15, 19, 14],
- [15, 16, 17, 18, 19]])
+def _pgroup_calcs():
+ """
+ Although only 2 permutations are needed for a polyhedron in order to
+ generate all the possible orientations, it is customary to give a
+ group of permutations (P0, P1, ...) such that powers of them alone are
+ able to generate the orientations, e.g. P0, P0**2, P0**3, P1, P1**2,
+ etc..., instead of mixed permutations (P0*P1**2*P0). The following
+ work was used to calculate the permutation group of the polyhedra.
+ """
+ def _pgroups_of_double(polyh, ordered_faces, pgroup):
+ from sympy.utilities import unflatten, flatten
+ from sympy.ntheory.residue_ntheory import int_tested
+ n = len(ordered_faces[0])
+ # the vertices of the double which sits inside a give polyhedron
+ # can be found by tracking the faces of the outer polyhedron.
+ # A map between face and the vertex of the double is made so that
+ # afater rotation the position of the vertices can be located
+ fmap = dict(zip(ordered_faces,
+ range(len(ordered_faces))))
+ flat_faces = flatten(ordered_faces)
+ new_pgroup = []
+ for i, p in enumerate(pgroup):
+ h = polyh.copy()
+ h.rotate(p)
+ c = h.corners
+ # reorder corners in the order they should appear when
+ # enumerating the faces
+ reorder = unflatten([c[j] for j in flat_faces], n)
+ # make them canonical
+ reorder = [tuple(int_tested(minlex(f))) for f in reorder]
+ # map face to vertex: the resulting list of vertices are the
+ # permutation that we seek for the double
+ new_pgroup.append(Permutation([fmap[f] for f in reorder]))
+ return new_pgroup
+
+ tetrahedron_faces = [(0, 1, 2), (0, 2, 3), (0, 3, 1), (1, 2, 3)]
+
+ _t_pgroups = [
+ Permutation([[0,1,2], [3]]),\
+ Permutation([[0,1,3], [2]]),\
+ Permutation([[0,2,3], [1]]),\
+ Permutation([[1,2,3], [0]]),\
+ Permutation([[0,1], [2,3]]),\
+ Permutation([[0,2], [1,3]]),\
+ Permutation([[0,3], [1,2]])]
+
+ tetrahedron = Polyhedron(
+ range(4),
+ tetrahedron_faces,
+ _t_pgroups)
+
+ cube_faces = [
+ (0, 1, 2, 3),
+ (0, 1, 5, 4), (1, 2, 6, 5), (2, 3, 7, 6), (0, 3, 7, 4),
+ (4, 5, 6, 7)]
+
+ _c_pgroups = [Permutation(p) for p in
+ [[1,2,3,0,5,6,7,4],
+ [4,0,3,7,5,1,2,6],
+ [4,5,1,0,7,6,2,3],
+
+ [1,0,4,5,2,3,7,6],
+ [6,2,1,5,7,3,0,4],
+ [6,7,3,2,5,4,0,1],
+ [3,7,4,0,2,6,5,1],
+ [6,5,4,7,2,1,0,3],
+ [4,7,6,5,0,3,2,1],
+
+ [0,3,7,4,1,2,6,5],
+ [5,1,0,4,6,2,3,7],
+ [5,6,2,1,4,7,3,0],
+ [7,4,0,3,6,5,1,2]]]
+
+ cube = Polyhedron(
+ range(8),
+ cube_faces,
+ _c_pgroups)
+
+ octahedron_faces = [
+ (0, 1, 2), (0, 2, 3), (0, 3, 4), (0, 1, 4),
+ (1, 2, 5), (2, 3, 5), (3, 4, 5), (1, 4, 5)]
+
+ octahedron = Polyhedron(
+ range(6),
+ octahedron_faces,
+ _pgroups_of_double(cube, cube_faces, _c_pgroups))
+
+ dodecahedron_faces = [
+ (0,1,2,3,4),
+ (0,1,6,10,5), (1,2,7,11,6), (2,3,8,12,7),
+ (3,4,9,13,8), (0,4,9,14,5),
+ (5,10,16,15,14), (6,10,16,17,11), (7,11,17,18,12),
+ (8,12,18,19,13), (9,13,19,15,14),
+ (15,16,17,18,19)]
+
+ def _string_to_perm(s):
+ rv = Permutation(range(20))
+ last = None
+ for si in s:
+ if si == '0':
+ rv *= _f0
+ last = _f0
+ elif si == '1':
+ rv *= _f1
+ last = _f1
+ else:
+ for i in range(int(si) - 1):
+ rv *= last
+ return rv
+ # top face cw
+ _f0 = Permutation([
+ 1, 2, 3, 4, 0, 6, 7, 8, 9, 5, 11,
+ 12, 13, 14, 10, 16, 17, 18, 19, 15])
+ # front face cw
+ _f1 = Permutation([
+ 5, 0, 4, 9, 14, 10, 1, 3, 13, 15,
+ 6, 2, 8, 19, 16, 17, 11, 7, 12, 18])
+ # the strings below, like 0104 are shorthand for F0*F1*F0**4 and are
+ # the remaining 4 face rotations, 15 edge permutations, and the
+ # 10 vertex rotations.
+ _dodeca_pgroups = [_f0, _f1] + [_string_to_perm(s) for s in '''
+ 0104 140 014 0410
+ 010 1403 03104 04103 102
+ 120 1304 01303 021302 03130
+ 0412041 041204103 04120410 041204104 041204102
+ 10 01 1402 0140 04102 0412 1204 1302 0130 03120'''.strip().split()]
+
+ dodecahedron = Polyhedron(
+ range(20),
+ dodecahedron_faces,
+ _dodeca_pgroups)
+
+ 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]]
+
+ icosahedron = Polyhedron(
+ range(12),
+ icosahedron_faces,
+ _pgroups_of_double(dodecahedron, dodecahedron_faces, _dodeca_pgroups))
+
+ return (tetrahedron, cube, octahedron, dodecahedron, icosahedron,
+ 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()
View
2 sympy/combinatorics/tests/test_perm_groups.py
@@ -2,7 +2,7 @@
from sympy.combinatorics.group_constructs import DirectProduct
from sympy.combinatorics.named_groups import SymmetricGroup, CyclicGroup,\
DihedralGroup, AlternatingGroup, AbelianGroup
-from sympy.combinatorics.permutations import Permutation, _af_mul, cyclic
+from sympy.combinatorics.permutations import Permutation, _af_mul
from sympy.utilities.pytest import raises, skip, XFAIL
from sympy.combinatorics.generators import rubik_cube_generators
import random
View
10 sympy/combinatorics/tests/test_permutations.py
@@ -1,6 +1,6 @@
from sympy.core import FiniteSet
from sympy.combinatorics.permutations import (Permutation, _af_parity,
- _af_mul, _af_mul, cyclic, one_based)
+ _af_mul, _af_mul, full_cyclic_form0, cyclic_form1)
from sympy.utilities.pytest import raises
@@ -19,10 +19,10 @@ def test_Permutation():
assert _af_mul([2, 5, 1, 6, 3, 0, 4], [3, 1, 4, 5, 0, 6, 2]) == \
[6, 5, 3, 0, 2, 4, 1]
- assert cyclic([(2,3,5)], 5) == [[1, 2, 4], [0], [3]]
- assert cyclic([(2,3,5)], 3) == [[1, 2, 4], [0]]
- assert one_based([[0, 1], [2]], singletons=True) == [[1, 2], [3]]
- assert one_based([[0, 1], [2]], singletons=False) == [[1, 2]]
+ assert full_cyclic_form0([(2,3,5)], 5) == [[1, 2, 4], [0], [3]]
+ assert full_cyclic_form0([(2,3,5)], 3) == [[1, 2, 4], [0]]
+ assert cyclic_form1([[0, 1], [2]], singletons=True) == [[1, 2], [3]]
+ assert cyclic_form1([[0, 1], [2]], singletons=False) == [[1, 2]]
assert (Permutation([[1,2,3],[0,4]])*Permutation([[1,2,4],[0],[3]])).cyclic_form == \
[[0, 4, 2], [1, 3]]
assert q.array_form == [3, 1, 4, 5, 0, 6, 2]
View
56 sympy/combinatorics/tests/test_polyhedron.py
@@ -1,11 +1,16 @@
from sympy import symbols, FiniteSet
from sympy.combinatorics.polyhedron import (Polyhedron,
- tetrahedron, cube as square, octahedron, dodecahedron, icosahedron)
+ tetrahedron, cube as square, octahedron, dodecahedron, icosahedron, minlex,
+ cube_faces)
from sympy.combinatorics.permutations import Permutation
import random
-C1, C2, C3, C4, C5, C6, C7, C8, C9 = range(9)
+def test_minlex():
+ p = Permutation(range(3))
+ while p:
+ assert minlex(p.array_form) == (0, 1, 2)
+ p = p.next_lex()
def test_polyhedron():
pgroup = [Permutation([[0,7,2,5],[6,1,4,3]]),\
@@ -22,17 +27,13 @@ def test_polyhedron():
Permutation([[4,1],[0,5],[6,2],[7,3]]),\
Permutation([[7,2],[3,6],[0,4],[1,5]]),\
Permutation([0,1,2,3,4,5,6,7])]
-
- faces = ((C1,C8,C3,C6),(C1,C8,C2,C7),(C2,C5,C3,C8),
- (C2,C5,C4,C7),(C4,C7,C1,C6),(C3,C5,C4,C6))
-
-
corners = tuple(symbols('A:H'))
+ faces = cube_faces
cube = Polyhedron(corners, faces, pgroup)
- assert cube.size == 8
- assert cube.edges == FiniteSet(*[(C1, C6), (C1, C7), (C1, C8), (C2, C5), (C2, C7),
- (C2, C8), (C3, C5), (C3, C6), (C3, C8), (C4, C5), (C4, C6), (C4, C7)])
+ assert cube.edges == FiniteSet(*(
+ (0, 1), (6, 7), (1, 2), (5, 6), (0, 3), (2, 3),
+ (4, 7), (4, 5), (3, 7), (1, 5), (0, 4), (2, 6)))
for i in xrange(3): # add 180 degree face rotations
cube.rotate(cube.pgroups[i]**2)
@@ -46,6 +47,35 @@ def test_polyhedron():
assert cube.make_perm(5, seed=range(5)) == Permutation([4, 5, 7, 6, 0, 1, 3, 2])
assert cube.make_perm(7, seed=range(7)) == Permutation([5, 4, 6, 7, 1, 0, 2, 3])
- assert all(len(f) + len(v) - len(Polyhedron(v, f).edges) == 2
- for v, f in (tetrahedron, square, octahedron,
- dodecahedron, icosahedron))
+
+
+ def check(h, size, rpt, target):
+
+ assert len(h.faces) + len(h.vertices) - len(h.edges) == 2
+ assert h.size == size
+
+ got = set()
+ for p in h.pgroups:
+ # make sure it restores original
+ P = h.copy()
+ hit = P.corners
+ for i in range(rpt):
+ P.rotate(p)
+ if P.corners == hit:
+ break
+ else:
+ print 'error in permutation', p.array_form
+ for i in range(rpt):
+ P.rotate(p)
+ got.add(tuple(P.corners))
+ c = P.corners
+ f = [[c[i] for i in f] for f in P.faces]
+ assert h.faces == Polyhedron(c, f).faces
+ assert len(got) == target
+
+ for h, size, rpt, target in zip(
+ (tetrahedron, square, octahedron, dodecahedron, icosahedron),
+ (4, 8, 6, 20, 12),
+ (3, 4, 4, 5, 5),
+ (12, 24, 24, 60, 60)):
+ check(h, size, rpt, target)
View
2 sympy/core/basic.py
@@ -85,6 +85,8 @@ def __new__(cls, *args):
obj._args = args # all items in args must be Basic objects
return obj
+ def copy(self):
+ return self.func(*self.args)
def __reduce_ex__(self, proto):
""" Pickling support."""

0 comments on commit 052f6fe

Please sign in to comment.
Something went wrong with that request. Please try again.