Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FreeGroup implementation in SymPy #10350

Merged
merged 32 commits into from May 20, 2016
Merged
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
45f3cf2
``FreeGroup`` implementation in SymPy
Jan 2, 2016
c1c324c
code simplified
Jan 3, 2016
84dc4c3
math fixes in code
Jan 3, 2016
642d2b0
Merge branch 'master' into implementation_FreeGroup
May 5, 2016
c3f812e
remove un-necessary import
May 10, 2016
e6d63ac
trying to remove the __new__ method from FreeGroupElm
May 11, 2016
2b244c3
make FreeGroupElm a subclass of list instead of basic
May 12, 2016
65ae08e
changes in methods using dtype
May 12, 2016
428945a
Add test file for free_group.py
May 12, 2016
697cf88
checking the input type with `isint`
May 12, 2016
cbab81e
zero_mul_simp method improved
May 12, 2016
a1848de
change free group API to similar to polys
May 13, 2016
4512ff4
Add `tuple` as baseclass for FreeGroupElm not list
May 13, 2016
77e83a8
changes in zero_mul_simp function
May 13, 2016
afde353
printing and different free group introduction
May 14, 2016
21343af
changes in methods
May 14, 2016
9115376
documentation and (index, exp) -> (symbol, exp) changes
May 14, 2016
49a3eff
remove the unused import of collections.abc
May 14, 2016
7daba8c
changes in methods and __truediv__
May 14, 2016
a96dd7e
comparison with `is` instead of `==` for Symbol
May 15, 2016
a3e2ab5
base class changed from Basic -> DefaultPrinting
May 15, 2016
23d151f
hash method for FreeGroup and FreeGroupElm and _parse_symbols
May 16, 2016
2c40d4d
tests files initialised with good tests
May 16, 2016
efeef3d
add tests and comparison of FreeGroupElm fixed
May 17, 2016
9f1df56
add tests for "words", "syllables"
May 17, 2016
11037dd
Fix docstring, printing issue of FreeGroupElm
May 17, 2016
aa11087
make lw=len(array_form), remove while loop
May 17, 2016
15dd87a
use loop instead of recursion for zero_mul_simp
May 17, 2016
a55835b
change the zero_simp_mul method
May 17, 2016
fc560cb
Raise TypeError, Add tests for invalid FreeGroupElm operations
May 18, 2016
b3f1053
remove useless import
May 18, 2016
48158b4
change condition from len(l) >1 to index>=0 in zero_mul_simp
May 18, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
188 changes: 82 additions & 106 deletions sympy/combinatorics/free_group.py
Expand Up @@ -118,15 +118,15 @@ def _generators(group):
Examples
========

>>> from sympy.combinatorics.free_group import FreeGroup
>>> f = FreeGroup( 3, "swapnil" )
>>> from sympy.combinatorics.free_group import free_group
>>> f, x, y, z = free_group("x, y, z")
>>> f.generators
[swapnil0, swapnil1, swapnil2]
[x, y, z]

"""
gens = []
for i in range(group.rank):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe for sym in group.symbols:.

elm = ((i, 1),)
elm = ((group.symbols[i], 1),)
gens.append(group.dtype(elm))
return gens

Expand All @@ -140,15 +140,6 @@ def __contains__(self, i):
Examples
========

>>> from sympy.combinatorics.free_group import FreeGroup
>>> f = FreeGroup( 4, "swap" )
>>> g = FreeGroup( 4, "swapnil" )

>>> f[0]**2*f[3] in f
True
>>> f[0]**2*f[3] in g
False

"""
if not isinstance(i, FreeGroupElm):
raise TypeError("FreeGroup contains only FreeGroupElm as elements "
Expand Down Expand Up @@ -176,14 +167,6 @@ def __eq__(self, other):
Examples
========

>>> from sympy.combinatorics.free_group import FreeGroup
>>> f = FreeGroup( 4, "swapnil" )
>>> g = FreeGroup( 4, "swapnil" )
>>> f == g
False
>>> f == f
True

"""
return self is other
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is probable that Python would provide this as a default

But for the above doctest i have added. It is such that even if the two instances f and g have the same arguments (i.e "4" and "swapnil") but still f == g has to be returned as being not equal, different from the usual way Python defines __eq__(which returns True when the arguments are same for two instances of same class).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see... This behaviour is probably inherited from Basic. I wonder if it is necessary to make Group a subclass of Basic. (PolyRing is not...) @asmeurer ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you want this behavior to work this way? The whole idea behind Basic.__eq__ is that == works as structural (not mathematical) equality, which tends to be the most useful thing when dealing with symbolic objects.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then, did we made a mistake here in PR #10230 for the PermutationGroup?


Expand Down Expand Up @@ -221,16 +204,13 @@ def is_abelian(self):
Examples
========

>>> from sympy.combinatorics.free_group import FreeGroup
>>> f = FreeGroup( 4 )
>>> from sympy.combinatorics.free_group import free_group
>>> f, x, y, z = free_group("x y z")
>>> f.is_abelian
False

>>> g = FreeGroup( 0 )
>>> g.is_abelian
True

"""
# this needs to be tested
if self.rank == 0 or self.rank == 1:
return True
else:
Expand All @@ -249,15 +229,15 @@ def contains(self, g):
Examples
========

>>> from sympy.combinatorics.free_group import FreeGroup
>>> f = FreeGroup( 4 )
>>> f.contains(f[0]**3*f[1]**2)
>>> from sympy.combinatorics.free_group import free_group
>>> f, x, y, z = free_group("x y z")
>>> f.contains(x**3*y**2)
True

"""
if not isinstance(i, FreeGroupElm):
if not isinstance(g, FreeGroupElm):
return False
elif self != i.group:
elif self != g.group:
return False
else:
return True
Expand Down Expand Up @@ -329,11 +309,11 @@ def array_form(self):
Examples
========

>>> from sympy.combinatorics.free_group import FreeGroup
>>> f = FreeGroup( 4 )
>>> (f[0]*f[2]).array_form
>>> from sympy.combinatorics.free_group import free_group
>>> f, x, y, z = free_group("x y z")
>>> (x*z).array_form
[(0, 1), (2, 1)]
>>> (f[0]**2*f[2]*f[1]*f[0]**2).array_form
>>> (x**2*z*y*x**2).array_form
[(0, 2), (2, 1), (1, 1), (0, 2)]

See Also
Expand All @@ -355,13 +335,13 @@ def letter_form(self):
Examples
========

>>> from sympy.combinatorics.free_group import FreeGroup
>>> f = FreeGroup( 4 )
>>> (f[0]**3).letter_form
>>> from sympy.combinatorics.free_group import free_group
>>> f, a, b, c, d = free_group("a b c d")
>>> (a**3).letter_form
[1, 1, 1]
>>> (f[0]**2*f[3]**-2*f[0]*f[1]**-4).letter_form
>>> (a**2*d**-2*a*b**-4).letter_form
[1, 1, -4, -4, 1, -2, -2, -2, -2]
>>> (f[0]**-2*f[1]**3*f[3]).letter_form
>>> (a**-2*b**3*d).letter_form
[-1, -1, 2, 2, 2, 4]

See Also
Expand Down Expand Up @@ -392,15 +372,15 @@ def __str__(self):
for i in range(len(array_form)):
if i == len(array_form) - 1:
if array_form[i][1] == 1:
str_form += str(symbols[array_form[i][0]])
str_form += str(array_form[i][0])
else:
str_form += str(symbols[array_form[i][0]]) + \
str_form += str(array_form[i][0]) + \
"**" + str(array_form[i][1])
else:
if array_form[i][1] == 1:
str_form += str(symbols[array_form[i][0]]) + "*"
str_form += str(array_form[i][0]) + "*"
else:
str_form += str(symbols[array_form[i][0]]) + \
str_form += str(array_form[i][0]) + \
"**" + str(array_form[i][1]) + "*"
return str_form

Expand All @@ -427,13 +407,13 @@ def __mul__(self, other):
Examples
========

>>> from sympy.combinatorics.free_group import FreeGroup
>>> f = FreeGroup( 4, "swapnil" )
>>> f[0]*f[1]**2*f[1]**-4
swapnil0*swapnil1**-2
>>> f[2]*f[1]**-2
swapnil2*swapnil1**-2
>>> (f[0]**2*f[1]*f[1]**-1*f[0]**-2)
>>> from sympy.combinatorics.free_group import free_group
>>> f, x, y, z = free_group("x y z")
>>> x*y**2*y**-4
x*y**-2
>>> z*y**-2
z*y**-2
>>> x**2*y*y**-1*x**-2
<identity>

"""
Expand All @@ -452,19 +432,22 @@ def __mul__(self, other):
def __div__(self, other):
return self*(other.inverse())

def __rdiv__(self, other):
return other*(self.inverse())

def inverse(self):
"""
Returns the inverse of a `FreeGroupElm` element

Examples
========

>>> from sympy.combinatorics.free_group import FreeGroup
>>> f = FreeGroup( 2, "swapnil" )
>>> f[0].inverse()
swapnil0**-1
>>> (f[0]*f[1]).inverse()
swapnil1**-1*swapnil0**-1
>>> from sympy.combinatorics.free_group import free_group
>>> f, x, y, z = free_group("x y z")
>>> x.inverse()
x**-1
>>> (x*y).inverse()
y**-1*x**-1

"""
group = self.group
Expand All @@ -477,9 +460,9 @@ def order(self):
Examples
========

>>> from sympy.combinatorics.free_group import FreeGroup
>>> f = FreeGroup( 4 )
>>> (f[0]**2*f[1]*f[1]**-1*f[0]**-2).order()
>>> from sympy.combinatorics.free_group import free_group
>>> f, x, y = free_group("x y")
>>> (x**2*y*y**-1*x**-2).order()
1

"""
Expand Down Expand Up @@ -507,14 +490,13 @@ def eliminate_word(self, gen, by):
Examples
========

>>> from sympy.combinatorics.free_group import FreeGroup
>>> f = FreeGroup( 4 )
>>> w = f[0]**5*f[1]*f[0]**2*f[1]**-4*f[0]
>>> w.eliminate_word( f[0], f[0]**2 )
f0**10*f1*f0**4*f1**-4*f0**2

>>> w.eliminate_word( f[0], f[1]**-1 )
f1**-11
>>> from sympy.combinatorics.free_group import free_group
>>> f, x, y = free_group("x y")
>>> w = x**5*y*x**2*y**-4*x
>>> w.eliminate_word( x, x**2 )
x**10*y*x**4*y**-4*x**2
>>> w.eliminate_word( x, y**-1 )
y**-5*y*y**-2*y**-4*y**-1

"""
group = self.group
Expand All @@ -540,7 +522,7 @@ def eliminate_word(self, gen, by):

if len(app) > 0:
l.append(tuple(app))
l = zero_mul_simp(l)
# zero_mul_simp to be used
return group.dtype(l)

def __len__(self):
Expand All @@ -550,9 +532,8 @@ def __len__(self):
Examples
========

>>> from sympy import free_group
>>> f = free_group("x y")
>>> a, b = f[0][0], f[0][1]
>>> from sympy.combinatorics.free_group import free_group
>>> f, a, b = free_group("a b")
>>> w = a**5*b*a**2*b**-4*a
>>> len(w)
13
Expand All @@ -576,22 +557,22 @@ def __eq__(self, other):
Examples
========

>>> from sympy.combinatorics.free_group import FreeGroup
>>> f = FreeGroup( 2, "swapnil" )
>>> from sympy.combinatorics.free_group import free_group
>>> f, swapnil0, swapnil1 = free_group("swapnil0 swapnil1")
>>> f
<free group on the generators [swapnil0, swapnil1]>
>>> g = FreeGroup( 2 , "swapnil" )
>>> g, swap0, swap1 = free_group("swap0 swap1")
>>> g
<free group on the generators [swapnil0, swapnil1]>
<free group on the generators [swapl0, swap1]>

>>> f[0] == f[1]
>>> swapnil0 == swapnil1
False
>>> f[0]*f[1] == f[1]/f[1]*f[0]*f[1]
>>> swapnil0*swapnil1 == swapnil1/swapnil1*swapnil0*swapnil1
True
>>> f[0]*f[1] == f[1]*f[0]
>>> swapnil0*swapnil1 == swapnil1*swapnil0
False

>>> f[1]**0 == g[0]**0
>>> swapnil1**0 == swap0**0
False

"""
Expand All @@ -614,11 +595,11 @@ def __lt__(self, other):
Examples
========

>>> from sympy.combinatorics.free_group import FreeGroup
>>> a = FreeGroup( 4, "swapnil" )
>>> a[1] < a[0]
>>> from sympy.combinatorics.free_group import free_group
>>> f, a, b = free_group("a b")
>>> b < a
False
>>> a[0] < a[0].inverse()
>>> a < a.inverse()
False

"""
Expand Down Expand Up @@ -657,13 +638,13 @@ def __gt__(self, other):
Examples
========

>>> from sympy.combinatorics.free_group import FreeGroup
>>> b = FreeGroup( 3, "swapnil" )
>>> b[1]**2 > b[0]**2
>>> from sympy.combinatorics.free_group import free_group
>>> f, x, y, z = free_group("x y z")
>>> y**2 > x**2
True
>>> b[1]*b[2] > b[2]*b[1]
>>> y*z > z*y
False
>>> b[0] > b[0].inverse()
>>> x > x.inverse()
True

"""
Expand All @@ -687,9 +668,8 @@ def exponent_sum_word(self, gen):
Examples
========

>>> from sympy import free_group
>>> f = freegroup("x y")
>>> a, b = f[0][0], f[0][1]
>>> from sympy.combinatorics.free_group import free_group
>>> f, a, b = free_group("a b")
>>> w = a**5*b*a**2*b**-4*a
>>> w.exponent_sum_word(a)
8
Expand Down Expand Up @@ -726,9 +706,8 @@ def subword(self, from_i, to_j):
Examples
========

>>> from sympy import free_group
>>> f = free_group("x y")
>>> a, b = f[0][0], f[0][1]
>>> from sympy.combinatorics.free_group import free_group
>>> f, a, b = free_group("a b")
>>> w = a**5*b*a**2*b**-4*a
>>> w.subword(2, 6)
x**3*y
Expand Down Expand Up @@ -757,7 +736,7 @@ def number_syllables(self):
Examples
========

>>> from sympy import free_group
>>> from sympy.combinatorics.free_group import free_group
>>> f = free_group("swapnil0 swapnil1")
>>> swapnil0, swapnil1 = f[0][0], f[0][1]
>>> (swapnil1**3*swapnil0*swapnil1**-1).number_syllables()
Expand All @@ -774,9 +753,8 @@ def exponent_syllable(self, i):
Examples
========

>>> from sympy import free_group
>>> f = free_group("x y")
>>> a, b = f[0][0], f[0][1]
>>> from sympy.combinatorics.free_group import free_group
>>> f, a, b = free_group("a b")
>>> w = a**5*b*a**2*b**-4*a
>>> w.exponent_syllable( 2 )
2
Expand All @@ -792,9 +770,8 @@ def generator_syllable(self, i):
Examples
========

>>> from sympy import free_group
>>> f = free_group("x y")
>>> a, b = f[0][0], f[0][1]
>>> from sympy.combinatorics.free_group import free_group
>>> f, a, b = free_group("a b")
>>> w = a**5*b*a**2*b**-4*a
>>> w.generator_syllable( 3 )
1
Expand All @@ -812,9 +789,8 @@ def sub_syllables(self, from_i, to_j):
Examples
========

>>> from sympy import free_group
>>> f = free_group("x y")
>>> a, b = f[0][0], f[0][1]
>>> from sympy.combinatorics.free_group import free_group
>>> f, a, b = free_group("a b")
>>> w = a**5*b*a**2*b**-4*a
>>> w.sub_syllables(1, 2)
f1
Expand Down