Skip to content
This repository

SHADOWS #1508 - Don't commit #1498

Closed
wants to merge 218 commits into from
Christopher Smith
Collaborator

Combinatorics #531 overhauled

I'm leaving this PR open as a shadow of #1508 which is against 0.7.2. That is the one that should be committed.

Christopher Smith
Collaborator

I think the work on Polyhedron is ready to look at.

Julien Rioux jrioux commented on the diff August 19, 2012
sympy/combinatorics/polyhedron.py
((39 lines not shown))
  39
+        """
  40
+        The constructor of the Polyhedron group object.
  41
+
  42
+        It takes up to three parameters: the corners, faces, and
  43
+        allowed transformations.
  44
+
  45
+        The corners/vertices are entered as a list of arbitrary
  46
+        expressions that are used to identify each vertex.
  47
+
  48
+        The faces are entered as a list of tuples of indices; a tuple
  49
+        of indices identifies the vertices which define the face. They
  50
+        should be entered in a cw or ccw order; they will be standardized
  51
+        by reversal and rotation to be give the lowest lexical ordering.
  52
+        If no faces are given then no edges will be computed.
  53
+
  54
+            >>> from sympy.combinatorics.polyhedron import Polyhedron
3
Julien Rioux Collaborator
jrioux added a note August 19, 2012

No need to indent.

Christopher Smith Collaborator
smichr added a note August 19, 2012

I'm not to the proper examples, yet, and this is more parenthetical. Is it ok to leave it indented or do you still think it should dedent.

Julien Rioux Collaborator
jrioux added a note August 20, 2012

It's fine, I guess.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
sympy/combinatorics/polyhedron.py
((284 lines not shown))
  284
+            raise ValueError("Permutation size unequal to number of corners.")
  285
+        if len(set([a.size for a in pgroups])) > 1:
  286
+            raise ValueError("All permutations must be of the same size.")
  287
+        obj._pgroups = pgroups
  288
+        return obj
  289
+
  290
+    @property
  291
+    def corners(self):
  292
+        """
  293
+        Get the corners of the Polyhedron.
  294
+
  295
+        The method ``vertices`` is an alias for ``corners``.
  296
+
  297
+        Examples
  298
+        ========
  299
+        >>> from sympy.combinatorics import Polyhedron
1
Julien Rioux Collaborator
jrioux added a note August 19, 2012

There needs to be an empty line before the example.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Julien Rioux
Collaborator

Each time you have

Examples
========

it should be followed by an empty line, then the actual code example.

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request passes (merged ed988314 into 5569bb2).

Stefan Krastanov
Collaborator

SymPy Bot Summary: :eight_spoked_asterisk: All tests have passed.

Test command: setup.py test
master hash: 5569bb2
branch hash: ed98831

Interpreter 1: :eight_spoked_asterisk: All tests have passed.

Interpreter: /usr/local/bin/python2.5 (2.5.6-final-0)
Architecture: Linux (64-bit)
Cache: yes

Test results html report: http://reviews.sympy.org/report/agZzeW1weTNyDAsSBFRhc2sYirsjDA

Interpreter 2: :eight_spoked_asterisk: All tests have passed.

Interpreter: /usr/bin/python2.7 (2.7.3-candidate-2)
Architecture: Linux (64-bit)
Cache: yes

Test results html report: http://reviews.sympy.org/report/agZzeW1weTNyDAsSBFRhc2sYmNojDA

Interpreter 3: :eight_spoked_asterisk: All tests have passed.

Interpreter: /usr/bin/python3.2 (3.2.3-candidate-2)
Architecture: Linux (64-bit)
Cache: yes

Test results html report: http://reviews.sympy.org/report/agZzeW1weTNyDAsSBFRhc2sY8LYiDA

Build HTML Docs: :eight_spoked_asterisk: All tests have passed.

Docs build command: make html-errors
Sphinx version: 1.1.3

Test results html report: http://reviews.sympy.org/report/agZzeW1weTNyDAsSBFRhc2sYibsjDA

Automatic review by SymPy Bot.

Aleksandar Makelov

I see that some of the stuff concerning cyclic forms in permutations.py is modified here. I'm currently working on excluding singleton cycles from the cyclic form. My approach is the following: I add a _size attribute to the Permutation class, and then, when faced with something like Permutation([[2, 3], [4, 5, 6], [8]]), find the maximum index appearing in the permutation (here it's 8) and assign the size of the permutation to that + 1. Then it remains to adjust some of the other methods in the class (after I adjusted mul so that it treats permutations of different sizes as if they leave all points outside their domain fixed, all the tests passed) so that they make sense with that new approach to cyclic forms. Is that going to be harmful to this PR?

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request fails (merged c46c2bb5 into 5569bb2).

Christopher Smith
Collaborator

I see that some of the stuff concerning cyclic forms in permutations.py is modified here. I'm currently working on excluding singleton cycles from the cyclic form. My approach is the following: I add a _size attribute to the Permutation class, and then, when faced with something like Permutation([[2, 3], [4, 5, 6], [8]]), find the maximum index appearing in the permutation (here it's 8) and assign the size of the permutation to that + 1.

I thought of this, too, but the problem is that you don't know if they left out higher singletons (e.g. should [9] be in the permutation?)

Then it remains to adjust some of the other methods in the class (after I adjusted mul so that it treats permutations of different sizes as if they leave all points outside their domain fixed, all the tests passed) so that they make sense with that new approach to cyclic forms. Is that going to be harmful to this PR?

If you want to exclude them in the returned value of cyclic_form you can use the method reduced_cyclic_form.

If you have a 1-based cyclic_form you can use the function cyclic(cycle_form, n) to fill it out with singletons. I think I will modify it so you can optionally not subtract 1 from each element.

I wouldn't have been able to even talk about this 2 days ago, but I did a lot to combinaatorics over the past few days, so if you want to discuss this more it would be helpful.

Christopher Smith
Collaborator

OK, so now you can convert a 0-based cyclic form into a 1-based cyclic form with or without singletons by using the one_based() function.

1-based -> 0-based-full with cyclic
0-based-full -> reduced-0-based-full with reduced_cyclic_form
0-based -> 1-based (full or reduced) with one_based.

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request passes (merged 0c94e217 into 5569bb2).

Aleksandar Makelov

@smichr : the problem with higher singletons can be fixed in one of two ways:

  • as in my previous comment. We'll just have to make the functions treating two possibly different permutation allow different sizes. Additionally, we can supply an optional argument to the constructor that specifies the size of the permutation, something like a = Permutation([[2, 3, 4]], 20)
  • more ambitious: make a new class, ExtendedArrayForm or something, with a field _array_form that holds the usual array form of a permutation. Then we overload the __getitem__ method so that if the index is outside the bounds of self._array_form we return the index unchanged. Of course, we'll have to overload other things, like the __len__ and __str__ to make it behave like a list. Then instead of using a list to initialize the array form of a permutation, we use the corresponding ExtendedArrayForm. This will make all permutations behave as if they are acting on a practically infinite domain, and if we do it that way, we won't have to make any changes to the methods in Permutation - everything is going to work as expected, no casework like if len(a) > len(b),... will be needed. So this sounds like a rather elegant approach. On the other hand, I'm not entirely sure if it is possible to make it completely like a list, and also it doesn't seem like a very performance-efficient decision since ExtendedArrayForm instances will be created all the time.

And by the way, are we going to switch to 1-based form only? It's going to be hard and make the code uglier than it is right now; also, is it a good idea to have two standards for representing permutations -- isn't that going to get confusing?

Julien Rioux
Collaborator

While building docs:
Warning, treated as error:
doc/src/modules/combinatorics/permutations.rst:11: WARNING: autodoc can't import/find method 'sympy.combinatorics.permutations.perm_af_parity', it reported error: "perm_af_parity", please check your spelling and sys.path

Christopher Smith
Collaborator

@jrioux , I got the sphinx working here and can check my own work now. The wrapping of the first See Also in partitions looks bad, however, as it appears to be trying to fill the paragraph instead of using ragged-right filling. And I added the LatticeOps change here to see that it would work in tests but will rebase this out once your request is in.

Christopher Smith smichr closed this August 22, 2012
Christopher Smith smichr reopened this August 23, 2012
Christopher Smith
Collaborator

I did a total overhaul on #531. There are some other issues that were addressed along the way (e.g. quick_sort for LatticeOps args and dealing with evalf(1)) since these were causing test failures. I have already reviewed @saptman 's work but now need someone to look over the changes that I've made.

Christopher Smith
Collaborator

@certik , you asked @saptman about whether this could be finalized...I worked with him quite a bit in review and discussion and so felt that I could do the final touches. It ended up being a lot more than that! (And I learned a lot in the process.) Perhaps you would have a chance to look this over?

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request passes (merged f73cd8a1 into 333ca3a).

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request passes (merged b86464d8 into a184841).

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request passes (merged 4b001a71 into 333ca3a).

Christopher Smith
Collaborator

I'll close this here in favor of getting it in with 0.7.2 (#1508)

Christopher Smith smichr closed this August 23, 2012
Christopher Smith smichr reopened this August 30, 2012
Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request passes (merged d0ed468f into d208118).

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request passes (merged e04e85e3 into d208118).

david joyner

Is it possible to easily change the default printing of the elements of a perm gp to be in disjoint cycle notation?

If not, is is possible to describe in the docstring of perm gp exactly what the notation is. As I explained on the sympy list, group-theorists using this will expect disjoint cycle notation.

Is is possible to add lots more examples (eg, with the Rubik's cube group, etc) where the disjoint cycle notation is used to define a perm gp and then do lots of computations with it? For example, something like

F = Permutation([(17,19,24,22),(18,21,23,20),( 6,25,43,16),( 7,28,42,13),( 8,30,41,11)], size=49)
B = Permutation([(33,35,40,38),(34,37,39,36),( 3, 9,46,32),( 2,12,47,29),( 1,14,48,27)], size=49)
L = Permutation([( 9,11,16,14),(10,13,15,12),( 1,17,41,40),( 4,20,44,37),( 6,22,46,35)], size=49)
R = Permutation([ (25,27,32,30),(26,29,31,28),( 3,38,43,19),( 5,36,45,21),( 8,33,48,24)], size=49)
U = Permutation([ ( 1, 3, 8, 6),( 2, 5, 7, 4),( 9,33,25,17),(10,34,26,18),(11,35,27,19)], size=49)
D = Permutation([ (41,43,48,46),(42,45,47,44),(14,22,30,38),(15,23,31,39),(16,24,32,40)], size=49)
G = PermutationGroup([F,B,L,R,U,D])
G.order()
43252003274489856000

Generally, IMHO it seems to me that the documentation is minimal.

Sorry to seem so critical. This is a great contribution to sympy by Aleksander and Chris!

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request passes (merged a4c1bef1 into d208118).

Christopher Smith
Collaborator
david joyner
Christopher Smith
Collaborator
Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request passes (merged a1ab0336 into d208118).

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request passes (merged dd2c0434 into d208118).

david joyner

This is much better now and, in my opinion, ready to go in.
Thanks Chris!

Christopher Smith
Collaborator

There is now a global flag that controls output:

>>> a = Permutation([[1,2],[5,3]])
>>> a
Cycle(1, 2)(3, 5)
>>> isinstance(_, Permutation)
True
>>> Cycle(a)
[(1, 2), (3, 5)]
>>> Permutation.print_cyclic = False
>>> a
Permutation([0, 2, 1, 5, 4, 3])

So when you see Permutation or Cycle you know you are working with a
Permutation instance printing in two different ways. This is maybe a bad
idea since copying and pasting Cycle(1, 2)(3, 5) will not give a
Permutation, it will give a Cycle.

I got rid of the __mul__ method for cycle so only the Cycle(1, 2)(2, 3)
sort of notation is allowed (not Cycle(1, 2)*(2,3)).

The problem with the global flag is that now doctests have to explicitly
set the flag or else a previous test with the flag off will affect another
test that things that the flag is on (because that's what the default is).

I've got to check that all the PermutationGroups calculate properly when
they get permutations in cycle form.

Christopher Smith
Collaborator

Should coset_decomposition fail if the input permutation is shorter than those in the PermutationGroup?


        >>> from sympy.combinatorics import Permutation, Cycle
        >>> Permutation.print_cyclic = True
        >>> from sympy.combinatorics.perm_groups import PermutationGroup
        >>> a = Permutation([[0, 1, 3, 7, 6, 4], [2, 5]])
        >>> b = Permutation([[0, 1, 3, 2], [4, 5, 7, 6]])
        >>> G = PermutationGroup([a, b])

        >>> c = Permutation([[2, 4], [3, 5]])
        >>> c.array_form
        [0, 1, 4, 5, 2, 3, 6, 7]
        >>> G.has_element(c)
        True
        >>> G.coset_decomposition(c)
        [[0, 1, 2, 3, 4, 5, 6, 7],
         [0, 1, 2, 3, 4, 5, 6, 7],
         [0, 1, 4, 5, 2, 3, 6, 7]]
        >>> Permutation.lmul(*[Permutation(p) for p in _]) == c
        True

This succeeds because the routine now adjusts input c to have the same length as the group and the result compares == because __eq__ ignores trivial tails of permutations (i.e. Permutation([1, 0, 3, 4, 5]) == Permutation([1, 0])). Does this seem right, David?

Aaron Meurer
Owner

Yes. We could make the default printing for all permutations to be the
cyclic_form. I know we used to have a flag for how polys were printed...I
thought we got rid of that and I don't recall why. Can you comment, Aaron?

Are you talking about the order keyword, because that still exists?

Christopher Smith
Collaborator

I think I have a sane method of representation for disjoint cycle and array forms. If you look at the docstring for Permutation i try to lay it out clearly.

Christopher Smith
Collaborator

about the order keyword

Yes...I never use it and I know that Mateusz stripped something out at one point. Thanks for clarifying.

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request fails (merged 4b81be1f into d208118).

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request fails (merged 17d12a16 into d208118).

david joyner
Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request passes (merged 22607286 into d208118).

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request passes (merged a113079f into d208118).

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request fails (merged 79498c27 into d208118).

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request passes (merged 8bfba19c into d208118).

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request passes (merged 533d41ee into d208118).

Christopher Smith
Collaborator

Does it makes sense to allow duplicate permutations in a PermutationGroup? I'm thinking not, and have made the changes accordingly.

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request fails (merged 17203029 into d208118).

Don't Add Me To Your Organization a.k.a The Travis Bot

This pull request fails (merged fdee9636 into d208118).

david joyner
pernici

_af_mul is slower than perm_af_muln previously defined; on my computer computing the order of
the Rubik cube takes 1.84s using _af_mul; using the code of perm_af_muln it takes 1.6s, and taking away
the check that Permutations have the same size, as in _af_mul in this PR (which does not seem to me to be
a good idea), it takes 1.54s; in particular _af_mul takes half the time as the one in this PR.

pernici
    def __mul__(self, other):
        """
        Routine for multiplication of permutations following R to L order.

        Note
        ====

        a*b*c applies permutations in order c, b, a which is consistent with
        function notation abc(x) meaning a(b(c(x))).

I do not think this is correct; it is lmul which is consistent with the function notation

For instance

>>> from sympy.combinatorics import Permutation
>>> Permutation.print_cyclic = False
>>> p = Permutation([1, 2, 3, 0])
>>> q = Permutation([3, 2, 0, 1])
>>> Permutation.lmul(p, q)
Permutation([0, 3, 1, 2])
>>> [p.array_form[q.array_form[i]] for i in range(4)]              # p(q(x))
[0, 3, 1, 2]
>>> p*q
Permutation([2, 0, 1])

p*q is consistent with the exponential notation `x**(p*q) = (x**p)**q

Christopher Smith
Collaborator

oops, you have to escape math or else the ** gets interpreted as bold.

Regarding L to R or R to L, we can ask "did p get applied
to q or vice versa. If p gets applied to q we take position 1 from q (which is 2)
then position 2 from q (0), etc... to obtain [2, 0, 1, 3]. This is R to L
order. If q gets applied to p then that is L to R order (which is what lmul
does. If you still think I am incorrect about this, please let me know. It took a long
time to convince myself of the order (and thinking about 3 permutations
rather than 2 helped to clarify the issue).

>>> p = Permutation([1, 2, 3, 0])
>>> q = Permutation([3, 2, 0, 1])
>>> r = Permutation([3, 1, 0, 2])
>>> p*q*r
Permutation(1, 3, 2)
>>> r*q*p
Permutation(0, 2)(1, 3)
>>> Permutation.lmul(p,q,r)
Permutation(0, 2)(1, 3)

p*q*r will apply q to r then p to that result whereas lmul(p, q, r) applies
q to *p* then r to that result: permutation are applied in the order
listed, from left to right, and so it is called lmul.

If you write [a[i] for i in b] you are applying b to a so

[p.array_form[q.array_form[i]] for i in range(4)]              # p(q(x))

is applying q to p: q's elements are selcting p's elements, so I would write q(p) (and I would write the code as

[P.array_form(qi) for qi in q.array_form]
Christopher Smith
Collaborator

@asmeurer and all others. I think this is ready to go. I only wish I could discuss groups and cosets better. Also, there is the issue about the possible name change for coset_repr -> coset_decomposition and coset_decomposition->coset_factor. @wdjoyner or @pernici or @amakelov , do you have feedback about that name change?

Christopher Smith
Collaborator

@pernici , I split _af_mul into _af_muln -- this should restore the performance.

Christopher Smith
Collaborator

One further question: should we get rid of the space between elements so Permutation(1, 2, 3) shows as Permutation(1,2,3)?

david joyner
david joyner
Christopher Smith
Collaborator
Christopher Smith
Collaborator
pernici

I split _af_mul into _af_muln -- this should restore the performance.

No, it does not; computing the Rubik cube order takes the same time as before.
_af_muln with 7 arguments makes 6 lists instead of one; using master only one list is made;
this is why it is faster.

david joyner
pernici

In the documentation of __mul__ it is written

        a*b*c applies permutations in order c, b, a which is consistent with
        function notation abc(x) meaning a(b(c(x))).

This is wrong; I quote here Bachmann in https://groups.google.com/forum/?fromgroups=#!topic/sympy/4ZzZxFbRIAo

Let us fix a set X we are considering the permutation group of, below I
will take X = {1, 2, 3, 4, 5}. A permutation of X is by definition a
bijective function f:X->X. It is specified uniquely by providing the
image of every element. We can write this in the short form
[f(1), f(2), f(3), f(4), f(5)]. In this way, every permutation is
represented by an array of constant size.
...

Now let's consider composition. There are two schools of thought. Let me
write * for "ordinary" (where I come from) composition, and . for
"weird" composition. By definition, if f, g are permutations, then the
permutation f*g is the unique mapping such that (f*g)(x) = f(g(x))
["apply right to left"], whereas (f.g)(x) = g(f(x)) ["apply left to
right"]. [*]

[] Note that this can be made to look more sensible (for some
definitions of sensible), by writing *arguments
on the left: applying f
to x can be written as (x)f, and then (x)(f.g) = ((x)f)g ...
<\quote>

(x)f is sometimes called exponential notation x**f.
This is the convention used in this PR.

pernici

In the example you give

```>>> from sympy.combinatorics import Permutation

Permutation.print_cyclic = False
p = Permutation([1, 2, 3, 0])
q = Permutation([3, 2, 0, 1])
r = Permutation([3, 1, 0, 2])
p*q*r
Permutation([0, 3, 1, 2])
r*q*p
Permutation([2, 3, 0, 1])
[p.array_form[q.array_form[r.array_form[i]]] for i in range(4)]
[2, 3, 0, 1]

(x)(p*q*r) = (p(x))(q*r) = (q(p(x)))**r = r(q(p(x)))

r(q(p(x))) is given by

>>> [r.array_form[q.array_form[p.array_form[i]]] for i in range(4)]
[0, 3, 1, 2]

You write

p*q*r will apply q to r then p to that result whereas lmul(p, q, r) applies
q to p then r to that result: permutation are applied in the order
listed, from left to right, and so it is called lmu

I do not think it is a good terminology to say that q is applied to r; q is applied to i in [0,1,..,n-1]
not to another permutation; at least in the sense of p*q, one can apply it to q as p**q == p.conjugate(q).

I think that the definition of p.conjugate(q) should be ~q*p*q, not as defined in the code, since

((x)p)q = (x)p*q = (x)q*~q*p*q = (x)q*p.conjugate(q)

pernici

I do not think matrix_form is right; it is the Cauchy two-line form, so that

>>> a = Permutation([2, 0, 3, 1])
>>> a.matrix_form
[0, 1, 2, 3]
[2, 0, 3, 1]

not [1, 3, 0, 2].

pernici

In the dostring of Permutation it is written

Any permutation can be represented as a set of transpositions

it should be as a sequence of transpositions, since the order matters.

Christopher Smith
Collaborator
Christopher Smith
Collaborator
david joyner
Christopher Smith
Collaborator

regarding the terminology for multiplication:

Do you have a recommendation for how to say this? Is "r selects from q and
the result selects from p" for p*q*r better?

Regarding mul and lmul. I could very well be wrong about the terminology
being used but this much is sure:

The code that uses lmul is applying permutations in the opposite order of
__mul__. So whatever order we describe for a*b*c, the opposite applies
to lmul(a, b, c).

Christopher Smith
Collaborator

array_form is already taken for the explicit permutation so cauchy_form would be better.

Christopher Smith
Collaborator

OK, _af_mul is almost back to master...I don't like the recursive call, though...how is the performance now?

pernici

OK, _af_mul is almost back to master...I don't like the recursive call, though...how is the performance now?

It is fine for the Rubik cube, since there are at most products of 7 permutations; for more than 8 permutations
it is still slow without the recursion; why do you not like it?

pernici

In http://www.sagemath.org/doc/reference/sage/combinat/permutation.html
multiplication is done by default from left to right 'l2r' (like in GAP)

mult: ‘l2r’ - the multiplication of permutations is done like
composition of functions from left to right.
That is, if we think of the permutations p1 and p2 as functions,
then (p1*p2)(x) = p2(p1(x)). This is the default in multiplication in GAP.

‘r2l’ - the multiplication of permutations is done right to left so that (p1*p2)(x) = p1(p2(x))

Maybe we can use a similar terminology:
'l2r' L to R convention
'r2l' R to L convention

so that __mul__ satisfies the L to R convention
lmul satisfies the R to L convention

Example:

>>> from sympy.combinatorics import Permutation
>>> p = Permutation([1, 2, 3, 0])
>>> q = Permutation([3, 2, 0, 1])
>>> r = Permutation([3, 1, 0, 2])
>>> for i in range(4):
...     assert Permutation.lmul(p,q,r)(i) == p(q(r(i)))
...     assert (p*q*r)(i) == r(q(p(i)))
...
>>>

In the following I suggest changes concerning multiplication convention

def _af_mul(a, b):
    """
    Product of two permutations in array form, following the
-    L to R convention: given args A and B, B is applied to A.
+   R to L convention:  _af_mul(a, b)[i] = a[b[i]]

def _af_muln(*a, **kwargs):
    """
    Product of two or more permutations in array form, following the
-   L to R convention: given args [A, B, C], B is applied to A and
-   then C is applied to the result.
+   R to L convention:   _af_mul(a, b, c)[i] = a[b[c[i]]]

In the docstring of Permutation

-    The product of two permutations p and q is defined as their composition as
-    functions, (p*q)(i) = p(q(i)) [6]_.

+    The product of two permutations p and q is defined using the
+    L to R convention (p*q)(i) = q(p(i)); (p*q*r)(i) = r(q(p(i)))

    @staticmethod
    def lmul(*args):
        """
-        Return product of permutations following L to R order.
-        Given lmul(A, B, C), A is applied to B and that result
-        is applied to C. This is the opposite of A*B*C which
-        applies B to C then applies A to that result.

+        Return product of permutations following R to L order
+        Permutation.lmul(A, B, C)(i) == A*B(C(i)))

    P*foo was changed to lmul(P, foo):

maybe foo*P ? I do not understand. Is this line necessary?

    def __mul__(self, other):
        """
-        Routine for multiplication of permutations following R to L order.
+        Routine for multiplication of permutations following L to R order.

        Note
        ====

-        a*b*c applies permutations in order c, b, a which is consistent with
-        function notation abc(x) meaning a(b(c(x))).

+        (a*b*c)(x) means c(b(a(x)))

maybe transpositions should return the cycles in opposite order,
so that their product (not the lmul product) is equal to the permutation?

    def conjugate(self, x):
        """
-       Computes the conjugate Permutation ``x*p*~x``
+       Computes the conjugate Permutation ``~x*p*x`
Christopher Smith
Collaborator
Christopher Smith
Collaborator
Sergiu Ivanov immutablematrices.rst: Doctest the TypeError.
This commit makes the doctest in the said file actually test the raising
of ``TypeError``.
98a3f3f
Christopher Smith
Collaborator

@pernici , what do you think about the re-written docstrings for the different mul methods?

I've added ^ as an operator for conjugate -- does that seem ok to you guys?

Interestingly, this whole PR was named something like "allow permutation to be indexed". I never implemented that because it is ambiguous whether p[2] should give element at index 2 or the 2nd ranked permutation. The former is already implemented by __call__ and the latter depends on what type of ranking scheme one uses, so __getitem__ was never defined.

@pernici , do you want this to go in first or do you want yours to go in and then I rebase over it?

pernici

_af_rmuln is still slow, compared to perm_af_muln; adding the latter here

In [1]: from sympy.combinatorics.permutations import Permutation, _af_rmuln, perm_af_muln

In [2]: a = [Permutation.unrank_lex(500, i).array_form for i in range(10)]

In [3]: timeit _af_rmuln(*a)
1000 loops, best of 3: 626 us per loop

In [4]: timeit perm_af_muln(*a)
1000 loops, best of 3: 188 us per loop
pernici

In the Cycle doctest

        >>> a = C(1, 2)
-       >>> print a(2, 3)
+       >>> a(2, 3)

In the Permutation docstring what does the following mean?

 If you choose to number items
    starting from 1 (and thus enter the permutation as [1, 2, 4, 3]) SymPy
    will pretend that the 0th element was not moved and store the permutation
    as [0, 1, 2, 4, 3].

I do not undestand the following, since (1, 2)(1, 3)(2, 3) is not a
disjoint cycle product

    It also provides some economy in entry when computing products of
    permutations that are written in disjoint cycle notation:

    >>> Permutation(1, 2)(1, 3)(2, 3)
    Permutation([0, 3, 2, 1])
    >>> _ == Permutation([[1, 2]])*Permutation([[1, 3]])*Permutation([[2, 3]])
    True

In the Permutation doctest I would take away the paragraphs on
Cauchy Matrix Notation and 2-Line Notation and Matrix Notation;
cauchy_form is still wrong, it is not the Cauchy 2-line notation;
I suggest take it away.

pernici
    The permutation can act as a bijective function, telling what element is
    located at a given position

    >>> p.array_form
    [1, 0, 2, 3]
    >>> p.array_form.index(1) # the hard way
    0
    >>> p(1) # the easy way
    0

This is wrong; here is a counterexample

>>> p = Permutation([5,2,3,4,1,0])
>>> p.array_form.index(1)
4
>>> p(1)
2
pernici
The product of two permutations p and q is defined as their composition as
functions, (p*q)(i) = p(q(i)) [6]_.

This is still wrong; the correct expression is (p*q)(i) = q(p(i))
In the example which follows that statement, q commutes with p so that it is not a good example;
here is a possible replacement

>>> p = Permutation([1, 0, 2, 3])
>>> q = Permutation([2, 3, 1, 0])
>>> list(p*q)
[3, 2, 1, 0]
>>> [q(p(i)) for i in range(p.size)]
[3, 2, 1, 0]
Matthew Rocklin Update immutablematrix.__setitem__ error message
Now points user to use the Matrix class for this case.
a2c5418
Aaron Meurer
Owner

Check that ^ has the right precedence for what you want.

Christopher Smith
Collaborator

q(p(i))

I made that change - thanks for the example, too. I had caught that commuting pair elsewhere but not here.

check ^ precedence

>>> p = Permutation([1, 0, 2, 3])
>>> q = Permutation([2, 3, 1, 0])
>>> p^q==p.conjugate(q)
True
>>> p^q != q^p
True
Christopher Smith
Collaborator

.index(1)

.index(1) is replaced with [1] and the example you gave has been used.

Christopher Smith
Collaborator

print C

the print has been removed

take it away

The docstring and function for cauchy_form have been removed.

Christopher Smith
Collaborator

what does the following mean

I removed that and just left it at "Python is 0-based". It means that if you type Permutation(1,2) you are swapping positions 1 and 2 since SymPy is assuming that the array form starts at 0.

I do not undestand the following, since (1, 2)(1, 3)(2, 3) is not a
disjoint cycle product

It is just a product of disjont cycles (in this case a series of transpositions). is there something to make clearer yet?

Christopher Smith smichr referenced this pull request September 07, 2012
Closed

0.7.2 Release #1507

Christopher Smith
Collaborator

_af_rmul is slow

OK, I restored the original form. My only concern is that I don't see why this is being broken down in a binary way instead of just being handled in 7 piece chunks at a time.

pernici

It is just a product of disjoint cycles (in this case a series of transpositions). is there something to make clearer yet?

It if fine.

Aaron Meurer
Owner

No, what I meant is that a^b*c is going to be interpreted as a^(b*c). Is this OK? Note that this is the opposite of how ** would be interpreted.

pernici

a^b*c = a^(b*c) seems to me to be OK.
However if the rule is a^b^c = a^(b^c)
then a^b^c = b*c*~b*a*(b*~c*~b) which has no meaning, while
(a^b)^c = c*(b*a*~b)*~c = a^(c*b) makes sense, in fact defining R(x)y = y^x = x*y*~x one gets
R(c)R(b)a = R(c*b)a

david joyner
Ronan Lamy Move int_tested to the core and refactor it.
* Move int_tested() to sympy.core.compatibility, to make it
  importable anywhere.
* Simplify it to take only a single argument, like int().
* Rename it as_int().
eb6e9da
david joyner
pernici

To have (a.conjugate(b)).conjugate(c) = a.conjugate(b*c) it should be a.conjugate(b) = ~b*a*b
while currently a.conjugate(b) = b*a*~b leading to (a.conjugate(b)).conjugate(c) = a.conjugate(c*b)
In the first case R(x)y = x.conjugate(y) gives R(c)R(b)a = R(b*c)a, in the second case R(c)R(b)a = R(c*b)a;
since the second case is an homomorphism it seems nicer.

I cannot find which are the precedence rules in Python for __xor__;
is a^b^c equal to (a^b)^c or a^(b^c) or it is not defined?

The following example shows that if it is defined, it is a^b^c =(a^b)^c`

class A:
  def __init__(self, a):
    self.a = a

  def __str__(self):
    return str(self.a)

  def __xor__(self, other):
    return A('(%s^%s)' % (self.a, other.a))

a = A('a')
b = A('b')
c = A('c')

print a^b^c   # prints ((a^b)^c)

If it is so, it has the same precedence rule as conjugate.

Aaron Meurer
Owner

I believe all binary operators in Python associate from the left, with the exception of **.

Christopher Smith
Collaborator

On Sat, Sep 8, 2012 at 12:57 AM, pernici notifications@github.com wrote:
a^b*c = a^(b*c) seems to me to be OK.
However if the rule is a^b^c = a^(b^c)
then a^b^c = b*c*~b*a*(b*~c*~b) which has no meaning, while
(a^b)^c = c*(b*a*~b)~c = a^(c*b) makes sense, in fact defining R(x)y = y^x = x*y~x one gets

It is left binding as Aaron has said:

>>> q^p^r
Permutation(1, 2)
>>> q^(p^r)
Permutation(2)(0, 1)
>>> (q^p)^r
Permutation(1, 2)
>>> q,p,r
(Permutation(2)(0, 1), Permutation(2), Permutation(0, 2))
Christopher Smith
Collaborator

So is everything ok with the conjugate operator? (And nice demo with classes, @pernici)

Christopher Smith Merge pull request #1526 from rlamy/int_tested
Move int_tested to the core and refactor it.
a0e2c05
pernici

wdjoyner wrote

I think conjugation should be defined so that (a.conjugate(b)).conjugate(c) = a.conjugate(b*c) and (a^b)^c = a^(bc)

With the current definition a.conjugate(b) = b*a*~b one has instead (a^b)^c = a^(c*b)

>>> from sympy.combinatorics import Permutation
>>> q= Permutation(6, 9, 8)
>>> p= Permutation(6, 9)
>>> r= Permutation(6, 9, 7, 8)
>>> q^p^r
Permutation(9)(6, 8, 7)
>>> q^(p*r)
Permutation(7, 8, 9)
>>> q^(r*p)
Permutation(9)(6, 8, 7)

I suspect that Joyner is right;
I wrote before that currently a.conjugate(b) = b*a*~b leading to (a.conjugate(b)).conjugate(c) = a.conjugate(c*b)
and that definingR(x)y = x.conjugate(y) one gets
R(c)R(b)a = R(c*b)a;
this is how usually homomorphisms are defined, but R(c)R(b) is a product of application defined in the
usual order, while c*b is the permutation product defined in the standard (crazy, in my opinion) way,
so a homomorphism is R(c)R(b) = R(b*c).

Another argument is that it should be, using the notation x -> (x)p
((x)p)q = (x)p*q = (x)q*~q*p*q = (x)q*p.conjugate(q) so p.conjugate(q) = ~q*p*q

Therefore the correct definition of conjugate is a.conjugate(b) = ~b*a*b leading to (a^b)^c = a^(b*c)

Another issue:
is there a problem in using ^ for conjugate when SymPy is called in Sage, were ^ is the exponential operator,
with different precedence rules?

Christopher Smith
Collaborator

Therefore the correct definition of conjugate is a.conjugate(b) = ~b*a*b

If a.conjugate(b) is defined as ~a*b*a then the following will not hold (just quoting from the docstring; I don't know how things should be):

        >>> p = Permutation([2,0,3,1])
        >>> q = Permutation([1,0,3,2])
        >>> r = Permutation([0,2,3,1])
        >>> p**4
        Permutation([0, 1, 2, 3])
        >>> p**q == p.conjugate(q)
        True
        >>> q**p == q.conjugate(p)
        True
        >>> (p**q)**r == p**(r*q)
        True

I agree with @pernici that the way we have the __mul__ defined right now is very confusing. I just read www.neiu.edu/~bhdayton/permutations.pdf where it says "when we write gf it means we do f first and g after" but in sympy we would have to type this as f*q and that's terrible. Let's get this settled. If standard notation for g*f in permutations means "f first and g next" then we have to reverse mul so we can just write that. So...is __mul__ backward right now?

pernici

p**q has the wrong precedence,
in the sense that p**q**r = p**(q**r)
using p**q = p.conjugate(q) has no particular meaning;
therefore conjugate should be taken away from __pow__.

In www.neiu.edu/~bhdayton/permutations.pdf it is used the same convention
for permutations as in master; the convention used in this PR is
the standard group theory software, in particular it is the one used in GAP,
and by default in Sage; it is also used by most books on permutations.

I think this is the reason why __mul__ has been redefined in this PR.

For instance in Holt,Eick,O'Brein
"Handbook of Computational Group Theory", from which I quote:

For x in \Omega and g in Sym(\Omega), we shall denote the result of applying
g to x by x^g rather than by the more usual g(x).
The composite gh will mean "first apply g, then apply h", and so
x^(gh)=(x^g)^h.

To be precise I wrote in the above x^g for what is visualized
by latex $x^{g}$. This is what I wrote as (x)g in the previous post,
with ((x)p)q = (x)p*q = (x)q*~q*p*q = (x)q*p.conjugate(q).

Using '^' this equation becomes
x^p^q = (x^p)^q = x^q*p^q defining p^q = p.conjugate(q) = ~q*p*q

One can introduce also x^p, where x is an integer
or a list of elements, using __rxor__;

Here is an example, after redefining p.conjugate(q) = ~q*p*q
and (to be improved)

    def __rxor__(self, x):
        if int(x) == x:
            return self(x)
        else:
            raise NotImplementedError
>>> from sympy.combinatorics import Permutation
>>> p = Permutation(1, 2, 9)
>>> q = Permutation(6, 9, 8)
>>> r = Permutation(9)(4,6,8)
>>> q^p^r
Permutation(9)(1, 4, 8)
>>> (q^p)^r
Permutation(9)(1, 4, 8)
>>> q^(p*r)
Permutation(9)(1, 4, 8)
>>> 2^p
9
>>> 2^p^q
8
>>> 2^(p*q)
8


sage -gap
> p := (2,3,10);
> q := (7,10,9);
> r := (5,7,9);
gap> q^p^r;
Syntax error: '^' is not associative
> (q^p)^r;
(2,5,9)
gap> 3^p;
10
gap> (3^p)^q;
9
gap> 3^(p*q);
9

Notice that in GAP one must specify the parenthesis (q^p)^r

Christopher Smith
Collaborator

@pernici , could you just make a pull request against this PR implementing the changes?

pernici

could you tell me the procedure to make a pull request against this PR?

Christopher Smith
Collaborator

It's just like making a regular pull request except after you press the pull request button you must change the branch against which you want it applied. The default is sympy master. Just select from the list smichr (base repo) and combinatorics (base branch) then continue as usual.

pernici

Thanks; I have another question about this.
Currently to get your branch combinatorics I download the zipped branch each time; since this is done out
of my git repository, to do a pull request out of it I have to copy the files I am interested in in a branch of mine,
make the changes and then do the pull request; this is messy.
There is surely a way to get your branch in my repository. I guess that it is roughly

git remote add smichr https://github.com/smichr/sympy
git fetch smichr
git checkout smichr/combinatorics

but I do not dare to do that because I am afraid I would get all your ( > 600) branches in my repository,
which would make the command git branch unreadable, and I do not know what happens if a branch of
yours has the same name as one of mine; besides, 600 branches would take a lot of memory.

Can you tell me if the above commands are correct and that what I am afraid of does not happen?

Matthew Brett

There is surely a way to get your branch in my repository. I guess that it is roughly

git remote add smichr https://github.com/smichr/sympy
git fetch smichr
git checkout smichr/combinatorics

The last would more likely be something like:

git checkout -b my-combinatorics smichr/combinatorics

but I do not dare to do that because I am afraid I would get all your ( > 600) branches in my repository,
which would make the command git branch unreadable,

Well, git branch -a would show all of smichr's branches, but not
git branch`

and I do not know what happens if a branch of
yours has the same name as one of mine;

smichr's branches only appear as 'remote' branches, with prefix
'smichr/' so they won't clash with yours. So, if you have a
'my-fixes' branch, which perhaps you push to your own github repo,
meaning you have a remote branch `origin/my-fixes' - there would be no
clash with 'smichr/my-fixes' - for example.

besides, 600 branches would take a lot of memory.

Don't forget that a branch is just a pointer to a commit. The amount
of disk space taken up by the fetch, over and above the sympy original
checkout, is the amount of code that is in smichr's branches and not
in the sympy original checkout branches, and that's likely to be a
relatively small amount, because a lot of it will have been merged
over time.

pernici

Thanks!

Christopher Smith
Collaborator

@wdjoyner last commented that he thought this was ready to go. I took off the __xor__ commit so that can be settled out as a new PR. I also rewrote the docstring for commutator to accurately reflect what it returns.

This then, as far as I am concerned, is ready to go but should be committed from #1508, not here. @pernici , do you have any estimate of how long it will take to resolve the conjugate issue? I would imagine this would be an important change to have be part of 0.7.2 if there is a change in what it returns.

Christopher Smith
Collaborator

git checkout -b my-combinatorics smichr/combinatorics

Or, realizing that "Namespaces are one honking great idea -- let's do more
of those!" (last line from "import this") you don't have to try avoid a
clash with the "my-" prefix.

git checkout -b combinatorics smichr/combinatorics

is fine, too.

pernici

do you have any estimate of how long it will take to resolve the conjugate issue?

I have made a pull request for it.

Christopher Smith Merge pull request #1528 from jrioux/documentation
Fix Sphinx doc failure in 0.7.2 branch.
9f56be7
pernici

I have the smichr/combinatorics in my repository; how do I update it to the last changes you made?

Julien Rioux
Collaborator

git fetch smichr

Christopher Smith
Collaborator
and others added some commits October 18, 2011
Saptarshi Mandal combinatorics/permutations: Made the permutation object indexable.
Signed-off-by: Saptarshi Mandal <sapta.iitkgp@gmail.com>
ce5d49c
Saptarshi Mandal combinatorics/polyhedron: Added a Polyhedron class.
Signed-off-by: Saptarshi Mandal <sapta.iitkgp@gmail.com>
eedb639
Saptarshi Mandal combinatorics/polyhedron: Added tests for Polyhedron.
Signed-off-by: Saptarshi Mandal <sapta.iitkgp@gmail.com>
0688428
Saptarshi Mandal combinatorics/polyhedron: Added tests for make_perm.
Signed-off-by: Saptarshi Mandal <sapta.iitkgp@gmail.com>
e9f04f4
Saptarshi Mandal combinatorics/polyhedron: Fixed the doctest to make things a bit
more clear.

Signed-off-by: Saptarshi Mandal <sapta.iitkgp@gmail.com>
f94b1bd
Saptarshi Mandal combinatorics/polyhedron: Made the test code a bit more
streamlined.

We use a set in edge list construction.

Fixed some doctests comments.

Signed-off-by: Saptarshi Mandal <sapta.iitkgp@gmail.com>
1642d44
Saptarshi Mandal combinatorics/polyhedron: Made the docstrings a bit more clearer.
Helped-by: Chris Smith <smichr@gmail.com>
Signed-off-by: Saptarshi Mandal <sapta.iitkgp@gmail.com>
f9e8b6f
Saptarshi Mandal combinatorics/polyhedron: Simplified docstring and added a
reference.

Signed-off-by: Saptarshi Mandal <sapta.iitkgp@gmail.com>
29209f5
Christopher Smith polyhedron fixes e368ca3
Christopher Smith polyhedron: add test for args 61a9149
Christopher Smith polyhedron: use FiniteSet and Symbols d271b6c
Christopher Smith polyhedron: fix randomization test 7876322
Christopher Smith polyhedron: docstring and method changes d85515c
Christopher Smith add predefined corners and faces for standard solids 3f8200e
Christopher Smith polyhedron: fix and test predefined polyhedra 10d5ac0
Christopher Smith polyhedron: make faces canonical 55b40ee
Christopher Smith partition: use group in as_dict f8c7a57
Christopher Smith remove indexing of permutation; use array_form instead 7288ecd
Christopher Smith polyhedron: add polyhedra nets in docstring 1c4c854
Christopher Smith polyhedron: use list when using index for Py 2.5 3626b4c
Christopher Smith polyhedron: fix docstrings 1883e99
Christopher Smith iterables: has_variety added and used throughout sympy 9f7053e
Christopher Smith combinatorics changes
Transpositions are now stored in FiniteSet

Permutation's cyclic_form is made canonical with singletons
(which are insignificant but necessary for the current implementation)
are stored at the end of the list.
c009ce9
Christopher Smith permutations: add support method c77439b
Christopher Smith fix named_groups 5f6e30c
Christopher Smith combinatorics: cleanup
The utility functions for working with lists instead of permutations
(perm_af_*) were renamed (_af_*) to make them shorter and private.

The _af_mul routine was simplified to not be nested.
995a56e
Christopher Smith permutations: add one_based 9221943
Christopher Smith fix reduced_cyclic_form 4f554bc
Christopher Smith combinatorics: documentation changes 7ca0fa7
Christopher Smith combinatorics: add doc files 39e8e7d
Christopher Smith combinatorics: fix documentation dc3a0a2
Christopher Smith fix LatticeOps args
Since args need only be intra-session canonical, hash sorting is
used than the more elaborate default_sort_key sorting.

If an inter-system compatibility is needed then a _sorted_args
routine can be written using the default_sort_key sorting.
e8c2f60
Christopher Smith permutations: further simplify _af_mul 25b8ba5
Christopher Smith fix perm_groups 23fad87
Christopher Smith permutations: one_based omits singletons by default 890a178
Christopher Smith fix DirectProduct doc error e0c3a42
Christopher Smith combinatorics: perm_groups edit fb43ed1
Christopher Smith allow evalf(1) fb0d419
Christopher Smith add quick_sort for args ordering
When an object has arguments whose order is arbitrary, it is
still a good idea to order them in some canonical way so that
two objects that may have been entered with arguments in different
order will still be the same, e.g. x + 2 == 2 + x. Although hash
sorting is used (in Add, for example) this may run into hash collisions
and so in those cases there should be a way to consistently break ties.
The quick_sort function has been added to iterables to allow for this.
It sorts elements of an iterable on the basis of hash and breaks ties
using the default_sort_key. A tuple is returned from the function.
5f1c551
Christopher Smith fix quick_sort doctest 3c49022
Christopher Smith 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.
052f6fe
Christopher Smith code printing: use repr(expr); preprosessor (sp)
correction brought to attention by

David M. Rogers <predictivestatmech@gmail.com
1b60e43
Christopher Smith move minlex to iterables; combinatorics edits 6fbad64
Christopher Smith add tests for quick_sort 0de8dbc
Christopher Smith permutations: add tests and docstrings about R to L Mul: ABC(x) = A(B…
…(C(x)))
dac9403
Christopher Smith Permutation.mul added for convenience; product can be reversed 4512247
Christopher Smith variations requires n f2f027c
Christopher Smith permutation: add 0 to non-0-based perm
A duplicate __new__ method was also deleted from Permutation.
26d61b4
Christopher Smith permutations: keep [] bf2c098
Christopher Smith permutations: drop singletons from cyclic_form 5c63a71
Christopher Smith permutations: add DisjointCycle class ff5a323
Christopher Smith import has_dups 79f9ee2
Christopher Smith import Tuple 82f0f28
Christopher Smith add note about L->R processing of DisjointCycle 9c84979
Christopher Smith permutations: add as_cycle method 2a57a3d
Christopher Smith permutations: null DisjointCycle and has_dups err; length/support met…
…hods

length and support are methods since they do not simply read a property,
they calculate something. (It's an O(n) process, though, so perhaps they
could remain properties.)
2c7b8a9
Christopher Smith permutation: clean up DisjointCycle
Thanks to Tom Bachmann for the help in cleaning this up.

Also, dict is used instead of defaultdict since it, too, allows
for a __missing__ method. The printing of the DisjointCycle
as something other than a dict in doctests has not been resolved,
i.e. in doctests

>>> DisjointCycle(1,2)
{1: 2, 2: 1}

while during an interactive session this would give [(1, 2)].
a383604
Christopher Smith permutations: use lmul in code b2d5595
Christopher Smith permutation: lmul and other edits; DisjointCycle -> Cycle
Cycle and Permutation both act from R to L in the sense that
given A and B, A*B applies B to the elements and then applies A.

_af_mul works from L to R (but has a reverse option)
lmul accepts a list of permutations and processes them L to R

lmul is used throughout combinatorics to clearly indicate which
order the multiplication is being performed, but it could probably
be removed and the arguments just reversed in order.

A current deficiency with Permutation is that it cannot be rebuilt
from its args when it is in cycle form since the entire cycle is
not stored. A way around this would be to store the entire cycle
but have the print method only show the non-singletons.
663b9c9
Christopher Smith remove as_cycle; use Cycle(p) instead
Cycle will always know how to instantiate from a permutation
and such a cycle will always be convertable back to a permutation
since all elements are present; the general Cycle, however, cannot
be converted without a size parameter if some elements are missing.

Permutation(Cycle(p)) will return p as a permutation in array form
Permutation(Cycle(1, 6)) will fail
Permutation(Cycle(1, 6), size = 7) will succeed
1dd6c1b
Christopher Smith permutation: store args as array form 9c053ed
Christopher Smith permutation: add __rmul__ and do not coerce in lmul e184f79
Christopher Smith polyhedron: array_form and cyclic_form added; Perm used internally 4bb77bf
Christopher Smith perm_groups: __getitem__ added; generators stored as list a8d78a8
Christopher Smith permutation: pgroups->pgroup; docstring edits 90c4b26
Christopher Smith perm_group gets len; watches for single Permutation 72c6c05
Christopher Smith polyhedron: store pgroup as PermutationGroup 0802f47
Christopher Smith polyhedron: pgroups -> pgroup 8df3e36
Christopher Smith polyhedron: use list for Py 2.5 sake ac07c29
Christopher Smith iterables: runs added 13063ce
Christopher Smith quick_sort updated for failing test 47dc462
Christopher Smith permutations: coverage to 100% and other changes
Misc changes other than docstring edits and test addition:

no testing in the _af_foo routines to allow them
to be as fast as possible (as private methods)

__invert__ uses duplicating _af_invert now

Permutations support the iter method so list(P)
will give P.array_form

error corrected in parity which used the _cyclic_form
which is now not inclusive of singletons

the code of runs was simplified and moved to iterables

the docstring of josephus was written to be less historical and more descriptive

random_permutation is renamed random since, being a classmethod, it will be addressed as Permutation.random (clearly indicating it is related to Permutation).
3ca01a9
Christopher Smith fix whitespace 285a757
Christopher Smith fix permutations.rst ec6eeac
Christopher Smith only allow af_mul to work from L to R f00fe27
Christopher Smith don't use int_tested in permutations
The significant place not to use it is in __call__ as
noted in the code.

We can let the code fail with a simple int when the user
is working with Cycles.
6bfed40
Christopher Smith fix __eq__/__contains__ for PermutationGroup 0fe75b0
Christopher Smith perm_groups: add has(); cleanup docstrings 0de06e2
Christopher Smith move main make_perm to perm_groups
Standardize the input to the PermutationGroup so a list of permutations
always gets stored in the object (rather than the unacked args):

PG([a, b]) for PG(a, b) and PG([a, b]) rather than PG(a, b) for the
former.

Correct spelling of continuing.
8761a8e
Christopher Smith fix formatting of docstrings 6394e0f
Christopher Smith fix perm_groups docstring 9cfba20
Christopher Smith perm_groups docstring edits f7b73a2
Christopher Smith perm_group: fix corner case error; modify docstrings 823c9f4
Christopher Smith perm_group: fix doctest 0f2e747
Christopher Smith polyhedron: 100% coverage
One of the checks for permutation length was omitted since this
is checked by PermutationGroup.
110a49c
Christopher Smith combinatorics: edits 36fad91
Christopher Smith named_groups: RubikGroup 512768d
Aleksandar Makelov Improve multiplication of Permutations with different lengths
Disjoint cycles can be used to instantiate Permutation without
having to include singletons.

Multiplication of permutations of different sizes is handled by
extending the permutation of lesser size so that it matches
the size of the other permutation.
f07cc14
Christopher Smith combinatorics: more classes imported in init 90a40f9
Christopher Smith permutation: call handles list arg; doc edits 3fb9fe5
Christopher Smith permutation: doc edits 8989ade
Christopher Smith permutation: add to docstrings about adjusting mul f538786
Christopher Smith combinatorics: docstrings about Polyhedron and PermutationGroup f7430cb
Christopher Smith polyhedron: let set handle duplicates 0d30bbd
Christopher Smith combinatorics: remove make_perm from polyhedron
There is no need to duplicate the make_perm method in Polyhedron
since Polyhedron stores the permutations in a PermutationGroup
and that group has the make_perm method.
b84e74c
Christopher Smith combinatorics: perm watch for resizing; PermutationGroup adjusts size
Previously, PermutationGroup raised an error if all permutations were
not the same size. Now, in keeping with more flexible disjoint cycle
notation for Permutation, the size of all is simply adjusted so all
have the same maximum value.

More documentation was given to PermutationGroup, too.
35f4fa6
Christopher Smith print PG in cycles; PG accepts cycles; __eq__ ignores size d7aa8db
Christopher Smith combinatorics: global flag for printing in cyclic form
Permutation.print_cyclic will cause Permutations to be printed
as Cycle, e.g. Permutation([0, 2, 1, 3]) -> Cycle(1, 2)

When False, the normal array_form will be used.

This does not affect how cyclic_form and array_form are shown.
So even if the print_cycle flag is True, Permutation([0, 2, 1, 3]).array_form
will still be [0, 2, 1, 3].
ebab47d
Christopher Smith remove __mul__ from Cycle
To avoid confusion, only the __call__ method for Cycle is defined while
__mul__ is defined for Permutation:

Permutation([[1, 2]])*Permutation([[2, 3]]) == Cycle(1, 2)(2, 3)

TODO: a possible confusion is that Permutations printed with print_cyclic
= True print as Cycle(1, 2)(2, 3) (for example) and look like a Cycle
but they are actual a Permutation. So the array_form is defined and the
as_list is not. The Cycle prints as something like [(1, 3, 2)].

>>> a = Permutation([[1,2],[5,3]])
>>> a
Cycle(1, 2)(3, 5)
>>> Cycle(a)
[(1, 2), (3, 5)]
>>> Permutation.print_cyclic = False
>>> a
Permutation([0, 2, 1, 5, 4, 3])
56f483b
Christopher Smith perm_groups: adjust size of input to coset_decomposition 81b9082
Christopher Smith combinatorics: __eq__ uses cyclic_form 041291f
Christopher Smith combinatorics: (a) implement cycle I/O for Permutation c83f573
Christopher Smith permutations: rewrite docs 0c7dd8d
Christopher Smith PERM -> Permutation 9c7d8b5
Christopher Smith coset_rank aligns size of g cbe679d
Christopher Smith permutation: better checking of input c01f1cc
Christopher Smith permutations: fix max() error 0bb3a79
Christopher Smith permutations: add matrix_form method and update docstrings af84c76
Christopher Smith combinatorics: add is_group method and docstring in polyhedron b22723b
Christopher Smith combinatorics: PermutationGroup raises error if gens are duplicated
raise error in PermutationGroup if duplicate permutations are received

remove duplicate permutations from DirectProduct before passing to
PermutationGroup

remove duplicate from names_groups before sending to PermutationGroup

util
    change orbs -> orbits

perm_groups:
    use range instead of xrange in perm_groups
    clean up test for Identity generator
    clean up loop testing whether a new base should be added
    clean up tracking of _base length

permutations:
    make sure perm is a list; if it is a tuple a different obj is
    created -- this is faster than just making it a list and also
    creates a small level of safety for the private routine

    is_Identity will short circuit now without having to generate
    the entire list to make the comparison
9ea9fa7
Christopher Smith combinatorics: simplify is_trivial calc 8a0c0dc
Christopher Smith permutation: work with ints 432ae5d
Christopher Smith permutation: split af_mul into af_muln e0e27df
Christopher Smith permutations: raise error for missing 0; filter gens for PermutationG…
…roup

group_constructs
    use dups=False
named_groups
    use dups=False
perm_groups
    allow duplicate checking to sbe skipped with dups=False keyword
permutations
    don't add 0 by default to permutations entered in array form
    (entering in cycle form automatically adds it, however)

    no: Permutation([2,3,1,4])
    yes:
    >>> Permutation(1, 2, 3, size=5).array_form
    [0, 2, 3, 1, 4]
    >>> Cycle(1,2,3)(4).as_list()
    [0, 2, 3, 1, 4]
    >>> Cycle(1,2,3).as_list(5)

tests modified in keeping with the above
2a08a49
Christopher Smith permutations: differentiate between None and 0 in as_list ebf1cd2
Christopher Smith permutations: add not to lmul docstring about L to R order 30ac89b
Christopher Smith permutations: always show the size when printing 644853b
Christopher Smith perm_groups: clean up coset_decomposition -> coset_factor 445be4a
Christopher Smith coset_factor: return [] instead of False 2cce155
Christopher Smith coset_factor: look for quick exits 873fff4
Christopher Smith perm_groups: coset_repr -> coset_decomposition 48b953a
Christopher Smith permutations: return transpositions factors as list, not set f01d0d6
Christopher Smith _af_mul special cases up to 8 factors d976353
Christopher Smith combinatorics: lmul -> mul; __xor__ -> conjugate
The computation of the product of more than 8 items in _af_mul (now
_af_rmul) was made to only create 1 intermediate list.

The discussion about R or L multiplication was dropped in favor of
just demonstrating what was meant, e.g. a(b(c(i))), and giving a
corresponding doctest.

The __xor__ method was mapped to conjugate so now a^b given a.conjugate(b)

The subgroup_search test for size 16 was xfailed as slow.
2016b3d
Christopher Smith combinatorics: Permutations not equal unless size is equal, too
Things are slowed down considerably when testing cyclic forms, and
allowing permutations of different lengths to compare equal leaves
open the possibiliity of subtle errors. Permutations now compare
equal only if their array forms are equal.

An error is also raise for coset_factor if the g to be factored is
not the same length as the permutations in the group.
c6cf17e
Christopher Smith permutations: fix sphinx error 2f1ab6e
Christopher Smith polyhedron: reorder tetrahedron permutations 0e03412
Christopher Smith cube: add inline references for the pgroup 188f178
Christopher Smith permutations: make sure largest is printed first in permutation cycli…
…c form

The output should be copyable and pastable for reevaluation, and it
won't be if it is printed like Permutation(1,2)(5) instead of
Permutation(5)(1,2).
9d2067a
Christopher Smith perm_groups: minor docstring edits 7c292d8
Christopher Smith permutations: cleanup docstring 0424fdf
Christopher Smith permutation: define _hashable_content 4595ff4
Christopher Smith permutations: remove cauchy form; edit docstrings cb18cb5
Ronan Lamy Move int_tested to the core and refactor it.
* Move int_tested() to sympy.core.compatibility, to make it
  importable anywhere.
* Simplify it to take only a single argument, like int().
* Rename it as_int().

cps: add compatibility to core.rst
717d4e3
Christopher Smith permutations: restore recursive _af_rmul 44da66e
Christopher Smith polyhedron: edit docstrings 98f2ed9
Christopher Smith permutations: change docstring so r*q!=q*r 277274a
Christopher Smith prem_groups: coset_decomposition -> stabilizer_cosets; stabilizers_ge…
…ns -> stabilizer_gens
68a8d33
Christopher Smith permutations: add note about static arrow diagrams 0750839
Christopher Smith permutations: add as_permutation method
This is inspired by the Mathematica function FindPermutation.

dec
208c021
Christopher Smith perm_groups: expand is_group docstring and modify generate docstring d6e08ca
Christopher Smith permutations: remove __xor__ operator
This is being removed until the question of whether a.conjugate(b)
should give ~a*b*a or a*b*~a.
09aae58
Christopher Smith permutations: change commutator and conjugate docstrings
Permutations were selected for commutator so xp~x~p != ~p~xpx
2c68a68
Christopher Smith as_permutation -> from_sequence ea6cbeb
pernici permutations: used __xor__ instead pf __pow__ for conjugation
In addition,

used __rxor__ to represent the application i --> i^p

Changes by Chris Smith (smichr@gmail.com)

removed conjugate method in favor or only the __xor__ method
and introduced a test function, conjugate_of to test whether
self and other are conjugates of each other.

other docstring edits
f74a09e
pernici
    def conjugate_of(self, other):
        """Return True if self and other are conjugates, else False.

If two permutations have the same cycle structure, they are conjugates
in S_n, but not necessarily in another permutation group.

see http://math.stackexchange.com/questions/48134/why-are-two-permutations-conjugate-iff-they-have-the-same-cycle-structure

I suggest to specify that it is a test whether they are conjugate in S_n; the alternative is to add as default
parameter group=S_n, compute h such that self = other^h and check if h belongs to the group,
but I do not think it is a good idea.

pernici

I do not think it is a good idea to introduce the division by a permutation, since permutations do not commute.

Aaron Meurer
Owner

I haven't been following this or the other PR that it shadows very closely. Please ping me when it's ready to be merged.

and others added some commits September 11, 2012
Christopher Smith permutations: +/- on basis of rank
Partitions and Prufer add on the basis of rank and this seems to
be a better idea than adding the elements of the inversion code
together.

rank(i) now gives ith permutation

modify which form of the commutator is returned
523f73a
Christopher Smith named_groups: add the 3 polyhedral groups 6903994
Christopher Smith permutations: Cycle gets size property and __iter__ 4487a92
Christopher Smith permutations: as_list -> list method fa90805
Christopher Smith permutations: remove conjugate_of 0a31443
Christopher Smith named_groups: remove Polyhedral groups
I'm not confident enough that I understand what someone would expect
for these groups, so I'm leaving them out. They should be easy to add
back and modify if necessary.
61a9211
Christopher Smith permutations: remove test functions 660108c
Christopher Smith permutations: cycle_structure method added e952282
Christopher Smith permutations: add note about getting h*f*~h instead of ~h*f*h 029ca86
Christopher Smith iterables: lazyDSU_sort added ae76b99
Christopher Smith permutations: make cycle_structure a property; return dict 72d63d7
Christopher Smith perm_groups: remove has; add _hashable_content 165707f
Christopher Smith fix permutation str test 569d161
Christopher Smith permutation: Permutation has list method, too 0cc5f75
Christopher Smith move quick_sort to compatibility 3928e43
Christopher Smith permutations: add to contains docstring 2fb0465
Christopher Smith fix sphinx errors in compatibility 68217a3
Christopher Smith fix Permutation and PermutationGroup args 69f14da
Christopher Smith perm_groups: minor edits of insert
There is no need to append element [0,...,cmin] to the end of the
range starting from cmin since negative indices handle this just
fine.

ig was changed to gi since it represents g[i] and ig is similar to jg
which is short for JerrumGraph.

There is no need to do double work in testing to see if g is Identity
and then search for the min change. If there is no min change then
it's the identity. The only caveat would be if one got a g like
[2,1,0,3,4,5] and alpha was 3: None would be returned and the routine
would have failed. For safety, an assertion could be made that if i
is None then g[:cmin] == range(cmin)...this has not been done and no
test has failed to it was left out.
5faabf9
Christopher Smith named_groups: fix docstring d3989e4
Christopher Smith examples: minor edits d6d8759
Christopher Smith add reshape to iterables 1692d79
Christopher Smith perm_groups: remove bisect 912ff2e
Christopher Smith fix str error for PermutationGroup dee3ba2
pernici Changed is_subgroup to admit that a group can be subgroup of a group
with larger degree
69e60a3
Christopher Smith fix str error f36b1de
Christopher Smith Merge pull request #15 from pernici/combinatorics
Changed is_subgroup to admit that a group can be subgroup of a group with larger degree
cd0ff48
Christopher Smith Merge branch 'combinatorics' of github.com:smichr/sympy into combinat…
…orics
5da3f9f
Christopher Smith fix perm_group docstring 2a86561
Christopher Smith perm: add trivial check to contains 1f6dcca
Christopher Smith permutations: removed unused imports and tuplizatation of args 1ea38fa
Christopher Smith fix trouble with hash and PermutationGroup
The redefining of __eq__ required that __hash__ also be defined
as noted now in the __eq__ docstring that was edited in Basic.
32a7c3a
Christopher Smith perm_groups: minor edits 5d82051
Christopher Smith move __eq__ to contains; __eq__ is more literal 556cc4e
Christopher Smith move the old __eq__ code from contains to is_in e1ef520
Christopher Smith merge is_in and is_subgroup with strict option 9668728
pernici fixed bug in the computation of the strong base 6a4830a
pernici Added default argument `strict` to is_transitive` 8df042c
Christopher Smith Merge pull request #16 from pernici/combinatorics
Added default argument `strict` to is_transitive`; fixed bug in `base`
eeb5b73
Christopher Smith is_transitive: False for strict=False possible 77fe489
Christopher Smith contains gets strict option e1b091b
Christopher Smith resize in contains rather than in is_subgroup ea5bf22
pernici Faster coset_factor and coset_rank 51a50f1
Christopher Smith stabilizer_cosets, coset_factor and gens come back as permutations
af=True will send them back in array form
d08c9dc
Christopher Smith fix error in simplify with use of has_variety 419d310
Christopher Smith
Collaborator

#1508 is now in.

Christopher Smith smichr closed this September 17, 2012
Coveralls

Coverage Status

Changes Unknown when pulling 419d310 on smichr:combinatorics into ** on sympy:master**.

Coveralls

Coverage Status

Changes Unknown when pulling 419d310 on smichr:combinatorics into ** on sympy:master**.

Coveralls

Coverage Status

Changes Unknown when pulling 419d310 on smichr:combinatorics into ** on sympy:master**.

Coveralls

Coverage Status

Changes Unknown when pulling 419d310 on smichr:combinatorics into ** on sympy:master**.

Coveralls

Coverage Status

Changes Unknown when pulling 419d310 on smichr:combinatorics into ** on sympy:master**.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.