Graph-ReadWrite-2.08/000755 000765 000024 00000000000 12614772247 014640 5ustar00neilbstaff000000 000000 Graph-ReadWrite-2.08/Changes000644 000765 000024 00000010161 12614772247 016132 0ustar00neilbstaff000000 000000 Revision history for perl distribution Graph-ReadWrite 2.08 2015-10-30 NEILB - Switched to Dist::Zilla - Updated the github repo URL after changing my github username - Removed a spurious =back from Graph::ReadWrite. Thanks to Lucas Kanashiro for RT#106063 2.07 2015-02-21 NEILB - Made mentions in SEE ALSO be links. MANWAR++ for starting this. - Added Graph::ReadWrite module, so there's a module that matches the dist name. - The NAME field in Makefile.PL was set to dist name (Graph-ReadWrite) instead of module name (Graph::ReadWrite). 2.06 2014-01-24 - Graph::Write::daVinci had a different version number from all the other modules. 2.05 2014-01-22 - the daVinci writer would sometimes fail due to the random hash order change in Perl 5.18 - Specified min perl version as 5.6.0 - Added ExtUtils::MakeMaker to CONFIGURE_REQUIRES - Changed Makefile.PL to metaspec 2 2.04 2013-07-27 - Added license type to Metadata - Ensured all releases in this file have a date, as per CPAN::Changes::Spec 2.03 2012-02-14 - added ABSTRACT, AUTHOR and github repository info to Makefile.PL - added parent, Carp, and File::Compare as pre-reqs 2.02 2012-02-12 - Pulled out the Parse::Yapp::Driver code that was embedded in the Dot reader. PAUSE didn't like me uploading code for a module I don't have permission for. Now added as a pre-req. 2.01 2012-02-12 - Fixed RT bug #39792: trying to call method set_graph_attribute() on Graph::Reader::XML, which should have been set_attribute(). - changed calls to File::Compare::compare() to hopefully cope with EOL differences between Windows and Unix. Reported by Philip Potter, and fix noted by Max - Ensured all modules were use'ing strict and warnings. Fixed warnings :-) - Cleaned up formatting of all modules - renamed ChangeLog to Changes and reformatted as per CPAN::Changes::Spec 2.00 2005-01-02 - made the changes needed to work with version 0.5 of Graph classes - patch to Graph::Reader::Dot from Mark Hillebrand. - fixed warnings "Using a hash as a reference is deprecated" - added support for new Dot attributes to Graph::Reader::Dot - node ids are now quoted in Graph::Writer::Dot, which means you can safely have space, ':', '-', and other interesting characters in node ids. 1.07 2002-07-09 - Added XML::Parser and XML::Writer as dependencies in Makefile.PL. This was prompted by looking at testers.cpan.org, which has this distribution as failing. 1.06 2002-03-20 - Graph::Writer::VCG - common attributes (label, color, and text color) weren't supported on edges. Bug and fix reported by Alexandre Cherif. 1.05 2002-01-20 - Added a basic test-suite. - Commented out debugging output in the HTK Writer. Sorry Phil! 1.04 2001-11-11 - Added Graph::Reader::Dot, a reader for the Dot format contributed by Mark Hillebrand. - Fixed a bug in Graph::Reader::XML, found by Mark Hillebrand. The reader would only cope with a single element inside each graph, node or edge element. - Changed contact email address to neil at bowers dot com 1.03 2001-04-25 - Added reader and writer classes for HTK lattice files. 1.02 2001-03-18 - Fixed a bug in the XML writer module - the way it was using XML::Writer caused STDOUT to be closed after you've written a graph. I consider it a bug in XML::Writer, but I was able to change the way Graph::Writer::XML uses that module. Basically it just means that we construct a new instance of XML::Writer every time we write out a graph. For most uses, this won't be a problem, but you'd notice a hit if you were creating the writer and then writing a lot of graphs. This was noticed by Mike Hayward 1.01 2001-03-12 - Added support for URL attribute on nodes in Dot. - Added support for almost all attributes understood by VCG. - Added a rough cut at a Writer class for daVinci: Graph::Writer::daVinci 1.00 2001-02 - Initial release - has baseclass for Reader and Writer classes. - Reader and Writer for simple XML format. - Writers for Dot and VCG formats. Graph-ReadWrite-2.08/dist.ini000644 000765 000024 00000000437 12614772247 016310 0ustar00neilbstaff000000 000000 name = Graph-ReadWrite author = Neil Bowers license = Perl_5 copyright_holder = Neil Bowers copyright_year = 2001 version = 2.08 [@Filter] -bundle = @Basic -remove = Readme [PkgVersion] [AutoPrereqs] [MetaJSON] [GithubMeta] [Git::Tag] tag_message= [Git::Push] Graph-ReadWrite-2.08/lib/000755 000765 000024 00000000000 12614772247 015406 5ustar00neilbstaff000000 000000 Graph-ReadWrite-2.08/LICENSE000644 000765 000024 00000043652 12614772247 015657 0ustar00neilbstaff000000 000000 This software is copyright (c) 2001 by Neil Bowers. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- This software is Copyright (c) 2001 by Neil Bowers. This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! --- The Artistic License 1.0 --- This software is Copyright (c) 2001 by Neil Bowers. This is free software, licensed under: The Artistic License 1.0 The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: - "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. - "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. - "Copyright Holder" is whoever is named in the copyright or copyrights for the package. - "You" is you, if you're thinking about copying or distributing this Package. - "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) - "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End Graph-ReadWrite-2.08/Makefile.PL000644 000765 000024 00000002743 12614772247 016620 0ustar00neilbstaff000000 000000 # This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v5.037. use strict; use warnings; use 5.006; use ExtUtils::MakeMaker; my %WriteMakefileArgs = ( "ABSTRACT" => "modules for reading and writing directed graphs", "AUTHOR" => "Neil Bowers ", "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => 0 }, "DISTNAME" => "Graph-ReadWrite", "EXE_FILES" => [], "LICENSE" => "perl", "MIN_PERL_VERSION" => "5.006", "NAME" => "Graph::ReadWrite", "PREREQ_PM" => { "Carp" => 0, "Graph" => 0, "IO::File" => 0, "Parse::Yapp::Driver" => 0, "XML::Parser" => 0, "XML::Writer" => 0, "constant" => 0, "parent" => 0, "strict" => 0, "vars" => 0, "warnings" => 0 }, "TEST_REQUIRES" => { "File::Compare" => 0 }, "VERSION" => "2.08", "test" => { "TESTS" => "t/*.t" } ); my %FallbackPrereqs = ( "Carp" => 0, "ExtUtils::MakeMaker" => 0, "File::Compare" => 0, "Graph" => 0, "IO::File" => 0, "Parse::Yapp::Driver" => 0, "XML::Parser" => 0, "XML::Writer" => 0, "constant" => 0, "parent" => 0, "strict" => 0, "vars" => 0, "warnings" => 0 ); unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); Graph-ReadWrite-2.08/MANIFEST000644 000765 000024 00000001036 12614772247 015771 0ustar00neilbstaff000000 000000 # This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.037. Changes LICENSE MANIFEST META.json META.yml Makefile.PL README TODO dist.ini lib/Graph/ReadWrite.pm lib/Graph/Reader.pm lib/Graph/Reader/Dot.pm lib/Graph/Reader/HTK.pm lib/Graph/Reader/XML.pm lib/Graph/Writer.pm lib/Graph/Writer/Dot.pm lib/Graph/Writer/HTK.pm lib/Graph/Writer/VCG.pm lib/Graph/Writer/XML.pm lib/Graph/Writer/daVinci.pm t/base.t t/data/simple.davinci t/data/simple.dot t/data/simple.htk t/data/simple.vcg t/data/simple.xml t/reader.t t/simple.t Graph-ReadWrite-2.08/META.json000644 000765 000024 00000002563 12614772247 016267 0ustar00neilbstaff000000 000000 { "abstract" : "modules for reading and writing directed graphs", "author" : [ "Neil Bowers " ], "dynamic_config" : 0, "generated_by" : "Dist::Zilla version 5.037, CPAN::Meta::Converter version 2.150005", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Graph-ReadWrite", "prereqs" : { "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Carp" : "0", "Graph" : "0", "IO::File" : "0", "Parse::Yapp::Driver" : "0", "XML::Parser" : "0", "XML::Writer" : "0", "constant" : "0", "parent" : "0", "perl" : "5.006", "strict" : "0", "vars" : "0", "warnings" : "0" } }, "test" : { "requires" : { "File::Compare" : "0" } } }, "release_status" : "stable", "resources" : { "homepage" : "https://github.com/neilb/Graph-ReadWrite", "repository" : { "type" : "git", "url" : "https://github.com/neilb/Graph-ReadWrite.git", "web" : "https://github.com/neilb/Graph-ReadWrite" } }, "version" : "2.08" } Graph-ReadWrite-2.08/META.yml000644 000765 000024 00000001371 12614772247 016113 0ustar00neilbstaff000000 000000 --- abstract: 'modules for reading and writing directed graphs' author: - 'Neil Bowers ' build_requires: File::Compare: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 0 generated_by: 'Dist::Zilla version 5.037, CPAN::Meta::Converter version 2.150005' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Graph-ReadWrite requires: Carp: '0' Graph: '0' IO::File: '0' Parse::Yapp::Driver: '0' XML::Parser: '0' XML::Writer: '0' constant: '0' parent: '0' perl: '5.006' strict: '0' vars: '0' warnings: '0' resources: homepage: https://github.com/neilb/Graph-ReadWrite repository: https://github.com/neilb/Graph-ReadWrite.git version: '2.08' Graph-ReadWrite-2.08/README000644 000765 000024 00000003473 12614772247 015527 0ustar00neilbstaff000000 000000 Graph-ReadWrite This is a collection of perl classes for reading and writing directed graphs in a variety of file formats. The graphs are represented in Perl using Jarkko Hietaniemi's Graph classes. Version 2+ of this distribution works with version 0.5 and later of the Graph distribution. There are two base classes: Graph::Reader Base class for classes which read a graph file and create an instance of the Graph class. Graph::Writer Base class for classes which take an instance of the Graph class and write it out in a specific file format. This distribution also defines a simple XML format for storing directed graphs, defined to meet the needs of the Graph class. A reader and writer are provided for this: Graph::Reader::XML Graph::Writer::XML Writers are also included for Dot, VCG, and daVinci, two packages for displaying / rendering graphs. Dot and VCG are freely available; daVinci is freely available at the moment, but that is going to change soon. Graph::Writer::Dot Graph::Writer::VCG Graph::Writer::daVinci A reader for Dot files has been contributed by Mark Hillebrand: Graph::Reader::Dot A reader and writer for HTK lattices are also included: Graph::Reader::HTK Graph::Writer::HTK These last two will probably only be of interest to people working with HTK, or tools which use the same format. Dependencies: Graph Jarkko's Graph classes XML::Parser used by Graph::Reader::XML XML::Writer used by Graph::Writer::XML IO::File To install these modules, you should just have to run the following: % perl Makefile.PL % make % make test % make install This distribution contains an early version of a test-suite; you may get a warning about an undefined value from one of the tests. Bugs, suggestions, and new readers and writers will be gratefully received. Neil Bowers Graph-ReadWrite-2.08/t/000755 000765 000024 00000000000 12614772247 015103 5ustar00neilbstaff000000 000000 Graph-ReadWrite-2.08/TODO000644 000765 000024 00000001124 12614772247 015326 0ustar00neilbstaff000000 000000 TODO for Graph-ReadWrite * add test cases for reading and writing attributes * consider doing readers and writers for other graph formats: - GraphML graphml.graphdrawing.org - GXL http://www.gupro.de/GXL/ - GML http://www.infosun.fmi.uni-passau.de/Graphlet/GML/ - XGMML http://www.cs.rpi.edu/~puninj/XGMML/ - GDL http://www.aisee.com/gdl/nutshell/ (this is possibly exactly the same as the VCG format, as aiSee is the commercial version of VCG)) * readers for formats we currently only have writers for: - daVinci - VCG $Id: TODO,v 1.2 2005/01/02 19:05:29 neilb Exp $ Graph-ReadWrite-2.08/t/base.t000644 000765 000024 00000001066 12614772247 016205 0ustar00neilbstaff000000 000000 #!./perl # # base.t - simple tests for the base classes # use Graph::Writer; use Graph::Reader; print "1..2\n"; # # You can't create instances of the base classes directly # #----------------------------------------------------------------------- eval { $r = Graph::Reader->new(); }; if ($@ && not defined $r) { print "ok 1\n"; } else { print "not ok 1\n"; } #----------------------------------------------------------------------- eval { $r = Graph::Writer->new(); }; if ($@ && not defined $r) { print "ok 2\n"; } else { print "not ok 2\n"; } Graph-ReadWrite-2.08/t/data/000755 000765 000024 00000000000 12614772247 016014 5ustar00neilbstaff000000 000000 Graph-ReadWrite-2.08/t/reader.t000644 000765 000024 00000003703 12614772247 016535 0ustar00neilbstaff000000 000000 # # reader.t - test reading in simple graph # use Graph; use File::Compare; use Graph::Reader::XML; use Graph::Reader::HTK; use Graph::Writer::HTK; use Graph::Reader::Dot; my ($graph, $reader, $writer); my ($testfile); my $FILE; print "1..3\n"; $graph = Graph->new(); $graph->add_edge('a' => 'b'); $graph->add_edge('b' => 'c'); $graph->add_edge('c' => 'd'); $graph->add_edge('b' => 'd'); $graph->add_edge('a' => 'c'); $graph->add_edge('c' => 'e'); $graph->add_edge('e' => 'e'); my $ingraph; #----------------------------------------------------------------------- # XML #----------------------------------------------------------------------- $testfile = 't/data/simple.xml'; $reader = Graph::Reader::XML->new(); if (defined($reader) && ($ingraph = $reader->read_graph($testfile)) && $graph->eq($ingraph)) { print "ok 1\n"; } else { print "not ok 1\n"; } #----------------------------------------------------------------------- # HTK # given the nature of the format, the nodes end up with idenfifiers # of numbers, even though we start off with letters. # So we do a read, write, and then compare the two files. #----------------------------------------------------------------------- $testfile = 't/data/simple.htk'; $genfile = 'foobar.htk'; $reader = Graph::Reader::HTK->new(); $writer = Graph::Writer::HTK->new(); if (defined($reader) && defined($writer) && ($ingraph = $reader->read_graph($testfile)) && $writer->write_graph($ingraph, $genfile) && compare($genfile, $testfile, -1) == 0) { print "ok 2\n"; } else { print "not ok 2\n"; } unlink($genfile); #----------------------------------------------------------------------- # Dot #----------------------------------------------------------------------- $testfile = 't/data/simple.dot'; $reader = Graph::Reader::Dot->new(); if (defined($reader) && ($ingraph = $reader->read_graph($testfile)) && $graph->eq($ingraph)) { print "ok 3\n"; } else { print "not ok 3\n"; } Graph-ReadWrite-2.08/t/simple.t000644 000765 000024 00000005220 12614772247 016560 0ustar00neilbstaff000000 000000 # # simple.t - simple tests for writing graphs # use Graph; use Graph::Writer::XML; use Graph::Writer::HTK; use Graph::Writer::Dot; use Graph::Writer::VCG; use Graph::Writer::daVinci; use File::Compare; my ($graph, $writer); my ($genfile, $expected); my $FILE; print "1..5\n"; $graph = Graph->new(); $graph->add_edge('a' => 'b'); $graph->add_edge('b' => 'c'); $graph->add_edge('c' => 'd'); $graph->add_edge('b' => 'd'); $graph->add_edge('a' => 'c'); $graph->add_edge('c' => 'e'); $graph->add_edge('e' => 'e'); #----------------------------------------------------------------------- # XML #----------------------------------------------------------------------- $genfile = 'test.xml'; $expected = 't/data/simple.xml'; $writer = Graph::Writer::XML->new(); if (defined($writer) && $writer->write_graph($graph, $genfile) && compare($genfile, $expected, -1) == 0) { print "ok 1\n"; } else { print "not ok 1\n"; } unlink $genfile; #----------------------------------------------------------------------- # HTK #----------------------------------------------------------------------- $genfile = 'test.htk'; $expected = 't/data/simple.htk'; $writer = Graph::Writer::HTK->new(); if (defined($writer) && $writer->write_graph($graph, $genfile) && compare($genfile, $expected, -1) == 0) { print "ok 2\n"; } else { print "not ok 2\n"; } unlink $genfile; #----------------------------------------------------------------------- # Dot #----------------------------------------------------------------------- $genfile = 'test.dot'; $expected = 't/data/simple.dot'; $writer = Graph::Writer::Dot->new(); if (defined($writer) && $writer->write_graph($graph, $genfile) && compare($genfile, $expected, -1) == 0) { print "ok 3\n"; } else { print "not ok 3\n"; } unlink $genfile; #----------------------------------------------------------------------- # VCG #----------------------------------------------------------------------- $genfile = 'test.vcg'; $expected = 't/data/simple.vcg'; $writer = Graph::Writer::VCG->new(); if (defined($writer) && $writer->write_graph($graph, $genfile) && compare($genfile, $expected, -1) == 0) { print "ok 4\n"; } else { print "not ok 4\n"; } unlink $genfile; #----------------------------------------------------------------------- # daVinci #----------------------------------------------------------------------- $genfile = 'test.davinci'; $expected = 't/data/simple.davinci'; $writer = Graph::Writer::daVinci->new(); if (defined($writer) && $writer->write_graph($graph, $genfile) && compare($genfile, $expected, -1) == 0) { print "ok 5\n"; } else { print "not ok 5\n"; } unlink $genfile; Graph-ReadWrite-2.08/t/data/simple.davinci000644 000765 000024 00000001107 12614772247 020643 0ustar00neilbstaff000000 000000 [ l("Node a", n("", [], [ l("Edge a->b", e("", [], l("Node b", n("", [], [ l("Edge b->c", e("", [], l("Node c", n("", [], [ l("Edge c->d", e("", [], l("Node d", n("", [], [])))), l("Edge c->e", e("", [], l("Node e", n("", [], [ l("Edge e->e", e("", [], r("Node e"))) ])))) ])))), l("Edge b->d", e("", [], r("Node d"))) ])))), l("Edge a->c", e("", [], r("Node c"))) ])) ] Graph-ReadWrite-2.08/t/data/simple.dot000644 000765 000024 00000000301 12614772247 020007 0ustar00neilbstaff000000 000000 digraph g { /* list of nodes */ "a"; "b"; "c"; "d"; "e"; /* list of edges */ "a" -> "b"; "a" -> "c"; "b" -> "c"; "b" -> "d"; "c" -> "d"; "c" -> "e"; "e" -> "e"; } Graph-ReadWrite-2.08/t/data/simple.htk000644 000765 000024 00000000213 12614772247 020011 0ustar00neilbstaff000000 000000 VERSION=1.0 N=5 L=7 I=0 I=1 I=2 I=3 I=4 J=0 S=0 E=1 J=1 S=0 E=2 J=2 S=1 E=2 J=3 S=1 E=3 J=4 S=2 E=3 J=5 S=2 E=4 J=6 S=4 E=4 Graph-ReadWrite-2.08/t/data/simple.vcg000644 000765 000024 00000000677 12614772247 020020 0ustar00neilbstaff000000 000000 graph: { node: { title: "a" } node: { title: "b" } node: { title: "c" } node: { title: "d" } node: { title: "e" } edge: { sourcename: "a" targetname: "b" } edge: { sourcename: "a" targetname: "c" } edge: { sourcename: "b" targetname: "c" } edge: { sourcename: "b" targetname: "d" } edge: { sourcename: "c" targetname: "d" } edge: { sourcename: "c" targetname: "e" } edge: { sourcename: "e" targetname: "e" } } Graph-ReadWrite-2.08/t/data/simple.xml000644 000765 000024 00000000450 12614772247 020026 0ustar00neilbstaff000000 000000 Graph-ReadWrite-2.08/lib/Graph/000755 000765 000024 00000000000 12614772247 016447 5ustar00neilbstaff000000 000000 Graph-ReadWrite-2.08/lib/Graph/Reader/000755 000765 000024 00000000000 12614772247 017651 5ustar00neilbstaff000000 000000 Graph-ReadWrite-2.08/lib/Graph/Reader.pm000644 000765 000024 00000011676 12614772247 020222 0ustar00neilbstaff000000 000000 # # Graph::Reader - perl base class for Graph file format readers # package Graph::Reader; $Graph::Reader::VERSION = '2.08'; use 5.006; use strict; use warnings; use IO::File; use Graph; #======================================================================= # # new () - constructor # #======================================================================= sub new { my $class = shift; my %args = @_; die "don't create an instance of $class!\n" if $class eq __PACKAGE__; my $self = bless {}, $class; $self->_init(\%args); return $self; } #======================================================================= # # _init() - initialise instance # # This is for any instance-specific initialisation. The idea is that # a sub-class will define an _init() method if it needs one. # For future compatibility the class-specific method should invoke # this. # #======================================================================= sub _init { } #======================================================================= # # read_graph() - create a Graph and read the given file into it # # This is the public method that will be invoked to read a graph. # The file can be specified either as a filename, or a filehandle. # #======================================================================= sub read_graph { my $self = shift; my $filename = shift; my $graph = Graph->new(); my $FILE; if (ref $filename) { $self->_read_graph($graph, $filename); } else { $FILE = IO::File->new("< $filename"); if (not defined $FILE) { warn "couldn't read from $filename: $!\n"; return 0; } $self->_read_graph($graph, $FILE); $FILE->close(); } return $graph; } 1; __END__ =head1 NAME Graph::Reader - base class for Graph file format readers =head1 SYNOPSIS package Graph::Reader::MyFormat; use Graph::Reader; use vars qw(@ISA); @ISA = qw(Graph::Reader); sub _read_graph { my ($self, $graph, $FILE) = @_; # read $FILE and populate $graph } =head1 DESCRIPTION B is a base class for Graph file format readers. A particular subclass of Graph::Reader will handle a specific file format, and generate a Graph, represented using Jarkko Hietaniemi's Graph class. You should never create an instance of this class yourself, it is only meant for subclassing. If you try to create an instance of Graph::Reader, the constructor will throw an exception. =head1 METHODS =head2 new() Constructor - generate a new reader instance. This is a virtual method, or whatever the correct lingo is. You're not meant to call this on the base class, it is inherited by the subclasses. Ie if you do something like: $reader = Graph::Reader->new(); It will throw an exception. =head2 read_graph() Read a graph from the specified file: $graph = $reader->read_graph($file); The C<$file> argument can either be a filename, or a filehandle for a previously opened file. =head1 SUBCLASSING To create your own graph format reader, create a module which subclasses B. For example, suppose DGF is a directed graph format - create a B module, with the following structure: package Graph::Reader::DGF; use Graph::Reader; use vars qw(@ISA); @ISA = qw(Graph::Reader); sub _read_graph { my $self = shift; my $graph = shift; my $FILE = shift; while (<$FILE>) { } return 1; } 1; Note the leading underscore on the B<_read_graph()> method. The base class provides the public method, and invokes the private method which you're expected to provide, as above. If you want to perform additional initialisation at construction time, you can provide an B<_init()> method, which will be invoked by the base class's constructor. You should invoke the superclass's initialiser as well, as follows: sub _init { my $self = shift; $self->SUPER::_init(); # your initialisation here } Someone can then use your class as follows: use Graph::Reader::DGF; $reader = Graph::Reader::DGF->new(); $graph = $reader->read_graph('foo.dgf'); =head1 SEE ALSO =over 4 =item L Jarkko Hietaniemi's modules for representing directed graphs, available from CPAN under modules/by-module/Graph/ =item Algorithms in Perl This O'Reilly book has a chapter on directed graphs, which is based around Jarkko's modules. =item L A simple subclass of this class for reading a simple XML format for directed graphs. =item L A baseclass for Graph file format writers. =back =head1 REPOSITORY L =head1 AUTHOR Neil Bowers Eneil@bowers.comE =head1 COPYRIGHT Copyright (c) 2001-2012, Neil Bowers. All rights reserved. Copyright (c) 2001, Canon Research Centre Europe. All rights reserved. This script is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Graph-ReadWrite-2.08/lib/Graph/ReadWrite.pm000644 000765 000024 00000002640 12614772247 020675 0ustar00neilbstaff000000 000000 package Graph::ReadWrite; $Graph::ReadWrite::VERSION = '2.08'; use 5.006; use strict; use warnings; 1; =head1 NAME Graph::ReadWrite - modules for reading and writing directed graphs =head1 DESCRIPTION This module is a placeholder in the Graph-ReadWrite distribution, which is a collection of modules for reading and writing directed graphs. You don't use C, you use one of the reader or writer modules for a specific format: =over 4 =item * L - class for reading a Graph instance from Dot format. =item * L - read an HTK lattice in as an instance of Graph. =item * L - class for reading a Graph instance from XML =item * L - write out directed graph in Dot format =item * L - write a perl Graph out as an HTK lattice file =item * L - write out directed graph in VCG format =item * L - write out directed graph as XML =item * L - write out directed graph in daVinci format =back =head1 REPOSITORY L =head1 AUTHOR Neil Bowers Eneilb@cpan.orgE =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2001-2015 by Neil Bowers . This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Graph-ReadWrite-2.08/lib/Graph/Writer/000755 000765 000024 00000000000 12614772247 017723 5ustar00neilbstaff000000 000000 Graph-ReadWrite-2.08/lib/Graph/Writer.pm000644 000765 000024 00000012626 12614772247 020270 0ustar00neilbstaff000000 000000 # # Graph::Writer - perl base class for Graph file format writers # package Graph::Writer; $Graph::Writer::VERSION = '2.08'; use 5.006; use strict; use warnings; use IO::File; #======================================================================= # # new () - constructor # # Create an instance of a Graph writer. This will not be invoked # directly on this class, but will be inherited by writers for # specific formats. # #======================================================================= sub new { my $class = shift; die "don't create an instance of $class!\n" if $class eq __PACKAGE__; my $self = bless {}, $class; $self->_init(@_); return $self; } #======================================================================= # # _init() - initialise instance # # This is for any instance-specific initialisation. The idea is that # a sub-class will define an _init() method if it needs one. # For future compatibility the class-specific method should invoke # this. # #======================================================================= sub _init { } #======================================================================= # # write_graph() - write the specified graph to the specified file (handle) # # This is the public method that will be invoked to write a graph. # The file can be specified either as a filename, or a filehandle. # #======================================================================= sub write_graph { my $self = shift; my $graph = shift; my $filename = shift; if (ref $filename) { $self->_write_graph($graph, $filename); } else { my $FILE = IO::File->new("> $filename"); if (not defined $FILE) { warn "couldn't write to $filename: $!\n"; return 0; } $self->_write_graph($graph, $FILE); $FILE->close(); } return 1; } 1; __END__ =head1 NAME Graph::Writer - base class for Graph file format writers =head1 SYNOPSIS package Graph::Writer::MyFormat; use Graph::Writer; use vars qw(@ISA); @ISA = qw(Graph::Writer); sub _write_graph { my ($self, $graph, $FILE) = @_; # write $graph to $FILE } =head1 DESCRIPTION B is a base class for Graph file format writers. A particular subclass of Graph::Writer will handle a specific file format, and generate a Graph, represented using Jarkko Hietaniemi's Graph class. You should never create an instance of this class yourself, it is only meant for subclassing. If you try to create an instance of Graph::Writer, the constructor will throw an exception. =head1 METHODS =head2 new() Constructor - generate a new writer instance. This is a virtual method, or whatever the correct lingo is. You're not meant to call this on the base class, it is inherited by the subclasses. Ie if you do something like: $writer = Graph::Writer->new(); It will throw an exception. =head2 write_graph() Read a graph from the specified file: $graph = $writer->write_graph($file); The C<$file> argument can either be a filename, or a filehandle for a previously opened file. =head1 SUBCLASSING To create your own graph format writer, create a module which subclasses B. For example, suppose DGF is a directed graph format - create a B module, with the following structure: package Graph::Writer::DGF; use Graph::Writer; use vars qw(@ISA); @ISA = qw(Graph::Writer); sub _write_graph { my $self = shift; my $graph = shift; my $FILE = shift; while (<$FILE>) { } return 1; } 1; Note the leading underscore on the B<_write_graph()> method. The base class provides the public method, and invokes the private method which you're expected to provide, as above. If you want to perform additional initialisation at construction time, you can provide an B<_init()> method, which will be invoked by the base class's constructor. You should invoke the superclass's initialiser as well, as follows: sub _init { my $self = shift; $self->SUPER::_init(); # your initialisation here } Someone can then use your class as follows: use Graph::Writer::DGF; $writer = Graph::Writer::DGF->new(); $writer->write_graph($graph, 'foo.dgf'); =head1 SEE ALSO =over 4 =item L Jarkko Hietaniemi's modules for representing directed graphs, available from CPAN under modules/by-module/Graph/ =item Algorithms in Perl The O'Reilly book has a chapter on directed graphs, which is based around Jarkko's modules. =item L A simple subclass of this class for writing graphs in the file format used by dot, which is part of the graphviz package from AT&T. =item L A simple subclass of this class for writing graphs in the file format used by VCG, a tool for visualising directed graphs, initially developed for visualising compiler graphs. =item L A simple subclass of this class for writing graphs as XML, using a simple graph markup. =item L A baseclass for Graph file format readers. =back =head1 REPOSITORY L =head1 AUTHOR Neil Bowers Eneil@bowers.comE =head1 COPYRIGHT Copyright (c) 2001-2012, Neil Bowers. All rights reserved. Copyright (c) 2001, Canon Research Centre Europe. All rights reserved. This script is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Graph-ReadWrite-2.08/lib/Graph/Writer/daVinci.pm000644 000765 000024 00000014433 12614772247 021643 0ustar00neilbstaff000000 000000 # # Graph::Writer::daVinci - write a directed graph out in daVinci format # package Graph::Writer::daVinci; $Graph::Writer::daVinci::VERSION = '2.08'; use 5.006; use strict; use warnings; use parent 'Graph::Writer'; #----------------------------------------------------------------------- # List of valid daVinci attributes for the entire graph, per node, # and per edge. You can set other attributes, but they won't get # written out. #----------------------------------------------------------------------- my %valid_attributes = ( node => [qw(OBJECT FONTFAMILY FONTSTYLE COLOR CCOLOR _GO _CGO ICONFILE CICONFILE HIDDEN BORDER)], edge => [qw(EDGECOLOR EDGEPATTERN _DIR HEAD)], ); #======================================================================= # # _write_graph() # # The private method which actually does the writing out in # daVinci format. # # This is called from the public method, write_graph(), which is # found in Graph::Writer. # #======================================================================= sub _write_graph { my $self = shift; my $graph = shift; my $FILE = shift; my $v; my $from; my $to; my $gn; my $aref; my @keys; my (@nodes, @edges); my %done = (); my $node; @nodes = sort $graph->source_vertices; if (@nodes == 0) { die "expecting source vertices!\n"; } print $FILE "[\n"; while (@nodes > 0) { $node = shift @nodes; $self->_dump_node($graph, $FILE, $node, \%done, 1); print $FILE ",\n" if @nodes > 0; } print $FILE "\n]\n"; return 1; #------------------------------------------------------------------- # Generate a list of edges, along with any attributes #------------------------------------------------------------------- print $FILE "\n /* list of edges */\n"; @edges = sort _by_vertex $graph->edges; for (my $i = 0; $i < @edges; $i++) { ($from, $to) = @{ $edges[$i] }; print $FILE " $from -> $to"; $aref = $graph->get_graph_attributes($from, $to); @keys = grep(exists $aref->{$_}, @{$valid_attributes{'edge'}}); if (@keys > 0) { print $FILE " [", join(',', map { "$_ = \"".$aref->{$_}."\"" } @keys), "]"; } print $FILE ", " if $i < @edges - 1; } return 1; } sub _by_vertex { return $a->[0].$a->[1] cmp $b->[0].$b->[1]; } #======================================================================= # # _dump_node # # Write out a node, using a reference if we've already written it. # If there are any outgoing edges, we dump them out, recursively # calling ourself to dump the nodes at the other end of each edge. # #======================================================================= sub _dump_node { my ($self, $graph, $FILE, $node, $doneref, $depth) = @_; my $aref; my @keys; my @children; my $child; local $_; if (exists $doneref->{$node}) { print $FILE ' ' x (2 * $depth), "r(\"Node $node\")"; } else { print $FILE ' ' x (2 * $depth), "l(\"Node $node\", n(\"\""; $aref = $graph->get_vertex_attributes($node); @keys = grep(exists $aref->{$_}, @{$valid_attributes{'node'}}); if (@keys > 0) { print $FILE ", [", join(', ', map { "a(\"$_\", \"".$aref->{$_}."\")" } @keys), "]"; } else { print $FILE ", []"; } $doneref->{$node} = 1; @children = sort $graph->successors($node); if (@children == 0) { print $FILE ", []"; } else { print $FILE ",\n", ' ' x (2 * $depth + 1), "[\n"; while (@children > 0) { $child = shift @children; print $FILE ' ' x (2 * $depth + 2), "l(\"Edge ${node}->$child\", e(\"\", ["; # write out any attributes of the edge $aref = $graph->get_edge_attributes($node, $child); @keys = grep(exists $aref->{$_}, @{$valid_attributes{'edge'}}); if (@keys > 0) { print $FILE join(', ', map { "a(\"$_\", \"".$aref->{$_}."\")" } @keys); } print $FILE "],\n"; $self->_dump_node($graph, $FILE, $child, $doneref, $depth+2); print $FILE "))"; print $FILE ",\n" if @children > 0; } print $FILE ' ' x (2 * $depth + 1), "]"; } print $FILE "))"; } } 1; __END__ =head1 NAME Graph::Writer::daVinci - write out directed graph in daVinci format =head1 SYNOPSIS use Graph; use Graph::Writer::daVinci; $graph = Graph->new(); # add edges and nodes to the graph $writer = Graph::Writer::daVinci->new(); $writer->write_graph($graph, 'mygraph.davinci'); =head1 DESCRIPTION B is a class for writing out a directed graph in the file format used by the I tool. The graph must be an instance of the Graph class, which is actually a set of classes developed by Jarkko Hietaniemi. =head1 METHODS =head2 new() Constructor - generate a new writer instance. $writer = Graph::Writer::daVinci->new(); This doesn't take any arguments. =head2 write_graph() Write a specific graph to a named file: $writer->write_graph($graph, $file); The C<$file> argument can either be a filename, or a filehandle for a previously opened file. =head1 SEE ALSO =over 4 =item http://www.b-novative.de/ The home page for the daVinci. =item L Jarkko Hietaniemi's modules for representing directed graphs, available from CPAN under modules/by-module/Graph/ =item Algorithms in Perl The O'Reilly book which has a chapter on directed graphs, which is based around Jarkko's modules. =item L The base-class for Graph::Writer::daVinci =back =head1 REPOSITORY L =head1 AUTHOR Neil Bowers Eneil@bowers.comE =head1 COPYRIGHT Copyright (c) 2001-2012, Neil Bowers. All rights reserved. Copyright (c) 2001, Canon Research Centre Europe. All rights reserved. This script is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Graph-ReadWrite-2.08/lib/Graph/Writer/Dot.pm000644 000765 000024 00000015616 12614772247 021020 0ustar00neilbstaff000000 000000 # # Graph::Writer::Dot - write a directed graph out in Dot format # package Graph::Writer::Dot; $Graph::Writer::Dot::VERSION = '2.08'; use 5.006; use strict; use warnings; use parent 'Graph::Writer'; #----------------------------------------------------------------------- # List of valid dot attributes for the entire graph, per node, # and per edge. You can set other attributes, but they won't get # written out. #----------------------------------------------------------------------- my %valid_attributes = ( graph => [qw(bb bgcolor center clusterrank color comment compound concentrate Damping defaultlist dim dpi epsilon fontcolor fontname fontpath fontsize label labeljust labelloc layers layersep lp margin maxiter mclimit mindist mode model nodesep nojustify normalize nslimit nslimit1 ordering ordering orientation outputorder overlap pack packmode page pagedir quantum rank rankdir ranksep ratio remincross resolution root rotate samplepoints searchsize sep showboxes size splines start stylesheet target truecolor viewport voro_margin)], node => [qw(bottomlabel color comment distortion fillcolor fixedsize fontcolor fontname fontsize group height width label layer margin nojustify orientation peripheries pin pos rects regular root shape shapefile showboxes sides skew style target tooltip toplabel URL vertices width z)], edge => [qw(arrowhead arrowsize arrowtail color comment constraint decorate dir fontcolor fontname fontsize headURL headclip headhref headlabel headport headtarget headtooltip href id label labelangle labeldistance labelfloat labelfontcolor labelfontname labelfontsize layer len lhead lp ltail minlen nojustify pos samehead sametail showboxes style tailURL tailclip tailhref taillabel tailport tailtarget tailtooltip target tooltip weight)], ); #======================================================================= # # _init() # # class-specific initialisation. There isn't any here, but it's # kept as a place-holder. # #======================================================================= sub _init { my $self = shift; $self->SUPER::_init(); } #======================================================================= # # _write_graph() # # The private method which actually does the writing out in # dot format. # # This is called from the public method, write_graph(), which is # found in Graph::Writer. # #======================================================================= sub _write_graph { my $self = shift; my $graph = shift; my $FILE = shift; my $v; my $from; my $to; my $gn; my $attrref; my @keys; #------------------------------------------------------------------- # If the graph has a 'name' attribute, then we use that for the # name of the digraph instance. Else it's just 'g'. #------------------------------------------------------------------- $gn = $graph->has_graph_attribute('name') ? $graph->get_graph_attribute('name') : 'g'; print $FILE "digraph $gn\n{\n"; #------------------------------------------------------------------- # Dump out any overall attributes of the graph #------------------------------------------------------------------- $attrref = $graph->get_graph_attributes(); @keys = grep(exists $attrref->{$_}, @{$valid_attributes{'graph'}}); if (@keys > 0) { print $FILE " /* graph attributes */\n"; foreach my $a (@keys) { print $FILE " $a = \"", $attrref->{$a}, "\";\n"; } } #------------------------------------------------------------------- # Generate a list of nodes, with attributes for those that have any. #------------------------------------------------------------------- print $FILE "\n /* list of nodes */\n"; foreach $v (sort $graph->vertices) { print $FILE " \"$v\""; $attrref = $graph->get_vertex_attributes($v); @keys = grep(exists $attrref->{$_}, @{$valid_attributes{'node'}}); if (@keys > 0) { print $FILE " [", join(',', map { "$_=\"".$attrref->{$_}."\"" } @keys), "]"; } print $FILE ";\n"; } #------------------------------------------------------------------- # Generate a list of edges, along with any attributes #------------------------------------------------------------------- print $FILE "\n /* list of edges */\n"; foreach my $edge (sort _by_vertex $graph->edges) { ($from, $to) = @$edge; print $FILE " \"$from\" -> \"$to\""; $attrref = $graph->get_edge_attributes($from, $to); @keys = grep(exists $attrref->{$_}, @{$valid_attributes{'edge'}}); if (@keys > 0) { print $FILE " [", join(',', map { "$_ = \"".$attrref->{$_}."\"" } @keys), "]"; } print $FILE ";\n"; } #------------------------------------------------------------------- # close off the digraph instance #------------------------------------------------------------------- print $FILE "}\n"; return 1; } sub _by_vertex { return $a->[0].$a->[1] cmp $b->[0].$b->[1]; } 1; __END__ =head1 NAME Graph::Writer::Dot - write out directed graph in Dot format =head1 SYNOPSIS use Graph; use Graph::Writer::Dot; $graph = Graph->new(); # add edges and nodes to the graph $writer = Graph::Writer::Dot->new(); $writer->write_graph($graph, 'mygraph.dot'); =head1 DESCRIPTION B is a class for writing out a directed graph in the file format used by the I tool (part of the AT+T graphviz package). The graph must be an instance of the Graph class, which is actually a set of classes developed by Jarkko Hietaniemi. =head1 METHODS =head2 new() Constructor - generate a new writer instance. $writer = Graph::Writer::Dot->new(); This doesn't take any arguments. =head2 write_graph() Write a specific graph to a named file: $writer->write_graph($graph, $file); The C<$file> argument can either be a filename, or a filehandle for a previously opened file. =head1 SEE ALSO =over 4 =item L The home page for the AT+T graphviz toolkit that includes the dot tool. =item L Jarkko Hietaniemi's modules for representing directed graphs, available from CPAN under modules/by-module/Graph/ =item Algorithms in Perl The O'Reilly book which has a chapter on directed graphs, which is based around Jarkko's modules. =item L The base-class for Graph::Writer::Dot =back =head1 REPOSITORY L =head1 AUTHOR Neil Bowers Eneil@bowers.comE =head1 COPYRIGHT Copyright (c) 2001-2012, Neil Bowers. All rights reserved. Copyright (c) 2001, Canon Research Centre Europe. All rights reserved. This script is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Graph-ReadWrite-2.08/lib/Graph/Writer/HTK.pm000644 000765 000024 00000007526 12614772247 020721 0ustar00neilbstaff000000 000000 # # Graph::Writer::HTK - perl module for writing a Graph as an HTK lattice # package Graph::Writer::HTK; $Graph::Writer::HTK::VERSION = '2.08'; use 5.006; use strict; use warnings; #======================================================================= #======================================================================= use parent 'Graph::Writer'; my @graph_attributes = qw(base lmname lmscale wdpenalty); my %node_attributes = ( 'W' => [ 'WORD', 'label' ], 't' => [ 'time' ], 'v' => [ 'var' ], 'L' => [ 'L' ], ); my %edge_attributes = ( 'W' => [ 'WORD', 'label' ], 'v' => [ 'var' ], 'd' => [ 'div' ], 'a' => [ 'acoustic' ], 'n' => [ 'ngram' ], 'l' => [ 'language', 'weight' ], ); #======================================================================= # # _write_graph # # dump the graph out as an HTK lattice to the given filehandle. # #======================================================================= sub _write_graph { my $self = shift; my $graph = shift; my $FILE = shift; my $nvertices; my $nedges; my $v; my $from; my $to; my %v2n; my $node_num; my $edge_num; print $FILE "VERSION=1.0\n"; print $FILE "N=",int($graph->vertices)," L=",int($graph->edges),"\n"; $node_num = 0; foreach $v (sort $graph->vertices) { $v2n{$v} = $node_num; print $FILE "I=$node_num"; foreach my $field (keys %node_attributes) { foreach my $attr (@{ $node_attributes{$field} }) { if ($graph->has_vertex_attribute($v, $attr)) { print $FILE " $field=", $graph->get_vertex_attribute($v, $attr); last; } } } print $FILE "\n"; ++$node_num; } $edge_num = 0; foreach my $edge (sort _by_vertex $graph->edges) { ($from, $to) = @$edge; print $FILE "J=$edge_num S=", $v2n{$from}, " E=", $v2n{$to}; foreach my $field (keys %edge_attributes) { foreach my $attr (@{ $edge_attributes{$field} }) { if ($graph->has_edge_attribute($from, $to, $attr)) { print $FILE " $field=", $graph->get_vertex_attribute($from, $to, $attr); last; } } } print $FILE "\n"; ++$edge_num; } return 1; } sub _by_vertex { return $a->[0].$a->[1] cmp $b->[0].$b->[1]; } 1; __END__ =head1 NAME Graph::Writer::HTK - write a perl Graph out as an HTK lattice file =head1 SYNOPSIS use Graph::Writer::HTK; $writer = Graph::Reader::HTK->new(); $reader->write_graph($graph, 'mylattice.lat'); =head1 DESCRIPTION This module will write a directed graph to a file in the L lattice format. The graph must be an instance of the L class. =head1 SEE ALSO =over 4 =item L Jarkko Hietaniemi's Graph class and others, used for representing and manipulating directed graphs. Available from CPAN. Also described / used in the chapter on directed graph algorithms in the B book from O'Reilly. =item L The base-class for this module, which defines the public methods, and describes the ideas behind Graph reader and writer modules. =item L A class which will read a perl Graph from an HTK lattice file. =back =head1 REPOSITORY L =head1 AUTHOR Neil Bowers Eneil@bowers.comE =head1 COPYRIGHT Copyright (c) 2000-2012, Neil Bowers. All rights reserved. Copyright (c) 2000, Canon Research Centre Europe. All rights reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Graph-ReadWrite-2.08/lib/Graph/Writer/VCG.pm000644 000765 000024 00000025722 12614772247 020710 0ustar00neilbstaff000000 000000 # # Graph::Writer::VCG - write a directed graph out in VCG format # package Graph::Writer::VCG; $Graph::Writer::VCG::VERSION = '2.08'; use 5.006; use strict; use warnings; use parent 'Graph::Writer'; #----------------------------------------------------------------------- # Attribute type information #----------------------------------------------------------------------- use constant VCG_ATTR_TYPE_INTEGER => 1; use constant VCG_ATTR_TYPE_STRING => 2; use constant VCG_ATTR_TYPE_FLOAT => 3; my $enum_color = [qw(aquamarine black blue cyan darkblue darkcyan darkgreen darkgrey darkmagenta darkred darkyellow gold green khaki lightblue lightcyan lightgreen lightgrey lightmagenta lightred lightyellow lilac magenta orange orchid pink purple red turquoise white yellow yellowgreen)]; my $enum_yes_no = [qw(yes no)]; my $enum_textmode = [qw(center left_justify right_justify)]; my $enum_shape = [qw(box rhomb ellipse triangle)]; my $enum_arrowstyle = [qw(none line solid)]; my %common_attrs = ( label => VCG_ATTR_TYPE_STRING, color => $enum_color, textcolor => $enum_color, ); #----------------------------------------------------------------------- # List of valid dot attributes for the entire graph, per node, # and per edge. You can set other attributes, but they won't get # written out. #----------------------------------------------------------------------- my %valid_attributes = ( graph => { %common_attrs, title => VCG_ATTR_TYPE_STRING, info1 => VCG_ATTR_TYPE_STRING, info2 => VCG_ATTR_TYPE_STRING, info3 => VCG_ATTR_TYPE_STRING, bordercolor => $enum_color, width => VCG_ATTR_TYPE_INTEGER, height => VCG_ATTR_TYPE_INTEGER, borderwidth => VCG_ATTR_TYPE_INTEGER, x => VCG_ATTR_TYPE_INTEGER, y => VCG_ATTR_TYPE_INTEGER, # loc folding => VCG_ATTR_TYPE_INTEGER, scaling => VCG_ATTR_TYPE_FLOAT, shrink => VCG_ATTR_TYPE_INTEGER, stretch => VCG_ATTR_TYPE_INTEGER, textmode => $enum_textmode, shape => $enum_shape, level => VCG_ATTR_TYPE_INTEGER, vertical_order => VCG_ATTR_TYPE_INTEGER, horizontal_order => VCG_ATTR_TYPE_INTEGER, status => [qw(black grey white)], xmax => VCG_ATTR_TYPE_INTEGER, ymax => VCG_ATTR_TYPE_INTEGER, xbase => VCG_ATTR_TYPE_INTEGER, ybase => VCG_ATTR_TYPE_INTEGER, xspace => VCG_ATTR_TYPE_INTEGER, xlspace => VCG_ATTR_TYPE_INTEGER, yspace => VCG_ATTR_TYPE_INTEGER, xraster => VCG_ATTR_TYPE_INTEGER, xlraster => VCG_ATTR_TYPE_INTEGER, invisble => VCG_ATTR_TYPE_INTEGER, hidden => VCG_ATTR_TYPE_INTEGER, # classname # colorentry # infoname layoutalgorithm => [qw(tree maxdepth mindepth maxdepthslow mindepthslow maxdegree mindegree maxindegree minindegree maxoutdegree minoutdegree minbackward dfs)], layout_downfactor => VCG_ATTR_TYPE_INTEGER, layout_upfactor => VCG_ATTR_TYPE_INTEGER, layout_nearfactor => VCG_ATTR_TYPE_INTEGER, splinefactor => VCG_ATTR_TYPE_INTEGER, late_edge_labels => $enum_yes_no, display_edge_labels => $enum_yes_no, dirty_edge_labels => $enum_yes_no, finetuning => $enum_yes_no, ignoresingles => $enum_yes_no, straight_phase => $enum_yes_no, priority_phase => $enum_yes_no, manhattan_edges => $enum_yes_no, smanhattan_edges => $enum_yes_no, nearedges => $enum_yes_no, orientation => [qw(top_to_bottom bottom_to_top left_to_right right_to_left)], node_alignment => [qw(bottom top center)], port_sharing => $enum_yes_no, arrowmode => [qw(fixed free)], spreadlevel => VCG_ATTR_TYPE_INTEGER, treefactor => VCG_ATTR_TYPE_FLOAT, crossingphase2 => $enum_yes_no, crossingoptimization=> $enum_yes_no, crossingweight => [qw(bary median barymedian medianbary)], view => [qw(cfish fcfish pfish fpfish)], edges => $enum_yes_no, nodes => $enum_yes_no, splines => $enum_yes_no, bmax => VCG_ATTR_TYPE_INTEGER, cmax => VCG_ATTR_TYPE_INTEGER, cmin => VCG_ATTR_TYPE_INTEGER, pmax => VCG_ATTR_TYPE_INTEGER, pmin => VCG_ATTR_TYPE_INTEGER, rmax => VCG_ATTR_TYPE_INTEGER, rmin => VCG_ATTR_TYPE_INTEGER, smax => VCG_ATTR_TYPE_INTEGER, }, node => { %common_attrs, info1 => VCG_ATTR_TYPE_STRING, info2 => VCG_ATTR_TYPE_STRING, info3 => VCG_ATTR_TYPE_STRING, bordercolor => $enum_color, width => VCG_ATTR_TYPE_INTEGER, height => VCG_ATTR_TYPE_INTEGER, borderwidth => VCG_ATTR_TYPE_INTEGER, # loc folding => VCG_ATTR_TYPE_INTEGER, scaling => VCG_ATTR_TYPE_FLOAT, shrink => VCG_ATTR_TYPE_INTEGER, stretch => VCG_ATTR_TYPE_INTEGER, textmode => $enum_textmode, shape => $enum_shape, level => VCG_ATTR_TYPE_INTEGER, vertical_order => VCG_ATTR_TYPE_INTEGER, horizontal_order => VCG_ATTR_TYPE_INTEGER, }, edge => { %common_attrs, thickness => VCG_ATTR_TYPE_INTEGER, class => VCG_ATTR_TYPE_INTEGER, priority => VCG_ATTR_TYPE_INTEGER, arrowcolor => $enum_color, backarrowcolor => $enum_color, arrowsize => VCG_ATTR_TYPE_INTEGER, backarrowsize => VCG_ATTR_TYPE_INTEGER, arrowstyle => $enum_arrowstyle, backarrowstyle => $enum_arrowstyle, linestyle => [qw(continuous solid dotted dashed invisible)], anchor => VCG_ATTR_TYPE_INTEGER, horizontal_order => VCG_ATTR_TYPE_INTEGER, }, ); #======================================================================= # # _write_graph() # # The private method which actually does the writing out in # VCG format. # # This is called from the public method, write_graph(), which is # found in Graph::Writer. # #======================================================================= sub _write_graph { my $self = shift; my $graph = shift; my $FILE = shift; my $v; my $from; my $to; my $aref; my @keys; #------------------------------------------------------------------- #------------------------------------------------------------------- print $FILE "graph: {\n"; #------------------------------------------------------------------- # Dump out any overall attributes of the graph #------------------------------------------------------------------- $aref = $graph->get_graph_attributes(); _render_attributes('graph', $aref, $FILE); #------------------------------------------------------------------- # Dump out a list of the nodes, along with any defined attributes #------------------------------------------------------------------- foreach $v (sort $graph->vertices) { print $FILE " node: { title: \"$v\""; $aref = $graph->get_vertex_attributes($v); _render_attributes('node', $aref, $FILE, 1); print $FILE " }\n"; } print $FILE "\n"; #------------------------------------------------------------------- # Dump out a list of the edges, along with any defined attributes #------------------------------------------------------------------- foreach my $edge (sort _by_vertex $graph->edges) { ($from, $to) = @$edge; print $FILE " edge: { sourcename: \"$from\" targetname: \"$to\""; $aref = $graph->get_edge_attributes($from, $to); _render_attributes('edge', $aref, $FILE, 1); print $FILE " }\n"; } print $FILE "}\n"; return 1; } sub _by_vertex { return $a->[0].$a->[1] cmp $b->[0].$b->[1]; } #======================================================================= # # _render_attributes # # Take a hash of attribute names and values and format # as VCG attribute specs, quoting the value if needed. # We filter the hash against legal attributes, since VCG will # barf on unknown attribute names. # # Returns the number of attributes written out. # #======================================================================= sub _render_attributes { my $entity = shift; # 'graph' or 'node' or 'edge' my $attref = shift; my $FILE = shift; my $depth = @_ > 0 ? shift : 0; my @keys; my $type; @keys = grep(exists $attref->{$_}, keys %{$valid_attributes{$entity}}); if (@keys > 0) { print $FILE "\n"; foreach my $a (@keys) { $type = $valid_attributes{$entity}->{$a}; if (ref $type || $type == VCG_ATTR_TYPE_INTEGER || $type == VCG_ATTR_TYPE_FLOAT) { print $FILE " ", ' ' x $depth, "$a: ", $attref->{$a}, "\n"; } else { print $FILE " ", ' ' x $depth, "$a: \"", $attref->{$a}, "\"\n"; } } } return int @keys; } 1; __END__ =head1 NAME Graph::Writer::VCG - write out directed graph in VCG format =head1 SYNOPSIS use Graph; use Graph::Writer::VCG; $graph = Graph->new(); # add edges and nodes to the graph $writer = Graph::Writer::VCG->new(); $writer->write_graph($graph, 'mygraph.vcg'); =head1 DESCRIPTION B is a class for writing out a directed graph in the file format used by the I tool, originally developed for Visualising Compiler Graphs. The graph must be an instance of the Graph class, which is actually a set of classes developed by Jarkko Hietaniemi. If you have defined any attributes for the graph, nodes, or edges, they will be written out to the file, as long as they are attributes understood by VCG. =head1 METHODS =head2 new() Constructor - generate a new writer instance. $writer = Graph::Writer::VCG->new(); This doesn't take any arguments. =head2 write_graph() Write a specific graph to a named file: $writer->write_graph($graph, $file); The C<$file> argument can either be a filename, or a filehandle for a previously opened file. =head1 KNOWN BUGS AND LIMITATIONS =over 4 =item * Attributes with non-atomic values aren't currently handled. This includes the B, B, B, and B attributes for graphs, and the B attribute for nodes, =item * Can currently only handle B, B, and B elements and their attributes. So doesn't know about B and things like that. =back =head1 SEE ALSO =over 4 =item http://www.cs.uni-sb.de/RW/users/sander/html/gsvcg1.html The home page for VCG. =item L Jarkko Hietaniemi's modules for representing directed graphs, available from CPAN under modules/by-module/Graph/ =item Algorithms in Perl The O'Reilly book which has a chapter on directed graphs, which is based around Jarkko's modules. =item L The base-class for Graph::Writer::VCG =back =head1 REPOSITORY L =head1 AUTHOR Neil Bowers Eneil@bowers.comE =head1 COPYRIGHT Copyright (c) 2001-2012, Neil Bowers. All rights reserved. Copyright (c) 2001, Canon Research Centre Europe. All rights reserved. This script is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Graph-ReadWrite-2.08/lib/Graph/Writer/XML.pm000644 000765 000024 00000012013 12614772247 020716 0ustar00neilbstaff000000 000000 # # Graph::Writer::XML - write a directed graph out as XML # package Graph::Writer::XML; $Graph::Writer::XML::VERSION = '2.08'; use 5.006; use strict; use warnings; use parent 'Graph::Writer'; use XML::Writer; #======================================================================= # # _write_graph() - perform the writing of the graph # # This is invoked from the public write_graph() method, # and is where the actual writing of the graph happens. # # Basically we start a graph element then: # [] dump out any attributes of the graph # [] dump out all vertices, with any attributes of each vertex # [] dump out all edges, with any attributes of each edge # And then close the graph element. Ta da! # #======================================================================= sub _write_graph { my $self = shift; my $graph = shift; my $FILE = shift; my $v; my $from; my $to; my $aref; my $xmlwriter; $xmlwriter = XML::Writer->new(OUTPUT => $FILE, DATA_MODE => 1, DATA_INDENT => 2); $xmlwriter->setOutput($FILE); $xmlwriter->startTag('graph'); #------------------------------------------------------------------- # dump out attributes of the graph, if it has any #------------------------------------------------------------------- $aref = $graph->get_graph_attributes(); foreach my $attr (keys %{ $aref }) { $xmlwriter->emptyTag('attribute', 'name' => $attr, 'value' => $aref->{$attr}); } #------------------------------------------------------------------- # dump out vertices of the graph, including any attributes #------------------------------------------------------------------- foreach $v (sort $graph->vertices) { $aref = $graph->get_vertex_attributes($v); if (keys(%{ $aref }) > 0) { $xmlwriter->startTag('node', 'id' => $v); foreach my $attr (keys %{ $aref }) { $xmlwriter->emptyTag('attribute', 'name' => $attr, 'value' => $aref->{$attr}); } $xmlwriter->endTag('node'); } else { $xmlwriter->emptyTag('node', 'id' => $v); } } #------------------------------------------------------------------- # dump out edges of the graph, including any attributes #------------------------------------------------------------------- foreach my $edge (sort _by_vertex $graph->edges) { ($from, $to) = @$edge; $aref = $graph->get_edge_attributes($from, $to); if (keys(%{ $aref }) > 0) { $xmlwriter->startTag('edge', 'from' => $from, 'to' => $to); foreach my $attr (keys %{ $aref }) { $xmlwriter->emptyTag('attribute', 'name' => $attr, 'value' => $aref->{$attr}); } $xmlwriter->endTag('edge'); } else { $xmlwriter->emptyTag('edge', 'from' => $from, 'to' => $to); } } $xmlwriter->endTag('graph'); $xmlwriter->end(); return 1; } sub _by_vertex { return $a->[0].$a->[1] cmp $b->[0].$b->[1]; } 1; __END__ =head1 NAME Graph::Writer::XML - write out directed graph as XML =head1 SYNOPSIS use Graph; use Graph::Writer::XML; $graph = Graph->new(); # add edges and nodes to the graph $writer = Graph::Writer::XML->new(); $writer->write_graph($graph, 'mygraph.xml'); =head1 DESCRIPTION B is a class for writing out a directed graph in a simple XML format. The graph must be an instance of the Graph class, which is actually a set of classes developed by Jarkko Hietaniemi. The XML format is designed to support the Graph classes: it can be used to represent a single graph with a collection of nodes, and edges between those nodes. The graph, nodes, and edges can all have attributes specified, where an attribute is a (name,value) pair, with the value being scalar. =head1 METHODS =head2 new() Constructor - generate a new writer instance. $writer = Graph::Writer::XML->new(); This doesn't take any arguments. =head2 write_graph() Write a specific graph to a named file: $writer->write_graph($graph, $file); The C<$file> argument can either be a filename, or a filehandle for a previously opened file. =head1 KNOWN BUGS Attribute values must be scalar. If they're not, well, you're on your own. =head1 SEE ALSO =over 4 =item L The perl module used to actually write out the XML. It handles entities etc. =item L Jarkko Hietaniemi's modules for representing directed graphs, available from CPAN under modules/by-module/Graph/ =item Algorithms in Perl The O'Reilly book which has a chapter on directed graphs, which is based around Jarkko's modules. =item L The base-class for Graph::Writer::XML =back =head1 REPOSITORY L =head1 AUTHOR Neil Bowers Eneil@bowers.comE =head1 COPYRIGHT Copyright (c) 2001-2012, Neil Bowers. All rights reserved. Copyright (c) 2001, Canon Research Centre Europe. All rights reserved. This script is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Graph-ReadWrite-2.08/lib/Graph/Reader/Dot.pm000644 000765 000024 00000050522 12614772247 020741 0ustar00neilbstaff000000 000000 #################################################################### # # This file was generated using Parse::Yapp version 1.02. # # Don't edit this file, use source file instead. # # ANY CHANGE MADE HERE WILL BE LOST ! # #################################################################### package Graph::Reader::Dot; $Graph::Reader::Dot::VERSION = '2.08'; use strict; use warnings; use parent 'Parse::Yapp::Driver'; sub new { my($class)=shift; ref($class) and $class=ref($class); my($self)=$class->SUPER::new( yyversion => '1.02', yystates => [ {#State 0 ACTIONS => { 'STRICT' => 1, 'GRAPH' => 2, 'DIGRAPH' => 5 }, GOTOS => { 'Graph' => 3, 'GraphType' => 4 } }, {#State 1 ACTIONS => { 'STRICT' => 1, 'GRAPH' => 2, 'DIGRAPH' => 5 }, GOTOS => { 'GraphType' => 6 } }, {#State 2 DEFAULT => -6 }, {#State 3 ACTIONS => { '' => 7 } }, {#State 4 ACTIONS => { 'QUOT' => 9, 'NUMBER' => 8, 'ID' => 10 }, GOTOS => { 'IdNumQuot' => 11 } }, {#State 5 DEFAULT => -5 }, {#State 6 DEFAULT => -4 }, {#State 7 DEFAULT => -0 }, {#State 8 DEFAULT => -31 }, {#State 9 DEFAULT => -30 }, {#State 10 DEFAULT => -32 }, {#State 11 ACTIONS => { "{" => 12 } }, {#State 12 ACTIONS => { 'GRAPH' => 13, 'EDGE' => 17, 'NODE' => 19, 'NUMBER' => 8, 'QUOT' => 9, "{" => 22, 'SUBGRAPH' => 24, 'ID' => 10 }, DEFAULT => -2, GOTOS => { 'AttrStmt' => 15, 'NodeId' => 14, 'StmtList' => 16, 'IdNumQuot' => 18, 'OptStmtList' => 20, 'Stmt' => 21, 'Attr' => 23, 'Subgraph' => 25, 'EdgeStmt' => 26, 'NodeStmt' => 27, 'NodeIdSubgraph' => 28 } }, {#State 13 ACTIONS => { "[" => 29 }, DEFAULT => -33, GOTOS => { 'OptAttrList' => 30 } }, {#State 14 ACTIONS => { "[" => 29 }, DEFAULT => -26, GOTOS => { 'OptAttrList' => 31 } }, {#State 15 ACTIONS => { ";" => 32 }, DEFAULT => -39, GOTOS => { 'OptSemicolon' => 33 } }, {#State 16 ACTIONS => { 'GRAPH' => 13, 'EDGE' => 17, 'NODE' => 19, 'NUMBER' => 8, 'QUOT' => 9, "{" => 22, 'SUBGRAPH' => 24, 'ID' => 10 }, DEFAULT => -3, GOTOS => { 'AttrStmt' => 15, 'NodeId' => 14, 'IdNumQuot' => 18, 'Stmt' => 34, 'Attr' => 23, 'Subgraph' => 25, 'EdgeStmt' => 26, 'NodeStmt' => 27, 'NodeIdSubgraph' => 28 } }, {#State 17 ACTIONS => { "[" => 29 }, DEFAULT => -33, GOTOS => { 'OptAttrList' => 35 } }, {#State 18 ACTIONS => { ":" => 36, "=" => 37 }, DEFAULT => -21 }, {#State 19 ACTIONS => { "[" => 29 }, DEFAULT => -33, GOTOS => { 'OptAttrList' => 38 } }, {#State 20 ACTIONS => { "}" => 39 } }, {#State 21 DEFAULT => -10 }, {#State 22 DEFAULT => -7, GOTOS => { 'BeginScope' => 41, 'WrappedStmtList' => 40 } }, {#State 23 ACTIONS => { ";" => 32 }, DEFAULT => -39, GOTOS => { 'OptSemicolon' => 42 } }, {#State 24 ACTIONS => { 'QUOT' => 9, 'NUMBER' => 8, 'ID' => 10 }, GOTOS => { 'IdNumQuot' => 43 } }, {#State 25 ACTIONS => { ";" => 32 }, DEFAULT => -25, GOTOS => { 'OptSemicolon' => 44 } }, {#State 26 ACTIONS => { ";" => 32 }, DEFAULT => -39, GOTOS => { 'OptSemicolon' => 45 } }, {#State 27 ACTIONS => { ";" => 32 }, DEFAULT => -39, GOTOS => { 'OptSemicolon' => 46 } }, {#State 28 ACTIONS => { 'EDGEOP' => 47, "[" => 29 }, DEFAULT => -33, GOTOS => { 'OptAttrList' => 48 } }, {#State 29 ACTIONS => { 'QUOT' => 9, 'NUMBER' => 8, "]" => 52, 'ID' => 10 }, GOTOS => { 'Attr' => 51, 'IdNumQuot' => 49, 'AttrList' => 50 } }, {#State 30 DEFAULT => -17 }, {#State 31 DEFAULT => -20 }, {#State 32 DEFAULT => -40 }, {#State 33 DEFAULT => -12 }, {#State 34 DEFAULT => -11 }, {#State 35 DEFAULT => -19 }, {#State 36 ACTIONS => { 'QUOT' => 9, 'NUMBER' => 8, 'ID' => 10 }, GOTOS => { 'IdNumQuot' => 53 } }, {#State 37 ACTIONS => { 'QUOT' => 9, 'NUMBER' => 8, 'ID' => 10 }, GOTOS => { 'IdNumQuot' => 54 } }, {#State 38 DEFAULT => -18 }, {#State 39 ACTIONS => { ";" => 32 }, DEFAULT => -39, GOTOS => { 'OptSemicolon' => 55 } }, {#State 40 ACTIONS => { "}" => 56 } }, {#State 41 ACTIONS => { "{" => 22, 'QUOT' => 9, 'NUMBER' => 8, 'GRAPH' => 13, 'SUBGRAPH' => 24, 'ID' => 10, 'EDGE' => 17, 'NODE' => 19 }, GOTOS => { 'AttrStmt' => 15, 'NodeId' => 14, 'StmtList' => 57, 'IdNumQuot' => 18, 'Stmt' => 21, 'Attr' => 23, 'Subgraph' => 25, 'EdgeStmt' => 26, 'NodeStmt' => 27, 'NodeIdSubgraph' => 28 } }, {#State 42 DEFAULT => -16 }, {#State 43 ACTIONS => { "{" => 58 }, DEFAULT => -29 }, {#State 44 DEFAULT => -15 }, {#State 45 DEFAULT => -14 }, {#State 46 DEFAULT => -13 }, {#State 47 ACTIONS => { "{" => 22, 'QUOT' => 9, 'NUMBER' => 8, 'SUBGRAPH' => 24, 'ID' => 10 }, GOTOS => { 'NodeId' => 59, 'Subgraph' => 61, 'EdgeStmt' => 62, 'IdNumQuot' => 60, 'NodeIdSubgraph' => 28 } }, {#State 48 DEFAULT => -24 }, {#State 49 ACTIONS => { "=" => 37 } }, {#State 50 ACTIONS => { "," => 64, "]" => 65 }, DEFAULT => -41, GOTOS => { 'OptComma' => 63 } }, {#State 51 DEFAULT => -37 }, {#State 52 DEFAULT => -34 }, {#State 53 DEFAULT => -22 }, {#State 54 DEFAULT => -38 }, {#State 55 DEFAULT => -1 }, {#State 56 DEFAULT => -27 }, {#State 57 ACTIONS => { 'GRAPH' => 13, 'EDGE' => 17, 'NODE' => 19, 'NUMBER' => 8, 'QUOT' => 9, "{" => 22, 'SUBGRAPH' => 24, 'ID' => 10 }, DEFAULT => -8, GOTOS => { 'EndScope' => 66, 'AttrStmt' => 15, 'NodeId' => 14, 'IdNumQuot' => 18, 'Stmt' => 34, 'Attr' => 23, 'Subgraph' => 25, 'EdgeStmt' => 26, 'NodeStmt' => 27, 'NodeIdSubgraph' => 28 } }, {#State 58 DEFAULT => -7, GOTOS => { 'BeginScope' => 41, 'WrappedStmtList' => 67 } }, {#State 59 DEFAULT => -26 }, {#State 60 ACTIONS => { ":" => 36 }, DEFAULT => -21 }, {#State 61 DEFAULT => -25 }, {#State 62 DEFAULT => -23 }, {#State 63 ACTIONS => { 'QUOT' => 9, 'NUMBER' => 8, 'ID' => 10 }, GOTOS => { 'Attr' => 68, 'IdNumQuot' => 49 } }, {#State 64 DEFAULT => -42 }, {#State 65 DEFAULT => -35 }, {#State 66 DEFAULT => -9 }, {#State 67 ACTIONS => { "}" => 69 } }, {#State 68 DEFAULT => -36 }, {#State 69 DEFAULT => -28 } ], yyrules => [ [#Rule 0 '$start', 2, undef ], [#Rule 1 'Graph', 6, sub #line 16 "Graph_Reader_Dot.yp" { # add the graph attributes... my $r = $_[0]->YYData->{DefAttr}->[-1]->{Graph}; my $g = $_[0]->{GRAPH}; for my $attr (keys %{$r}) { my $value = $r->{$attr}; $g->set_graph_attribute($attr,$value); } $g->set_graph_attribute('name', $_[2] ); # set name, will be reused by Graph::Writer::Dot } ], [#Rule 2 'OptStmtList', 0, sub #line 28 "Graph_Reader_Dot.yp" { #empty return undef; } ], [#Rule 3 'OptStmtList', 1, undef ], [#Rule 4 'GraphType', 2, sub #line 35 "Graph_Reader_Dot.yp" { return $_[2]; # dunno what to do with the strict anyway... } ], [#Rule 5 'GraphType', 1, undef ], [#Rule 6 'GraphType', 1, sub #line 41 "Graph_Reader_Dot.yp" { &{$_[0]->YYData->{Options}->{Carp}}( "!graph will be treated as digraph" ); # see below for expl. return $_[1]; } ], [#Rule 7 'BeginScope', 0, sub #line 48 "Graph_Reader_Dot.yp" { # empty # mah: use some clone() function? # mah: for optimization should do lazy copying... (i.e. COW, copy-on-write) my $n = {}; $n->{Graph} = { %{$_[0]->YYData->{DefAttr}->[-1]->{Graph}} }; $n->{Node} = { %{$_[0]->YYData->{DefAttr}->[-1]->{Node}} }; $n->{Edge} = { %{$_[0]->YYData->{DefAttr}->[-1]->{Edge}} }; push @{$_[0]->YYData->{DefAttr}}, $n; } ], [#Rule 8 'EndScope', 0, sub #line 59 "Graph_Reader_Dot.yp" { # empty pop @{$_[0]->YYData->{DefAttr}}; } ], [#Rule 9 'WrappedStmtList', 3, sub #line 64 "Graph_Reader_Dot.yp" { return $_[2]; } ], [#Rule 10 'StmtList', 1, sub #line 69 "Graph_Reader_Dot.yp" { return $_[1]; } ], [#Rule 11 'StmtList', 2, sub #line 73 "Graph_Reader_Dot.yp" { for my $k ( keys %{$_[2]} ) { # merge the hashes $_[1]->{$k}++; } return $_[1]; } ], [#Rule 12 'Stmt', 2, sub #line 81 "Graph_Reader_Dot.yp" { return {}; } ], [#Rule 13 'Stmt', 2, undef ], [#Rule 14 'Stmt', 2, sub #line 87 "Graph_Reader_Dot.yp" { return $_[1]->[2]; # only pass on the cumulative node set } ], [#Rule 15 'Stmt', 2, undef ], [#Rule 16 'Stmt', 2, sub #line 93 "Graph_Reader_Dot.yp" { # graph / subgraph attribute (i.e. same as graph [bla=3];) my $r = $_[0]->YYData->{DefAttr}->[-1]->{Graph}; $r->{$_[1]->[0]} = $_[1]->[1]; return {}; # no node returned... } ], [#Rule 17 'AttrStmt', 2, sub #line 101 "Graph_Reader_Dot.yp" { _merge_hash( $_[0]->YYData->{DefAttr}->[-1]->{Graph}, $_[2] ); } ], [#Rule 18 'AttrStmt', 2, sub #line 105 "Graph_Reader_Dot.yp" { # note: those will only apply to newly created nodes... _merge_hash( $_[0]->YYData->{DefAttr}->[-1]->{Node}, $_[2] ); } ], [#Rule 19 'AttrStmt', 2, sub #line 109 "Graph_Reader_Dot.yp" { # note: those will only apply to newly created edges... _merge_hash( $_[0]->YYData->{DefAttr}->[-1]->{Edge}, $_[2] ); } ], [#Rule 20 'NodeStmt', 2, sub #line 114 "Graph_Reader_Dot.yp" { my $g = $_[0]->{GRAPH}; unless( $g->has_vertex($_[1]) ) { $g->add_vertex($_[1]); # default node attribute only apply to *new* nodes (as in dot) # btw, that implies also, that the order is important in dot files for the attribute values... if( $_[0]->YYData->{Options}->{UseNodeAttr} ) { _set_attribute_hash( $g, $_[0]->YYData->{DefAttr}->[-1]->{Node}, $_[1] ); } }; _set_attribute_hash( $g, $_[2], $_[1] ); return { $_[1] => 1 }; } ], [#Rule 21 'NodeId', 1, undef ], [#Rule 22 'NodeId', 3, sub #line 131 "Graph_Reader_Dot.yp" { &{$_[0]->YYData->{Options}->{Carp}}( "!cannot correctly process subnodes" ); return $_[1]; } ], [#Rule 23 'EdgeStmt', 3, sub #line 142 "Graph_Reader_Dot.yp" { my $g = $_[0]->{GRAPH}; for my $u (keys %{$_[1]}) { for my $v (keys %{ @{$_[3]}[0] } ) { # add non-existent nodes... (should make a separate loop for efficiency) if( $_[0]->YYData->{Options}->{UseNodeAttr} ) { unless ( $g->has_vertex($u) ) { $g->add_vertex($u); # important _set_attribute_hash( $g, $_[0]->YYData->{DefAttr}->[-1]->{Node}, $u ); } unless( $g->has_vertex($v) ) { $g->add_vertex($v); # important _set_attribute_hash( $g, $_[0]->YYData->{DefAttr}->[-1]->{Node}, $v ); } } $g->add_edge($u,$v); _set_attribute_hash($g, $_[3]->[1], $u, $v ); if( $_[0]->YYData->{Options}->{UseEdgeAttr} ) { _set_attribute_hash($g, $_[0]->YYData->{DefAttr}->[-1]->{Edge}, $u, $v ); } } } for my $u (keys %{$_[1]}) { # update cumulative node hash $_[3]->[2]->{$u}++; } return [$_[1],$_[3]->[1], $_[3]->[2]]; } ], [#Rule 24 'EdgeStmt', 2, sub #line 170 "Graph_Reader_Dot.yp" { return [$_[1],$_[2],$_[1]]; # mah: not copying $_[1] is dangerous but works at the moment # (it requires the other routines to keep the order of (a) make edges and (b) update cumulative nodes) } ], [#Rule 25 'NodeIdSubgraph', 1, undef ], [#Rule 26 'NodeIdSubgraph', 1, sub #line 178 "Graph_Reader_Dot.yp" { return { $_[1] => 1 } } ], [#Rule 27 'Subgraph', 3, sub #line 185 "Graph_Reader_Dot.yp" { # anonymous subgraph return $_[2]; } ], [#Rule 28 'Subgraph', 5, sub #line 189 "Graph_Reader_Dot.yp" { # named subgraph # have to store the nodeset somewhere... if( defined $_[0]->YYData->{Subgraphs}->{$_[2]} ) { # check for name clash for subgraph die "?subgraph '$_[2]' has been doubly defined\n"; } else { # *copy* the subgraphs nodes for later use # mah: note: assumptions is, that the outside may (and in fact will) modify hash contents $_[0]->YYData->{Subgraphs}->{$_[2]} = { %{$_[4]} }; } return $_[4]; } ], [#Rule 29 'Subgraph', 2, sub #line 202 "Graph_Reader_Dot.yp" { # subgraph reference (mah: what does it do?) if( !defined $_[0]->YYData->{Subgraphs}->{$_[2]} ) { # check for missing name die "?subgraph '$_[2]' has not been defined\n"; } else { # hand out copy... return +{ %{$_[0]->YYData->{Subgraphs}->{$_[2]}} }; } } ], [#Rule 30 'IdNumQuot', 1, sub #line 213 "Graph_Reader_Dot.yp" { return substr $_[1],1,-1; } ], [#Rule 31 'IdNumQuot', 1, undef ], [#Rule 32 'IdNumQuot', 1, undef ], [#Rule 33 'OptAttrList', 0, sub #line 223 "Graph_Reader_Dot.yp" { # may be empty return {}; } ], [#Rule 34 'OptAttrList', 2, sub #line 227 "Graph_Reader_Dot.yp" { return {}; } ], [#Rule 35 'OptAttrList', 3, sub #line 231 "Graph_Reader_Dot.yp" { return $_[2]; } ], [#Rule 36 'AttrList', 3, sub #line 236 "Graph_Reader_Dot.yp" { my ($k,$v) = @{$_[3]}; $_[1]->{$k} = $v; return $_[1]; } ], [#Rule 37 'AttrList', 1, sub #line 242 "Graph_Reader_Dot.yp" { return { @{$_[1]} }; # pull it into a hash reference } ], [#Rule 38 'Attr', 3, sub #line 247 "Graph_Reader_Dot.yp" { return [$_[1],$_[3]]; } ], [#Rule 39 'OptSemicolon', 0, sub #line 252 "Graph_Reader_Dot.yp" { #empty return ';' # just for the sake of completeness... } ], [#Rule 40 'OptSemicolon', 1, sub #line 256 "Graph_Reader_Dot.yp" { } ], [#Rule 41 'OptComma', 0, sub #line 260 "Graph_Reader_Dot.yp" { # empty return ','; # for the sake of completeness... } ], [#Rule 42 'OptComma', 1, sub #line 264 "Graph_Reader_Dot.yp" { } ] ], @_); bless($self,$class); } #line 267 "Graph_Reader_Dot.yp" sub _merge_hash { my ($dst,$src) = @_; # merge keys and values of %{$src} in %{$dst} for ( keys %$src ) { $dst->{$_} = $src->{$_}; } } sub _set_attribute_hash { my $g = shift; my $h = shift; local $_; # @_ contains the destination... (graph, node, edge) for (keys %$h ) { if (@_ == 0) { $g->set_graph_attribute(@_,$_,$h->{$_}); } elsif (@_ == 1) { $g->set_vertex_attribute(@_,$_,$h->{$_}); } else { $g->set_edge_attribute(@_,$_,$h->{$_}); } } } # lexer starts here: # build regexp for reserved words: my @reserved = qw( strict digraph graph edge node subgraph ); my $reserved_re = qr{\b(@{[join '|', @reserved]})\b}oi; sub _Error { exists $_[0]->YYData->{ERRMSG} and do { print $_[0]->YYData->{ERRMSG}; delete $_[0]->YYData->{ERRMSG}; return; }; print "\$_[0]->YYCurtok " . $_[0]->YYCurtok."\n"; print "\$_[0]->YYCurval " . $_[0]->YYCurval."\n"; print "\@\$_[0]->YYExpect " . (join " ", $_[0]->YYExpect )."\n"; print "\$_[0]->YYLexer " . $_[0]->YYLexer."\n"; print "substr(\$_[0]->YYData->{INPUT},0,21) " . substr($_[0]->YYData->{INPUT},0,21) . "...\n"; print "Syntax error.\n"; } sub _Lexer { my($parser)=shift; my $fh = $parser->{FILE}; $parser->YYData->{INPUT} =~ s:^//.*::; # must be at beginning of string, this ensures it is unquoted (string are only single line) if( $parser->YYData->{INPUT} eq '' ) { do { return ('',undef) if( $fh->eof ); $_ = <$fh>; chomp; s/^\s*//; if( m:/\*: ) { # kill c-style comments # TODO scan for eof... while( ! s:/\*.*\*/::s ) { $_ .= <$fh>; } chomp; } } while( m:^//: || $_ eq '' ); # skip comment & empty lines $parser->YYData->{INPUT} = $_; } $parser->YYData->{INPUT} =~ s/^($reserved_re)\s*// and return uc $1; # reserved word $parser->YYData->{INPUT} =~ s/^(-[->])\s*// and return( 'EDGEOP', $1 ); # edge operator (directed or undirected) $parser->YYData->{INPUT} =~ s/^([_a-zA-Z][._a-zA-Z0-9]*)\s*// and return( 'ID',$1 ); # identifier $parser->YYData->{INPUT} =~ s/^(-?[0-9]*\.[0-9]*|-?[0-9]+)\s*// and return( 'NUMBER',$1 ); # number $parser->YYData->{INPUT} =~ s/^(\"(?:\\\"|[^\"])*\")\s*// and return( 'QUOT', $1 ); # quoted string $parser->YYData->{INPUT} =~ s/^(.)\s*//s and return($1,$1); # any char } use Graph::Reader; use vars qw(@ISA $UseNodeAttr $UseEdgeAttr); @ISA = qw(Parse::Yapp::Driver Graph::Reader); # this will override setting from yapp sub _init { my $self = shift; $self->SUPER::_init(); } sub _read_graph { my $self = shift; my $graph = shift; my $FILE = shift; $self->{CONTEXT} = []; $self->{GRAPH} = $graph; $self->{FILE} = $FILE; # initialize parse data structures... undef $self->YYData->{Subgraphs}; # will contain node sets for every name subgraph # clear default attribs for current scope: $self->YYData->{DefAttr} = [{Graph=>{}, Node=>{}, Edge=>{}}]; $self->YYData->{Options}->{UseNodeAttr} = $UseNodeAttr; $self->YYData->{Options}->{UseEdgeAttr} = $UseEdgeAttr; $self->YYData->{Options}->{Carp} = \&Carp::carp; $self->YYData->{Options}->{Croak} = \&Carp::croak; # ^ now that's a workaround for not being able to declare Carp early enough, coz of Yapp restrictions... # the following kills a warning from the test regression suite: $self->YYData->{INPUT} = '' unless defined $self->YYData->{INPUT}; $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error ); return 1; } 1; =head1 NAME Graph::Reader::Dot - class for reading a Graph instance from Dot format =head1 SYNOPSIS use Graph::Reader::Dot; use Graph; $reader = Graph::Reader::Dot->new(); $graph = $reader->read_graph('mygraph.dot'); =head1 DESCRIPTION B is a class for reading in a directed graph in the file format used by the I tool (part of the AT+T graphviz package). B is a subclass of B, which defines the generic interface for Graph reader classes. =head1 METHODS AND CONFIGURATION =head2 C Constructor - generate a new reader instance. $reader = Graph::Reader::Dot->new(); This doesn't take any arguments. =head2 C Read a graph from a file: $graph = $reader->read_graph( $file ); The C<$file> argument can be either a filename or a filehandle of a previously opened file. =head2 C<$Graph::Reader::Dot::UseNodeAttr> Controls, if implicit node attributes given by the dot directive C will be merged into (new) nodes. Setting it to C<0> or C (default) will not disable this feature. Setting it to any other value will enable this feature. =head2 C<$Graph::Reader::Dot::UseEdgeAttr> Controls, if implicit edge attributes given by the dot directive C will be merged into edges. Setting it to C<0> or C (default) will not disable this feature. Setting it to any other value will enable this feature. =head1 RESTRICTIONS =over 4 =item * Default (graph) attributes in subgraphs (i.e. inside C<{}>) are not processed. =item * Sub nodes as used by dot's C node shape are supported. =item * Undirected graphs will be treated as directed graphs. This means that the C<--> edge operator works as the C<-E> edge operator. =item * Be aware that you are loosing scope information on writing back the graph. =item * Multiple C or C statements in the same scope are not correctly supported. =back =head1 SEE ALSO =over 4 =item http://www.graphviz.org/ The home page for the AT+T graphviz toolkit that includes the dot tool. =item Graph::Reader The base class for B. =item Graph::Writer::Dot Used to serialise a Graph instance in Dot format. =item Graph Jarkko Hietaniemi's classes for representing directed graphs. =item Parse::Yapp Another base class for B. The B module comes with the following copyright notice: The Parse::Yapp module and its related modules and shell scripts are copyright (c) 1998-1999 Francois Desarmenien, France. All rights reserved. You may use and distribute them under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. If you use the "standalone parser" option so people don't need to install Parse::Yapp on their systems in order to run you software, this copyright noticed should be included in your software copyright too, and the copyright notice in the embedded driver should be left untouched. =back =head1 AUTHOR Mark A. Hillebrand Emah@wjpserver.cs.uni-sb.deE =head1 COPYRIGHT Copyright (c) 2001 by Mark A. Hillebrand. All rights reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; Graph-ReadWrite-2.08/lib/Graph/Reader/HTK.pm000644 000765 000024 00000015053 12614772247 020641 0ustar00neilbstaff000000 000000 # # Graph::Reader::HTK - perl module for reading an HTK lattice into a Graph # package Graph::Reader::HTK; $Graph::Reader::HTK::VERSION = '2.08'; use 5.006; use strict; use warnings; use parent 'Graph::Reader'; use Carp; my %node_attributes = ( 'WORD' => [ 'WORD', 'label' ], 'W' => [ 'WORD', 'label' ], 'time' => [ 'time' ], 't' => [ 'time' ], 'var' => [ 'var' ], 'v' => [ 'var' ], 'L' => [ 'L' ], ); my %edge_attributes = ( 'WORD' => [ 'WORD', 'label' ], 'W' => [ 'WORD', 'label' ], 'START' => [ 'START' ], 'S' => [ 'START' ], 'END' => [ 'END' ], 'E' => [ 'END' ], 'var' => [ 'var' ], 'v' => [ 'var' ], 'div' => [ 'div' ], 'd' => [ 'div' ], 'acoustic' => [ 'acoustic' ], 'a' => [ 'acoustic' ], 'ngram' => [ 'ngram' ], 'n' => [ 'ngram' ], 'language' => [ 'language', 'weight' ], 'l' => [ 'language', 'weight' ], ); #======================================================================= # # _read_graph # # The private method which implements the actual reading of the file. # #======================================================================= sub _read_graph { my $self = shift; my $graph = shift; my $FILE = shift; my $nvertices; my $nedges; my $v; my $from; my $to; my $weight; my ($an, $av); my $node_num; my $link; while (<$FILE>) { chop; #--------------------------------------------------------------- # ignore version line #--------------------------------------------------------------- if (/^\s*(V|VERSION)\s*=\s*(\S+)/) { $graph->set_graph_attribute('HTK_VERSION', $2); next; } if (/^\s*(base|lmname|lmscale|wdpenalty)\s*=\s*(\S+)/) { # print STDERR "Setting graph attribute $1 to $2\n"; $graph->set_graph_attribute($1, ''.$2); } #--------------------------------------------------------------- # line which says how many nodes & links we have #--------------------------------------------------------------- if (/N\s*=\s*(\d+)\s*L\s*=\s*(\d+)/) { # $NUM_NODES = $1; # $NUM_LINKS = $2; next; } #--------------------------------------------------------------- # node definition #--------------------------------------------------------------- if (/^I\s*=\s*(\d+)/mg) { #--------------------------------------------------------------- # strip off the fields from the rest of the line # and set appropriate attributes #--------------------------------------------------------------- $node_num = "n$1"; $graph->add_vertex($node_num); # print STDERR "Node $node_num:\n"; while (/\s*(\S+)\s*=\s*(\S+)/mg) { $an = $1; $av = $2; if (exists $node_attributes{$an}) { foreach my $a (@{ $node_attributes{$an} }) { # print STDERR " attr $a = $av\n"; $graph->set_vertex_attribute($node_num, $a, $av); } } else { carp "unknown node field \"$an\" - ignoring\n"; } } next; } elsif (/I\s*=\s*/) { carp "unexpected format for node line \"$_\" - ignoring\n"; next; } #--------------------------------------------------------------- # edge definition #--------------------------------------------------------------- if (/^J\s*=\s*(\d+)/mg) { my %attr; $link = $1; # print STDERR "Edge $link:\n"; while (/\s*(\S+)\s*=\s*(\S+)/mg) { $an = $1; $av = $2; # print STDERR " field $an = $av\n"; if (exists $edge_attributes{$an}) { foreach my $a (@{ $edge_attributes{$an} }) { $attr{$a} = $av; } } else { carp "unknown link field \"$an\" - ignoring\n"; } } if (exists $attr{START} && exists $attr{END}) { $from = 'n'.$attr{START}; $to = 'n'.$attr{END}; delete $attr{START}; delete $attr{END}; } else { carp "link on line $. doesn't have START and END - ignoring\n"; next; } $graph->add_edge($from, $to); foreach $a (keys %attr) { # print STDERR " attr $a = ", $attr{$a}, "\n"; $graph->set_edge_attribute($from, $to, $a, $attr{$a}); } } elsif (/^J/) { carp "unexpected format for link line \"$_\" - ignoring\n"; next; } } return 1; } 1; __END__ =head1 NAME Graph::Reader::HTK - read an HTK lattice in as an instance of Graph =head1 SYNOPSIS use Graph::Reader::HTK; $reader = Graph::Reader::HTK->new; $graph = $reader->read_graph('mylattice.lat'); =head1 DESCRIPTION This module can be used to read a directed graph in the L lattice format. It returns an instance of the L class. =head1 SEE ALSO =over 4 =item L Jarkko Hietaniemi's Graph class and others, used for representing and manipulating directed graphs. Available from CPAN. Also described / used in the chapter on directed graph algorithms in the B book from O'Reilly. =item L The base-class for this module, which defines the public methods, and describes the ideas behind Graph reader and writer modules. =item L A class which will write a perl Graph out as an HTK lattice. =item L The Hidden Markov Model Toolkit. =back =head1 REPOSITORY L =head1 AUTHOR Neil Bowers Eneil@bowers.comE =head1 COPYRIGHT Copyright (c) 2000-2012, Neil Bowers. All rights reserved. Copyright (c) 2000, Canon Research Centre Europe. All rights reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Graph-ReadWrite-2.08/lib/Graph/Reader/XML.pm000644 000765 000024 00000013231 12614772247 020647 0ustar00neilbstaff000000 000000 # # Graph::Reader::XML - perl class for reading directed graphs from XML # package Graph::Reader::XML; $Graph::Reader::XML::VERSION = '2.08'; use 5.006; use strict; use warnings; use parent 'Graph::Reader'; use Carp; use XML::Parser; #======================================================================= # # _init() # # initialisation private method, invoked by the constructor. # First call the superclass initialiser, then create an # instance of XML::Parser, which does most of the work for us. # #======================================================================= sub _init { my $self = shift; $self->SUPER::_init(); #------------------------------------------------------------------- # use closures to associate the $self reference with the handler # function which will get invoked by the XML::Parser #------------------------------------------------------------------- $self->{PARSER} = XML::Parser->new(Handlers => { Start => sub { handle_start($self, @_); }, End => sub { handle_end($self, @_); }, }); } #======================================================================= # # _read_graph # # private method where the business is done. Just invoke the # parse method on the XML::Parser instance. The real business is # done in the handle_start() and handle_end() "methods", which # are invoked by the XML parser. # #======================================================================= sub _read_graph { my $self = shift; my $graph = shift; my $FILE = shift; $self->{CONTEXT} = []; $self->{GRAPH} = $graph; $self->{PARSER}->parse($FILE); return 1; } #======================================================================= # # handle_start # # XML parser handler for the start of an element. # #======================================================================= sub handle_start { my ($self, $p, $el, %attr) = @_; my $graph = $self->{GRAPH}; if ($el eq 'attribute') { if (exists $attr{name} && exists $attr{value}) { $self->set_attribute($attr{name}, $attr{value}); } else { carp "attribute should have name and value - ignoring\n"; } } elsif ($el eq 'node') { $graph->add_vertex($attr{id}); push(@{$self->{CONTEXT}}, [$el, $attr{id}]); } elsif ($el eq 'edge') { $graph->add_edge($attr{from}, $attr{to}); push(@{$self->{CONTEXT}}, [$el, $attr{from}, $attr{to}]); } elsif ($el eq 'graph') { push(@{$self->{CONTEXT}}, [$el]); } else { carp "unknown element \"$el\"\n"; } } #======================================================================= # # handle_end # # XML parser handler for the end of an element. # #======================================================================= sub handle_end { my ($self, $p, $el) = @_; if ($el eq 'node' || $el eq 'edge' || $el eq 'graph') { pop(@{$self->{CONTEXT}}); } } #======================================================================= # # set_attribute # # Performs the actual setting of an attribute. Looks at the saved # context to determine what we're setting an attribute of, and sets # it on the Graph instance. # #======================================================================= sub set_attribute { my ($self, $name, $value) = @_; if (@{$self->{CONTEXT}} == 0) { carp "attribute element with no context - ignoring!\n"; return; } my $graph = $self->{GRAPH}; my ($el, @args) = @{ (@{$self->{CONTEXT}})[-1] }; if ($el eq 'node') { $graph->set_vertex_attribute($args[0], $name, $value); } elsif ($el eq 'edge') { $graph->set_edge_attribute($args[0], $args[1], $name, $value); } elsif ($el eq 'graph') { $graph->set_graph_attribute($name, $value); } else { carp "unexpected context for attribute\n"; } } 1; =head1 NAME Graph::Reader::XML - class for reading a Graph instance from XML =head1 SYNOPSIS use Graph::Reader::XML; use Graph; $reader = Graph::Reader::XML->new(); $graph = $reader->read_graph('mygraph.xml'); =head1 DESCRIPTION B is a perl class used to read a directed graph stored as XML, and return an instance of the B class. The XML format is designed to support the Graph classes: it can be used to represent a single graph with a collection of nodes, and edges between those nodes. The graph, nodes, and edges can all have attributes specified, B is a subclass of B, which defines the generic interface for Graph reader classes. =head1 METHODS =head2 new() Constructor - generate a new reader instance. $reader = Graph::Reader::XML->new(); This doesn't take any arguments. =head2 read_graph() Read a graph from a file: $graph = $reader->read_graph( $file ); The C<$file> argument can be either a filename or a filehandle of a previously opened file. =head1 KNOWN BUGS Attribute values must be scalar. If they're not, well, you're on your own. =head1 SEE ALSO =over 4 =item Graph::Reader The base class for B. =item Graph::Writer::XML Used to serialise a Graph instance as XML. =item Graph Jarkko Hietaniemi's classes for representing directed graphs. =back =head1 REPOSITORY L =head1 AUTHOR Neil Bowers Eneil@bowers.comE =head1 COPYRIGHT Copyright (c) 2001-2012, Neil Bowers. All rights reserved. Copyright (c) 2001, Canon Research Centre Europe. All rights reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut