Graph-ReadWrite-2.05/000755 000765 000024 00000000000 12270047120 014614 5ustar00neilbstaff000000 000000 Graph-ReadWrite-2.05/Changes000644 000765 000024 00000006761 12270046670 016132 0ustar00neilbstaff000000 000000 Revision history for perl distribution Graph-ReadWrite 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.05/lib/000755 000765 000024 00000000000 12270047120 015362 5ustar00neilbstaff000000 000000 Graph-ReadWrite-2.05/Makefile.PL000644 000765 000024 00000003243 12270043411 016567 0ustar00neilbstaff000000 000000 # # Makefile.PL for Graph-ReadWrite # use ExtUtils::MakeMaker; my $mm_ver = $ExtUtils::MakeMaker::VERSION; if ($mm_ver =~ /_/) { # dev version $mm_ver = eval $mm_ver; die $@ if $@; } &WriteMakefile( NAME => 'Graph-ReadWrite', DISTNAME => 'Graph-ReadWrite', ABSTRACT => 'Classes for reading and writing directed graphs', AUTHOR => 'Neil Bowers ', VERSION => '2.05', LICENSE => 'perl', ($mm_ver <= 6.45 ? () : (META_MERGE => { 'meta-spec' => { version => 2 }, resources => { bugtracker => 'http://rt.cpan.org/Public/Dist/Display.html?Name=Graph-ReadWrite', repository => { type => 'git', web => 'https://github.com/neilbowers/Graph-ReadWrite', url => 'git://github.com/neilbowers/Graph-ReadWrite.git', }, }, }) ), PREREQ_PM => { 'IO::File' => 0, 'Graph' => 0.5, 'XML::Parser' => 0, 'XML::Writer' => 0, 'Parse::Yapp::Driver' => 0, 'parent' => 0, 'Carp' => 0, 'File::Compare' => 0, }, ($mm_ver >= 6.48 ? (MIN_PERL_VERSION => 5.006) : () ), ($mm_ver >= 6.52 ? (CONFIGURE_REQUIRES => { 'ExtUtils::MakeMaker' => 6.30, }) : () ), dist => {COMPRESS => 'gzip', SUFFIX => 'gz'}, ); Graph-ReadWrite-2.05/MANIFEST000644 000765 000024 00000001072 12270047120 015745 0ustar00neilbstaff000000 000000 Makefile.PL MANIFEST README TODO Changes lib/Graph/Writer.pm lib/Graph/Writer/Dot.pm lib/Graph/Writer/XML.pm lib/Graph/Writer/VCG.pm lib/Graph/Writer/daVinci.pm lib/Graph/Writer/HTK.pm lib/Graph/Reader.pm lib/Graph/Reader/XML.pm lib/Graph/Reader/HTK.pm lib/Graph/Reader/Dot.pm t/base.t t/simple.t t/reader.t t/data/simple.davinci t/data/simple.xml t/data/simple.dot t/data/simple.htk t/data/simple.vcg META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Graph-ReadWrite-2.05/META.json000644 000765 000024 00000002350 12270047120 016235 0ustar00neilbstaff000000 000000 { "abstract" : "Classes for reading and writing directed graphs", "author" : [ "Neil Bowers " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 6.82, CPAN::Meta::Converter version 2.133380", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Graph-ReadWrite", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Carp" : "0", "File::Compare" : "0", "Graph" : "0.5", "IO::File" : "0", "Parse::Yapp::Driver" : "0", "XML::Parser" : "0", "XML::Writer" : "0", "parent" : "0", "perl" : "5.006" } } }, "release_status" : "stable", "resources" : { "repository" : { "type" : "git", "url" : "git://github.com/neilbowers/Graph-ReadWrite.git", "web" : "https://github.com/neilbowers/Graph-ReadWrite" } }, "version" : "2.05" } Graph-ReadWrite-2.05/META.yml000644 000765 000024 00000001224 12270047120 016064 0ustar00neilbstaff000000 000000 --- abstract: 'Classes for reading and writing directed graphs' author: - 'Neil Bowers ' build_requires: ExtUtils::MakeMaker: 0 dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 6.82, CPAN::Meta::Converter version 2.133380' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Graph-ReadWrite no_index: directory: - t - inc requires: Carp: 0 File::Compare: 0 Graph: 0.5 IO::File: 0 Parse::Yapp::Driver: 0 XML::Parser: 0 XML::Writer: 0 parent: 0 perl: 5.006 resources: repository: git://github.com/neilbowers/Graph-ReadWrite.git version: 2.05 Graph-ReadWrite-2.05/README000644 000765 000024 00000003473 11716424651 015517 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.05/t/000755 000765 000024 00000000000 12270047120 015057 5ustar00neilbstaff000000 000000 Graph-ReadWrite-2.05/TODO000644 000765 000024 00000001124 11716011471 015306 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.05/t/base.t000644 000765 000024 00000001066 11716011471 016165 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.05/t/data/000755 000765 000024 00000000000 12270047120 015770 5ustar00neilbstaff000000 000000 Graph-ReadWrite-2.05/t/reader.t000644 000765 000024 00000003703 11716021220 016506 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.05/t/simple.t000644 000765 000024 00000005220 12270046473 016546 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.05/t/data/simple.davinci000644 000765 000024 00000001107 12270046445 020630 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.05/t/data/simple.dot000644 000765 000024 00000000301 11716011471 017767 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.05/t/data/simple.htk000644 000765 000024 00000000213 11716011471 017771 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.05/t/data/simple.vcg000644 000765 000024 00000000677 11716011471 020000 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.05/t/data/simple.xml000644 000765 000024 00000000450 11716011471 020006 0ustar00neilbstaff000000 000000 Graph-ReadWrite-2.05/lib/Graph/000755 000765 000024 00000000000 12270047120 016423 5ustar00neilbstaff000000 000000 Graph-ReadWrite-2.05/lib/Graph/Reader/000755 000765 000024 00000000000 12270047120 017625 5ustar00neilbstaff000000 000000 Graph-ReadWrite-2.05/lib/Graph/Reader.pm000644 000765 000024 00000011607 12270043500 020166 0ustar00neilbstaff000000 000000 # # Graph::Reader - perl base class for Graph file format readers # package Graph::Reader; use strict; use warnings; our $VERSION = '2.05'; 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 Graph 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 Graph::Reader::XML A simple subclass of this class for reading a simple XML format for directed graphs. =item Graph::Writer A baseclass for Graph file format writers. =back =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.05/lib/Graph/Writer/000755 000765 000024 00000000000 12270047120 017677 5ustar00neilbstaff000000 000000 Graph-ReadWrite-2.05/lib/Graph/Writer.pm000644 000765 000024 00000012545 12270043506 020250 0ustar00neilbstaff000000 000000 # # Graph::Writer - perl base class for Graph file format writers # package Graph::Writer; use strict; use warnings; our $VERSION = '2.05'; 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 Graph 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 Graph::Writer::Dot 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 Graph::Writer::VCG 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 Graph::Writer::XML A simple subclass of this class for writing graphs as XML, using a simple graph markup. =item Graph::Reader A baseclass for Graph file format readers. =back =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.05/lib/Graph/Writer/daVinci.pm000644 000765 000024 00000014277 12270046372 021635 0ustar00neilbstaff000000 000000 # # Graph::Writer::daVinci - write a directed graph out in daVinci format # package Graph::Writer::daVinci; use strict; use warnings; use parent 'Graph::Writer'; our $VERSION = '2.04'; #----------------------------------------------------------------------- # 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 Graph 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 Graph::Writer The base-class for Graph::Writer::daVinci =back =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.05/lib/Graph/Writer/Dot.pm000644 000765 000024 00000015442 12270043557 021003 0ustar00neilbstaff000000 000000 # # Graph::Writer::Dot - write a directed graph out in Dot format # package Graph::Writer::Dot; use strict; use warnings; use parent 'Graph::Writer'; our $VERSION = '2.05'; #----------------------------------------------------------------------- # 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 http://www.graphviz.org/ The home page for the AT+T graphviz toolkit that includes the dot tool. =item Graph 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 Graph::Writer The base-class for Graph::Writer::Dot =back =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.05/lib/Graph/Writer/HTK.pm000644 000765 000024 00000007126 12270043564 020701 0ustar00neilbstaff000000 000000 # # Graph::Writer::HTK - perl module for writing a Graph as an HTK lattice # package Graph::Writer::HTK; use strict; use warnings; #======================================================================= #======================================================================= use parent 'Graph::Writer'; our $VERSION = '2.05'; 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 =head1 SEE ALSO =over 4 =item Graph 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 Graph::Writer The base-class for this module, which defines the public methods, and describes the ideas behind Graph reader and writer modules. =item Graph::Reader::HTK A class which will read a perl Graph from an HTK lattice file. =back =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.05/lib/Graph/Writer/VCG.pm000644 000765 000024 00000025566 12270043574 020703 0ustar00neilbstaff000000 000000 # # Graph::Writer::VCG - write a directed graph out in VCG format # package Graph::Writer::VCG; use strict; use warnings; use parent 'Graph::Writer'; our $VERSION = '2.05'; #----------------------------------------------------------------------- # 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 Graph 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 Graph::Writer The base-class for Graph::Writer::VCG =back =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.05/lib/Graph/Writer/XML.pm000644 000765 000024 00000011661 12270043601 020702 0ustar00neilbstaff000000 000000 # # Graph::Writer::XML - write a directed graph out as XML # package Graph::Writer::XML; use strict; use warnings; use parent 'Graph::Writer'; use XML::Writer; our $VERSION = '2.05'; #======================================================================= # # _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 XML::Writer The perl module used to actually write out the XML. It handles entities etc. =item Graph 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 Graph::Writer The base-class for Graph::Writer::XML =back =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.05/lib/Graph/Reader/Dot.pm000644 000765 000024 00000050514 12270043540 020720 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; 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 $VERSION $UseNodeAttr $UseEdgeAttr); $VERSION = '2.05'; @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.05/lib/Graph/Reader/HTK.pm000644 000765 000024 00000014353 12270043546 020627 0ustar00neilbstaff000000 000000 # # Graph::Reader::HTK - perl module for reading an HTK lattice into a Graph # package Graph::Reader::HTK; use strict; use warnings; use parent 'Graph::Reader'; use Carp; our $VERSION = '2.05'; 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 =head1 SEE ALSO =over 4 =item Graph 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 Graph::Reader The base-class for this module, which defines the public methods, and describes the ideas behind Graph reader and writer modules. =item Graph::Writer::HTK A class which will write a perl Graph out as an HTK lattice. =back =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.05/lib/Graph/Reader/XML.pm000644 000765 000024 00000013101 12270043553 020625 0ustar00neilbstaff000000 000000 # # Graph::Reader::XML - perl class for reading directed graphs from XML # package Graph::Reader::XML; use strict; use warnings; use parent 'Graph::Reader'; use Carp; use XML::Parser; our $VERSION = '2.05'; #======================================================================= # # _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 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