File Coverage

blib/lib/Math/PartialOrder/CEnum.pm
Criterion Covered Total %
statement 86 193 44.5
branch 16 76 21.0
condition 9 93 9.6
subroutine 12 17 70.5
pod 10 10 100.0
total 133 389 34.1


line stmt bran cond sub pod time code
1             # -*- Mode: Perl -*-
2              
3             #
4             # Copyright (c) 2001, Bryan Jurish. All rights reserved.
5             #
6             # This package is free software. You may redistribute it
7             # and/or modify it under the same terms as Perl itself.
8             #
9              
10             ###############################################################
11             #
12             # File: Math::PartialOrder::CEnum.pm
13             # Author: Bryan Jurish
14             #
15             # Description: QuD Hierarchy class using
16             # Bit::Vector objects to manipulate hierarchy
17             # information, internal storage as 'Enum'-type
18             # strings (compiling version)
19             #
20             ###############################################################
21              
22             package Math::PartialOrder::CEnum;
23             # System modules
24 7     7   7754 use Carp;
  7         29  
  7         572  
25             #require Exporter;
26             # 3rd party exstensions
27             # user extension modules
28 7     7   47 use Math::PartialOrder::CMasked qw(:bincompat :bvutils :enumutils);
  7         12  
  7         21243  
29             @ISA = qw(Math::PartialOrder::CMasked);
30             #@EXPORT = qw();
31             #@EXPORT_OK = qw();
32             #%EXPORT_TAGS = (
33             # );
34              
35             our $VERSION = 0.01;
36              
37              
38             ###############################################################
39             # Initialization
40             # + object structure:
41             # [
42             # --- inherited ---
43             # indices => { Type0 => Index0, ... }
44             # types => [ Type0, Type1, ... ]
45             # root => scalar type-name
46             # parents => [ Type0Parents, Type1Parents, ... ]
47             # children => [ Type0Children, Type1Children, ... ]
48             # attributes => [ { attr1.1 => val1.1, ... }, ... ]
49             # removed => [ FirstFreeIndex, SecondFreeIndex, ... ]
50             # vectors => [ Bit::Vector0, Bit::Vector1 ]
51             # compiled => scalar boolean
52             # hattributes => { a1 => v1, ... }
53             # --- overriden ---
54             # ancestors => [ Type0Ancs, Type1Ancs, ... ] # Ancs are Enum-strings!
55             # descendants => [ Type0Dscs, Type1Dscs, ... ] # Dscs are Enum-strings!
56             # ]
57             ###############################################################
58              
59             #----------------------------------------------------------------------
60             # new({root=>$r}) : inherited from CMasked
61              
62              
63              
64             #--------------------------------------------------------------
65             # $bool = $h->compile();
66             sub compile ($) {
67 5     5 1 11 my $h = shift;
68 5         38 my $rv = $h->SUPER::compile();
69 5 50       19 return $rv unless ($rv);
70             # compact ancestors/descendants
71 5 50       54 @{$h->{ancestors}} =
  33         131  
72             map {
73 5         11 defined($_) ? $_->to_Enum : undef
74 5         11 } @{$h->{ancestors}};
75 5 50       50 @{$h->{descendants}} =
  33         116  
76             map {
77 5         11 defined($_) ? $_->to_Enum : undef
78 5         13 } @{$h->{descendants}};
79 5         63 return $rv;
80             }
81              
82             #--------------------------------------------------------------
83             # $h->decompile() : inherited from CMasked
84              
85             #--------------------------------------------------------------
86             # $h->compiled() : inherited from CMasked
87              
88              
89              
90             ###############################################################
91             # Hierarchy Maintainance
92             ###############################################################
93              
94             #--------------------------------------------------------------
95             # @types = $h->types(): inherited from CMasked
96              
97             #--------------------------------------------------------------
98             # $h = $h->add($t,@ps) : inherited from CMasked
99              
100             #--------------------------------------------------------------
101             # $bool = $h->has_type($t) : inherited from CMasked
102              
103             #--------------------------------------------------------------
104             # $h = $h->add_parents($t,@ps) : inherited from CMasked
105              
106             #--------------------------------------------------------------
107             # $h = $h->replace($old,$new) : inherited from CMasked
108              
109             #--------------------------------------------------------------
110             # $h = $h->move($t,@ps) : inherited from CMasked
111              
112             #--------------------------------------------------------------
113             # $h = $h->remove(@types) : inherited from CMasked
114              
115             #--------------------------------------------------------------
116             # @prts = $h->parents($type) : inherited from CMasked
117              
118             #--------------------------------------------------------------
119             # @kids = $h->children($type) : inherited from CMasked
120              
121             #--------------------------------------------------------------
122             sub ancestors ($$) {
123 1     1 1 3 my ($i);
124             return
125 1 50 33     16 defined($_[1]) && defined($i = $_[0]->{indices}{$_[1]}) &&
126             $_[0]->compiled(1)
127             ? $_[0]->_enum2types($_[0]->{ancestors}[$i],
128             $_[0]->{vectors}[0])
129             : qw();
130             }
131              
132             #--------------------------------------------------------------
133             sub descendants ($$) {
134 1     1 1 2 my ($i);
135             return
136 1 50 33     15 defined($_[1]) && defined($i = $_[0]->{indices}{$_[1]}) &&
137             $_[0]->compiled(1)
138             ? $_[0]->_enum2types($_[0]->{descendants}[$i],
139             $_[0]->{vectors}[0])
140             : qw();
141             }
142              
143             #--------------------------------------------------------------
144             # $bool = $h->has_parent($typ,$prt) : inherited from CMasked
145              
146              
147             #--------------------------------------------------------------
148             # $bool = $h->has_child($typ,$kid) : inherited from CMasked
149              
150              
151             #--------------------------------------------------------------
152             # $bool = $h->has_ancestor($typ,$anc) : inherited from CMasked
153             # --> delegates to has_ancestor_index($typ_idx,$anc_idx)
154              
155             #--------------------------------------------------------------
156             # $bool = $h->has_descendant($typ,$anc) : inherited from CMasked
157             # --> delegates to has_descendant_index($typ_idx,$anc_idx)
158              
159              
160             #--------------------------------------------------------------
161             # @sorted = subsort(@types)
162             sub subsort ($@) {
163 0     0 1 0 my $h = shift;
164 0 0       0 return qw() unless (@_);
165 0         0 $h->compiled(1);
166 0 0       0 my @indices = map { defined($_) ? $h->{indices}{$_} : undef } @_;
  0         0  
167 0         0 my @other = qw();
168 0         0 my $v = $h->{vectors}[0];
169 0         0 my ($i,$j,$e);
170 0         0 for ($i = 0; $i <= $#_; ++$i) {
171 0         0 for ($j = $i+1; $j <= $#_; ++$j) {
172 0 0 0     0 if (!defined($indices[$i])
      0        
      0        
      0        
173             ||
174             (defined($indices[$j]) &&
175             defined($e = $h->{ancestors}[$indices[$i]]) &&
176             $e ne '' &&
177             _enum_bit_test($e, $indices[$j], $v)))
178             {
179 0         0 @indices[$i,$j] = @indices[$j,$i];
180 0         0 @_[$i,$j] = @_[$j,$i];
181             }
182             }
183             }
184 0         0 return @_, @other;
185             }
186              
187              
188             #--------------------------------------------------------------
189             # \%strata = get_strata(@types)
190             sub get_strata ($@) {
191 0     0 1 0 my $h = shift;
192 0         0 $h->compiled(1);
193 0 0       0 my @indices = @{$h->{indices}}{grep { defined($_) && exists($h->{indices}{$_}) } @_};
  0         0  
  0         0  
194 0         0 my (@strata);
195 0         0 foreach (@indices) { $strata[$_] = 0; }
  0         0  
196 0         0 my $v = $h->{vectors}[0];
197 0         0 my ($cmp,$i,$j,$e);
198 0         0 my $changed = 1;
199 0         0 my $step = 1;
200              
201 0         0 while ($changed) {
202 0 0       0 last if ($step > scalar(@_));
203 0         0 $changed = 0;
204              
205 0         0 for ($i = 0; $i < $#indices; ++$i) {
206 0         0 for ($j = $i+1; $j <= $#indices; ++$j) {
207            
208 0 0 0     0 if (defined($e = $h->{ancestors}[$indices[$j]]) &&
    0 0        
      0        
      0        
209             $e ne '' &&
210             _enum_bit_test($e, $indices[$i], $v))
211             {
212 0 0       0 next if ($strata[$indices[$i]] < $strata[$indices[$j]]);
213 0         0 $changed = 1;
214 0         0 $strata[$indices[$j]] = $strata[$indices[$i]] + 1;
215             }
216             elsif (defined($e = $h->{ancestors}[$indices[$i]]) &&
217             $e ne '' &&
218             _enum_bit_test($e, $indices[$j], $v))
219             {
220 0 0       0 next if ($strata[$indices[$i]] > $strata[$indices[$j]]);
221 0         0 $changed = 1;
222 0         0 $strata[$indices[$i]] = $strata[$indices[$j]] + 1;
223             }
224             }
225             }
226             }
227 0         0 my %strata =
228 0         0 (map { $h->{types}[$_] => $strata[$_] } @indices);
229 0         0 return \%strata;
230             }
231              
232              
233              
234             #--------------------------------------------------------------
235             # $bv = $h->_minimize($bv,$tmp)
236             sub _minimize ($$;$) {
237 12     12   12 my $self = shift;
238 12         13 my $bv = shift;
239 12   33     36 my $tmp = shift || $self->{vectors}[1];
240 12         29 $self->compiled(1);
241 12         40 foreach ($bv->Index_List_Read) {
242 14 50       54 $tmp->from_Enum(defined($self->{descendants}[$_])
243             ? $self->{descendants}[$_]
244             : '');
245 14         43 $bv->Difference($bv,$tmp);
246             }
247 12         54 return $bv;
248             }
249              
250             #--------------------------------------------------------------
251             # $bv = $h->_maximize($bv,$tmp)
252             sub _maximize ($$;$) {
253 1     1   2 my $self = shift;
254 1         1 my $bv = shift;
255 1   33     4 my $tmp = shift || $self->{vectors}[1];;
256 1         3 $self->compiled(1);
257 1         4 foreach ($bv->Index_List_Read) {
258 2 50       9 $tmp->from_Enum(defined($self->{ancestors}[$_])
259             ? $self->{ancestors}[$_]
260             : '');
261 2         7 $bv->Difference($bv,$tmp);
262             }
263 1         5 return $bv;
264             }
265              
266              
267             #--------------------------------------------------------------
268             # $val = $h->get_attribute($t,$a) : inherited from Base
269              
270             #--------------------------------------------------------------
271             # $v = $h->set_attribute($t,$a,$v) : inherited from Base
272              
273             #--------------------------------------------------------------
274             # $h1 = $h1->assign($h2) : inherited from CMasked
275              
276             #--------------------------------------------------------------
277             # $h = $h->merge($h1,...) : inherited from Base
278              
279             #--------------------------------------------------------------
280             # $h = $h->clear() : inherited from CMasked
281              
282              
283              
284             ###############################################################
285             # Additional Hierarchy Maintainence Operations
286             ###############################################################
287              
288             #--------------------------------------------------------------
289             # $root = $h->ensure_types(@types): inherited from Base
290              
291             #--------------------------------------------------------------
292             # $bool = $h->has_types(@types): inherited from Base
293              
294             # $bool = $h->has_ancestor_index($typ_idx,$anc_idx);
295             sub has_ancestor_index ($$$) {
296 3     3 1 7 my ($e);
297             return
298 3   66     33 defined($_[1]) && defined($_[2]) &&
299             $_[0]->compiled(1) &&
300             defined($e = $_[0]->{ancestors}[$_[1]]) && $e ne '' &&
301             _enum_bit_test($e, $_[2], $_[0]->{vectors}[0]);
302             }
303              
304             # $bool = $h->has_descendant_index($typ_idx,$dsc_idx);
305             sub has_descendant_index ($$$) {
306 1     1 1 3 my ($e);
307             return
308 1   33     11 defined($_[1]) && defined($_[2]) &&
309             $_[0]->compiled(1) &&
310             defined($e = $_[0]->_descendants->[$_[1]]) && $e ne '' &&
311             _enum_bit_test($e, $_[2], $_[0]->_vectors->[0]);
312             }
313              
314             # $bv = $h->ancestors_mask($typ_idx)
315             sub ancestors_mask ($$) {
316 0 0 0 0 1 0 if (defined($_[0]) && defined($_[1]) && $_[0]->compiled(1)) {
      0        
317 0         0 my $v = $_[0]->{vectors}[0];
318 0         0 $v->from_Enum($_[0]->{ancestors}[$_[1]]);
319 0         0 return $v->Clone;
320             }
321 0         0 return undef;
322             }
323              
324             # $bv = $h->descendants_mask($typ_idx)
325             sub descendants_mask ($$) {
326 0 0 0 0 1 0 if (defined($_[0]) && defined($_[1]) && $_[0]->compiled(1)) {
      0        
327 0         0 my $v = $_[0]->{vectors}[0];
328 0         0 $v->from_Enum($_[0]->{descendants}[$_[1]]);
329 0         0 return $v->Clone;
330             }
331 0         0 return undef;
332             }
333              
334             #--------------------------------------------------------------
335             # $rv = $h->iterate_i(\&next,\&callback,\%args) : inherited from CMasked
336              
337             #--------------------------------------------------------------
338             # $rv = $h->iterate_pc_i(\&callback,\%args) : inherited from CMasked
339              
340             #--------------------------------------------------------------
341             # $rv = $h->iterate_cp_i(\&callback,\%args) : inherited from CMasked
342              
343              
344             ###############################################################
345             # Type Operations
346             ###############################################################
347              
348             #--------------------------------------------------------------
349             # _get_bounds_log($i1,$i2,\@enums,$want_indices,$min_or_max)
350             sub _get_bounds_log ($$$$;$$) {
351 13     13   17 my $self = shift;
352 13         16 my $i1 = shift;
353 13         13 my $i2 = shift;
354 13         13 my $enums = shift;
355              
356             # sanity checks
357             return undef unless
358 13 50 33     84 (defined($i1) && defined($i2) && $self->compiled(1));
      33        
359              
360             # set up solutions vector
361 13         24 my $tmp = $self->{vectors}[0];
362 13         45 my $solns = $tmp->Shadow;
363              
364             # do the *real* computation
365 13 50       50 $solns->from_Enum(defined($enums->[$i1]) ? $enums->[$i1] : '');
366 13 50       39 $tmp->from_Enum(defined($enums->[$i2]) ? $enums->[$i2] : '');
367 13 50       24 if (shift) { # $want_indices
368 13         29 $solns->Bit_On($i1);
369 13         26 $tmp->Bit_On($i2);
370             }
371 13         34 $solns->Intersection($solns,$tmp);
372 13 100       25 if ($_[0] < 0) {
    50          
373 12         25 return $self->_minimize($solns,$tmp);
374             } elsif ($_[0] > 0) {
375 1         5 return $self->_maximize($solns,$tmp);
376             }
377             # well that's odd -- let's just return the intersection
378 0         0 return $solns;
379             }
380              
381              
382             #--------------------------------------------------------------
383             # @lubs = $h->_lub($t1,$t2) : inherited from CMasked
384             # --> $h->types($h->_get_bounds_log($i1,$i2,$h->descendants,1,-1)->Index_List_Read)
385              
386             #--------------------------------------------------------------
387             # @mcds = $h->_mcd($i1,$i2) : inherited from CMasked
388             # --> $h->types($h->_get_bounds_log($i1,$i2,$h->descendants,0,-1)->Index_List_Read)
389              
390             #--------------------------------------------------------------
391             # @glbs = $h->_glb($t1,$t2) : inherited from CMasked
392             # --> $h->types($h->_get_bounds_log($i1,$i2,$h->ancestors,1,1)->Index_List_Read)
393              
394             #--------------------------------------------------------------
395             # @mcas = $h->_mca($i1,$i2)
396             # --> $h->types($h->_get_bounds_log($i1,$i2,$h->ancestors,0,1)->Index_List_Read)
397              
398              
399             ###############################################################
400             # Low-level Accessors/manipulators : inherited from CMasked
401             ###############################################################
402              
403              
404             ###############################################################
405             # Misc
406             ###############################################################
407              
408             #--------------------------------------------------------------
409             sub dump ($;$$) {
410 0     0 1 0 my $h = shift;
411 0   0     0 my $name = shift || "$h";
412 0         0 my $what = shift;
413 0         0 my $dump = "\$$name = [\n";
414 0         0 my ($i);
415 0 0 0     0 if (!defined($what) || $what =~ /\btypes\b/) {
416 0         0 $dump .= " TYPES: [";
417 0         0 for ($i = 0; $i <= $#{$h->{types}}; ++$i) {
  0         0  
418 0 0       0 $dump .=
419             "\n $i: " .
420             (defined($h->{types}[$i]) ? "'" . $h->{types}[$i] . "'" : 'undef');
421             }
422 0         0 $dump .= "\n ],\n";
423             }
424 0 0 0     0 if (!defined($what) || $what =~ /\bindices\b/) {
425 0         0 $dump .= " INDICES: {";
426 0         0 foreach $i (keys(%{$h->{indices}})) {
  0         0  
427 0         0 $dump .= "\n '$i' => '" . $h->{indices}{$i} . "'";
428             }
429 0         0 $dump .= "\n },\n";
430             }
431 0 0 0     0 if (!defined($what) || $what =~ /\broot\b/) {
432 0         0 $dump .= " ROOT: '" . $h->{root} . "',\n";
433             }
434 0 0 0     0 if (!defined($what) || $what =~ /\bparents\b/) {
435 0         0 $dump .= " PARENTS: [";
436 0         0 for ($i = 0; $i <= $#{$h->{parents}}; ++$i) {
  0         0  
437 0         0 $dump .= "\n $i: (" . $h->{parents}[$i] . ")";
438             }
439 0         0 $dump .= "\n ],\n";
440             }
441 0 0 0     0 if (!defined($what) || $what =~ /\bchildren\b/) {
442 0         0 $dump .= " CHILDREN: [";
443 0         0 for ($i = 0; $i <= $#{$h->{children}}; ++$i) {
  0         0  
444 0         0 $dump .= "\n $i: (" . $h->{children}[$i] . ")";
445             }
446 0         0 $dump .= "\n ],\n";
447             }
448 0 0 0     0 if (!defined($what) || $what =~ /\bremoved\b/) {
449 0         0 $dump .= " REMOVED: [" . join(',', @{$h->{removed}}) . "],\n";
  0         0  
450             }
451 0 0 0     0 if (!defined($what) || $what =~ /\bancestors\b/) {
452 0         0 $dump .= " ANCESTORS: [";
453 0         0 for ($i = 0; $i <= $#{$h->{ancestors}}; ++$i) {
  0         0  
454 0         0 $dump .= "\n $i: (" . $h->{ancestors}[$i] . ")";
455             }
456 0         0 $dump .= "\n ],\n";
457             }
458 0 0 0     0 if (!defined($what) || $what =~ /\bdescendants\b/) {
459 0         0 $dump .= " DESCENDANTS: [";
460 0         0 for ($i = 0; $i <= $#{$h->{descendants}}; ++$i) {
  0         0  
461 0         0 $dump .= "\n $i: (" . $h->{descendants}[$i] . ")";
462             }
463 0         0 $dump .= "\n ],\n";
464             }
465 0 0 0     0 if (!defined($what) || $what =~ /\bcompiled\b/) {
466 0 0       0 $dump .= " COMPILED: " . ($h->compiled ? '1' : '0') . "\n";
467             }
468 0 0 0     0 if (!defined($what) || $what =~ /\bhattr/) {
469 0         0 $dump .= " HATTRS: {";
470 0         0 foreach $i (keys(%{$h->{hattributes}})) {
  0         0  
471 0         0 $dump .= "\n '$i' => '" . $h->{hattributes}{$i} . "'";
472             }
473 0         0 $dump .= "\n },\n";
474             }
475 0         0 return $dump . "];\n";
476             }
477              
478              
479             #--------------------------------------------------------------
480             # Storage/retrieval
481              
482             #---------------------------------------------------------------------
483             # $hashref = $h->_get_bin_compat() : inherited from CMasked
484              
485             #---------------------------------------------------------------------
486             # $h->_store_before($retr)
487             sub _store_before {
488 1     1   2 my ($h,$retr) = @_;
489 1         3 $retr->{RemovedIndices} = $h->{removed};
490 1         3 $retr->{ParentsEnums} = $h->{parents};
491 1         6 $retr->{ChildrenEnums} = $h->{children};
492 1         3 $retr->{CompiledFlag} = $h->{compiled};
493 1 50       4 if ($h->{compiled}) {
494 1         3 $retr->{AncestorsEnums} = $h->{ancestors};
495 1         2 $retr->{DescendantsEnums} = $h->{descendants};
496             }
497 1         2 return $retr;
498             }
499              
500             #--------------------------------------------------------------
501             # $h->_store_type($tr,$retr) : inherited from CMasked
502              
503             #--------------------------------------------------------------
504             # $h->_retrieve_type($tr,$retr) : inherited from CMasked
505              
506             #--------------------------------------------------------------
507             # $h->_retrieve_after($h,$retr)
508             sub _retrieve_after {
509 1     1   2 my ($h,$retr) = @_;
510 1         2 @{$h->{removed}} = @{$retr->{RemovedIndices}};
  1         2  
  1         3  
511 1         1 @{$h->{parents}} = @{$retr->{ParentsEnums}};
  1         7  
  1         3  
512 1         3 @{$h->{children}} = @{$retr->{ChildrenEnums}};
  1         5  
  1         2  
513 1         3 $h->{compiled} = $retr->{CompiledFlag};
514 1 50       5 if ($h->{compiled}) {
515 1         4 $h->_ensure_vector_sizes();
516 1         2 @{$h->{ancestors}} = @{$retr->{AncestorsEnums}};
  1         4  
  1         3  
517 1         2 @{$h->{descendants}} = @{$retr->{DescendantsEnums}};
  1         6  
  1         2  
518             }
519             }
520              
521             1;
522             __END__