File Coverage

blib/lib/Graph/Maker/FibonacciTree.pm
Criterion Covered Total %
statement 6 8 75.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 9 11 81.8


line stmt bran cond sub pod time code
1             # Copyright 2015, 2016, 2017 Kevin Ryde
2             #
3             # This file is part of Graph-Maker-Other.
4             #
5             # This file is free software; you can redistribute it and/or modify it
6             # under the terms of the GNU General Public License as published by the Free
7             # Software Foundation; either version 3, or (at your option) any later
8             # version.
9             #
10             # This file is distributed in the hope that it will be useful, but
11             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12             # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13             # for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with Graph-Maker-Other. See the file COPYING. If not, see
17             # .
18              
19             package Graph::Maker::FibonacciTree;
20 1     1   1118 use 5.004;
  1         3  
21 1     1   4 use strict;
  1         1  
  1         17  
22 1     1   139 use Graph::Maker;
  0            
  0            
23              
24             use vars '$VERSION','@ISA';
25             $VERSION = 8;
26             @ISA = ('Graph::Maker');
27              
28             # uncomment this to run the ### lines
29             # use Smart::Comments;
30              
31             sub _default_graph_maker {
32             require Graph;
33             Graph->new(@_);
34             }
35              
36             # require Math::NumSeq::FibonacciWord;
37             # my $seq = Math::NumSeq::FibonacciWord->new;
38              
39             sub init {
40             my ($self, %params) = @_;
41              
42             my $height = delete($params{'height'}) || 0;
43             my $series_reduced = delete($params{'series_reduced'}) ? 1 : 0;
44             my $leaf_reduced = delete $params{'leaf_reduced'};
45             my $graph_maker = delete($params{'graph_maker'}) || \&_default_graph_maker;
46              
47             ### FibonacciTree ...
48             ### $height
49              
50             my $graph = $graph_maker->(%params);
51              
52             $graph->set_graph_attribute
53             (name => "Fibonacci Tree height $height"
54             . ($series_reduced && $leaf_reduced ? ', series and leaf reduced' : '')
55             . ($series_reduced ? ', series reduced' : '')
56             . ($leaf_reduced ? ', leaf reduced' : ''));
57              
58             if ($height > 0) {
59             $graph->add_vertex(1);
60              
61             my @pending_n = (1);
62             my @pending_depth = (1);
63             my @pending_type = (0); # left
64             my $upto = 1;
65             my $directed = $graph->is_directed;
66              
67             my $add = sub {
68             my ($parent) = @_;
69             my $n = ++$upto;
70             $graph->add_edge($parent, $n);
71             if ($directed) { $graph->add_edge($n, $parent); }
72             return $n;
73             };
74              
75             foreach (2 .. $height) {
76             ### at: "row $_"
77             ### pending_n: join(',',@pending_n)
78             ### pending_depth: join(',',@pending_depth)
79             ### pending_type: join(',',@pending_type)
80              
81             my @new_pending_n;
82             my @new_pending_depth;
83             my @new_pending_type;
84              
85             while (@pending_n) {
86             my $parent = shift @pending_n;
87             my $depth = shift @pending_depth;
88             my $type = shift @pending_type;
89             ### under: "parent=$parent depth=$depth type=$type"
90              
91             next if $depth >= $height;
92             $depth++;
93              
94             # 0 0
95             # / \ / \
96             # d+1 0 1 d+1 0 0 d+2
97             # / \ | / \
98             # 0 1 0 d+2 0 0
99              
100             # left child
101             {
102             ### left to: "depth=$depth"
103             push @new_pending_n, $add->($parent);
104             push @new_pending_depth, $depth;
105             push @new_pending_type, 0; # non-delay
106             }
107              
108             if ($type == 0) {
109             if ($series_reduced && $depth < $height) {
110             # series reduced, step down to depth+2
111             $depth++;
112             } elsif ($leaf_reduced && $depth == $height) {
113             # leaf reduced, no node
114             next;
115             } else {
116             $type = 1;
117             }
118             } else {
119             # only single child under a delay
120             next;
121             }
122              
123             ### right to: "depth=$depth"
124             push @new_pending_n, $add->($parent);
125             push @new_pending_depth, $depth;
126             push @new_pending_type, $type; # right
127             }
128              
129             @pending_n = @new_pending_n;
130             @pending_depth = @new_pending_depth;
131             @pending_type = @new_pending_type;
132             }
133             }
134             return $graph;
135             }
136              
137             Graph::Maker->add_factory_type('fibonacci_tree' => __PACKAGE__);
138             1;
139              
140             __END__