Ticket #11880: trac_11880-XML_storage.patch

File trac_11880-XML_storage.patch, 11.0 KB (added by ncohen, 7 years ago)
  • sage/graphs/isgci.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1332522988 -3600
    # Node ID 258aec8b2b0be1decdec13da0d969e3059c721e0
    # Parent  35baa3abf4c08425596fbdd317ca8a62d3529d76
    ISGCI in Sage -- now storing it as an XML file
    
    diff --git a/sage/graphs/isgci.py b/sage/graphs/isgci.py
    a b  
    5858    <BLANKLINE>
    5959    Problems :
    6060    -----------
     61    3-Colourability                :  Linear
     62    Clique                         :  Polynomial
     63    Clique cover                   :  Polynomial
     64    Cliquewidth                    :  Unbounded
     65    Cliquewidth expression         :  NP-complete
     66    Colourability                  :  Linear
     67    Domination                     :  NP-complete
    6168    Independent set                :  Linear
     69    Recognition                    :  Linear
    6270    Treewidth                      :  Polynomial
     71    Weighted clique                :  Polynomial
    6372    Weighted independent set       :  Linear
    64     Cliquewidth expression         :  NP-complete
    65     Weighted clique                :  Polynomial
    66     Clique cover                   :  Polynomial
    67     Domination                     :  NP-complete
    68     Clique                         :  Polynomial
    69     Colourability                  :  Linear
    70     Cliquewidth                    :  Unbounded
    71     3-Colourability                :  Linear
    72     Recognition                    :  Linear
    7373
    7474It is possible to obtain the complete list of the classes stored in ISGCI by
    7575calling the :meth:`~GraphClasses.show_all` method (beware -- long output)::
     
    190190in a huge dictionary (see :meth:`~sage.graphs.isgci.GraphClasses.classes`).
    191191Below is what Sage knows of ``gc_249``::
    192192
    193     sage: graph_classes.classes()['gc_249']
     193    sage: graph_classes.classes()['gc_249']        # random
    194194    {'problems':
    195195        {'Independent set': 'Polynomial',
    196196         'Treewidth': 'Unknown',
     
    231231Hence bipartite graphs are perfect graphs. We can see how ISGCI obtains this
    232232result ::
    233233
    234     sage: d.shortest_path(perfect_id, bip_id)
     234    sage: p = d.shortest_path(perfect_id, bip_id)
     235    sage: len(p) - 1
     236    2
     237    sage: print p                  # random
    235238    ['gc_56', 'gc_76', 'gc_69']
    236     sage: map(graph_classes.get_class, d.shortest_path(perfect_id, bip_id))
    237     [perfect graphs, unimodular graphs, bipartite graphs]
     239    sage: for c in p:
     240    ...      print graph_classes.get_class(c)
     241    perfect graphs
     242    ...
     243    bipartite graphs
    238244
    239245What ISGCI knows is that perfect graphs contain unimodular graph which contain
    240246bipartite graphs. Therefore bipartite graphs are perfect !
     
    267273  :meth:`~sage.graphs.isgci.GraphClasses.inclusion_digraph`.
    268274
    269275* Upon the first access to the database, the information is extracted
    270   from the ``.sobj`` files and stored in the following variables :
     276  from the XML file and stored in the cache of three methods:
    271277
    272278  * ``sage.graphs.isgci._classes`` (dictionary)
    273279  * ``sage.graphs.isgci._inclusions`` (list of dictionaries)
     
    467473            <BLANKLINE>
    468474            Problems :
    469475            -----------
     476            3-Colourability                :  Linear
     477            Clique                         :  Polynomial
     478            Clique cover                   :  Polynomial
     479            Cliquewidth                    :  Unbounded
     480            Cliquewidth expression         :  NP-complete
     481            Colourability                  :  Linear
     482            Domination                     :  NP-complete
    470483            Independent set                :  Linear
     484            Recognition                    :  Linear
    471485            Treewidth                      :  Polynomial
     486            Weighted clique                :  Polynomial
    472487            Weighted independent set       :  Linear
    473             Cliquewidth expression         :  NP-complete
    474             Weighted clique                :  Polynomial
    475             Clique cover                   :  Polynomial
    476             Domination                     :  NP-complete
    477             Clique                         :  Polynomial
    478             Colourability                  :  Linear
    479             Cliquewidth                    :  Unbounded
    480             3-Colourability                :  Linear
    481             Recognition                    :  Linear
    482488        """
    483489
    484490        classes = GraphClasses().classes()
     
    494500
    495501        print "\nProblems :"
    496502        print "-"*11
    497         for key, value in cls["problems"].iteritems():
     503        for key, value in sorted(cls["problems"].iteritems()):
    498504            if value != "":
    499505                print "{0:30} : ".format(key),
    500506                print value
     
    548554        Returns the graph classes, as a dictionary.
    549555
    550556        Upon the first call, this loads the database from the local
    551         sobj files. Subsequent calls are cached.
     557        XML file. Subsequent calls are cached.
    552558
    553559        EXAMPLES::
    554560
     
    576582        a list of dictionaries
    577583
    578584        Upon the first call, this loads the database from the local
    579         sobj files. Subsequent calls are cached.
     585        XML file. Subsequent calls are cached.
    580586
    581587        EXAMPLES::
    582588
     
    595601        Returns the class inclusion digraph
    596602
    597603        Upon the first call, this loads the database from the local
    598         sobj files. Subsequent calls are cached.
     604        XML file. Subsequent calls are cached.
    599605
    600606        EXAMPLES::
    601607
     
    625631            sage: graph_classes._download_db() # Not tested -- requires internet
    626632        """
    627633
    628         from sage.misc.misc import SAGE_TMP
     634        from sage.misc.misc import SAGE_TMP, SAGE_ROOT
    629635        import urllib2
    630636        u = urllib2.urlopen('http://www.graphclasses.org/data.zip')
    631637        localFile = open(SAGE_TMP+'isgci.zip', 'w')
     
    633639        localFile.close()
    634640        import os, zipfile
    635641        z = zipfile.ZipFile(SAGE_TMP+'isgci.zip')
    636         z.extract(_XML_FILE, SAGE_TMP)
    637642
    638     def _create_db(self):
     643        # Save a systemwide updated copy whenever possible
     644
     645        try:
     646            z.extract(_XML_FILE, SAGE_ROOT+"/data/graphs/")
     647        except IOError:
     648            z.extract(_XML_FILE, SAGE_TMP)
     649
     650
     651    def _parse_db(self, xml_file):
    639652        r"""
    640653        Parses the ISGCI database and returns its content as Python objects.
    641654
     655        INPUT:
     656
     657        - ``xml_file`` -- the name of an XML file containing the data from ISGCI
     658
    642659        EXAMPLE::
    643660
    644             sage: graph_classes._create_db() # Not tested -- requires internet
     661            sage: map(type, graph_classes._parse_db(SAGE_ROOT+"/data/graphs/isgci_sage.xml"))
     662            [<type 'dict'>, <type 'list'>]
    645663        """
    646         from sage.misc.misc import SAGE_TMP
    647664        import xml.dom.minidom
    648665        from xml.dom.minidom import Node
    649666
     
    651668        # database. It is admittedly not very pretty, but it builds the class we
    652669        # want from the XML file and that's more or less all we ask it to do :-p
    653670
    654         doc = xml.dom.minidom.parse(SAGE_TMP+_XML_FILE)
     671        doc = xml.dom.minidom.parse(xml_file)
    655672
    656673        classes = {}
    657674
     
    705722        r"""
    706723        Updates the ISGCI database by downloading the latest version from internet.
    707724
    708         This method downloads the ISGCI database from the website `GraphClasses.org
    709         <http://www.graphclasses.org/>`_.
     725        This method downloads the ISGCI database from the website
     726        `GraphClasses.org <http://www.graphclasses.org/>`_. It then extracts the
     727        zip file and parses its XML content.
    710728
    711         It then extracts the zip file and parses its XML content, which is
    712         stored as two ``.sobj`` files, the first one representing the
    713         graph classes, and the second representing their inclusions.
    714 
    715         Depending on the credentials of the user running Sage when this
    716         command is run, one attempt is made at saving the result in Sage's
    717         directory so that all users can benefit from it. If the
    718         credentials are not sufficient, the ``.sobj`` files are saved
    719         instead in the user's directory (in the SAGE_DB folder).
     729        Depending on the credentials of the user running Sage when this command
     730        is run, one attempt is made at saving the result in Sage's directory so
     731        that all users can benefit from it. If the credentials are not
     732        sufficient, the XML file are saved instead in the user's directory (in
     733        the SAGE_DB folder).
    720734
    721735        EXAMPLE::
    722736
     
    728742
    729743        print "Database downloaded"
    730744
    731         classes, inclusions = self._create_db()
    732 
    733         print "XML file converted into Python dictionaries"
    734 
    735         from sage.all import save
    736 
    737         # Trying to save to Sage's directory
    738         # TODO: get rid of duplication
    739         try:
    740             save(classes, SAGE_ROOT+'/data/graphs/isgci_classes.sobj')
    741             save(inclusions, SAGE_ROOT+'/data/graphs/isgci_inclusions.sobj')
    742             self.classes.clear_cache()
    743             self.inclusions.clear_cache()
    744             self.inclusion_digraph.clear_cache()
    745             print "Database saved to .sobj files in "+SAGE_ROOT+'/data/graphs/'
    746             return
    747 
    748         except IOError, v:
    749             print "Could not save save database in "+SAGE_ROOT+"/data/graphs/ ("+str(v.strerror)+")"
    750             print "Now attempting to save the files to "+str(SAGE_DB)
    751 
    752         # Trying to save to the user's home directory
    753         save(classes, SAGE_DB+"/isgci_classes.sobj")
    754         save(inclusions, SAGE_DB+"/isgci_inclusions.sobj")
    755745        self.classes.clear_cache()
    756746        self.inclusions.clear_cache()
    757747        self.inclusion_digraph.clear_cache()
    758         print "Database saved to .sobj files in "+SAGE_DB
    759748
    760749    def _get_ISGCI(self):
    761750        r"""
     
    784773        from sage.misc.misc import SAGE_TMP, SAGE_ROOT, SAGE_LOCAL, SAGE_DB
    785774
    786775        try:
    787             open(SAGE_DB+"/isgci_classes.sobj")
     776            open(SAGE_DB+"/"+_XML_FILE)
    788777
    789778            # Which copy is the most recent on the disk ?
    790             if (os.path.getmtime(SAGE_DB+"/isgci_classes.sobj") >
    791                 os.path.getmtime(SAGE_ROOT+"/data/graphs/isgci_classes.sobj")):
     779            if (os.path.getmtime(SAGE_DB+"/"+_XML_FILE) >
     780                os.path.getmtime(SAGE_ROOT+"/data/graphs/"+_XML_FILE)):
    792781
    793                 classes = load(SAGE_DB+"/isgci_classes.sobj")
    794                 inclusions = load(SAGE_DB+"/isgci_inclusions.sobj")
     782                filename = SAGE_DB+"/"+_XML_FILE
    795783
    796784            else:
    797                 classes = load(SAGE_ROOT+"/data/graphs/isgci_classes.sobj")
    798                 inclusions = load(SAGE_ROOT+"/data/graphs/isgci_inclusions.sobj")
     785                filename = SAGE_ROOT+"/data/graphs/"+_XML_FILE
    799786
    800787        except IOError as e:
    801             # No local version of the file exists
    802             classes = load(SAGE_ROOT+"/data/graphs/isgci_classes.sobj")
    803             inclusions = load(SAGE_ROOT+"/data/graphs/isgci_inclusions.sobj")
     788            filename = SAGE_ROOT+"/data/graphs/"+_XML_FILE
    804789
    805         return classes, inclusions
     790        return self._parse_db(filename)
    806791
    807792    def show_all(self):
    808793        r"""