File Coverage

blib/lib/Graph/Undirected/Hamiltonicity/Spoof.pm
Criterion Covered Total %
statement 73 73 100.0
branch 23 24 95.8
condition 11 15 73.3
subroutine 10 10 100.0
pod 4 5 80.0
total 121 127 95.2


line stmt bran cond sub pod time code
1             package Graph::Undirected::Hamiltonicity::Spoof;
2              
3 5     5   33505 use Modern::Perl;
  5         25  
  5         85  
4 5     5   604 use Carp;
  5         10  
  5         229  
5              
6 5     5   1172 use Graph::Undirected;
  5         97713  
  5         133  
7 5     5   1797 use Graph::Undirected::Hamiltonicity::Transforms qw(&add_random_edges &get_random_isomorph);
  5         10  
  5         559  
8              
9 5     5   34 use Exporter qw(import);
  5         9  
  5         3610  
10              
11             our @EXPORT_OK = qw(
12             &spoof_canonical_hamiltonian_graph
13             &spoof_known_hamiltonian_graph
14             &spoof_random_graph
15             &spoof_randomish_graph
16             );
17              
18             our %EXPORT_TAGS = ( all => \@EXPORT_OK, );
19              
20             ##############################################################################
21              
22             sub spoof_canonical_hamiltonian_graph {
23 32     32 1 9062 my ($v) = @_;
24              
25 32         77 my $last_vertex = $v - 1;
26 32         131 my @vertices = ( 0 .. $last_vertex );
27              
28 32         151 my $g = Graph::Undirected->new( vertices => \@vertices );
29 32         14260 $g->add_edge( 0, $last_vertex );
30              
31 32         17775 for ( my $i = 0; $i < $last_vertex; $i++ ) {
32 276         24037 $g->add_edge( $i, $i + 1 );
33             }
34              
35 32         2960 return $g;
36             }
37              
38             ##############################################################################
39              
40             sub spoof_known_hamiltonian_graph {
41 25     25 1 19654 my ( $v, $e ) = @_;
42              
43 25 100 66     186 croak "Please provide the number of vertices." unless defined $v and $v;
44 24 100       94 croak "A graph with 2 vertices cannot be Hamiltonian." if $v == 2;
45              
46 23   66     99 $e ||= get_random_edge_count($v);
47              
48 23 100       74 croak "The number of edges must be >= number of vertices." if $e < $v;
49              
50 22         65 my $g = spoof_canonical_hamiltonian_graph($v);
51 22         109 $g = get_random_isomorph($g);
52 22 100       160 $g = add_random_edges( $g, $e - $v ) if ( $e - $v ) > 0;
53              
54 22         110 return $g;
55             }
56              
57             ##############################################################################
58              
59             sub spoof_random_graph {
60              
61 44     44 1 16894 my ( $v, $e ) = @_;
62 44   66     124 $e //= get_random_edge_count($v);
63              
64 44         247 my $g = Graph::Undirected->new( vertices => [ 0 .. $v-1 ] );
65 44 50       19364 $g = add_random_edges( $g, $e ) if $e;
66              
67 44         117 return $g;
68             }
69              
70             ##############################################################################
71              
72             sub spoof_randomish_graph {
73              
74 22     22 1 198385 my ( $v, $e ) = @_;
75 22   66     80 $e ||= get_random_edge_count($v);
76              
77 22         60 my $g = spoof_random_graph( $v, $e );
78              
79             ### Seek out vertices with degree < 2
80             ### and add random edges to them.
81 22         37 my $edges_to_remove = 0;
82 22         64 foreach my $vertex1 ( $g->vertices() ) {
83 253         848 my $degree = $g->degree($vertex1);
84              
85 253 100       86585 next if $degree > 1;
86 33         54 my $added_edges = 0;
87 33         74 while ( $added_edges < (2 - $degree) ) {
88 50         199 my $vertex2 = int( rand($v) );
89 50 100       92 next if $vertex1 == $vertex2;
90 45 100       95 next if $g->has_edge($vertex1, $vertex2);
91 42         1553 $g->add_edge($vertex1,$vertex2);
92 42         4250 $added_edges++;
93 42         129 $edges_to_remove++;
94             }
95             }
96              
97 22         59 my $try_count = 0;
98 22         45 my $max_tries = 2 * $edges_to_remove;
99             ### Seek out vertices with degree > 2
100             ### with neighbor of degree < 3
101             ### and delete edges.
102             ### Try to delete the same number of edges,
103             ### as the random edges added.
104 22   100     91 while ( $edges_to_remove and ($try_count < $max_tries) ) {
105 72         11327 $try_count++;
106             LOOP:
107 72         186 foreach my $vertex1 ( $g->vertices() ) {
108 1000 100       195539 next if $g->degree($vertex1) < 3;
109              
110 96         27207 foreach my $vertex2 ( $g->neighbors($vertex1) ) {
111 348 100       59175 next if $g->degree($vertex2) < 3;
112 16         4220 $g->delete_edge($vertex1,$vertex2);
113 16         1395 $edges_to_remove--;
114 16         79 last LOOP;
115             }
116             }
117             }
118              
119 22 100       1055 carp "Exiting with $edges_to_remove extra edges.\n" if $edges_to_remove;
120              
121 22         90 return $g;
122             }
123              
124             ##############################################################################
125              
126             sub get_random_edge_count {
127 34     34 0 69 my ( $v ) = @_;
128              
129 34         135 my %h = ( 0 => 0, 1 => 0, 2 => 1, 3 => 3, 4 => 4 );
130 34         97 my $e = $h{$v};
131 34 100       103 return $e if defined $e;
132              
133 28         71 my $max_edges = ( $v * $v - $v ) / 2;
134 28         73 my $range = $max_edges - 2 * $v + 2;
135 28         65 $e = int( rand( $range ) ) + $v;
136              
137 28         103 return $e;
138             }
139              
140             ##############################################################################
141              
142             1; # End of Graph::Undirected::Hamiltonicity::Spoof