Ticket #10976: trac_10976.8.patch

File trac_10976.8.patch, 4.2 KB (added by was, 9 years ago)

folded the two patches into one; added proper "Trac #10976" to commit message.

  • sage/groups/perm_gps/permgroup.py

    # HG changeset patch
    # User Christopher Swenson <chris@caswenson.com>
    # Date 1330946247 18000
    # Node ID d7365d978d5f8e96a4f5953300f1101b811213cf
    # Parent  68e89260148df131fec1708338ceba3ea964b2bb
    Trac #10976: Fixed the order of certain permutation groups to be much faster to compute.
    
    diff --git a/sage/groups/perm_gps/permgroup.py b/sage/groups/perm_gps/permgroup.py
    a b  
    9090
    9191- Nicolas Borie (2009): Added orbit, transversals, stabiliser and strong_generating_system methods
    9292
     93- Christopher Swenson (2012): Added a special case to compute the order efficiently.
     94  (This patch Copyright 2012 Google Inc. All Rights Reserved. )
     95
    9396REFERENCES:
    9497
    9598- Cameron, P., Permutation Groups. New York: Cambridge University
     
    132135from sage.misc.package import is_package_installed
    133136from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
    134137from sage.categories.all import FiniteEnumeratedSets
     138from sage.functions.other import factorial
    135139
    136140def load_hap():
    137141    """
     
    12891293        return '\\langle ' + \
    12901294               ', '.join([x._latex_() for x in self.gens()]) + ' \\rangle'
    12911295
     1296    def _order(self):
     1297        """
     1298        This handles a few special cases of computing the subgroup order much
     1299        faster than GAP.
     1300
     1301        This currently operates very quickly for stabilizer subgroups of
     1302        permutation groups, for one.
     1303
     1304        Will return None if the we could not easily compute it.
     1305
     1306        Author: Christopher Swenson
     1307
     1308        EXAMPLES::
     1309
     1310            sage: SymmetricGroup(10).stabilizer(4)._order()
     1311            362880
     1312            sage: SymmetricGroup(10).stabilizer(4).stabilizer(5)._order()
     1313            40320
     1314            sage: SymmetricGroup(200).stabilizer(100)._order() == factorial(199) # this should be very fast
     1315            True
     1316       
     1317        TESTS::
     1318
     1319            sage: [SymmetricGroup(n).stabilizer(1)._gap_().Size() for n in [4..10]]
     1320            [6, 24, 120, 720, 5040, 40320, 362880]
     1321            sage: [SymmetricGroup(n).stabilizer(1)._order() for n in [4..10]]
     1322            [6, 24, 120, 720, 5040, 40320, 362880]
     1323        """
     1324        gens = self.gens()
     1325        # This special case only works with more than 1 generator.
     1326        if not gens or len(gens) < 2:
     1327            return None
     1328        # Special case: certain subgroups of the symmetric group for which Gap reports
     1329        # generators of the form ((1, 2), (1, 3), ...)
     1330        # This means that this group is isomorphic to a smaller symmetric group
     1331        # S_n, where n is the number of generators supported.
     1332        #
     1333        # The code that follows checks that the following assumptions hold:
     1334        #     * All generators are transpositions (i.e., permutations
     1335        #     that switch two elements and leave everything else fixed),
     1336        #     * All generators share a common element.
     1337        #
     1338        # We then know that this group is isomorphic to S_n,
     1339        # and therefore its order is n!.
     1340       
     1341        # Check that all generators are order 2 and have length-1 cycle tuples.
     1342        for g in gens:
     1343            if g.order() != 2:
     1344                return None
     1345            if len(g.cycle_tuples()) != 1:
     1346                return None
     1347        # Find the common element.
     1348        g0 = gens[0].cycle_tuples()[0]
     1349        g1 = gens[1].cycle_tuples()[0]
     1350        a, b = g0
     1351        if a not in g1 and b not in g1:
     1352            return None
     1353        if a in g1:
     1354            elem = a
     1355        else:
     1356            elem = b
     1357        # Count the number of unique elements in the generators.
     1358        unique = set()
     1359        for g in gens:
     1360            a, b = g.cycle_tuples()[0]
     1361            if a != elem and b != elem:
     1362                return None
     1363            unique.add(a)
     1364            unique.add(b)
     1365        # Compute the order.
     1366        return factorial(len(unique))
     1367
    12921368    def order(self):
    12931369        """
    12941370        Return the number of elements of this group.
     
    13071383        """
    13081384        if not self.gens() or self.gens() == [self(1)]:
    13091385            return Integer(1)
     1386        subgroup_order = self._order()
     1387        if subgroup_order is not None:
     1388          return subgroup_order
    13101389        return Integer(self._gap_().Size())
    13111390
    13121391    def random_element(self):