File Coverage

blib/lib/Lingua/PT/Actants.pm
Criterion Covered Total %
statement 128 211 60.6
branch 29 44 65.9
condition 2 3 66.6
subroutine 14 23 60.8
pod 6 11 54.5
total 179 292 61.3


line stmt bran cond sub pod time code
1             package Lingua::PT::Actants;
2             # ABSTRACT: compute verb actants for Portuguese
3             $Lingua::PT::Actants::VERSION = '0.05';
4 3     3   45928 use strict;
  3         7  
  3         89  
5 3     3   14 use warnings;
  3         4  
  3         105  
6              
7 3     3   1903 use Storable qw/dclone/;
  3         8905  
  3         7025  
8              
9             sub new {
10 4     4 1 6284 my ($class, %args) = @_;
11 4         12 my $self = bless({ }, $class);
12              
13 4 50       14 if (exists($args{conll})) {
14 4         18 $self->{conll} = $args{conll};
15             }
16             else {
17             # FIXME PLN::PT
18             }
19              
20             # initial data -- conll format
21 4         16 $self->{data} = $self->_conll2data($self->{conll});
22              
23             # build a tree from the list of deps
24 4         11 $self->{tree} = $self->_data2tree($self->{data});
25              
26             # split tree into one tree per verb+conj
27 4         288 my $tree = dclone($self->{tree});
28 4         13 $self->{deps} = [ reverse $self->_tree2deps($tree) ];
29              
30             # simplify each dep tree verbs
31 4         6 my @deps = @{dclone($self->{deps})};
  4         165  
32 4         10 $self->{simple} = [ map {$self->_tree2simple($_)} @deps ];
  4         12  
33              
34 4         20 return $self;
35             }
36              
37             # conll -> data
38             sub _conll2data {
39 4     4   11 my ($self, $conll) = @_;
40              
41 4         7 my @data;
42 4         48 foreach my $line (split /\n/, $conll) {
43 26 50       78 next if $line =~ m/^\s*$/;
44              
45 26         190 my @l = split /\s+/, $line;
46 26         141 push @data, {
47             id=>$l[0], form=>$l[1], pos=>$l[3], dep=>$l[6], rule=>$l[7]
48             };
49             }
50              
51 4         18 return [@data];
52             }
53              
54             # data -> tree
55             sub _data2tree {
56 4     4   7 my ($self, $data) = @_;
57              
58 4         5 my $root;
59 4         9 foreach (@$data) {
60 26 100       56 $root = $_ if $_->{rule} eq 'ROOT';
61             }
62              
63 4         10 $root = $self->_node($root, $data);
64              
65 4         9 return $root;
66             }
67              
68             sub _node {
69 26     26   28 my ($self, $node, $data) = @_;
70              
71 26         24 my @child = ();
72 26         29 foreach (@$data) {
73 174 100       367 push @child, $self->_node($_, $data) if ($_->{dep} == $node->{id});
74             }
75 26         41 $node->{child} = [@child];
76              
77 26         42 return $node;
78             }
79              
80             # tree -> deps
81             sub _tree2deps {
82 4     4   8 my ($self, $node, @deps) = @_;
83              
84 4 50       15 if ($node->{pos} eq 'VERB') {
85 4         4 my @child = ();
86 4         8 foreach my $c (@{ $node->{child} }) {
  4         10  
87 13 50 66     40 if ($c->{pos} eq 'VERB' and $c->{rule} eq 'conj') {
88 0         0 push @deps, $self->_tree2deps($c, @deps);
89             }
90             else {
91 13         22 push @child, $c;
92             }
93             }
94 4         11 $node->{child} = [@child];
95             }
96 4         8 push @deps, $node;
97              
98 4         13 return @deps;
99             }
100              
101             # tree -> simple tree
102             # FIXME make recursive
103             sub _tree2simple {
104 4     4   5 my ($self, $node) = @_;
105              
106 4 50       14 if ($node->{pos} eq 'VERB') {
107 4         7 my $found = undef;
108 4         5 foreach my $c (@{ $node->{child} }) {
  4         10  
109 13 100       27 $found = $c if ($c->{pos} eq 'VERB');
110             }
111 4 100       36 if ($found) {
112 2         3 my @child;
113 2         2 foreach (@{ $node->{child} }, @{$found->{child}}) {
  2         4  
  2         4  
114 9 100       25 push @child, $_ unless $_->{id} == $found->{id};
115             }
116 2         5 $found->{child} = [@child];
117 2         5 $node = $found;
118             }
119             }
120              
121 4         16 return $node;
122             }
123              
124             sub tree2dot {
125 0     0 0 0 my ($self, $tree) = @_;
126              
127 0         0 my $data = $self->{$tree};
128 0         0 my @graphs = ();
129 0 0       0 if (ref($data) eq 'ARRAY') { push @graphs, @$data; }
  0         0  
130 0         0 else { push @graphs, $data; }
131              
132 0         0 my $dot = "digraph G {\ncharset= \"UTF-8\";\n";
133 0         0 foreach (@graphs) {
134 0         0 my $rand = int(rand(1000));
135 0         0 $dot .= " subgraph G_$rand {\n";
136 0         0 $dot .= join("\n", $self->_deps2nodes($rand, $_));
137 0         0 $dot .= join("\n", $self->_deps2edges($rand, $_));
138 0         0 $dot .= "\n }\n";
139             }
140 0         0 $dot .= "\n}\n";
141             }
142              
143             sub _deps2nodes {
144 0     0   0 my ($self, $prefix, $node) = @_;
145 0         0 my @lines;
146              
147 0         0 push @lines, " node [label=\"$node->{form}\"] N_${prefix}_$node->{id};";
148 0         0 foreach (@{$node->{child}}) {
  0         0  
149 0         0 push @lines, $self->_deps2nodes($prefix, $_);
150             }
151              
152 0         0 return @lines;
153             }
154              
155             sub _deps2edges {
156 0     0   0 my ($self, $prefix, $node) = @_;
157 0         0 my @lines;
158              
159 0         0 foreach (@{$node->{child}}) {
  0         0  
160 0         0 push @lines, " N_${prefix}_$node->{id} -> N_${prefix}_$_->{id} [label=\"$_->{rule}\"];";
161 0         0 push @lines, $self->_deps2edges($prefix, $_);
162             }
163              
164 0         0 return @lines;
165             }
166              
167             sub cores2dot {
168 0     0 0 0 my ($self, @cores) = @_;
169              
170 0         0 my $dot = "digraph G {\ncharset= \"UTF-8\";\n";
171 0         0 foreach my $core (@cores) {
172 0         0 my $rand = int(rand(1000));
173 0         0 $dot .= " subgraph G_$rand {\n";
174 0         0 foreach ($core->{verb}, @{$core->{cores}}) {
  0         0  
175 0         0 $dot .= " node [label=\"$_->{form}\"] N_$_->{id};";
176             }
177 0         0 foreach (@{$core->{cores}}) {
  0         0  
178 0         0 $dot .= " N_$core->{verb}->{id} -> N_$_->{id};\n";
179             }
180 0         0 $dot .= "\n }\n";
181             }
182 0         0 $dot .= "\n}\n";
183              
184 0         0 return $dot;
185             }
186              
187             sub text {
188 0     0 1 0 my ($self) = @_;
189              
190 0         0 return join(' ', map {$_->{form}} @{$self->{data}});
  0         0  
  0         0  
191             }
192              
193             sub actants {
194 0     0 1 0 my ($self, %args) = @_;
195              
196 0         0 my @cores = $self->acts_cores;
197 0         0 my @syns = $self->acts_syns(@cores);
198              
199 0         0 return ([@cores], [@syns]);
200             }
201              
202             # compute actant cores
203             sub acts_cores {
204 4     4 1 502 my ($self) = @_;
205 4         6 my $data = $self->{simple};
206 4         5 my @final;
207              
208 4         9 foreach my $tree (@$data) {
209 4         141 my $verb = dclone($tree);
210 4         18 delete $verb->{child};
211              
212 4         8 my @cores = ();
213 4         5 my @children = @{$tree->{child}};
  4         9  
214              
215 4         7 foreach my $i (@children) {
216 20 100       31 if ($self->_score($i) > 0) {
217 8         7 push @cores, $i;
218             }
219 20 50       40 push @children, @{$i->{child}} if $i->{child};
  20         28  
220             }
221 4         22 push @final, { verb=>$verb, cores=>[@cores] };
222             }
223              
224 4         8 $self->{cores} = [@final];
225              
226 4         14 return @final;
227             }
228              
229             sub cores_simple {
230 0     0 0 0 my ($self, @cores) = @_;
231 0 0       0 @cores = @{$self->{cores}} unless @cores;
  0         0  
232              
233 0         0 my @simple;
234 0         0 foreach (@cores) {
235 0         0 my $verb = $_->{verb}->{form};
236 0         0 my @cs = @{$_->{cores}};
  0         0  
237 0         0 @cs = map {$_->{form}} @cs;
  0         0  
238 0         0 push @simple, { $verb => [@cs] };
239             }
240              
241 0         0 return @simple;
242             }
243              
244             sub acts_syns {
245 3     3 0 3930 my ($self, @cores) = @_;
246 3 50       7 @cores = @{$self->{cores}} unless @cores;
  0         0  
247              
248 3         3 my @syns;
249 3         6 foreach (@cores) {
250 3         3 my $verb = $_->{verb};
251 3         3 my @cs = @{ $_->{cores} };
  3         5  
252 3         4 my @curr;
253              
254 3         3 foreach my $c (@cs) {
255 6         6 my @tokens = ($c);
256 6 50       48 my @child = exists($c->{child}) ? @{$c->{child}} : ();
  6         9  
257 6         7 foreach (@child) {
258 6 50       8 unless (_is_core($_, @cs)) {
259 6         6 push @tokens, $_;
260 6         3 push @child, @{$_->{child}};
  6         10  
261             }
262             }
263 6         13 @tokens = sort {$a->{id} <=> $b->{id}} @tokens;
  6         11  
264 6         14 delete($_->{child}) foreach (@tokens);
265 6         12 push @curr, [@tokens];
266             }
267              
268 3         9 push @syns, { verb=>$verb, syns=>[@curr] };
269             }
270              
271 3         7 return @syns;
272             }
273              
274             sub _is_core {
275 6     6   8 my ($c, @cs) = @_;
276              
277 6         6 foreach (@cs) {
278 12 50       27 return 1 if $_->{id} == $c->{id};
279             }
280              
281 6         13 return 0;
282             }
283              
284             sub _score {
285 20     20   19 my ($self, $token) = @_;
286 20         15 my $score = 0;
287              
288             # token POS component
289 20 100       73 $score += 8 if ($token->{pos} =~ m/^(noun|propn|prop)$/i);
290 20 100       45 $score += -10 if ($token->{pos} =~ m/^(punct)$/i);
291              
292             # token rule component
293 20 100       52 $score += 4 if ($token->{rule} =~ m/^(nsubj|nsubjpass)$/i);
294 20 50       40 $score += 2 if ($token->{rule} =~ m/^(nmod)$/i);
295              
296 20         38 return $score;
297             }
298              
299             sub syns_simple {
300 3     3 0 10 my ($self, @syns) = @_;
301              
302 3         3 my @simple;
303 3         4 foreach (@syns) {
304 3         5 my $verb = $_->{verb}->{form};
305 3         2 my @curr;
306 3         2 foreach my $s (@{$_->{syns}}) {
  3         5  
307 6         9 push @curr, join(' ', map {$_->{form}} @$s);
  12         24  
308             };
309            
310 3         9 push @simple, { $verb => [@curr] };
311             }
312              
313 3         6 return @simple;
314             }
315              
316             sub pp_acts_cores {
317 0     0 1   my ($self, @cores) = @_;
318              
319 0           my $r = "# Actants syntagma cores\n";
320 0           foreach (@cores) {
321 0           my ($verb, @tokens) = ($_->{verb}, @{$_->{cores}} );
  0            
322              
323 0           $r .= " Verb: $verb->{form}\n";
324 0           foreach (@tokens) {
325 0           $r .= sprintf " = %s\n", $_->{form};
326             }
327             }
328              
329 0           return $r;
330             }
331              
332             sub pp_acts_syntagmas {
333 0     0 1   my ($self, @syns) = @_;
334              
335 0           my $r = "# Actants syntagmas\n";
336 0           foreach (@syns) {
337 0           my ($verb, @list) = ($_->{verb}, @{ $_->{syns} });
  0            
338              
339 0           $r .= " Verb: $verb->{form}\n";
340 0           foreach (@list) {
341 0           $r .= sprintf " = %s\n", join(' ', map {$_->{form}} @$_);
  0            
342             }
343             }
344              
345 0           return $r;
346             }
347              
348             1;
349              
350             __END__