File Coverage

blib/lib/Set/Infinite.pm
Criterion Covered Total %
statement 721 830 86.8
branch 314 464 67.6
condition 74 102 72.5
subroutine 42 51 82.3
pod 22 29 75.8
total 1173 1476 79.4


line stmt bran cond sub pod time code
1             package Set::Infinite;
2              
3             # Copyright (c) 2001, 2002, 2003, 2004 Flavio Soibelmann Glock.
4             # All rights reserved.
5             # This program is free software; you can redistribute it and/or
6             # modify it under the same terms as Perl itself.
7              
8 11     11   76589 use 5.005_03;
  11         57  
  11         530  
9              
10             # These methods are inherited from Set::Infinite::Basic "as-is":
11             # type list fixtype numeric min max integer real new span copy
12             # start_set end_set universal_set empty_set minus difference
13             # symmetric_difference is_empty
14              
15 11     11   59 use strict;
  11         22  
  11         478  
16 11     11   56 use base qw(Set::Infinite::Basic Exporter);
  11         46  
  11         27961  
17 11     11   68 use Carp;
  11         23  
  11         845  
18 11     11   10363 use Set::Infinite::Arithmetic;
  11         29  
  11         6904  
19              
20             use overload
21 11         123 '<=>' => \&spaceship,
22 11     11   76 '""' => \&as_string;
  11         91  
23              
24 11         3933 use vars qw(@EXPORT_OK $VERSION
25             $TRACE $DEBUG_BT $PRETTY_PRINT $inf $minus_inf $neg_inf
26             %_first %_last %_backtrack
27             $too_complex $backtrack_depth
28             $max_backtrack_depth $max_intersection_depth
29 11     11   964 $trace_level %level_title );
  11         16  
30              
31             @EXPORT_OK = qw(inf $inf trace_open trace_close);
32              
33             $inf = 100**100**100;
34             $neg_inf = $minus_inf = -$inf;
35              
36              
37             # obsolete methods - included for backward compatibility
38 0     0 0 0 sub inf () { $inf }
39 0     0 0 0 sub minus_inf () { $minus_inf }
40 0     0 0 0 sub no_cleanup { $_[0] }
41             *type = \&Set::Infinite::Basic::type;
42 0     0 0 0 sub compact { @_ }
43              
44              
45             BEGIN {
46 11     11   34 $VERSION = "0.65";
47 11         19 $TRACE = 0; # enable basic trace method execution
48 11         35 $DEBUG_BT = 0; # enable backtrack tracer
49 11         13 $PRETTY_PRINT = 0; # 0 = print 'Too Complex'; 1 = describe functions
50 11         33 $trace_level = 0; # indentation level when debugging
51              
52 11         18 $too_complex = "Too complex";
53 11         12 $backtrack_depth = 0;
54 11         12 $max_backtrack_depth = 10; # _backtrack()
55 11         69542 $max_intersection_depth = 5; # first()
56             }
57              
58             sub trace { # title=>'aaa'
59 4193 50   4193 0 8969 return $_[0] unless $TRACE;
60 0         0 my ($self, %parm) = @_;
61 0         0 my @caller = caller(1);
62             # print "self $self ". ref($self). "\n";
63 0 0       0 print "" . ( ' | ' x $trace_level ) .
    0          
64             "$parm{title} ". $self->copy .
65             ( exists $parm{arg} ? " -- " . $parm{arg}->copy : "" ).
66             " $caller[1]:$caller[2] ]\n" if $TRACE == 1;
67 0         0 return $self;
68             }
69              
70             sub trace_open {
71 0 0   0 0 0 return $_[0] unless $TRACE;
72 0         0 my ($self, %parm) = @_;
73 0         0 my @caller = caller(1);
74 0 0       0 print "" . ( ' | ' x $trace_level ) .
75             "\\ $parm{title} ". $self->copy .
76             ( exists $parm{arg} ? " -- ". $parm{arg}->copy : "" ).
77             " $caller[1]:$caller[2] ]\n";
78 0         0 $trace_level++;
79 0         0 $level_title{$trace_level} = $parm{title};
80 0         0 return $self;
81             }
82              
83             sub trace_close {
84 0 0   0 0 0 return $_[0] unless $TRACE;
85 0         0 my ($self, %parm) = @_;
86 0         0 my @caller = caller(0);
87 0 0       0 print "" . ( ' | ' x ($trace_level-1) ) .
    0          
    0          
88             "\/ $level_title{$trace_level} ".
89             ( exists $parm{arg} ?
90             (
91             defined $parm{arg} ?
92             "ret ". ( UNIVERSAL::isa($parm{arg}, __PACKAGE__ ) ?
93             $parm{arg}->copy :
94             "<$parm{arg}>" ) :
95             "undef"
96             ) :
97             "" # no arg
98             ).
99             " $caller[1]:$caller[2] ]\n";
100 0         0 $trace_level--;
101 0         0 return $self;
102             }
103              
104              
105             # creates a 'function' object that can be solved by _backtrack()
106             sub _function {
107 4751     4751   7201 my ($self, $method) = (shift, shift);
108 4751         11664 my $b = $self->empty_set();
109 4751         7716 $b->{too_complex} = 1;
110 4751         6693 $b->{parent} = $self;
111 4751         6938 $b->{method} = $method;
112 4751         16155 $b->{param} = [ @_ ];
113 4751         14840 return $b;
114             }
115              
116              
117             # same as _function, but with 2 arguments
118             sub _function2 {
119 1685     1685   2967 my ($self, $method, $arg) = (shift, shift, shift);
120 1685 100 100     5742 unless ( $self->{too_complex} || $arg->{too_complex} ) {
121 791         2651 return $self->$method($arg, @_);
122             }
123 894         2207 my $b = $self->empty_set();
124 894         1511 $b->{too_complex} = 1;
125 894         1821 $b->{parent} = [ $self, $arg ];
126 894         1467 $b->{method} = $method;
127 894         2178 $b->{param} = [ @_ ];
128 894         2652 return $b;
129             }
130              
131              
132             sub quantize {
133 3742     3742 1 8337 my $self = shift;
134 3742 50       7473 $self->trace_open(title=>"quantize") if $TRACE;
135 3742         7393 my @min = $self->min_a;
136 3742         8428 my @max = $self->max_a;
137 3742 100 100     30516 if (($self->{too_complex}) or
      66        
      100        
      66        
138             (defined $min[0] && $min[0] == $neg_inf) or
139             (defined $max[0] && $max[0] == $inf)) {
140              
141 2372         5435 return $self->_function( 'quantize', @_ );
142             }
143              
144 1370         1591 my @a;
145 1370         2804 my %rule = @_;
146 1370         3897 my $b = $self->empty_set();
147 1370         4605 my $parent = $self;
148              
149 1370 100       4332 $rule{unit} = 'one' unless $rule{unit};
150 1370 100       2884 $rule{quant} = 1 unless $rule{quant};
151 1370         1830 $rule{parent} = $parent;
152 1370 50       3525 $rule{strict} = $parent unless exists $rule{strict};
153 1370         2394 $rule{type} = $parent->{type};
154              
155 1370         2574 my ($min, $open_begin) = $parent->min_a;
156              
157 1370 100       3295 unless (defined $min) {
158 52 50       150 $self->trace_close( arg => $b ) if $TRACE;
159 52         190 return $b;
160             }
161              
162 1318 50       3177 $rule{fixtype} = 1 unless exists $rule{fixtype};
163 1318         4691 $Set::Infinite::Arithmetic::Init_quantizer{$rule{unit}}->(\%rule);
164              
165 1318         2864 $rule{sub_unit} = $Set::Infinite::Arithmetic::Offset_to_value{$rule{unit}};
166 1318 50       3430 carp "Quantize unit '".$rule{unit}."' not implemented" unless ref( $rule{sub_unit} ) eq 'CODE';
167              
168 1318         2473 my ($max, $open_end) = $parent->max_a;
169 1318         4900 $rule{offset} = $Set::Infinite::Arithmetic::Value_to_offset{$rule{unit}}->(\%rule, $min);
170 1318         4065 my $last_offset = $Set::Infinite::Arithmetic::Value_to_offset{$rule{unit}}->(\%rule, $max);
171 1318         3643 $rule{size} = $last_offset - $rule{offset} + 1;
172 1318         1479 my ($index, $tmp, $this, $next);
173 1318         3014 for $index (0 .. $rule{size} ) {
174             # ($this, $next) = $rule{sub_unit} (\%rule, $index);
175 3324         9651 ($this, $next) = $rule{sub_unit}->(\%rule, $index);
176 3324 50       7690 unless ( $rule{fixtype} ) {
177 0         0 $tmp = { a => $this , b => $next ,
178             open_begin => 0, open_end => 1 };
179             }
180             else {
181 3324         9300 $tmp = Set::Infinite::Basic::_simple_new($this,$next, $rule{type} );
182 3324         5620 $tmp->{open_end} = 1;
183             }
184 3324 100 100     8453 next if ( $rule{strict} and not $rule{strict}->intersects($tmp));
185 1890         6766 push @a, $tmp;
186             }
187              
188 1318         2595 $b->{list} = \@a; # change data
189 1318 50       3949 $self->trace_close( arg => $b ) if $TRACE;
190 1318         7203 return $b;
191             }
192              
193              
194             sub _first_n {
195 8     8   14 my $self = shift;
196 8         11 my $n = shift;
197 8         38 my $tail = $self->copy;
198 8         12 my @result;
199             my $first;
200 8         21 for ( 1 .. $n )
201             {
202 62 50       147 ( $first, $tail ) = $tail->first if $tail;
203 62         796 push @result, $first;
204             }
205 8         48 return $tail, @result;
206             }
207              
208             sub _last_n {
209 6     6   11 my $self = shift;
210 6         8 my $n = shift;
211 6         19 my $tail = $self->copy;
212 6         12 my @result;
213             my $last;
214 6         12 for ( 1 .. $n )
215             {
216 48 50       109 ( $last, $tail ) = $tail->last if $tail;
217 48         272 unshift @result, $last;
218             }
219 6         121 return $tail, @result;
220             }
221              
222              
223             sub select {
224 16     16 1 196 my $self = shift;
225 16 50       54 $self->trace_open(title=>"select") if $TRACE;
226              
227 16         50 my %param = @_;
228 16 50       47 die "select() - parameter 'freq' is deprecated" if exists $param{freq};
229              
230 16         21 my $res;
231             my $count;
232 0         0 my @by;
233 16 100       47 @by = @{ $param{by} } if exists $param{by};
  11         33  
234 16   66     65 $count = delete $param{count} || $inf;
235             # warn "select: count=$count by=[@by]";
236              
237 16 50       45 if ($count <= 0) {
238 0 0       0 $self->trace_close( arg => $res ) if $TRACE;
239 0         0 return $self->empty_set();
240             }
241              
242 16         21 my @set;
243             my $tail;
244 0         0 my $first;
245 0         0 my $last;
246 16 100       42 if ( @by )
247             {
248 11         17 my @res;
249 11 100       33 if ( ! $self->is_too_complex )
250             {
251 3         7 $res = $self->new;
252 3         5 @res = @{ $self->{list} }[ @by ] ;
  3         11  
253             }
254             else
255             {
256 8         13 my ( @pos_by, @neg_by );
257 8         19 for ( @by ) {
258 28 100       65 ( $_ < 0 ) ? push @neg_by, $_ :
259             push @pos_by, $_;
260             }
261 8         15 my @first;
262 8 50       26 if ( @pos_by ) {
263 8         30 @pos_by = sort { $a <=> $b } @pos_by;
  8         22  
264 8         30 ( $tail, @set ) = $self->_first_n( 1 + $pos_by[-1] );
265 8         32 @first = @set[ @pos_by ];
266             }
267 8         12 my @last;
268 8 100       52 if ( @neg_by ) {
269 6         20 @neg_by = sort { $a <=> $b } @neg_by;
  6         12  
270 6         18 ( $tail, @set ) = $self->_last_n( - $neg_by[0] );
271 6         39 @last = @set[ @neg_by ];
272             }
273 8         20 @res = map { $_->{list}[0] } ( @first , @last );
  28         86  
274             }
275              
276 11         43 $res = $self->new;
277 11         29 @res = sort { $a->{a} <=> $b->{a} } grep { defined } @res;
  39         102  
  40         109  
278 11         21 my $last;
279             my @a;
280 11         28 for ( @res ) {
281 40 100 100     178 push @a, $_ if ! $last || $last->{a} != $_->{a};
282 40         66 $last = $_;
283             }
284 11         37 $res->{list} = \@a;
285             }
286             else
287             {
288 5         11 $res = $self;
289             }
290              
291 16 100       119 return $res if $count == $inf;
292 11         42 my $count_set = $self->empty_set();
293 11 100       35 if ( ! $self->is_too_complex )
294             {
295 3         5 my @a;
296 3         9 @a = grep { defined } @{ $res->{list} }[ 0 .. $count - 1 ] ;
  9         20  
  3         8  
297 3         8 $count_set->{list} = \@a;
298             }
299             else
300             {
301 8         13 my $last;
302 8         24 while ( $res ) {
303 21         85 ( $first, $res ) = $res->first;
304 21 50       80 last unless $first;
305 21 100 100     165 last if $last && $last->{a} == $first->{list}[0]{a};
306 20         36 $last = $first->{list}[0];
307 20         25 push @{$count_set->{list}}, $first->{list}[0];
  20         44  
308 20         30 $count--;
309 20 100       62 last if $count <= 0;
310             }
311             }
312 11         285 return $count_set;
313             }
314              
315             BEGIN {
316              
317             # %_first and %_last hashes are used to backtrack the value
318             # of first() and last() of an infinite set
319              
320             %_first = (
321             'complement' =>
322             sub {
323 5         9 my $self = $_[0];
324 5         17 my @parent_min = $self->{parent}->first;
325 5 50       16 unless ( defined $parent_min[0] ) {
326 0         0 return (undef, 0);
327             }
328 5         7 my $parent_complement;
329             my $first;
330 0         0 my @next;
331 0         0 my $parent;
332 5 100       21 if ( $parent_min[0]->min == $neg_inf ) {
333 2         26 my @parent_second = $parent_min[1]->first;
334             # (-inf..min) (second..?)
335             # (min..second) = complement
336 2         10 $first = $self->new( $parent_min[0]->complement );
337 2         11 $first->{list}[0]{b} = $parent_second[0]->{list}[0]{a};
338 2         7 $first->{list}[0]{open_end} = ! $parent_second[0]->{list}[0]{open_begin};
339 2 50 33     25 @{ $first->{list} } = () if
  2   33     8  
340             ( $first->{list}[0]{a} == $first->{list}[0]{b}) &&
341             ( $first->{list}[0]{open_begin} ||
342             $first->{list}[0]{open_end} );
343 2         7 @next = $parent_second[0]->max_a;
344 2         7 $parent = $parent_second[1];
345             }
346             else {
347             # (min..?)
348             # (-inf..min) = complement
349 3         9 $parent_complement = $parent_min[0]->complement;
350 3         12 $first = $self->new( $parent_complement->{list}[0] );
351 3         8 @next = $parent_min[0]->max_a;
352 3         5 $parent = $parent_min[1];
353             }
354 5         19 my @no_tail = $self->new($neg_inf,$next[0]);
355 5         24 $no_tail[0]->{list}[0]{open_end} = $next[1];
356 5         14 my $tail = $parent->union($no_tail[0])->complement;
357 5         19 return ($first, $tail);
358             }, # end: first-complement
359             'intersection' =>
360             sub {
361 131         261 my $self = $_[0];
362 131         158 my @parent = @{ $self->{parent} };
  131         337  
363             # warn "$method parents @parent";
364 131         207 my $retry_count = 0;
365 131         204 my (@first, @min, $which, $first1, $intersection);
366 131         361 SEARCH: while ($retry_count++ < $max_intersection_depth) {
367 188 50       450 return undef unless defined $parent[0];
368 188 50       364 return undef unless defined $parent[1];
369 188         445 @{$first[0]} = $parent[0]->first;
  188         444  
370 188         529 @{$first[1]} = $parent[1]->first;
  188         435  
371 188 50       637 unless ( defined $first[0][0] ) {
372             # warn "don't know first of $method";
373 0 0       0 $self->trace_close( arg => 'undef' ) if $TRACE;
374 0         0 return undef;
375             }
376 188 50       476 unless ( defined $first[1][0] ) {
377             # warn "don't know first of $method";
378 0 0       0 $self->trace_close( arg => 'undef' ) if $TRACE;
379 0         0 return undef;
380             }
381 188         509 @{$min[0]} = $first[0][0]->min_a;
  188         492  
382 188         616 @{$min[1]} = $first[1][0]->min_a;
  188         515  
383 188 50 33     1000 unless ( defined $min[0][0] && defined $min[1][0] ) {
384 0         0 return undef;
385             }
386             # $which is the index to the bigger "first".
387 188 100       555 $which = ($min[0][0] < $min[1][0]) ? 1 : 0;
388 188         443 for my $which1 ( $which, 1 - $which ) {
389 253         371 my $tmp_parent = $parent[$which1];
390 253         274 ($first1, $parent[$which1]) = @{ $first[$which1] };
  253         503  
391 253 50       835 if ( $first1->is_empty ) {
392             # warn "first1 empty! count $retry_count";
393             # trace_close;
394             # return $first1, undef;
395 0         0 $intersection = $first1;
396 0         0 $which = $which1;
397 0         0 last SEARCH;
398             }
399 253         716 $intersection = $first1->intersection( $parent[1-$which1] );
400             # warn "intersection with $first1 is $intersection";
401 253 100       1223 unless ( $intersection->is_null ) {
402             # $self->trace( title=>"got an intersection" );
403 196 100       454 if ( $intersection->is_too_complex ) {
404 65         179 $parent[$which1] = $tmp_parent;
405             }
406             else {
407 131         171 $which = $which1;
408 131         341 last SEARCH;
409             }
410             };
411             }
412             }
413 131 100       197 if ( $#{ $intersection->{list} } > 0 ) {
  131         461  
414 1         2 my $tail;
415 1         3 ($intersection, $tail) = $intersection->first;
416 1         5 $parent[$which] = $parent[$which]->union( $tail );
417             }
418 131         174 my $tmp;
419 131 100 66     746 if ( defined $parent[$which] and defined $parent[1-$which] ) {
420 130         318 $tmp = $parent[$which]->intersection ( $parent[1-$which] );
421             }
422 131         654 return ($intersection, $tmp);
423             }, # end: first-intersection
424             'union' =>
425             sub {
426 23         48 my $self = $_[0];
427 23         34 my (@first, @min);
428 23         34 my @parent = @{ $self->{parent} };
  23         65  
429 23         71 @{$first[0]} = $parent[0]->first;
  23         62  
430 23         66 @{$first[1]} = $parent[1]->first;
  23         52  
431 23 50       87 unless ( defined $first[0][0] ) {
432             # looks like one set was empty
433 0         0 return @{$first[1]};
  0         0  
434             }
435 23         66 @{$min[0]} = $first[0][0]->min_a;
  23         67  
436 23         70 @{$min[1]} = $first[1][0]->min_a;
  23         72  
437              
438             # check min1/min2 for undef
439 23 100       80 unless ( defined $min[0][0] ) {
440 1 50       4 $self->trace_close( arg => "@{$first[1]}" ) if $TRACE;
  0         0  
441 1         2 return @{$first[1]}
  1         4  
442             }
443 22 50       68 unless ( defined $min[1][0] ) {
444 0 0       0 $self->trace_close( arg => "@{$first[0]}" ) if $TRACE;
  0         0  
445 0         0 return @{$first[0]}
  0         0  
446             }
447              
448 22 100       73 my $which = ($min[0][0] < $min[1][0]) ? 0 : 1;
449 22         44 my $first = $first[$which][0];
450              
451             # find out the tail
452 22         35 my $parent1 = $first[$which][1];
453             # warn $self->{parent}[$which]." - $first = $parent1";
454 22 100       105 my $parent2 = ($min[0][0] == $min[1][0]) ?
455             $self->{parent}[1-$which]->complement($first) :
456             $self->{parent}[1-$which];
457 22         26 my $tail;
458 22 100 66     71 if (( ! defined $parent1 ) || $parent1->is_null) {
459             # warn "union parent1 tail is null";
460 20         28 $tail = $parent2;
461             }
462             else {
463 2         4 my $method = $self->{method};
464 2         5 $tail = $parent1->$method( $parent2 );
465             }
466              
467 22 100       91 if ( $first->intersects( $tail ) ) {
468 3         4 my $first2;
469 3         13 ( $first2, $tail ) = $tail->first;
470 3         12 $first = $first->union( $first2 );
471             }
472              
473 22 50       70 $self->trace_close( arg => "$first $tail" ) if $TRACE;
474 22         104 return ($first, $tail);
475             }, # end: first-union
476             'iterate' =>
477             sub {
478 0         0 my $self = $_[0];
479 0         0 my $parent = $self->{parent};
480 0         0 my ($first, $tail) = $parent->first;
481 0 0       0 $first = $first->iterate( @{$self->{param}} ) if ref($first);
  0         0  
482 0 0       0 $tail = $tail->_function( 'iterate', @{$self->{param}} ) if ref($tail);
  0         0  
483 0         0 my $more;
484 0 0       0 ($first, $more) = $first->first if ref($first);
485 0 0       0 $tail = $tail->_function2( 'union', $more ) if defined $more;
486 0         0 return ($first, $tail);
487             },
488             'until' =>
489             sub {
490 33         70 my $self = $_[0];
491 33         45 my ($a1, $b1) = @{ $self->{parent} };
  33         90  
492 33         109 $a1->trace( title=>"computing first()" );
493 33         80 my @first1 = $a1->first;
494 33         88 my @first2 = $b1->first;
495 33         62 my ($first, $tail);
496 33 100       154 if ( $first2[0] <= $first1[0] ) {
497             # added ->first because it returns 2 spans if $a1 == $a2
498 16         48 $first = $a1->empty_set()->until( $first2[0] )->first;
499 16         117 $tail = $a1->_function2( "until", $first2[1] );
500             }
501             else {
502 17         75 $first = $a1->new( $first1[0] )->until( $first2[0] );
503 17 50       94 if ( defined $first1[1] ) {
504 17         59 $tail = $first1[1]->_function2( "until", $first2[1] );
505             }
506             else {
507 0         0 $tail = undef;
508             }
509             }
510 33         95 return ($first, $tail);
511             },
512             'offset' =>
513             sub {
514 364         510 my $self = $_[0];
515 364         840 my ($first, $tail) = $self->{parent}->first;
516 364         506 $first = $first->offset( @{$self->{param}} );
  364         1089  
517 364         509 $tail = $tail->_function( 'offset', @{$self->{param}} );
  364         1010  
518 364         2343 my $more;
519 364         705 ($first, $more) = $first->first;
520 364 100       1359 $tail = $tail->_function2( 'union', $more ) if defined $more;
521 364         600 return ($first, $tail);
522             },
523             'quantize' =>
524             sub {
525 1109         1359 my $self = $_[0];
526 1109         2415 my @min = $self->{parent}->min_a;
527 1109 100 100     4437 if ( $min[0] == $neg_inf || $min[0] == $inf ) {
528 669         1853 return ( $self->new( $min[0] ) , $self->copy );
529             }
530 440         1315 my $first = $self->new( $min[0] )->quantize( @{$self->{param}} );
  440         1263  
531 440         1440 return ( $first,
532             $self->{parent}->
533             _function2( 'intersection', $first->complement )->
534 440         2499 _function( 'quantize', @{$self->{param}} ) );
535             },
536             'tolerance' =>
537             sub {
538 1         2 my $self = $_[0];
539 1         4 my ($first, $tail) = $self->{parent}->first;
540 1         2 $first = $first->tolerance( @{$self->{param}} );
  1         3  
541 1         2 $tail = $tail->tolerance( @{$self->{param}} );
  1         3  
542 1         2 return ($first, $tail);
543             },
544 11     11   580 ); # %_first
545              
546             %_last = (
547             'complement' =>
548             sub {
549 5         7 my $self = $_[0];
550 5         18 my @parent_max = $self->{parent}->last;
551 5 50       12 unless ( defined $parent_max[0] ) {
552 0         0 return (undef, 0);
553             }
554 5         8 my $parent_complement;
555             my $last;
556 0         0 my @next;
557 0         0 my $parent;
558 5 100       20 if ( $parent_max[0]->max == $inf ) {
559             # (inf..min) (second..?) = parent
560             # (min..second) = complement
561 2         7 my @parent_second = $parent_max[1]->last;
562 2         8 $last = $self->new( $parent_max[0]->complement );
563 2         12 $last->{list}[0]{a} = $parent_second[0]->{list}[0]{b};
564 2         11 $last->{list}[0]{open_begin} = ! $parent_second[0]->{list}[0]{open_end};
565 2 50 33     15 @{ $last->{list} } = () if
  2   33     15  
566             ( $last->{list}[0]{a} == $last->{list}[0]{b}) &&
567             ( $last->{list}[0]{open_end} ||
568             $last->{list}[0]{open_begin} );
569 2         6 @next = $parent_second[0]->min_a;
570 2         5 $parent = $parent_second[1];
571             }
572             else {
573             # (min..?)
574             # (-inf..min) = complement
575 3         9 $parent_complement = $parent_max[0]->complement;
576 3         13 $last = $self->new( $parent_complement->{list}[-1] );
577 3         8 @next = $parent_max[0]->min_a;
578 3         5 $parent = $parent_max[1];
579             }
580 5         15 my @no_tail = $self->new($next[0], $inf);
581 5         15 $no_tail[0]->{list}[-1]{open_begin} = $next[1];
582 5         11 my $tail = $parent->union($no_tail[-1])->complement;
583 5         19 return ($last, $tail);
584             },
585             'intersection' =>
586             sub {
587 114         189 my $self = $_[0];
588 114         138 my @parent = @{ $self->{parent} };
  114         295  
589             # TODO: check max1/max2 for undef
590              
591 114         168 my $retry_count = 0;
592 114         124 my (@last, @max, $which, $last1, $intersection);
593              
594 114         315 SEARCH: while ($retry_count++ < $max_intersection_depth) {
595 123 50       275 return undef unless defined $parent[0];
596 123 50       277 return undef unless defined $parent[1];
597              
598 123         300 @{$last[0]} = $parent[0]->last;
  123         313  
599 123         397 @{$last[1]} = $parent[1]->last;
  123         310  
600 123 50       408 unless ( defined $last[0][0] ) {
601 0 0       0 $self->trace_close( arg => 'undef' ) if $TRACE;
602 0         0 return undef;
603             }
604 123 50       310 unless ( defined $last[1][0] ) {
605 0 0       0 $self->trace_close( arg => 'undef' ) if $TRACE;
606 0         0 return undef;
607             }
608 123         375 @{$max[0]} = $last[0][0]->max_a;
  123         296  
609 123         342 @{$max[1]} = $last[1][0]->max_a;
  123         296  
610 123 50 33     660 unless ( defined $max[0][0] && defined $max[1][0] ) {
611 0 0       0 $self->trace( title=>"can't find max()" ) if $TRACE;
612 0 0       0 $self->trace_close( arg => 'undef' ) if $TRACE;
613 0         0 return undef;
614             }
615              
616             # $which is the index to the smaller "last".
617 123 100       327 $which = ($max[0][0] > $max[1][0]) ? 1 : 0;
618              
619 123         260 for my $which1 ( $which, 1 - $which ) {
620 142         198 my $tmp_parent = $parent[$which1];
621 142         134 ($last1, $parent[$which1]) = @{ $last[$which1] };
  142         278  
622 142 50       296 if ( $last1->is_null ) {
623 0         0 $which = $which1;
624 0         0 $intersection = $last1;
625 0         0 last SEARCH;
626             }
627 142         392 $intersection = $last1->intersection( $parent[1-$which1] );
628              
629 142 100       529 unless ( $intersection->is_null ) {
630             # $self->trace( title=>"got an intersection" );
631 133 100       290 if ( $intersection->is_too_complex ) {
632 19 50       62 $self->trace( title=>"got a too_complex intersection" ) if $TRACE;
633             # warn "too complex intersection";
634 19         63 $parent[$which1] = $tmp_parent;
635             }
636             else {
637 114 50       235 $self->trace( title=>"got an intersection" ) if $TRACE;
638 114         121 $which = $which1;
639 114         265 last SEARCH;
640             }
641             };
642             }
643             }
644 114 50       260 $self->trace( title=>"exit loop" ) if $TRACE;
645 114 100       135 if ( $#{ $intersection->{list} } > 0 ) {
  114         366  
646 1         2 my $tail;
647 1         4 ($intersection, $tail) = $intersection->last;
648 1         5 $parent[$which] = $parent[$which]->union( $tail );
649             }
650 114         134 my $tmp;
651 114 100 66     549 if ( defined $parent[$which] and defined $parent[1-$which] ) {
652 113         294 $tmp = $parent[$which]->intersection ( $parent[1-$which] );
653             }
654 114         506 return ($intersection, $tmp);
655             },
656             'union' =>
657             sub {
658 10         21 my $self = $_[0];
659 10         15 my (@last, @max);
660 10         15 my @parent = @{ $self->{parent} };
  10         31  
661 10         34 @{$last[0]} = $parent[0]->last;
  10         30  
662 10         182 @{$last[1]} = $parent[1]->last;
  10         27  
663 10         37 @{$max[0]} = $last[0][0]->max_a;
  10         31  
664 10         33 @{$max[1]} = $last[1][0]->max_a;
  10         27  
665 10 100       39 unless ( defined $max[0][0] ) {
666 1         3 return @{$last[1]}
  1         4  
667             }
668 9 50       32 unless ( defined $max[1][0] ) {
669 0         0 return @{$last[0]}
  0         0  
670             }
671              
672 9 100       43 my $which = ($max[0][0] > $max[1][0]) ? 0 : 1;
673 9         21 my $last = $last[$which][0];
674             # find out the tail
675 9         28 my $parent1 = $last[$which][1];
676             # warn $self->{parent}[$which]." - $last = $parent1";
677 9 100       43 my $parent2 = ($max[0][0] == $max[1][0]) ?
678             $self->{parent}[1-$which]->complement($last) :
679             $self->{parent}[1-$which];
680 9         19 my $tail;
681 9 100 66     84 if (( ! defined $parent1 ) || $parent1->is_null) {
682 7         11 $tail = $parent2;
683             }
684             else {
685 2         6 my $method = $self->{method};
686 2         6 $tail = $parent1->$method( $parent2 );
687             }
688              
689 9 100       27 if ( $last->intersects( $tail ) ) {
690 2         5 my $last2;
691 2         10 ( $last2, $tail ) = $tail->last;
692 2         9 $last = $last->union( $last2 );
693             }
694              
695 9         54 return ($last, $tail);
696             },
697             'until' =>
698             sub {
699 28         54 my $self = $_[0];
700 28         44 my ($a1, $b1) = @{ $self->{parent} };
  28         66  
701 28         85 $a1->trace( title=>"computing last()" );
702 28         68 my @last1 = $a1->last;
703 28         79 my @last2 = $b1->last;
704 28         46 my ($last, $tail);
705 28 100       117 if ( $last2[0] <= $last1[0] ) {
706             # added ->last because it returns 2 spans if $a1 == $a2
707 12         37 $last = $last2[0]->until( $a1 )->last;
708 12         61 $tail = $a1->_function2( "until", $last2[1] );
709             }
710             else {
711 16         53 $last = $a1->new( $last1[0] )->until( $last2[0] );
712 16 100       74 if ( defined $last1[1] ) {
713 14         39 $tail = $last1[1]->_function2( "until", $last2[1] );
714             }
715             else {
716 2         5 $tail = undef;
717             }
718             }
719 28         78 return ($last, $tail);
720             },
721             'iterate' =>
722             sub {
723 0         0 my $self = $_[0];
724 0         0 my $parent = $self->{parent};
725 0         0 my ($last, $tail) = $parent->last;
726 0 0       0 $last = $last->iterate( @{$self->{param}} ) if ref($last);
  0         0  
727 0 0       0 $tail = $tail->_function( 'iterate', @{$self->{param}} ) if ref($tail);
  0         0  
728 0         0 my $more;
729 0 0       0 ($last, $more) = $last->last if ref($last);
730 0 0       0 $tail = $tail->_function2( 'union', $more ) if defined $more;
731 0         0 return ($last, $tail);
732             },
733             'offset' =>
734             sub {
735 158         224 my $self = $_[0];
736 158         449 my ($last, $tail) = $self->{parent}->last;
737 158         220 $last = $last->offset( @{$self->{param}} );
  158         449  
738 158         262 $tail = $tail->_function( 'offset', @{$self->{param}} );
  158         460  
739 158         215 my $more;
740 158         891 ($last, $more) = $last->last;
741 158 50       637 $tail = $tail->_function2( 'union', $more ) if defined $more;
742 158         286 return ($last, $tail);
743             },
744             'quantize' =>
745             sub {
746 1028         1205 my $self = $_[0];
747 1028         2293 my @max = $self->{parent}->max_a;
748 1028 100 100     4217 if (( $max[0] == $neg_inf ) || ( $max[0] == $inf )) {
749 677         2141 return ( $self->new( $max[0] ) , $self->copy );
750             }
751 351         1052 my $last = $self->new( $max[0] )->quantize( @{$self->{param}} );
  351         965  
752 351 100       1634 if ($max[1]) { # open_end
753 107 50       396 if ( $last->min <= $max[0] ) {
754 107         319 $last = $self->new( $last->min - 1e-9 )->quantize( @{$self->{param}} );
  107         312  
755             }
756             }
757 351         988 return ( $last, $self->{parent}->
758             _function2( 'intersection', $last->complement )->
759 351         1828 _function( 'quantize', @{$self->{param}} ) );
760             },
761             'tolerance' =>
762             sub {
763 1         3 my $self = $_[0];
764 1         4 my ($last, $tail) = $self->{parent}->last;
765 1         3 $last = $last->tolerance( @{$self->{param}} );
  1         3  
766 1         2 $tail = $tail->tolerance( @{$self->{param}} );
  1         3  
767 1         9 return ($last, $tail);
768             },
769 11         18919 ); # %_last
770             } # BEGIN
771              
772             sub first {
773 2322     2322 1 11338 my $self = $_[0];
774 2322 100       4900 unless ( exists $self->{first} ) {
775 2223 50       4129 $self->trace_open(title=>"first") if $TRACE;
776 2223 100       4078 if ( $self->{too_complex} ) {
777 1666         2255 my $method = $self->{method};
778             # warn "method $method ". ( exists $_first{$method} ? "exists" : "does not exist" );
779 1666 50       2989 if ( exists $_first{$method} ) {
780 1666         3929 @{$self->{first}} = $_first{$method}->($self);
  1666         5250  
781             }
782             else {
783 0         0 my $redo = $self->{parent}->$method ( @{ $self->{param} } );
  0         0  
784 0         0 @{$self->{first}} = $redo->first;
  0         0  
785             }
786             }
787             else {
788 557         1977 return $self->SUPER::first;
789             }
790             }
791 1765 100       4783 return wantarray ? @{$self->{first}} : $self->{first}[0];
  1750         4335  
792             }
793              
794              
795             sub last {
796 1688     1688 1 13021 my $self = $_[0];
797 1688 100       4329 unless ( exists $self->{last} ) {
798 1653 50       3099 $self->trace(title=>"last") if $TRACE;
799 1653 100       2670 if ( $self->{too_complex} ) {
800 1344         1748 my $method = $self->{method};
801 1344 50       2590 if ( exists $_last{$method} ) {
802 1344         3344 @{$self->{last}} = $_last{$method}->($self);
  1344         3983  
803             }
804             else {
805 0         0 my $redo = $self->{parent}->$method ( @{ $self->{param} } );
  0         0  
806 0         0 @{$self->{last}} = $redo->last;
  0         0  
807             }
808             }
809             else {
810 309         1036 return $self->SUPER::last;
811             }
812             }
813 1379 100       3548 return wantarray ? @{$self->{last}} : $self->{last}[0];
  1357         3453  
814             }
815              
816              
817             # offset: offsets subsets
818             sub offset {
819 3045     3045 1 4095 my $self = shift;
820 3045 100       6518 if ($self->{too_complex}) {
821 1036         1944 return $self->_function( 'offset', @_ );
822             }
823 2009 50       3400 $self->trace_open(title=>"offset") if $TRACE;
824              
825 2009         2184 my @a;
826 2009         6313 my %param = @_;
827 2009         5721 my $b1 = $self->empty_set();
828 2009         2383 my ($interval, $ia, $i);
829 2009 100       4292 $param{mode} = 'offset' unless $param{mode};
830              
831 2009 50       8434 unless (ref($param{value}) eq 'ARRAY') {
832 0         0 $param{value} = [0 + $param{value}, 0 + $param{value}];
833             }
834 2009 50       4198 $param{unit} = 'one' unless $param{unit};
835 2009         1795 my $parts = ($#{$param{value}}) / 2;
  2009         4092  
836 2009         3688 my $sub_unit = $Set::Infinite::Arithmetic::subs_offset2{$param{unit}};
837 2009         2772 my $sub_mode = $Set::Infinite::Arithmetic::_MODE{$param{mode}};
838              
839 2009 50       3657 carp "unknown unit $param{unit} for offset()" unless defined $sub_unit;
840 2009 50       3562 carp "unknown mode $param{mode} for offset()" unless defined $sub_mode;
841              
842 2009         1869 my ($j);
843 2009         2077 my ($cmp, $this, $next, $ib, $part, $open_begin, $open_end, $tmp);
844              
845 0         0 my @value;
846 2009         3679 foreach $j (0 .. $parts) {
847 2011         7973 push @value, [ $param{value}[$j+$j], $param{value}[$j+$j + 1] ];
848             }
849              
850 2009         2992 foreach $interval ( @{ $self->{list} } ) {
  2009         4335  
851 2390         3300 $ia = $interval->{a};
852 2390         2603 $ib = $interval->{b};
853 2390         2755 $open_begin = $interval->{open_begin};
854 2390         2612 $open_end = $interval->{open_end};
855 2390         3241 foreach $j (0 .. $parts) {
856             # print " [ofs($ia,$ib)] ";
857 2394         2645 ($this, $next) = $sub_mode->( $sub_unit, $ia, $ib, @{$value[$j]} );
  2394         6930  
858 2394 100       9550 next if ($this > $next); # skip if a > b
859 2393 100       4392 if ($this == $next) {
860             # TODO: fix this
861 2367         2423 $open_end = $open_begin;
862             }
863 2393         11670 push @a, { a => $this , b => $next ,
864             open_begin => $open_begin , open_end => $open_end };
865             } # parts
866             } # self
867 2009         4091 @a = sort { $a->{a} <=> $b->{a} } @a;
  496         1074  
868 2009         3168 $b1->{list} = \@a; # change data
869 2009 50       4170 $self->trace_close( arg => $b1 ) if $TRACE;
870 2009 50       7369 $b1 = $b1->fixtype if $self->{fixtype};
871 2009         10374 return $b1;
872             }
873              
874              
875             sub is_null {
876 1702 100   1702 1 7610 $_[0]->{too_complex} ? 0 : $_[0]->SUPER::is_null;
877             }
878              
879              
880             sub is_too_complex {
881 351 100   351 1 1258 $_[0]->{too_complex} ? 1 : 0;
882             }
883              
884              
885             # shows how a 'compacted' set looks like after quantize
886             sub _quantize_span {
887 2317     2317   2705 my $self = shift;
888 2317         3108 my %param = @_;
889 2317 50       4407 $self->trace_open(title=>"_quantize_span") if $TRACE;
890 2317         2599 my $res;
891 2317 100       3921 if ($self->{too_complex}) {
892 1525         2000 $res = $self->{parent};
893 1525 100       3251 if ($self->{method} ne 'quantize') {
894 697         2514 $self->trace( title => "parent is a ". $self->{method} );
895 697 100       2126 if ( $self->{method} eq 'union' ) {
    100          
896 7         44 my $arg0 = $self->{parent}[0]->_quantize_span(%param);
897 7         27 my $arg1 = $self->{parent}[1]->_quantize_span(%param);
898 7         20 $res = $arg0->union( $arg1 );
899             }
900             elsif ( $self->{method} eq 'intersection' ) {
901 4         17 my $arg0 = $self->{parent}[0]->_quantize_span(%param);
902 4         16 my $arg1 = $self->{parent}[1]->_quantize_span(%param);
903 4         11 $res = $arg0->intersection( $arg1 );
904             }
905              
906             # TODO: other methods
907             else {
908 686         922 $res = $self; # ->_function( "_quantize_span", %param );
909             }
910 697 50       1219 $self->trace_close( arg => $res ) if $TRACE;
911 697         1370 return $res;
912             }
913              
914             # $res = $self->{parent};
915 828 100       1760 if ($res->{too_complex}) {
916 2         8 $res->trace( title => "parent is complex" );
917 2         23 $res = $res->_quantize_span( %param );
918 2         4 $res = $res->quantize( @{$self->{param}} )->_quantize_span( %param );
  2         9  
919             }
920             else {
921             $res = $res->iterate (
922             sub {
923 1010     1010   1495 $_[0]->quantize( @{$self->{param}} )->span;
  1010         2614  
924             }
925 826         3761 );
926             }
927             }
928             else {
929 792     936   3344 $res = $self->iterate ( sub { $_[0] } );
  936         2418  
930             }
931 1620 50       6496 $self->trace_close( arg => $res ) if $TRACE;
932 1620         3589 return $res;
933             }
934              
935              
936              
937             BEGIN {
938              
939             %_backtrack = (
940              
941             until => sub {
942 145         195 my ($self, $arg) = @_;
943 145         638 my $before = $self->{parent}[0]->intersection( $neg_inf, $arg->min )->max;
944 145 100       2643 $before = $arg->min unless $before;
945 145         711 my $after = $self->{parent}[1]->intersection( $arg->max, $inf )->min;
946 145 100       4084 $after = $arg->max unless $after;
947 145         501 return $arg->new( $before, $after );
948             },
949              
950             iterate => sub {
951 6         11 my ($self, $arg) = @_;
952              
953 6 100       21 if ( defined $self->{backtrack_callback} )
954             {
955 2         55 return $arg = $self->new( $self->{backtrack_callback}->( $arg ) );
956             }
957              
958 4         22 my $before = $self->{parent}->intersection( $neg_inf, $arg->min )->max;
959 4 100       200 $before = $arg->min unless $before;
960 4         20 my $after = $self->{parent}->intersection( $arg->max, $inf )->min;
961 4 50       284 $after = $arg->max unless $after;
962              
963 4         16 return $arg->new( $before, $after );
964             },
965              
966             quantize => sub {
967 880         1054 my ($self, $arg) = @_;
968 880 100       1694 if ($arg->{too_complex}) {
969 2         6 return $arg;
970             }
971             else {
972 878         945 return $arg->quantize( @{$self->{param}} )->_quantize_span;
  878         2531  
973             }
974             },
975              
976             offset => sub {
977 1256         1617 my ($self, $arg) = @_;
978             # offset - apply offset with negative values
979 1256         1174 my %tmp = @{$self->{param}};
  1256         4026  
980 1256         1545 my @values = sort @{$tmp{value}};
  1256         9811  
981              
982 1256         5898 my $backtrack_arg2 = $arg->offset(
983             unit => $tmp{unit},
984             mode => $tmp{mode},
985             value => [ - $values[-1], - $values[0] ] );
986 1256         3871 return $arg->union( $backtrack_arg2 ); # fixes some problems with 'begin' mode
987             },
988              
989 11     11   28222 );
990             }
991              
992              
993             sub _backtrack {
994 3238     3238   4703 my ($self, $method, $arg) = @_;
995 3238 100       7856 return $self->$method ($arg) unless $self->{too_complex};
996              
997 2358 50       3958 $self->trace_open( title => 'backtrack '.$self->{method} ) if $TRACE;
998              
999 2358         2294 $backtrack_depth++;
1000 2358 50       4507 if ( $backtrack_depth > $max_backtrack_depth ) {
1001 0         0 carp ( __PACKAGE__ . ": Backtrack too deep " .
1002             "(more than $max_backtrack_depth levels)" );
1003             }
1004              
1005 2358 100       6294 if (exists $_backtrack{ $self->{method} } ) {
1006 2287         5083 $arg = $_backtrack{ $self->{method} }->( $self, $arg );
1007             }
1008              
1009 2358         4479 my $result;
1010 2358 100       5393 if ( ref($self->{parent}) eq 'ARRAY' ) {
1011             # has 2 parents (intersection, union, until)
1012              
1013 211         270 my ( $result1, $result2 ) = @{$self->{parent}};
  211         475  
1014 211 50       827 $result1 = $result1->_backtrack( $method, $arg )
1015             if $result1->{too_complex};
1016 211 100       766 $result2 = $result2->_backtrack( $method, $arg )
1017             if $result2->{too_complex};
1018              
1019 211         428 $method = $self->{method};
1020 211 100 66     883 if ( $result1->{too_complex} || $result2->{too_complex} ) {
1021 169         416 $result = $result1->_function2( $method, $result2 );
1022             }
1023             else {
1024 42         130 $result = $result1->$method ($result2);
1025             }
1026             }
1027             else {
1028             # has 1 parent and parameters (offset, select, quantize, iterate)
1029              
1030 2147         9831 $result = $self->{parent}->_backtrack( $method, $arg );
1031 2147         3998 $method = $self->{method};
1032 2147         2428 $result = $result->$method ( @{$self->{param}} );
  2147         6393  
1033             }
1034              
1035 2358         3730 $backtrack_depth--;
1036 2358 50       4325 $self->trace_close( arg => $result ) if $TRACE;
1037 2358         9751 return $result;
1038             }
1039              
1040              
1041             sub intersects {
1042 3433     3433 1 5799 my $a1 = shift;
1043 3433 100       13157 my $b1 = (ref ($_[0]) eq ref($a1) ) ? shift : $a1->new(@_);
1044              
1045 3433         8378 $a1->trace(title=>"intersects");
1046 3433 100       7400 if ($a1->{too_complex}) {
1047 8         50 $a1 = $a1->_backtrack('intersection', $b1 );
1048             } # don't put 'else' here
1049 3433 100       6243 if ($b1->{too_complex}) {
1050 33         76 $b1 = $b1->_backtrack('intersection', $a1);
1051             }
1052 3433 100 100     13856 if (($a1->{too_complex}) or ($b1->{too_complex})) {
1053 8         124 return undef; # we don't know the answer!
1054             }
1055 3425         10218 return $a1->SUPER::intersects( $b1 );
1056             }
1057              
1058              
1059             sub iterate {
1060 1634     1634 1 4344 my $self = shift;
1061 1634         1695 my $callback = shift;
1062 1634 50       4111 die "First argument to iterate() must be a subroutine reference"
1063             unless ref( $callback ) eq 'CODE';
1064 1634         1482 my $backtrack_callback;
1065 1634 100 66     4075 if ( @_ && $_[0] eq 'backtrack_callback' )
1066             {
1067 2         6 ( undef, $backtrack_callback ) = ( shift, shift );
1068             }
1069 1634         1531 my $set;
1070 1634 100       2911 if ($self->{too_complex}) {
1071 6 50       20 $self->trace(title=>"iterate:backtrack") if $TRACE;
1072 6         25 $set = $self->_function( 'iterate', $callback, @_ );
1073             }
1074             else
1075             {
1076 1628 50       2969 $self->trace(title=>"iterate") if $TRACE;
1077 1628         5145 $set = $self->SUPER::iterate( $callback, @_ );
1078             }
1079 1634         2720 $set->{backtrack_callback} = $backtrack_callback;
1080             # warn "set backtrack_callback" if defined $backtrack_callback;
1081 1634         3083 return $set;
1082             }
1083              
1084              
1085             sub intersection {
1086 3162     3162 1 8793 my $a1 = shift;
1087 3162 100       7964 my $b1 = (ref ($_[0]) eq ref($a1) ) ? shift : $a1->new(@_);
1088              
1089 3162 50       6078 $a1->trace_open(title=>"intersection", arg => $b1) if $TRACE;
1090 3162 100 100     12819 if (($a1->{too_complex}) or ($b1->{too_complex})) {
1091 705         1507 my $arg0 = $a1->_quantize_span;
1092 705         1257 my $arg1 = $b1->_quantize_span;
1093 705 100 100     3223 unless (($arg0->{too_complex}) or ($arg1->{too_complex})) {
1094 20         43 my $res = $arg0->intersection( $arg1 );
1095 20 50       66 $a1->trace_close( arg => $res ) if $TRACE;
1096 20         182 return $res;
1097             }
1098             }
1099 3142 100       7494 if ($a1->{too_complex}) {
1100 601 100       2058 $a1 = $a1->_backtrack('intersection', $b1) unless $b1->{too_complex};
1101             } # don't put 'else' here
1102 3142 100       6530 if ($b1->{too_complex}) {
1103 85 100       299 $b1 = $b1->_backtrack('intersection', $a1) unless $a1->{too_complex};
1104             }
1105 3142 100 100     11917 if ( $a1->{too_complex} || $b1->{too_complex} ) {
1106 572 50       1075 $a1->trace_close( ) if $TRACE;
1107 572         1177 return $a1->_function2( 'intersection', $b1 );
1108             }
1109 2570         8213 return $a1->SUPER::intersection( $b1 );
1110             }
1111              
1112              
1113             sub intersected_spans {
1114 12     12 1 21 my $a1 = shift;
1115 12 100       53 my $b1 = ref ($_[0]) eq ref($a1) ? $_[0] : $a1->new(@_);
1116              
1117 12 100       42 if ($a1->{too_complex}) {
1118 8 100       41 $a1 = $a1->_backtrack('intersection', $b1 ) unless $b1->{too_complex};
1119             } # don't put 'else' here
1120 12 100       47 if ($b1->{too_complex}) {
1121 2 100       9 $b1 = $b1->_backtrack('intersection', $a1) unless $a1->{too_complex};
1122             }
1123              
1124 12 100 66     63 if ( ! $b1->{too_complex} && ! $a1->{too_complex} )
1125             {
1126 8         42 return $a1->SUPER::intersected_spans ( $b1 );
1127             }
1128              
1129             return $b1->iterate(
1130             sub {
1131 7     7   27 my $tmp = $a1->intersection( $_[0] );
1132 7 50       30 return $tmp unless defined $tmp->max;
1133              
1134 7         30 my $before = $a1->intersection( $neg_inf, $tmp->min )->last;
1135 7         414 my $after = $a1->intersection( $tmp->max, $inf )->first;
1136              
1137 7         512 $before = $tmp->union( $before )->first;
1138 7         66 $after = $tmp->union( $after )->last;
1139              
1140 7 100 66     115 $tmp = $tmp->union( $before )
1141             if defined $before && $tmp->intersects( $before );
1142 7 100 66     53 $tmp = $tmp->union( $after )
1143             if defined $after && $tmp->intersects( $after );
1144 7         70 return $tmp;
1145             }
1146 4         31 );
1147              
1148             }
1149              
1150              
1151             sub complement {
1152 1555     1555 1 5899 my $a1 = shift;
1153             # do we have a parameter?
1154 1555 100       3910 if (@_) {
1155 362 100       1934 my $b1 = (ref ($_[0]) eq ref($a1) ) ? shift : $a1->new(@_);
1156              
1157 362 50       755 $a1->trace_open(title=>"complement", arg => $b1) if $TRACE;
1158 362         878 $b1 = $b1->complement;
1159 362         1410 my $tmp =$a1->intersection($b1);
1160 362 50       1015 $a1->trace_close( arg => $tmp ) if $TRACE;
1161 362         1829 return $tmp;
1162             }
1163 1193 50       2811 $a1->trace_open(title=>"complement") if $TRACE;
1164 1193 100       3193 if ($a1->{too_complex}) {
1165 21 50       39 $a1->trace_close( ) if $TRACE;
1166 21         52 return $a1->_function( 'complement', @_ );
1167             }
1168 1172         3813 return $a1->SUPER::complement;
1169             }
1170              
1171              
1172             sub until {
1173 146     146 1 16065 my $a1 = shift;
1174 146 100       444 my $b1 = (ref ($_[0]) eq ref($a1) ) ? shift : $a1->new(@_);
1175              
1176 146 100 100     723 if (($a1->{too_complex}) or ($b1->{too_complex})) {
1177 35         112 return $a1->_function2( 'until', $b1 );
1178             }
1179 111         447 return $a1->SUPER::until( $b1 );
1180             }
1181              
1182              
1183             sub union {
1184 3337     3337 1 4792 my $a1 = shift;
1185 3337 100       6872 my $b1 = (ref ($_[0]) eq ref($a1) ) ? shift : $a1->new(@_);
1186            
1187 3337 50       6385 $a1->trace_open(title=>"union", arg => $b1) if $TRACE;
1188 3337 100 100     24025 if (($a1->{too_complex}) or ($b1->{too_complex})) {
1189 37 50       101 $a1->trace_close( ) if $TRACE;
1190 37 50       89 return $a1 if $b1->is_null;
1191 37 100       72 return $b1 if $a1->is_null;
1192 34         84 return $a1->_function2( 'union', $b1);
1193             }
1194 3300         12213 return $a1->SUPER::union( $b1 );
1195             }
1196              
1197              
1198             # there are some ways to process 'contains':
1199             # A CONTAINS B IF A == ( A UNION B )
1200             # - faster
1201             # A CONTAINS B IF B == ( A INTERSECTION B )
1202             # - can backtrack = works for unbounded sets
1203             sub contains {
1204 11     11 1 891 my $a1 = shift;
1205 11 50       30 $a1->trace_open(title=>"contains") if $TRACE;
1206 11 100       30 if ( $a1->{too_complex} ) {
1207             # we use intersection because it is better for backtracking
1208 4 50       20 my $b0 = (ref $_[0] eq ref $a1) ? shift : $a1->new(@_);
1209 4         11 my $b1 = $a1->intersection($b0);
1210 4 50       14 if ( $b1->{too_complex} ) {
1211 0 0       0 $b1->trace_close( arg => 'undef' ) if $TRACE;
1212 0         0 return undef;
1213             }
1214 4 0       12 $a1->trace_close( arg => ($b1 == $b0 ? 1 : 0) ) if $TRACE;
    50          
1215 4 100       15 return ($b1 == $b0) ? 1 : 0;
1216             }
1217 7         16 my $b1 = $a1->union(@_);
1218 7 50       19 if ( $b1->{too_complex} ) {
1219 0 0       0 $b1->trace_close( arg => 'undef' ) if $TRACE;
1220 0         0 return undef;
1221             }
1222 7 0       13 $a1->trace_close( arg => ($b1 == $a1 ? 1 : 0) ) if $TRACE;
    50          
1223 7 100       18 return ($b1 == $a1) ? 1 : 0;
1224             }
1225              
1226              
1227             sub min_a {
1228 11001     11001 1 12247 my $self = $_[0];
1229 11001 100       24695 return @{$self->{min}} if exists $self->{min};
  2745         7717  
1230 8256 100       17086 if ($self->{too_complex}) {
1231 957         2017 my @first = $self->first;
1232 957 50       3179 return @{$self->{min}} = $first[0]->min_a if defined $first[0];
  957         4746  
1233 0         0 return @{$self->{min}} = (undef, 0);
  0         0  
1234             }
1235 7299         20716 return $self->SUPER::min_a;
1236             };
1237              
1238              
1239             sub max_a {
1240 10458     10458 1 13260 my $self = $_[0];
1241 10458 100       22569 return @{$self->{max}} if exists $self->{max};
  2859         8422  
1242 7599 100       14046 if ($self->{too_complex}) {
1243 940         1864 my @last = $self->last;
1244 940 50       3290 return @{$self->{max}} = $last[0]->max_a if defined $last[0];
  940         4577  
1245 0         0 return @{$self->{max}} = (undef, 0);
  0         0  
1246             }
1247 6659         18096 return $self->SUPER::max_a;
1248             };
1249              
1250              
1251             sub count {
1252 2     2 1 178 my $self = $_[0];
1253             # NOTE: subclasses may return "undef" if necessary
1254 2 50       7 return $inf if $self->{too_complex};
1255 2         13 return $self->SUPER::count;
1256             }
1257              
1258              
1259             sub size {
1260 13     13 1 649 my $self = $_[0];
1261 13 100       36 if ($self->{too_complex}) {
1262 4         11 my @min = $self->min_a;
1263 4         8 my @max = $self->max_a;
1264 4 50 33     19 return undef unless defined $max[0] && defined $min[0];
1265 4         27 return $max[0] - $min[0];
1266             }
1267 9         35 return $self->SUPER::size;
1268             };
1269              
1270              
1271             sub spaceship {
1272 72     72 1 141 my ($tmp1, $tmp2, $inverted) = @_;
1273 72 50 33     381 carp "Can't compare unbounded sets"
1274             if $tmp1->{too_complex} or $tmp2->{too_complex};
1275 72         329 return $tmp1->SUPER::spaceship( $tmp2, $inverted );
1276             }
1277              
1278              
1279 0     0   0 sub _cleanup { @_ } # this subroutine is obsolete
1280              
1281              
1282             sub tolerance {
1283 3268     3268 1 3424 my $self = shift;
1284 3268         3160 my $tmp = pop;
1285 3268 50       5971 if (ref($self)) {
1286             # local
1287 3268 100       18545 return $self->{tolerance} unless defined $tmp;
1288 16 100       41 if ($self->{too_complex}) {
1289 3         7 my $b1 = $self->_function( 'tolerance', $tmp );
1290 3         4 $b1->{tolerance} = $tmp; # for max/min processing
1291 3         8 return $b1;
1292             }
1293 13         60 return $self->SUPER::tolerance( $tmp );
1294             }
1295             # class method
1296 0 0       0 __PACKAGE__->SUPER::tolerance( $tmp ) if defined($tmp);
1297 0         0 return __PACKAGE__->SUPER::tolerance;
1298             }
1299              
1300              
1301             sub _pretty_print {
1302 0     0   0 my $self = shift;
1303 0 0       0 return "$self" unless $self->{too_complex};
1304 0 0       0 return $self->{method} . "( " .
1305             ( ref($self->{parent}) eq 'ARRAY' ?
1306             $self->{parent}[0] . ' ; ' . $self->{parent}[1] :
1307             $self->{parent} ) .
1308             " )";
1309             }
1310              
1311              
1312             sub as_string {
1313 7213     7213 1 18498 my $self = shift;
1314 7213 50       17151 return ( $PRETTY_PRINT ? $self->_pretty_print : $too_complex )
    100          
1315             if $self->{too_complex};
1316 6974         20011 return $self->SUPER::as_string;
1317             }
1318              
1319              
1320 0     0     sub DESTROY {}
1321              
1322             1;
1323              
1324             __END__