File Coverage

blib/lib/Algorithm/X/ExactCoverProblem.pm
Criterion Covered Total %
statement 54 61 88.5
branch 19 20 95.0
condition 3 3 100.0
subroutine 10 11 90.9
pod 0 7 0.0
total 86 102 84.3


line stmt bran cond sub pod time code
1             package Algorithm::X::ExactCoverProblem;
2              
3 3     3   236797 use strict;
  3         8  
  3         101  
4 3     3   42 use warnings;
  3         5  
  3         173  
5              
6             require 5.06.0;
7              
8 3     3   16 use Carp;
  3         4  
  3         1946  
9              
10             # Constructor with width and secondary_columns
11             sub new {
12 22     22 0 573060 my ($class, $width, $rows_ref, $secondary_columns) = @_;
13 22 100       58 $width = 0 unless defined $width;
14 22 100       51 $secondary_columns = 0 unless defined $secondary_columns;
15              
16 22         85 my $self = bless {
17             rows_ => [],
18             width_ => $width,
19             secondary_columns_ => $secondary_columns,
20             }, $class;
21            
22 22 50       54 if ($secondary_columns > $width) {
23 0         0 croak("secondary_columns > width");
24             }
25            
26 22 100       46 if (defined $rows_ref) {
27 8         13 foreach my $row (@$rows_ref) {
28 8         39 $self->add_row($row);
29             }
30             }
31            
32 18         67 return $self;
33             }
34              
35             # Factory method for a dense ExactCoverProblem (binary matrix)
36             sub dense {
37 12     12 0 26090 my ($class, $bit_rows_ref, $secondary_columns) = @_;
38            
39 12 100       37 if (!@$bit_rows_ref) {
40 1         2 return $class->new(0, undef, $secondary_columns);
41             }
42              
43 11         16 my $width = scalar @{$bit_rows_ref->[0]};
  11         21  
44 11         31 my $problem = $class->new($width, undef, $secondary_columns);
45              
46 11         24 foreach my $bits (@$bit_rows_ref) {
47 15 100       50 if (scalar @$bits != $width) {
48 1         17 croak("rows have different lengths");
49             }
50            
51 13         19 my @row;
52 13         44 for (my $i = 0; $i < @$bits; ++$i) {
53 12 100 100     45 if ($bits->[$i] != 0 && $bits->[$i] != 1) {
54 1         11 croak("dense matrix must contain only 0s and 1s");
55             }
56 11 100       37 push @row, $i if $bits->[$i];
57             }
58 12         32 $problem->add_row(\@row);
59             }
60              
61 8         42 return $problem;
62             }
63              
64             # Accessors
65             sub width {
66 14     14 0 34 my ($self) = @_;
67 14         104 return $self->{width_};
68             }
69              
70             sub rows {
71 10     10 0 19 my ($self) = @_;
72 10         48 return $self->{rows_};
73             }
74              
75             sub secondary_columns {
76 6     6 0 15 my ($self) = @_;
77 6         25 return $self->{secondary_columns_};
78             }
79              
80             sub add_row {
81 20     20 0 34 my ($self, $row_ref) = @_;
82            
83 20         48 my @row = sort { $a <=> $b } @$row_ref;
  2         11  
84 20         33 foreach my $x (@row) {
85 12 100       47 if ($x >= $self->{width_}) {
86 3         53 croak("column out of range");
87             }
88             }
89              
90 17         41 for (my $i = 1; $i < @row; ++$i) {
91 2 100       9 if ($row[$i - 1] == $row[$i]) {
92 1         8 croak("duplicate columns");
93             }
94             }
95              
96 16         23 push @{$self->{rows_}}, \@row;
  16         83  
97             }
98              
99             # Override stringification
100             use overload
101 3     3   3270 '""' => \&stringify;
  3         5023  
  3         26  
102              
103             sub stringify {
104 0     0 0   my ($self) = @_;
105 0           my $output = $self->width() . ' ' . $self->secondary_columns() . "\n";
106 0           foreach my $row (@{$self->rows()}) {
  0            
107 0           $output .= join(' ', @$row) . "\n";
108             }
109 0           return $output;
110             }
111              
112             1;
113