``FpGroup`` implementation in SymPy #11140

Merged
merged 38 commits into from Jun 13, 2016

Projects

None yet

3 participants

@gxyd
Member
gxyd commented May 20, 2016

Implementation of classes/methods for "Coset Enumeration".
Currently very crude.

@jksuom jksuom and 2 others commented on an outdated diff May 20, 2016
sympy/combinatorics/free_group.py
@@ -127,6 +127,7 @@ class FreeGroup(DefaultPrinting):
"""
is_associative = True
is_group = True
+ is_fp_group = True
@jksuom
jksuom May 20, 2016 Member

There is is_FpGroup above. This might be confusing.

@gxyd
gxyd May 21, 2016 Member

This is how I think about it. .is_FpGroup would return True for an instance of FpGroup, while .is_fp_group would be for mathematically checking whether the group is finitely presented or not. Since a free group is a finitely presented group with empty relators list, hence is_fp_group = True is set.
This is similar to .is_number and .is_Number.

@leosartaj
leosartaj May 21, 2016 Member

This is how I think about it. .is_FpGroup would return True for an instance of FpGroup

I am -1 to this kind of functionality. I know this is abundantly done in SymPy codebase, but it is just not that useful. I think isinstance method covers all of the use cases. Plus, isinstance is always more clearer to me.

@jksuom
jksuom May 21, 2016 Member

I was also going to suggest using isinstance.

@gxyd
gxyd May 21, 2016 Member

I agree, so will remove "this" assignment (i.e .is_fp_group = True).

@jksuom
jksuom May 21, 2016 Member

I'm not sure which assignment would be more useful. It seems that testing, e.g., is_FpGroup could take a little less time than isinstance but at least now I cannot think of a situation where such tests would be needed so frequently that the difference would become meaningful. In addition, there is the problem that the attribute is_FpGroup would probably have to be added also elsewhere. Otherwise it could not be used without first testing its existence.

@leosartaj
leosartaj May 21, 2016 Member

To me is_fp_group seems Ok. I am not a fan of is_FpGroup instead of using isinstance though.

@gxyd gxyd added the GSoC label May 25, 2016
@gxyd gxyd commented on an outdated diff May 26, 2016
sympy/combinatorics/fp_groups.py
+ f = alpha
+ i = 0
+ r = len(word)
+ # list of union of generators and their inverses
+ # A = coset_table.A
+ while i < r and C[f][A.index(word.subword(i, i+1))] != -1:
+ f = C[f][A.index(word.subword(i, i+1))]
+ i += 1
+ if i >= r:
+ if f != alpha:
+ # implement the "coincidence" routine on Pg 158 of Handbook.
+ coincidence(C, f, alpha)
+ return
+ b = alpha
+ j = r
+ while j >= i and C[b][A.index(word.subword(j-1, j).inverse())] != -1:
@gxyd
gxyd May 26, 2016 Member

I am looking at the Pg. 155 of Derek Holt, pseudo-code for scan line number 9-10 there is "b​^{x^​−​​1}"​​ is defined"
According to the Derek Holt. pseudo-code is

while j >= i and b^{x^-1} is defined
    do; b:=b^{x^-1}; j:=j–1;

My point is in book it uses b^{x^-1}, which I initially fortunately/unfortunately coded as it is my commit right now. Also what we have commited here seems to work, but the one in book doesn't do the work.
You can test them using the "docs", first example.

@jksuom jksuom commented on an outdated diff May 27, 2016
sympy/combinatorics/fp_groups.py
+def merge(k, lamda, p, q, l):
+ phi = rep(k, p)
+ chi = rep(lamda, p)
+ if phi != chi:
+ mu = min(phi, chi)
+ v = max(phi, chi)
+ p[v] = mu
+ l += 1
+ q[l] = v
+ return l
+
+
+def rep(k, p):
+ lamda = k
+ pho = p[lamda]
+ while p != lamda:
@jksuom
jksuom May 27, 2016 Member

Should this be pho != lamda (or rho?)

@jksuom jksuom commented on an outdated diff May 27, 2016
sympy/combinatorics/fp_groups.py
+ lamda = pho
+ pho = p[lamda]
+ mu = k
+ pho = p[mu]
+ while pho != lamda:
+ p[mu] = lamda
+ mu = pho
+ pho = p[mu]
+ return lamda
+
+
+# alpha, beta coincide
+def coincidence(C, alpha, beta):
+ l = 0
+ q = []
+ #XXX what are p, q here?
@jksuom
jksuom May 27, 2016 Member

p could be an argument, or it could also be a part of C.

@jksuom jksuom commented on an outdated diff May 27, 2016
sympy/combinatorics/fp_groups.py
+ mu = pho
+ pho = p[mu]
+ return lamda
+
+
+# alpha, beta coincide
+def coincidence(C, alpha, beta):
+ l = 0
+ q = []
+ #XXX what are p, q here?
+ l = merge(alpha, beta, p, q, l)
+ i = 1
+ while i <= l:
+ gamma = q[i]
+ i += 1
+ del C[gamma]
@jksuom
jksuom May 27, 2016 Member

It seems that this is already implicitly done by merge when setting p[v] = mu.

@gxyd
Member
gxyd commented May 28, 2016 edited

I have added one of the examples mentioned in the originial todd-cox paper. In that paper (added example), there doesn't happen any use of coincidence routine (coincidence routine is never reached). I am still seeing to improve over the coincidence routine.

@jksuom jksuom commented on an outdated diff May 28, 2016
sympy/combinatorics/fp_groups.py
+ [None, 2, None, 0, 2, 0, None, 2, 1, 1],
+ [1, None, 0, None, None, 1, 1, 0, 0, None]]
+ >>> scan(c1, 0, e*a*b**-1, A)
+ >>> c1
+ [[0, None, 1, 2, 1, None, 2, None, 2, 2],
+ [None, 2, None, 0, 2, 0, None, 2, 1, 1],
+ [1, None, 0, None, None, 1, 1, 0, 0, 0]]
+ >>> scan(c1, 0, c*d*e**-1, A)
+ # sudden-collapse
+ # I don't know what this means!! (programmatically, mathematically clear)
+ >>> c1
+ [[0, None, 0, 0, 0, 0, 0, 0, 0, 0],
+ [None, 2, None, 0, 2, 0, None, 2, 1, None],
+ [0, None, 0, None, None, None, None, 0, 0, 0]]
+
+ # Example from original Todd-Cox
@jksuom
jksuom May 28, 2016 Member

Preferably Todd-Coxeter

@jksuom jksuom and 1 other commented on an outdated diff May 28, 2016
sympy/combinatorics/fp_groups.py
+# their inverses), represented using "FpGroupElm"
+
+# Pg. 153
+## later: remove "A" from argument
+def define(C, alpha, x, A):
+ # now C.n is not obtainable
+ if len(C) == DefaultMaxLimit:
+ # abort the further generation of cosets
+ return
+ C.append([None]*len(A))
+ # beta is the new coset generated
+ beta = len(C) - 1
+ C[alpha][A.index(x)] = beta
+ C[beta][A.index(x.inverse())] = alpha
+
+p = []
@jksuom
jksuom May 28, 2016 Member

I think this is logically a part of the table together with the action data. We should probably have class CosetTable.

@gxyd
gxyd May 28, 2016 Member

Ah! I was skeptical in making it a class, to be true. Now you have
raised the point. I think I will try to code it first.

On 05/28/2016 11:49 AM, Kalevi Suominen wrote:

In sympy/combinatorics/fp_groups.py
#11140 (comment):

+# their inverses), represented using "FpGroupElm"
+
+# Pg. 153
+## later: remove "A" from argument
+def define(C, alpha, x, A):

  • now C.n is not obtainable

  • if len(C) == DefaultMaxLimit:
  •    # abort the further generation of cosets
    
  •    return
    
  • C.append([None]*len(A))
  • beta is the new coset generated

  • beta = len(C) - 1
  • C[alpha][A.index(x)] = beta
  • C[beta][A.index(x.inverse())] = alpha

+p = []

I think this is logically a part of the table together with the action
data. We should probably have |class CosetTable|.


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
https://github.com/sympy/sympy/pull/11140/files/5f6f6b3f66ceef5bd48b68bbcb2ebb61855b64f6#r64984707,
or mute the thread
https://github.com/notifications/unsubscribe/AHWt8Y6YwLsTBNvNU18_dFJu5hD_7sD8ks5qF959gaJpZM4IjQRZ.

@jksuom jksuom commented on an outdated diff May 28, 2016
sympy/combinatorics/fp_groups.py
+ [5, 2, 5, None], [None, 4, 1, 4]]
+ >>> coincidence(C, 0, 5, [x, x**-1, y, y**-1], p)
+ >>> C
+ [[1, 3, 1, 3],
+ [2, 0, 2, 0],
+ [3, 1, 3, 1],
+ [0, 2, 0, 2],
+ [0, 2, None, None],
+ [None, 4, 1, 4]]
+
+ """
+ l = 0
+ q = []
+ l = merge(alpha, beta, p, q, l)
+ i = 0
+ while i < l:
@jksuom
jksuom May 28, 2016 Member

Perhaps we could think of q as a queue (as the choice of letter seems to hint). This could then be while len(q) > 0:, and the next line could be gamma = q.pop(0). i and l would not be needed.

@jksuom jksuom commented on an outdated diff May 29, 2016
sympy/combinatorics/fp_groups.py
+ # their inverses), represented using "FpGroupElm"
+ # fp_grp: Finitely Presented Group with < X|R > as presentation.
+ # H: subgroup of fp_grp.
+ # NOTE: We start with H as being only a list of words in generators
+ # of "fp_grp". Since `.subgroup` method has not been implemented.
+
+ # sets the upper limit on the number of cosets generated during
+ # Coset Enumeration. "M" from Derek Holt's. It is supposed to be
+ # user definable.
+ DefaultMaxLimit = 500
+
+ def __init__(self, fp_grp, subgroup):
+ self.fp_group = fp_grp
+ self.subgroup = subgroup
+ self.p = [0]
+ self._A = list(chain.from_iterable((gen, gen**-1) \
@jksuom
jksuom May 29, 2016 edited Member

Perhaps this could be self.A, with no need for the property A.

@gxyd
Member
gxyd commented May 31, 2016

I have added the test file. Though haven't added extensive tests. Will resolve the .subword(i, i+1) issue we discussed.
Will seek next improve using the "HLT" method given in the "1973chwd" paper.

@gxyd gxyd and 1 other commented on an outdated diff Jun 1, 2016
sympy/combinatorics/fp_groups.py
+ gamma = -1
+ A = self.A
+ A_dict = self.A_dict
+ for alpha in self.omega:
+ gamma += 1
+ # a non-live coset is found with `gamma ~ alpha`
+ if gamma != alpha:
+ # replace α by γ in coset table
+ for x in A:
+ beta = self.table[alpha][A_dict[x]]
+ if beta == alpha:
+ beta = gamma
+ self.table[gamma][A.index(x)] = beta
+ self.table[beta][A.index(x**-1)] == gamma
+ # all the cosets in the table are live cosets
+ self.p = list(range(gamma + 1))
@gxyd
gxyd Jun 1, 2016 Member

Does this assignment look dangerous? (its change of id of p)

@jksuom
jksuom Jun 1, 2016 Member

I don't think so. p is not a part of the external interface.

@jksuom jksuom commented on an outdated diff Jun 2, 2016
sympy/combinatorics/fp_groups.py
+ >>> c = CosetTable(f, [x])
+
+ """
+ # alpha is an integer representing a "coset"
+ # since scanning can be in two cases
+ # 1. for alpha=0 and w in Y (i.e generating set of H)
+ # 2. alpha in omega (set of live cosets), w in R (relators)
+ f = alpha
+ i = 0
+ r = len(word)
+ # list of union of generators and their inverses
+ A_dict = self.A_dict
+ while i < r and self.table[f][A_dict[word.subword(i, i+1)]] is not None:
+ f = self.table[f][A_dict[word.subword(i, i+1)]]
+ i += 1
+ # can this be replaced with i == r ?
@jksuom
jksuom Jun 2, 2016 Member

I believe it could be.

@jksuom jksuom and 1 other commented on an outdated diff Jun 2, 2016
sympy/combinatorics/fp_groups.py
+ if i >= r:
+ if f != alpha:
+ # implement the "coincidence" routine on Pg 158 of Handbook.
+ self.coincidence(f, alpha)
+ return
+ b = alpha
+ j = r - 1
+ while j >= i and self.table[b][A_dict[word.subword(j, j+1)**-1]] is not None:
+ b = self.table[b][A_dict[word.subword(j, j+1).inverse()]]
+ j -= 1
+ if j < i:
+ # we have an incorrect completed scan with coincidence f ~ b
+ # run the "coincidence" routine
+ # line: We assume that before each call of COINCIDENCE, for α ∈ [1..n],
+ # we have p[α]=α iff α ∈ Ω.
+ self.p.extend(list(range(len(self))))
@jksuom
jksuom Jun 2, 2016 Member

This line seems odd to me.

@gxyd
gxyd Jun 2, 2016 Member

Yes, I know this line is to be removed. The other method scan_and_fill doesn't have this line.

@jksuom jksuom commented on an outdated diff Jun 2, 2016
sympy/combinatorics/fp_groups.py
+ else:
+ self.define(f, word.subword(i, i+1))
+ # loop until it has filled the alpha row in the table.
+ i_A += 1
+
+ def look_ahead(self):
+ R = self.fp_group.relators()
+ p = self.p
+ for beta in p:
+ if p[beta] == beta:
+ # complete scan all relators under all cosets(obviously live)
+ # without making new definitions
+ for w in R:
+ self.scan(beta, w)
+ if p[beta] < beta:
+ continue
@jksuom
jksuom Jun 2, 2016 Member

What does this do? Should this be break?

@jksuom jksuom commented on an outdated diff Jun 3, 2016
sympy/combinatorics/fp_groups.py
+ def scan_and_fill(self, alpha, word):
+ f = alpha
+ i = 0
+ r = len(word)
+ A_dict = self.A_dict
+ l_A = len(A_dict)
+ i_A = 0
+ while i_A < l_A:
+ # do the forward scanning
+ while i < r and self.table[f][A_dict[word.subword(i, i+1)]] is not None:
+ f = self.table[f][A_dict[word.subword(i, i+1)]]
+ i += 1
+ if i >= r:
+ if f != alpha:
+ self.coincidence(f, alpha)
+ return
@jksuom
jksuom Jun 3, 2016 Member

This return should probably be indented the same as if f .... So we are finished in any case.

@jksuom jksuom commented on an outdated diff Jun 3, 2016
sympy/combinatorics/fp_groups.py
+ self.table[nu][A_dict_inv[x]] = mu
+
+ # method used in the HLT strategy
+ def scan_and_fill(self, alpha, word):
+ f = alpha
+ i = 0
+ r = len(word)
+ A_dict = self.A_dict
+ A_dict_inv = self.A_dict_inv
+ l_A = len(A_dict)
+ i_A = 0
+ b = alpha
+ j = r - 1
+ while i_A < l_A:
+ # do the forward scanning
+ while i < r and self.table[f][A_dict[word[i]]] is not None:
@jksuom
jksuom Jun 3, 2016 Member

This could probably be while i <= j and ... to end the loop if the indices meet.

@jksuom jksuom commented on an outdated diff Jun 3, 2016
sympy/combinatorics/fp_groups.py
+ def scan_and_fill(self, alpha, word):
+ f = alpha
+ i = 0
+ r = len(word)
+ A_dict = self.A_dict
+ A_dict_inv = self.A_dict_inv
+ l_A = len(A_dict)
+ i_A = 0
+ b = alpha
+ j = r - 1
+ while i_A < l_A:
+ # do the forward scanning
+ while i < r and self.table[f][A_dict[word[i]]] is not None:
+ f = self.table[f][A_dict[word[i]]]
+ i += 1
+ if i >= r:
@jksuom
jksuom Jun 3, 2016 Member

And here i > j.

@jksuom jksuom commented on an outdated diff Jun 3, 2016
sympy/combinatorics/fp_groups.py
+ f = alpha
+ i = 0
+ r = len(word)
+ A_dict = self.A_dict
+ A_dict_inv = self.A_dict_inv
+ l_A = len(A_dict)
+ i_A = 0
+ b = alpha
+ j = r - 1
+ while i_A < l_A:
+ # do the forward scanning
+ while i < r and self.table[f][A_dict[word[i]]] is not None:
+ f = self.table[f][A_dict[word[i]]]
+ i += 1
+ if i >= r:
+ if f != alpha:
@jksuom
jksuom Jun 3, 2016 Member

Here we would then have b instead of the fixed alpha.

@jksuom jksuom commented on an outdated diff Jun 5, 2016
sympy/combinatorics/fp_groups.py
+ if index % 2 == 0:
+ self.A_dict_inv[x] = self.A_dict[x] + 1
+ else:
+ self.A_dict_inv[x] = self.A_dict[x] - 1
+ self.deduction_stack = []
+
+ @property
+ def omega(self):
+ """Set of live cosets
+ """
+ return [coset for coset in range(len(self.p)) if self.p[coset] == coset]
+
+ @property
+ def n(self):
+ """The number `n` represents the largest number that has been used so
+ far for a live coset
@jksuom
jksuom Jun 5, 2016 Member

It seems that n is actually not used for a live coset because of +1. Maybe this should be something like the length of the sublist containing the live cosets.

@jksuom jksuom and 1 other commented on an outdated diff Jun 5, 2016
sympy/combinatorics/fp_groups.py
+
+ @property
+ def n(self):
+ """The number `n` represents the largest number that has been used so
+ far for a live coset
+ """
+ return max(self.omega) + 1
+
+ # checks whether the Coset Table is complete or not
+ def is_complete(self):
+ return not None in flatten(self.table)
+
+ # Pg. 153
+ def define(self, alpha, x):
+ A = self.A
+ if self.n == CosetTableDefaultMaxLimit:
@jksuom
jksuom Jun 5, 2016 Member

Maybe len(self.table) should be taken instead of self.n or else this should be an inequality. It is conceivable that the table could grow bigger than the limit with the tail containing only non-live cosets, and then a new live beta would be added making self.n > CosetTableDefaultMaxLimit.

@gxyd
gxyd Jun 9, 2016 Member

I agree with making this len(self.table).

@jksuom jksuom commented on an outdated diff Jun 5, 2016
sympy/combinatorics/fp_groups.py
+ else:
+ self.table[mu][A_dict[x]] = nu
+ self.table[nu][A_dict_inv[x]] = mu
+
+ # method used in the HLT strategy
+ def scan_and_fill(self, alpha, word):
+ A_dict = self.A_dict
+ A_dict_inv = self.A_dict_inv
+ r = len(word)
+ l_A = len(A_dict)
+ f = alpha
+ i = 0
+ i_A = 0
+ b = alpha
+ j = r - 1
+ while i_A < l_A:
@jksuom
jksuom Jun 5, 2016 Member

This could probably be while True:. The loop is expected to run until i > j.

@jksuom jksuom commented on an outdated diff Jun 5, 2016
sympy/combinatorics/fp_groups.py
+ self.deduction_stack.append((f, word[i]))
+ else:
+ self.define_f(f, word[i])
+ # loop until it has filled the α row in the table.
+ i_A += 1
+
+ def look_ahead(self):
+ R = self.fp_group.relators()
+ p = self.p
+ for beta in self.omega:
+ # complete scan all relators under all cosets(obviously live)
+ # without making new definitions
+ for w in R:
+ self.scan(beta, w)
+ if p[beta] < beta:
+ continue
@jksuom
jksuom Jun 5, 2016 Member

This could probably be break.

@gxyd gxyd commented on an outdated diff Jun 10, 2016
sympy/combinatorics/fp_groups.py
if gamma != alpha:
# replace α by γ in coset table
for x in A:
beta = self.table[alpha][A_dict[x]]
- if beta == alpha:
@gxyd
gxyd Jun 10, 2016 edited Member

This line introduced the bug, its not required as the below this does the task. I have now verified "Mennicke group" (n=1, n=2), Cox group, "BH Neuman", "Burnside groups" (some more groups) from GAP for exact coset value (not just index) and these seem to be working good.

@gxyd
Member
gxyd commented Jun 10, 2016 edited

Now, apart from a few printing issues. I don't think much major changes are necessary in this PR. Perhaps the "Felsch" strategy tests are too slow.

@jksuom jksuom commented on an outdated diff Jun 10, 2016
sympy/combinatorics/fp_groups.py
+ if index % 2 == 0:
+ self.A_dict_inv[x] = self.A_dict[x] + 1
+ else:
+ self.A_dict_inv[x] = self.A_dict[x] - 1
+ self.deduction_stack = []
+
+ @property
+ def omega(self):
+ """Set of live cosets
+ """
+ return [coset for coset in range(len(self.p)) if self.p[coset] == coset]
+
+ @property
+ def n(self):
+ """The number `n` represents length of the sublist containing the live
+ cosets far for a live coset.
@jksuom
jksuom Jun 10, 2016 Member

Maybe "The number 'n' represents the length of the sublist containing the live cosets".

@jksuom jksuom commented on an outdated diff Jun 10, 2016
sympy/combinatorics/fp_groups.py
+ def coincidence_f(self, alpha, beta):
+ """
+ """
+ A_dict = self.A_dict
+ A_dict_inv = self.A_dict_inv
+ p = self.p
+ l = 0
+ # behaves as a queue
+ q = []
+ self.merge(alpha, beta, q)
+ while len(q) > 0:
+ gamma = q.pop(0)
+ # comment by Kalevi, this is already done by p[v] = mu
+ # del C[gamma]
+ # commenting this out
+ # omega = omega - set(gamma)
@jksuom
jksuom Jun 10, 2016 Member

I think these comments could be dropped now. It seems that the deletion was some kind of typo in the original pseudocode.

@jksuom jksuom commented on an outdated diff Jun 10, 2016
sympy/combinatorics/fp_groups.py
+ C = CosetTable(fp_grp, Y)
+ R = fp_grp.relators()
+ A_dict = C.A_dict
+ A_dict_inv = C.A_dict_inv
+ p = C.p
+ for w in Y:
+ C.scan_and_fill(0, w)
+ alpha = 0
+ while alpha < C.n:
+ if p[alpha] == alpha:
+ for w in R:
+ C.scan_and_fill(alpha, w)
+ if p[alpha] < alpha:
+ break
+ if p[alpha] < alpha:
+ continue
@jksuom
jksuom Jun 10, 2016 Member

If p[alpha] < alpha, the while loop is repeated and only then alpha += 1 is executed. Changing continue to pass and adding else: before the for loop would increment alpha straight away.

gxyd added some commits May 20, 2016
@gxyd gxyd ``FpGroup`` implementation in SymPy 8f73ebb
@gxyd gxyd cyclic reduction methods added 44c5def
@gxyd gxyd add methods "define" and "scan" from Derek Holt 2c7e8aa
@gxyd gxyd Add the "Coicidence" procedure caae2fc
@gxyd gxyd Add "scan_and_fill" method 79892ec
@gxyd gxyd Add methods for Felsch strategy b998aa8
@gxyd gxyd Add more docs f4ef641
@gxyd gxyd changes to "coincidence" routine 3b2ee6e
@gxyd gxyd Add example for "scan", code fix for Coincidence routine
Add the complete step of "Coincidence" working and "l" assignment
e455077
@gxyd gxyd Add the example 5.4 from Derek Holt 3ef9646
@gxyd gxyd Added the example for "scan" method from original todd-coxeter paper 566ac12
@gxyd gxyd Make CosetTable a class, add examples for HLT strategy bf47cb7
@gxyd gxyd CosetTable is "not" a subclass of `list` 2200611
@gxyd gxyd loop `scan_and_fill` until it has filled the alpha row in the table
also add examples for the HLT enumeration method
0e0f8cf
@gxyd gxyd Add cyclic_conjugates method for FreeGroupElements 6afbd4a
@gxyd gxyd use "q" as a queue in "coincidence" routine
This improves the efficiency (is logically clear):
```
In [1]: F, a, b = free_group("a, b")
In [2]: Cox = FpGroup(F, [a**6, b**6, (a*b)**2, (a**2*b**2)**2, (a**3*b**3)**5])

"without" using "q" as queue
In [3]: %timeit f()
Out [3]: 1 loop, best of 3: 6.85 s per loop

"with" using "q" as queue
In [4]: %timeit f()
1 loop, best of 3: 6.6 s per loop
```
fbd72ad
@gxyd gxyd use "A_dict" instead of "A.index" for finding index of (gen, gen^-1) 015c1c1
@gxyd gxyd Add test file for "Coset Enumeration" aa80f96
@gxyd gxyd changes in Coset Table based method ec86008
@gxyd gxyd Add "Switch" method,also add "define_f"(for Felsch specific requireme…
…nts)
fc651b2
@gxyd gxyd Make compress() routine work fine 6109273
@gxyd gxyd fix "standardize" method of Coset Table (for some still raises index …
…error)
701b2a6
@gxyd gxyd FreeGroupElm -> FreeGroupElement (Aaron's comment fix) a9b4fcf
@gxyd gxyd Add code for `coset_enumeration_c` 8cc4120
@gxyd gxyd "stadardization" of a Coset Table 505d09b
@gxyd gxyd remove wrong-code line from "scan" routine dabc42b
@gxyd gxyd Make indexing of word to return a generator or its inverse
```
>>> F, x, y = free_group("x, y")
>>> w = x**2*y**-4*x**5
>>> w[1]
x
>>> w[4]
y**-1
```
Also re-indent the "return" statement (according to comment) by @jksuom
[https://github.com/sympy/sympy/pull/11140/files/f67951c394b7102a6899696e95c913f811f72aec#r65673875]
4b1d2d5
@gxyd gxyd In `scan_and_fill` set first defition of "b" and "j" outisde loop
This makes `scan_and_fill` efficient, since it apparently always scans
to the end of a word even if part of the end has already been scanned
backwards.
So avoid re-scanning of the part of word
a1b58bb
@gxyd gxyd change the comparison of cosets in `scan_and_fill` 255119d
@gxyd gxyd simplification to a tuple of "chi" e880867
@gxyd gxyd Address Aaron's comment from PR#11350, Felsch improvements dd8348e
@gxyd gxyd changes in methods for Felsch strategy, add doctest for Felsch strategy ea64060
@gxyd gxyd documentation and code fixes related to coset enumeration 1fe7faa
@gxyd gxyd fix the bug in compress() routine
Now verified every coset of table with GAP, seems to be working
fine.
bd31e1f
@gxyd gxyd Add modifications, tests for Felsch strategy
Add tests for Feslch strategy and improvements
72bdb8f
@gxyd gxyd delete un-necessary comments from fp_groups.py 7218fc6
@gxyd gxyd changes in printing and combined the tests for two strategies dfced7b
@gxyd gxyd Make FpGroup, CosetTable non-Basic just like FpGroup 6a4b023
@gxyd gxyd changed the title from [WIP] ``FpGroup`` implementation in SymPy to ``FpGroup`` implementation in SymPy Jun 11, 2016
@jksuom jksuom merged commit 1bf84aa into sympy:master Jun 13, 2016

1 check passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
@gxyd gxyd deleted the gxyd:implementation_FpGroup branch Jun 16, 2016
@gxyd gxyd restored the gxyd:implementation_FpGroup branch Aug 16, 2016
@gxyd gxyd deleted the gxyd:implementation_FpGroup branch Aug 24, 2016
@skirpichev skirpichev referenced this pull request in diofant/diofant Dec 7, 2016
Open

[wip] Backport some sympy fixes #390

81 of 99 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment