File Coverage

blib/lib/SemMed/Interface/GraphTraversal.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             #
3             # @File GraphTraversal.pm
4             # @Author andriy
5             # @Created Jul 1, 2016 10:53:44 AM
6             #
7 1     1   6 use strict;
  1         1  
  1         21  
8 1     1   2 use warnings;
  1         1  
  1         22  
9 1     1   244 use CUI;
  0            
  0            
10             use Predicate;
11             require DataAccess;
12             require Heap::Priority;
13             package GraphTraversal;
14              
15              
16              
17             my $conn = ""; #used for data access
18             sub new{
19             my $class = shift;
20             $conn = shift;
21             my $self = {};
22             bless $self, $class;
23             return $self;
24             }
25              
26              
27             #given a source CUI-ID and a destination CUI-ID this sub will return the destination CUI containing shortest path data or a
28             #-1 signifying no path was found. Path data in the returned CUI can be access through its methods (ie. $CUI->getPathLength())
29             #Utilizes Dijktras for finding shortest path between CUI's
30              
31             #INPUT: SOURCE_CUI(string), DESTINATION_CUI(St$gt = new GraphTraversal();ring), WEIGHT_STATISTICAL_MEASURE(string)
32             #OPTIONAL INPUT: , List of predicates to only include, List of Predicates to Ignore
33              
34              
35             sub findShortestPath{
36             my $self = shift;
37             my $startCui = $conn->getCUI(shift); #ex. heart arrest C0018790
38             my $endCui = $conn->getCUI(shift); #ex. traffic accidents C0000932
39             my $statistic = shift;
40             my $includedPredicates = shift; #array reference to list of predicates to include
41             my $excludedPredicates = shift; #array reference to list of predicates to ignore
42              
43              
44              
45             my $currentVertex = $startCui; #starting vertex
46             $currentVertex-> setPathLength(0); #mark first vertex as reached
47              
48             my @edges = (); #this array contains all predicate connections found thus far
49              
50             my $fringe = new Heap::Priority; #this PriorityQueue contains all CUI under consideration for the next shortest path.
51             $fringe->lowest_first(); #set priority to the smallest element
52              
53             my @reached = (); #this array contains references to all CUI's that have already been reached.
54              
55             ## load initial set of predicate connections
56             my @query = $conn->getPredicateConnections($startCui, $statistic, $includedPredicates, $excludedPredicates);
57             foreach my $edge (@query){
58             push @edges, $edge;
59             }
60              
61              
62              
63             while($currentVertex->getId() ne $endCui->getId()){ #while we have not reached the vertex we're searching for
64             $currentVertex->_print();
65             push @reached, $currentVertex; #add current vertex to reached vertices
66             # $currentVertex->printPath();
67             foreach my $edge (@edges){
68             if($edge->getSource()->getId() eq $currentVertex->getId() ){
69              
70             my $destVertex = $edge->getDestination();
71              
72              
73             if( not(grep $_->getId() eq $destVertex->getId(), @reached) ){ #if destVertex has not been reached yet
74              
75             if($destVertex->getPathLength() == -1){
76             $destVertex->setPathLength( $currentVertex->getPathLength() + $edge->getWeight() ); #TODO implement own method
77             $destVertex->setPrevCUI($currentVertex); #save the vertex we arrived from
78             $destVertex->setPrevPredicate($edge -> getPredicate);
79             }
80             if($destVertex->getPathLength() >= ($currentVertex->getPathLength() + $edge->getWeight() ) ){ #TODO
81             $destVertex->setPathLength( $currentVertex->getPathLength() + $edge->getWeight() ); #TODO implement own method
82             $destVertex->setPrevCUI($currentVertex); #save the vertex we arrived fromcd
83             $destVertex->setPrevPredicate($edge -> getPredicate);
84             }
85              
86             # if(not(grep $_->getId() eq $destVertex->getId(), @fringe) ){
87             $fringe->add($destVertex, $destVertex->getPathLength());
88             #push onto the queue giving it a priority equal to its edge weight.
89             # }
90             }
91             }
92             }
93              
94              
95             if($fringe->count()==0){ #if fringe is empty,break
96             return -1;
97             }
98              
99             #set current vertex to CUI with smallest aggregate weight
100             $currentVertex = $fringe->pop();
101              
102             ##loads new set of edges from databa$gt = new GraphTraversal();se
103             my @newedges = $conn->getPredicateConnections($currentVertex, $statistic);
104             foreach my $edge (@newedges){
105             push @edges, $edge;
106             }
107              
108             }
109              
110             push @reached, $currentVertex; #push end cui onto reached as we have found it
111              
112             return $currentVertex;
113              
114             }
115              
116              
117             #finds a path between two given CUI's
118             #utilizes BFS
119              
120             #
121             #INPUT: SOURCE_CUI(string), DESTINATION_CUI(string)
122             #OPTIONAL INPUT: , List of predicates to only include, List of Predicates to Ignore
123             #
124             #OUTPUT: PathLength from SOURCE_CUI to DESTINATION_CUI
125             #
126             #
127             sub findPath{
128             my $self = shift;
129             my $startCui = shift; #String containing the start cui
130             my $endCui = shift; #String containing the end cui
131             my $includedPredicates = shift; #array reference to list of predicates to include
132             my $excludedPredicates = shift; #array reference to list of predicates to ignore
133              
134              
135              
136              
137             #shift will return head of the queue
138             #push will add element to the queue
139             my @reachedCUI = (); #this array(treated as a queue) will contain the next node we want to go to
140             my @reachedLength = (); #parallel array to hold the length to each cui
141              
142             my $currentCUI = $startCui;
143             my $currentLength = 0;
144              
145             while($currentCUI ne $endCui){
146              
147              
148              
149             if($currentLength == 10){
150             return -1;
151             }
152              
153             my @adjacentedges = $conn->getPredicateConnections($conn->getCUI($currentCUI), 1, $includedPredicates, $excludedPredicates);
154              
155             #push new vertices to end of queue
156             foreach my $edge (@adjacentedges){
157             push @reachedCUI, $edge->getDestination()->getId();
158             push @reachedLength, ($currentLength + 1);
159             }
160              
161             #pop next vertex from queue
162             $currentCUI = shift @reachedCUI;
163             $currentLength = shift @reachedLength;
164              
165              
166             }
167              
168             return $currentLength;
169              
170              
171             }
172              
173             #finds the aggregate path score between two given CUI's
174             #utilizes BFS
175              
176             #
177             #INPUT: SOURCE_CUI(string), DESTINATION_CUI(string)
178             #OPTIONAL INPUT: statistical measure, List of predicates to only include, List of Predicates to Ignore
179             #
180             #OUTPUT: Aggregate relatedness score(measure specified in parameters) from SOURCE_CUI to DESTINATION_CUI
181             #
182             #TODO
183             sub findPathScore{
184             my $self = shift;
185             my $startCui = shift; #String containing the start cui
186             my $endCui = shift; #String containing the end cui
187             my $measure = shift;
188             my $includedPredicates = shift; #array reference to list of predicates to include
189             my $excludedPredicates = shift; #array reference to list of predicates to ignore
190              
191              
192              
193              
194             #shift will return head of the queue
195             #push will add element to the queue
196             my @reachedCUI = (); #this array(treated as a queue) will contain the next node we want to go to
197             my @reachedScore = (); #parallel array to hold the score of each cui
198              
199             my $currentCUI = $startCui;
200             my $currentLength = 0;
201             my $iter = 0;
202             while($currentCUI ne $endCui){
203             $iter++;
204             if($iter % 1000 == 0){
205             # print STDERR "Buffered CUI's: ". scalar(@reachedCUI)." ==> $iter \n";
206             }
207              
208             #TODO add threshold
209             # if($currentLength == 10){
210             # return -1;
211             # }
212              
213             my @adjacentedges = $conn->getPredicateConnections($conn->getCUI($currentCUI), $measure, $includedPredicates, $excludedPredicates);
214              
215             #push new vertices to end of queue
216             foreach my $edge (@adjacentedges){
217             push @reachedCUI, $edge->getDestination()->getId();
218             push @reachedScore, ($currentLength + ($edge->getWeight()));
219             }
220              
221             #pop next vertex from queue
222             $currentCUI = shift @reachedCUI;
223             $currentLength = shift @reachedScore;
224              
225              
226             }
227              
228             return $currentLength;
229              
230              
231             }
232              
233              
234             sub findPathString{
235             my $self = shift;
236             my $startCui = shift; #String containing the start cui
237             my $endCui = shift; #String containing the end cui
238             my $measure = shift;
239             my $includedPredicates = shift; #array reference to list of predicates to include
240             my $excludedPredicates = shift; #array reference to list of predicates to ignore
241              
242             my @reachedCUI; #this array(treated as a queue) will contain the next node we want to go to
243             my @reachedString = (); #parallel array to hold the path string
244              
245             my $currentCUI = $startCui;
246             my $currentString = "$startCui ";
247              
248             while($currentCUI ne $endCui){
249              
250             my @adjacentedges = $conn->getPredicateConnections($conn->getCUI($currentCUI), $measure, $includedPredicates, $excludedPredicates);
251              
252             #push new vertices to end of queue
253             foreach my $edge (@adjacentedges){
254             push @reachedCUI, $edge->getDestination()->getId();
255             push @reachedString, ($currentString." ".$edge->getDestination()->getId());
256             }
257              
258             #pop next vertex from queue
259             $currentCUI = shift @reachedCUI;
260             $currentString = shift @reachedString;
261              
262              
263             }
264              
265             return $currentString;
266              
267              
268              
269              
270             }
271              
272              
273             1;