Ticket #11880: trac_11880-moving_methods.patch

File trac_11880-moving_methods.patch, 22.3 KB (added by ncohen, 8 years ago)
  • sage/graphs/isgci.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1329654265 -3600
    # Node ID d84d80415d829517538b92a21dfb3db973cd4d80
    # Parent  d141e5f37a82e4c76aa75ef6510d5b838ccb2cc9
    GraphClasses - Moving some methods at a different place in the file
    
    diff --git a/sage/graphs/isgci.py b/sage/graphs/isgci.py
    a b  
    309309
    310310_XML_FILE = "isgci_sage.xml"
    311311
    312 def _download_db():
    313     r"""
    314     Downloads the current version of the ISGCI db
    315 
    316     EXAMPLE::
    317 
    318         sage: sage.graphs.isgci._download_db() # Not tested -- requires internet
    319     """
    320 
    321     from sage.misc.misc import SAGE_TMP
    322     import urllib2
    323     u = urllib2.urlopen('http://www.graphclasses.org/data.zip')
    324     localFile = open(SAGE_TMP+'isgci.zip', 'w')
    325     localFile.write(u.read())
    326     localFile.close()
    327     import os, zipfile
    328     z = zipfile.ZipFile(SAGE_TMP+'isgci.zip')
    329     z.extract(_XML_FILE, SAGE_TMP)
    330 
    331 def _create_db():
    332     r"""
    333     Parses the ISGCI database and returns its content as Python objects.
    334 
    335     EXAMPLE::
    336 
    337         sage: sage.graphs.isgci._create_db() # Not tested -- requires internet
    338     """
    339     from sage.misc.misc import SAGE_TMP
    340     import xml.dom.minidom
    341     from xml.dom.minidom import Node
    342 
    343     # This method is there to parse the XML file containing the ISGCI
    344     # database. It is admittedly not very pretty, but it builds the class we
    345     # want from the XML file and that's more or less all we ask it to do :-p
    346 
    347     doc = xml.dom.minidom.parse(SAGE_TMP+_XML_FILE)
    348 
    349     classes = {}
    350 
    351     giveme = lambda x,y : str(x.getAttribute(y))
    352 
    353     for node in doc.getElementsByTagName("GraphClass"):
    354         ID = str(node.getAttribute("id"))
    355         Dl = {}
    356         smallgraph = []
    357         Dl["ID"] = giveme(node, "id")
    358         problems = {}
    359         for node2 in node.childNodes:
    360             name = str(node2.nodeName)
    361             if name == "name":
    362                 Dl[name] = str(node2.childNodes[0].nodeValue)
    363 
    364             elif name ==  "smallgraph":
    365                 smallgraph.append(str(node2.childNodes[0].nodeValue))
    366 
    367             elif name == "problem":
    368                 problems[giveme(node2, "name")] = giveme(node2, "complexity")
    369 
    370         Dl["problems"] = problems
    371 
    372         if smallgraph:
    373             Dl["smallgraph"] = smallgraph
    374 
    375         if giveme(node, "type"):
    376             Dl["type"] = giveme(node, "type")
    377 
    378 
    379         classes[giveme(node, "id")] = Dl
    380 
    381     inclusions = []
    382     for node in doc.getElementsByTagName("incl"):
    383         Dl = {}
    384         for name in ["proper", "confidence", "super", "sub"]:
    385             if giveme(node, name):
    386                 Dl[name] = giveme(node, name)
    387 
    388         for node2 in node.childNodes:
    389             name = str(node2.nodeName)
    390             if name == "ref":
    391                 Dl[name] = str(node2.childNodes[0].nodeValue)
    392 
    393         inclusions.append(Dl)
    394 
    395     return classes, inclusions
    396 
    397 def update_db(verbose = False):
    398     r"""
    399     Updates the ISGCI database by downloading the latest version from internet.
    400 
    401     This method downloads the ISGCI database from the website `GraphClasses.org
    402     <http://www.graphclasses.org/>`_.
    403 
    404     It then extracts the zip file and parses its XML content, which is
    405     stored as two ``.sobj`` files, the first one representing the
    406     graph classes, and the second representing their inclusions.
    407 
    408     Depending on the credentials of the user running Sage when this
    409     command is run, one attempt is made at saving the result in Sage's
    410     directory so that all users can benefit from it. If the
    411     credentials are not sufficient, the ``.sobj`` files are saved
    412     instead in the user's directory. #TODO: be more specific about where in the user's directory?
    413 
    414     INPUT:
    415 
    416     - ``verbose`` -- a boolean (default: False); whether to output
    417       information of the update process
    418 
    419     EXAMPLE::
    420 
    421         sage: sage.graphs.isgci.update_db() # Not tested -- requires internet
    422     """
    423     from sage.misc.misc import SAGE_TMP, SAGE_ROOT, SAGE_LOCAL, SAGE_DB
    424     global classes, inclusions, inclusion_digraph
    425 
    426     try:
    427         _download_db()
    428     except:
    429         # TODO: as such, the user won't get the, probably more
    430         # informative, error message thrown by download_db. What about
    431         # not catching it? Or at least retransmitting the error
    432         # message?
    433         raise Exception("There has been a problem while downloading or unzipping the ISGCI database O_o")
    434 
    435 
    436     if verbose:
    437         print "Database downloaded"
    438 
    439     classes, inclusions = _create_db()
    440 
    441     if verbose:
    442         print "XML file converted to Python dictionaries"
    443 
    444 
    445     from sage.all import save
    446 
    447     # Trying to save to Sage's directory
    448     try:
    449         save(classes, SAGE_ROOT+'/data/graphs/isgci_classes.sobj')
    450         save(inclusions, SAGE_ROOT+'/data/graphs/isgci_inclusions.sobj')
    451         inclusions = inclusion_digraph = None
    452         classes = {}
    453         if verbose:
    454             print "Database saved to .sobj files in "+SAGE_ROOT+'/data/graphs/'
    455 
    456         return
    457     except IOError:
    458         if verbose:
    459             # TODO: improve!
    460             print "Could not save save database in "+SAGE_ROOT+'/data/graphs/'
    461         pass
    462 
    463     # Trying to save to the user's home directory
    464     try:
    465         save(classes, SAGE_DB+"/isgci_classes.sobj")
    466         save(inclusions, SAGE_DB+"/isgci_inclusions.sobj")
    467         classes = inclusions = inclusion_digraph = None
    468         if verbose:
    469             print "Database saved to .sobj files in "+SAGE_DB
    470 
    471         return
    472 
    473     except IOError:
    474         pass
    475 
    476     # TODO: as above: don't hide the more informative error message
    477     # from the system
    478 
    479     # Gloops !
    480     raise Exception("Sage is unable to write the files to your"+
    481                     "computer ! This shouldn't have happened. "+
    482                     "Could you report the bug ? ;-)")
    483 
    484 def get_ISGCI():
    485     r"""
    486     Returns the contents of the ISGCI database.
    487 
    488     This method is mostly for internal use, but often provides useful
    489     information during debugging operations.
    490 
    491     OUTPUT:
    492 
    493     A pair ``(classes, inclusions)`` where ``classes`` is a dict of dict, and
    494     ``inclusions`` is a list of dicts.
    495 
    496     .. NOTE::
    497 
    498         This method returns the data contained in the most recent ISGCI database
    499         present on the computer. See :func:`update_db` to update the latter.
    500 
    501     EXAMPLE::
    502 
    503         sage: classes, inclusions = sage.graphs.isgci.get_ISGCI()
    504     """
    505 
    506     import os.path
    507     from sage.all import save, load
    508     from sage.misc.misc import SAGE_TMP, SAGE_ROOT, SAGE_LOCAL, SAGE_DB
    509 
    510     # TODO: or systematically use the user's version if it exists,
    511     # throwing a warning if it is not the most recent?
    512 
    513     try:
    514         open(SAGE_DB+"/isgci_classes.sobj")
    515 
    516         # Which copy is the most recent on the disk ?
    517         if (os.path.getmtime(SAGE_DB+"/isgci_classes.sobj") >
    518             os.path.getmtime(SAGE_ROOT+"/data/graphs/isgci_classes.sobj")):
    519 
    520             classes = load(SAGE_DB+"/isgci_classes.sobj")
    521             inclusions = load(SAGE_DB+"/isgci_inclusions.sobj")
    522 
    523         else:
    524             classes = load(SAGE_ROOT+"/data/graphs/isgci_classes.sobj")
    525             inclusions = load(SAGE_ROOT+"/data/graphs/isgci_inclusions.sobj")
    526 
    527     except IOError as e:
    528         # No local version of the file exists
    529         classes = load(SAGE_ROOT+"/data/graphs/isgci_classes.sobj")
    530         inclusions = load(SAGE_ROOT+"/data/graphs/isgci_inclusions.sobj")
    531 
    532     return classes, inclusions
    533 
    534 def show_all():
    535     r"""
    536     Prints all graph classes stored in ISGCI
    537 
    538     EXAMPLE::
    539 
    540         sage: sage.graphs.isgci.show_all()
    541         ID        | name                                     | type                 | smallgraph
    542         ----------------------------------------------------------------------------------------------------------------------
    543         gc_309    | $K_4$--minor--free                       | base                 |
    544         gc_541    | $N^*$                                    | base                 |
    545         gc_215    | $N^*$--perfect                           | base                 |
    546         gc_5      | $P_4$--bipartite                         | base                 |
    547         gc_3      | $P_4$--brittle                           | base                 |
    548         gc_6      | $P_4$--comparability                     | base                 |
    549         gc_7      | $P_4$--extendible                        | base                 |
    550         ...
    551     """
    552     global classes
    553     _load_ISGCI_if_not_loaded()
    554     classes_list = classes.values()
    555 
    556     # We want to print the different fields, and this dictionary stores the
    557     # maximal number of characters of each field.
    558     MAX = {
    559         "ID" : 0,
    560         "type" : 0,
    561         "smallgraph": 0,
    562         "name": 0
    563         }
    564 
    565     # We sort the classes alphabetically, though we would like to display the
    566     # meaningful classes at the top of the list
    567     classes_list.sort(key = lambda x:x.get("name","zzzzz")+"{0:4}".format(int(x["ID"].split('_')[1])))
    568 
    569     # Maximum width of a field
    570     MAX_LEN = 40
    571 
    572     # Computing te max of each field with the database
    573     for key in MAX:
    574         MAX[key] = len(max(map(lambda x:str(x.get(key,"")),classes_list), key = len))
    575 
    576     # At most MAX characters per field
    577     for key, length in MAX.iteritems():
    578         MAX[key] = min(length, MAX_LEN)
    579 
    580     # Head of the table
    581     print ("{0:"+str(MAX["ID"])+"} | {1:"+str(MAX["name"])+"} | {2:"+str(MAX["type"])+"} | {3:"+str(MAX["smallgraph"])+"}").format("ID", "name", "type", "smallgraph")
    582     print "-"*(sum(MAX.values())+9)
    583 
    584     # Entries
    585     for entry in classes_list:
    586         ID = entry.get("ID","")
    587         name = entry.get("name","")
    588         type = entry.get("type","")
    589         smallgraph = entry.get("smallgraph","")
    590         print ("{0:"+str(MAX["ID"])+"} | {1:"+str(MAX["name"])+"} | {2:"+str(MAX["type"])+"} | ").format(ID, name[:MAX_LEN], type[:MAX_LEN])+str(smallgraph)[:MAX_LEN]
    591 
    592 def _load_ISGCI_if_not_loaded():
    593     r"""
    594     Load ISGI if not loaded already
    595 
    596     This is here to avoid having to load the db when Sage starts
    597     """
    598     global classes, inclusions
    599     if classes == {}:
    600         classes, inclusions = get_ISGCI()
    601 
    602 def _build_inclusion_digraph_if_not_built():
    603     r"""
    604     Builds the class digraph
    605     """
    606     global classes, inclusions, inclusion_digraph
    607 
    608     if not (inclusion_digraph is None):
    609         return
    610 
    611     _load_ISGCI_if_not_loaded()
    612 
    613     from sage.graphs.digraph import DiGraph
    614     inclusion_digraph = DiGraph()
    615     inclusion_digraph.add_vertices(classes.keys())
    616 
    617     for edge in inclusions:
    618         if edge.get("confidence","") == "unpublished":
    619             continue
    620 
    621         inclusion_digraph.add_edge(edge['super'], edge['sub'])
    622 
    623     inclusions = []
    624 
    625 
    626312class GraphClass(SageObject, UniqueRepresentation):
    627313    r"""
    628314    An instance of this class represents a Graph Class, matching some entry in
     
    782468        _build_inclusion_digraph_if_not_built()
    783469        return inclusion_digraph
    784470
     471    def _download_db():
     472        r"""
     473        Downloads the current version of the ISGCI db
     474
     475        EXAMPLE::
     476
     477            sage: sage.graphs.isgci._download_db() # Not tested -- requires internet
     478        """
     479
     480        from sage.misc.misc import SAGE_TMP
     481        import urllib2
     482        u = urllib2.urlopen('http://www.graphclasses.org/data.zip')
     483        localFile = open(SAGE_TMP+'isgci.zip', 'w')
     484        localFile.write(u.read())
     485        localFile.close()
     486        import os, zipfile
     487        z = zipfile.ZipFile(SAGE_TMP+'isgci.zip')
     488        z.extract(_XML_FILE, SAGE_TMP)
     489
     490    def _create_db():
     491        r"""
     492        Parses the ISGCI database and returns its content as Python objects.
     493
     494        EXAMPLE::
     495
     496            sage: sage.graphs.isgci._create_db() # Not tested -- requires internet
     497        """
     498        from sage.misc.misc import SAGE_TMP
     499        import xml.dom.minidom
     500        from xml.dom.minidom import Node
     501
     502        # This method is there to parse the XML file containing the ISGCI
     503        # database. It is admittedly not very pretty, but it builds the class we
     504        # want from the XML file and that's more or less all we ask it to do :-p
     505
     506        doc = xml.dom.minidom.parse(SAGE_TMP+_XML_FILE)
     507
     508        classes = {}
     509
     510        giveme = lambda x,y : str(x.getAttribute(y))
     511
     512        for node in doc.getElementsByTagName("GraphClass"):
     513            ID = str(node.getAttribute("id"))
     514            Dl = {}
     515            smallgraph = []
     516            Dl["ID"] = giveme(node, "id")
     517            problems = {}
     518            for node2 in node.childNodes:
     519                name = str(node2.nodeName)
     520                if name == "name":
     521                    Dl[name] = str(node2.childNodes[0].nodeValue)
     522
     523                elif name ==  "smallgraph":
     524                    smallgraph.append(str(node2.childNodes[0].nodeValue))
     525
     526                elif name == "problem":
     527                    problems[giveme(node2, "name")] = giveme(node2, "complexity")
     528
     529            Dl["problems"] = problems
     530
     531            if smallgraph:
     532                Dl["smallgraph"] = smallgraph
     533
     534            if giveme(node, "type"):
     535                Dl["type"] = giveme(node, "type")
     536
     537
     538            classes[giveme(node, "id")] = Dl
     539
     540        inclusions = []
     541        for node in doc.getElementsByTagName("incl"):
     542            Dl = {}
     543            for name in ["proper", "confidence", "super", "sub"]:
     544                if giveme(node, name):
     545                    Dl[name] = giveme(node, name)
     546
     547            for node2 in node.childNodes:
     548                name = str(node2.nodeName)
     549                if name == "ref":
     550                    Dl[name] = str(node2.childNodes[0].nodeValue)
     551
     552            inclusions.append(Dl)
     553
     554        return classes, inclusions
     555
     556    def update_db(verbose = False):
     557        r"""
     558        Updates the ISGCI database by downloading the latest version from internet.
     559
     560        This method downloads the ISGCI database from the website `GraphClasses.org
     561        <http://www.graphclasses.org/>`_.
     562
     563        It then extracts the zip file and parses its XML content, which is
     564        stored as two ``.sobj`` files, the first one representing the
     565        graph classes, and the second representing their inclusions.
     566
     567        Depending on the credentials of the user running Sage when this
     568        command is run, one attempt is made at saving the result in Sage's
     569        directory so that all users can benefit from it. If the
     570        credentials are not sufficient, the ``.sobj`` files are saved
     571        instead in the user's directory. #TODO: be more specific about where in the user's directory?
     572
     573        INPUT:
     574
     575        - ``verbose`` -- a boolean (default: False); whether to output
     576          information of the update process
     577
     578        EXAMPLE::
     579
     580            sage: sage.graphs.isgci.update_db() # Not tested -- requires internet
     581        """
     582        from sage.misc.misc import SAGE_TMP, SAGE_ROOT, SAGE_LOCAL, SAGE_DB
     583        global classes, inclusions, inclusion_digraph
     584
     585        try:
     586            _download_db()
     587        except:
     588            # TODO: as such, the user won't get the, probably more
     589            # informative, error message thrown by download_db. What about
     590            # not catching it? Or at least retransmitting the error
     591            # message?
     592            raise Exception("There has been a problem while downloading or unzipping the ISGCI database O_o")
     593
     594
     595        if verbose:
     596            print "Database downloaded"
     597
     598        classes, inclusions = _create_db()
     599
     600        if verbose:
     601            print "XML file converted to Python dictionaries"
     602
     603
     604        from sage.all import save
     605
     606        # Trying to save to Sage's directory
     607        try:
     608            save(classes, SAGE_ROOT+'/data/graphs/isgci_classes.sobj')
     609            save(inclusions, SAGE_ROOT+'/data/graphs/isgci_inclusions.sobj')
     610            inclusions = inclusion_digraph = None
     611            classes = {}
     612            if verbose:
     613                print "Database saved to .sobj files in "+SAGE_ROOT+'/data/graphs/'
     614
     615            return
     616        except IOError:
     617            if verbose:
     618                # TODO: improve!
     619                print "Could not save save database in "+SAGE_ROOT+'/data/graphs/'
     620            pass
     621
     622        # Trying to save to the user's home directory
     623        try:
     624            save(classes, SAGE_DB+"/isgci_classes.sobj")
     625            save(inclusions, SAGE_DB+"/isgci_inclusions.sobj")
     626            classes = inclusions = inclusion_digraph = None
     627            if verbose:
     628                print "Database saved to .sobj files in "+SAGE_DB
     629
     630            return
     631
     632        except IOError:
     633            pass
     634
     635        # TODO: as above: don't hide the more informative error message
     636        # from the system
     637
     638        # Gloops !
     639        raise Exception("Sage is unable to write the files to your"+
     640                        "computer ! This shouldn't have happened. "+
     641                        "Could you report the bug ? ;-)")
     642
     643    def get_ISGCI():
     644        r"""
     645        Returns the contents of the ISGCI database.
     646
     647        This method is mostly for internal use, but often provides useful
     648        information during debugging operations.
     649
     650        OUTPUT:
     651
     652        A pair ``(classes, inclusions)`` where ``classes`` is a dict of dict, and
     653        ``inclusions`` is a list of dicts.
     654
     655        .. NOTE::
     656
     657            This method returns the data contained in the most recent ISGCI database
     658            present on the computer. See :func:`update_db` to update the latter.
     659
     660        EXAMPLE::
     661
     662            sage: classes, inclusions = sage.graphs.isgci.get_ISGCI()
     663        """
     664
     665        import os.path
     666        from sage.all import save, load
     667        from sage.misc.misc import SAGE_TMP, SAGE_ROOT, SAGE_LOCAL, SAGE_DB
     668
     669        # TODO: or systematically use the user's version if it exists,
     670        # throwing a warning if it is not the most recent?
     671
     672        try:
     673            open(SAGE_DB+"/isgci_classes.sobj")
     674
     675            # Which copy is the most recent on the disk ?
     676            if (os.path.getmtime(SAGE_DB+"/isgci_classes.sobj") >
     677                os.path.getmtime(SAGE_ROOT+"/data/graphs/isgci_classes.sobj")):
     678
     679                classes = load(SAGE_DB+"/isgci_classes.sobj")
     680                inclusions = load(SAGE_DB+"/isgci_inclusions.sobj")
     681
     682            else:
     683                classes = load(SAGE_ROOT+"/data/graphs/isgci_classes.sobj")
     684                inclusions = load(SAGE_ROOT+"/data/graphs/isgci_inclusions.sobj")
     685
     686        except IOError as e:
     687            # No local version of the file exists
     688            classes = load(SAGE_ROOT+"/data/graphs/isgci_classes.sobj")
     689            inclusions = load(SAGE_ROOT+"/data/graphs/isgci_inclusions.sobj")
     690
     691        return classes, inclusions
     692
     693    def show_all():
     694        r"""
     695        Prints all graph classes stored in ISGCI
     696
     697        EXAMPLE::
     698
     699            sage: sage.graphs.isgci.show_all()
     700            ID        | name                                     | type                 | smallgraph
     701            ----------------------------------------------------------------------------------------------------------------------
     702            gc_309    | $K_4$--minor--free                       | base                 |
     703            gc_541    | $N^*$                                    | base                 |
     704            gc_215    | $N^*$--perfect                           | base                 |
     705            gc_5      | $P_4$--bipartite                         | base                 |
     706            gc_3      | $P_4$--brittle                           | base                 |
     707            gc_6      | $P_4$--comparability                     | base                 |
     708            gc_7      | $P_4$--extendible                        | base                 |
     709            ...
     710        """
     711        global classes
     712        _load_ISGCI_if_not_loaded()
     713        classes_list = classes.values()
     714
     715        # We want to print the different fields, and this dictionary stores the
     716        # maximal number of characters of each field.
     717        MAX = {
     718            "ID" : 0,
     719            "type" : 0,
     720            "smallgraph": 0,
     721            "name": 0
     722            }
     723
     724        # We sort the classes alphabetically, though we would like to display the
     725        # meaningful classes at the top of the list
     726        classes_list.sort(key = lambda x:x.get("name","zzzzz")+"{0:4}".format(int(x["ID"].split('_')[1])))
     727
     728        # Maximum width of a field
     729        MAX_LEN = 40
     730
     731        # Computing te max of each field with the database
     732        for key in MAX:
     733            MAX[key] = len(max(map(lambda x:str(x.get(key,"")),classes_list), key = len))
     734
     735        # At most MAX characters per field
     736        for key, length in MAX.iteritems():
     737            MAX[key] = min(length, MAX_LEN)
     738
     739        # Head of the table
     740        print ("{0:"+str(MAX["ID"])+"} | {1:"+str(MAX["name"])+"} | {2:"+str(MAX["type"])+"} | {3:"+str(MAX["smallgraph"])+"}").format("ID", "name", "type", "smallgraph")
     741        print "-"*(sum(MAX.values())+9)
     742
     743        # Entries
     744        for entry in classes_list:
     745            ID = entry.get("ID","")
     746            name = entry.get("name","")
     747            type = entry.get("type","")
     748            smallgraph = entry.get("smallgraph","")
     749            print ("{0:"+str(MAX["ID"])+"} | {1:"+str(MAX["name"])+"} | {2:"+str(MAX["type"])+"} | ").format(ID, name[:MAX_LEN], type[:MAX_LEN])+str(smallgraph)[:MAX_LEN]
     750
     751    def _load_ISGCI_if_not_loaded():
     752        r"""
     753        Load ISGI if not loaded already
     754
     755        This is here to avoid having to load the db when Sage starts
     756        """
     757        global classes, inclusions
     758        if classes == {}:
     759            classes, inclusions = get_ISGCI()
     760
     761    def _build_inclusion_digraph_if_not_built():
     762        r"""
     763        Builds the class digraph
     764        """
     765        global classes, inclusions, inclusion_digraph
     766
     767        if not (inclusion_digraph is None):
     768            return
     769
     770        _load_ISGCI_if_not_loaded()
     771
     772        from sage.graphs.digraph import DiGraph
     773        inclusion_digraph = DiGraph()
     774        inclusion_digraph.add_vertices(classes.keys())
     775
     776        for edge in inclusions:
     777            if edge.get("confidence","") == "unpublished":
     778                continue
     779
     780            inclusion_digraph.add_edge(edge['super'], edge['sub'])
     781
     782        inclusions = []
     783
     784
    785785graph_classes = GraphClasses()
    786786
    787787# Any object added to this list should also appear in the class' documentation, at the top of the file.