Repository: sympy/sympy

Issue:
coset_enumeration_c raises "AttributeError: 'CosetTable' object has no attribute 'lookahead'"
```
gaurav@stallman:~/Public/sympy$ python3
Python 3.4.3 (default, Oct 14 2015, 20:28:29) 
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from sympy import *
>>> from sympy.combinatorics.free_group import free_group
>>> from sympy.combinatorics.fp_groups import FpGroup, coset_enumeration_c, coset_enumeration_r
>>> F, a, b, c = free_group("a, b, c")
>>> f = FpGroup(F, [a**11, b**5, c**4, (a*c)**3, b**2*c**-1*b**-1*c, a**4*b**-1*a**-1*b])
>>> H = [c, b, c**2]
>>> C = coset_enumeration_c(f, H)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/gaurav/Public/sympy/sympy/combinatorics/fp_groups.py", line 793, in coset_enumeration_c
    C.process_deductions(R_c_list[C.A_dict[x]], R_c_list[C.A_dict_inv[x]])
  File "/home/gaurav/Public/sympy/sympy/combinatorics/fp_groups.py", line 466, in process_deductions
    self.lookahead()
AttributeError: 'CosetTable' object has no attribute 'lookahead'
```

Discussion:

Patch:
diff --git a/sympy/combinatorics/fp_groups.py b/sympy/combinatorics/fp_groups.py
index e4a7a112c3..8be1c0b8eb 100644
--- a/sympy/combinatorics/fp_groups.py
+++ b/sympy/combinatorics/fp_groups.py
@@ -1,6 +1,5 @@
 # -*- coding: utf-8 -*-
 from __future__ import print_function, division
-
 from sympy.core.basic import Basic
 from sympy.core import Symbol, Mod
 from sympy.printing.defaults import DefaultPrinting
@@ -86,12 +85,6 @@ def __str__(self):
 #                           COSET TABLE                                       #
 ###############################################################################
 
-# 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.
-CosetTableDefaultMaxLimit = 4096000
-max_stack_size = 500
-
 class CosetTable(DefaultPrinting):
     # coset_table: Mathematically a coset table
     #               represented using a list of lists
@@ -118,6 +111,13 @@ class CosetTable(DefaultPrinting):
     "Implementation and Analysis of the Todd-Coxeter Algorithm"
 
     """
+    # default limit for the number of cosets allowed in a
+    # coset enumeration.
+    coset_table_max_limit = 4096000
+    # maximun size of deduction stack above or equal to
+    # which it is emptied
+    max_stack_size = 500
+
     def __init__(self, fp_grp, subgroup):
         self.fp_group = fp_grp
         self.subgroup = subgroup
@@ -174,7 +174,7 @@ def is_complete(self):
     # Pg. 153 [1]
     def define(self, alpha, x):
         A = self.A
-        if len(self.table) == CosetTableDefaultMaxLimit:
+        if len(self.table) == CosetTable.coset_table_max_limit:
             # abort the further generation of cosets
             return
         self.table.append([None]*len(A))
@@ -186,7 +186,7 @@ def define(self, alpha, x):
 
     def define_f(self, alpha, x):
         A = self.A
-        if self.table == CosetTableDefaultMaxLimit:
+        if len(self.table) == CosetTable.coset_table_max_limit:
             # abort the further generation of cosets
             return
         self.table.append([None]*len(A))
@@ -446,7 +446,6 @@ def scan_and_fill_f(self, alpha, word):
             else:
                 self.define_f(f, word[i])
 
-    # currently not used anywhere
     def look_ahead(self):
         R = self.fp_group.relators()
         p = self.p
@@ -462,8 +461,8 @@ def look_ahead(self):
     def process_deductions(self, R_c_x, R_c_x_inv):
         p = self.p
         while len(self.deduction_stack) > 0:
-            if len(self.deduction_stack) >= max_stack_size:
-                self.lookahead()
+            if len(self.deduction_stack) >= CosetTable.max_stack_size:
+                self.look_ahead()
                 del self.deduction_stack[:]
             else:
                 alpha, x = self.deduction_stack.pop()


Test patch:
diff --git a/sympy/combinatorics/tests/test_fp_groups.py b/sympy/combinatorics/tests/test_fp_groups.py
index d567cf2cd4..5c8d8fced3 100644
--- a/sympy/combinatorics/tests/test_fp_groups.py
+++ b/sympy/combinatorics/tests/test_fp_groups.py
@@ -691,6 +691,27 @@ def test_coset_enumeration():
     assert C_c.table == table4
 
 
+def test_look_ahead():
+    # Section 3.2 [Test Example] Example (d) from [2]
+    F, a, b, c = free_group("a, b, c")
+    f = FpGroup(F, [a**11, b**5, c**4, (a*c)**3, b**2*c**-1*b**-1*c, a**4*b**-1*a**-1*b])
+    H = [c, b, c**2]
+    table0 = [[1, 2, 0, 0, 0, 0],
+              [3, 0, 4, 5, 6, 7],
+              [0, 8, 9, 10, 11, 12],
+              [5, 1, 10, 13, 14, 15],
+              [16, 5, 16, 1, 17, 18],
+              [4, 3, 1, 8, 19, 20],
+              [12, 21, 22, 23, 24, 1],
+              [25, 26, 27, 28, 1, 24],
+              [2, 10, 5, 16, 22, 28],
+              [10, 13, 13, 2, 29, 30]]
+    CosetTable.max_stack_size = 10
+    C_c = coset_enumeration_c(f, H)
+    C_c.compress(); C_c.standardize()
+    assert C_c.table[: 10] == table0
+
+
 def test_low_index_subgroups():
     F, x, y = free_group("x, y")