File Coverage

blib/lib/SemMed/Interface/GraphTraversal.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


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   7 use strict;
  1         1  
  1         23  
8 1     1   2 use warnings;
  1         2  
  1         22  
9 1     1   389 use SemMed::Interface::CUI;
  1         1  
  1         18  
10 1     1   301 use SemMed::Interface::Predicate;
  1         1  
  1         20  
11 1     1   322 use SemMed::Interface::DataAccess;
  0            
  0            
12             use Heap::Priority;
13             package GraphTraversal;
14              
15              
16              
17             my $conn = ""; #used for data access
18             sub new{
19             my $class = shift;
20             my $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             my @reachedCUI; #this array(treated as a queue) will contain the next node we want to go to
234             sub findPathR{
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             @reachedCUI = ();
243            
244             my $pathString = _findPathHelper($endCui, $startCui, "$startCui", $measure, $includedPredicates, $excludedPredicates );
245             @reachedCUI = ();
246             return $pathString;
247            
248            
249            
250             }
251              
252              
253             sub _findPathHelper{
254             my $self = shift;
255             my $endCui = shift;
256             my $currentCui = shift;
257             my $currentString = shift;
258             my $measure = shift;
259             my $includedPredicates = shift; #array reference to list of predicates to include
260             my $excludedPredicates = shift; #array reference to list of predicates to ignore
261            
262             if($endCui = $currentCui){
263             return $currentString;
264             }
265            
266             my @adjacentedges = $conn->getPredicateConnections($conn->getCUI($currentCui), $measure, $includedPredicates, $excludedPredicates);
267            
268             #push new vertices to end of queue
269             foreach my $edge (@adjacentedges) {
270             push @reachedCUI, $edge->getDestination()->getId();
271             }
272            
273             $currentCui = shift @reachedCUI;
274            
275             return _findPathHelper($endCui, $currentCui,"$currentString $currentCui", $measure, $includedPredicates, $excludedPredicates);
276            
277             }
278             1;
279