File Coverage

blib/lib/Algorithm/X/LinkedMatrix.pm
Criterion Covered Total %
statement 71 89 79.7
branch 5 8 62.5
condition 2 3 66.6
subroutine 17 19 89.4
pod 0 15 0.0
total 95 134 70.9


line stmt bran cond sub pod time code
1             package Algorithm::X::LinkedMatrix;
2              
3 2     2   91440 use strict;
  2         3  
  2         63  
4 2     2   7 use warnings;
  2         3  
  2         127  
5              
6             require 5.06.0;
7              
8 2     2   9 use Carp;
  2         4  
  2         118  
9 2     2   458 use Algorithm::X::ExactCoverProblem;
  2         8  
  2         1906  
10              
11             sub new {
12 6     6 0 18 my ($class, $problem) = @_;
13              
14 6         27 my $self = {
15             col_ids => [],
16             sizes => [(0) x $problem->width()],
17             nodes => [],
18             };
19 6         18 bless $self, $class;
20              
21 6         33 my $root = $self->create_node(~0, ~0);
22 6 50       33 croak "Root ID mismatch" unless $root == $self->root_id();
23              
24 6         21 for my $x (0 .. $problem->width() - 1) {
25 6         17 my $id = $self->create_node($x, ~0);
26 6         16 $self->{col_ids}[$x] = $id;
27 6 50       20 if ($x >= $problem->secondary_columns()) {
28 6         15 $self->{nodes}[$id]{r} = $root;
29 6         19 $self->{nodes}[$id]{l} = $self->L($root);
30 6         18 $self->{nodes}[$self->L($root)]->{r} = $id;
31 6         21 $self->{nodes}[$root]->{l} = $id;
32             }
33             }
34              
35 6         12 for my $y (0 .. $#{$problem->rows()}) {
  6         22  
36 4         13 $self->add_row($y, $problem->rows()->[$y]);
37             }
38              
39 6         26 return $self;
40             }
41              
42             sub add_row {
43 4     4 0 12 my ($self, $y, $xs) = @_;
44              
45 4         34 my $first_id = 0;
46              
47 4         14 for my $x (@$xs) {
48 3         11 my $id = $self->create_node($x, $y);
49 3         12 $self->{nodes}[$id]{d} = $self->C($id);
50 3         10 $self->{nodes}[$id]{u} = $self->U($self->C($id));
51 3         10 $self->{nodes}[$self->U($self->C($id))]->{d} = $id;
52 3         11 $self->{nodes}[$self->C($id)]->{u} = $id;
53 3         6 $self->{sizes}[$x]++;
54              
55 3 100       11 if ($first_id == 0) {
56 2         6 $first_id = $id;
57              
58             } else {
59 1         3 $self->{nodes}[$id]{r} = $first_id;
60 1         4 $self->{nodes}[$id]{l} = $self->L($first_id);
61 1         3 $self->{nodes}[$self->L($first_id)]->{r} = $id;
62 1         4 $self->{nodes}[$first_id]->{l} = $id;
63             }
64             }
65             }
66              
67             sub cover_column {
68 0     0 0 0 my ($self, $c) = @_;
69 0         0 $c = $self->C($c);
70              
71 0         0 $self->{nodes}[$self->L($c)]->{r} = $self->R($c);
72 0         0 $self->{nodes}[$self->R($c)]->{l} = $self->L($c);
73            
74 0         0 for (my $i = $self->D($c); $i != $c; $i = $self->D($i)) {
75 0         0 for (my $j = $self->R($i); $j != $i; $j = $self->R($j)) {
76 0         0 $self->{nodes}[$self->U($j)]->{d} = $self->D($j);
77 0         0 $self->{nodes}[$self->D($j)]->{u} = $self->U($j);
78 0         0 $self->{sizes}[$self->X($j)]--;
79             }
80             }
81             }
82              
83             sub uncover_column {
84 0     0 0 0 my ($self, $c) = @_;
85 0         0 $c = $self->C($c);
86            
87 0         0 for (my $i = $self->U($c); $i != $c; $i = $self->U($i)) {
88 0         0 for (my $j = $self->L($i); $j != $i; $j = $self->L($j)) {
89 0         0 $self->{nodes}[$self->U($j)]->{d} = $j;
90 0         0 $self->{nodes}[$self->D($j)]->{u} = $j;
91 0         0 $self->{sizes}[$self->X($j)]++;
92             }
93             }
94 0         0 $self->{nodes}[$self->L($c)]->{r} = $c;
95 0         0 $self->{nodes}[$self->R($c)]->{l} = $c;
96             }
97              
98             sub create_node {
99 15     15 0 35 my ($self, $x, $y) = @_;
100              
101 15 50 66     34 croak "Invalid node creation" unless $x <= $self->width() || $x == ~0;
102 15         28 my $id = scalar @{$self->{nodes}};
  15         28  
103 15         33 push @{$self->{nodes}}, { id => $id, x => $x, y => $y, l => $id, r => $id, u => $id, d => $id };
  15         170  
104 15         33 return $id;
105             }
106              
107 15     15 0 31 sub width { my ($self) = @_; return scalar @{$self->{col_ids}} }
  15         67  
  15         114  
108 12     12 0 64 sub root_id { return 0 }
109 25     25 0 52 sub X { my ($self, $id) = @_; return $self->{nodes}[$id]{x}; } # column id
  25         105  
110 3     3 0 10 sub Y { my ($self, $id) = @_; return $self->{nodes}[$id]{y}; } # row id
  3         18  
111 6     6 0 3279 sub S { my ($self, $id) = @_; return $self->{sizes}[$self->X($id)]; } # node count in same column
  6         25  
112 17     17 0 36 sub C { my ($self, $id) = @_; return $self->{col_ids}[$self->X($id)]; } # last node in same column
  17         47  
113 25     25 0 5243 sub L { my ($self, $id) = @_; return $self->{nodes}[$id]{l}; } # left node
  25         122  
114 17     17 0 53 sub R { my ($self, $id) = @_; return $self->{nodes}[$id]{r}; } # right node
  17         82  
115 16     16 0 45 sub U { my ($self, $id) = @_; return $self->{nodes}[$id]{u}; } # upward node
  16         75  
116 13     13 0 45 sub D { my ($self, $id) = @_; return $self->{nodes}[$id]{d}; } # downward node
  13         66  
117              
118             1;
119