Path: blob/master/src/sage/combinat/designs/ext_rep.py
8818 views
"""1External Representations of Block Designs23The "ext_rep" module is an API to the abstract tree represented by4an XML document containing the External Representation of a list of5block designs. The module also provides the related I/O operations for6reading/writing ext-rep files or data. The parsing is based on expat.78This is a modified form of the module ext_rep.py (version 0.8)9written by Peter Dobcsanyi [D2009]_ [email protected].1011REFERENCES:1213.. [D2009] P. Dobcsanyi et al. DesignTheory.org14http://designtheory.org/database/1516TODO: The XML data from the designtheory.org database contains a wealth17of information about things like automorphism groups, transitivity,18cycle type representatives, etc, but none of this data is made19available through the current implementation.20"""2122###########################################################################23# This software is released under the terms of the GNU General Public24# License, version 2 or above (your choice). For details on licensing,25# see the accompanying documentation.26#27# This is a modified form of the module ext_rep.py (version 0.8)28# written by Peter Dobcsanyi [email protected].29#30# Copyright 2004 by Peter Dobcsanyi [email protected], and copyright31# 2009 Carlo Hamalainen [email protected]32###########################################################################3334import sys35import xml.parsers.expat36from types import *37import re38import os.path39import gzip40import bz241from sage.misc.misc import tmp_filename42import urllib243import sys4445XML_NAMESPACE = 'http://designtheory.org/xml-namespace'46DTRS_PROTOCOL = '2.0'4748# The following string is the file49# http://designtheory.org/database/v-b-k/v2-b2-k2.icgsa.txt.bz250# We use this for doctests to make sure that the parsing works.5152v2_b2_k2_icgsa = \53"""<?xml version="1.0"?>54<list_of_designs55design_type="block_design"56dtrs_protocol="2.0"57no_designs="1"58pairwise_nonisomorphic="true"59xmlns="http://designtheory.org/xml-namespace">60<info>61<software>62[ DESIGN-1.1, GRAPE-4.2, GAPDoc-0.9999, GAP-4.4.3 ]63</software>64<software>65[ bdstat-0.8/280, numarray-1.1.1, pydesign-0.5/274, python-2.4.0.final.0 ]66</software>67</info>68<designs>69<block_design70b="2"71id="v2-b2-k2-0"72v="2">73<blocks ordered="true">74<block>75<z>0</z>76<z>1</z>77</block>78<block>79<z>0</z>80<z>1</z>81</block>82</blocks>83<indicators>84<repeated_blocks flag="true"/>85<resolvable flag="true"/>86<affine_resolvable87flag="true"88mu="2"/>89<equireplicate90flag="true"91r="2"/>92<constant_blocksize93flag="true"94k="2"/>95<t_design96flag="true"97maximum_t="2"/>98<connected99flag="true"100no_components="1"/>101<pairwise_balanced102flag="true"103lambda="2"/>104<variance_balanced flag="true"/>105<efficiency_balanced flag="true"/>106<cyclic flag="true"/>107<one_rotational flag="true"/>108</indicators>109<combinatorial_properties>110<point_concurrences>111<function_on_ksubsets_of_indices112domain_base="points"113k="1"114n="2"115ordered="true"116title="replication_numbers">117<map>118<preimage>119<entire_domain/>120</preimage>121<image>122<z>2</z>123</image>124</map>125</function_on_ksubsets_of_indices>126<function_on_ksubsets_of_indices127domain_base="points"128k="2"129n="2"130ordered="true"131title="pairwise_point_concurrences">132<map>133<preimage>134<entire_domain/>135</preimage>136<image>137<z>2</z>138</image>139</map>140</function_on_ksubsets_of_indices>141</point_concurrences>142<block_concurrences>143<function_on_ksubsets_of_indices144domain_base="blocks"145k="1"146n="2"147ordered="unknown"148title="block_sizes">149<map>150<preimage_cardinality>151<z>2</z>152</preimage_cardinality>153<image>154<z>2</z>155</image>156</map>157</function_on_ksubsets_of_indices>158<function_on_ksubsets_of_indices159domain_base="blocks"160k="2"161n="2"162ordered="unknown"163title="pairwise_block_intersection_sizes">164<map>165<preimage_cardinality>166<z>1</z>167</preimage_cardinality>168<image>169<z>2</z>170</image>171</map>172</function_on_ksubsets_of_indices>173</block_concurrences>174<t_design_properties>175<parameters176b="2"177k="2"178lambda="2"179r="2"180t="2"181v="2"/>182<square flag="true"/>183<projective_plane flag="false"/>184<affine_plane flag="false"/>185<steiner_system flag="false"/>186<steiner_triple_system flag="false"/>187</t_design_properties>188<alpha_resolvable>189<index_flag190flag="true"191index="2"/>192</alpha_resolvable>193<t_wise_balanced>194<index_flag195flag="true"196index="1"/>197<index_flag198flag="true"199index="2"/>200</t_wise_balanced>201</combinatorial_properties>202<automorphism_group>203<permutation_group204degree="2"205domain="points"206order="2">207<generators>208<permutation>209<z>1</z>210<z>0</z>211</permutation>212</generators>213<permutation_group_properties>214<primitive flag="true"/>215<generously_transitive flag="true"/>216<multiplicity_free flag="true"/>217<stratifiable flag="true"/>218<no_orbits value="1"/>219<degree_transitivity value="2"/>220<rank value="2"/>221<cycle_type_representatives>222<cycle_type_representative>223<permutation>224<z>1</z>225<z>0</z>226</permutation>227<cycle_type ordered="true">228<z>2</z>229</cycle_type>230<no_having_cycle_type>231<z>1</z>232</no_having_cycle_type>233</cycle_type_representative>234<cycle_type_representative>235<permutation>236<z>0</z>237<z>1</z>238</permutation>239<cycle_type ordered="true">240<z>1</z>241<z>1</z>242</cycle_type>243<no_having_cycle_type>244<z>1</z>245</no_having_cycle_type>246</cycle_type_representative>247</cycle_type_representatives>248</permutation_group_properties>249</permutation_group>250<automorphism_group_properties>251<block_primitive flag="not_applicable"/>252<no_block_orbits value="not_applicable"/>253<degree_block_transitivity value="not_applicable"/>254</automorphism_group_properties>255</automorphism_group>256<resolutions257all_classes_represented="true"258pairwise_nonisomorphic="true">259<resolution>260<function_on_indices261domain="blocks"262n="2"263ordered="true"264title="resolution">265<map>266<preimage>267<z>0</z>268</preimage>269<image>270<z>0</z>271</image>272</map>273<map>274<preimage>275<z>0</z>276</preimage>277<image>278<z>1</z>279</image>280</map>281</function_on_indices>282<automorphism_group>283<permutation_group284degree="2"285domain="points"286order="2">287<generators>288<permutation>289<z>1</z>290<z>0</z>291</permutation>292</generators>293</permutation_group>294</automorphism_group>295</resolution>296</resolutions>297<statistical_properties precision="9">298<canonical_variances299no_distinct="1"300ordered="true">301<value multiplicity="1">302<d>0.5</d>303</value>304</canonical_variances>305<pairwise_variances>306<function_on_ksubsets_of_indices307domain_base="points"308k="2"309n="2"310ordered="true">311<map>312<preimage>313<entire_domain/>314</preimage>315<image>316<d>1.0</d>317</image>318</map>319</function_on_ksubsets_of_indices>320</pairwise_variances>321<optimality_criteria>322<phi_0>323<value>324<d>-0.693147181</d>325</value>326<absolute_efficiency>327<z>1</z>328</absolute_efficiency>329<calculated_efficiency>330<z>1</z>331</calculated_efficiency>332</phi_0>333<phi_1>334<value>335<d>0.5</d>336</value>337<absolute_efficiency>338<z>1</z>339</absolute_efficiency>340<calculated_efficiency>341<z>1</z>342</calculated_efficiency>343</phi_1>344<phi_2>345<value>346<d>0.25</d>347</value>348<absolute_efficiency>349<z>1</z>350</absolute_efficiency>351<calculated_efficiency>352<z>1</z>353</calculated_efficiency>354</phi_2>355<maximum_pairwise_variances>356<value>357<d>1.0</d>358</value>359<absolute_efficiency>360<z>1</z>361</absolute_efficiency>362<calculated_efficiency>363<z>1</z>364</calculated_efficiency>365</maximum_pairwise_variances>366<E_criteria>367<E_value index="1">368<value>369<d>0.5</d>370</value>371<absolute_efficiency>372<z>1</z>373</absolute_efficiency>374<calculated_efficiency>375<z>1</z>376</calculated_efficiency>377</E_value>378</E_criteria>379</optimality_criteria>380<other_ordering_criteria>381<trace_of_square_of_C>382<value>383<d>4.0</d>384</value>385<absolute_comparison>386<z>1</z>387</absolute_comparison>388<calculated_comparison>389<z>1</z>390</calculated_comparison>391</trace_of_square_of_C>392<max_min_ratio_canonical_variances>393<value>394<d>1.0</d>395</value>396<absolute_comparison>397<z>1</z>398</absolute_comparison>399<calculated_comparison>400<z>1</z>401</calculated_comparison>402</max_min_ratio_canonical_variances>403<max_min_ratio_pairwise_variances>404<value>405<d>1.0</d>406</value>407<absolute_comparison>408<z>1</z>409</absolute_comparison>410<calculated_comparison>411<z>1</z>412</calculated_comparison>413</max_min_ratio_pairwise_variances>414<no_distinct_canonical_variances>415<value>416<z>1</z>417</value>418<absolute_comparison>419<z>1</z>420</absolute_comparison>421<calculated_comparison>422<z>1</z>423</calculated_comparison>424</no_distinct_canonical_variances>425<no_distinct_pairwise_variances>426<value>427<z>1</z>428</value>429<absolute_comparison>430<z>1</z>431</absolute_comparison>432<calculated_comparison>433<z>1</z>434</calculated_comparison>435</no_distinct_pairwise_variances>436</other_ordering_criteria>437<canonical_efficiency_factors438no_distinct="1"439ordered="true">440<value multiplicity="1">441<d>1.0</d>442</value>443</canonical_efficiency_factors>444<functions_of_efficiency_factors>445<harmonic_mean alias="A">446<value>447<d>1.0</d>448</value>449</harmonic_mean>450<geometric_mean alias="D">451<value>452<d>1.0</d>453</value>454</geometric_mean>455<minimum alias="E">456<value>457<d>1.0</d>458</value>459</minimum>460</functions_of_efficiency_factors>461</statistical_properties>462</block_design>463</designs>464</list_of_designs>465"""466467def dump_to_tmpfile(s):468"""469Utility function to dump a string to a temporary file.470471EXAMPLE::472473sage: from sage.combinat.designs import ext_rep474sage: file_loc = ext_rep.dump_to_tmpfile("boo")475sage: os.remove(file_loc)476"""477478file_loc = tmp_filename()479f = open(file_loc,"w")480f.write(v2_b2_k2_icgsa)481f.close()482return file_loc483484def check_dtrs_protocols(input_name, input_pv):485"""486Check that the XML data is in a valid format. We can currently487handle version 2.0. For more information see488http://designtheory.org/library/extrep/489490EXAMPLES::491492sage: from sage.combinat.designs import ext_rep493sage: ext_rep.check_dtrs_protocols('source', '2.0')494sage: ext_rep.check_dtrs_protocols('source', '3.0')495Traceback (most recent call last):496...497RuntimeError: Incompatible dtrs_protocols: program: 2.0 source: 3.0498"""499500program_pv = DTRS_PROTOCOL501ppv_major, ppv_minor = program_pv.split('.')502ipv_major, ipv_minor = input_pv.split('.')503if ppv_major != ipv_major or int(ppv_minor) < int(ipv_minor):504msg = ('''Incompatible dtrs_protocols: program: %s %s: %s''' % (program_pv, input_name, input_pv))505raise RuntimeError, msg506507def open_extrep_file(fname):508"""509Try to guess the compression type from extension510and open the extrep file.511512EXAMPLES::513514sage: from sage.combinat.designs import ext_rep515sage: file_loc = ext_rep.dump_to_tmpfile(ext_rep.v2_b2_k2_icgsa)516sage: proc = ext_rep.XTreeProcessor()517sage: f = ext_rep.open_extrep_file(file_loc)518sage: proc.parse(f)519sage: f.close()520sage: os.remove(file_loc)521"""522523if fname == '-':524f = sys.stdin525else:526root, ext = os.path.splitext(fname)527if ext == '.gz':528f = gzip.GzipFile(fname)529elif ext == '.bz2':530f = bz2.BZ2File(fname)531else:532f = open(fname)533return f534535def open_extrep_url(url):536"""537Try to guess the compression type from extension538and open the extrep file pointed to by the url. This function539(unlike open_extrep_file) returns the uncompressed text contained in540the file.541542EXAMPLES::543544sage: from sage.combinat.designs import ext_rep545sage: file_loc = ext_rep.dump_to_tmpfile(ext_rep.v2_b2_k2_icgsa)546sage: proc = ext_rep.XTreeProcessor()547sage: s = ext_rep.open_extrep_url("file://" + file_loc)548sage: proc.parse(s)549sage: os.remove(file_loc)550551sage: from sage.combinat.designs import ext_rep552sage: s = ext_rep.designs_from_XML_url("http://designtheory.org/database/v-b-k/v3-b6-k2.icgsa.txt.bz2") # optional - internet553"""554555f = urllib2.urlopen(url)556557root, ext = os.path.splitext(url)558if ext == '.gz':559# f = gzip.GzipFile(f_url)560raise NotImplemented561elif ext == '.bz2':562return bz2.decompress(f.read())563else:564return f.read()565566pattern_integer = re.compile(r'\d+$')567pattern_decimal = re.compile(r'-?\d+\.\d+$')568pattern_rational = re.compile(r'-?\d+/\d+$')569570def _encode_attribute(string):571"""572Convert numbers in attributes into binary format.573Currently integer and floating point conversions are implemented.574575EXAMPLES::576577sage: from sage.combinat.designs.ext_rep import _encode_attribute578sage: _encode_attribute('1')5791580sage: _encode_attribute('2')5812582sage: _encode_attribute('12')58312584sage: _encode_attribute('true')585'true'586sage: _encode_attribute('A')587'A'588sage: _encode_attribute('D')589'D'590sage: _encode_attribute('E')591'E'592"""593594if pattern_integer.match(string):595return int(string)596elif pattern_decimal.match(string):597return float(string)598else:599return string600601class XTree(object):602'''603A lazy class to wrap a rooted tree representing an XML document.604The tree's nodes are tuples of the structure:605606(name, {dictionary of attributes}, [list of children])607608Methods and services of an XTree object ``t``:609610- ``t.attribute`` -- attribute named611- ``t.child`` -- first child named612- ``t[i]`` -- i-th child613- ``for child in t:`` -- iterate over ``t``'s children614- ``len(t)`` -- number of ``t``'s children615616If child is not an empty subtree, return the subtree as an ``XTree``617object. If child is an empty subtree, return ``_name`` of the subtree.618Otherwise return the child itself.619620The lazy tree idea originated from a utility class of the621pyRXP 0.9 package by Robin Becker at ReportLab.622'''623624def __init__(self, node):625"""626Initialisation method given a node in an XML document.627628EXAMPLES::629630sage: from sage.combinat.designs.ext_rep import *631sage: xt = XTree(('blocks', {'ordered': 'true'}, [('block', {}, [[0, 1, 2]]), ('block', {}, [[0, 3, 4]]), ('block', {}, [[0, 5, 6]]), ('block', {}, [[0, 7, 8]]), ('block', {}, [[0, 9, 10]]), ('block', {}, [[0, 11, 12]]), ('block', {}, [[1, 3, 5]]), ('block', {}, [[1, 4, 6]]), ('block', {}, [[1, 7, 9]]), ('block', {}, [[1, 8, 11]]), ('block', {}, [[1, 10, 12]]), ('block', {}, [[2, 3, 7]]), ('block', {}, [[2, 4, 8]]), ('block', {}, [[2, 5, 10]]), ('block', {}, [[2, 6, 12]]), ('block', {}, [[2, 9, 11]]), ('block', {}, [[3, 6, 9]]), ('block', {}, [[3, 8, 12]]), ('block', {}, [[3, 10, 11]]), ('block', {}, [[4, 5, 11]]), ('block', {}, [[4, 7, 10]]), ('block', {}, [[4, 9, 12]]), ('block', {}, [[5, 7, 12]]), ('block', {}, [[5, 8, 9]]), ('block', {}, [[6, 7, 11]]), ('block', {}, [[6, 8, 10]])]))632sage: xt.xt_children633[('block', {}, [[0, 1, 2]]),634('block', {}, [[0, 3, 4]]),635('block', {}, [[0, 5, 6]]),636('block', {}, [[0, 7, 8]]),637('block', {}, [[0, 9, 10]]),638('block', {}, [[0, 11, 12]]),639('block', {}, [[1, 3, 5]]),640('block', {}, [[1, 4, 6]]),641('block', {}, [[1, 7, 9]]),642('block', {}, [[1, 8, 11]]),643('block', {}, [[1, 10, 12]]),644('block', {}, [[2, 3, 7]]),645('block', {}, [[2, 4, 8]]),646('block', {}, [[2, 5, 10]]),647('block', {}, [[2, 6, 12]]),648('block', {}, [[2, 9, 11]]),649('block', {}, [[3, 6, 9]]),650('block', {}, [[3, 8, 12]]),651('block', {}, [[3, 10, 11]]),652('block', {}, [[4, 5, 11]]),653('block', {}, [[4, 7, 10]]),654('block', {}, [[4, 9, 12]]),655('block', {}, [[5, 7, 12]]),656('block', {}, [[5, 8, 9]]),657('block', {}, [[6, 7, 11]]),658('block', {}, [[6, 8, 10]])]659"""660661662if type(node) == StringType:663node = (node, {}, [])664name, attributes, children = node665self.xt_node = node666self.xt_name = name667self.xt_attributes = attributes668self.xt_children = children669670def __repr__(self):671"""672String representation of an XTree object.673674EXAMPLES::675676sage: from sage.combinat.designs.ext_rep import *677sage: xt = XTree(('blocks', {'ordered': 'true'}, [('block', {}, [[0, 1, 2]]), ('block', {}, [[0, 3, 4]]), ('block', {}, [[0, 5, 6]]), ('block', {}, [[0, 7, 8]]), ('block', {}, [[0, 9, 10]]), ('block', {}, [[0, 11, 12]]), ('block', {}, [[1, 3, 5]]), ('block', {}, [[1, 4, 6]]), ('block', {}, [[1, 7, 9]]), ('block', {}, [[1, 8, 11]]), ('block', {}, [[1, 10, 12]]), ('block', {}, [[2, 3, 7]]), ('block', {}, [[2, 4, 8]]), ('block', {}, [[2, 5, 10]]), ('block', {}, [[2, 6, 12]]), ('block', {}, [[2, 9, 11]]), ('block', {}, [[3, 6, 9]]), ('block', {}, [[3, 8, 12]]), ('block', {}, [[3, 10, 11]]), ('block', {}, [[4, 5, 11]]), ('block', {}, [[4, 7, 10]]), ('block', {}, [[4, 9, 12]]), ('block', {}, [[5, 7, 12]]), ('block', {}, [[5, 8, 9]]), ('block', {}, [[6, 7, 11]]), ('block', {}, [[6, 8, 10]])]))678sage: xt.__repr__()679'XTree<blocks>'680"""681682return 'XTree<%s>' % self.xt_name683684def __getattr__(self, attr):685"""686Returns the data for the first attribute with name attr.687688EXAMPLES::689690sage: from sage.combinat.designs.ext_rep import *691sage: xt = XTree(('blocks', {'ordered': 'true'}, [('block', {}, [[0, 1, 2]]), ('block', {}, [[0, 3, 4]]), ('block', {}, [[0, 5, 6]]), ('block', {}, [[0, 7, 8]]), ('block', {}, [[0, 9, 10]]), ('block', {}, [[0, 11, 12]]), ('block', {}, [[1, 3, 5]]), ('block', {}, [[1, 4, 6]]), ('block', {}, [[1, 7, 9]]), ('block', {}, [[1, 8, 11]]), ('block', {}, [[1, 10, 12]]), ('block', {}, [[2, 3, 7]]), ('block', {}, [[2, 4, 8]]), ('block', {}, [[2, 5, 10]]), ('block', {}, [[2, 6, 12]]), ('block', {}, [[2, 9, 11]]), ('block', {}, [[3, 6, 9]]), ('block', {}, [[3, 8, 12]]), ('block', {}, [[3, 10, 11]]), ('block', {}, [[4, 5, 11]]), ('block', {}, [[4, 7, 10]]), ('block', {}, [[4, 9, 12]]), ('block', {}, [[5, 7, 12]]), ('block', {}, [[5, 8, 9]]), ('block', {}, [[6, 7, 11]]), ('block', {}, [[6, 8, 10]])]))692sage: xt.__getattr__('block')693[0, 1, 2]694"""695696if self.xt_attributes.has_key(attr):697return self.xt_attributes[attr]698else:699for child in self.xt_children:700name, attributes, children = child701if name == attr:702if len(attributes) > 0:703return XTree(child)704else:705if len(children) == 0:706# need this to get an empty Xtree, for append707return XTree(child)708grandchild = children[0]709if type(grandchild) == TupleType:710if len(grandchild[1]) == 0 and \711len(grandchild[2]) == 0:712return grandchild[0]713else:714return XTree(child)715else:716return grandchild717msg = '"%s" is not found in attributes of %s or its children.' % \718(attr, self)719raise AttributeError, msg720721def __getitem__(self, i):722"""723Get the ``i``-th item in the current node.724725EXAMPLES::726727sage: from sage.combinat.designs.ext_rep import *728sage: xt = XTree(('blocks', {'ordered': 'true'}, [('block', {}, [[0, 1, 2]]), ('block', {}, [[0, 3, 4]]), ('block', {}, [[0, 5, 6]]), ('block', {}, [[0, 7, 8]]), ('block', {}, [[0, 9, 10]]), ('block', {}, [[0, 11, 12]]), ('block', {}, [[1, 3, 5]]), ('block', {}, [[1, 4, 6]]), ('block', {}, [[1, 7, 9]]), ('block', {}, [[1, 8, 11]]), ('block', {}, [[1, 10, 12]]), ('block', {}, [[2, 3, 7]]), ('block', {}, [[2, 4, 8]]), ('block', {}, [[2, 5, 10]]), ('block', {}, [[2, 6, 12]]), ('block', {}, [[2, 9, 11]]), ('block', {}, [[3, 6, 9]]), ('block', {}, [[3, 8, 12]]), ('block', {}, [[3, 10, 11]]), ('block', {}, [[4, 5, 11]]), ('block', {}, [[4, 7, 10]]), ('block', {}, [[4, 9, 12]]), ('block', {}, [[5, 7, 12]]), ('block', {}, [[5, 8, 9]]), ('block', {}, [[6, 7, 11]]), ('block', {}, [[6, 8, 10]])]))729sage: xt.__getitem__(0)730[0, 1, 2]731sage: xt.__getitem__(1)732[0, 3, 4]733"""734735try:736child = self.xt_children[i]737except IndexError:738raise IndexError, '%s no index %s' % (self.__repr__(), `i`)739if type(child) == TupleType:740name, attributes, children = child741if len(attributes) > 0:742return XTree(child)743else:744grandchild = children[0]745if type(grandchild) == TupleType:746if len(grandchild[1]) == 0 and len(grandchild[2]) == 0:747return grandchild[0]748else:749return XTree(child)750else:751return grandchild752else:753return child754755def __len__(self):756"""757Returns the length of the current node.758759EXAMPLES::760761sage: from sage.combinat.designs.ext_rep import *762sage: xt = XTree(('blocks', {'ordered': 'true'}, [('block', {}, [[0, 1, 2]]), ('block', {}, [[0, 3, 4]]), ('block', {}, [[0, 5, 6]]), ('block', {}, [[0, 7, 8]]), ('block', {}, [[0, 9, 10]]), ('block', {}, [[0, 11, 12]]), ('block', {}, [[1, 3, 5]]), ('block', {}, [[1, 4, 6]]), ('block', {}, [[1, 7, 9]]), ('block', {}, [[1, 8, 11]]), ('block', {}, [[1, 10, 12]]), ('block', {}, [[2, 3, 7]]), ('block', {}, [[2, 4, 8]]), ('block', {}, [[2, 5, 10]]), ('block', {}, [[2, 6, 12]]), ('block', {}, [[2, 9, 11]]), ('block', {}, [[3, 6, 9]]), ('block', {}, [[3, 8, 12]]), ('block', {}, [[3, 10, 11]]), ('block', {}, [[4, 5, 11]]), ('block', {}, [[4, 7, 10]]), ('block', {}, [[4, 9, 12]]), ('block', {}, [[5, 7, 12]]), ('block', {}, [[5, 8, 9]]), ('block', {}, [[6, 7, 11]]), ('block', {}, [[6, 8, 10]])]))763sage: xt.__len__()76426765"""766767return len(self.xt_children)768769class XTreeProcessor(object):770'''771An incremental event-driven parser for ext-rep documents.772The processing stages:773774- ``<list_of_designs ...>`` opening element.775call-back: ``list_of_designs_proc``776777- ``<list_definition>`` subtree.778call-back: ``list_definition_proc``779780- ``<info>`` subtree.781call-back: ``info_proc``782783- iterating over ``<designs>`` processing each ``<block_design>``784separately.785call-back: ``block_design_proc``786787- finishing with closing ``</designs>`` and ``</list_of_designs>``.788'''789def _init(self):790"""791Internal initialisation for the processor of XTrees.792793EXAMPLES::794795sage: from sage.combinat.designs import ext_rep796sage: proc = ext_rep.XTreeProcessor()797sage: proc._init()798sage: proc.current_node799('root0', {}, [])800"""801802self.current_node = ('root0', {}, [])803self.node_stack = [self.current_node]804self.in_item = False805806def __init__(self):807"""808Internal initialisation for the processor of XTrees.809810EXAMPLES::811812sage: from sage.combinat.designs.ext_rep import *813sage: proc = XTreeProcessor()814sage: proc.current_node815('root0', {}, [])816sage: proc.node_stack817[('root0', {}, [])]818sage: proc.in_item819False820"""821822self._init()823self.outf = sys.stdout824# call-back handlers825self.list_of_designs_start_proc = None826self.list_definition_proc = None827self.info_proc = None828self.designs_start_proc = None829self.block_design_proc = None830self.designs_end_proc = None831self.list_of_designs_end_proc = None832833self.save_designs = False834self.list_of_designs = []835836def _start_element(self, name, attrs):837"""838Process the start of an element with certain name and839attributes.840841EXAMPLES::842843sage: from sage.combinat.designs.ext_rep import *844sage: name = "block_design"845sage: attrs = {'b': '26', 'id': 't2-v13-b26-r6-k3-L1-0', 'v': '13'}846sage: proc = XTreeProcessor()847sage: proc._start_element(name, attrs)848sage: proc.current_node849('block_design', {'b': 26, 'id': 't2-v13-b26-r6-k3-L1-0', 'v': 13}, [])850"""851852if name == 'block_design' or name == 'info' or name == 'list_definition':853self.in_item = True854elif name == 'list_of_designs':855check_dtrs_protocols('source', attrs['dtrs_protocol'])856if self.list_of_designs_start_proc:857self.list_of_designs_start_proc(attrs)858#self.outf.write('<%s' % name)859#pp_attributes(self.outf, attrs, indent='', precision_stack=[])860#self.outf.write('>\n')861elif name == 'designs':862pass # self.outf.write(' <%s>\n' % name)863if self.in_item:864for k, v in attrs.iteritems():865attrs[k] = _encode_attribute(v)866new_node = (name, attrs, [])867self.node_stack.append(new_node)868self.current_node[2].append(new_node)869self.current_node = new_node870871def _end_element(self, name):872"""873Finish processing the element name.874875EXAMPLES::876877sage: from sage.combinat.designs.ext_rep import *878sage: name = "block_design"879sage: attrs = {'b': '26', 'id': 't2-v13-b26-r6-k3-L1-0', 'v': '13'}880sage: proc = XTreeProcessor()881sage: proc._start_element(name, attrs)882sage: proc._end_element(name)883sage: proc.current_node884('root0', {}, [])885"""886887if self.in_item:888children = self.current_node[2]889if len(children) > 0 and type(children[0]) == TupleType:890if children[0][0] == 'z' or children[0][0] == 'd' \891or children[0][0] == 'q':892if children[0][0] == 'z':893convert = int894elif children[0][0] == 'd':895convert = float896else:897raise NotImplementedError, 'rational numbers'898ps = []899for x in children:900ps.append(convert(''.join(x[2])))901del children[:]902if name == 'block' or name == 'permutation' \903or name == 'preimage' or name == 'ksubset' \904or name == 'cycle_type' or name == 'row':905# these enclose lists of numbers906children.append(ps)907else:908# the rest is a single number909children.append(ps[0])910self.node_stack.pop()911self.current_node = self.node_stack[-1]912if name == 'block_design':913if self.block_design_proc:914self.block_design_proc(self.current_node[2][0])915if self.save_designs:916init_bd = XTree(self.current_node[2][0])917self.list_of_designs.append((init_bd.v, [b for b in init_bd.blocks]))918#print_subxt(self.current_node[2][0], level=2, outf=self.outf)919self._init()920elif name == 'info':921if self.info_proc:922self.info_proc(self.current_node[2][0])923#print_subxt(self.current_node[2][0], level=1, outf=self.outf)924self._init()925else:926if name == 'designs':927if self.designs_end_proc:928self.designs_end_proc()929#self.outf.write(' ')930#self.outf.write('</%s>\n' % name)931932def _char_data(self, data):933"""934Internal function to tidy up character data.935936EXAMPLES::937938sage: from sage.combinat.designs.ext_rep import *939sage: name = "block_design"940sage: attrs = {'b': '26', 'id': 't2-v13-b26-r6-k3-L1-0', 'v': '13'}941942sage: proc = XTreeProcessor()943sage: proc._start_element(name, attrs)944945sage: proc._char_data(r" [ DESIGN-1.1, GRAPE-4.2, GAPDoc-0.9999, GAP-4.4.3]")946sage: proc.current_node947('block_design',948{'b': 26, 'id': 't2-v13-b26-r6-k3-L1-0', 'v': 13},949['[ DESIGN-1.1, GRAPE-4.2, GAPDoc-0.9999, GAP-4.4.3]'])950"""951952if self.in_item:953#@ this stripping may distort char data in the <info> subtree954# if they are not bracketed in some way.955data = data.strip()956if data != '':957# we use the xtree's childrens list here to collect char data958# since only leaves have char data.959self.current_node[2].append(data)960961def parse(self, xml_source):962"""963The main parsing function. Given an XML source (either a file964handle or a string), parse the entire XML source.965966EXAMPLES::967968sage: from sage.combinat.designs import ext_rep969sage: file_loc = ext_rep.dump_to_tmpfile(ext_rep.v2_b2_k2_icgsa)970sage: proc = ext_rep.XTreeProcessor()971sage: proc.save_designs = True972sage: f = ext_rep.open_extrep_file(file_loc)973sage: proc.parse(f)974sage: f.close()975sage: os.remove(file_loc)976sage: proc.list_of_designs[0]977(2, [[0, 1], [0, 1]])978"""979980p = xml.parsers.expat.ParserCreate()981p.StartElementHandler = self._start_element982p.EndElementHandler = self._end_element983p.CharacterDataHandler = self._char_data984p.returns_unicode = 0985986if isinstance(xml_source, StringType):987p.Parse(xml_source)988else:989p.ParseFile(xml_source)990991def designs_from_XML(fname):992"""993Returns a list of designs contained in an XML file fname. The list994contains tuples of the form (v, bs) where v is the number of points of995the design and bs is the list of blocks.996997EXAMPLES::998999sage: from sage.combinat.designs import ext_rep1000sage: file_loc = ext_rep.dump_to_tmpfile(ext_rep.v2_b2_k2_icgsa)1001sage: ext_rep.designs_from_XML(file_loc)[0]1002(2, [[0, 1], [0, 1]])1003sage: os.remove(file_loc)10041005sage: from sage.combinat.designs import ext_rep1006sage: from sage.combinat.designs.block_design import BlockDesign1007sage: file_loc = ext_rep.dump_to_tmpfile(ext_rep.v2_b2_k2_icgsa)1008sage: v, blocks = ext_rep.designs_from_XML(file_loc)[0]1009sage: d = BlockDesign(v, blocks)1010sage: d.blocks()1011[[0, 1], [0, 1]]1012sage: d.parameters(t=2)1013(2, 2, 2, 2)1014"""10151016proc = XTreeProcessor()1017proc.save_designs = True1018f = open_extrep_file(fname)1019proc.parse(f)1020f.close()10211022return proc.list_of_designs10231024def designs_from_XML_url(url):1025"""1026Returns a list of designs contained in an XML file named by a URL.1027The list contains tuples of the form (v, bs) where v is the number1028of points of the design and bs is the list of blocks.10291030EXAMPLES::10311032sage: from sage.combinat.designs import ext_rep1033sage: file_loc = ext_rep.dump_to_tmpfile(ext_rep.v2_b2_k2_icgsa)1034sage: ext_rep.designs_from_XML_url("file://" + file_loc)[0]1035(2, [[0, 1], [0, 1]])1036sage: os.remove(file_loc)10371038sage: from sage.combinat.designs import ext_rep1039sage: ext_rep.designs_from_XML_url("http://designtheory.org/database/v-b-k/v3-b6-k2.icgsa.txt.bz2") # optional - internet1040[(3, [[0, 1], [0, 1], [0, 1], [0, 1], [0, 1], [0, 2]]),1041(3, [[0, 1], [0, 1], [0, 1], [0, 1], [0, 2], [0, 2]]),1042(3, [[0, 1], [0, 1], [0, 1], [0, 1], [0, 2], [1, 2]]),1043(3, [[0, 1], [0, 1], [0, 1], [0, 2], [0, 2], [0, 2]]),1044(3, [[0, 1], [0, 1], [0, 1], [0, 2], [0, 2], [1, 2]]),1045(3, [[0, 1], [0, 1], [0, 2], [0, 2], [1, 2], [1, 2]])]1046"""1047proc = XTreeProcessor()1048proc.save_designs = True1049s = open_extrep_url(url)1050proc.parse(s)10511052return proc.list_of_designs1053105410551056