| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | # WordNet::Similarity::hso.pm version 2.04 | 
| 2 |  |  |  |  |  |  | # (Last updated $Id: hso.pm,v 1.16 2008/03/27 06:21:17 sidz1979 Exp $) | 
| 3 |  |  |  |  |  |  | # | 
| 4 |  |  |  |  |  |  | # Semantic Similarity Measure package implementing the measure | 
| 5 |  |  |  |  |  |  | # described by Hirst and St-Onge (1998). | 
| 6 |  |  |  |  |  |  | # | 
| 7 |  |  |  |  |  |  | # Copyright (c) 2005, | 
| 8 |  |  |  |  |  |  | # | 
| 9 |  |  |  |  |  |  | # Ted Pedersen, University of Minnesota Duluth | 
| 10 |  |  |  |  |  |  | # tpederse at d.umn.edu | 
| 11 |  |  |  |  |  |  | # | 
| 12 |  |  |  |  |  |  | # Siddharth Patwardhan, University of Utah, Salt Lake City | 
| 13 |  |  |  |  |  |  | # sidd at cs.utah.edu | 
| 14 |  |  |  |  |  |  | # | 
| 15 |  |  |  |  |  |  | # This program is free software; you can redistribute it and/or | 
| 16 |  |  |  |  |  |  | # modify it under the terms of the GNU General Public License | 
| 17 |  |  |  |  |  |  | # as published by the Free Software Foundation; either version 2 | 
| 18 |  |  |  |  |  |  | # of the License, or (at your option) any later version. | 
| 19 |  |  |  |  |  |  | # | 
| 20 |  |  |  |  |  |  | # This program is distributed in the hope that it will be useful, | 
| 21 |  |  |  |  |  |  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 22 |  |  |  |  |  |  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| 23 |  |  |  |  |  |  | # GNU General Public License for more details. | 
| 24 |  |  |  |  |  |  | # | 
| 25 |  |  |  |  |  |  | # You should have received a copy of the GNU General Public License | 
| 26 |  |  |  |  |  |  | # along with this program; if not, write to | 
| 27 |  |  |  |  |  |  | # | 
| 28 |  |  |  |  |  |  | # The Free Software Foundation, Inc., | 
| 29 |  |  |  |  |  |  | # 59 Temple Place - Suite 330, | 
| 30 |  |  |  |  |  |  | # Boston, MA  02111-1307, USA. | 
| 31 |  |  |  |  |  |  | # | 
| 32 |  |  |  |  |  |  | # ------------------------------------------------------------------ | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | package WordNet::Similarity::hso; | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | =head1 NAME | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | WordNet::Similarity::hso - Perl module for computing semantic relatedness | 
| 39 |  |  |  |  |  |  | of word senses using the method described by Hirst and St-Onge (1998). | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | use WordNet::Similarity::hso; | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | use WordNet::QueryData; | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | my $wn = WordNet::QueryData->new(); | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | my $object = WordNet::Similarity::hso->new($wn); | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | my $value = $object->getRelatedness("car#n#1", "bus#n#2"); | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | ($error, $errorString) = $object->getError(); | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | die "$errorString\n" if($error); | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | print "car (sense 1) <-> bus (sense 2) = $value\n"; | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  | This module computes the semantic relatedness of word senses according to | 
| 62 |  |  |  |  |  |  | the method described by Hirst and St-Onge (1998). In their paper they | 
| 63 |  |  |  |  |  |  | describe a method to identify 'lexical chains' in text. They measure the | 
| 64 |  |  |  |  |  |  | semantic relatedness of words in text to identify the links of the lexical | 
| 65 |  |  |  |  |  |  | chains. This measure of relatedness has been implemented in this module. | 
| 66 |  |  |  |  |  |  |  | 
| 67 |  |  |  |  |  |  | =head2 Methods | 
| 68 |  |  |  |  |  |  |  | 
| 69 |  |  |  |  |  |  | =over | 
| 70 |  |  |  |  |  |  |  | 
| 71 |  |  |  |  |  |  | =cut | 
| 72 |  |  |  |  |  |  |  | 
| 73 | 3 |  |  | 3 |  | 6762 | use strict; | 
|  | 3 |  |  |  |  | 7 |  | 
|  | 3 |  |  |  |  | 110 |  | 
| 74 |  |  |  |  |  |  |  | 
| 75 | 3 |  |  | 3 |  | 15 | use Exporter; | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 116 |  | 
| 76 | 3 |  |  | 3 |  | 1751 | use WordNet::Similarity; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 77 |  |  |  |  |  |  |  | 
| 78 |  |  |  |  |  |  | use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | @ISA = qw/WordNet::Similarity/; | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  | %EXPORT_TAGS = (); | 
| 83 |  |  |  |  |  |  |  | 
| 84 |  |  |  |  |  |  | @EXPORT_OK = (); | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | @EXPORT = (); | 
| 87 |  |  |  |  |  |  |  | 
| 88 |  |  |  |  |  |  | our $VERSION = '2.04'; | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | =item $hso->setPosList() | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | This method is internally called to determine the parts of speech | 
| 93 |  |  |  |  |  |  | this measure is capable of dealing with. | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | Parameters: none. | 
| 96 |  |  |  |  |  |  |  | 
| 97 |  |  |  |  |  |  | Returns: none. | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | =cut | 
| 100 |  |  |  |  |  |  |  | 
| 101 |  |  |  |  |  |  | sub setPosList | 
| 102 |  |  |  |  |  |  | { | 
| 103 |  |  |  |  |  |  | my $self = shift; | 
| 104 |  |  |  |  |  |  | $self->{n} = 1; | 
| 105 |  |  |  |  |  |  | $self->{v} = 1; | 
| 106 |  |  |  |  |  |  | $self->{a} = 1; | 
| 107 |  |  |  |  |  |  | $self->{r} = 1; | 
| 108 |  |  |  |  |  |  | } | 
| 109 |  |  |  |  |  |  |  | 
| 110 |  |  |  |  |  |  | # How medium strong relations work (from an e-mail by Sid): | 
| 111 |  |  |  |  |  |  | # Basically, for the | 
| 112 |  |  |  |  |  |  | # medium strong relations, I had to start from the given node and explore | 
| 113 |  |  |  |  |  |  | # all "legal" paths starting from that node and ending on $offset2. | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  | # To do this I created a recursive function _medStrong, that is called like | 
| 116 |  |  |  |  |  |  | # so in line 247: | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | #  my $score = $self->_medStrong(0, 0, 0, $offset1, $offset1, $offset2); | 
| 119 |  |  |  |  |  |  |  | 
| 120 |  |  |  |  |  |  | # The first parameter is the "state" (=0 initially). This parameter keeps | 
| 121 |  |  |  |  |  |  | # track of what part of the path we are on. For example, one of the legal | 
| 122 |  |  |  |  |  |  | # paths goes upwards, then horizontally, and then downwards. So along the | 
| 123 |  |  |  |  |  |  | # upwards section of the path, "state" would be 0. Along the horizontal | 
| 124 |  |  |  |  |  |  | # section of the path, the "state" becomes 1. Along the downwards section | 
| 125 |  |  |  |  |  |  | # the "state" is 2. Similarly, the state recognizes different legal paths. | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | # The second parameter is "distance" (=0 initially). This parameter keeps | 
| 128 |  |  |  |  |  |  | # track of the length of the path that we are at. Since the maximum length | 
| 129 |  |  |  |  |  |  | # possible is 5, we stop the recursive function when the path length reaches | 
| 130 |  |  |  |  |  |  | # 5. | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | # The third parameter is "chdir" (=0 initally) counts the number of changes | 
| 133 |  |  |  |  |  |  | # in direction. This value is required in the formula for the medium-strong | 
| 134 |  |  |  |  |  |  | # relation, so is updated everytime there is a change in path direction. | 
| 135 |  |  |  |  |  |  |  | 
| 136 |  |  |  |  |  |  | # The fourth parameter is "from node" (=offset1 initally). The recursive | 
| 137 |  |  |  |  |  |  | # function uses the from node to decide which are the next possible nodes in | 
| 138 |  |  |  |  |  |  | # a given path. Each of these are then explored creating n recursive copies. | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | # The fifth parameter is "path". It is  a string of the form | 
| 141 |  |  |  |  |  |  |  | 
| 142 |  |  |  |  |  |  | #  "$offset [DUH] $offset [DUH] $offset..." | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | # that stores a string representation of the path. This string is used in | 
| 145 |  |  |  |  |  |  | # the traces (if the path turns out to be a legal path). A path would turn | 
| 146 |  |  |  |  |  |  | # out to be a legal path if it is generated by our recursive function and | 
| 147 |  |  |  |  |  |  | # the first and last nodes in the path are $offset1 and $offset2 of the | 
| 148 |  |  |  |  |  |  | # relatedness measure. | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | # The sixth parameter to the function is "endOffset". This is basically | 
| 151 |  |  |  |  |  |  | # "$offset2" throughout and is used by the recursive function to determine | 
| 152 |  |  |  |  |  |  | # if the current node in the path is the last node of that path. | 
| 153 |  |  |  |  |  |  |  | 
| 154 |  |  |  |  |  |  | # The basic idea of the recursive function is at each stage, to determine | 
| 155 |  |  |  |  |  |  | # the next possible nodes in the path, from the current node and state. Then | 
| 156 |  |  |  |  |  |  | # _medStrong is called on each of these. The recursive function does a | 
| 157 |  |  |  |  |  |  | # search through a tree of "partially" legal paths, until a completely legal | 
| 158 |  |  |  |  |  |  | # path is found. Multiple such paths may be found. The highest of the scores | 
| 159 |  |  |  |  |  |  | # of these is returned. | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | # _medStrong returns the maximum length of a legal path that was found in a | 
| 162 |  |  |  |  |  |  | # given subtree of the recursive search. These return values are used by | 
| 163 |  |  |  |  |  |  | # _medStrong and the highest of these is returned. | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | =item $hso->getRelatedness ($synset1, $synset2) | 
| 167 |  |  |  |  |  |  |  | 
| 168 |  |  |  |  |  |  | Computes the relatedness of two word senses using the method of Hirst & | 
| 169 |  |  |  |  |  |  | St-Onge. | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | Parameters: two word senses in "word#pos#sense" format. | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | Returns: Unless a problem occurs, the return value is the relatedness | 
| 174 |  |  |  |  |  |  | score, which is greater-than or equal-to 0 and less-than or equal-to 16. | 
| 175 |  |  |  |  |  |  | If an error occurs, then the error level is set to non-zero and an error | 
| 176 |  |  |  |  |  |  | string is created (see the description of getError()). | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  | =cut | 
| 179 |  |  |  |  |  |  |  | 
| 180 |  |  |  |  |  |  | sub getRelatedness | 
| 181 |  |  |  |  |  |  | { | 
| 182 |  |  |  |  |  |  | my $self = shift; | 
| 183 |  |  |  |  |  |  | my $class = ref $self || $self; | 
| 184 |  |  |  |  |  |  | my $wps1 = shift; | 
| 185 |  |  |  |  |  |  | my $wps2 = shift; | 
| 186 |  |  |  |  |  |  | my $wn = $self->{wn}; | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  | # Check the existence of the WordNet::QueryData object. | 
| 189 |  |  |  |  |  |  | if(!$wn) { | 
| 190 |  |  |  |  |  |  | $self->{errorString} .= "\nError (${class}::getRelatedness()) - "; | 
| 191 |  |  |  |  |  |  | $self->{errorString} .= "A WordNet::QueryData object is required."; | 
| 192 |  |  |  |  |  |  | $self->{error} = 2; | 
| 193 |  |  |  |  |  |  | return undef; | 
| 194 |  |  |  |  |  |  | } | 
| 195 |  |  |  |  |  |  |  | 
| 196 |  |  |  |  |  |  | # Initialize traces. | 
| 197 |  |  |  |  |  |  | $self->{traceString} = ""; | 
| 198 |  |  |  |  |  |  |  | 
| 199 |  |  |  |  |  |  | # Undefined input cannot go unpunished. | 
| 200 |  |  |  |  |  |  | if(!$wps1 || !$wps2) { | 
| 201 |  |  |  |  |  |  | $self->{errorString} .= "\nWarning (${class}::getRelatedness()) - "; | 
| 202 |  |  |  |  |  |  | $self->{errorString} .= "Undefined input values."; | 
| 203 |  |  |  |  |  |  | $self->{error} = ($self->{error} < 1) ? 1 : $self->{error}; | 
| 204 |  |  |  |  |  |  | return undef; | 
| 205 |  |  |  |  |  |  | } | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | # Security check -- are the input strings in the correct format (word#pos#sense). | 
| 208 |  |  |  |  |  |  | my ($pos1, $pos2); | 
| 209 |  |  |  |  |  |  | my ($word1, $word2); | 
| 210 |  |  |  |  |  |  | if($wps1 =~ /^(\S+)\#([nvar])\#\d+$/) { | 
| 211 |  |  |  |  |  |  | $word1 = $1; | 
| 212 |  |  |  |  |  |  | $pos1 = $2; | 
| 213 |  |  |  |  |  |  | } | 
| 214 |  |  |  |  |  |  | else { | 
| 215 |  |  |  |  |  |  | $self->{errorString} .= "\nWarning (${class}::getRelatedness()) - "; | 
| 216 |  |  |  |  |  |  | $self->{errorString} .= "Input not in word\#pos\#sense format."; | 
| 217 |  |  |  |  |  |  | $self->{error} = ($self->{error} < 1) ? 1 : $self->{error}; | 
| 218 |  |  |  |  |  |  | return undef; | 
| 219 |  |  |  |  |  |  | } | 
| 220 |  |  |  |  |  |  | if($wps2 =~ /^(\S+)\#([nvar])\#\d+$/) { | 
| 221 |  |  |  |  |  |  | $word2 = $1; | 
| 222 |  |  |  |  |  |  | $pos2 = $2; | 
| 223 |  |  |  |  |  |  | } | 
| 224 |  |  |  |  |  |  | else { | 
| 225 |  |  |  |  |  |  | $self->{errorString} .= "\nWarning (${class}::getRelatedness()) - "; | 
| 226 |  |  |  |  |  |  | $self->{errorString} .= "Input not in word\#pos\#sense format."; | 
| 227 |  |  |  |  |  |  | $self->{error} = ($self->{error} < 1) ? 1 : $self->{error}; | 
| 228 |  |  |  |  |  |  | return undef; | 
| 229 |  |  |  |  |  |  | } | 
| 230 |  |  |  |  |  |  |  | 
| 231 |  |  |  |  |  |  | # Which parts of speech do we have. | 
| 232 |  |  |  |  |  |  | if($pos1 !~ /[nvar]/ || $pos2 !~ /[nvar]/) { | 
| 233 |  |  |  |  |  |  | $self->{errorString} .= "\nWarning (${class}::getRelatedness()) - "; | 
| 234 |  |  |  |  |  |  | $self->{errorString} .= "Unknown part(s) of speech."; | 
| 235 |  |  |  |  |  |  | $self->{error} = ($self->{error} < 1) ? 1 : $self->{error}; | 
| 236 |  |  |  |  |  |  | return 0; | 
| 237 |  |  |  |  |  |  | } | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  | # Now check if the similarity value for these two synsets is in | 
| 240 |  |  |  |  |  |  | # fact in the cache... if so return the cached value. | 
| 241 |  |  |  |  |  |  | my $relatedness = | 
| 242 |  |  |  |  |  |  | $self->{doCache} ? $self->fetchFromCache ($wps1, $wps2) : undef; | 
| 243 |  |  |  |  |  |  | defined $relatedness and return $relatedness; | 
| 244 |  |  |  |  |  |  |  | 
| 245 |  |  |  |  |  |  | # Now get down to really finding the relatedness of these two. | 
| 246 |  |  |  |  |  |  | my $offset1 = $wn->offset($wps1); | 
| 247 |  |  |  |  |  |  | my $offset2 = $wn->offset($wps2); | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | if(!$offset1 || !$offset2) { | 
| 250 |  |  |  |  |  |  | $self->{errorString} .= "\nWarning (${class}::getRelatedness()) - "; | 
| 251 |  |  |  |  |  |  | $self->{errorString} .= "Input senses not found in WordNet."; | 
| 252 |  |  |  |  |  |  | $self->{error} = ($self->{error} < 1) ? 1 : $self->{error}; | 
| 253 |  |  |  |  |  |  | return undef; | 
| 254 |  |  |  |  |  |  | } | 
| 255 |  |  |  |  |  |  |  | 
| 256 |  |  |  |  |  |  | $offset1 = $offset1.$pos1; | 
| 257 |  |  |  |  |  |  | $offset2 = $offset2.$pos2; | 
| 258 |  |  |  |  |  |  |  | 
| 259 |  |  |  |  |  |  | if($offset1 eq $offset2) { | 
| 260 |  |  |  |  |  |  | # [trace] | 
| 261 |  |  |  |  |  |  | if($self->{trace}) { | 
| 262 |  |  |  |  |  |  | $self->{'traceString'} .= "Strong Rel (Synset Match) : "; | 
| 263 |  |  |  |  |  |  | $self->printSet($pos1, 'offset', $offset1); | 
| 264 |  |  |  |  |  |  | $self->{'traceString'} .= "\n\n"; | 
| 265 |  |  |  |  |  |  | } | 
| 266 |  |  |  |  |  |  | # [/trace] | 
| 267 |  |  |  |  |  |  |  | 
| 268 |  |  |  |  |  |  | $self->{doCache} and $self->storeToCache ($wps1, $wps2, 16); | 
| 269 |  |  |  |  |  |  | return 16; | 
| 270 |  |  |  |  |  |  | } | 
| 271 |  |  |  |  |  |  |  | 
| 272 |  |  |  |  |  |  | my @horiz1 = &_getHorizontalOffsetsPOS($self->{wn}, $offset1); | 
| 273 |  |  |  |  |  |  | my @upward1 = &_getUpwardOffsetsPOS($self->{wn}, $offset1); | 
| 274 |  |  |  |  |  |  | my @downward1 = &_getDownwardOffsetsPOS($self->{wn}, $offset1); | 
| 275 |  |  |  |  |  |  | my @horiz2 = &_getHorizontalOffsetsPOS($self->{wn}, $offset2); | 
| 276 |  |  |  |  |  |  | my @upward2 = &_getUpwardOffsetsPOS($self->{wn}, $offset2); | 
| 277 |  |  |  |  |  |  | my @downward2 = &_getDownwardOffsetsPOS($self->{wn}, $offset2); | 
| 278 |  |  |  |  |  |  |  | 
| 279 |  |  |  |  |  |  | # [trace] | 
| 280 |  |  |  |  |  |  | if($self->{trace}) { | 
| 281 |  |  |  |  |  |  | $self->{traceString} .= "Horizontal Links of "; | 
| 282 |  |  |  |  |  |  | $self->printSet($pos1, 'offset', $offset1); | 
| 283 |  |  |  |  |  |  | $self->{traceString} .= ": "; | 
| 284 |  |  |  |  |  |  | $self->printSet($pos1, 'offset', @horiz1); | 
| 285 |  |  |  |  |  |  | $self->{traceString} .= "\nUpward Links of "; | 
| 286 |  |  |  |  |  |  | $self->printSet($pos1, 'offset', $offset1); | 
| 287 |  |  |  |  |  |  | $self->{traceString} .= ": "; | 
| 288 |  |  |  |  |  |  | $self->printSet($pos1, 'offset', @upward1); | 
| 289 |  |  |  |  |  |  | $self->{traceString} .= "\nDownward Links of "; | 
| 290 |  |  |  |  |  |  | $self->printSet($pos1, 'offset', $offset1); | 
| 291 |  |  |  |  |  |  | $self->{traceString} .= ": "; | 
| 292 |  |  |  |  |  |  | $self->printSet($pos1, 'offset', @downward1); | 
| 293 |  |  |  |  |  |  | $self->{traceString} .= "\nHorizontal Links of "; | 
| 294 |  |  |  |  |  |  | $self->printSet($pos2, 'offset', $offset2); | 
| 295 |  |  |  |  |  |  | $self->{traceString} .= ": "; | 
| 296 |  |  |  |  |  |  | $self->printSet($pos2, 'offset', @horiz2); | 
| 297 |  |  |  |  |  |  | $self->{traceString} .= "\nUpward Links of "; | 
| 298 |  |  |  |  |  |  | $self->printSet($pos2, 'offset', $offset2); | 
| 299 |  |  |  |  |  |  | $self->{traceString} .= ": "; | 
| 300 |  |  |  |  |  |  | $self->printSet($pos2, 'offset', @upward2); | 
| 301 |  |  |  |  |  |  | $self->{traceString} .= "\nDownward Links of "; | 
| 302 |  |  |  |  |  |  | $self->printSet($pos2, 'offset', $offset2); | 
| 303 |  |  |  |  |  |  | $self->{traceString} .= ": "; | 
| 304 |  |  |  |  |  |  | $self->printSet($pos2, 'offset', @downward2); | 
| 305 |  |  |  |  |  |  | $self->{traceString} .= "\n\n"; | 
| 306 |  |  |  |  |  |  | } | 
| 307 |  |  |  |  |  |  | # [/trace] | 
| 308 |  |  |  |  |  |  |  | 
| 309 |  |  |  |  |  |  | if(&_isIn($offset1, @horiz2) || &_isIn($offset2, @horiz1)) { | 
| 310 |  |  |  |  |  |  | # [trace] | 
| 311 |  |  |  |  |  |  | if($self->{trace}) { | 
| 312 |  |  |  |  |  |  | $self->{traceString} .= "Strong Rel (Horizontal Match) : \n"; | 
| 313 |  |  |  |  |  |  | $self->{traceString} .= "Horizontal Links of "; | 
| 314 |  |  |  |  |  |  | $self->printSet($pos1, 'offset', $offset1); | 
| 315 |  |  |  |  |  |  | $self->{traceString} .= ": "; | 
| 316 |  |  |  |  |  |  | $self->printSet($pos1, 'offset', @horiz1); | 
| 317 |  |  |  |  |  |  | $self->{traceString} .= "\nHorizontal Links of "; | 
| 318 |  |  |  |  |  |  | $self->printSet($pos2, 'offset', $offset2); | 
| 319 |  |  |  |  |  |  | $self->{traceString} .= ": "; | 
| 320 |  |  |  |  |  |  | $self->printSet($pos2, 'offset', @horiz2); | 
| 321 |  |  |  |  |  |  | $self->{traceString} .= "\n\n"; | 
| 322 |  |  |  |  |  |  | } | 
| 323 |  |  |  |  |  |  | # [/trace] | 
| 324 |  |  |  |  |  |  |  | 
| 325 |  |  |  |  |  |  | $self->{doCache} and $self->storeToCache ($wps1, $wps2, 16); | 
| 326 |  |  |  |  |  |  | return 16; | 
| 327 |  |  |  |  |  |  | } | 
| 328 |  |  |  |  |  |  |  | 
| 329 |  |  |  |  |  |  | if($word1 =~ /$word2/ || $word2 =~ /$word1/) { | 
| 330 |  |  |  |  |  |  | if(&_isIn($offset1, @upward2) || &_isIn($offset1, @downward2)) { | 
| 331 |  |  |  |  |  |  | # [trace] | 
| 332 |  |  |  |  |  |  | if($self->{trace}) { | 
| 333 |  |  |  |  |  |  | $self->{traceString} .= "Strong Rel (Compound Word Match) : \n"; | 
| 334 |  |  |  |  |  |  | $self->{traceString} .= "All Links of $word1: "; | 
| 335 |  |  |  |  |  |  | $self->printSet($pos1, 'offset', @horiz1, @upward1, @downward1); | 
| 336 |  |  |  |  |  |  | $self->{traceString} .= "\nAll Links of $word2: "; | 
| 337 |  |  |  |  |  |  | $self->printSet($pos2, 'offset', @horiz2, @upward2, @downward2); | 
| 338 |  |  |  |  |  |  | $self->{traceString} .= "\n\n"; | 
| 339 |  |  |  |  |  |  | } | 
| 340 |  |  |  |  |  |  | # [/trace] | 
| 341 |  |  |  |  |  |  |  | 
| 342 |  |  |  |  |  |  | $self->{doCache} and $self->storeToCache ($wps1, $wps2, 16); | 
| 343 |  |  |  |  |  |  | return 16; | 
| 344 |  |  |  |  |  |  | } | 
| 345 |  |  |  |  |  |  |  | 
| 346 |  |  |  |  |  |  | if(&_isIn($offset2, @upward1) || &_isIn($offset2, @downward1)) { | 
| 347 |  |  |  |  |  |  | # [trace] | 
| 348 |  |  |  |  |  |  | if($self->{trace}) { | 
| 349 |  |  |  |  |  |  | $self->{traceString} .= "Strong Rel (Compound Word Match) : \n"; | 
| 350 |  |  |  |  |  |  | $self->{traceString} .= "All Links of $word1: "; | 
| 351 |  |  |  |  |  |  | $self->printSet($pos1, 'offset', @horiz1, @upward1, @downward1); | 
| 352 |  |  |  |  |  |  | $self->{traceString} .= "\nAll Links of $word2: "; | 
| 353 |  |  |  |  |  |  | $self->printSet($pos2, 'offset', @horiz2, @upward2, @downward2); | 
| 354 |  |  |  |  |  |  | $self->{traceString} .= "\n\n"; | 
| 355 |  |  |  |  |  |  | } | 
| 356 |  |  |  |  |  |  | # [/trace] | 
| 357 |  |  |  |  |  |  |  | 
| 358 |  |  |  |  |  |  | $self->{doCache} and $self->storeToCache ($wps1, $wps2, 16); | 
| 359 |  |  |  |  |  |  | } | 
| 360 |  |  |  |  |  |  | } | 
| 361 |  |  |  |  |  |  |  | 
| 362 |  |  |  |  |  |  | # Conditions for Medium-Strong relations ... | 
| 363 |  |  |  |  |  |  | my $score = $self->_medStrong(0, 0, 0, $offset1, $offset1, $offset2); | 
| 364 |  |  |  |  |  |  |  | 
| 365 |  |  |  |  |  |  | $self->{doCache} and $self->storeToCache ($wps1, $wps2, $score); | 
| 366 |  |  |  |  |  |  | return $score; | 
| 367 |  |  |  |  |  |  | } | 
| 368 |  |  |  |  |  |  |  | 
| 369 |  |  |  |  |  |  | # Subroutine to get offsets(POS) of all horizontal links from a given | 
| 370 |  |  |  |  |  |  | # word (offset(POS)). All horizontal links specified  are -- | 
| 371 |  |  |  |  |  |  | # Also See, Antonymy, Attribute, Pertinence, Similarity. | 
| 372 |  |  |  |  |  |  | # INPUT PARAMS  : $wn      .. WordNet::QueryData object. | 
| 373 |  |  |  |  |  |  | #                 $offset  .. An offset-pos (e.g. 637554v) | 
| 374 |  |  |  |  |  |  | # RETURN VALUES : @offsets .. Array of offset-pos (e.g. 736438n) | 
| 375 |  |  |  |  |  |  | sub _getHorizontalOffsetsPOS | 
| 376 |  |  |  |  |  |  | { | 
| 377 |  |  |  |  |  |  | my $wn; | 
| 378 |  |  |  |  |  |  | my $offset; | 
| 379 |  |  |  |  |  |  | my $synset; | 
| 380 |  |  |  |  |  |  | my $pos; | 
| 381 |  |  |  |  |  |  | my $wordForm; | 
| 382 |  |  |  |  |  |  | my @partsOfSpeech; | 
| 383 |  |  |  |  |  |  | my @synsets; | 
| 384 |  |  |  |  |  |  | my @offsets; | 
| 385 |  |  |  |  |  |  |  | 
| 386 |  |  |  |  |  |  | $wn = shift; | 
| 387 |  |  |  |  |  |  | $offset = shift; | 
| 388 |  |  |  |  |  |  | @offsets = (); | 
| 389 |  |  |  |  |  |  | if($offset =~ /^([0-9]+)([a-z])$/) | 
| 390 |  |  |  |  |  |  | { | 
| 391 |  |  |  |  |  |  | $offset = $1; | 
| 392 |  |  |  |  |  |  | $pos = $2; | 
| 393 |  |  |  |  |  |  | } | 
| 394 |  |  |  |  |  |  | else | 
| 395 |  |  |  |  |  |  | { | 
| 396 |  |  |  |  |  |  | return @offsets; | 
| 397 |  |  |  |  |  |  | } | 
| 398 |  |  |  |  |  |  | $wordForm = $wn->getSense($offset,$pos); | 
| 399 |  |  |  |  |  |  | @synsets = $wn->queryWord($wordForm, "also"); | 
| 400 |  |  |  |  |  |  | push @synsets, $wn->queryWord($wordForm, "ants"); | 
| 401 |  |  |  |  |  |  | push @synsets, $wn->querySense($wordForm, "attr"); | 
| 402 |  |  |  |  |  |  | push @synsets, $wn->queryWord($wordForm, "pert"); | 
| 403 |  |  |  |  |  |  | push @synsets, $wn->querySense($wordForm, "sim"); | 
| 404 |  |  |  |  |  |  | foreach $synset (@synsets) | 
| 405 |  |  |  |  |  |  | { | 
| 406 |  |  |  |  |  |  | $pos = $synset; | 
| 407 |  |  |  |  |  |  | if($pos =~ /.*\#([a-z])\#.*/) | 
| 408 |  |  |  |  |  |  | { | 
| 409 |  |  |  |  |  |  | $pos = $1; | 
| 410 |  |  |  |  |  |  | push @offsets, $wn->offset($synset).$pos; | 
| 411 |  |  |  |  |  |  | } | 
| 412 |  |  |  |  |  |  | } | 
| 413 |  |  |  |  |  |  | return @offsets; | 
| 414 |  |  |  |  |  |  | } | 
| 415 |  |  |  |  |  |  |  | 
| 416 |  |  |  |  |  |  |  | 
| 417 |  |  |  |  |  |  | # Subroutine that returns all offsetPOSs that are linked | 
| 418 |  |  |  |  |  |  | # to a given synset by upward links. Upward link types -- | 
| 419 |  |  |  |  |  |  | # Hypernymy, Meronymy | 
| 420 |  |  |  |  |  |  | # INPUT PARAMS  : $wn       .. WordNet::QueryData object. | 
| 421 |  |  |  |  |  |  | #                 $offset   .. OffsetPOS of the synset. | 
| 422 |  |  |  |  |  |  | # RETURN VALUES : @offsets  .. Array of offsetPOSs. | 
| 423 |  |  |  |  |  |  | sub _getUpwardOffsetsPOS | 
| 424 |  |  |  |  |  |  | { | 
| 425 |  |  |  |  |  |  | my $wn; | 
| 426 |  |  |  |  |  |  | my $offset; | 
| 427 |  |  |  |  |  |  | my $synset; | 
| 428 |  |  |  |  |  |  | my $pos; | 
| 429 |  |  |  |  |  |  | my $wordForm; | 
| 430 |  |  |  |  |  |  | my @partsOfSpeech; | 
| 431 |  |  |  |  |  |  | my @synsets; | 
| 432 |  |  |  |  |  |  | my @offsets; | 
| 433 |  |  |  |  |  |  |  | 
| 434 |  |  |  |  |  |  | $wn = shift; | 
| 435 |  |  |  |  |  |  | $offset = shift; | 
| 436 |  |  |  |  |  |  | @offsets = (); | 
| 437 |  |  |  |  |  |  | if($offset =~ /^([0-9]+)([a-z])$/) | 
| 438 |  |  |  |  |  |  | { | 
| 439 |  |  |  |  |  |  | $offset = $1; | 
| 440 |  |  |  |  |  |  | $pos = $2; | 
| 441 |  |  |  |  |  |  | } | 
| 442 |  |  |  |  |  |  | else | 
| 443 |  |  |  |  |  |  | { | 
| 444 |  |  |  |  |  |  | return @offsets; | 
| 445 |  |  |  |  |  |  | } | 
| 446 |  |  |  |  |  |  | $wordForm = $wn->getSense($offset,$pos); | 
| 447 |  |  |  |  |  |  | @synsets = $wn->querySense($wordForm, "hypes"); | 
| 448 |  |  |  |  |  |  | push @synsets, $wn->querySense($wordForm, "mero"); | 
| 449 |  |  |  |  |  |  | foreach $synset (@synsets) | 
| 450 |  |  |  |  |  |  | { | 
| 451 |  |  |  |  |  |  | $pos = $synset; | 
| 452 |  |  |  |  |  |  | if($pos =~ /.*\#([a-z])\#.*/) | 
| 453 |  |  |  |  |  |  | { | 
| 454 |  |  |  |  |  |  | $pos = $1; | 
| 455 |  |  |  |  |  |  | push @offsets, $wn->offset($synset).$pos; | 
| 456 |  |  |  |  |  |  | } | 
| 457 |  |  |  |  |  |  | } | 
| 458 |  |  |  |  |  |  | return @offsets; | 
| 459 |  |  |  |  |  |  | } | 
| 460 |  |  |  |  |  |  |  | 
| 461 |  |  |  |  |  |  |  | 
| 462 |  |  |  |  |  |  | # Subroutine that returns all offsetPOSs that are linked | 
| 463 |  |  |  |  |  |  | # to a given synset by downward links. Downward link types -- | 
| 464 |  |  |  |  |  |  | # Cause, Entailment, Holonymy, Hyponymy. | 
| 465 |  |  |  |  |  |  | # INPUT PARAMS  : $wn       .. WordNet::QueryData object. | 
| 466 |  |  |  |  |  |  | #                 $offset   .. OffsetPOS of the synset. | 
| 467 |  |  |  |  |  |  | # RETURN VALUES : @offsets  .. Array of offsetPOSs. | 
| 468 |  |  |  |  |  |  | sub _getDownwardOffsetsPOS | 
| 469 |  |  |  |  |  |  | { | 
| 470 |  |  |  |  |  |  | my $wn; | 
| 471 |  |  |  |  |  |  | my $offset; | 
| 472 |  |  |  |  |  |  | my $synset; | 
| 473 |  |  |  |  |  |  | my $pos; | 
| 474 |  |  |  |  |  |  | my $wordForm; | 
| 475 |  |  |  |  |  |  | my @partsOfSpeech; | 
| 476 |  |  |  |  |  |  | my @synsets; | 
| 477 |  |  |  |  |  |  | my @offsets; | 
| 478 |  |  |  |  |  |  |  | 
| 479 |  |  |  |  |  |  | $wn = shift; | 
| 480 |  |  |  |  |  |  | $offset = shift; | 
| 481 |  |  |  |  |  |  | @offsets = (); | 
| 482 |  |  |  |  |  |  | if($offset =~ /^([0-9]+)([a-z])$/) | 
| 483 |  |  |  |  |  |  | { | 
| 484 |  |  |  |  |  |  | $offset = $1; | 
| 485 |  |  |  |  |  |  | $pos = $2; | 
| 486 |  |  |  |  |  |  | } | 
| 487 |  |  |  |  |  |  | else | 
| 488 |  |  |  |  |  |  | { | 
| 489 |  |  |  |  |  |  | return @offsets; | 
| 490 |  |  |  |  |  |  | } | 
| 491 |  |  |  |  |  |  | $wordForm = $wn->getSense($offset,$pos); | 
| 492 |  |  |  |  |  |  | @synsets = $wn->querySense($wordForm, "holo"); | 
| 493 |  |  |  |  |  |  | push @synsets, $wn->querySense($wordForm, "hypos"); | 
| 494 |  |  |  |  |  |  | push @synsets, $wn->querySense($wordForm, "enta"); | 
| 495 |  |  |  |  |  |  | push @synsets, $wn->querySense($wordForm, "caus"); | 
| 496 |  |  |  |  |  |  | foreach $synset (@synsets) | 
| 497 |  |  |  |  |  |  | { | 
| 498 |  |  |  |  |  |  | $pos = $synset; | 
| 499 |  |  |  |  |  |  | if($pos =~ /.*\#([a-z])\#.*/) | 
| 500 |  |  |  |  |  |  | { | 
| 501 |  |  |  |  |  |  | $pos = $1; | 
| 502 |  |  |  |  |  |  | push @offsets, $wn->offset($synset).$pos; | 
| 503 |  |  |  |  |  |  | } | 
| 504 |  |  |  |  |  |  | } | 
| 505 |  |  |  |  |  |  | return @offsets; | 
| 506 |  |  |  |  |  |  | } | 
| 507 |  |  |  |  |  |  |  | 
| 508 |  |  |  |  |  |  |  | 
| 509 |  |  |  |  |  |  | # Subroutine that checks if an offset is in a given | 
| 510 |  |  |  |  |  |  | # set of offsets. | 
| 511 |  |  |  |  |  |  | # INPUT PARAMS  : $offset, @offsets .. The offset and the set of | 
| 512 |  |  |  |  |  |  | #                                      offsets. | 
| 513 |  |  |  |  |  |  | # RETURN VALUES : 0 or 1. | 
| 514 |  |  |  |  |  |  | sub _isIn | 
| 515 |  |  |  |  |  |  | { | 
| 516 |  |  |  |  |  |  | my $op1; | 
| 517 |  |  |  |  |  |  | my @op2; | 
| 518 |  |  |  |  |  |  | my $line; | 
| 519 |  |  |  |  |  |  |  | 
| 520 |  |  |  |  |  |  |  | 
| 521 |  |  |  |  |  |  | $op1 = shift; | 
| 522 |  |  |  |  |  |  | @op2 = @_; | 
| 523 |  |  |  |  |  |  | $line = " ".join(" ", @op2)." "; | 
| 524 |  |  |  |  |  |  | if($line =~ / $op1 /) { | 
| 525 |  |  |  |  |  |  | return 1; | 
| 526 |  |  |  |  |  |  | } | 
| 527 |  |  |  |  |  |  | return 0; | 
| 528 |  |  |  |  |  |  | } | 
| 529 |  |  |  |  |  |  |  | 
| 530 |  |  |  |  |  |  |  | 
| 531 |  |  |  |  |  |  | # Recursive subroutine to check the existence of a Medium-Strong | 
| 532 |  |  |  |  |  |  | # relation between two synsets. | 
| 533 |  |  |  |  |  |  | # INPUT PARAMS  : $state, $distance, $chdir, $offset, $path, $endOffset | 
| 534 |  |  |  |  |  |  | #                 .. The state of the state machine. | 
| 535 |  |  |  |  |  |  | #                    Similarity (links) covered thus far. | 
| 536 |  |  |  |  |  |  | #                    Number of changes in direction thus far. | 
| 537 |  |  |  |  |  |  | #                    Current node. | 
| 538 |  |  |  |  |  |  | #                    Path so far. | 
| 539 |  |  |  |  |  |  | #                    Last offset. | 
| 540 |  |  |  |  |  |  | # RETURN VALUES : $weight .. weight of the path found. | 
| 541 |  |  |  |  |  |  | sub _medStrong | 
| 542 |  |  |  |  |  |  | { | 
| 543 |  |  |  |  |  |  | my $self; | 
| 544 |  |  |  |  |  |  | my $state; | 
| 545 |  |  |  |  |  |  | my $distance; | 
| 546 |  |  |  |  |  |  | my $chdir; | 
| 547 |  |  |  |  |  |  | my $from; | 
| 548 |  |  |  |  |  |  | my $path; | 
| 549 |  |  |  |  |  |  | my $endOffset; | 
| 550 |  |  |  |  |  |  | my $retT; | 
| 551 |  |  |  |  |  |  | my $retH; | 
| 552 |  |  |  |  |  |  | my $retU; | 
| 553 |  |  |  |  |  |  | my $retD; | 
| 554 |  |  |  |  |  |  | my $synset; | 
| 555 |  |  |  |  |  |  | my $maxVal; | 
| 556 |  |  |  |  |  |  | my @horiz; | 
| 557 |  |  |  |  |  |  | my @upward; | 
| 558 |  |  |  |  |  |  | my @downward; | 
| 559 |  |  |  |  |  |  |  | 
| 560 |  |  |  |  |  |  | $self = shift; | 
| 561 |  |  |  |  |  |  | $state = shift; | 
| 562 |  |  |  |  |  |  | $distance = shift; | 
| 563 |  |  |  |  |  |  | $chdir = shift; | 
| 564 |  |  |  |  |  |  | $from = shift; | 
| 565 |  |  |  |  |  |  | $path = shift; | 
| 566 |  |  |  |  |  |  | $endOffset = shift; | 
| 567 |  |  |  |  |  |  | if($from eq $endOffset && $distance > 1) | 
| 568 |  |  |  |  |  |  | { | 
| 569 |  |  |  |  |  |  | # [trace] | 
| 570 |  |  |  |  |  |  | if($self->{'trace'}) | 
| 571 |  |  |  |  |  |  | { | 
| 572 |  |  |  |  |  |  | $self->{'traceString'} .= "MedStrong relation path... \n"; | 
| 573 |  |  |  |  |  |  | while($path =~ /([0-9]+)([nvar]?)\s*(\[[DUH]\])?\s*/g) | 
| 574 |  |  |  |  |  |  | { | 
| 575 |  |  |  |  |  |  | $self->printSet($2, 'offset', $1); | 
| 576 |  |  |  |  |  |  | $self->{traceString} .= " $3 " if($3); | 
| 577 |  |  |  |  |  |  | } | 
| 578 |  |  |  |  |  |  | $self->{traceString} .= "\n"; | 
| 579 |  |  |  |  |  |  | } | 
| 580 |  |  |  |  |  |  | # [/trace] | 
| 581 |  |  |  |  |  |  | return 8 - $distance - $chdir; | 
| 582 |  |  |  |  |  |  | } | 
| 583 |  |  |  |  |  |  | if($distance >= 5) | 
| 584 |  |  |  |  |  |  | { | 
| 585 |  |  |  |  |  |  | return 0; | 
| 586 |  |  |  |  |  |  | } | 
| 587 |  |  |  |  |  |  | if($state == 0) | 
| 588 |  |  |  |  |  |  | { | 
| 589 |  |  |  |  |  |  | @horiz = &_getHorizontalOffsetsPOS($self->{'wn'}, $from); | 
| 590 |  |  |  |  |  |  | @upward = &_getUpwardOffsetsPOS($self->{'wn'}, $from); | 
| 591 |  |  |  |  |  |  | @downward = &_getDownwardOffsetsPOS($self->{'wn'}, $from); | 
| 592 |  |  |  |  |  |  | $retU = 0; | 
| 593 |  |  |  |  |  |  | foreach $synset (@upward) | 
| 594 |  |  |  |  |  |  | { | 
| 595 |  |  |  |  |  |  | $retT = $self->_medStrong(1, $distance+1, 0, $synset, $path." [U] ".$synset, $endOffset); | 
| 596 |  |  |  |  |  |  | $retU = $retT if($retT > $retU); | 
| 597 |  |  |  |  |  |  | } | 
| 598 |  |  |  |  |  |  | $retD = 0; | 
| 599 |  |  |  |  |  |  | foreach $synset (@downward) | 
| 600 |  |  |  |  |  |  | { | 
| 601 |  |  |  |  |  |  | $retT = $self->_medStrong(2, $distance+1, 0, $synset, $path." [D] ".$synset, $endOffset); | 
| 602 |  |  |  |  |  |  | $retD = $retT if($retT > $retD); | 
| 603 |  |  |  |  |  |  | } | 
| 604 |  |  |  |  |  |  | $retH = 0; | 
| 605 |  |  |  |  |  |  | foreach $synset (@horiz) | 
| 606 |  |  |  |  |  |  | { | 
| 607 |  |  |  |  |  |  | $retT = $self->_medStrong(3, $distance+1, 0, $synset, $path." [H] ".$synset, $endOffset); | 
| 608 |  |  |  |  |  |  | $retH = $retT if($retT > $retH); | 
| 609 |  |  |  |  |  |  | } | 
| 610 |  |  |  |  |  |  | return $retU if($retU > $retD && $retU > $retH); | 
| 611 |  |  |  |  |  |  | return $retD if($retD > $retH); | 
| 612 |  |  |  |  |  |  | return $retH; | 
| 613 |  |  |  |  |  |  | } | 
| 614 |  |  |  |  |  |  | if($state == 1) | 
| 615 |  |  |  |  |  |  | { | 
| 616 |  |  |  |  |  |  | @horiz = &_getHorizontalOffsetsPOS($self->{'wn'}, $from); | 
| 617 |  |  |  |  |  |  | @upward = &_getUpwardOffsetsPOS($self->{'wn'}, $from); | 
| 618 |  |  |  |  |  |  | @downward = &_getDownwardOffsetsPOS($self->{'wn'}, $from); | 
| 619 |  |  |  |  |  |  | $retU = 0; | 
| 620 |  |  |  |  |  |  | foreach $synset (@upward) | 
| 621 |  |  |  |  |  |  | { | 
| 622 |  |  |  |  |  |  | $retT = $self->_medStrong(1, $distance+1, 0, $synset, $path." [U] ".$synset, $endOffset); | 
| 623 |  |  |  |  |  |  | $retU = $retT if($retT > $retU); | 
| 624 |  |  |  |  |  |  | } | 
| 625 |  |  |  |  |  |  | $retD = 0; | 
| 626 |  |  |  |  |  |  | foreach $synset (@downward) | 
| 627 |  |  |  |  |  |  | { | 
| 628 |  |  |  |  |  |  | $retT = $self->_medStrong(4, $distance+1, 1, $synset, $path." [D] ".$synset, $endOffset); | 
| 629 |  |  |  |  |  |  | $retD = $retT if($retT > $retD); | 
| 630 |  |  |  |  |  |  | } | 
| 631 |  |  |  |  |  |  | $retH = 0; | 
| 632 |  |  |  |  |  |  | foreach $synset (@horiz) | 
| 633 |  |  |  |  |  |  | { | 
| 634 |  |  |  |  |  |  | $retT = $self->_medStrong(5, $distance+1, 1, $synset, $path." [H] ".$synset, $endOffset); | 
| 635 |  |  |  |  |  |  | $retH = $retT if($retT > $retH); | 
| 636 |  |  |  |  |  |  | } | 
| 637 |  |  |  |  |  |  | return $retU if($retU > $retD && $retU > $retH); | 
| 638 |  |  |  |  |  |  | return $retD if($retD > $retH); | 
| 639 |  |  |  |  |  |  | return $retH; | 
| 640 |  |  |  |  |  |  | } | 
| 641 |  |  |  |  |  |  | if($state == 2) | 
| 642 |  |  |  |  |  |  | { | 
| 643 |  |  |  |  |  |  | @horiz = &_getHorizontalOffsetsPOS($self->{'wn'}, $from); | 
| 644 |  |  |  |  |  |  | @downward = &_getDownwardOffsetsPOS($self->{'wn'}, $from); | 
| 645 |  |  |  |  |  |  | $retD = 0; | 
| 646 |  |  |  |  |  |  | foreach $synset (@downward) | 
| 647 |  |  |  |  |  |  | { | 
| 648 |  |  |  |  |  |  | $retT = $self->_medStrong(2, $distance+1, 0, $synset, $path." [D] ".$synset, $endOffset); | 
| 649 |  |  |  |  |  |  | $retD = $retT if($retT > $retD); | 
| 650 |  |  |  |  |  |  | } | 
| 651 |  |  |  |  |  |  | $retH = 0; | 
| 652 |  |  |  |  |  |  | foreach $synset (@horiz) | 
| 653 |  |  |  |  |  |  | { | 
| 654 |  |  |  |  |  |  | $retT = $self->_medStrong(6, $distance+1, 0, $synset, $path." [H] ".$synset, $endOffset); | 
| 655 |  |  |  |  |  |  | $retH = $retT if($retT > $retH); | 
| 656 |  |  |  |  |  |  | } | 
| 657 |  |  |  |  |  |  | return ($retD > $retH) ? $retD : $retH; | 
| 658 |  |  |  |  |  |  | } | 
| 659 |  |  |  |  |  |  | if($state == 3) | 
| 660 |  |  |  |  |  |  | { | 
| 661 |  |  |  |  |  |  | @horiz = &_getHorizontalOffsetsPOS($self->{'wn'}, $from); | 
| 662 |  |  |  |  |  |  | @downward = &_getDownwardOffsetsPOS($self->{'wn'}, $from); | 
| 663 |  |  |  |  |  |  | $retD = 0; | 
| 664 |  |  |  |  |  |  | foreach $synset (@downward) | 
| 665 |  |  |  |  |  |  | { | 
| 666 |  |  |  |  |  |  | $retT = $self->_medStrong(7, $distance+1, 0, $synset, $path." [D] ".$synset, $endOffset); | 
| 667 |  |  |  |  |  |  | $retD = $retT if($retT > $retD); | 
| 668 |  |  |  |  |  |  | } | 
| 669 |  |  |  |  |  |  | $retH = 0; | 
| 670 |  |  |  |  |  |  | foreach $synset (@horiz) | 
| 671 |  |  |  |  |  |  | { | 
| 672 |  |  |  |  |  |  | $retT = $self->_medStrong(3, $distance+1, 0, $synset, $path." [H] ".$synset, $endOffset); | 
| 673 |  |  |  |  |  |  | $retH = $retT if($retT > $retH); | 
| 674 |  |  |  |  |  |  | } | 
| 675 |  |  |  |  |  |  | return ($retD > $retH) ? $retD : $retH; | 
| 676 |  |  |  |  |  |  | } | 
| 677 |  |  |  |  |  |  | if($state == 4) | 
| 678 |  |  |  |  |  |  | { | 
| 679 |  |  |  |  |  |  | @downward = &_getDownwardOffsetsPOS($self->{'wn'}, $from); | 
| 680 |  |  |  |  |  |  | $retD = 0; | 
| 681 |  |  |  |  |  |  | foreach $synset (@downward) | 
| 682 |  |  |  |  |  |  | { | 
| 683 |  |  |  |  |  |  | $retT = $self->_medStrong(4, $distance+1, 1, $synset, $path." [D] ".$synset, $endOffset); | 
| 684 |  |  |  |  |  |  | $retD = $retT if($retT > $retD); | 
| 685 |  |  |  |  |  |  | } | 
| 686 |  |  |  |  |  |  | return $retD; | 
| 687 |  |  |  |  |  |  | } | 
| 688 |  |  |  |  |  |  | if($state == 5) | 
| 689 |  |  |  |  |  |  | { | 
| 690 |  |  |  |  |  |  | @horiz = &_getHorizontalOffsetsPOS($self->{'wn'}, $from); | 
| 691 |  |  |  |  |  |  | @downward = &_getDownwardOffsetsPOS($self->{'wn'}, $from); | 
| 692 |  |  |  |  |  |  | $retD = 0; | 
| 693 |  |  |  |  |  |  | foreach $synset (@downward) | 
| 694 |  |  |  |  |  |  | { | 
| 695 |  |  |  |  |  |  | $retT = $self->_medStrong(4, $distance+1, 2, $synset, $path." [D] ".$synset, $endOffset); | 
| 696 |  |  |  |  |  |  | $retD = $retT if($retT > $retD); | 
| 697 |  |  |  |  |  |  | } | 
| 698 |  |  |  |  |  |  | $retH = 0; | 
| 699 |  |  |  |  |  |  | foreach $synset (@horiz) | 
| 700 |  |  |  |  |  |  | { | 
| 701 |  |  |  |  |  |  | $retT = $self->_medStrong(5, $distance+1, 1, $synset, $path." [H] ".$synset, $endOffset); | 
| 702 |  |  |  |  |  |  | $retH = $retT if($retT > $retH); | 
| 703 |  |  |  |  |  |  | } | 
| 704 |  |  |  |  |  |  | return ($retD > $retH) ? $retD : $retH; | 
| 705 |  |  |  |  |  |  | } | 
| 706 |  |  |  |  |  |  | if($state == 6) | 
| 707 |  |  |  |  |  |  | { | 
| 708 |  |  |  |  |  |  | @horiz = &_getHorizontalOffsetsPOS($self->{'wn'}, $from); | 
| 709 |  |  |  |  |  |  | $retH = 0; | 
| 710 |  |  |  |  |  |  | foreach $synset (@horiz) | 
| 711 |  |  |  |  |  |  | { | 
| 712 |  |  |  |  |  |  | $retT = $self->_medStrong(6, $distance+1, 1, $synset, $path." [H] ".$synset, $endOffset); | 
| 713 |  |  |  |  |  |  | $retH = $retT if($retT > $retH); | 
| 714 |  |  |  |  |  |  | } | 
| 715 |  |  |  |  |  |  | return $retH; | 
| 716 |  |  |  |  |  |  | } | 
| 717 |  |  |  |  |  |  | if($state == 7) | 
| 718 |  |  |  |  |  |  | { | 
| 719 |  |  |  |  |  |  | @downward = &_getDownwardOffsetsPOS($self->{'wn'}, $from); | 
| 720 |  |  |  |  |  |  | $retD = 0; | 
| 721 |  |  |  |  |  |  | foreach $synset (@downward) | 
| 722 |  |  |  |  |  |  | { | 
| 723 |  |  |  |  |  |  | $retT = $self->_medStrong(7, $distance+1, 1, $synset, $path." [D] ".$synset, $endOffset); | 
| 724 |  |  |  |  |  |  | $retD = $retT if($retT > $retD); | 
| 725 |  |  |  |  |  |  | } | 
| 726 |  |  |  |  |  |  | return $retD; | 
| 727 |  |  |  |  |  |  | } | 
| 728 |  |  |  |  |  |  | return 0; | 
| 729 |  |  |  |  |  |  | } | 
| 730 |  |  |  |  |  |  |  | 
| 731 |  |  |  |  |  |  | 1; | 
| 732 |  |  |  |  |  |  |  | 
| 733 |  |  |  |  |  |  | __END__ |