Ticket #11880: trac_11880.patch

File trac_11880.patch, 26.3 KB (added by ncohen, 8 years ago)
  • doc/en/reference/graphs.rst

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1317396402 -7200
    # Node ID dabba6561a49043078372d281f2d9262ccb2bf55
    # Parent  e9560d18a936a029ae96e675f27c2eba4ba99faa
    trac 11880 -- ISGCI (a graph classes database)
    
    diff --git a/doc/en/reference/graphs.rst b/doc/en/reference/graphs.rst
    a b  
    2424   sage/graphs/graph_generators
    2525   sage/graphs/digraph_generators
    2626   sage/graphs/graph_database
     27   sage/graphs/isgci
    2728
    2829
    2930Low-level implementation
  • sage/graphs/all.py

    diff --git a/sage/graphs/all.py b/sage/graphs/all.py
    a b  
    1515from sage.graphs.cliquer import *
    1616from graph_database import graph_db_info
    1717from graph_editor import graph_editor
     18
     19import sage.graphs.isgci
     20from sage.graphs.isgci import graph_classes
    1821import 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 deals with anything related to the ISGCI database in Sage.
     5
     6The ISGCI database gathers information on graph classes and their inclusions in
     7each other. It also contains information on the complexity of several
     8computational problems.
     9
     10It is available on the `GraphClasses.org website
     11<http://www.graphclasses.org/>`_ maintained by H.N. de Ridder et al.
     12
     13How to use it ?
     14---------------
     15
     16The current support of the ISGCI database is elementary, and aims at
     17implementing a pure Sage/Python interface which is easier to deal with than a
     18XML file. I hope this code will be rewritten many times until it stabilizes :-)
     19
     20Presently, it is possible to use this database through the variables and methods
     21present in the ``graph_classes`` object. For instance ::
     22
     23    sage: Trees = graph_classes.Tree
     24    sage: Chordal = graph_classes.Chordal
     25
     26It is then possible to check the inclusion of classes inside of others, if the
     27information is available in the db::
     28
     29    sage: Trees <= Chordal
     30    True
     31
     32And indeed, the trees are chordal graphs.
     33
     34.. WARNING::
     35
     36    At the moment, only the *yes* answers can be assumed to be true !
     37
     38    ISGCI may not contain the information necessary to prove that a class A is a
     39    subset of a class B, but that does not mean that class A is **NOT** a subset
     40    of B. It just means ISGCI has no idea. Hence, no **NO** answer can be
     41    assumed to be true at the moment.
     42
     43    When asked to compare Trees and Chordal graphs, though, the correct answer
     44    is returned (as ISGCI obviously does not contain any proof that all chordal
     45    graphs are trees, which would be a mistake)::
     46
     47        sage: Chordal <= Trees
     48        False
     49
     50Given a graph class, one can obtain its associated information in the
     51ISGCI database with the :meth:`show
     52<sage.graphs.isgci.GraphClass.show>` method::
     53
     54    sage: Chordal.show()
     55    Class of graphs : Chordal
     56    -------------------------
     57    type                           :  base
     58    ID                             :  gc_32
     59    name                           :  chordal
     60    <BLANKLINE>
     61    Problems :
     62    -----------
     63    Independent set                :  Linear
     64    Treewidth                      :  Polynomial
     65    Weighted independent set       :  Linear
     66    Cliquewidth expression         :  NP-complete
     67    Weighted clique                :  Polynomial
     68    Clique cover                   :  Polynomial
     69    Domination                     :  NP-complete
     70    Clique                         :  Polynomial
     71    Colourability                  :  Linear
     72    Cliquewidth                    :  Unbounded
     73    3-Colourability                :  Linear
     74    Recognition                    :  Linear
     75
     76It is possible to obtain the complete list of the classes stored in ISGCI by
     77calling the :meth:`show_all <sage.graphs.isgci.show_all>` method
     78(beware -- long output)::
     79
     80    sage: sage.graphs.isgci.show_all()
     81    ID        | name                                     | type                 | smallgraph                             
     82    ----------------------------------------------------------------------------------------------------------------------
     83    gc_309    | $K_4$--minor--free                       | base                 |
     84    gc_541    | $N^*$                                    | base                 |
     85    gc_215    | $N^*$--perfect                           | base                 |
     86    gc_5      | $P_4$--bipartite                         | base                 |
     87    gc_3      | $P_4$--brittle                           | base                 |
     88    gc_6      | $P_4$--comparability                     | base                 |
     89    gc_7      | $P_4$--extendible                        | base                 |
     90    ...
     91
     92This lets one find a class which does not appear in ``graph_classes`` (and
     93should really be replaced by a proper search method). Given the ISGCI ID code
     94corresponding to a classe, the :meth:`get_class_from_id
     95<sage.graphs.isgci.GraphClasses.get_class_from_id>` method returns the
     96corresponding graph class::
     97
     98    sage: GC = graph_classes.get_class_from_id("gc_5")
     99    sage: GC
     100    Graph class : $P_4$--bipartite
     101
     102Predefined classes
     103------------------
     104
     105The ``graph_classes.*`` currently lists the following graph classes
     106
     107.. list-table::
     108   :widths: 20 30
     109   :header-rows: 1
     110
     111   * - Class
     112     - Related methods
     113
     114   * - BinaryTrees
     115
     116     - :meth:`BalancedTree <sage.graphs.graph_generators.GraphGenerators.BalancedTree>`,
     117       :meth:`is_tree <sage.graphs.generic_graph.GenericGraph.is_tree>`
     118
     119   * - Bipartite
     120
     121     - :meth:`BalancedTree <sage.graphs.graph_generators.GraphGenerators.BalancedTree>`,
     122       :meth:`is_bipartite <sage.graphs.graph.Graph.is_bipartite>`
     123
     124   * - Block
     125
     126     - :meth:`blocks_and_cut_vertices <sage.graphs.generic_graph.GenericGraph.blocks_and_cut_vertices>`,
     127
     128   * - Chordal
     129
     130     - :meth:`is_chordal <sage.graphs.generic_graph.GenericGraph.is_chordal>`
     131
     132   * - Clique
     133
     134     - :meth:`CompleteGraph <sage.graphs.graph_generators.GraphGenerators.CompleteGraph>`,
     135       :meth:`is_clique <sage.graphs.generic_graph.GenericGraph.is_clique>`
     136
     137   * - Comparability
     138     -
     139
     140   * - Gallai
     141
     142     - :meth:`is_gallai_tree <sage.graphs.generic_graph.GenericGraph.is_gallai_tree>`
     143
     144   * - Grid
     145
     146     - :meth:`Grid2dGraph <sage.graphs.graph_generators.GraphGenerators.Grid2dGraph>`,
     147       :meth:`GridGraph <sage.graphs.graph_generators.GraphGenerators.GridGraph>`
     148
     149   * - Interval
     150
     151     - :meth:`RandomInterval <sage.graphs.graph_generators.GraphGenerators.RandomInterval>`,
     152       :meth:`IntervalGraph <sage.graphs.graph_generators.GraphGenerators.IntervalGraph>`,
     153       :meth:`is_interval <sage.graphs.generic_graph.GenericGraph.is_interval>`
     154
     155   * - Line
     156
     157     - :meth:`line_graph_forbidden_subgraphs <sage.graphs.graph_generators.GraphGenerators.line_graph_forbidden_subgraphs>`,
     158       :meth:`is_line_graph <sage.graphs.graph.Graph.is_line_graph>`
     159
     160   * - Modular
     161
     162     - :meth:`modular_decomposition <sage.graphs.graph.Graph.modular_decomposition>`
     163
     164   * - Outerplanar
     165
     166     - :meth:`is_circular_planar <sage.graphs.generic_graph.GenericGraph.is_circular_planar>`
     167
     168   * - Perfect
     169
     170     - :meth:`is_perfect <sage.graphs.graph.Graph.is_perfect>`
     171
     172   * - Planar
     173
     174     - :meth:`is_planar <sage.graphs.generic_graph.GenericGraph.is_planar>`
     175
     176   * - Split
     177
     178     - :meth:`is_split <sage.graphs.graph.Graph.is_split>`
     179
     180   * - Tree
     181
     182     - :meth:`trees <sage.graphs.graph_generators.GraphGenerators.trees>`,
     183       :meth:`is_tree <sage.graphs.generic_graph.GenericGraph.is_tree>`
     184
     185   * - UnitDisk
     186     -
     187
     188   * - UnitInterval
     189
     190     - :meth:`is_interval <sage.graphs.generic_graph.GenericGraph.is_interval>`
     191
     192
     193Information for developpers
     194----------------------------
     195
     196* The database is not *so* large, but enough to prevent it from being loaded at
     197  Sage's startup. The internal methods using the database should often be
     198  preceded by a call to :meth:`_load_ISGCI_if_not_loaded
     199  <sage.graphs.isgci._load_ISGCI_if_not_loaded>` or to
     200  :meth:`_build_class_digraph_if_not_built
     201  <sage.graphs.isgci._build_class_digraph_if_not_built>`.
     202
     203* Once the database has been accessed once, the information is extracted from
     204  the ``.sobj`` files in which it is stored and their information can be
     205  accessed by the following variables :
     206
     207  * ``sage.graphs.isgci.classes`` (dictionary)
     208  * ``sage.graphs.isgci.inclusions`` (list of dictionaries)
     209  * ``sage.graphs.isgci.class_digraph`` (DiGraph)
     210
     211  Note that the digraph is only built if necessary (for instance if the user
     212  tried to compare two classes).
     213
     214* The ``DiGraph`` object ``sage.graphs.isgci.class_digraph`` has for vertex set
     215  the ID of the graph classes. This digraph contains an edge `uv` if the graph
     216  class represented by `u` is larger (not necessarily strictly) than the one
     217  represented by `v`.
     218
     219  Though it represents inclusions of sets, this ``DiGraph`` is **NOT
     220  ACYCLIC**. Several entries exist in the ISGCI database whise represent the
     221  same graph class::
     222
     223    sage: Berge = graph_classes.get_class_from_id("gc_274"); Berge
     224    Graph class : Berge
     225    sage: Perfect = graph_classes.get_class_from_id("gc_56"); Perfect
     226    Graph class : perfect
     227    sage: Berge <= Perfect
     228    True
     229    sage: Perfect <= Berge
     230    True
     231     
     232  (Which is the same as)::
     233
     234    sage: Perfect == Berge
     235    True
     236
     237  Indeed ::
     238
     239    sage: sage.graphs.isgci.class_digraph.is_directed_acyclic()
     240    False
     241
     242ToDo list
     243---------
     244
     245Technical things :
     246
     247* Find a proper way to find a graph class which does not appear in
     248  ``graph_classes`` by can be listed by :meth:`show_all
     249  <sage.graphs.isgci.show_all>`.
     250
     251* Some of the graph classes appearing in ``graph_classes.*`` already have a
     252  recognition algorithm in Sage. It would be so nice to be able to write ``g in
     253  Trees``, ``g in Perfect``, ``g in Chordal``, ... `:-)`
     254
     255Long-term stuff :
     256
     257* To be able to ask questions to ISGCI from the inside of Sage, easily enough,
     258  related to any information it contains (for instance everything that can be
     259  done through the website)
     260
     261* Write generic recognition algorithms for specific classes (when a graph class
     262  is defined by the exclusion of subgraphs, one can write a generic algorithm
     263  checking the existence of each of the graphs, and this method already exists
     264  in Sage).
     265
     266* Modify our algorithms so that they could use the properties of a graph class
     267  to improve their performances. Right now, the same algorithm is used to find
     268  an independent set in a tree, in a planar graph, or any other graph.
     269
     270
     271AUTHORS:
     272--------
     273
     274* H.N. de Ridder et al. (ISGCI database)
     275* Nathann Cohen (Sage implementation)
     276
     277Methods
     278-------
     279"""
     280
     281classes = {}
     282inclusions = []
     283class_digraph = None
     284
     285
     286#*****************************************************************************
     287#      Copyright (C) 2011 Nathann Cohen <nathann.cohen@gmail.com>           
     288#
     289# Distributed  under  the  terms  of  the  GNU  General  Public  License (GPL)
     290#                         http://www.gnu.org/licenses/
     291#*****************************************************************************
     292
     293_XML_FILE = "isgci_sage.xml"
     294
     295def _download_db():
     296    r"""
     297    Downloads the current version of the ISGCI db
     298
     299    EXAMPLE::
     300
     301        sage: sage.graphs.isgci._download_db() # Not tested -- requires internet
     302    """
     303
     304    from sage.misc.misc import SAGE_TMP
     305    import urllib2
     306    u = urllib2.urlopen('http://www.graphclasses.org/data.zip')
     307    localFile = open(SAGE_TMP+'isgci.zip', 'w')
     308    localFile.write(u.read())
     309    localFile.close()
     310    import os, zipfile
     311    z = zipfile.ZipFile(SAGE_TMP+'isgci.zip')
     312    z.extract(_XML_FILE, SAGE_TMP)
     313
     314def _create_db():
     315    r"""
     316    Parses the ISGCI database and returns its content as Python objects.
     317
     318    EXAMPLE::
     319
     320        sage: sage.graphs.isgci._create_db() # Not tested -- requires internet
     321    """
     322    from sage.misc.misc import SAGE_TMP
     323    import xml.dom.minidom
     324    from xml.dom.minidom import Node
     325
     326    # This method is there to parse the XML file containing the ISGCI
     327    # database. It is admittedly not very pretty, but it builds the class we
     328    # want from the XML file and that's more or less all we ask it to do :-p
     329
     330    doc = xml.dom.minidom.parse(SAGE_TMP+_XML_FILE)
     331   
     332    classes = {}
     333
     334    giveme = lambda x,y : str(x.getAttribute(y))
     335
     336    for node in doc.getElementsByTagName("GraphClass"):
     337        ID = str(node.getAttribute("id"))
     338        Dl = {}
     339        smallgraph = []
     340        Dl["ID"] = giveme(node, "id")
     341        problems = {}
     342        for node2 in node.childNodes:
     343            name = str(node2.nodeName)
     344            if name == "name":
     345                Dl[name] = str(node2.childNodes[0].nodeValue)
     346
     347            elif name ==  "smallgraph":
     348                smallgraph.append(str(node2.childNodes[0].nodeValue))
     349
     350            elif name == "problem":
     351                problems[giveme(node2, "name")] = giveme(node2, "complexity")
     352
     353        Dl["problems"] = problems
     354
     355        if smallgraph:
     356            Dl["smallgraph"] = smallgraph
     357
     358        if giveme(node, "type"):
     359            Dl["type"] = giveme(node, "type")
     360
     361   
     362        classes[giveme(node, "id")] = Dl
     363
     364    inclusions = []
     365    for node in doc.getElementsByTagName("incl"):
     366        Dl = {}
     367        for name in ["proper", "confidence", "super", "sub"]:
     368            if giveme(node, name):
     369                Dl[name] = giveme(node, name)           
     370
     371        for node2 in node.childNodes:
     372            name = str(node2.nodeName)
     373            if name == "ref":
     374                Dl[name] = str(node2.childNodes[0].nodeValue)
     375
     376        inclusions.append(Dl)
     377
     378    return classes, inclusions
     379
     380def update_db(verbose = False):
     381    r"""
     382    Updates the current version of the ISGCI database by download it from internet.
     383
     384    This method downloads the ISGCI database from the website `GraphClasses.org
     385    <http://www.graphclasses.org/>`_. 
     386
     387    It then extracts the zip file and parses its XML content, which is stored as
     388    two .sobj files, the first one representing the graph classes, and the
     389    second representing their inclusions.
     390
     391    Depending on the rights of the user running Sage when this command is run,
     392    one attempt is made at saving its result in Sage's directory so that all
     393    users would benefit from it. If the rights are not sufficient, the .sobj
     394    files are saved to the current user's directory, so that he will be the only
     395    one to benefit from the update.
     396
     397    INPUT:
     398
     399    - ``verbose`` (boolean) -- whether to output information of the update
     400      process.
     401
     402    EXAMPLE::
     403
     404        sage: sage.graphs.isgci.update_db() # Not tested -- requires internet
     405    """
     406    from sage.misc.misc import SAGE_TMP, SAGE_ROOT, SAGE_LOCAL, SAGE_DB
     407    global classes, inclusions, class_digraph
     408   
     409    try:
     410        _download_db()
     411    except:
     412        raise Exception("There has been a problem while downloading or unzipping the ISGCI database O_o")
     413
     414
     415    if verbose:
     416        print "Database downloaded"
     417
     418    classes, inclusions = _create_db()
     419
     420    if verbose:
     421        print "XML file converted to Python dictionaries"
     422   
     423
     424    from sage.all import save
     425   
     426    # Trying to save to Sage's directory
     427    try:
     428        save(classes, SAGE_ROOT+'/data/graphs/isgci_classes.sobj')
     429        save(inclusions, SAGE_ROOT+'/data/graphs/isgci_inclusions.sobj')
     430        inclusions = class_digraph = None
     431        classes = {}
     432        if verbose:
     433            print "Database saved to .sobj files in "+SAGE_ROOT+'/data/graphs/'
     434
     435        return
     436    except IOError:
     437        pass
     438
     439    # Trying to save to the user's home directory
     440    try:
     441        save(classes, SAGE_DB+"/isgci_classes.sobj")
     442        save(inclusions, SAGE_DB+"/isgci_inclusions.sobj")
     443        classes = inclusions = class_digraph = None
     444        if verbose:
     445            print "Database saved to .sobj files in "+SAGE_DB
     446
     447        return
     448
     449    except IOError:
     450        pass
     451
     452    # Gloops !
     453    raise Exception("Sage is unable to write the files to your"+
     454                    "computer ! This shouldn't have happened. "+
     455                    "Could you report the bug ? ;-)")
     456
     457def get_ISGCI():
     458    r"""
     459    Returns the contents of the ISGCI database.
     460
     461    This method is mostly for internal use, but often provides useful
     462    information during debugging operations.
     463
     464    OUTPUT:
     465
     466    A pair ``(classes, inclusions)`` where ``classes`` is a dict of dict, and
     467    ``inclusions`` is a list of dicts.
     468   
     469    .. NOTE::
     470
     471        This method returns the data contained in the most recent version of the
     472        ISGCI database present on the computer. See ``update_db`` to update it.
     473
     474    EXAMPLE::
     475
     476        sage: classes, inclusions = sage.graphs.isgci.get_ISGCI()
     477    """
     478
     479    import os.path
     480    from sage.all import save, load
     481    from sage.misc.misc import SAGE_TMP, SAGE_ROOT, SAGE_LOCAL, SAGE_DB
     482
     483    try:
     484        open(SAGE_DB+"/isgci_classes.sobj")
     485
     486        # Which copy is the most recent on the disk ?
     487        if (os.path.getmtime(SAGE_DB+"/isgci_classes.sobj") >
     488            os.path.getmtime(SAGE_ROOT+"/data/graphs/isgci_classes.sobj")):
     489           
     490            classes = load(SAGE_DB+"/isgci_classes.sobj")
     491            inclusions = load(SAGE_DB+"/isgci_inclusions.sobj")
     492
     493        else:
     494            classes = load(SAGE_ROOT+"/data/graphs/isgci_classes.sobj")
     495            inclusions = load(SAGE_ROOT+"/data/graphs/isgci_inclusions.sobj")
     496
     497    except IOError as e:
     498        # No local version of the file exists
     499        classes = load(SAGE_ROOT+"/data/graphs/isgci_classes.sobj")
     500        inclusions = load(SAGE_ROOT+"/data/graphs/isgci_inclusions.sobj")
     501
     502    return classes, inclusions
     503
     504def show_all():
     505    r"""
     506    Prints all graph classes stored in ISGCI
     507
     508    EXAMPLE::
     509
     510        sage: sage.graphs.isgci.show_all()
     511        ID        | name                                     | type                 | smallgraph                             
     512        ----------------------------------------------------------------------------------------------------------------------
     513        gc_309    | $K_4$--minor--free                       | base                 |
     514        gc_541    | $N^*$                                    | base                 |
     515        gc_215    | $N^*$--perfect                           | base                 |
     516        gc_5      | $P_4$--bipartite                         | base                 |
     517        gc_3      | $P_4$--brittle                           | base                 |
     518        gc_6      | $P_4$--comparability                     | base                 |
     519        gc_7      | $P_4$--extendible                        | base                 |
     520        ...
     521    """
     522    global classes
     523    _load_ISGCI_if_not_loaded()
     524    classes_list = classes.values()
     525
     526    # We want to print the different fields, and this dictionary stores the
     527    # maximal number of characters of each field.
     528    MAX = {
     529        "ID" : 0,
     530        "type" : 0,
     531        "smallgraph": 0,
     532        "name": 0
     533        }
     534
     535    # We sort the classes alphabetically, though we would like to display the
     536    # meaningful classes at the top of the list
     537    classes_list.sort(key = lambda x:x.get("name","zzzzz")+"{0:4}".format(int(x["ID"].split('_')[1])))
     538
     539    # Maximum width of a field
     540    MAX_LEN = 40
     541
     542    # Computing te max of each field with the database
     543    for key in MAX:
     544        MAX[key] = len(max(map(lambda x:str(x.get(key,"")),classes_list), key = len))
     545
     546    # At most MAX characters per field
     547    for key, length in MAX.iteritems():
     548        MAX[key] = min(length, MAX_LEN)
     549
     550    # Head of the table
     551    print ("{0:"+str(MAX["ID"])+"} | {1:"+str(MAX["name"])+"} | {2:"+str(MAX["type"])+"} | {3:"+str(MAX["smallgraph"])+"}").format("ID", "name", "type", "smallgraph")
     552    print "-"*(sum(MAX.values())+9)
     553
     554    # Entries
     555    for entry in classes_list:
     556        ID = entry.get("ID","")
     557        name = entry.get("name","")
     558        type = entry.get("type","")
     559        smallgraph = entry.get("smallgraph","")
     560        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]
     561
     562def _load_ISGCI_if_not_loaded():
     563    r"""
     564    Load ISGI if not loaded already
     565
     566    This is here to avoid having to load the db when Sage starts
     567    """
     568    global classes, inclusions
     569    if classes == {}:
     570        classes, inclusions = get_ISGCI()
     571
     572def _build_class_digraph_if_not_built():
     573    r"""
     574    Builds the class digraph
     575    """
     576    global classes, inclusions, class_digraph
     577
     578    if not (class_digraph is None):
     579        return
     580
     581    _load_ISGCI_if_not_loaded()
     582
     583    from sage.graphs.digraph import DiGraph
     584    class_digraph = DiGraph()
     585    class_digraph.add_vertices(classes.keys())
     586
     587    for edge in inclusions:
     588        if edge.get("confidence","") == "unpublished":
     589            continue
     590
     591        class_digraph.add_edge(edge['super'], edge['sub'])
     592   
     593    inclusions = []
     594
     595class GraphClass:
     596    r"""
     597    An instance of this class represents a Graph Class, matching some entry in
     598    the ISGCI database.
     599
     600    EXAMPLE:
     601
     602    Testing the inclusion of two classes::
     603
     604        sage: Chordal = graph_classes.Chordal
     605        sage: Trees = graph_classes.Tree
     606        sage: Trees <= Chordal
     607        True
     608        sage: Chordal <= Trees
     609        False
     610
     611    TEST::
     612
     613        sage: Trees >= Chordal
     614        False
     615        sage: Chordal >= Trees
     616        True
     617    """
     618    def __init__(self, name, gc_id):
     619        self._name = name
     620        self._gc_id = gc_id
     621
     622    def __repr__(self):
     623        r"""
     624        Returns a short description of the class
     625
     626        EXAMPLE::
     627
     628            sage: graph_classes.Chordal
     629            Graph class : Chordal
     630        """
     631        return self._name+" graphs"
     632
     633    def __hash__(self):
     634        r"""
     635        Returns the class' ID
     636        """
     637        return self._gc_id
     638
     639    def __le__(self, other):
     640        return other.__ge__(self)
     641
     642    def __ge__(self, other):
     643        global class_digraph, classes
     644
     645        _build_class_digraph_if_not_built()
     646
     647        return (class_digraph.shortest_path(self._gc_id,other._gc_id) != [])
     648
     649    def __eq__(self, other):
     650        return self.__ge__(other) and other.__ge__(self)
     651
     652    def __lt__(self, other):
     653        raise Exception("Not Implemented")
     654
     655    __gt__ = __ne__ = __lt__
     656
     657    def show(self):
     658        r"""
     659        Prints the information of ISGCI about the current class.
     660
     661        EXAMPLE::
     662
     663            sage: graph_classes.Chordal.show()
     664            Class of graphs : Chordal
     665            -------------------------
     666            type                           :  base
     667            ID                             :  gc_32
     668            name                           :  chordal
     669            <BLANKLINE>
     670            Problems :
     671            -----------
     672            Independent set                :  Linear
     673            Treewidth                      :  Polynomial
     674            Weighted independent set       :  Linear
     675            Cliquewidth expression         :  NP-complete
     676            Weighted clique                :  Polynomial
     677            Clique cover                   :  Polynomial
     678            Domination                     :  NP-complete
     679            Clique                         :  Polynomial
     680            Colourability                  :  Linear
     681            Cliquewidth                    :  Unbounded
     682            3-Colourability                :  Linear
     683            Recognition                    :  Linear
     684        """
     685        global classes
     686        _load_ISGCI_if_not_loaded()
     687
     688        classs = classes[self._gc_id]
     689        print "Class of graphs : "+self._name
     690        print "-"*(len(self._name)+18)
     691
     692        for key, value in classs.iteritems():
     693            if value != "" and key != "problems":
     694                print "{0:30} : ".format(key),
     695                print value
     696
     697        print "\nProblems :"
     698        print "-"*11
     699        for key, value in classs["problems"].iteritems():
     700            if value != "":
     701                print "{0:30} : ".format(key),
     702                print value
     703       
     704
     705
     706class GraphClasses:
     707    def get_class_from_id(self, ID):
     708        r"""
     709        Returns the class corresponding to the given ID in the ISGCI database.
     710
     711        EXAMPLE:
     712
     713        With an existing ID::
     714
     715            sage: Cographs = graph_classes.get_class_from_id("gc_151")
     716            sage: Cographs
     717            Graph class : cograph
     718
     719        With a wrong ID::
     720
     721            sage: graph_classes.get_class_from_id(-1)
     722            Traceback (most recent call last):
     723            ...
     724            ValueError: The given class ID does not exist in the ISGCI database. Is the db too old ? You can update it with sage.graphs.isgci.update_db().
     725        """
     726        global classes
     727        _load_ISGCI_if_not_loaded()
     728        if ID in classes:
     729            c = classes[ID]
     730
     731            if "name" in c and c["name"] != "":
     732                name = c["name"]
     733            else:
     734                name = "class "+str(ID)
     735
     736            return GraphClass(name, ID)
     737
     738        else:
     739            raise ValueError("The given class ID does not exist in the ISGCI database. Is the db too old ? You can update it with sage.graphs.isgci.update_db().")
     740
     741graph_classes = GraphClasses()
     742
     743
     744
     745
     746
     747
     748# Any object added to this list should also appear in the class' documentation, at the top of the file.
     749graph_classes.BinaryTrees = GraphClass("BinaryTrees", "gc_847")
     750graph_classes.Bipartite = GraphClass("Bipartite", "gc_69")
     751graph_classes.Block = GraphClass("Block", "gc_93")
     752graph_classes.Chordal = GraphClass("Chordal", "gc_32")
     753graph_classes.Clique = GraphClass("Clique", "gc_141")
     754graph_classes.Comparability = GraphClass("Comparability", "gc_72")
     755graph_classes.Gallai = GraphClass("Gallai", "gc_73")
     756graph_classes.Grid = GraphClass("Grid", "gc_464")
     757graph_classes.Interval = GraphClass("Interval", "gc_234")
     758graph_classes.Line = GraphClass("Line", "gc_249")
     759graph_classes.Modular = GraphClass("Modular", "gc_50")
     760graph_classes.Outerplanar = GraphClass("Outerplanar", "gc_110")
     761graph_classes.Perfect = GraphClass("Perfect", "gc_56")
     762graph_classes.Planar = GraphClass("Planar", "gc_43")
     763graph_classes.Split = GraphClass("Split", "gc_39")
     764graph_classes.Tree = GraphClass("Tree", "gc_342")
     765graph_classes.UnitDisk = GraphClass("UnitDisk", "gc_389")
     766graph_classes.UnitInterval = GraphClass("UnitInterval", "gc_299")
     767