Ticket #11880: trac_11880-ISGCI-all-in-one.patch

File trac_11880-ISGCI-all-in-one.patch, 29.9 KB (added by ncohen, 7 years ago)
  • doc/en/reference/graphs.rst

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1331055323 -3600
    # Node ID fcffc1700cc431e6457f5144414028382bc21d5e
    # Parent  c5aa6b0e38f012e65e64d94f06d4072416f11320
    Implements an interface between Sage and ISGCI (a graph class database)
    
    diff --git a/doc/en/reference/graphs.rst b/doc/en/reference/graphs.rst
    a b  
    2525   sage/graphs/digraph_generators
    2626   sage/graphs/graph_generators_pyx
    2727   sage/graphs/graph_database
     28   sage/graphs/isgci
    2829
    2930
    3031Low-level implementation
  • doc/en/reference/misc.rst

    diff --git a/doc/en/reference/misc.rst b/doc/en/reference/misc.rst
    a b  
    3636   sage/misc/lazy_import
    3737   sage/misc/log
    3838   sage/misc/persist
     39   sage/misc/unknown
    3940   sage/misc/func_persist
    4041   sage/misc/sage_eval
    4142   sage/misc/random_testing
  • sage/graphs/all.py

    diff --git a/sage/graphs/all.py b/sage/graphs/all.py
    a b  
    1818from sage.graphs.cliquer import *
    1919from graph_database import graph_db_info
    2020from graph_editor import graph_editor
     21
     22import sage.graphs.isgci
     23from sage.graphs.isgci import graph_classes
    2124import sage.graphs.distances_all_pairs
  • new file sage/graphs/isgci.py

    diff --git a/sage/graphs/isgci.py b/sage/graphs/isgci.py
    new file mode 100644
    - +  
     1r"""
     2Information System on Graph Classes and their Inclusions
     3
     4This module implements an interface to the `ISGCI <http://www.graphclasses.org/>`_ database in Sage.
     5
     6This database gathers information on graph classes and their
     7inclusions in each other. It also contains information on the
     8complexity of several computational problems.
     9
     10It is available on the `GraphClasses.org <http://www.graphclasses.org/>`_
     11website maintained by H.N. de Ridder et al.
     12
     13How to use it?
     14--------------
     15
     16The current limited aim of this module is to provide a pure Sage/Python
     17interface which is easier to deal with than a XML file. I hope it will be
     18rewritten many times until it stabilizes :-)
     19
     20Presently, it is possible to use this database through the variables and methods
     21present in the :obj:`graph_classes <GraphClasses>` object.
     22For instance::
     23
     24    sage: Trees = graph_classes.Tree
     25    sage: Chordal = graph_classes.Chordal
     26
     27It is then possible to check the inclusion of classes inside of others, if the
     28information is available in the database::
     29
     30    sage: Trees <= Chordal
     31    True
     32
     33And indeed, trees are chordal graphs.
     34
     35.. WARNING::
     36
     37    The ISGCI database is not all-knowing, and so comparing two classes can
     38    return ``True``, ``False``, or ``Unknown`` (see the :mod:`documentation of
     39    the Unknown truth value <sage.misc.unknown>`).
     40
     41    An *unknown* answer to ``A <= B`` only means that ISGCI cannot deduce from
     42    the information in its database that ``A`` is a subclass of ``B`` nor that
     43    it is not. For instance, ISGCI does not know at the moment that some chordal
     44    graphs are not trees::
     45
     46        sage: graph_classes.Chordal <= graph_classes.Tree
     47        Unknown
     48
     49Given a graph class, one can obtain its associated information in the
     50ISGCI database with the :meth:`~GraphClass.description` method::
     51
     52    sage: Chordal.description()
     53    Class of graphs : Chordal
     54    -------------------------
     55    type                           :  base
     56    ID                             :  gc_32
     57    name                           :  chordal
     58    <BLANKLINE>
     59    Problems :
     60    -----------
     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
     68    Independent set                :  Linear
     69    Recognition                    :  Linear
     70    Treewidth                      :  Polynomial
     71    Weighted clique                :  Polynomial
     72    Weighted independent set       :  Linear
     73
     74It is possible to obtain the complete list of the classes stored in ISGCI by
     75calling the :meth:`~GraphClasses.show_all` method (beware -- long output)::
     76
     77    sage: graph_classes.show_all()
     78    ID        | name                                     | type                 | smallgraph
     79    ----------------------------------------------------------------------------------------------------------------------
     80    gc_309    | $K_4$--minor--free                       | base                 |
     81    gc_541    | $N^*$                                    | base                 |
     82    gc_215    | $N^*$--perfect                           | base                 |
     83    gc_5      | $P_4$--bipartite                         | base                 |
     84    gc_3      | $P_4$--brittle                           | base                 |
     85    gc_6      | $P_4$--comparability                     | base                 |
     86    gc_7      | $P_4$--extendible                        | base                 |
     87    ...
     88
     89Until a proper search method is implemented, this lets one find
     90classes which do not appear in :obj:`graph_classes.* <GraphClasses>`.
     91
     92To retrieve a class of graph from its ISGCI ID one may use
     93the :meth:`~GraphClasses.get_class` method::
     94
     95    sage: GC = graph_classes.get_class("gc_5")
     96    sage: GC
     97    $P_4$--bipartite graphs
     98
     99Predefined classes
     100------------------
     101
     102:obj:`graph_classes <GraphClasses>` currently predefines the following graph classes
     103
     104.. list-table::
     105   :widths: 20 30
     106   :header-rows: 1
     107
     108   * - Class
     109     - Related methods
     110
     111   * - BinaryTrees
     112
     113     - :meth:`~sage.graphs.graph_generators.GraphGenerators.BalancedTree`,
     114       :meth:`~sage.graphs.generic_graph.GenericGraph.is_tree`
     115
     116   * - Bipartite
     117
     118     - :meth:`~sage.graphs.graph_generators.GraphGenerators.BalancedTree`,
     119       :meth:`~sage.graphs.graph.Graph.is_bipartite`
     120
     121   * - Block
     122
     123     - :meth:`~sage.graphs.generic_graph.GenericGraph.blocks_and_cut_vertices`,
     124
     125   * - Chordal
     126
     127     - :meth:`~sage.graphs.generic_graph.GenericGraph.is_chordal`
     128
     129   * - Comparability
     130     -
     131
     132   * - Gallai
     133
     134     - :meth:`~sage.graphs.generic_graph.GenericGraph.is_gallai_tree`
     135
     136   * - Grid
     137
     138     - :meth:`~sage.graphs.graph_generators.GraphGenerators.Grid2dGraph`,
     139       :meth:`~sage.graphs.graph_generators.GraphGenerators.GridGraph`
     140
     141   * - Interval
     142
     143     - :meth:`~sage.graphs.graph_generators.GraphGenerators.RandomInterval`,
     144       :meth:`~sage.graphs.graph_generators.GraphGenerators.IntervalGraph`,
     145       :meth:`~sage.graphs.generic_graph.GenericGraph.is_interval`
     146
     147   * - Line
     148
     149     - :meth:`~sage.graphs.graph_generators.GraphGenerators.line_graph_forbidden_subgraphs`,
     150       :meth:`~sage.graphs.graph.Graph.is_line_graph`
     151
     152   * - Modular
     153
     154     - :meth:`~sage.graphs.graph.Graph.modular_decomposition`
     155
     156   * - Outerplanar
     157
     158     - :meth:`~sage.graphs.generic_graph.GenericGraph.is_circular_planar`
     159
     160   * - Perfect
     161
     162     - :meth:`~sage.graphs.graph.Graph.is_perfect`
     163
     164   * - Planar
     165
     166     - :meth:`~sage.graphs.generic_graph.GenericGraph.is_planar`
     167
     168   * - Split
     169
     170     - :meth:`~sage.graphs.graph.Graph.is_split`
     171
     172   * - Tree
     173
     174     - :meth:`~sage.graphs.graph_generators.GraphGenerators.trees`,
     175       :meth:`~sage.graphs.generic_graph.GenericGraph.is_tree`
     176
     177   * - UnitDisk
     178     - :meth:`~sage.graphs.graph_generators.GraphGenerators.IntervalGraph`,
     179
     180   * - UnitInterval
     181
     182     - :meth:`~sage.graphs.generic_graph.GenericGraph.is_interval`
     183
     184Sage's view of ISGCI
     185--------------------
     186
     187The database is stored by Sage in two ways.
     188
     189**The classes**: the list of all graph classes and their properties is stored
     190in a huge dictionary (see :meth:`~sage.graphs.isgci.GraphClasses.classes`).
     191Below is what Sage knows of ``gc_249``::
     192
     193    sage: graph_classes.classes()['gc_249']        # random
     194    {'problems':
     195        {'Independent set': 'Polynomial',
     196         'Treewidth': 'Unknown',
     197         'Weighted independent set': 'Polynomial',
     198         'Cliquewidth expression': 'NP-complete',
     199         'Weighted clique': 'Polynomial',
     200         'Clique cover': 'Unknown',
     201         'Domination': 'NP-complete',
     202         'Clique': 'Polynomial',
     203         'Colourability': 'NP-complete',
     204         'Cliquewidth': 'Unbounded',
     205         '3-Colourability': 'NP-complete',
     206         'Recognition': 'Linear'},
     207     'type': 'base',
     208     'ID': 'gc_249',
     209     'name': 'line'}
     210
     211**The class inclusion digraph**: Sage remembers the class inclusions through
     212the inclusion digraph (see :meth:`~sage.graphs.isgci.GraphClasses.inclusion_digraph`).
     213Its nodes are ID of ISGCI classes::
     214
     215    sage: d = graph_classes.inclusion_digraph()
     216    sage: d.vertices()[-10:]
     217    ['gc_990', 'gc_991', 'gc_992', 'gc_993', 'gc_994', 'gc_995', 'gc_996', 'gc_997', 'gc_998', 'gc_999']
     218
     219An arc from ``gc1`` to ``gc2`` means that ``gc1`` is a superclass of
     220``gc2``. This being said, not all edges are stored ! To ensure that a given
     221class is included in another one, we have to check whether there is in the
     222digraph a ``path`` from the first one to the other::
     223
     224    sage: bip_id = graph_classes.Bipartite._gc_id
     225    sage: perfect_id = graph_classes.Perfect._gc_id
     226    sage: d.has_edge(perfect_id, bip_id)
     227    False
     228    sage: d.distance(perfect_id, bip_id)
     229    2
     230
     231Hence bipartite graphs are perfect graphs. We can see how ISGCI obtains this
     232result ::
     233
     234    sage: p = d.shortest_path(perfect_id, bip_id)
     235    sage: len(p) - 1
     236    2
     237    sage: print p                  # random
     238    ['gc_56', 'gc_76', 'gc_69']
     239    sage: for c in p:
     240    ...      print graph_classes.get_class(c)
     241    perfect graphs
     242    ...
     243    bipartite graphs
     244
     245What ISGCI knows is that perfect graphs contain unimodular graph which contain
     246bipartite graphs. Therefore bipartite graphs are perfect !
     247
     248.. note::
     249
     250    The inclusion digraph is **NOT ACYCLIC**. Indeed, several entries
     251    exist in the ISGCI database which represent the same graph class,
     252    for instance Perfect graphs and Berge graphs::
     253
     254        sage: graph_classes.inclusion_digraph().is_directed_acyclic()
     255        False
     256        sage: Berge = graph_classes.get_class("gc_274"); Berge
     257        Berge graphs
     258        sage: Perfect = graph_classes.get_class("gc_56"); Perfect
     259        perfect graphs
     260        sage: Berge <= Perfect
     261        True
     262        sage: Perfect <= Berge
     263        True
     264        sage: Perfect == Berge
     265        True
     266
     267Information for developpers
     268----------------------------
     269
     270* The database is loaded not *so* large, but it is still preferable to
     271  only load it on demand. This is achieved through the cached methods
     272  :meth:`~sage.graphs.isgci.GraphClasses.classes` and
     273  :meth:`~sage.graphs.isgci.GraphClasses.inclusion_digraph`.
     274
     275* Upon the first access to the database, the information is extracted
     276  from the XML file and stored in the cache of three methods:
     277
     278  * ``sage.graphs.isgci._classes`` (dictionary)
     279  * ``sage.graphs.isgci._inclusions`` (list of dictionaries)
     280  * ``sage.graphs.isgci._inclusion_digraph`` (DiGraph)
     281
     282  Note that the digraph is only built if necessary (for instance if
     283  the user tries to compare two classes).
     284
     285.. todo::
     286
     287    Technical things:
     288
     289    * Query the database for non-inclusion results so that comparisons can
     290      return ``False``, and implement strict inclusions.
     291
     292    * Implement a proper search method for the classes not listed in
     293      :obj:`graph_classes <GraphClasses>`
     294
     295      .. seealso: :func:`sage.graphs.isgci.show_all`.
     296
     297    * Some of the graph classes appearing in :obj:`graph_classes
     298      <GraphClasses>` already have a recognition
     299      algorithm implemented in Sage. It would be so nice to be able to
     300      write ``g in Trees``, ``g in Perfect``, ``g in Chordal``, ... :-)
     301
     302    Long-term stuff:
     303
     304    * Implement simple accessors for all the information in the ISGCI
     305      database (as can be done from the website)
     306
     307    * Implement intersection of graph classes
     308
     309    * Write generic recognition algorithms for specific classes (when a graph class
     310      is defined by the exclusion of subgraphs, one can write a generic algorithm
     311      checking the existence of each of the graphs, and this method already exists
     312      in Sage).
     313
     314    * Improve the performance of Sage's graph library by letting it
     315      take advantage of the properties of graph classes. For example,
     316      :meth:`Graph.independent_set` could use the library to detect
     317      that a given graph is, say, a tree or a planar graph, and use a
     318      specialized algorithm for finding an independent set.
     319
     320AUTHORS:
     321--------
     322
     323* H.N. de Ridder et al. (ISGCI database)
     324* Nathann Cohen (Sage implementation)
     325
     326Methods
     327-------
     328"""
     329
     330from sage.structure.sage_object import SageObject
     331from sage.structure.unique_representation import UniqueRepresentation
     332from sage.misc.unknown import Unknown
     333
     334#*****************************************************************************
     335#      Copyright (C) 2011 Nathann Cohen <nathann.cohen@gmail.com>
     336#
     337# Distributed  under  the  terms  of  the  GNU  General  Public  License (GPL)
     338#                         http://www.gnu.org/licenses/
     339#*****************************************************************************
     340
     341_XML_FILE = "isgci_sage.xml"
     342
     343class GraphClass(SageObject, UniqueRepresentation):
     344    r"""
     345    An instance of this class represents a Graph Class, matching some entry in
     346    the ISGCI database.
     347
     348    EXAMPLE:
     349
     350    Testing the inclusion of two classes::
     351
     352        sage: Chordal = graph_classes.Chordal
     353        sage: Trees = graph_classes.Tree
     354        sage: Trees <= Chordal
     355        True
     356        sage: Chordal <= Trees
     357        Unknown
     358
     359    TEST::
     360
     361        sage: Trees >= Chordal
     362        Unknown
     363        sage: Chordal >= Trees
     364        True
     365    """
     366    def __init__(self, name, gc_id):
     367        r"""
     368        Class constructor
     369
     370        EXAMPLE::
     371
     372            sage: graph_classes.Chordal  # indirect doctest
     373            Chordal graphs
     374        """
     375        self._name = name
     376        self._gc_id = gc_id
     377
     378    def _repr_(self):
     379        r"""
     380        Returns a short description of the class
     381
     382        EXAMPLE::
     383
     384            sage: graph_classes.Chordal  # indirect doctest
     385            Chordal graphs
     386        """
     387        return self._name+" graphs"
     388
     389    def __hash__(self):
     390        r"""
     391        Returns the class' ID hash
     392
     393        EXAMPLE::
     394
     395            sage: hash(graph_classes.Chordal) == hash(graph_classes.Chordal)
     396            True
     397        """
     398        return hash(self._gc_id)
     399
     400    def __le__(self, other):
     401        r"""
     402        <= operator
     403
     404        EXAMPLE::
     405
     406            sage: graph_classes.Chordal <= graph_classes.Tree
     407            Unknown
     408        """
     409        return other.__ge__(self)
     410
     411    def __ge__(self, other):
     412        r"""
     413        >= operator
     414
     415        EXAMPLE::
     416
     417            sage: graph_classes.Chordal >= graph_classes.Tree
     418            True
     419        """
     420
     421        inclusion_digraph = GraphClasses().inclusion_digraph()
     422        if inclusion_digraph.shortest_path(self._gc_id,other._gc_id) != []:
     423            return True
     424        else:
     425            return Unknown
     426
     427    def __eq__(self, other):
     428        r"""
     429        == operator
     430
     431        EXAMPLE::
     432
     433            sage: graph_classes.Chordal == graph_classes.Tree
     434            Unknown
     435        """
     436        return self.__ge__(other) and other.__ge__(self)
     437
     438    def __lt__(self, other):
     439        r"""
     440        >, !=, and < operators
     441
     442        EXAMPLE::
     443
     444            sage: graph_classes.Chordal > graph_classes.Tree
     445            Traceback (most recent call last):
     446            ...
     447            Exception: Not Implemented
     448            sage: graph_classes.Chordal < graph_classes.Tree
     449            Traceback (most recent call last):
     450            ...
     451            Exception: Not Implemented
     452            sage: graph_classes.Chordal != graph_classes.Tree
     453            Traceback (most recent call last):
     454            ...
     455            Exception: Not Implemented
     456        """
     457        raise Exception("Not Implemented")
     458
     459    __gt__ = __ne__ = __lt__
     460
     461    def description(self):
     462        r"""
     463        Prints the information of ISGCI about the current class.
     464
     465        EXAMPLE::
     466
     467            sage: graph_classes.Chordal.description()
     468            Class of graphs : Chordal
     469            -------------------------
     470            type                           :  base
     471            ID                             :  gc_32
     472            name                           :  chordal
     473            <BLANKLINE>
     474            Problems :
     475            -----------
     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
     483            Independent set                :  Linear
     484            Recognition                    :  Linear
     485            Treewidth                      :  Polynomial
     486            Weighted clique                :  Polynomial
     487            Weighted independent set       :  Linear
     488        """
     489
     490        classes = GraphClasses().classes()
     491
     492        cls = classes[self._gc_id]
     493        print "Class of graphs : "+self._name
     494        print "-"*(len(self._name)+18)
     495
     496        for key, value in cls.iteritems():
     497            if value != "" and key != "problems":
     498                print "{0:30} : ".format(key),
     499                print value
     500
     501        print "\nProblems :"
     502        print "-"*11
     503        for key, value in sorted(cls["problems"].iteritems()):
     504            if value != "":
     505                print "{0:30} : ".format(key),
     506                print value
     507
     508from sage.misc.cachefunc import cached_method
     509
     510class GraphClasses(UniqueRepresentation):
     511    def get_class(self, id):
     512        r"""
     513        Returns the class corresponding to the given id in the ISGCI database.
     514
     515        INPUT:
     516
     517        - ``id`` (string) -- the desired class' ID
     518
     519        .. seealso:
     520
     521            :meth:`~sage.graphs.isgci.GraphClasses.show_all`
     522
     523        EXAMPLE:
     524
     525        With an existing id::
     526
     527            sage: Cographs = graph_classes.get_class("gc_151")
     528            sage: Cographs
     529            cograph graphs
     530
     531        With a wrong id::
     532
     533            sage: graph_classes.get_class(-1)
     534            Traceback (most recent call last):
     535            ...
     536            ValueError: The given class id does not exist in the ISGCI database. Is the db too old ? You can update it with graph_classes.update_db().
     537        """
     538        classes = self.classes()
     539        if id in classes:
     540            c = classes[id]
     541
     542            if "name" in c and c["name"] != "":
     543                name = c["name"]
     544            else:
     545                name = "class "+str(id)
     546
     547            return GraphClass(name, id)
     548        else:
     549            raise ValueError("The given class id does not exist in the ISGCI database. Is the db too old ? You can update it with graph_classes.update_db().")
     550
     551    @cached_method
     552    def classes(self):
     553        r"""
     554        Returns the graph classes, as a dictionary.
     555
     556        Upon the first call, this loads the database from the local
     557        XML file. Subsequent calls are cached.
     558
     559        EXAMPLES::
     560
     561            sage: t = graph_classes.classes()
     562            sage: type(t)
     563            <type 'dict'>
     564            sage: sorted(t["gc_151"].keys())
     565            ['ID', 'name', 'problems', 'type']
     566            sage: t["gc_151"]['name']
     567            'cograph'
     568            sage: t["gc_151"]['problems']['Clique']
     569            'Linear'
     570        """
     571        classes, inclusions = self._get_ISGCI()
     572        self.inclusions.set_cache(inclusions)
     573        return classes
     574
     575    @cached_method
     576    def inclusions(self):
     577        r"""
     578        Returns the graph class inclusions
     579
     580        OUTPUT:
     581
     582        a list of dictionaries
     583
     584        Upon the first call, this loads the database from the local
     585        XML file. Subsequent calls are cached.
     586
     587        EXAMPLES::
     588
     589            sage: t = graph_classes.inclusions()
     590            sage: type(t)
     591            <type 'list'>
     592            sage: t[0]
     593            {'super': 'gc_2', 'sub': 'gc_1'}
     594        """
     595        self.classes()
     596        return self.inclusions()
     597
     598    @cached_method
     599    def inclusion_digraph(self):
     600        r"""
     601        Returns the class inclusion digraph
     602
     603        Upon the first call, this loads the database from the local
     604        XML file. Subsequent calls are cached.
     605
     606        EXAMPLES::
     607
     608            sage: g = graph_classes.inclusion_digraph(); g
     609            Digraph on ... vertices
     610        """
     611        classes    = self.classes()
     612        inclusions = self.inclusions()
     613
     614        from sage.graphs.digraph import DiGraph
     615        inclusion_digraph = DiGraph()
     616        inclusion_digraph.add_vertices(classes.keys())
     617
     618        for edge in inclusions:
     619            if edge.get("confidence","") == "unpublished":
     620                continue
     621            inclusion_digraph.add_edge(edge['super'], edge['sub'])
     622
     623        return inclusion_digraph
     624
     625    def _download_db(self):
     626        r"""
     627        Downloads the current version of the ISGCI db
     628
     629        EXAMPLE::
     630
     631            sage: graph_classes._download_db() # Not tested -- requires internet
     632        """
     633
     634        from sage.misc.misc import SAGE_TMP, SAGE_ROOT
     635        import urllib2
     636        u = urllib2.urlopen('http://www.graphclasses.org/data.zip')
     637        localFile = open(SAGE_TMP+'isgci.zip', 'w')
     638        localFile.write(u.read())
     639        localFile.close()
     640        import os, zipfile
     641        z = zipfile.ZipFile(SAGE_TMP+'isgci.zip')
     642
     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):
     652        r"""
     653        Parses the ISGCI database and returns its content as Python objects.
     654
     655        INPUT:
     656
     657        - ``xml_file`` -- the name of an XML file containing the data from ISGCI
     658
     659        EXAMPLE::
     660
     661            sage: map(type, graph_classes._parse_db(SAGE_ROOT+"/data/graphs/isgci_sage.xml"))
     662            [<type 'dict'>, <type 'list'>]
     663        """
     664        import xml.dom.minidom
     665        from xml.dom.minidom import Node
     666
     667        # This method is there to parse the XML file containing the ISGCI
     668        # database. It is admittedly not very pretty, but it builds the class we
     669        # want from the XML file and that's more or less all we ask it to do :-p
     670
     671        doc = xml.dom.minidom.parse(xml_file)
     672
     673        classes = {}
     674
     675        giveme = lambda x,y : str(x.getAttribute(y))
     676
     677        for node in doc.getElementsByTagName("GraphClass"):
     678            ID = str(node.getAttribute("id"))
     679            Dl = {}
     680            smallgraph = []
     681            Dl["ID"] = giveme(node, "id")
     682            problems = {}
     683            for node2 in node.childNodes:
     684                name = str(node2.nodeName)
     685                if name == "name":
     686                    Dl[name] = str(node2.childNodes[0].nodeValue)
     687
     688                elif name ==  "smallgraph":
     689                    smallgraph.append(str(node2.childNodes[0].nodeValue))
     690
     691                elif name == "problem":
     692                    problems[giveme(node2, "name")] = giveme(node2, "complexity")
     693
     694            Dl["problems"] = problems
     695
     696            if smallgraph:
     697                Dl["smallgraph"] = smallgraph
     698
     699            if giveme(node, "type"):
     700                Dl["type"] = giveme(node, "type")
     701
     702
     703            classes[giveme(node, "id")] = Dl
     704
     705        inclusions = []
     706        for node in doc.getElementsByTagName("incl"):
     707            Dl = {}
     708            for name in ["proper", "confidence", "super", "sub"]:
     709                if giveme(node, name):
     710                    Dl[name] = giveme(node, name)
     711
     712            for node2 in node.childNodes:
     713                name = str(node2.nodeName)
     714                if name == "ref":
     715                    Dl[name] = str(node2.childNodes[0].nodeValue)
     716
     717            inclusions.append(Dl)
     718
     719        return classes, inclusions
     720
     721    def update_db(self):
     722        r"""
     723        Updates the ISGCI database by downloading the latest version from internet.
     724
     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.
     728
     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).
     734
     735        EXAMPLE::
     736
     737            sage: graph_classes.update_db() # Not tested -- requires internet
     738        """
     739        from sage.misc.misc import SAGE_TMP, SAGE_ROOT, SAGE_LOCAL, SAGE_DB
     740
     741        self._download_db()
     742
     743        print "Database downloaded"
     744
     745        self.classes.clear_cache()
     746        self.inclusions.clear_cache()
     747        self.inclusion_digraph.clear_cache()
     748
     749    def _get_ISGCI(self):
     750        r"""
     751        Returns the contents of the ISGCI database.
     752
     753        This method is mostly for internal use, but often provides useful
     754        information during debugging operations.
     755
     756        OUTPUT:
     757
     758        A pair ``(classes, inclusions)`` where ``classes`` is a dict of dict, and
     759        ``inclusions`` is a list of dicts.
     760
     761        .. NOTE::
     762
     763            This method returns the data contained in the most recent ISGCI database
     764            present on the computer. See :meth:`update_db` to update the latter.
     765
     766        EXAMPLE::
     767
     768            sage: classes, inclusions = graph_classes._get_ISGCI()
     769        """
     770
     771        import os.path
     772        from sage.all import save, load
     773        from sage.misc.misc import SAGE_TMP, SAGE_ROOT, SAGE_LOCAL, SAGE_DB
     774
     775        try:
     776            open(SAGE_DB+"/"+_XML_FILE)
     777
     778            # Which copy is the most recent on the disk ?
     779            if (os.path.getmtime(SAGE_DB+"/"+_XML_FILE) >
     780                os.path.getmtime(SAGE_ROOT+"/data/graphs/"+_XML_FILE)):
     781
     782                filename = SAGE_DB+"/"+_XML_FILE
     783
     784            else:
     785                filename = SAGE_ROOT+"/data/graphs/"+_XML_FILE
     786
     787        except IOError as e:
     788            filename = SAGE_ROOT+"/data/graphs/"+_XML_FILE
     789
     790        return self._parse_db(filename)
     791
     792    def show_all(self):
     793        r"""
     794        Prints all graph classes stored in ISGCI
     795
     796        EXAMPLE::
     797
     798            sage: graph_classes.show_all()
     799            ID        | name                                     | type                 | smallgraph
     800            ----------------------------------------------------------------------------------------------------------------------
     801            gc_309    | $K_4$--minor--free                       | base                 |
     802            gc_541    | $N^*$                                    | base                 |
     803            gc_215    | $N^*$--perfect                           | base                 |
     804            gc_5      | $P_4$--bipartite                         | base                 |
     805            gc_3      | $P_4$--brittle                           | base                 |
     806            gc_6      | $P_4$--comparability                     | base                 |
     807            gc_7      | $P_4$--extendible                        | base                 |
     808            ...
     809        """
     810        classes = self.classes()
     811        classes_list = classes.values()
     812
     813        # We want to print the different fields, and this dictionary stores the
     814        # maximal number of characters of each field.
     815        MAX = {
     816            "ID" : 0,
     817            "type" : 0,
     818            "smallgraph": 0,
     819            "name": 0
     820            }
     821
     822        # We sort the classes alphabetically, though we would like to display the
     823        # meaningful classes at the top of the list
     824        classes_list.sort(key = lambda x:x.get("name","zzzzz")+"{0:4}".format(int(x["ID"].split('_')[1])))
     825
     826        # Maximum width of a field
     827        MAX_LEN = 40
     828
     829        # Computing te max of each field with the database
     830        for key in MAX:
     831            MAX[key] = len(max(map(lambda x:str(x.get(key,"")),classes_list), key = len))
     832
     833        # At most MAX characters per field
     834        for key, length in MAX.iteritems():
     835            MAX[key] = min(length, MAX_LEN)
     836
     837        # Head of the table
     838        print ("{0:"+str(MAX["ID"])+"} | {1:"+str(MAX["name"])+"} | {2:"+str(MAX["type"])+"} | {3:"+str(MAX["smallgraph"])+"}").format("ID", "name", "type", "smallgraph")
     839        print "-"*(sum(MAX.values())+9)
     840
     841        # Entries
     842        for entry in classes_list:
     843            ID = entry.get("ID","")
     844            name = entry.get("name","")
     845            type = entry.get("type","")
     846            smallgraph = entry.get("smallgraph","")
     847            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]
     848
     849graph_classes = GraphClasses()
     850
     851# Any object added to this list should also appear in the class' documentation, at the top of the file.
     852graph_classes.BinaryTrees = GraphClass("BinaryTrees", "gc_847")
     853graph_classes.Bipartite = GraphClass("Bipartite", "gc_69")
     854graph_classes.Block = GraphClass("Block", "gc_93")
     855graph_classes.Chordal = GraphClass("Chordal", "gc_32")
     856graph_classes.Comparability = GraphClass("Comparability", "gc_72")
     857graph_classes.Gallai = GraphClass("Gallai", "gc_73")
     858graph_classes.Grid = GraphClass("Grid", "gc_464")
     859graph_classes.Interval = GraphClass("Interval", "gc_234")
     860graph_classes.Line = GraphClass("Line", "gc_249")
     861graph_classes.Modular = GraphClass("Modular", "gc_50")
     862graph_classes.Outerplanar = GraphClass("Outerplanar", "gc_110")
     863graph_classes.Perfect = GraphClass("Perfect", "gc_56")
     864graph_classes.Planar = GraphClass("Planar", "gc_43")
     865graph_classes.Split = GraphClass("Split", "gc_39")
     866graph_classes.Tree = GraphClass("Tree", "gc_342")
     867graph_classes.UnitDisk = GraphClass("UnitDisk", "gc_389")
     868graph_classes.UnitInterval = GraphClass("UnitInterval", "gc_299")