File Coverage

blib/lib/Lingua/PT/Actants.pm
Criterion Covered Total %
statement 83 211 39.3
branch 21 44 47.7
condition 1 3 33.3
subroutine 11 23 47.8
pod 6 11 54.5
total 122 292 41.7


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.04';
4 3     3   41421 use strict;
  3         3  
  3         76  
5 3     3   9 use warnings;
  3         4  
  3         75  
6              
7 3     3   1503 use Storable qw/dclone/;
  3         7204  
  3         5392  
8              
9             sub new {
10 1     1 1 1329 my ($class, %args) = @_;
11 1         2 my $self = bless({ }, $class);
12              
13 1 50       4 if (exists($args{conll})) {
14 1         6 $self->{conll} = $args{conll};
15             }
16             else {
17             # FIXME PLN::PT
18             }
19              
20             # initial data -- conll format
21 1         4 $self->{data} = $self->_conll2data($self->{conll});
22              
23             # build a tree from the list of deps
24 1         5 $self->{tree} = $self->_data2tree($self->{data});
25              
26             # split tree into one tree per verb+conj
27 1         82 my $tree = dclone($self->{tree});
28 1         4 $self->{deps} = [ reverse $self->_tree2deps($tree) ];
29              
30             # simplify each dep tree verbs
31 1         2 my @deps = @{dclone($self->{deps})};
  1         33  
32 1         2 $self->{simple} = [ map {$self->_tree2simple($_)} @deps ];
  1         4  
33              
34 1         4 return $self;
35             }
36              
37             # conll -> data
38             sub _conll2data {
39 1     1   2 my ($self, $conll) = @_;
40              
41 1         3 my @data;
42 1         28 foreach my $line (split /\n/, $conll) {
43 5 50       17 next if $line =~ m/^\s*$/;
44              
45 5         37 my @l = split /\s+/, $line;
46 5         26 push @data, {
47             id=>$l[0], form=>$l[1], pos=>$l[3], dep=>$l[6], rule=>$l[7]
48             };
49             }
50              
51 1         5 return [@data];
52             }
53              
54             # data -> tree
55             sub _data2tree {
56 1     1   1 my ($self, $data) = @_;
57              
58 1         2 my $root;
59 1         3 foreach (@$data) {
60 5 100       12 $root = $_ if $_->{rule} eq 'ROOT';
61             }
62              
63 1         3 $root = $self->_node($root, $data);
64              
65 1         3 return $root;
66             }
67              
68             sub _node {
69 5     5   5 my ($self, $node, $data) = @_;
70              
71 5         5 my @child = ();
72 5         6 foreach (@$data) {
73 25 100       52 push @child, $self->_node($_, $data) if ($_->{dep} == $node->{id});
74             }
75 5         8 $node->{child} = [@child];
76              
77 5         8 return $node;
78             }
79              
80             # tree -> deps
81             sub _tree2deps {
82 1     1   3 my ($self, $node, @deps) = @_;
83              
84 1 50       4 if ($node->{pos} eq 'VERB') {
85 1         2 my @child = ();
86 1         1 foreach my $c (@{ $node->{child} }) {
  1         3  
87 3 50 33     7 if ($c->{pos} eq 'VERB' and $c->{rule} eq 'conj') {
88 0         0 push @deps, $self->_tree2deps($c, @deps);
89             }
90             else {
91 3         4 push @child, $c;
92             }
93             }
94 1         3 $node->{child} = [@child];
95             }
96 1         2 push @deps, $node;
97              
98 1         3 return @deps;
99             }
100              
101             # tree -> simple tree
102             # FIXME make recursive
103             sub _tree2simple {
104 1     1   1 my ($self, $node) = @_;
105              
106 1 50       4 if ($node->{pos} eq 'VERB') {
107 1         2 my $found = undef;
108 1         1 foreach my $c (@{ $node->{child} }) {
  1         2  
109 3 50       6 $found = $c if ($c->{pos} eq 'VERB');
110             }
111 1 50       12 if ($found) {
112 0         0 my @child;
113 0         0 foreach (@{ $node->{child} }, @{$found->{child}}) {
  0         0  
  0         0  
114 0 0       0 push @child, $_ unless $_->{id} == $found->{id};
115             }
116 0         0 $found->{child} = [@child];
117 0         0 $node = $found;
118             }
119             }
120              
121 1         4 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 1     1 1 377 my ($self) = @_;
205 1         1 my $data = $self->{simple};
206 1         2 my @final;
207              
208 1         2 foreach my $tree (@$data) {
209 1         36 my $verb = dclone($tree);
210 1         4 delete $verb->{child};
211              
212 1         2 my @cores = ();
213 1         1 my @children = @{$tree->{child}};
  1         3  
214              
215 1         2 foreach my $i (@children) {
216 4 100       7 if ($self->_score($i) > 0) {
217 2         2 push @cores, $i;
218             }
219 4 50       7 push @children, @{$i->{child}} if $i->{child};
  4         5  
220             }
221 1         6 push @final, { verb=>$verb, cores=>[@cores] };
222             }
223              
224 1         2 $self->{cores} = [@final];
225              
226 1         2 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 0     0 0 0 my ($self, @cores) = @_;
246 0 0       0 @cores = @{$self->{cores}} unless @cores;
  0         0  
247              
248 0         0 my @syns;
249 0         0 foreach (@cores) {
250 0         0 my $verb = $_->{verb};
251 0         0 my @cs = @{ $_->{cores} };
  0         0  
252 0         0 my @curr;
253              
254 0         0 foreach my $c (@cs) {
255 0         0 my @tokens = ($c);
256 0 0       0 my @child = exists($c->{child}) ? @{$c->{child}} : ();
  0         0  
257 0         0 foreach (@child) {
258 0 0       0 unless (_is_core($_, @cs)) {
259 0         0 push @tokens, $_;
260 0         0 push @child, @{$_->{child}};
  0         0  
261             }
262             }
263 0         0 @tokens = sort {$a->{id} <=> $b->{id}} @tokens;
  0         0  
264 0         0 delete($_->{child}) foreach (@tokens);
265 0         0 push @curr, [@tokens];
266             }
267              
268 0         0 push @syns, { verb=>$verb, syns=>[@curr] };
269             }
270              
271 0         0 return @syns;
272             }
273              
274             sub _is_core {
275 0     0   0 my ($c, @cs) = @_;
276              
277 0         0 foreach (@cs) {
278 0 0       0 return 1 if $_->{id} == $c->{id};
279             }
280              
281 0         0 return 0;
282             }
283              
284             sub _score {
285 4     4   4 my ($self, $token) = @_;
286 4         4 my $score = 0;
287              
288             # token POS component
289 4 100       19 $score += 8 if ($token->{pos} =~ m/^(noun|propn|prop)$/i);
290 4 100       12 $score += -10 if ($token->{pos} =~ m/^(punct)$/i);
291              
292             # token rule component
293 4 100       8 $score += 4 if ($token->{rule} =~ m/^(nsubj|nsubjpass)$/i);
294 4 50       9 $score += 2 if ($token->{rule} =~ m/^(nmod)$/i);
295              
296 4         9 return $score;
297             }
298              
299             sub syns_simple {
300 0     0 0   my ($self, @syns) = @_;
301              
302 0           my @simple;
303 0           foreach (@syns) {
304 0           my $verb = $_->{verb}->{form};
305 0           my @curr;
306 0           foreach my $s (@{$_->{syns}}) {
  0            
307 0           push @curr, join(' ', map {$_->{form}} @$s);
  0            
308             };
309            
310 0           push @simple, { $verb => [@curr] };
311             }
312              
313 0           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__