# 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


58  58  <BLANKLINE> 
59  59  Problems : 
60  60   
 61  3Colourability : Linear 
 62  Clique : Polynomial 
 63  Clique cover : Polynomial 
 64  Cliquewidth : Unbounded 
 65  Cliquewidth expression : NPcomplete 
 66  Colourability : Linear 
 67  Domination : NPcomplete 
61  68  Independent set : Linear 
 69  Recognition : Linear 
62  70  Treewidth : Polynomial 
 71  Weighted clique : Polynomial 
63  72  Weighted independent set : Linear 
64   Cliquewidth expression : NPcomplete 
65   Weighted clique : Polynomial 
66   Clique cover : Polynomial 
67   Domination : NPcomplete 
68   Clique : Polynomial 
69   Colourability : Linear 
70   Cliquewidth : Unbounded 
71   3Colourability : Linear 
72   Recognition : Linear 
73  73  
74  74  It is possible to obtain the complete list of the classes stored in ISGCI by 
75  75  calling the :meth:`~GraphClasses.show_all` method (beware  long output):: 
… 
… 

190  190  in a huge dictionary (see :meth:`~sage.graphs.isgci.GraphClasses.classes`). 
191  191  Below is what Sage knows of ``gc_249``:: 
192  192  
193   sage: graph_classes.classes()['gc_249'] 
 193  sage: graph_classes.classes()['gc_249'] # random 
194  194  {'problems': 
195  195  {'Independent set': 'Polynomial', 
196  196  'Treewidth': 'Unknown', 
… 
… 

231  231  Hence bipartite graphs are perfect graphs. We can see how ISGCI obtains this 
232  232  result :: 
233  233  
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 
235  238  ['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 
238  244  
239  245  What ISGCI knows is that perfect graphs contain unimodular graph which contain 
240  246  bipartite graphs. Therefore bipartite graphs are perfect ! 
… 
… 

267  273  :meth:`~sage.graphs.isgci.GraphClasses.inclusion_digraph`. 
268  274  
269  275  * 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: 
271  277  
272  278  * ``sage.graphs.isgci._classes`` (dictionary) 
273  279  * ``sage.graphs.isgci._inclusions`` (list of dictionaries) 
… 
… 

467  473  <BLANKLINE> 
468  474  Problems : 
469  475   
 476  3Colourability : Linear 
 477  Clique : Polynomial 
 478  Clique cover : Polynomial 
 479  Cliquewidth : Unbounded 
 480  Cliquewidth expression : NPcomplete 
 481  Colourability : Linear 
 482  Domination : NPcomplete 
470  483  Independent set : Linear 
 484  Recognition : Linear 
471  485  Treewidth : Polynomial 
 486  Weighted clique : Polynomial 
472  487  Weighted independent set : Linear 
473   Cliquewidth expression : NPcomplete 
474   Weighted clique : Polynomial 
475   Clique cover : Polynomial 
476   Domination : NPcomplete 
477   Clique : Polynomial 
478   Colourability : Linear 
479   Cliquewidth : Unbounded 
480   3Colourability : Linear 
481   Recognition : Linear 
482  488  """ 
483  489  
484  490  classes = GraphClasses().classes() 
… 
… 

494  500  
495  501  print "\nProblems :" 
496  502  print ""*11 
497   for key, value in cls["problems"].iteritems(): 
 503  for key, value in sorted(cls["problems"].iteritems()): 
498  504  if value != "": 
499  505  print "{0:30} : ".format(key), 
500  506  print value 
… 
… 

548  554  Returns the graph classes, as a dictionary. 
549  555  
550  556  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. 
552  558  
553  559  EXAMPLES:: 
554  560  
… 
… 

576  582  a list of dictionaries 
577  583  
578  584  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. 
580  586  
581  587  EXAMPLES:: 
582  588  
… 
… 

595  601  Returns the class inclusion digraph 
596  602  
597  603  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. 
599  605  
600  606  EXAMPLES:: 
601  607  
… 
… 

625  631  sage: graph_classes._download_db() # Not tested  requires internet 
626  632  """ 
627  633  
628   from sage.misc.misc import SAGE_TMP 
 634  from sage.misc.misc import SAGE_TMP, SAGE_ROOT 
629  635  import urllib2 
630  636  u = urllib2.urlopen('http://www.graphclasses.org/data.zip') 
631  637  localFile = open(SAGE_TMP+'isgci.zip', 'w') 
… 
… 

633  639  localFile.close() 
634  640  import os, zipfile 
635  641  z = zipfile.ZipFile(SAGE_TMP+'isgci.zip') 
636   z.extract(_XML_FILE, SAGE_TMP) 
637  642  
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): 
639  652  r""" 
640  653  Parses the ISGCI database and returns its content as Python objects. 
641  654  
 655  INPUT: 
 656  
 657   ``xml_file``  the name of an XML file containing the data from ISGCI 
 658  
642  659  EXAMPLE:: 
643  660  
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'>] 
645  663  """ 
646   from sage.misc.misc import SAGE_TMP 
647  664  import xml.dom.minidom 
648  665  from xml.dom.minidom import Node 
649  666  
… 
… 

651  668  # database. It is admittedly not very pretty, but it builds the class we 
652  669  # want from the XML file and that's more or less all we ask it to do :p 
653  670  
654   doc = xml.dom.minidom.parse(SAGE_TMP+_XML_FILE) 
 671  doc = xml.dom.minidom.parse(xml_file) 
655  672  
656  673  classes = {} 
657  674  
… 
… 

705  722  r""" 
706  723  Updates the ISGCI database by downloading the latest version from internet. 
707  724  
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. 
710  728  
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). 
720  734  
721  735  EXAMPLE:: 
722  736  
… 
… 

728  742  
729  743  print "Database downloaded" 
730  744  
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") 
755  745  self.classes.clear_cache() 
756  746  self.inclusions.clear_cache() 
757  747  self.inclusion_digraph.clear_cache() 
758   print "Database saved to .sobj files in "+SAGE_DB 
759  748  
760  749  def _get_ISGCI(self): 
761  750  r""" 
… 
… 

784  773  from sage.misc.misc import SAGE_TMP, SAGE_ROOT, SAGE_LOCAL, SAGE_DB 
785  774  
786  775  try: 
787   open(SAGE_DB+"/isgci_classes.sobj") 
 776  open(SAGE_DB+"/"+_XML_FILE) 
788  777  
789  778  # 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)): 
792  781  
793   classes = load(SAGE_DB+"/isgci_classes.sobj") 
794   inclusions = load(SAGE_DB+"/isgci_inclusions.sobj") 
 782  filename = SAGE_DB+"/"+_XML_FILE 
795  783  
796  784  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 
799  786  
800  787  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 
804  789  
805   return classes, inclusions 
 790  return self._parse_db(filename) 
806  791  
807  792  def show_all(self): 
808  793  r""" 