File Coverage

blib/lib/Treex/Tool/Parser/MSTperl/ModelAdditional.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             package Treex::Tool::Parser::MSTperl::ModelAdditional;
2             {
3             $Treex::Tool::Parser::MSTperl::ModelAdditional::VERSION = '0.11949';
4             }
5              
6 1     1   1804 use Data::Dumper;
  1         2  
  1         70  
7 1     1   6 use autodie;
  1         2  
  1         8  
8 1     1   5557 use Moose;
  0            
  0            
9             use Carp;
10              
11             require File::Temp;
12             use File::Temp ();
13             use File::Temp qw/ :seekable /;
14              
15             has config => (
16             isa => 'Treex::Tool::Parser::MSTperl::Config',
17             is => 'ro',
18             required => '1',
19             );
20              
21             has model => (
22             is => 'rw',
23             isa => 'HashRef',
24             default => sub { {} },
25             );
26              
27             has model_file => (
28             is => 'ro',
29             isa => 'Str',
30             default => '',
31             );
32              
33             has model_format => (
34             is => 'ro',
35             isa => 'Str',
36             default => 'tsv',
37             );
38              
39             has 'buckets' => (
40             is => 'rw',
41             isa => 'Maybe[ArrayRef[Int]]',
42             default => undef,
43             trigger => \&_buckets_set,
44             );
45              
46             # sets value2bucket, maxBucket and minBucket
47             sub _buckets_set {
48             my ( $self, $buckets ) = @_;
49              
50             if ( !defined $buckets ) {
51             return;
52             }
53              
54             my %value2bucket;
55             $value2bucket{'?'} = '?';
56              
57             # find maximal and minimal bucket & partly fill %value2bucket
58             my $minBucket = -1000;
59             my $maxBucket = 1000;
60             foreach my $bucket ( @{$buckets} ) {
61             if ( $value2bucket{$bucket} ) {
62             warn "Bucket '$bucket' is defined more than once; "
63             . "disregarding its later definitions.\n";
64             }
65             elsif ( $bucket > 0 ) {
66             croak "MSTperl config file error: "
67             . "Error on bucket '$bucket' - "
68             . "buckets must be negative integers.";
69             }
70             else {
71             $value2bucket{$bucket} = $bucket;
72             if ( $bucket > $maxBucket ) {
73             $maxBucket = $bucket;
74             }
75             elsif ( $bucket < $minBucket ) {
76             $minBucket = $bucket;
77             }
78             }
79             }
80              
81             # set maxBucket and minBucket
82             $self->maxBucket($maxBucket);
83             $self->minBucket($minBucket);
84              
85             # fill %value2bucket from minBucket to maxBucket
86             my $lastBucket = $minBucket;
87             for ( my $value = $minBucket + 1; $value < $maxBucket; $value++ ) {
88             if ( defined $value2bucket{$value} ) {
89              
90             # the value defines a bucket
91             $lastBucket = $value2bucket{$value};
92             }
93             else {
94              
95             # the value falls into the highest lower bucket
96             $value2bucket{$value} = $lastBucket;
97             }
98             }
99             $self->value2bucket( \%value2bucket );
100              
101             return;
102             }
103              
104             has 'value2bucket' => (
105             is => 'rw',
106             isa => 'HashRef',
107             default => sub { { '?' => '?' } },
108             );
109              
110             # if mapping is not found in the hash, maxBucket or minBucket is used
111             # -17 is the default as it seems to be the most frequent value
112             # (if no buckets are set. always -17 or '?' are returned)
113              
114             # any higher value falls into this bucket
115             has 'maxBucket' => (
116             isa => 'Int',
117             is => 'rw',
118             default => '-17',
119             );
120              
121             # any lower value falls into this bucket
122             has 'minBucket' => (
123             isa => 'Int',
124             is => 'rw',
125             default => '-17',
126             );
127              
128             sub load {
129              
130             my ($self) = @_;
131              
132             if ( $self->config->DEBUG >= 1 ) {
133             print "Loading additional model from '" . $self->model_file . "...\n";
134             }
135              
136             my $result = undef;
137             if ( $self->model_format eq 'tsv' ) {
138             $result = $self->load_tsv( $self->model_file );
139             }
140              
141             # probably TODO
142             # } elsif ( $self->model_format eq 'tsv.gz' ) {
143             # my $tmpfile = File::Temp->new( UNLINK => 1 );
144             # system "gunzip -c $filename > $tmpfile";
145             # $filename = $tmpfile->filename;
146             # }
147             else {
148             croak "Model format " . $self->model_format . " is not supported!";
149             }
150              
151             if ($result) {
152             if ( $self->config->DEBUG >= 1 ) {
153             print "Additional model loaded.\n";
154             }
155             return 1;
156             }
157             else {
158             croak "MSTperl parser error: additional model file data error!";
159             }
160             }
161              
162             sub load_tsv {
163              
164             # (Str $filename)
165             my ( $self, $filename ) = @_;
166              
167             {
168             open my $file, '<:encoding(UTF-8)', $filename;
169             my $line;
170             while ( $line = <$file> ) {
171             chomp $line;
172             my ( $child, $parent, $value ) = split /\t/, $line;
173             $self->model->{$child}->{$parent} = $value;
174             }
175             close $file;
176             }
177              
178             return 1;
179             }
180              
181             sub get_value {
182             my ( $self, $child, $parent ) = @_;
183              
184             my $value = $self->model->{$child}->{$parent};
185             if ( !defined $value ) {
186             $value = '?';
187             }
188              
189             return $value;
190             }
191              
192             sub get_rounded_value {
193             my ( $self, $child, $parent, $rounding ) = @_;
194              
195             my $value = $self->model->{$child}->{$parent};
196             if ( defined $value ) {
197              
198             # get the rounding coefficient
199             if ( !defined $rounding ) {
200             $rounding = 0;
201             }
202             my $coef = 1;
203             for ( my $i = 0; $i < $rounding; $i++ ) {
204             $coef *= 10;
205             }
206              
207             # get the value
208             $value = int( $value * $coef ) / $coef;
209             }
210             else {
211             $value = '?';
212             }
213              
214             return $value;
215             }
216              
217             sub get_bucketed_value {
218             my ( $self, $child, $parent ) = @_;
219              
220             my $value = $self->get_rounded_value( $child, $parent );
221             my $bucket = $self->value2bucket->{$value};
222             if ( !defined $bucket ) {
223             if ( $value <= $self->minBucket ) {
224             $bucket = $self->minBucket;
225             }
226             else {
227              
228             # assert $value > $self->maxBucket
229             $bucket = $self->maxBucket;
230             }
231             }
232              
233             return $bucket;
234             }
235              
236             1;
237              
238             __END__
239              
240             =pod
241              
242             =encoding utf-8
243              
244             =head1 NAME
245              
246             Treex::Tool::Parser::MSTperl::ModelAdditional
247              
248             =head1 VERSION
249              
250             version 0.11949
251              
252             =head1 DESCRIPTION
253              
254             A model containing edge PMI, i.e.
255             PMI[c,p] = log #[c,p] / #([c,*])#([*,p])
256             where c=child and p=parent
257              
258             =head1 FIELDS
259              
260             =head2 Public Fields
261              
262             =over 4
263              
264             =item model_file
265              
266             The file containing the model,
267             i.e. a TSV file in the format
268             child[tab]parent[tab]PMI
269              
270             =item model_format
271              
272             Currently only tsv is supported.
273             TODO support tsv.gz, probably also Data Dumper model.
274              
275             =item buckets
276              
277             (A reference to) an array of buckets that PMI is bucketed into
278             (negative integers, do not have to be sorted).
279             The PMI is first ceiled,
280             and then it falls into the nearest lower bucket;
281             (if there is no such bucket, falls into the lowest one).
282              
283             =back
284              
285             =head2 Internal Fields
286              
287             =over 4
288              
289             =item model
290              
291             In-memory representation of the model file,
292             in the format model->{child}->{parent} = PMI.
293              
294             =item minBucket
295              
296             The lowest bucket (a bin for all PMIs lower than that).
297              
298             =item maxBucket
299              
300             The highest bucket (a bin for all PMIs higher than that).
301              
302             =item value2bucket
303              
304             Provides fast conversion of ceiled PMIs
305             that are between minBucket and maxBucket
306             to buckets.
307              
308             =back
309              
310             =head1 METHODS
311              
312             =over 4
313              
314             =item load
315              
316             =item get_value($child, $parent)
317              
318             Returns the real PMI, i.e. a negative float
319             (there are hundreds of thousands of possible values).
320              
321             Returns '?' if PMI is unknown.
322              
323             =item get_rounded_value($child, $parent)
324              
325             Returns ceiled PMI, i.e. the integer part of the real PMI
326             (there are about 30 possible values).
327              
328             Returns '?' if PMI is unknown.
329              
330             =item get_bucketed_value($child, $parent)
331              
332             Returns the nearest bucket that is lower or equal
333             to the ceiled value of the PMI,
334             or the lowest existing bucket if the value is even lower.
335              
336             Returns '?' if PMI is unknown.
337              
338             =back
339              
340             =head1 AUTHORS
341              
342             Rudolf Rosa <rosa@ufal.mff.cuni.cz>
343              
344             =head1 COPYRIGHT AND LICENSE
345              
346             Copyright © 2012 by Institute of Formal and Applied Linguistics, Charles
347             University in Prague
348              
349             This module is free software; you can redistribute it and/or modify it under
350             the same terms as Perl itself.