Mercurial > repos > deepakjadmin > r_caret_test
diff mayachemtool/mayachemtools/lib/Graph/PathGraph.pm @ 0:68300206e90d draft default tip
Uploaded
author | deepakjadmin |
---|---|
date | Thu, 05 Nov 2015 02:41:30 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mayachemtool/mayachemtools/lib/Graph/PathGraph.pm Thu Nov 05 02:41:30 2015 -0500 @@ -0,0 +1,410 @@ +package Graph::PathGraph; +# +# $RCSfile: PathGraph.pm,v $ +# $Date: 2015/02/28 20:49:06 $ +# $Revision: 1.24 $ +# +# Author: Manish Sud <msud@san.rr.com> +# +# Copyright (C) 2015 Manish Sud. All rights reserved. +# +# This file is part of MayaChemTools. +# +# MayaChemTools is free software; you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) any +# later version. +# +# MayaChemTools is distributed in the hope that it will be useful, but without +# any warranty; without even the implied warranty of merchantability of fitness +# for a particular purpose. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or +# write to the Free Software Foundation Inc., 59 Temple Place, Suite 330, +# Boston, MA, 02111-1307, USA. +# + +use strict; +use Carp; +use Exporter; +use Storable (); +use Scalar::Util (); +use Graph; +use Graph::Path; + +use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); + +@ISA = qw(Graph Exporter); +@EXPORT = qw(IsPathGraph); +@EXPORT_OK = qw(); + +%EXPORT_TAGS = (all => [@EXPORT, @EXPORT_OK]); + +# Setup class variables... +my($ClassName, $PathsPropertyName, $CyclicPathsPropertyName); +_InitializeClass(); + +# Overload Perl functions... +use overload '""' => 'StringifyPathGraph'; + +# Class constructor... +sub new { + my($Class, $Graph) = @_; + + # Initialize object... + my $This = $Class->SUPER::new(); + bless $This, ref($Class) || $Class; + $This->_InitializePathGraph($Graph); + + $This->_ConvertGraphIntoPathGraph($Graph); + + return $This; +} + +# Initialize object data... +sub _InitializePathGraph { + my($This, $Graph) = @_; + + if (!(defined($Graph) && Graph::IsGraph($Graph))) { + croak "Error: ${ClassName}->new: PathGraph object can't be instantiated without a Graph object..."; + } + + $This->{Graph} = $Graph; + + # Maximum time allowed for cycles detection during collapse vertex cycles detection + # methodology in seconds... + $This->{MaxAllowedTime} = 30; + + # Starting time for cycles detection during collapse vertex cycles detection + # methodology... + $This->{StartTime} = time; + + return $This; +} + +# Initialize class ... +sub _InitializeClass { + #Class name... + $ClassName = __PACKAGE__; + + # Path edge property name... + $PathsPropertyName = 'Paths'; + + # Cyclic path vertex property name... + $CyclicPathsPropertyName = 'CyclicPaths'; +} + +# Convert graph into a path graph... +# +sub _ConvertGraphIntoPathGraph { + my($This, $Graph) = @_; + + # Copy graph vertices and edges without any associated properties data + # from Graph to This: Graph properties data is available using Graph object reference + # store in This object... + # + $Graph->CopyVerticesAndEdges($This); + + # . Attach Path property to each edge... + # + my($Index, $VertexID1, $VertexID2, $Path, @EdgesVertexIDs); + + @EdgesVertexIDs = (); + @EdgesVertexIDs = $This->GetEdges(); + for ($Index = 0; $Index < $#EdgesVertexIDs; $Index += 2) { + $VertexID1 = $EdgesVertexIDs[$Index]; $VertexID2 = $EdgesVertexIDs[$Index + 1]; + $Path = new Graph::Path($VertexID1, $VertexID2); + my(@Paths) = (); + push @Paths, $Path; + $This->SetEdgeProperty($PathsPropertyName, \@Paths, $VertexID1, $VertexID2); + } + return $This; +} + +# Collapse paths around a specified vertex by updating paths around the vertex +# and adding any resulting cyclic paths to vertices attached to specified vertex. +# +# Notes: +# . Path object references are stored as a list attached to Paths property on edges. +# Usage of list allows multiple paths attached to the egde between a pair of vertices; +# Graph doesn't support multiple egdes between a pair of vertices. +# +# . Cyclic path object references are stored as list on vertices as CyclicPaths graph property. +# List allows multiple Loop properties attached to a vertex. +# +# . For topologically complex graphs containing large number of cycles, cycles detection algorithm +# [ Ref 31 ] as implemented implemented in CollapseVertexAndCollectCyclicPathsDetectCycles +# might not be able to find all the cycles in a reasonable amount of time and is designed to +# abandon cycles detection after MaxAllowedTime. Consequently, no cycles are detected +# or assigned. +# +sub CollapseVertexAndCollectCyclicPaths { + my($This, $VertexID) = @_; + + if (!$This->HasVertex($VertexID)) { + carp "Warning: ${ClassName}->CollapseVertexAndCollectCyclicPaths: Didn't collapse vertex $VertexID: Vertex $VertexID doesn't exist..."; + return undef; + } + # Collect all paths around specified VertexID by going over paths associated with its edges... + my($Index, $EdgePathsRef, $EdgeVertexID1, $EdgeVertexID2, @Paths, @EdgesVertexIDs); + + @EdgesVertexIDs = (); + @EdgesVertexIDs = $This->GetEdges($VertexID); + + @Paths = (); + for ($Index = 0; $Index < $#EdgesVertexIDs; $Index += 2) { + ($EdgeVertexID1, $EdgeVertexID2) = ($EdgesVertexIDs[$Index], $EdgesVertexIDs[$Index + 1]); + $EdgePathsRef = $This->GetEdgeProperty($PathsPropertyName, $EdgeVertexID1, $EdgeVertexID2); + push @Paths, @{$EdgePathsRef}; + } + + # Go over each pair of paths around the specified vertex, join paths and associate + # joined path to appropriate edge... + my($Index1, $Index2, $Path1, $Path2, $JoinedPath, $JoinedPathStartVertexID, $JoinedPathEndVertexID, @CommonVertices); + + for ($Index1 = 0; $Index1 < $#Paths; $Index1 +=1 ) { + $Path1 = $Paths[$Index1]; + + PATH2: for ($Index2 = $Index1 + 1; $Index2 <= $#Paths; $Index2 +=1 ) { + $Path2 = $Paths[$Index2]; + + # For JoinedPath to be valid cycle, Path1 and Path2 must have exactly two vertices in common. + # Otherwise, joined path contains duplicate vertices besides the terminal vertices and + # indicates a path from a different direction. + # + # For paths leading to cycles, it only makes sense to join paths with only one common vertex; + # otherwise, it wouldn't lead to a cycle and can be ignored. + # + @CommonVertices = $Path1->GetCommonVertices($Path2); + if (!(@CommonVertices <= 2 && ($CommonVertices[0] == $VertexID || $CommonVertices[1] == $VertexID))) { + next PATH2; + } + + $JoinedPath = $Path1->JoinAtVertex($Path2, $VertexID); + ($JoinedPathStartVertexID, $JoinedPathEndVertexID) = $JoinedPath->GetTerminalVertices(); + + if (!$JoinedPath->IsIndependentPath()) { + next PATH2; + } + + # Decide whether to give up or keep going... + if ($This->_IsTimeToGiveUpCyclesDetection()) { + warn "Warning: ${ClassName}->CollapseVertexAndCollectCyclicPaths: Cycles detection algorithm [ Ref 31 ] as implemented in the current release of MayaChemTools didn't finish with in the maximum allowed time of $This->{MaxAllowedTime} seconds; Cycles detection has been abandoned..."; + return undef; + } + + if ($JoinedPathStartVertexID == $JoinedPathEndVertexID) { + # It's a cycle. Attach it to the graph as CylicPaths property... + if ($This->HasGraphProperty($CyclicPathsPropertyName)) { + my($ExistingCyclicPathsRef); + $ExistingCyclicPathsRef = $This->GetGraphProperty($CyclicPathsPropertyName); + push @{$ExistingCyclicPathsRef}, $JoinedPath; + } + else { + my(@NewCyclicPaths) = (); + push @NewCyclicPaths, $JoinedPath; + $This->SetGraphProperty($CyclicPathsPropertyName, \@NewCyclicPaths, $JoinedPathStartVertexID); + } + } + else { + if ($This->HasEdge($JoinedPathStartVertexID, $JoinedPathEndVertexID)) { + # Append to the list of exisiting paths property of the edge... + my($ExistingPathsRef); + $ExistingPathsRef = $This->GetEdgeProperty($PathsPropertyName, $JoinedPathStartVertexID, $JoinedPathEndVertexID); + push @{$ExistingPathsRef}, $JoinedPath; + } + else { + # Create a new edge and associate path property... + my(@NewPaths) = (); + push @NewPaths, $JoinedPath; + $This->AddEdge($JoinedPathStartVertexID, $JoinedPathEndVertexID); + $This->SetEdgeProperty($PathsPropertyName, \@NewPaths, $JoinedPathStartVertexID, $JoinedPathEndVertexID); + } + } + } + } + $This->DeleteVertex($VertexID); + + return $This; +} + +# Decide whether to give up cycles detection using collapse vertex methodology... +# +sub _IsTimeToGiveUpCyclesDetection { + my($This) = @_; + + return ((time - $This->{StartTime}) > $This->{MaxAllowedTime}) ? 1 : 0; +} + +# Delete vertices with degree less than a specifed degree... +# +sub DeleteVerticesWithDegreeLessThan { + my($This, $Degree) = @_; + my($VertexID, @VertexIDs); + + while (@VertexIDs = $This->GetVerticesWithDegreeLessThan($Degree)) { + for $VertexID (@VertexIDs) { + $This->DeleteVertex($VertexID); + } + } + return $This; +} + +# Get paths associated with edges... +# +sub GetPaths { + my($This) = @_; + my($PathsRef, @Paths, @PathsList); + + @Paths = (); @PathsList = (); + @PathsList = $This->GetEdgesProperty($PathsPropertyName); + for $PathsRef (@PathsList) { + push @Paths, @{$PathsRef}; + } + return wantarray ? @Paths : scalar @Paths; +} + +# Get paths associated with edges which make a cylce... +# +sub GetCyclicPaths { + my($This) = @_; + my($PathsRef, @Paths, @PathsList); + + @Paths = (); @PathsList = (); + @PathsList = $This->GetGraphProperty($CyclicPathsPropertyName); + PATHS: for $PathsRef (@PathsList) { + if (!(defined($PathsRef) && @{$PathsRef})) { + next PATHS; + } + push @Paths, @{$PathsRef}; + } + return wantarray ? @Paths : scalar @Paths; +} + +# Is it a path graph object? +sub IsPathGraph ($) { + my($Object) = @_; + + return _IsPathGraph($Object); +} + +# Return a string containg data for PathGraph object... +sub StringifyPathGraph { + my($This) = @_; + my($PathGraphString); + + $PathGraphString = 'PathGraph:' . $This->StringifyVerticesAndEdges() . '; ' . $This->StringifyProperties(); + + return $PathGraphString; +} + +# Is it a PathGraph object? +sub _IsPathGraph { + my($Object) = @_; + + return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0; +} + +1; + +__END__ + +=head1 NAME + +PathGraph + +=head1 SYNOPSIS + +use Graph::PathGraph; + +use Graph::PathGraph qw(:all); + +=head1 DESCRIPTION + +B<PathGraph> class provides the following methods: + +new, CollapseVertexAndCollectCyclicPaths, DeleteVerticesWithDegreeLessThan, +GetCyclicPaths, GetPaths, IsPathGraph, StringifyPathGraph + +B<PathGraph> class is derived from I<Graph> class. + +=head2 METHODS + +=over 4 + +=item B<new> + + $NewPathGraph = new Graph::PathGraph($Graph); + +Using specified I<Graph>, B<new> method creates a new B<PathGraph> object and returns +newly created B<PathGraph> object. + +I<Graph> is converted into a B<PathGraph> by copying all its vertices and edges without any +associated properties data and associating a I<Path> object to each edge containing edge +vertex IDs as intial path. + +=item B<CollapseVertexAndCollectCyclicPaths> + + $PathGraph->CollapseVertexAndCollectCyclicPaths($VertexID); + +Collapses paths around a I<VertexID> by updating paths around the vertex [Ref 31] and associating any +resulting cyclic paths to graph as B<CyclicPaths> property name. And returns I<PathGraph>. + +=item B<DeleteVerticesWithDegreeLessThan> + + $Return = $PathGraph->DeleteVerticesWithDegreeLessThan($Degree); + +Deletes vertices with degree less than I<Degree> from I<PathGraph> and returns I<PathGraph>. + +=item B<GetCyclicPaths> + + @CyclicPaths = $PathGraph->GetCyclicPaths(); + $NumOfPaths = $PathGraph->GetCyclicPaths(); + +Returns an array of cyclic I<Paths> associated with edges in I<PathGraph>. In scalar context, number +of cyclic paths is returned. + +=item B<GetPaths> + + @Paths = $PathGraph->GetPaths(); + $NumOfPaths = $PathGraph->GetPaths(); + +Returns an array of I<Paths> associated with edges in I<PathGraph>. In scalar context, number +of paths is returned. + +=item B<IsPathGraph> + + $Status = Graph::PathGraph::IsPathGraph($Object); + +Returns 1 or 0 based on whether I<Object> is a B<PathGraph> object. + +=item B<StringifyPathGraph> + + $String = $PathGraph->StringifyPathGraph(); + +Returns a string containing information about traversed paths in I<PathGraph> object. + +=back + +=head1 AUTHOR + +Manish Sud <msud@san.rr.com> + +=head1 SEE ALSO + +Graph.pm, Path.pm + +=head1 COPYRIGHT + +Copyright (C) 2015 Manish Sud. All rights reserved. + +This file is part of MayaChemTools. + +MayaChemTools is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the Free +Software Foundation; either version 3 of the License, or (at your option) +any later version. + +=cut