line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Algorithm::BitVector; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
#!/usr/bin/perl -w |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
#------------------------------------------------------------------------------------ |
6
|
|
|
|
|
|
|
# Copyright (c) 2018 Avinash Kak. All rights reserved. This program is free |
7
|
|
|
|
|
|
|
# software. You may modify and/or distribute it under the same terms as Perl itself. |
8
|
|
|
|
|
|
|
# This copyright notice must remain attached to the file. |
9
|
|
|
|
|
|
|
# |
10
|
|
|
|
|
|
|
# Algorithm::BitVector is a Perl module for creating a memory efficient packed |
11
|
|
|
|
|
|
|
# representation of bit arrays and for logical and numerical operations on such |
12
|
|
|
|
|
|
|
# arrays. |
13
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------------- |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
#use 5.10.0; |
16
|
1
|
|
|
1
|
|
61744
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
28
|
|
17
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
24
|
|
18
|
1
|
|
|
1
|
|
5
|
use Carp; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
112
|
|
19
|
1
|
|
|
1
|
|
7
|
use List::Util qw(pairmap min max reduce any); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
136
|
|
20
|
1
|
|
|
1
|
|
7469
|
use Math::BigInt; |
|
1
|
|
|
|
|
27535
|
|
|
1
|
|
|
|
|
5
|
|
21
|
1
|
|
|
1
|
|
26238
|
use Math::Random; |
|
1
|
|
|
|
|
6898
|
|
|
1
|
|
|
|
|
133
|
|
22
|
1
|
|
|
1
|
|
9
|
use Fcntl 'SEEK_CUR'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
166
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
our $VERSION = '1.26'; |
25
|
|
|
|
|
|
|
|
26
|
1
|
|
|
|
|
8
|
use overload '+' => '_join', |
27
|
|
|
|
|
|
|
'""' => '_str', |
28
|
|
|
|
|
|
|
'0+' => '_int', |
29
|
|
|
|
|
|
|
'~' => '_invert', |
30
|
|
|
|
|
|
|
'|' => '_or', |
31
|
|
|
|
|
|
|
'&' => '_and', |
32
|
|
|
|
|
|
|
'^' => '_xor', |
33
|
|
|
|
|
|
|
'<=>' => '_compare', |
34
|
|
|
|
|
|
|
'<<' => '_lshift', |
35
|
|
|
|
|
|
|
'>>' => '_rshift', |
36
|
|
|
|
|
|
|
'<>' => '_iter', |
37
|
1
|
|
|
1
|
|
9
|
'fallback' => 1; |
|
1
|
|
|
|
|
7
|
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub _readblock { |
40
|
0
|
|
|
0
|
|
0
|
my $blocksize = shift; |
41
|
0
|
|
|
|
|
0
|
my $bitvector = shift; |
42
|
0
|
|
|
|
|
0
|
my $block; |
43
|
|
|
|
|
|
|
my $more_to_read; |
44
|
0
|
|
|
|
|
0
|
my $i = 0; |
45
|
0
|
|
|
|
|
0
|
my $byte_as_bits; |
46
|
0
|
|
|
|
|
0
|
my $bitstring = ''; |
47
|
0
|
|
|
|
|
0
|
while ( $i < $blocksize / 8 ) { |
48
|
0
|
|
|
|
|
0
|
$i++; |
49
|
0
|
|
|
|
|
0
|
my $num_bytes_read = sysread($bitvector->{FILEIN}, my $byte, 1); |
50
|
0
|
0
|
|
|
|
0
|
unless ($num_bytes_read) { |
51
|
0
|
0
|
|
|
|
0
|
if (length($bitstring) < $blocksize) { |
52
|
0
|
|
|
|
|
0
|
$bitvector->{more_to_read} = 0; |
53
|
0
|
|
|
|
|
0
|
$more_to_read = 0; |
54
|
|
|
|
|
|
|
} |
55
|
0
|
|
|
|
|
0
|
return $bitstring; |
56
|
|
|
|
|
|
|
} else { |
57
|
0
|
|
|
|
|
0
|
my $bits_as_string = sprintf "%vb", $byte; |
58
|
0
|
|
|
|
|
0
|
$bits_as_string = '0' x (8 - length($bits_as_string)) . $bits_as_string; |
59
|
0
|
|
|
|
|
0
|
$bitstring .= $bits_as_string; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
} |
62
|
0
|
|
|
|
|
0
|
my $file_pos = tell $bitvector->{FILEIN}; |
63
|
|
|
|
|
|
|
# peek at the next byte; moves file position only if a |
64
|
|
|
|
|
|
|
# byte is read |
65
|
0
|
|
|
|
|
0
|
my $num_bytes_read = sysread($bitvector->{FILEIN}, my $next_byte, 1); |
66
|
0
|
0
|
|
|
|
0
|
if ($num_bytes_read) { |
67
|
|
|
|
|
|
|
# pretend we never read the byte |
68
|
0
|
|
|
|
|
0
|
sysseek $bitvector->{FILEIN}, $file_pos - 1, SEEK_CUR; |
69
|
|
|
|
|
|
|
} else { |
70
|
0
|
|
|
|
|
0
|
$bitvector->{more_to_read} = 0; |
71
|
|
|
|
|
|
|
} |
72
|
0
|
|
|
|
|
0
|
return $bitstring; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
# Constructor: |
76
|
|
|
|
|
|
|
sub new { |
77
|
3
|
|
|
3
|
0
|
102
|
my ($class, %args) = @_; |
78
|
3
|
|
|
|
|
11
|
my @params = keys %args; |
79
|
3
|
50
|
|
|
|
9
|
croak "\nYou have used a wrong name for a keyword argument " . |
80
|
|
|
|
|
|
|
"--- perhaps a misspelling\n" |
81
|
|
|
|
|
|
|
if _check_for_illegal_params(@params) == 0; |
82
|
|
|
|
|
|
|
my $self = { |
83
|
|
|
|
|
|
|
filename => $args{filename}, |
84
|
|
|
|
|
|
|
size => $args{size}, |
85
|
|
|
|
|
|
|
intVal => $args{intVal}, |
86
|
|
|
|
|
|
|
bitlist => $args{bitlist}, |
87
|
|
|
|
|
|
|
bitstring => $args{bitstring}, |
88
|
|
|
|
|
|
|
hexstring => $args{hexstring}, |
89
|
|
|
|
|
|
|
textstring => $args{textstring}, |
90
|
3
|
|
|
|
|
28
|
}; |
91
|
3
|
|
|
|
|
7
|
bless $self, $class; |
92
|
3
|
50
|
|
|
|
60
|
if ( $self->{filename} ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
93
|
|
|
|
|
|
|
die "When using the `filename' option in the constructor call, you cannot use any " . |
94
|
|
|
|
|
|
|
"other option at the same time: $!" |
95
|
|
|
|
|
|
|
if $self->{intVal} or $self->{size} or $self->{bitlist} |
96
|
0
|
0
|
0
|
|
|
0
|
or $self->{bitstring} or $self->{hexstring} or $self->{textstring}; |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
97
|
0
|
0
|
|
|
|
0
|
open $self->{FILEIN}, "< $self->{filename}" |
98
|
|
|
|
|
|
|
or die "unable to open file $self->{filename}: $!"; |
99
|
0
|
|
|
|
|
0
|
$self->{more_to_read} = 1; |
100
|
0
|
|
|
|
|
0
|
return $self; |
101
|
|
|
|
|
|
|
} elsif ( defined $self->{intVal} ) { |
102
|
|
|
|
|
|
|
die "When using the `intVal' option in the constructor call, you CANNOT use `filename', " . |
103
|
|
|
|
|
|
|
"`bitlist', 'bitstring', `hexstring', or `textstring' options: $!" |
104
|
|
|
|
|
|
|
if $self->{filename} or $self->{bitlist} or $self->{bitstring} |
105
|
1
|
50
|
33
|
|
|
16
|
or $self->{hexstring} or $self->{textstring}; |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
106
|
1
|
50
|
33
|
|
|
7
|
if ($self->{intVal} == 0 && ! defined $self->{size}) { |
107
|
0
|
|
|
|
|
0
|
$self->{bitlist} = [0]; |
108
|
0
|
|
|
|
|
0
|
$self->{size} = 1; |
109
|
|
|
|
|
|
|
} else { |
110
|
1
|
|
|
|
|
6
|
my @bitarray; |
111
|
|
|
|
|
|
|
# if (ref($self->{intVal}) eq 'Math::BigInt') { |
112
|
1
|
50
|
33
|
|
|
7
|
if (ref($self->{intVal}) eq 'Math::BigInt' && ! defined $self->{size}) { |
|
|
50
|
33
|
|
|
|
|
113
|
0
|
|
|
|
|
0
|
my $bitlist_str = $self->{intVal}->as_bin(); |
114
|
0
|
|
|
|
|
0
|
$bitlist_str =~ s/^0b//; |
115
|
0
|
|
|
|
|
0
|
@bitarray = split //, $bitlist_str; |
116
|
|
|
|
|
|
|
} elsif (ref($self->{intVal}) eq 'Math::BigInt' && defined $self->{size}) { #new<<<<<<<<<<<<< |
117
|
0
|
|
|
|
|
0
|
my $bitlist_str = $self->{intVal}->as_bin(); |
118
|
0
|
|
|
|
|
0
|
$bitlist_str =~ s/^0b//; |
119
|
|
|
|
|
|
|
croak "\nThe value specified for size must be at least as large as for the " . |
120
|
|
|
|
|
|
|
"smallest bitvector possible for the intVal integer: $!" |
121
|
0
|
0
|
|
|
|
0
|
if $self->{size} < length $bitlist_str; |
122
|
0
|
|
|
|
|
0
|
@bitarray = split //, $bitlist_str; |
123
|
0
|
|
|
|
|
0
|
my $n = $self->{size} - @bitarray; |
124
|
0
|
|
|
|
|
0
|
my $extended_bitlist_str = '0' x $n . $bitlist_str; |
125
|
0
|
|
|
|
|
0
|
@bitarray = split //, $extended_bitlist_str; |
126
|
|
|
|
|
|
|
} else { |
127
|
1
|
|
|
|
|
9
|
my $bitlist_str = sprintf "%b", $self->{intVal}; |
128
|
1
|
50
|
|
|
|
3
|
if (defined $self->{size}) { |
129
|
|
|
|
|
|
|
croak "\nThe value specified for size must be at least as large as for the " . |
130
|
|
|
|
|
|
|
"smallest bitvector possible for the intVal integer: $!" |
131
|
0
|
0
|
|
|
|
0
|
if $self->{size} < length $bitlist_str; |
132
|
0
|
|
|
|
|
0
|
my $n = $self->{size} - length $bitlist_str; |
133
|
0
|
|
|
|
|
0
|
my $extended_bitlist_str = '0' x $n . $bitlist_str; |
134
|
0
|
|
|
|
|
0
|
@bitarray = split //, $extended_bitlist_str; |
135
|
|
|
|
|
|
|
} else { |
136
|
1
|
|
|
|
|
5
|
@bitarray = split //, $bitlist_str; |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
} |
139
|
1
|
|
|
|
|
4
|
$self->{bitlist} = \@bitarray; |
140
|
1
|
|
|
|
|
2
|
$self->{size} = scalar @{$self->{bitlist}}; |
|
1
|
|
|
|
|
3
|
|
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
} elsif (defined $self->{size}) { |
143
|
|
|
|
|
|
|
die "When using the `size' option in the constructor call, you CANNOT use `filename', " . |
144
|
|
|
|
|
|
|
"`bitlist', 'bitstring', `hexstring', or `textstring' options: $!" |
145
|
|
|
|
|
|
|
if $self->{filename} or $self->{intVal} or $self->{bitlist} |
146
|
1
|
50
|
33
|
|
|
37
|
or $self->{bitstring} or $self->{hexstring} or $self->{textstring}; |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
147
|
1
|
|
|
|
|
4
|
my $bitstring = "0" x $self->{size}; |
148
|
1
|
|
|
|
|
7
|
my @bitlist_from_bitstring = split '', $bitstring; |
149
|
1
|
|
|
|
|
3
|
$self->{bitlist} = \@bitlist_from_bitstring; |
150
|
|
|
|
|
|
|
} elsif ($self->{bitlist}) { |
151
|
|
|
|
|
|
|
die "When using the `bitlist' option in the constructor call, you cannot use any " . |
152
|
|
|
|
|
|
|
"other option at the same time: $!" |
153
|
|
|
|
|
|
|
if $self->{filename} or $self->{intVal} or $self->{size} |
154
|
0
|
0
|
0
|
|
|
0
|
or $self->{bitstring} or $self->{hexstring} or $self->{textstring}; |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
155
|
0
|
|
|
|
|
0
|
$self->{size} = scalar @{$self->{bitlist}}; |
|
0
|
|
|
|
|
0
|
|
156
|
|
|
|
|
|
|
} elsif (defined $self->{bitstring}) { |
157
|
|
|
|
|
|
|
die "When using the `bitstring' option in the constructor call, you cannot use any " . |
158
|
|
|
|
|
|
|
"other option at the same time: $!" |
159
|
|
|
|
|
|
|
if $self->{filename} or $self->{intVal} or $self->{size} |
160
|
0
|
0
|
0
|
|
|
0
|
or $self->{bitlist} or $self->{hexstring} or $self->{textstring}; |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
161
|
0
|
|
|
|
|
0
|
my @bitlist_from_bitstring = split //, $self->{bitstring}; |
162
|
0
|
|
|
|
|
0
|
$self->{bitlist} = \@bitlist_from_bitstring; |
163
|
0
|
|
|
|
|
0
|
$self->{size} = scalar @{$self->{bitlist}}; |
|
0
|
|
|
|
|
0
|
|
164
|
|
|
|
|
|
|
} elsif (defined $self->{textstring}) { |
165
|
|
|
|
|
|
|
die "When using the `textstring' option in the constructor call, you cannot use any " . |
166
|
|
|
|
|
|
|
"other option at the same time: $!" |
167
|
|
|
|
|
|
|
if $self->{filename} or $self->{intVal} or $self->{size} |
168
|
1
|
50
|
33
|
|
|
29
|
or $self->{bitlist} or $self->{hexstring} or $self->{bitstring}; |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
169
|
5
|
50
|
|
|
|
17
|
my $bitstring_from_text = join '', map {length($_) == 8 ? $_ |
170
|
5
|
|
|
|
|
14
|
: ('0' x (8 - length($_))) . $_} map {sprintf "%b", $_} |
171
|
1
|
|
|
|
|
10
|
map ord, split //, $self->{textstring}; |
172
|
1
|
|
|
|
|
23
|
my @bitlist_from_text = split //, $bitstring_from_text; |
173
|
1
|
|
|
|
|
5
|
$self->{bitlist} = \@bitlist_from_text; |
174
|
1
|
|
|
|
|
2
|
$self->{size} = scalar @{$self->{bitlist}}; |
|
1
|
|
|
|
|
3
|
|
175
|
|
|
|
|
|
|
} elsif (defined $self->{hexstring}) { |
176
|
|
|
|
|
|
|
die "When using the `hexstring' option in the constructor call, you cannot use any " . |
177
|
|
|
|
|
|
|
"other option at the same time: $!" |
178
|
|
|
|
|
|
|
if $self->{filename} or $self->{intVal} or $self->{size} |
179
|
0
|
0
|
0
|
|
|
0
|
or $self->{bitlist} or $self->{textstring} or $self->{bitstring}; |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
180
|
0
|
0
|
|
|
|
0
|
my $bitstring_from_hex = join '', map {length($_) == 4 ? $_ |
181
|
0
|
|
|
|
|
0
|
: ('0' x (4 - length($_))) . $_} map {sprintf "%b", $_} |
182
|
0
|
|
|
|
|
0
|
map {hex $_} split //, $self->{hexstring}; |
|
0
|
|
|
|
|
0
|
|
183
|
0
|
|
|
|
|
0
|
my @bitlist_from_hex = split //, $bitstring_from_hex; |
184
|
0
|
|
|
|
|
0
|
$self->{bitlist} = \@bitlist_from_hex; |
185
|
0
|
|
|
|
|
0
|
$self->{size} = scalar @{$self->{bitlist}}; |
|
0
|
|
|
|
|
0
|
|
186
|
|
|
|
|
|
|
} |
187
|
3
|
|
|
|
|
5
|
my $shorts_needed = int( (@{$self->{bitlist}} + 15) / 16 ); |
|
3
|
|
|
|
|
11
|
|
188
|
3
|
|
|
|
|
9
|
@{$self->{_vector}} = map {unpack "n", pack("n", 0)} 0 .. $shorts_needed-1; |
|
3
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
19
|
|
189
|
3
|
|
|
|
|
19
|
my @interleaved = (0..$self->{size}-1, @{$self->{bitlist}}) |
190
|
3
|
|
|
|
|
9
|
[map {$_,$_+$self->{size}} (0 .. $self->{size}-1)]; |
|
60
|
|
|
|
|
100
|
|
191
|
3
|
|
|
60
|
|
32
|
pairmap {$self->set_bit($a,$b)} @interleaved; |
|
60
|
|
|
|
|
122
|
|
192
|
3
|
|
|
|
|
15
|
$self->{bitlist} = undef; |
193
|
3
|
|
|
|
|
23
|
return $self; |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
## Set the bit at the designated position to the value shown |
197
|
|
|
|
|
|
|
sub set_bit { |
198
|
60
|
|
|
60
|
1
|
81
|
my $self = shift; |
199
|
60
|
|
|
|
|
73
|
my $posn = shift; |
200
|
60
|
|
|
|
|
88
|
my $val = shift; |
201
|
60
|
50
|
66
|
|
|
254
|
croak "incorrect value for a bit" unless $val =~ /\d/ && ($val == 0 or $val == 1); |
|
|
|
33
|
|
|
|
|
202
|
60
|
50
|
33
|
|
|
192
|
die "index range error" if ($posn >= $self->{size}) or ($posn < - $self->{size}); |
203
|
60
|
50
|
|
|
|
96
|
$posn = $self->{size} + $posn if $posn < 0; |
204
|
60
|
|
|
|
|
100
|
my $block_index = int($posn / 16); |
205
|
60
|
|
|
|
|
71
|
my $shift = $posn & 0xF; |
206
|
60
|
|
|
|
|
83
|
my $cv = $self->{_vector}->[$block_index]; |
207
|
60
|
100
|
|
|
|
138
|
if ( ( ( $cv >> $shift ) & 1 ) != $val) { |
208
|
25
|
|
|
|
|
72
|
$self->{_vector}->[$block_index] = $cv ^ (1 << $shift); |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
## Get the bit from the designated position. This method can also return a slice of a |
213
|
|
|
|
|
|
|
## bitvector. HOWEVER, NOTE THAT THE SLICE IS RETURNED AS A LIST OF THE BITS IN THE |
214
|
|
|
|
|
|
|
## INDEX RANGE YOU SPECIFIED. You can either easily convert the list of bits returned |
215
|
|
|
|
|
|
|
## into a bitvector in your own code or, starting with Version 1.26, you can call the |
216
|
|
|
|
|
|
|
## get_slice() method. |
217
|
|
|
|
|
|
|
sub get_bit { |
218
|
65
|
|
|
65
|
1
|
91
|
my $self = shift; |
219
|
65
|
|
|
|
|
83
|
my $pos = shift; |
220
|
65
|
100
|
|
|
|
112
|
unless (ref($pos) eq "ARRAY") { |
221
|
60
|
50
|
33
|
|
|
170
|
die "index range error" if ($pos >= $self->{size}) or ($pos < - $self->{size}); |
222
|
60
|
50
|
|
|
|
102
|
$pos = $self->{size} + $pos if $pos < 0; |
223
|
60
|
|
|
|
|
163
|
return ( $self->{_vector}->[int($pos/16)] >> ($pos&15) ) & 1; |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
# my @slice = map $self->get_bit($_), (@$pos)[0..@$pos-1]; |
226
|
5
|
|
|
|
|
18
|
my @slice = map $self->get_bit($_), (@$pos)[0..@$pos-2]; |
227
|
5
|
|
|
|
|
31
|
return \@slice; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
## Get the slice of bits from the bitvector corresponding to the index range specified |
231
|
|
|
|
|
|
|
## by the argument. The slice is returned as an instance of Algorithm::BitVector |
232
|
|
|
|
|
|
|
sub get_slice { |
233
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
234
|
0
|
|
|
|
|
0
|
my $index_range = shift; |
235
|
0
|
|
|
|
|
0
|
my $slice_bv = Algorithm::BitVector->new( size => @$index_range - 1 ); |
236
|
0
|
|
|
|
|
0
|
map $slice_bv->set_bit($_ - $index_range->[0], $self->get_bit($_)), @$index_range[0..@$index_range-2]; |
237
|
0
|
|
|
|
|
0
|
return $slice_bv; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
## Set a slice of a BitVector from the bits in the argument BitVector object: |
241
|
|
|
|
|
|
|
sub set_slice { |
242
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
243
|
0
|
|
|
|
|
0
|
my $index_range = shift; |
244
|
0
|
|
|
|
|
0
|
my $values_bv = shift; |
245
|
0
|
0
|
|
|
|
0
|
die "the width of the index range for slice setting does not equal the size of the values array" |
246
|
|
|
|
|
|
|
unless @$index_range - 1 == $values_bv->length(); |
247
|
|
|
|
|
|
|
# unless @$index_range == $values_bv->length(); |
248
|
0
|
|
|
|
|
0
|
map $self->set_bit($_, $values_bv->get_bit($_ - $index_range->[0])), @$index_range[0..@$index_range-2]; |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
## Overloading of the string conversion operator. Return the string representation |
252
|
|
|
|
|
|
|
## of a bitvector. |
253
|
|
|
|
|
|
|
sub _str { |
254
|
1
|
|
|
1
|
|
8
|
my $self = shift; |
255
|
1
|
|
|
|
|
6
|
return join '', map $self->get_bit($_), 0 .. $self->{size}-1; |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
## Overloading of the `+' operator. Concatenate the argument bitvectors. Return the |
259
|
|
|
|
|
|
|
## concatenated bitvector as a new BitVector instance. |
260
|
|
|
|
|
|
|
sub _join { |
261
|
0
|
|
|
0
|
|
0
|
my ($bv1, $bv2) = @_; |
262
|
0
|
0
|
0
|
|
|
0
|
croak "Abort: The concatenation operator invoked with either undefined " . |
263
|
|
|
|
|
|
|
"or wrong types of operands: $!" |
264
|
|
|
|
|
|
|
unless UNIVERSAL::isa( $bv1, 'Algorithm::BitVector') and |
265
|
|
|
|
|
|
|
UNIVERSAL::isa( $bv2, 'Algorithm::BitVector'); |
266
|
0
|
|
|
|
|
0
|
my $allbits = $bv1->_str() . $bv2->_str(); |
267
|
0
|
|
|
|
|
0
|
return Algorithm::BitVector->new( bitstring => $allbits ); |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
sub _compare { |
271
|
0
|
|
|
0
|
|
0
|
my ($bv1, $bv2) = @_; |
272
|
0
|
0
|
0
|
|
|
0
|
croak "Abort: The comparison operator invoked with either undefined " . |
273
|
|
|
|
|
|
|
"or wrong types of operands: $!" |
274
|
|
|
|
|
|
|
unless UNIVERSAL::isa( $bv1, 'Algorithm::BitVector') and |
275
|
|
|
|
|
|
|
UNIVERSAL::isa( $bv2, 'Algorithm::BitVector'); |
276
|
0
|
|
|
|
|
0
|
my $bigint1 = Math::BigInt->from_bin( "$bv1" ); |
277
|
0
|
|
|
|
|
0
|
my $bigint2 = Math::BigInt->from_bin( "$bv2" ); |
278
|
0
|
|
|
|
|
0
|
return $bigint1->bcmp($bigint2); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
sub deep_copy { |
282
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
283
|
0
|
|
|
|
|
0
|
my $result_bv = Algorithm::BitVector->new( size => $self->{size} ); |
284
|
0
|
|
|
|
|
0
|
foreach my $i (0..@{$result_bv->{_vector}}-1) { |
|
0
|
|
|
|
|
0
|
|
285
|
0
|
|
|
|
|
0
|
$result_bv->{_vector}->[$i] = $self->{_vector}->[$i]; |
286
|
|
|
|
|
|
|
} |
287
|
0
|
|
|
|
|
0
|
return $result_bv; |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
## Invert the bits in the bitvector on which the method is invoked |
291
|
|
|
|
|
|
|
## and return the result as a new bitvector. |
292
|
|
|
|
|
|
|
sub _invert { |
293
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
294
|
0
|
0
|
|
|
|
0
|
die "Abort: The operator '~' for bit inversion invoked on an object that is " . |
295
|
|
|
|
|
|
|
"not of type Algorithm::BitVector" |
296
|
|
|
|
|
|
|
unless UNIVERSAL::isa( $self, 'Algorithm::BitVector'); |
297
|
0
|
|
|
|
|
0
|
my $result_bv = $self->deep_copy(); |
298
|
0
|
|
|
|
|
0
|
foreach my $i (0..@{$result_bv->{_vector}}-1) { |
|
0
|
|
|
|
|
0
|
|
299
|
|
|
|
|
|
|
# The unary `~' operator may assume a 32-bit wide field: |
300
|
0
|
|
|
|
|
0
|
$result_bv->{_vector}->[$i] = ~ $result_bv->{_vector}->[$i] & 0x0000FFFF; |
301
|
|
|
|
|
|
|
} |
302
|
0
|
|
|
|
|
0
|
return $result_bv; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
## Take a bitwise 'OR' of two bitvectors. Return the result as a new bitvector. If |
306
|
|
|
|
|
|
|
## the two bitvectors are not of the same size, pad the shorter one with zeros from |
307
|
|
|
|
|
|
|
## the left. |
308
|
|
|
|
|
|
|
sub _or { |
309
|
0
|
|
|
0
|
|
0
|
my ($bv1, $bv2) = @_; |
310
|
0
|
0
|
0
|
|
|
0
|
croak "Abort: The `|' operator invoked with either undefined " . |
311
|
|
|
|
|
|
|
"or wrong types of operands: $!" |
312
|
|
|
|
|
|
|
unless UNIVERSAL::isa( $bv1, 'Algorithm::BitVector') and |
313
|
|
|
|
|
|
|
UNIVERSAL::isa( $bv2, 'Algorithm::BitVector'); |
314
|
0
|
|
|
|
|
0
|
my ($bv3, $bv4); |
315
|
0
|
0
|
|
|
|
0
|
if ( $bv1->{size} < $bv2->{size} ) { |
|
|
0
|
|
|
|
|
|
316
|
0
|
|
|
|
|
0
|
$bv3 = $bv1->_resize_pad_from_left($bv2->{size} - $bv1->{size}); |
317
|
0
|
|
|
|
|
0
|
$bv4 = $bv2; |
318
|
|
|
|
|
|
|
} elsif ( $bv1->{size} > $bv2->{size} ) { |
319
|
0
|
|
|
|
|
0
|
$bv3 = $bv1; |
320
|
0
|
|
|
|
|
0
|
$bv4 = $bv2->_resize_pad_from_left($bv1->{size} - $bv2->{size}); |
321
|
|
|
|
|
|
|
} else { |
322
|
0
|
|
|
|
|
0
|
$bv3 = $bv1; |
323
|
0
|
|
|
|
|
0
|
$bv4 = $bv2; |
324
|
|
|
|
|
|
|
} |
325
|
0
|
|
|
|
|
0
|
my $result_bv = Algorithm::BitVector->new( size => $bv3->{size} ); |
326
|
0
|
|
|
|
|
0
|
foreach my $i (0..@{$result_bv->{_vector}}-1) { |
|
0
|
|
|
|
|
0
|
|
327
|
|
|
|
|
|
|
# The binary `|' operator may assume 32-bit wide fields: |
328
|
0
|
|
|
|
|
0
|
$result_bv->{_vector}->[$i] = ($bv3->{_vector}->[$i] | $bv4->{_vector}->[$i] ) & 0x0000FFFF; |
329
|
|
|
|
|
|
|
} |
330
|
0
|
|
|
|
|
0
|
return $result_bv; |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
## Resize a bitvector by padding with n 0's from the left. Return the result as a |
334
|
|
|
|
|
|
|
## new bitvector. |
335
|
|
|
|
|
|
|
sub _resize_pad_from_left { |
336
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
337
|
0
|
|
|
|
|
0
|
my $n = shift; |
338
|
0
|
|
|
|
|
0
|
my $new_str = '0' x $n . "$self"; |
339
|
0
|
|
|
|
|
0
|
return Algorithm::BitVector->new( bitstring => $new_str ); |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
## Take a bitwise 'AND' of the bitvector on which the method is invoked with |
343
|
|
|
|
|
|
|
## the argument bitvector. Return the result as a new bitvector. If the two |
344
|
|
|
|
|
|
|
## bitvectors are not of the same size, pad the shorter one with zeros from the |
345
|
|
|
|
|
|
|
## left. |
346
|
|
|
|
|
|
|
sub _and { |
347
|
0
|
|
|
0
|
|
0
|
my ($bv1, $bv2) = @_; |
348
|
0
|
0
|
0
|
|
|
0
|
croak "Abort: The concatenation operator invoked with either undefined " . |
349
|
|
|
|
|
|
|
"or wrong types of operands: $!" |
350
|
|
|
|
|
|
|
unless UNIVERSAL::isa( $bv1, 'Algorithm::BitVector') and |
351
|
|
|
|
|
|
|
UNIVERSAL::isa( $bv2, 'Algorithm::BitVector'); |
352
|
0
|
|
|
|
|
0
|
my ($bv3, $bv4); |
353
|
0
|
0
|
|
|
|
0
|
if ( $bv1->{size} < $bv2->{size} ) { |
|
|
0
|
|
|
|
|
|
354
|
0
|
|
|
|
|
0
|
$bv3 = $bv1->_resize_pad_from_left($bv2->{size} - $bv1->{size}); |
355
|
0
|
|
|
|
|
0
|
$bv4 = $bv2; |
356
|
|
|
|
|
|
|
} elsif ( $bv1->{size} > $bv2->{size} ) { |
357
|
0
|
|
|
|
|
0
|
$bv3 = $bv1; |
358
|
0
|
|
|
|
|
0
|
$bv4 = $bv2->_resize_pad_from_left($bv1->{size} - $bv2->{size}); |
359
|
|
|
|
|
|
|
} else { |
360
|
0
|
|
|
|
|
0
|
$bv3 = $bv1; |
361
|
0
|
|
|
|
|
0
|
$bv4 = $bv2; |
362
|
|
|
|
|
|
|
} |
363
|
0
|
|
|
|
|
0
|
my $result_bv = Algorithm::BitVector->new( size => $bv3->{size} ); |
364
|
0
|
|
|
|
|
0
|
foreach my $i (0..@{$result_bv->{_vector}}-1) { |
|
0
|
|
|
|
|
0
|
|
365
|
|
|
|
|
|
|
# The binary bitwise `&' operator may assume 32-bit wide fields: |
366
|
0
|
|
|
|
|
0
|
$result_bv->{_vector}->[$i] = ($bv3->{_vector}->[$i] & $bv4->{_vector}->[$i] ) & 0x0000FFFF; |
367
|
|
|
|
|
|
|
} |
368
|
0
|
|
|
|
|
0
|
return $result_bv; |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
## Take a bitwise 'XOR' of the bitvector on which the method is invoked with |
372
|
|
|
|
|
|
|
## the argument bitvector. Return the result as a new bitvector. If the two |
373
|
|
|
|
|
|
|
## bitvectors are not of the same size, pad the shorter one with zeros from the |
374
|
|
|
|
|
|
|
## left. |
375
|
|
|
|
|
|
|
sub _xor { |
376
|
0
|
|
|
0
|
|
0
|
my ($bv1, $bv2) = @_; |
377
|
0
|
0
|
0
|
|
|
0
|
croak "Abort: The xor operator invoked with either undefined " . |
378
|
|
|
|
|
|
|
"or wrong types of operands: $!" |
379
|
|
|
|
|
|
|
unless UNIVERSAL::isa( $bv1, 'Algorithm::BitVector') and |
380
|
|
|
|
|
|
|
UNIVERSAL::isa( $bv2, 'Algorithm::BitVector'); |
381
|
0
|
|
|
|
|
0
|
my ($bv3, $bv4); |
382
|
0
|
0
|
|
|
|
0
|
if ( $bv1->{size} < $bv2->{size} ) { |
|
|
0
|
|
|
|
|
|
383
|
0
|
|
|
|
|
0
|
$bv3 = $bv1->_resize_pad_from_left($bv2->{size} - $bv1->{size}); |
384
|
0
|
|
|
|
|
0
|
$bv4 = $bv2; |
385
|
|
|
|
|
|
|
} elsif ( $bv1->{size} > $bv2->{size} ) { |
386
|
0
|
|
|
|
|
0
|
$bv3 = $bv1; |
387
|
0
|
|
|
|
|
0
|
$bv4 = $bv2->_resize_pad_from_left($bv1->{size} - $bv2->{size}); |
388
|
|
|
|
|
|
|
} else { |
389
|
0
|
|
|
|
|
0
|
$bv3 = $bv1; |
390
|
0
|
|
|
|
|
0
|
$bv4 = $bv2; |
391
|
|
|
|
|
|
|
} |
392
|
0
|
|
|
|
|
0
|
my $result_bv = Algorithm::BitVector->new( size => $bv3->{size} ); |
393
|
0
|
|
|
|
|
0
|
foreach my $i (0..@{$result_bv->{_vector}}-1) { |
|
0
|
|
|
|
|
0
|
|
394
|
|
|
|
|
|
|
# The binary bitwise `^' operator may assume 32-bit wide fields: |
395
|
0
|
|
|
|
|
0
|
$result_bv->{_vector}->[$i] = ($bv3->{_vector}->[$i] ^ $bv4->{_vector}->[$i] ) & 0x0000FFFF; |
396
|
|
|
|
|
|
|
} |
397
|
0
|
|
|
|
|
0
|
return $result_bv; |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
# For the overloading of the iterator '<>' operator: |
401
|
|
|
|
|
|
|
sub _iter { |
402
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
403
|
0
|
|
|
|
|
0
|
my $pos = 0; |
404
|
0
|
0
|
|
|
|
0
|
$self->{_iterator} = BitVecIterator->new($self, $pos) unless $self->{_iter_called}; |
405
|
0
|
|
|
|
|
0
|
&{$self->{_iterator}->next()}; |
|
0
|
|
|
|
|
0
|
|
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
{ |
409
|
|
|
|
|
|
|
# This inner class needed for implementing iterator overloading: |
410
|
|
|
|
|
|
|
package BitVecIterator; |
411
|
|
|
|
|
|
|
sub new { |
412
|
0
|
|
|
0
|
|
0
|
my $self = [ $_[1], $_[2] ]; |
413
|
0
|
|
|
|
|
0
|
bless $self, $_[0]; |
414
|
0
|
|
|
|
|
0
|
$_[1]->{_iter_called} = 1; |
415
|
0
|
|
|
|
|
0
|
return $self; |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
sub next { |
418
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
419
|
0
|
|
|
|
|
0
|
my $bitvec = $self->[0]; |
420
|
|
|
|
|
|
|
# The anonymous subroutine that follows is a closure over the variables |
421
|
|
|
|
|
|
|
# incorporated in it: |
422
|
|
|
|
|
|
|
return sub { |
423
|
0
|
0
|
|
0
|
|
0
|
if ($self->[1] >= $bitvec->{size}) { |
424
|
0
|
|
|
|
|
0
|
delete $bitvec->{_iter_called}; |
425
|
0
|
|
|
|
|
0
|
return; |
426
|
|
|
|
|
|
|
} |
427
|
0
|
|
|
|
|
0
|
my $bit = $bitvec->get_bit($self->[1]); |
428
|
0
|
|
|
|
|
0
|
$self->[1] = $self->[1] + 1; |
429
|
0
|
|
|
|
|
0
|
return $bit; |
430
|
|
|
|
|
|
|
} |
431
|
0
|
|
|
|
|
0
|
} |
432
|
|
|
|
|
|
|
} |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
# for the overloading of the numification operator: |
435
|
|
|
|
|
|
|
sub _int { |
436
|
1
|
|
|
1
|
|
6
|
my $self = shift; |
437
|
1
|
|
|
|
|
4
|
return $self->int_value(); |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
## Divides an even-sized bitvector into two and returns the two halves as a |
441
|
|
|
|
|
|
|
## list of two bitvectors. |
442
|
|
|
|
|
|
|
sub divide_into_two { |
443
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
444
|
0
|
0
|
|
|
|
0
|
die "Abort: The divide_into_two() method invoked on an object that is " . |
445
|
|
|
|
|
|
|
"not of type Algorithm::BitVector" |
446
|
|
|
|
|
|
|
unless UNIVERSAL::isa( $self, 'Algorithm::BitVector'); |
447
|
|
|
|
|
|
|
die "The bitvector to be divided must have even number of bits: $!" |
448
|
0
|
0
|
|
|
|
0
|
if $self->{size} % 2; |
449
|
0
|
|
|
|
|
0
|
my @outlist1 = (); |
450
|
0
|
|
|
|
|
0
|
foreach my $i (0..$self->{size} / 2 - 1) { |
451
|
0
|
|
|
|
|
0
|
push @outlist1, $self->get_bit($i); |
452
|
|
|
|
|
|
|
} |
453
|
0
|
|
|
|
|
0
|
my @outlist2 = (); |
454
|
0
|
|
|
|
|
0
|
foreach my $i ( ($self->{size} / 2) .. ($self->{size} - 1) ) { |
455
|
0
|
|
|
|
|
0
|
push @outlist2, $self->get_bit($i); |
456
|
|
|
|
|
|
|
} |
457
|
0
|
|
|
|
|
0
|
return Algorithm::BitVector->new( bitlist => \@outlist1 ), |
458
|
|
|
|
|
|
|
Algorithm::BitVector->new( bitlist => \@outlist2 ); |
459
|
|
|
|
|
|
|
} |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
## Permute a bitvector according to the indices shown in the second argument list. |
462
|
|
|
|
|
|
|
## Return the permuted bitvector as a new bitvector. |
463
|
|
|
|
|
|
|
sub permute { |
464
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
465
|
0
|
0
|
|
|
|
0
|
die "Abort: The permute() method invoked on an object that is " . |
466
|
|
|
|
|
|
|
"not of type Algorithm::BitVector" |
467
|
|
|
|
|
|
|
unless UNIVERSAL::isa( $self, 'Algorithm::BitVector'); |
468
|
0
|
|
|
|
|
0
|
my $permute_list = shift; |
469
|
|
|
|
|
|
|
die "Bad permutation index in your permutation list" |
470
|
0
|
0
|
|
|
|
0
|
if max(@$permute_list) > $self->{size} - 1; |
471
|
0
|
|
|
|
|
0
|
my @outlist = (); |
472
|
0
|
|
|
|
|
0
|
foreach my $index (@$permute_list) { |
473
|
0
|
|
|
|
|
0
|
push @outlist, $self->get_bit($index); |
474
|
|
|
|
|
|
|
} |
475
|
0
|
|
|
|
|
0
|
return Algorithm::BitVector->new( bitlist => \@outlist ); |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
## Unpermute the bitvector according to the permutation list supplied as the |
479
|
|
|
|
|
|
|
## second argument. If you first permute a bitvector by using permute() and |
480
|
|
|
|
|
|
|
## then unpermute() it using the same permutation list, you will get back the |
481
|
|
|
|
|
|
|
## original bitvector. |
482
|
|
|
|
|
|
|
sub unpermute { |
483
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
484
|
0
|
0
|
|
|
|
0
|
die "Abort: The unpermute() method invoked on an object that is " . |
485
|
|
|
|
|
|
|
"not of type Algorithm::BitVector" |
486
|
|
|
|
|
|
|
unless UNIVERSAL::isa( $self, 'Algorithm::BitVector'); |
487
|
0
|
|
|
|
|
0
|
my $permute_list = shift; |
488
|
|
|
|
|
|
|
die "Bad permutation index in your permutation list: $!" |
489
|
0
|
0
|
|
|
|
0
|
if max(@$permute_list) > $self->{size} - 1; |
490
|
|
|
|
|
|
|
die "Size of the permute list for unpermuting not consistent with the size of the bet vector:$!" |
491
|
0
|
0
|
|
|
|
0
|
unless $self->{size} == @$permute_list; |
492
|
0
|
|
|
|
|
0
|
my $out_bv = Algorithm::BitVector->new( size => $self->{size} ); |
493
|
0
|
|
|
|
|
0
|
foreach my $i (0..@$permute_list-1) { |
494
|
0
|
|
|
|
|
0
|
$out_bv->set_bit( $permute_list->[$i], $self->get_bit($i) ); |
495
|
|
|
|
|
|
|
} |
496
|
0
|
|
|
|
|
0
|
return $out_bv; |
497
|
|
|
|
|
|
|
} |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
## Write the bitvector to the file object file_out. (A file object is returned |
500
|
|
|
|
|
|
|
## by a call to open()). Since all file I/O is byte oriented, the bitvector must |
501
|
|
|
|
|
|
|
## be multiple of 8 bits. Each byte treated as MSB first (0th index). |
502
|
|
|
|
|
|
|
sub write_to_file { |
503
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
504
|
0
|
0
|
|
|
|
0
|
die "Abort: The write_to_file() method invoked on an object that is " . |
505
|
|
|
|
|
|
|
"not of type Algorithm::BitVector" |
506
|
|
|
|
|
|
|
unless UNIVERSAL::isa( $self, 'Algorithm::BitVector'); |
507
|
0
|
|
|
|
|
0
|
my $file_out = shift; |
508
|
0
|
|
|
|
|
0
|
my $err_str = "Only a bitvector whose length is a multiple of 8 can " . |
509
|
|
|
|
|
|
|
"be written to a file. Use the padding functions to satisfy " . |
510
|
|
|
|
|
|
|
"this constraint."; |
511
|
0
|
0
|
|
|
|
0
|
$self->{FILEOUT} = $file_out unless $self->{FILEOUT}; |
512
|
0
|
0
|
|
|
|
0
|
die $err_str if $self->{size} % 8; |
513
|
0
|
|
|
|
|
0
|
for my $byte (0..$self->{size}/8 - 1){ |
514
|
0
|
|
|
|
|
0
|
my $value = 0; |
515
|
0
|
|
|
|
|
0
|
foreach my $bit (0..7) { |
516
|
0
|
|
|
|
|
0
|
$value += $self->get_bit( $byte*8+(7 - $bit) ) << $bit; |
517
|
|
|
|
|
|
|
} |
518
|
0
|
|
|
|
|
0
|
syswrite $file_out, chr($value), 1; |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
} |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
## For closing a file object that was used for reading the bits into one or more |
523
|
|
|
|
|
|
|
## BitVector objects. |
524
|
|
|
|
|
|
|
sub close_file_handle { |
525
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
526
|
0
|
0
|
|
|
|
0
|
die "Abort: The close_file_handle() method invoked on an object that is " . |
527
|
|
|
|
|
|
|
"not of type Algorithm::BitVector" |
528
|
|
|
|
|
|
|
unless UNIVERSAL::isa( $self, 'Algorithm::BitVector'); |
529
|
|
|
|
|
|
|
die "No open file currently associated with the file handle: $!" |
530
|
0
|
0
|
|
|
|
0
|
unless $self->{FILEIN}; |
531
|
0
|
|
|
|
|
0
|
close $self->{FILEIN}; |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
## Return the integer value of a bitvector. If the original integer from which the |
535
|
|
|
|
|
|
|
## bitvector was constructed is a Math::BigInt object, then return the string |
536
|
|
|
|
|
|
|
## representation of the integer value. |
537
|
|
|
|
|
|
|
sub int_value { |
538
|
1
|
|
|
1
|
1
|
1
|
my $self = shift; |
539
|
1
|
50
|
|
|
|
5
|
die "Abort: The int() method invoked on an object that is " . |
540
|
|
|
|
|
|
|
"not of type Algorithm::BitVector" |
541
|
|
|
|
|
|
|
unless UNIVERSAL::isa( $self, 'Algorithm::BitVector'); |
542
|
1
|
|
|
|
|
11
|
my $int_value; |
543
|
1
|
50
|
33
|
|
|
11
|
if (defined($self->{intVal}) && (ref($self->{intVal}) eq 'Math::BigInt')) { |
544
|
0
|
|
|
|
|
0
|
$int_value = $self->{intVal}->bstr(); |
545
|
|
|
|
|
|
|
} else { |
546
|
1
|
|
|
|
|
3
|
$int_value = 0; |
547
|
1
|
|
|
|
|
12
|
foreach my $i (0..$self->{size}-1) { |
548
|
4
|
|
|
|
|
11
|
$int_value += $self->get_bit($i) * ( 2 ** ( $self->{size} - $i - 1 ) ); |
549
|
|
|
|
|
|
|
} |
550
|
|
|
|
|
|
|
} |
551
|
1
|
|
|
|
|
7
|
return $int_value; |
552
|
|
|
|
|
|
|
} |
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
## Return the text string formed by dividing the bitvector into bytes from the |
555
|
|
|
|
|
|
|
## left and replacing each byte by its ASCII character (this is a useful thing |
556
|
|
|
|
|
|
|
## to do only if the length of the vector is an integral multiple of 8 and every |
557
|
|
|
|
|
|
|
## byte in your bitvector has a print representation) |
558
|
|
|
|
|
|
|
sub get_bitvector_in_ascii { |
559
|
1
|
|
|
1
|
1
|
2
|
my $self = shift; |
560
|
1
|
50
|
|
|
|
6
|
die "Abort: The get_bitvector_in_ascii() method invoked on an object that is " . |
561
|
|
|
|
|
|
|
"not of type Algorithm::BitVector" |
562
|
|
|
|
|
|
|
unless UNIVERSAL::isa( $self, 'Algorithm::BitVector'); |
563
|
|
|
|
|
|
|
die "\nThe bitvector for get_text_from_bitvector() must be an integral multiple of 8 bits: $!" |
564
|
1
|
50
|
|
|
|
5
|
if $self->{size} % 8; |
565
|
1
|
|
|
|
|
2
|
my $ascii = ''; |
566
|
1
|
|
|
|
|
4
|
for (my $i=0; $i < $self->{size}; $i += 8) { |
567
|
|
|
|
|
|
|
# $ascii .= chr oct "0b". join '', @{$self->get_bit([$i..$i+7])}; |
568
|
5
|
|
|
|
|
10
|
$ascii .= chr oct "0b". join '', @{$self->get_bit([$i..$i+8])}; |
|
5
|
|
|
|
|
13
|
|
569
|
|
|
|
|
|
|
} |
570
|
1
|
|
|
|
|
12
|
return $ascii; |
571
|
|
|
|
|
|
|
} |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
# for backward compatibility: |
574
|
|
|
|
|
|
|
sub get_text_from_bitvector { |
575
|
1
|
|
|
1
|
0
|
6
|
my $self = shift; |
576
|
1
|
|
|
|
|
4
|
$self->get_bitvector_in_ascii(@_); |
577
|
|
|
|
|
|
|
} |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
## Return a string of hex digits by scanning the bits from the left and |
580
|
|
|
|
|
|
|
## replacing each sequence of 4 bits by its corresponding hex digit (this is a |
581
|
|
|
|
|
|
|
## useful thing to do only if the length of the vector is an integral multiple |
582
|
|
|
|
|
|
|
## of 4) |
583
|
|
|
|
|
|
|
#sub get_hex_string_from_bitvector { |
584
|
|
|
|
|
|
|
sub get_bitvector_in_hex { |
585
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
586
|
0
|
0
|
|
|
|
0
|
die "Abort: The get_bitvector_in_hex() method invoked on an object that is " . |
587
|
|
|
|
|
|
|
"not of type Algorithm::BitVector" |
588
|
|
|
|
|
|
|
unless UNIVERSAL::isa( $self, 'Algorithm::BitVector'); |
589
|
|
|
|
|
|
|
die "\nThe bitvector for get_hex_from_bitvector() must be a multiple of 4 bits: $!" |
590
|
0
|
0
|
|
|
|
0
|
if $self->{size} % 4; |
591
|
0
|
|
|
|
|
0
|
my $hex = ''; |
592
|
0
|
|
|
|
|
0
|
for (my $i=0; $i < $self->{size}; $i += 4) { |
593
|
|
|
|
|
|
|
# $hex .= sprintf "%x", oct "0b". join '', @{$self->get_bit([$i..$i+3])}; |
594
|
0
|
|
|
|
|
0
|
$hex .= sprintf "%x", oct "0b". join '', @{$self->get_bit([$i..$i+4])}; |
|
0
|
|
|
|
|
0
|
|
595
|
|
|
|
|
|
|
} |
596
|
0
|
|
|
|
|
0
|
return $hex; |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
# for backward compatibility: |
600
|
|
|
|
|
|
|
sub get_hex_string_from_bitvector { |
601
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
602
|
0
|
|
|
|
|
0
|
$self->get_bitvector_in_hex(@_); |
603
|
|
|
|
|
|
|
} |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
## Read blocksize bits from a disk file and return a BitVector object containing |
606
|
|
|
|
|
|
|
## the bits. If the file contains fewer bits than blocksize, construct the |
607
|
|
|
|
|
|
|
## BitVector object from however many bits there are in the file. If the file |
608
|
|
|
|
|
|
|
## contains zero bits, return a BitVector object of size attribute set to 0. |
609
|
|
|
|
|
|
|
sub read_bits_from_file { |
610
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
611
|
0
|
0
|
|
|
|
0
|
die "Abort: The read_bits_from_file() method invoked on an object that is " . |
612
|
|
|
|
|
|
|
"not of type Algorithm::BitVector" |
613
|
|
|
|
|
|
|
unless UNIVERSAL::isa( $self, 'Algorithm::BitVector'); |
614
|
0
|
|
|
|
|
0
|
my $blocksize = shift; |
615
|
0
|
|
|
|
|
0
|
my $error_str = "You need to first construct a BitVector object with a filename as argument"; |
616
|
0
|
0
|
|
|
|
0
|
die "$error_str" unless $self->{filename}; |
617
|
0
|
0
|
|
|
|
0
|
die "block size must be a multiple of 8" if $blocksize % 8; |
618
|
0
|
|
|
|
|
0
|
my $bitstr = _readblock( $blocksize, $self ); |
619
|
0
|
0
|
|
|
|
0
|
if (length $bitstr == 0) { |
620
|
0
|
|
|
|
|
0
|
return Algorithm::BitVector->new( size => 0 ); |
621
|
0
|
|
|
|
|
0
|
print "file has no bits\n"; |
622
|
|
|
|
|
|
|
} else { |
623
|
0
|
|
|
|
|
0
|
return Algorithm::BitVector->new( bitstring => $bitstr ); |
624
|
|
|
|
|
|
|
} |
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
## For an in-place left circular shift by n bit positions |
628
|
|
|
|
|
|
|
sub _lshift { |
629
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
630
|
0
|
|
|
|
|
0
|
my $n = shift; |
631
|
0
|
0
|
|
|
|
0
|
die "Circular shift of an empty vector makes no sense" unless $self->{size}; |
632
|
0
|
0
|
|
|
|
0
|
return $self >> abs($n) if $n < 0; |
633
|
0
|
|
|
|
|
0
|
foreach my $i (0..$n-1) { |
634
|
0
|
|
|
|
|
0
|
$self->_circular_rotate_left_by_one(); |
635
|
|
|
|
|
|
|
} |
636
|
0
|
|
|
|
|
0
|
return $self; |
637
|
|
|
|
|
|
|
} |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
## For an in-place right circular shift by n bit positions |
640
|
|
|
|
|
|
|
sub _rshift { |
641
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
642
|
0
|
|
|
|
|
0
|
my $n = shift; |
643
|
0
|
0
|
|
|
|
0
|
die "Circular shift of an empty vector makes no sense" unless $self->{size}; |
644
|
0
|
0
|
|
|
|
0
|
return $self << abs($n) if $n < 0; |
645
|
0
|
|
|
|
|
0
|
foreach my $i (0..$n-1) { |
646
|
0
|
|
|
|
|
0
|
$self->_circular_rotate_right_by_one(); |
647
|
|
|
|
|
|
|
} |
648
|
0
|
|
|
|
|
0
|
return $self; |
649
|
|
|
|
|
|
|
} |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
## For a one-bit in-place left circular shift |
652
|
|
|
|
|
|
|
sub _circular_rotate_left_by_one { |
653
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
654
|
0
|
|
|
|
|
0
|
my $max_index = int( ($self->{size} - 1) / 16 ); |
655
|
0
|
|
|
|
|
0
|
my $left_most_bit = $self->{_vector}->[0] & 1; |
656
|
0
|
|
|
|
|
0
|
$self->{_vector}->[0] = $self->{_vector}->[0] >> 1; |
657
|
0
|
|
|
|
|
0
|
foreach my $i (1 .. $max_index) { |
658
|
0
|
|
|
|
|
0
|
my $left_bit = $self->{_vector}->[$i] & 1; |
659
|
0
|
|
|
|
|
0
|
$self->{_vector}->[$i] = $self->{_vector}->[$i] >> 1; |
660
|
0
|
|
|
|
|
0
|
$self->{_vector}->[$i-1] |= $left_bit << 15; |
661
|
|
|
|
|
|
|
} |
662
|
0
|
|
|
|
|
0
|
$self->set_bit($self->{size} - 1, $left_most_bit); |
663
|
|
|
|
|
|
|
} |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
## For a one-bit in-place right circular shift |
666
|
|
|
|
|
|
|
sub _circular_rotate_right_by_one { |
667
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
668
|
0
|
|
|
|
|
0
|
my $max_index = int( ($self->{size} - 1) / 16 ); |
669
|
0
|
|
|
|
|
0
|
my $right_most_bit = $self->get_bit( $self->{size} - 1); |
670
|
0
|
|
|
|
|
0
|
$self->{_vector}->[$max_index] &= ~0x8000; |
671
|
0
|
|
|
|
|
0
|
$self->{_vector}->[$max_index] = $self->{_vector}->[$max_index] << 1; |
672
|
0
|
|
|
|
|
0
|
for (my $i=$max_index-1; $i > -1; $i -= 1) { |
673
|
0
|
|
|
|
|
0
|
my $right_bit = $self->{_vector}->[$i] & 0x8000; |
674
|
0
|
|
|
|
|
0
|
$self->{_vector}->[$i] &= ~0x8000; |
675
|
0
|
|
|
|
|
0
|
$self->{_vector}->[$i] = $self->{_vector}->[$i] << 1; |
676
|
0
|
|
|
|
|
0
|
$self->{_vector}->[$i+1] |= $right_bit >> 15; |
677
|
|
|
|
|
|
|
} |
678
|
0
|
|
|
|
|
0
|
$self->set_bit(0, $right_most_bit); |
679
|
|
|
|
|
|
|
} |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
## Pad a bitvector with n zeros from the left |
682
|
|
|
|
|
|
|
sub pad_from_left { |
683
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
684
|
0
|
|
|
|
|
0
|
my $n = shift; |
685
|
0
|
0
|
|
|
|
0
|
die "a negative value for index positions not allowed for padding from left" if $n < 0; |
686
|
0
|
|
|
|
|
0
|
my $new_str = ('0' x $n) . "$self"; |
687
|
0
|
|
|
|
|
0
|
my $new_bitvec = Algorithm::BitVector->new( bitstring => $new_str ); |
688
|
0
|
|
|
|
|
0
|
$self->{size} = length $new_str; |
689
|
0
|
|
|
|
|
0
|
$self->{_vector} = $new_bitvec->{_vector}; |
690
|
0
|
|
|
|
|
0
|
return $self; |
691
|
|
|
|
|
|
|
} |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
## Pad a bitvector with n zeros from the right |
694
|
|
|
|
|
|
|
sub pad_from_right { |
695
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
696
|
0
|
|
|
|
|
0
|
my $n = shift; |
697
|
0
|
|
|
|
|
0
|
my $new_str = "$self" . ('0' x $n); |
698
|
0
|
|
|
|
|
0
|
my $new_bitvec = Algorithm::BitVector->new( bitstring => $new_str ); |
699
|
0
|
|
|
|
|
0
|
$self->{size} = length $new_str; |
700
|
0
|
|
|
|
|
0
|
$self->{_vector} = $new_bitvec->{_vector}; |
701
|
0
|
|
|
|
|
0
|
return $self; |
702
|
|
|
|
|
|
|
} |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
## Resets a previously created BitVector to either all zeros or all ones |
705
|
|
|
|
|
|
|
## depending on the argument val. |
706
|
|
|
|
|
|
|
sub reset { |
707
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
708
|
0
|
|
|
|
|
0
|
my $val = shift; |
709
|
0
|
0
|
0
|
|
|
0
|
die "Incorrect argument to reset(): $!" unless ($val == 0) or ($val == 1); |
710
|
0
|
|
|
|
|
0
|
my $reset_bv = Algorithm::BitVector->new( bitstring => ("$val" x $self->{size}) ); |
711
|
0
|
|
|
|
|
0
|
$self->{_vector} = $reset_bv->{_vector}; |
712
|
|
|
|
|
|
|
} |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
## Return the number of bits set in a BitVector instance. |
715
|
|
|
|
|
|
|
sub count_bits { |
716
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
717
|
0
|
|
|
0
|
|
0
|
return reduce {$a + $b} split //, "$self"; |
|
0
|
|
|
|
|
0
|
|
718
|
|
|
|
|
|
|
} |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
## Changes the bit pattern associated with a previously constructed BitVector |
721
|
|
|
|
|
|
|
## instance. The allowable modes for changing the internally stored bit pattern |
722
|
|
|
|
|
|
|
## are the same as for the constructor. |
723
|
|
|
|
|
|
|
sub set_value { |
724
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
725
|
0
|
|
|
|
|
0
|
my $reset_bv = Algorithm::BitVector->new( @_ ); |
726
|
0
|
|
|
|
|
0
|
$self->{_vector} = $reset_bv->{_vector}; |
727
|
0
|
|
|
|
|
0
|
$self->{size} = $reset_bv->{size}; |
728
|
|
|
|
|
|
|
} |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
## This method for counting the set bits is much faster for sparse bitvectors. |
732
|
|
|
|
|
|
|
## Note, however, that count_bits() may work much faster for dense-packed |
733
|
|
|
|
|
|
|
## bitvectors. |
734
|
|
|
|
|
|
|
sub count_bits_sparse { |
735
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
736
|
0
|
|
|
|
|
0
|
my $num = 0; |
737
|
0
|
|
|
|
|
0
|
foreach my $intval (@{$self->{_vector}}) { |
|
0
|
|
|
|
|
0
|
|
738
|
0
|
0
|
|
|
|
0
|
next if $intval == 0; |
739
|
0
|
|
|
|
|
0
|
my ($c, $iv) = (0, $intval); |
740
|
0
|
|
|
|
|
0
|
while ($iv > 0) { |
741
|
0
|
|
|
|
|
0
|
$iv = $iv & ($iv - 1); |
742
|
0
|
|
|
|
|
0
|
$c++; |
743
|
|
|
|
|
|
|
} |
744
|
0
|
|
|
|
|
0
|
$num += $c; |
745
|
|
|
|
|
|
|
} |
746
|
0
|
|
|
|
|
0
|
return $num; |
747
|
|
|
|
|
|
|
} |
748
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
## Computes the Jaccard similarity coefficient between two bitvectors |
750
|
|
|
|
|
|
|
sub jaccard_similarity { |
751
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
752
|
0
|
|
|
|
|
0
|
my $other = shift; |
753
|
0
|
0
|
0
|
|
|
0
|
die "Jaccard called on two zero vectors --- NOT ALLOWED: $!" |
754
|
|
|
|
|
|
|
if (int($self) == 0) && (int($other) == 0); |
755
|
|
|
|
|
|
|
die "Jaccard called on vectors of unequal size --- NOT ALLOWED: $!" |
756
|
0
|
0
|
|
|
|
0
|
if $self->{size} != $other->{size}; |
757
|
0
|
|
|
|
|
0
|
my $intersection = $self & $other; |
758
|
0
|
|
|
|
|
0
|
my $union = $self | $other; |
759
|
0
|
|
|
|
|
0
|
return $intersection->count_bits_sparse() / $union->count_bits_sparse(); |
760
|
|
|
|
|
|
|
} |
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
## Computes the Jaccard distance between two bitvectors |
763
|
|
|
|
|
|
|
sub jaccard_distance { |
764
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
765
|
0
|
|
|
|
|
0
|
my $other = shift; |
766
|
|
|
|
|
|
|
die "Jaccard called on vectors of unequal size --- NOT ALLOWED: $!" |
767
|
0
|
0
|
|
|
|
0
|
if $self->{size} != $other->{size}; |
768
|
0
|
|
|
|
|
0
|
return 1 - $self->jaccard_similarity( $other ); |
769
|
|
|
|
|
|
|
} |
770
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
## Computes the Hamming distance between two bitvectors |
772
|
|
|
|
|
|
|
sub hamming_distance { |
773
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
774
|
0
|
|
|
|
|
0
|
my $other = shift; |
775
|
|
|
|
|
|
|
die "hamming_distance() called on vectors of unequal size --- NOT ALLOWED: $!" |
776
|
0
|
0
|
|
|
|
0
|
if $self->{size} != $other->{size}; |
777
|
0
|
|
|
|
|
0
|
my $diff = $self ^ $other; |
778
|
0
|
|
|
|
|
0
|
return $diff->count_bits_sparse(); |
779
|
|
|
|
|
|
|
} |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
## This method calculates the position of the next set bit at or after the current |
782
|
|
|
|
|
|
|
## position index. It returns -1 if there is no next set bit. Logic based on the |
783
|
|
|
|
|
|
|
## contributions by Jason Allum and John Gleeson to the Python version of this |
784
|
|
|
|
|
|
|
## module. |
785
|
|
|
|
|
|
|
sub next_set_bit { |
786
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
787
|
0
|
|
0
|
|
|
0
|
my $from_index = shift || 0; |
788
|
0
|
0
|
|
|
|
0
|
die "The from_index must be nonnegative: $!" unless $from_index >= 0; |
789
|
0
|
|
|
|
|
0
|
my $i = $from_index; |
790
|
0
|
|
|
|
|
0
|
my $v = $self->{_vector}; |
791
|
0
|
|
|
|
|
0
|
my $l = scalar @$v; |
792
|
0
|
|
|
|
|
0
|
my $o = $i >> 4; |
793
|
0
|
|
|
|
|
0
|
my $s = $i & 0x0F; |
794
|
0
|
|
|
|
|
0
|
$i = $o << 4; |
795
|
0
|
|
|
|
|
0
|
while ($o < $l) { |
796
|
0
|
|
|
|
|
0
|
my $h = $v->[$o]; |
797
|
0
|
0
|
|
|
|
0
|
if ($h) { |
798
|
0
|
|
|
|
|
0
|
$i += $s; |
799
|
0
|
|
|
|
|
0
|
my $m = 1 << $s; |
800
|
0
|
|
|
|
|
0
|
while ($m != (1 << 0x10)) { |
801
|
0
|
0
|
|
|
|
0
|
return $i if $h & $m; |
802
|
0
|
|
|
|
|
0
|
$m <<= 1; |
803
|
0
|
|
|
|
|
0
|
$i += 1; |
804
|
|
|
|
|
|
|
} |
805
|
|
|
|
|
|
|
} else { |
806
|
0
|
|
|
|
|
0
|
$i += 0x10; |
807
|
|
|
|
|
|
|
} |
808
|
0
|
|
|
|
|
0
|
$s = 0; |
809
|
0
|
|
|
|
|
0
|
$o += 1; |
810
|
|
|
|
|
|
|
} |
811
|
0
|
|
|
|
|
0
|
return -1; |
812
|
|
|
|
|
|
|
} |
813
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
## For a bit that is set at the argument 'position', this method returns how many |
815
|
|
|
|
|
|
|
## bits are set to the left of that bit. For example, in the bit pattern |
816
|
|
|
|
|
|
|
## 000101100100, a call to this method with position set to 9 will return 4. |
817
|
|
|
|
|
|
|
sub rank_of_bit_set_at_index { |
818
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
819
|
0
|
|
|
|
|
0
|
my $position = shift; |
820
|
0
|
0
|
|
|
|
0
|
die "The bitvector has no bits set at the position in the call to rank_of_bit_set_at_index(): $!" |
821
|
|
|
|
|
|
|
unless $self->get_bit($position); |
822
|
0
|
|
|
|
|
0
|
my $bv_slice = Algorithm::BitVector->new( bitlist => $self->get_bit([0..$position]) ); |
823
|
0
|
|
|
|
|
0
|
return $bv_slice->count_bits(); |
824
|
|
|
|
|
|
|
} |
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
## Determines whether the integer value of a bitvector is a power of 2. |
827
|
|
|
|
|
|
|
sub is_power_of_2 { |
828
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
829
|
0
|
0
|
|
|
|
0
|
return 0 if int($self) == 0; |
830
|
0
|
|
|
|
|
0
|
my $bv = $self & Algorithm::BitVector->new( intVal => int($self) - 1); |
831
|
0
|
0
|
|
|
|
0
|
return 1 if int($bv) == 0; |
832
|
0
|
|
|
|
|
0
|
return 0; |
833
|
|
|
|
|
|
|
} |
834
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
## Faster version of is_power_of2() for sparse bitvectors |
836
|
|
|
|
|
|
|
sub is_power_of_2_sparse { |
837
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
838
|
0
|
0
|
|
|
|
0
|
return 1 if $self->count_bits_sparse() == 1; |
839
|
0
|
|
|
|
|
0
|
return 0; |
840
|
|
|
|
|
|
|
} |
841
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
## Returns a new bitvector by reversing the bits in the bitvector on which the |
843
|
|
|
|
|
|
|
## method is invoked. |
844
|
|
|
|
|
|
|
sub reverse { |
845
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
846
|
0
|
|
|
|
|
0
|
my @reverseList = (); |
847
|
0
|
|
|
|
|
0
|
for (my $i=1; $i < $self->{size} + 1; $i++) { |
848
|
0
|
|
|
|
|
0
|
push @reverseList, $self->get_bit( -$i ); |
849
|
|
|
|
|
|
|
} |
850
|
0
|
|
|
|
|
0
|
return Algorithm::BitVector->new( bitlist => \@reverseList ); |
851
|
|
|
|
|
|
|
} |
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
## Using Euclid's Algorithm, returns the greatest common divisor of the integer |
854
|
|
|
|
|
|
|
## value of the bitvector on which the method is invoked and the integer value |
855
|
|
|
|
|
|
|
## of the argument bitvector. |
856
|
|
|
|
|
|
|
sub gcd { |
857
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
858
|
0
|
|
|
|
|
0
|
my $other = shift; |
859
|
0
|
|
|
|
|
0
|
my ($a,$b) = (int($self), int($other)); |
860
|
0
|
0
|
|
|
|
0
|
($a,$b) = ($b,$a) if $a < $b; |
861
|
0
|
|
|
|
|
0
|
while ($b != 0) { |
862
|
0
|
|
|
|
|
0
|
($a, $b) = ($b, $a % $b); |
863
|
|
|
|
|
|
|
} |
864
|
0
|
|
|
|
|
0
|
return Algorithm::BitVector->new( intVal => $a ); |
865
|
|
|
|
|
|
|
} |
866
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
## Calculates the multiplicative inverse of the bitvector on which the method is |
868
|
|
|
|
|
|
|
## invoked modulo the bitvector that is supplied as the argument. Code based on |
869
|
|
|
|
|
|
|
## Extended Euclid's Algorithm. |
870
|
|
|
|
|
|
|
sub multiplicative_inverse { |
871
|
0
|
|
|
0
|
1
|
0
|
my $self = int( shift ); |
872
|
0
|
|
|
|
|
0
|
my $modulus = int( shift ); |
873
|
0
|
|
|
|
|
0
|
my ($mod, $num) = ($modulus, $self); |
874
|
0
|
|
|
|
|
0
|
my ($x, $x_old) = (0, 1); |
875
|
0
|
|
|
|
|
0
|
my ($y, $y_old) = (1, 0); |
876
|
0
|
|
|
|
|
0
|
while ($mod) { |
877
|
0
|
|
|
|
|
0
|
my $quotient = int($num / $mod); |
878
|
0
|
|
|
|
|
0
|
($num, $mod) = ($mod, $num % $mod); |
879
|
0
|
|
|
|
|
0
|
($x, $x_old) = ($x_old - $x * $quotient, $x); |
880
|
0
|
|
|
|
|
0
|
($y, $y_old) = ($y_old - $y * $quotient, $y); |
881
|
|
|
|
|
|
|
} |
882
|
0
|
0
|
|
|
|
0
|
if ($num != 1) { |
883
|
0
|
|
|
|
|
0
|
return 0; |
884
|
|
|
|
|
|
|
} else { |
885
|
0
|
|
|
|
|
0
|
my $MI = ($x_old + $modulus) % $modulus; |
886
|
0
|
|
|
|
|
0
|
return Algorithm::BitVector->new( intVal => $MI ); |
887
|
|
|
|
|
|
|
} |
888
|
|
|
|
|
|
|
} |
889
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
## For a one-bit in-place left non-circular shift. Note that the bitvector size |
891
|
|
|
|
|
|
|
## does not change. The leftmost bit that moves past the first element of the |
892
|
|
|
|
|
|
|
## bitvector is discarded and rightmost bit of the returned vector is set to zero. |
893
|
|
|
|
|
|
|
sub _shift_left_by_one { |
894
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
895
|
0
|
|
|
|
|
0
|
my $size = @{$self->{_vector}}; |
|
0
|
|
|
|
|
0
|
|
896
|
0
|
|
|
|
|
0
|
my @left_most_bits = map {$_ & 1} @{$self->{_vector}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
897
|
0
|
|
|
|
|
0
|
push @left_most_bits, $left_most_bits[0]; |
898
|
0
|
|
|
|
|
0
|
shift @left_most_bits; |
899
|
0
|
|
|
|
|
0
|
@{$self->{_vector}} = map {$_ >> 1} @{$self->{_vector}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
900
|
0
|
|
|
|
|
0
|
my @a = @{$self->{_vector}}; |
|
0
|
|
|
|
|
0
|
|
901
|
0
|
|
|
|
|
0
|
my @b = map {$_ << 15} @left_most_bits; |
|
0
|
|
|
|
|
0
|
|
902
|
0
|
|
|
|
|
0
|
my @interleaved = ( @a, @b )[ map { $_, $_ + @a } ( 0 .. $#a ) ]; |
|
0
|
|
|
|
|
0
|
|
903
|
0
|
|
|
0
|
|
0
|
@{$self->{_vector}} = pairmap {$a | $b} @interleaved; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
904
|
0
|
|
|
|
|
0
|
$self->set_bit(-1,0); |
905
|
|
|
|
|
|
|
} |
906
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
## For an in-place left non-circular shift by n bit positions. The bits shifted |
908
|
|
|
|
|
|
|
## out at the left are discarded. The new bit positions on the right are filled with |
909
|
|
|
|
|
|
|
## zeros |
910
|
|
|
|
|
|
|
sub shift_left { |
911
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
912
|
0
|
|
|
|
|
0
|
my $n = shift; |
913
|
0
|
|
|
|
|
0
|
foreach my $i (0..$n-1) { |
914
|
0
|
|
|
|
|
0
|
$self->_shift_left_by_one(); |
915
|
|
|
|
|
|
|
} |
916
|
0
|
|
|
|
|
0
|
return $self; |
917
|
|
|
|
|
|
|
} |
918
|
|
|
|
|
|
|
|
919
|
|
|
|
|
|
|
## For a one-bit in-place right non-circular shift. Note that bitvector size does |
920
|
|
|
|
|
|
|
## not change. The rightmost bit that moves past the last element of the bitvector |
921
|
|
|
|
|
|
|
## on the right is discarded and the leftmost bit of the returned vector is set to |
922
|
|
|
|
|
|
|
## zero. |
923
|
|
|
|
|
|
|
sub _shift_right_by_one { |
924
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
925
|
0
|
|
|
|
|
0
|
my $size = @{$self->{_vector}}; |
|
0
|
|
|
|
|
0
|
|
926
|
0
|
|
|
|
|
0
|
my @right_most_bits = map {$_ & 0x8000} @{$self->{_vector}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
927
|
0
|
|
|
|
|
0
|
@{$self->{_vector}} = map { $_ & ~0x8000 } @{$self->{_vector}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
928
|
0
|
|
|
|
|
0
|
unshift @right_most_bits, 0; |
929
|
0
|
|
|
|
|
0
|
pop @right_most_bits; |
930
|
0
|
|
|
|
|
0
|
@{$self->{_vector}} = map {$_ << 1} @{$self->{_vector}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
931
|
0
|
|
|
|
|
0
|
my @a = @{$self->{_vector}}; |
|
0
|
|
|
|
|
0
|
|
932
|
0
|
|
|
|
|
0
|
my @b = map {$_ >> 15} @right_most_bits; |
|
0
|
|
|
|
|
0
|
|
933
|
0
|
|
|
|
|
0
|
my @interleaved = ( @a, @b )[ map { $_, $_ + @a } ( 0 .. $#a ) ]; |
|
0
|
|
|
|
|
0
|
|
934
|
0
|
|
|
0
|
|
0
|
@{$self->{_vector}} = pairmap {$a | $b} @interleaved; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
935
|
0
|
|
|
|
|
0
|
$self->set_bit(0,0); |
936
|
|
|
|
|
|
|
} |
937
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
## For an in-place right non-circular shift by n bit positions. The n bits that |
939
|
|
|
|
|
|
|
## move past the last element of the bitvector on the right are discarded and |
940
|
|
|
|
|
|
|
## leftmost new n bit positions filled with zeros. |
941
|
|
|
|
|
|
|
sub shift_right { |
942
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
943
|
0
|
|
|
|
|
0
|
my $n = shift; |
944
|
0
|
|
|
|
|
0
|
foreach my $i (0..$n-1) { |
945
|
0
|
|
|
|
|
0
|
$self->_shift_right_by_one(); |
946
|
|
|
|
|
|
|
} |
947
|
0
|
|
|
|
|
0
|
return $self; |
948
|
|
|
|
|
|
|
} |
949
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
## In the set of polynomials defined over GF(2), multiplies the bitvector on which |
951
|
|
|
|
|
|
|
## the method is invoked with the argument bitvector. Returns the product |
952
|
|
|
|
|
|
|
## bitvector. Note that this method carries out straight polynomial multiplication |
953
|
|
|
|
|
|
|
## as opposed to modulo polynomial multiplication. As a result, the highest power of |
954
|
|
|
|
|
|
|
## the result polynomial will ALWAYS be greater than the highest powers of the |
955
|
|
|
|
|
|
|
## argument polynomials for non-trivial multiplications. |
956
|
|
|
|
|
|
|
sub gf_multiply { |
957
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
958
|
0
|
|
|
|
|
0
|
my $b = shift; |
959
|
0
|
|
|
|
|
0
|
my $a = $self->deep_copy(); |
960
|
0
|
|
|
|
|
0
|
my $b_copy = $b->deep_copy(); |
961
|
0
|
|
|
|
|
0
|
my $a_highest_power = $a->{size} - $a->next_set_bit(0) - 1; |
962
|
0
|
|
|
|
|
0
|
my $b_highest_power = $b->{size} - $b_copy->next_set_bit(0) - 1; |
963
|
0
|
|
|
|
|
0
|
my $result = Algorithm::BitVector->new( size => $a->{size} + $b_copy->{size} ); |
964
|
0
|
|
|
|
|
0
|
$a->pad_from_left( $result->{size} - $a->{size} ); |
965
|
0
|
|
|
|
|
0
|
$b_copy->pad_from_left( $result->{size} - $b_copy->{size} ); |
966
|
0
|
|
|
|
|
0
|
my @b_list = split //, "$b_copy"; |
967
|
0
|
|
|
|
|
0
|
my @enum = (0..@b_list-1, @b_list) [map {$_, $_+ @b_list} (0 .. @b_list - 1)]; |
|
0
|
|
|
|
|
0
|
|
968
|
0
|
|
|
|
|
0
|
for (my $i=0; $i < @enum-1; $i = $i + 2) { |
969
|
0
|
0
|
|
|
|
0
|
if ($enum[$i+1]) { |
970
|
0
|
|
|
|
|
0
|
my $power = $b_copy->{size} - $enum[$i] - 1; |
971
|
0
|
|
|
|
|
0
|
my $a_copy = $a->deep_copy(); |
972
|
0
|
|
|
|
|
0
|
$a_copy->shift_left( $power ); |
973
|
0
|
|
|
|
|
0
|
$result ^= $a_copy; |
974
|
|
|
|
|
|
|
} |
975
|
|
|
|
|
|
|
} |
976
|
0
|
|
|
|
|
0
|
return $result; |
977
|
|
|
|
|
|
|
} |
978
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
## Carries out modular division of a bitvector by the modulus bitvector mod in |
980
|
|
|
|
|
|
|
## GF(2^n) finite field. Returns both the quotient and the remainder. |
981
|
|
|
|
|
|
|
sub gf_divide_by_modulus { |
982
|
0
|
|
|
0
|
1
|
0
|
my $num = shift; |
983
|
0
|
|
|
|
|
0
|
my $mod = shift; |
984
|
0
|
|
|
|
|
0
|
my $n = shift; |
985
|
0
|
0
|
|
|
|
0
|
die "Modulus bit pattern too long" if $mod->{size} > $n + 1; |
986
|
0
|
|
|
|
|
0
|
my $quotient = Algorithm::BitVector->new( intVal => 0, size => $num->{size} ); |
987
|
0
|
|
|
|
|
0
|
my $remainder = $num->deep_copy(); |
988
|
0
|
|
|
|
|
0
|
for (my $i=0; $i < $num->{size}; $i++) { |
989
|
0
|
|
|
|
|
0
|
my $mod_highest_power = $mod->{size} - $mod->next_set_bit(0) - 1; |
990
|
0
|
|
|
|
|
0
|
my $remainder_highest_power; |
991
|
0
|
0
|
|
|
|
0
|
if ($remainder->next_set_bit(0) == -1) { |
992
|
0
|
|
|
|
|
0
|
$remainder_highest_power = 0; |
993
|
|
|
|
|
|
|
} else { |
994
|
0
|
|
|
|
|
0
|
$remainder_highest_power = $remainder->{size} - $remainder->next_set_bit(0) - 1; |
995
|
|
|
|
|
|
|
} |
996
|
0
|
0
|
0
|
|
|
0
|
if (($remainder_highest_power < $mod_highest_power) or (int($remainder) == 0)) { |
997
|
0
|
|
|
|
|
0
|
last; |
998
|
|
|
|
|
|
|
} else { |
999
|
0
|
|
|
|
|
0
|
my $exponent_shift = $remainder_highest_power - $mod_highest_power; |
1000
|
0
|
|
|
|
|
0
|
$quotient->set_bit($quotient->{size} - $exponent_shift - 1, 1); |
1001
|
0
|
|
|
|
|
0
|
my $quotient_mod_product = $mod->deep_copy(); |
1002
|
0
|
|
|
|
|
0
|
$quotient_mod_product->pad_from_left($remainder->{size} - $mod->{size}); |
1003
|
0
|
|
|
|
|
0
|
$quotient_mod_product->shift_left($exponent_shift); |
1004
|
0
|
|
|
|
|
0
|
$remainder ^= $quotient_mod_product; |
1005
|
|
|
|
|
|
|
} |
1006
|
|
|
|
|
|
|
} |
1007
|
0
|
0
|
|
|
|
0
|
if ($remainder->{size} > $n) { |
1008
|
|
|
|
|
|
|
$remainder = Algorithm::BitVector->new( |
1009
|
|
|
|
|
|
|
# bitlist => $remainder->get_bit([$remainder->{size}-$n .. $remainder->{size}-1])); |
1010
|
0
|
|
|
|
|
0
|
bitlist => $remainder->get_bit([$remainder->{size}-$n .. $remainder->{size}])); |
1011
|
|
|
|
|
|
|
} |
1012
|
0
|
|
|
|
|
0
|
return ($quotient, $remainder); |
1013
|
|
|
|
|
|
|
} |
1014
|
|
|
|
|
|
|
|
1015
|
|
|
|
|
|
|
## Multiplies a bitvector with the bitvector b in GF(2^n) finite field with the |
1016
|
|
|
|
|
|
|
## modulus bit pattern set to mod |
1017
|
|
|
|
|
|
|
sub gf_multiply_modular { |
1018
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
1019
|
0
|
|
|
|
|
0
|
my $b = shift; |
1020
|
0
|
|
|
|
|
0
|
my $mod = shift; |
1021
|
0
|
|
|
|
|
0
|
my $n = shift; |
1022
|
0
|
|
|
|
|
0
|
my $a_copy = $self->deep_copy(); |
1023
|
0
|
|
|
|
|
0
|
my $b_copy = $b->deep_copy(); |
1024
|
0
|
|
|
|
|
0
|
my $product = $a_copy->gf_multiply($b_copy); |
1025
|
0
|
|
|
|
|
0
|
my ($quotient, $remainder) = $product->gf_divide_by_modulus($mod, $n); |
1026
|
0
|
|
|
|
|
0
|
return $remainder |
1027
|
|
|
|
|
|
|
} |
1028
|
|
|
|
|
|
|
|
1029
|
|
|
|
|
|
|
## Returns the multiplicative inverse of a vector in the GF(2^n) finite field |
1030
|
|
|
|
|
|
|
## with the modulus polynomial set to mod |
1031
|
|
|
|
|
|
|
sub gf_MI { |
1032
|
0
|
|
|
0
|
1
|
0
|
my $num = shift; |
1033
|
0
|
|
|
|
|
0
|
my $mod = shift; |
1034
|
0
|
|
|
|
|
0
|
my $n = shift; |
1035
|
0
|
|
|
|
|
0
|
my ($NUM, $MOD) = ($num->deep_copy(), $mod->deep_copy()); |
1036
|
0
|
|
|
|
|
0
|
my $x = Algorithm::BitVector->new( size => $mod->{size} ); |
1037
|
0
|
|
|
|
|
0
|
my $x_old = Algorithm::BitVector->new( intVal => 1, size => $mod->{size} ); |
1038
|
0
|
|
|
|
|
0
|
my $y = Algorithm::BitVector->new( intVal => 1, size => $mod->{size} ); |
1039
|
0
|
|
|
|
|
0
|
my $y_old = Algorithm::BitVector->new( size => $mod->{size} ); |
1040
|
0
|
|
|
|
|
0
|
my ($quotient, $remainder); |
1041
|
0
|
|
|
|
|
0
|
while (int($mod)) { |
1042
|
0
|
|
|
|
|
0
|
($quotient, $remainder) = $num->gf_divide_by_modulus($mod, $n); |
1043
|
0
|
|
|
|
|
0
|
($num, $mod) = ($mod, $remainder); |
1044
|
0
|
|
|
|
|
0
|
($x, $x_old) = ($x_old ^ $quotient->gf_multiply($x), $x); |
1045
|
0
|
|
|
|
|
0
|
($y, $y_old) = ($y_old ^ $quotient->gf_multiply($y), $y); |
1046
|
|
|
|
|
|
|
} |
1047
|
0
|
0
|
|
|
|
0
|
if (int($num) != 1) { |
1048
|
0
|
|
|
|
|
0
|
return "NO MI. However, the GCD of $NUM and $MOD is $num\n"; |
1049
|
|
|
|
|
|
|
} else { |
1050
|
0
|
|
|
|
|
0
|
my $z = $x_old ^ $MOD; |
1051
|
0
|
|
|
|
|
0
|
($quotient, $remainder) = $z->gf_divide_by_modulus($MOD, $n); |
1052
|
0
|
|
|
|
|
0
|
return $remainder; |
1053
|
|
|
|
|
|
|
} |
1054
|
|
|
|
|
|
|
} |
1055
|
|
|
|
|
|
|
|
1056
|
|
|
|
|
|
|
## Returns a list of the consecutive runs of 1's and 0's in the bitvector. |
1057
|
|
|
|
|
|
|
## Each run is either a string of all 1's or a string of all 0's. |
1058
|
|
|
|
|
|
|
sub runs { |
1059
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
1060
|
0
|
0
|
|
|
|
0
|
die "An empty vector has no runs" if $self->{size} == 0; |
1061
|
0
|
|
|
|
|
0
|
my @allruns = (); |
1062
|
0
|
|
|
|
|
0
|
my $run = ''; |
1063
|
0
|
|
|
|
|
0
|
my $previous_bit = $self->get_bit(0); |
1064
|
0
|
0
|
|
|
|
0
|
if ($previous_bit == 0) { |
1065
|
0
|
|
|
|
|
0
|
$run = '0'; |
1066
|
|
|
|
|
|
|
} else { |
1067
|
0
|
|
|
|
|
0
|
$run = '1'; |
1068
|
|
|
|
|
|
|
} |
1069
|
0
|
|
|
|
|
0
|
my @bitlist = split //, "$self"; |
1070
|
0
|
|
|
|
|
0
|
shift @bitlist; |
1071
|
0
|
|
|
|
|
0
|
foreach my $bit (@bitlist) { |
1072
|
0
|
0
|
0
|
|
|
0
|
if (($bit == 0) && ($previous_bit == 0)) { |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
1073
|
0
|
|
|
|
|
0
|
$run .= '0'; |
1074
|
|
|
|
|
|
|
} elsif (($bit == 1) && ($previous_bit == 0)) { |
1075
|
0
|
|
|
|
|
0
|
push @allruns, $run; |
1076
|
0
|
|
|
|
|
0
|
$run = '1'; |
1077
|
|
|
|
|
|
|
} elsif (($bit == 0) && ($previous_bit == 1)) { |
1078
|
0
|
|
|
|
|
0
|
push @allruns, $run; |
1079
|
0
|
|
|
|
|
0
|
$run = '0'; |
1080
|
|
|
|
|
|
|
} else { |
1081
|
0
|
|
|
|
|
0
|
$run .= '1'; |
1082
|
|
|
|
|
|
|
} |
1083
|
0
|
|
|
|
|
0
|
$previous_bit = $bit; |
1084
|
|
|
|
|
|
|
} |
1085
|
0
|
|
|
|
|
0
|
push @allruns, $run; |
1086
|
|
|
|
|
|
|
return @allruns |
1087
|
0
|
|
|
|
|
0
|
} |
1088
|
|
|
|
|
|
|
|
1089
|
|
|
|
|
|
|
## This method returns the "canonical" form of a BitVector instance that is obtained by |
1090
|
|
|
|
|
|
|
## circularly rotating the bit pattern through all possible shifts and returning the |
1091
|
|
|
|
|
|
|
## pattern with the maximum number of leading zeros. This is also the minimum int value |
1092
|
|
|
|
|
|
|
## version of a bit pattern. This method is useful in the "Local Binary Pattern" |
1093
|
|
|
|
|
|
|
## algorithm for characterizing image textures. If you are curious as to how, see my |
1094
|
|
|
|
|
|
|
## tutorial on "Measuring Texture and Color in Images." |
1095
|
|
|
|
|
|
|
sub min_canonical { |
1096
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
1097
|
0
|
|
|
|
|
0
|
my @intvals_for_circular_shifts = map {int($self << 1)} 0 .. $self->length(); |
|
0
|
|
|
|
|
0
|
|
1098
|
0
|
|
|
|
|
0
|
my $min_int_val = min @intvals_for_circular_shifts; |
1099
|
0
|
|
|
|
|
0
|
return Algorithm::BitVector->new( intVal => $min_int_val, size => $self->length() ); |
1100
|
|
|
|
|
|
|
} |
1101
|
|
|
|
|
|
|
|
1102
|
|
|
|
|
|
|
## Check if the integer value of the bitvector is a prime through the Miller-Rabin |
1103
|
|
|
|
|
|
|
## probabilistic test of primality. If not found to be a composite, estimate the |
1104
|
|
|
|
|
|
|
## probability of the bitvector being a prime using this test. |
1105
|
|
|
|
|
|
|
sub test_for_primality { |
1106
|
0
|
|
|
0
|
1
|
0
|
my $p = int(shift); |
1107
|
0
|
0
|
|
|
|
0
|
die "\nThe primality test method test_for_primality() is intended for only " . |
1108
|
|
|
|
|
|
|
"small integers --- integers that are relatively small in relation to " . |
1109
|
|
|
|
|
|
|
"the largest integer that can fit Perl's 4-byte int representation:$!" |
1110
|
|
|
|
|
|
|
if $p > 0x7f_ff_ff_ff; |
1111
|
0
|
0
|
|
|
|
0
|
return "is NOT a prime" if $p == 1; |
1112
|
0
|
|
|
|
|
0
|
my @probes = (2,3,5,7,11,13,17); |
1113
|
0
|
|
|
|
|
0
|
foreach my $a (@probes) { |
1114
|
0
|
0
|
|
|
|
0
|
return "is a prime" if $a == $p; |
1115
|
|
|
|
|
|
|
} |
1116
|
0
|
0
|
|
0
|
|
0
|
return "is NOT a prime" if any {$p % $_ == 0} @probes; |
|
0
|
|
|
|
|
0
|
|
1117
|
0
|
|
|
|
|
0
|
my ($k, $q) = (0, $p-1); |
1118
|
0
|
|
|
|
|
0
|
while (! ($q & 1)) { |
1119
|
0
|
|
|
|
|
0
|
$q >>= 1; |
1120
|
0
|
|
|
|
|
0
|
$k++; |
1121
|
|
|
|
|
|
|
} |
1122
|
0
|
|
|
|
|
0
|
foreach my $a (@probes) { |
1123
|
0
|
|
|
|
|
0
|
my $a_raised_to_q = _powmod_small_ints($a, int($q), $p); |
1124
|
0
|
0
|
0
|
|
|
0
|
next if $a_raised_to_q == 1 or $a_raised_to_q == $p - 1; |
1125
|
0
|
|
|
|
|
0
|
my $a_raised_to_jq = $a_raised_to_q; |
1126
|
0
|
|
|
|
|
0
|
my $primeflag = 0; |
1127
|
0
|
|
|
|
|
0
|
foreach my $j (0..$k-1) { |
1128
|
0
|
|
|
|
|
0
|
$a_raised_to_jq = _powmod_small_ints($a_raised_to_jq, 2, $p); |
1129
|
0
|
0
|
|
|
|
0
|
if ($a_raised_to_jq == $p-1) { |
1130
|
0
|
|
|
|
|
0
|
$primeflag = 1; |
1131
|
0
|
|
|
|
|
0
|
last; |
1132
|
|
|
|
|
|
|
} |
1133
|
|
|
|
|
|
|
} |
1134
|
0
|
0
|
|
|
|
0
|
return "is NOT a prime" unless $primeflag; |
1135
|
|
|
|
|
|
|
} |
1136
|
0
|
|
|
|
|
0
|
my $probability_of_prime = 1 - 1.0/(4 ** @probes); |
1137
|
0
|
|
|
|
|
0
|
return "is a prime with probability $probability_of_prime"; |
1138
|
|
|
|
|
|
|
} |
1139
|
|
|
|
|
|
|
|
1140
|
|
|
|
|
|
|
## This routine is for modular exponentiation of small integers, meaning the |
1141
|
|
|
|
|
|
|
## integers that can be accommodated (before and after exponentiation) in the native |
1142
|
|
|
|
|
|
|
## 4-byte int representation. For larger integers, a call to this function should |
1143
|
|
|
|
|
|
|
## be replaced by a call to modular exponentiation of the Math::BigInt module. |
1144
|
|
|
|
|
|
|
sub _powmod_small_ints { |
1145
|
0
|
|
|
0
|
|
0
|
my $base = shift; |
1146
|
0
|
|
|
|
|
0
|
my $exponent = shift; |
1147
|
0
|
|
|
|
|
0
|
my $mod = int(shift); |
1148
|
|
|
|
|
|
|
warn "This is just a warning: The modular exponentiation method is not meant for very large numbers (IMPORTANT: This is just a very rough check on the size of the numbers involved)" |
1149
|
0
|
0
|
|
0
|
|
0
|
if any {$_ > 0x0f_ff_ff_ff} (int($base), int($exponent), int($mod)); |
|
0
|
|
|
|
|
0
|
|
1150
|
0
|
|
|
|
|
0
|
my $result = 1; |
1151
|
0
|
|
|
|
|
0
|
my $a = int($base); |
1152
|
0
|
|
|
|
|
0
|
my $b = $exponent; |
1153
|
0
|
|
|
|
|
0
|
while (int($b) > 0) { |
1154
|
0
|
0
|
|
|
|
0
|
$result = ($result * $a) % $mod if int($b) & 1; |
1155
|
0
|
|
|
|
|
0
|
$b = $b >> 1; |
1156
|
0
|
|
|
|
|
0
|
$a = ($a * $a) % $mod; |
1157
|
|
|
|
|
|
|
} |
1158
|
0
|
|
|
|
|
0
|
return $result; |
1159
|
|
|
|
|
|
|
} |
1160
|
|
|
|
|
|
|
|
1161
|
|
|
|
|
|
|
## This method is for a generating a bit pattern of a given size with random bits. |
1162
|
|
|
|
|
|
|
sub gen_random_bits { |
1163
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
1164
|
0
|
|
|
|
|
0
|
my $width = shift; |
1165
|
0
|
|
|
|
|
0
|
my $candidate_bits = "0b" . join '', Math::Random::random_uniform_integer($width, 0, 1); |
1166
|
0
|
|
|
|
|
0
|
my $candidate = oct $candidate_bits; |
1167
|
0
|
|
|
|
|
0
|
$candidate |= 1; |
1168
|
0
|
|
|
|
|
0
|
$candidate |= (1 << $width-1); |
1169
|
0
|
|
|
|
|
0
|
$candidate |= (2 << $width-3); |
1170
|
0
|
|
|
|
|
0
|
return Algorithm::BitVector->new( intVal => $candidate ); |
1171
|
|
|
|
|
|
|
} |
1172
|
|
|
|
|
|
|
|
1173
|
|
|
|
|
|
|
sub length { |
1174
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
1175
|
0
|
|
|
|
|
0
|
return $self->{size}; |
1176
|
|
|
|
|
|
|
} |
1177
|
|
|
|
|
|
|
|
1178
|
|
|
|
|
|
|
sub _check_for_illegal_params { |
1179
|
3
|
|
|
3
|
|
7
|
my @params = @_; |
1180
|
3
|
|
|
|
|
8
|
my @legal_params = qw / filename |
1181
|
|
|
|
|
|
|
size |
1182
|
|
|
|
|
|
|
intVal |
1183
|
|
|
|
|
|
|
bitlist |
1184
|
|
|
|
|
|
|
bitstring |
1185
|
|
|
|
|
|
|
hexstring |
1186
|
|
|
|
|
|
|
textstring |
1187
|
|
|
|
|
|
|
/; |
1188
|
3
|
|
|
|
|
6
|
my $found_match_flag; |
1189
|
3
|
|
|
|
|
5
|
foreach my $param (@params) { |
1190
|
3
|
|
|
|
|
6
|
foreach my $legal (@legal_params) { |
1191
|
12
|
|
|
|
|
16
|
$found_match_flag = 0; |
1192
|
12
|
100
|
|
|
|
25
|
if ($param eq $legal) { |
1193
|
3
|
|
|
|
|
5
|
$found_match_flag = 1; |
1194
|
3
|
|
|
|
|
5
|
last; |
1195
|
|
|
|
|
|
|
} |
1196
|
|
|
|
|
|
|
} |
1197
|
3
|
50
|
|
|
|
8
|
last if $found_match_flag == 0; |
1198
|
|
|
|
|
|
|
} |
1199
|
3
|
|
|
|
|
11
|
return $found_match_flag; |
1200
|
|
|
|
|
|
|
} |
1201
|
|
|
|
|
|
|
|
1202
|
|
|
|
|
|
|
1; |
1203
|
|
|
|
|
|
|
|
1204
|
|
|
|
|
|
|
|
1205
|
|
|
|
|
|
|
=pod |
1206
|
|
|
|
|
|
|
|
1207
|
|
|
|
|
|
|
=head1 NAME |
1208
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
Algorithm::BitVector --- A memory efficient packed representation of arbitrary sized |
1210
|
|
|
|
|
|
|
bit arrays and for logical and arithmetic operations on such arrays. |
1211
|
|
|
|
|
|
|
|
1212
|
|
|
|
|
|
|
=head1 SYNOPSIS |
1213
|
|
|
|
|
|
|
|
1214
|
|
|
|
|
|
|
use Algorithm::BitVector; |
1215
|
|
|
|
|
|
|
|
1216
|
|
|
|
|
|
|
# Constructing a given sized bitvector of all zeros: |
1217
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( size => 7 ); |
1218
|
|
|
|
|
|
|
print "$bv\n"; # 0000000 |
1219
|
|
|
|
|
|
|
|
1220
|
|
|
|
|
|
|
# Constructing a bitvector whose integer value is specified: |
1221
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( intVal => 123456 ); |
1222
|
|
|
|
|
|
|
print "$bv\n"; # 11110001001000000 |
1223
|
|
|
|
|
|
|
print int($bv); # 123456 |
1224
|
|
|
|
|
|
|
|
1225
|
|
|
|
|
|
|
# Constructing a bitvector from a very large integer: |
1226
|
|
|
|
|
|
|
use Math::BigInt; |
1227
|
|
|
|
|
|
|
$x = Math::BigInt->new('12345678901234567890123456789012345678901234567890'); |
1228
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( intVal => $x ); |
1229
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
# Constructing a bitvector from a given bit string: |
1231
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitstring => '00110011' ); |
1232
|
|
|
|
|
|
|
|
1233
|
|
|
|
|
|
|
# Constructing a bitvector from an ASCII text string: |
1234
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( textstring => "hello\njello" ); |
1235
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
# Constructing a bitvector from a hex string: |
1237
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( hexstring => "68656c6c6f" ); |
1238
|
|
|
|
|
|
|
|
1239
|
|
|
|
|
|
|
# Constructing a bitvector from a bit list passed as an anonymous array: |
1240
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitlist => [1, 1, 0, 1] ); |
1241
|
|
|
|
|
|
|
|
1242
|
|
|
|
|
|
|
# Constructing a bitvector from the contents of a disk file: |
1243
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( filename => 'testinput.txt' ); |
1244
|
|
|
|
|
|
|
$bv1 = $bv->read_bits_from_file(64); # bitvector from the first 64 bits |
1245
|
|
|
|
|
|
|
# and so on |
1246
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
|
1248
|
|
|
|
|
|
|
=head1 CHANGES |
1249
|
|
|
|
|
|
|
|
1250
|
|
|
|
|
|
|
Version 1.26 incorporates the following changes: (1) It allows you to carry out |
1251
|
|
|
|
|
|
|
slice-based set and get operations on a BitVector object. The two new methods for |
1252
|
|
|
|
|
|
|
these operations are named C and C. (2) It includes a new |
1253
|
|
|
|
|
|
|
method named C that returns a circularly rotated version of a |
1254
|
|
|
|
|
|
|
BitVector with the least integer value. For obvious reasons, this version would also |
1255
|
|
|
|
|
|
|
have the largest number of leading zeros. And (3) It fixes a bug in the |
1256
|
|
|
|
|
|
|
implementation of the method C. |
1257
|
|
|
|
|
|
|
|
1258
|
|
|
|
|
|
|
Version 1.25 incorporates bugfix for the case when you try to construct a bitvector |
1259
|
|
|
|
|
|
|
of a specified length from a large integer that is supplied to the module constructor |
1260
|
|
|
|
|
|
|
as a C object. |
1261
|
|
|
|
|
|
|
|
1262
|
|
|
|
|
|
|
Version 1.24 includes in the C file the minimum version restriction on |
1263
|
|
|
|
|
|
|
the C module that is imported. |
1264
|
|
|
|
|
|
|
|
1265
|
|
|
|
|
|
|
Version 1.23 mentions the required modules in the C file but with no |
1266
|
|
|
|
|
|
|
minimum version numbers. Additionally, the documentation associated with the methods |
1267
|
|
|
|
|
|
|
was significantly upgraded in this version. |
1268
|
|
|
|
|
|
|
|
1269
|
|
|
|
|
|
|
Version 1.22 removes the Perl version restriction from the module and the |
1270
|
|
|
|
|
|
|
C files and the C restrictions from the C file. |
1271
|
|
|
|
|
|
|
|
1272
|
|
|
|
|
|
|
Version 1.21 fixes a bug in the code for the Miller-Rabin primality test function |
1273
|
|
|
|
|
|
|
C. This version also places a hard limit on the size of the |
1274
|
|
|
|
|
|
|
integers that are allowed to be tested for primality. |
1275
|
|
|
|
|
|
|
|
1276
|
|
|
|
|
|
|
Version 1.2 fixes an important bug in creating bitvectors from the contents of a disk |
1277
|
|
|
|
|
|
|
file. This version also includes corrections for some of the documentation errors |
1278
|
|
|
|
|
|
|
discovered. |
1279
|
|
|
|
|
|
|
|
1280
|
|
|
|
|
|
|
Version 1.1 incorporates additional type checking on the operands for the overloaded |
1281
|
|
|
|
|
|
|
operators. Also fixed some minor documentation formatting issues. |
1282
|
|
|
|
|
|
|
|
1283
|
|
|
|
|
|
|
=head1 DESCRIPTION |
1284
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
My main motivation for creating this module was to provide the students at Purdue and |
1286
|
|
|
|
|
|
|
elsewhere with a Perl class whose API is the same as that of my Python based |
1287
|
|
|
|
|
|
|
C module that appears to have become popular for prototyping algorithms |
1288
|
|
|
|
|
|
|
for cryptography and hash functions. |
1289
|
|
|
|
|
|
|
|
1290
|
|
|
|
|
|
|
This module stores the bits of a bitvector in 16-bit unsigned shorts. As you can see |
1291
|
|
|
|
|
|
|
in the constructor code for C, after resolving the arguments with which the |
1292
|
|
|
|
|
|
|
constructor is called, the very first thing the constructor does is to figure out how |
1293
|
|
|
|
|
|
|
many of those 2-byte shorts it needs for the bits. That does not imply that the size |
1294
|
|
|
|
|
|
|
of a bit array that is stored in a bitvector must be a multiple of 16. B
|
1295
|
|
|
|
|
|
|
can be of any size whatsoever.> The C class keeps track of the |
1296
|
|
|
|
|
|
|
number of bits through its C instance variable. |
1297
|
|
|
|
|
|
|
|
1298
|
|
|
|
|
|
|
Note that, except for one case, the constructor must be called with a single keyword |
1299
|
|
|
|
|
|
|
argument, which determines how the bitvector will be constructed. The single |
1300
|
|
|
|
|
|
|
exception to this rule is for the keyword argument C which you would normally |
1301
|
|
|
|
|
|
|
use for constructing a bitvector from an integer. The additional option you can |
1302
|
|
|
|
|
|
|
supply with C is C. When both C and C are specified in a |
1303
|
|
|
|
|
|
|
constructor call, you get a bitvector of the specified size provided the value |
1304
|
|
|
|
|
|
|
supplied for C is larger than what it takes to accommodate the bits for the |
1305
|
|
|
|
|
|
|
C integer. |
1306
|
|
|
|
|
|
|
|
1307
|
|
|
|
|
|
|
In addition to constructing bitvectors from integers, this module can also construct |
1308
|
|
|
|
|
|
|
bitvectors from bit strings, from ASCII text strings, from hex strings, from a list |
1309
|
|
|
|
|
|
|
of bits, and from the contents of a file. With regards to constructing bitvectors |
1310
|
|
|
|
|
|
|
from integers, the module can construct very large bitvectors from very large |
1311
|
|
|
|
|
|
|
integers stored as C objects. |
1312
|
|
|
|
|
|
|
|
1313
|
|
|
|
|
|
|
=head1 OVERLOADED OPERATORS |
1314
|
|
|
|
|
|
|
|
1315
|
|
|
|
|
|
|
The following C |
1316
|
|
|
|
|
|
|
overloaded operators. Since C is set to 1, several other operators become |
1317
|
|
|
|
|
|
|
overloaded by autogeneration from those shown below. For example, overloading of the |
1318
|
|
|
|
|
|
|
3-way numerical comparison operator C<< <=> >> automatically overloads the C<< < >>, |
1319
|
|
|
|
|
|
|
C<< <= >>, C<< > >>, C<< >= >>, C<< == >>, and C<< != >> operators. |
1320
|
|
|
|
|
|
|
|
1321
|
|
|
|
|
|
|
use overload '+' => '_add', |
1322
|
|
|
|
|
|
|
'""' => '_str', |
1323
|
|
|
|
|
|
|
'0+' => '_int', |
1324
|
|
|
|
|
|
|
'~' => '_invert', |
1325
|
|
|
|
|
|
|
'|' => '_or', |
1326
|
|
|
|
|
|
|
'&' => '_and', |
1327
|
|
|
|
|
|
|
'^' => '_xor', |
1328
|
|
|
|
|
|
|
'<=>' => '_compare', |
1329
|
|
|
|
|
|
|
'<<' => '_lshift', |
1330
|
|
|
|
|
|
|
'>>' => '_rshift', |
1331
|
|
|
|
|
|
|
'<>' => '_iter', |
1332
|
|
|
|
|
|
|
'fallback' => 1; |
1333
|
|
|
|
|
|
|
|
1334
|
|
|
|
|
|
|
It is B to remember that the overloadings for the `C<<< << >>>' and `C<<< |
1335
|
|
|
|
|
|
|
>> >>>' operators are for B left and right shifts (their usual meaning as |
1336
|
|
|
|
|
|
|
bitwise operators is for non-circular shifts). This was done because the |
1337
|
|
|
|
|
|
|
applications for which this module is intended is more likely to use circular shifts |
1338
|
|
|
|
|
|
|
of bit fields than non-circular shifts. You can still carry out non-circular shifts |
1339
|
|
|
|
|
|
|
by calling the methods C and C as illustrated elsewhere |
1340
|
|
|
|
|
|
|
in this documentation. |
1341
|
|
|
|
|
|
|
|
1342
|
|
|
|
|
|
|
Another B thing to bear in mind is the overloading of the `C<+>' operator. |
1343
|
|
|
|
|
|
|
It is B addition. On the other hand, it is a concatenation of the two operand |
1344
|
|
|
|
|
|
|
bitvectors. This was done to keep the usage of this operator the same as in the |
1345
|
|
|
|
|
|
|
Python version of this module. |
1346
|
|
|
|
|
|
|
|
1347
|
|
|
|
|
|
|
By virtue of how the operators are overloaded, you can make the calls listed in the |
1348
|
|
|
|
|
|
|
rest of this section. To illustrate these calls, I will use the following two bit |
1349
|
|
|
|
|
|
|
vectors: |
1350
|
|
|
|
|
|
|
|
1351
|
|
|
|
|
|
|
$bv1 = Algorithm::BitVector->new( bitstring => "111000" ); |
1352
|
|
|
|
|
|
|
$bv2 = Algorithm::BitVector->new( bitstring => "000101000" ); |
1353
|
|
|
|
|
|
|
|
1354
|
|
|
|
|
|
|
These two bitvectors are intentionally of different lengths to illustrate what role |
1355
|
|
|
|
|
|
|
the size differences play in how the various operators work. |
1356
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
=over 4 |
1358
|
|
|
|
|
|
|
|
1359
|
|
|
|
|
|
|
=item B |
1360
|
|
|
|
|
|
|
|
1361
|
|
|
|
|
|
|
$bv3 = $bv1 + $bv2; # 111000000101000 |
1362
|
|
|
|
|
|
|
|
1363
|
|
|
|
|
|
|
The concatenation of two bitvectors is returned as a new bitvector. This is made |
1364
|
|
|
|
|
|
|
possible by the overload definition for the C<+> operator. |
1365
|
|
|
|
|
|
|
|
1366
|
|
|
|
|
|
|
Note that the following also works: |
1367
|
|
|
|
|
|
|
|
1368
|
|
|
|
|
|
|
print $bv1 . "hello"; # 111000hello |
1369
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
In this case, Perl implicitly converts the left operand of the `.' operator into a |
1371
|
|
|
|
|
|
|
string (which is made possible by the overloading for the stringification operator in |
1372
|
|
|
|
|
|
|
this module) and then returns the result as a string. |
1373
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
=item B |
1375
|
|
|
|
|
|
|
|
1376
|
|
|
|
|
|
|
print "$bv1"; # 111000 |
1377
|
|
|
|
|
|
|
|
1378
|
|
|
|
|
|
|
This is made possible for the overload definition for the C<""> operator. |
1379
|
|
|
|
|
|
|
|
1380
|
|
|
|
|
|
|
=item B |
1381
|
|
|
|
|
|
|
|
1382
|
|
|
|
|
|
|
print int($bv1); # 56 |
1383
|
|
|
|
|
|
|
|
1384
|
|
|
|
|
|
|
This is made possible by the overload definition for the C<0+> operator. |
1385
|
|
|
|
|
|
|
|
1386
|
|
|
|
|
|
|
=item B |
1387
|
|
|
|
|
|
|
|
1388
|
|
|
|
|
|
|
$bv3 = ~ $bv1; |
1389
|
|
|
|
|
|
|
print $bv3; # 000111 |
1390
|
|
|
|
|
|
|
|
1391
|
|
|
|
|
|
|
This is made possible by the overload definition for the C<~> operator. The original |
1392
|
|
|
|
|
|
|
bitvector on which this unary operator is invoked remains unchanged. |
1393
|
|
|
|
|
|
|
|
1394
|
|
|
|
|
|
|
=item B |
1395
|
|
|
|
|
|
|
|
1396
|
|
|
|
|
|
|
$bv3 = $bv1 | $bv2; # 000111000 |
1397
|
|
|
|
|
|
|
|
1398
|
|
|
|
|
|
|
When two bitvectors are of unequal length (as is the case here), the shorter vector |
1399
|
|
|
|
|
|
|
is zero-padded on the left to equalize their lengths before the application of the |
1400
|
|
|
|
|
|
|
logical operation. If this auto-padding property is not something you want, you |
1401
|
|
|
|
|
|
|
should check the lengths of the argument bitvectors in your own script before |
1402
|
|
|
|
|
|
|
invoking this operator. The result of the logical OR operation is returned as a new |
1403
|
|
|
|
|
|
|
bitvector. The two operand bitvectors remain unchanged. |
1404
|
|
|
|
|
|
|
|
1405
|
|
|
|
|
|
|
=item B |
1406
|
|
|
|
|
|
|
|
1407
|
|
|
|
|
|
|
$bv3 = $bv1 & $bv2; # 000101000 |
1408
|
|
|
|
|
|
|
|
1409
|
|
|
|
|
|
|
When two bitvectors are of unequal length (as is the case here), the shorter vector |
1410
|
|
|
|
|
|
|
is zero-padded on the left to equalize their lengths before the application of the |
1411
|
|
|
|
|
|
|
logical operation. If this auto-padding property is not something you want, you |
1412
|
|
|
|
|
|
|
should check the lengths of the argument bitvectors in your own script before |
1413
|
|
|
|
|
|
|
invoking this operator. The result of the logical AND operation is returned as a new |
1414
|
|
|
|
|
|
|
bitvector. The two operand bitvectors remain unchanged. |
1415
|
|
|
|
|
|
|
|
1416
|
|
|
|
|
|
|
|
1417
|
|
|
|
|
|
|
=item B |
1418
|
|
|
|
|
|
|
|
1419
|
|
|
|
|
|
|
$bv3 = $bv1 ^ $bv2; # 000010000 |
1420
|
|
|
|
|
|
|
|
1421
|
|
|
|
|
|
|
When two bitvectors are of unequal length (as is the case here), the shorter vector |
1422
|
|
|
|
|
|
|
is zero-padded on the left to equalize their lengths before the application of the |
1423
|
|
|
|
|
|
|
logical operation. If this auto-padding property is not something you want, you |
1424
|
|
|
|
|
|
|
should check the lengths of the argument bitvectors in your own script before |
1425
|
|
|
|
|
|
|
invoking this operator. The result of the logical XOR operation is returned as a new |
1426
|
|
|
|
|
|
|
bitvector. The two operand bitvectors remain unchanged. |
1427
|
|
|
|
|
|
|
|
1428
|
|
|
|
|
|
|
|
1429
|
|
|
|
|
|
|
=item B |
1430
|
|
|
|
|
|
|
|
1431
|
|
|
|
|
|
|
$bv1 < $bv2 ? print "yes\n" : print "no\n"; # no |
1432
|
|
|
|
|
|
|
|
1433
|
|
|
|
|
|
|
$bv1 > $bv2 ? print "yes\n" : print "no\n"; # yes |
1434
|
|
|
|
|
|
|
|
1435
|
|
|
|
|
|
|
$bv1 <= $bv2 ? print "yes\n" : print "no\n"; # no |
1436
|
|
|
|
|
|
|
|
1437
|
|
|
|
|
|
|
$bv1 >= $bv2 ? print "yes\n" : print "no\n"; # yes |
1438
|
|
|
|
|
|
|
|
1439
|
|
|
|
|
|
|
$bv1 == $bv2 ? print "yes\n" : print "no\n"; # no |
1440
|
|
|
|
|
|
|
|
1441
|
|
|
|
|
|
|
$bv1 != $bv2 ? print "yes\n" : print "no\n"; # yes |
1442
|
|
|
|
|
|
|
|
1443
|
|
|
|
|
|
|
The overload definitions for all these operators are autogenerated from the overload |
1444
|
|
|
|
|
|
|
definition for the 3-way numerical comparison operator 'C<< <=> >>'. B
|
1445
|
|
|
|
|
|
|
bitvectors are compared on the basis of their integer values.> That is, C<$bv1> is |
1446
|
|
|
|
|
|
|
less than C<$bv2> if C is less than C. |
1447
|
|
|
|
|
|
|
|
1448
|
|
|
|
|
|
|
=item B |
1449
|
|
|
|
|
|
|
|
1450
|
|
|
|
|
|
|
$n = 3; |
1451
|
|
|
|
|
|
|
|
1452
|
|
|
|
|
|
|
$bv1 << $n; # $bv1 is now 000111 |
1453
|
|
|
|
|
|
|
$bv1 >> $n; # $bv1 is now 111000 |
1454
|
|
|
|
|
|
|
|
1455
|
|
|
|
|
|
|
Since Perl does not expect these two operators to be invoked in a void context, such |
1456
|
|
|
|
|
|
|
statements in your code will elicit a warning from Perl to that effect. If these |
1457
|
|
|
|
|
|
|
warnings annoy you, you can turn them off by surrounding such statements with C
|
1458
|
|
|
|
|
|
|
warnings "void";> and C |
1459
|
|
|
|
|
|
|
such statements in the following manner: |
1460
|
|
|
|
|
|
|
|
1461
|
|
|
|
|
|
|
$bv1 = $bv1 << $n; |
1462
|
|
|
|
|
|
|
$bv2 = $bv1 >> $n; |
1463
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
That works because the overload definitions for these bit shift operators return the |
1465
|
|
|
|
|
|
|
bitvector object on which they are invoked. As it turns out, this also allows for |
1466
|
|
|
|
|
|
|
chained invocation of these operators, as in |
1467
|
|
|
|
|
|
|
|
1468
|
|
|
|
|
|
|
$bv1 = $bv1 << 3 << 1 >> 2; # 100011 |
1469
|
|
|
|
|
|
|
|
1470
|
|
|
|
|
|
|
$bv1 = $bv1 << 2 >> 1 >> 3; # 111000 |
1471
|
|
|
|
|
|
|
|
1472
|
|
|
|
|
|
|
=item B |
1473
|
|
|
|
|
|
|
|
1474
|
|
|
|
|
|
|
while (<$bv1>) { |
1475
|
|
|
|
|
|
|
print "$_ "; |
1476
|
|
|
|
|
|
|
} # 1 1 1 0 0 0 |
1477
|
|
|
|
|
|
|
|
1478
|
|
|
|
|
|
|
This is made possible by the overload definition for the C<< <> >> operator. The |
1479
|
|
|
|
|
|
|
C class includes an inner class C for this |
1480
|
|
|
|
|
|
|
purpose. |
1481
|
|
|
|
|
|
|
|
1482
|
|
|
|
|
|
|
=back |
1483
|
|
|
|
|
|
|
|
1484
|
|
|
|
|
|
|
|
1485
|
|
|
|
|
|
|
=head1 CONSTRUCTING BITVECTORS |
1486
|
|
|
|
|
|
|
|
1487
|
|
|
|
|
|
|
=over 4 |
1488
|
|
|
|
|
|
|
|
1489
|
|
|
|
|
|
|
=item B |
1490
|
|
|
|
|
|
|
|
1491
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( size => 0 ); |
1492
|
|
|
|
|
|
|
|
1493
|
|
|
|
|
|
|
print "$bv\n"; # no output |
1494
|
|
|
|
|
|
|
|
1495
|
|
|
|
|
|
|
=item B |
1496
|
|
|
|
|
|
|
|
1497
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( size => 13 ); # 0000000000000 |
1498
|
|
|
|
|
|
|
|
1499
|
|
|
|
|
|
|
=item B |
1500
|
|
|
|
|
|
|
|
1501
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( intVal => 5006 ); # 1001110001110 |
1502
|
|
|
|
|
|
|
|
1503
|
|
|
|
|
|
|
The module returns the smallest possible bitvector that would accommodate the |
1504
|
|
|
|
|
|
|
integer value provided with the C option. |
1505
|
|
|
|
|
|
|
|
1506
|
|
|
|
|
|
|
=item B |
1507
|
|
|
|
|
|
|
|
1508
|
|
|
|
|
|
|
As mentioned, with the C option, you get the smallest possible bitvector |
1509
|
|
|
|
|
|
|
that can be generated from that integer. If you want a I bitvector, you can |
1510
|
|
|
|
|
|
|
also supply the C option as shown below: |
1511
|
|
|
|
|
|
|
|
1512
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( intVal => 5006, size => 16 ); # 0001001110001110 |
1513
|
|
|
|
|
|
|
|
1514
|
|
|
|
|
|
|
If the value supplied for the C option in such a call is not larger than the |
1515
|
|
|
|
|
|
|
smallest bit array that represents the C value, the constructor will throw an |
1516
|
|
|
|
|
|
|
exception. |
1517
|
|
|
|
|
|
|
|
1518
|
|
|
|
|
|
|
=item B |
1519
|
|
|
|
|
|
|
|
1520
|
|
|
|
|
|
|
use Math::BigInt; |
1521
|
|
|
|
|
|
|
$x = Math::BigInt->new('12345678901234567890123456789012345678901234567890'); |
1522
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( intVal => $x ); |
1523
|
|
|
|
|
|
|
#1000011100100111111101100011011010011010101011111000001111001010000\ |
1524
|
|
|
|
|
|
|
#10101000000100110011101000111101011111000110001111111000110010110110\ |
1525
|
|
|
|
|
|
|
#01110001111110000101011010010 |
1526
|
|
|
|
|
|
|
|
1527
|
|
|
|
|
|
|
=item B |
1528
|
|
|
|
|
|
|
|
1529
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitstring => '00110011' ); # 00110011 |
1530
|
|
|
|
|
|
|
|
1531
|
|
|
|
|
|
|
=item B |
1532
|
|
|
|
|
|
|
|
1533
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( textstring => "hello\n" ); |
1534
|
|
|
|
|
|
|
# 011010000110010101101100011011000110111100001010 |
1535
|
|
|
|
|
|
|
|
1536
|
|
|
|
|
|
|
=item B |
1537
|
|
|
|
|
|
|
|
1538
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( hexstring => "68656c6c6f" ); |
1539
|
|
|
|
|
|
|
# 0110100001100101011011000110110001101111 |
1540
|
|
|
|
|
|
|
|
1541
|
|
|
|
|
|
|
=item B |
1542
|
|
|
|
|
|
|
|
1543
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitlist => [1, 1, 0, 1] ); # 1101 |
1544
|
|
|
|
|
|
|
|
1545
|
|
|
|
|
|
|
=item B |
1546
|
|
|
|
|
|
|
|
1547
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( filename => 'testinput1.txt' ); |
1548
|
|
|
|
|
|
|
|
1549
|
|
|
|
|
|
|
print "$bv\n"; # Nothing to show yet |
1550
|
|
|
|
|
|
|
|
1551
|
|
|
|
|
|
|
$bv1 = $bv->read_bits_from_file(64); # Now you have a bitvector from the |
1552
|
|
|
|
|
|
|
# first 64 bits |
1553
|
|
|
|
|
|
|
|
1554
|
|
|
|
|
|
|
Note that it takes two calls to create bitvectors from the contents of a file. The |
1555
|
|
|
|
|
|
|
first merely creates an empty bitvector just to set the necessary file handle for |
1556
|
|
|
|
|
|
|
reading the file. It is the second call in which you invoke the method |
1557
|
|
|
|
|
|
|
C that actually returns a bitvector from the bits read from |
1558
|
|
|
|
|
|
|
the file. Each call to C in this manner spits out a new bit |
1559
|
|
|
|
|
|
|
vector. |
1560
|
|
|
|
|
|
|
|
1561
|
|
|
|
|
|
|
=back |
1562
|
|
|
|
|
|
|
|
1563
|
|
|
|
|
|
|
=head1 METHODS |
1564
|
|
|
|
|
|
|
|
1565
|
|
|
|
|
|
|
=head3 close_file_handle() |
1566
|
|
|
|
|
|
|
|
1567
|
|
|
|
|
|
|
=over 4 |
1568
|
|
|
|
|
|
|
|
1569
|
|
|
|
|
|
|
When you construct bitvectors by block scanning a disk file, after you are done, you |
1570
|
|
|
|
|
|
|
can call this method to close the file handle that was created to read the file: |
1571
|
|
|
|
|
|
|
|
1572
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( filename => 'testinput.txt' ); |
1573
|
|
|
|
|
|
|
## your code to read bit blocks for constructing bitvectors goes here |
1574
|
|
|
|
|
|
|
$bv->close_file_handle(); |
1575
|
|
|
|
|
|
|
|
1576
|
|
|
|
|
|
|
The constructor call in the first statement opens a file handle for reading the bits. |
1577
|
|
|
|
|
|
|
It is this file handle that is closed by calling C, |
1578
|
|
|
|
|
|
|
|
1579
|
|
|
|
|
|
|
=back |
1580
|
|
|
|
|
|
|
|
1581
|
|
|
|
|
|
|
=head3 count_bits() |
1582
|
|
|
|
|
|
|
|
1583
|
|
|
|
|
|
|
=over 4 |
1584
|
|
|
|
|
|
|
|
1585
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( intVal => 45, size => 16 ); |
1586
|
|
|
|
|
|
|
print $bv->count_bits(); # 4 |
1587
|
|
|
|
|
|
|
|
1588
|
|
|
|
|
|
|
This method returns an integer value which is the number of bits set to 1 in the |
1589
|
|
|
|
|
|
|
bitvector on which the method is invoked. |
1590
|
|
|
|
|
|
|
|
1591
|
|
|
|
|
|
|
=back |
1592
|
|
|
|
|
|
|
|
1593
|
|
|
|
|
|
|
=head3 count_bits_sparse() |
1594
|
|
|
|
|
|
|
|
1595
|
|
|
|
|
|
|
=over 4 |
1596
|
|
|
|
|
|
|
|
1597
|
|
|
|
|
|
|
Say you have a bitvector with two million bits: |
1598
|
|
|
|
|
|
|
|
1599
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( size => 2000000 ); |
1600
|
|
|
|
|
|
|
|
1601
|
|
|
|
|
|
|
and you happen to set its individual bits by |
1602
|
|
|
|
|
|
|
|
1603
|
|
|
|
|
|
|
$bv->set_bit(345234, 1); |
1604
|
|
|
|
|
|
|
$bv->set_bit(233, 1); |
1605
|
|
|
|
|
|
|
$bv->set_bit(243, 1); |
1606
|
|
|
|
|
|
|
$bv->set_bit(18, 1); |
1607
|
|
|
|
|
|
|
$bv->set_bit(785, 1); |
1608
|
|
|
|
|
|
|
|
1609
|
|
|
|
|
|
|
The following call returns the number of bits set in the bitvector: |
1610
|
|
|
|
|
|
|
|
1611
|
|
|
|
|
|
|
print $bv->count_bits_sparse(); # 5 |
1612
|
|
|
|
|
|
|
|
1613
|
|
|
|
|
|
|
For very long bitvectors, as in the example here, this method will work much faster |
1614
|
|
|
|
|
|
|
than the C method. However, for dense bitvectors, I expect |
1615
|
|
|
|
|
|
|
C to work faster. |
1616
|
|
|
|
|
|
|
|
1617
|
|
|
|
|
|
|
=back |
1618
|
|
|
|
|
|
|
|
1619
|
|
|
|
|
|
|
=head3 deep_copy() |
1620
|
|
|
|
|
|
|
|
1621
|
|
|
|
|
|
|
=over 4 |
1622
|
|
|
|
|
|
|
|
1623
|
|
|
|
|
|
|
$bv_copy = $bv->deep_copy(); |
1624
|
|
|
|
|
|
|
|
1625
|
|
|
|
|
|
|
Subsequently, any alterations to the bitvectors pointed to by either C<$bv> or |
1626
|
|
|
|
|
|
|
C<$bv_copy> will not affect the other. |
1627
|
|
|
|
|
|
|
|
1628
|
|
|
|
|
|
|
=back |
1629
|
|
|
|
|
|
|
|
1630
|
|
|
|
|
|
|
=head3 divide_into_two() |
1631
|
|
|
|
|
|
|
|
1632
|
|
|
|
|
|
|
=over 4 |
1633
|
|
|
|
|
|
|
|
1634
|
|
|
|
|
|
|
($bv1, $bv2) = $bv->divide_into_two(); # say $bv = 0000000000101101 |
1635
|
|
|
|
|
|
|
print "$bv1\n"; # 00000000 |
1636
|
|
|
|
|
|
|
print "$bv2\n"; # 00101101 |
1637
|
|
|
|
|
|
|
|
1638
|
|
|
|
|
|
|
Divides an even sized bitvector into two bitvectors, each of size half of the |
1639
|
|
|
|
|
|
|
bitvector on which this method is invoked. Throws an exception when invoked on a |
1640
|
|
|
|
|
|
|
bitvector that is not even sized. |
1641
|
|
|
|
|
|
|
|
1642
|
|
|
|
|
|
|
=back |
1643
|
|
|
|
|
|
|
|
1644
|
|
|
|
|
|
|
=head3 gcd() |
1645
|
|
|
|
|
|
|
|
1646
|
|
|
|
|
|
|
=over 4 |
1647
|
|
|
|
|
|
|
|
1648
|
|
|
|
|
|
|
This method uses the Euclid's algorithm to return the Greatest Common Divisor of the |
1649
|
|
|
|
|
|
|
integer values represented by the two bitvectors. The following example shows a call |
1650
|
|
|
|
|
|
|
to C returning the GCD of the integer values of the bitvectors C<$bv1> and |
1651
|
|
|
|
|
|
|
C<$bv2>. |
1652
|
|
|
|
|
|
|
|
1653
|
|
|
|
|
|
|
$bv1 = Algorithm::BitVector->new( bitstring => '01100110' ); # 102 |
1654
|
|
|
|
|
|
|
$bv2 = Algorithm::BitVector->new( bitstring => '011010' ); # 26 |
1655
|
|
|
|
|
|
|
$gcd = $bv1->gcd( $bv2 ); # 10 |
1656
|
|
|
|
|
|
|
print int($gcd); # 2 |
1657
|
|
|
|
|
|
|
|
1658
|
|
|
|
|
|
|
The result returned by C is a bitvector. |
1659
|
|
|
|
|
|
|
|
1660
|
|
|
|
|
|
|
=back |
1661
|
|
|
|
|
|
|
|
1662
|
|
|
|
|
|
|
=head3 gen_random_bits() |
1663
|
|
|
|
|
|
|
|
1664
|
|
|
|
|
|
|
=over 4 |
1665
|
|
|
|
|
|
|
|
1666
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( intVal => 0 ); |
1667
|
|
|
|
|
|
|
$bv = $bv->gen_random_bits(16); # 1100111001010101 |
1668
|
|
|
|
|
|
|
|
1669
|
|
|
|
|
|
|
The call to C returns a bitvector whose bits are randomly |
1670
|
|
|
|
|
|
|
generated. The number of bits in the returned bitvector equals the argument integer. |
1671
|
|
|
|
|
|
|
|
1672
|
|
|
|
|
|
|
=back |
1673
|
|
|
|
|
|
|
|
1674
|
|
|
|
|
|
|
=head3 get_bit() |
1675
|
|
|
|
|
|
|
|
1676
|
|
|
|
|
|
|
=over 4 |
1677
|
|
|
|
|
|
|
|
1678
|
|
|
|
|
|
|
This method gives you array-like access to the individual bits of a bitvector. |
1679
|
|
|
|
|
|
|
|
1680
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitstring => '10111' ); |
1681
|
|
|
|
|
|
|
print $bv->get_bit(0); # 1 (the first bit) |
1682
|
|
|
|
|
|
|
print $bv->get_bit(1); # 0 |
1683
|
|
|
|
|
|
|
print $bv->get_bit(4); # 1 (the last bit) |
1684
|
|
|
|
|
|
|
|
1685
|
|
|
|
|
|
|
Negative values for the index scan a bitvector from right to left, with the C<-1> |
1686
|
|
|
|
|
|
|
index standing for the last (meaning the right-most) bit in the vector: |
1687
|
|
|
|
|
|
|
|
1688
|
|
|
|
|
|
|
print $bv->get_bit(-1); # 1 (the last bit) |
1689
|
|
|
|
|
|
|
print $bv->get_bit(-2); # 1 |
1690
|
|
|
|
|
|
|
print $bv->get_bit(-5); # 1 (the first bit) |
1691
|
|
|
|
|
|
|
|
1692
|
|
|
|
|
|
|
The C can also return a slice of a bitvector if the argument to the |
1693
|
|
|
|
|
|
|
method is an anonymous array of the index range you desire, as in the second |
1694
|
|
|
|
|
|
|
statement below: |
1695
|
|
|
|
|
|
|
|
1696
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitstring => "10111011"); |
1697
|
|
|
|
|
|
|
my $arr = $bv->get_bit( [3..7] ); |
1698
|
|
|
|
|
|
|
print "@$arr\n"; # 1 1 0 1 1 |
1699
|
|
|
|
|
|
|
|
1700
|
|
|
|
|
|
|
In this example, we want C to return all bits at positions indexed 3 |
1701
|
|
|
|
|
|
|
through 7, both ends inclusive. Note that the slice is returned as an array of bits. |
1702
|
|
|
|
|
|
|
|
1703
|
|
|
|
|
|
|
|
1704
|
|
|
|
|
|
|
=back |
1705
|
|
|
|
|
|
|
|
1706
|
|
|
|
|
|
|
=head3 get_bitvector_in_ascii() |
1707
|
|
|
|
|
|
|
|
1708
|
|
|
|
|
|
|
=over 4 |
1709
|
|
|
|
|
|
|
|
1710
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( textstring => "hello" ); |
1711
|
|
|
|
|
|
|
print "$bv\n"; # 0110100001100101011011000110110001101111 |
1712
|
|
|
|
|
|
|
print $bv->get_bitvector_in_ascrii(); # hello |
1713
|
|
|
|
|
|
|
|
1714
|
|
|
|
|
|
|
The method returns a string of ASCII characters by converting successive 8-bit slices |
1715
|
|
|
|
|
|
|
of the bitvector into an ASCII character. It throws an exception if the size of the |
1716
|
|
|
|
|
|
|
bit pattern is not a multiple of 8. Calling this method to create a text-based print |
1717
|
|
|
|
|
|
|
representation of a bit vector makes sense only if you don't expect to see any |
1718
|
|
|
|
|
|
|
unprintable characters in the successive 8-bit slices of the bitvector. Let's say |
1719
|
|
|
|
|
|
|
you have created a bitvector from a text string using the appropriate constructor |
1720
|
|
|
|
|
|
|
call. Subsequently, you encrypted this text string. Next, you or someone else |
1721
|
|
|
|
|
|
|
decrypts the encrypted bit stream. Since what comes out at the decryption end must |
1722
|
|
|
|
|
|
|
be the original text string, it would make sense to invoke this method to recover the |
1723
|
|
|
|
|
|
|
original text. |
1724
|
|
|
|
|
|
|
|
1725
|
|
|
|
|
|
|
=back |
1726
|
|
|
|
|
|
|
|
1727
|
|
|
|
|
|
|
=head3 get_bitvector_in_hex() |
1728
|
|
|
|
|
|
|
|
1729
|
|
|
|
|
|
|
=over 4 |
1730
|
|
|
|
|
|
|
|
1731
|
|
|
|
|
|
|
Assuming that length of your bitvector is a multiple of 4, this methods returns a |
1732
|
|
|
|
|
|
|
hex representation of the bit pattern: |
1733
|
|
|
|
|
|
|
|
1734
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new(bitstring => "0110100001100101011011000110110001101111"); |
1735
|
|
|
|
|
|
|
print $bv->get_bitvector_in_hex(); # 68656c6c6f |
1736
|
|
|
|
|
|
|
|
1737
|
|
|
|
|
|
|
The hex representation is returned in the form if a string of hex characters. This |
1738
|
|
|
|
|
|
|
method throws an exception if the size of the bitvector is not a multiple of 4. |
1739
|
|
|
|
|
|
|
|
1740
|
|
|
|
|
|
|
=back |
1741
|
|
|
|
|
|
|
|
1742
|
|
|
|
|
|
|
=head3 get_slice() |
1743
|
|
|
|
|
|
|
|
1744
|
|
|
|
|
|
|
=over 4 |
1745
|
|
|
|
|
|
|
|
1746
|
|
|
|
|
|
|
You can use this method to get a slice of a BitVector that is within a specified range. |
1747
|
|
|
|
|
|
|
You can specify the index range with the usual range operator in Perl. If the index |
1748
|
|
|
|
|
|
|
range is, say, '5..11', the method will return all bits at index values 5 through 10. |
1749
|
|
|
|
|
|
|
|
1750
|
|
|
|
|
|
|
my $bv9 = Algorithm::BitVector->new( intVal => 63437, size => 16 ); |
1751
|
|
|
|
|
|
|
print "BitVector for testing get_slice(): $bv9\n"; # 1111011111001101 |
1752
|
|
|
|
|
|
|
my $slice_bv = $bv9->get_slice( [5..11] ); |
1753
|
|
|
|
|
|
|
print "slice BitVector for index values 5 through 10: $slice_bv\n"; # 111110 |
1754
|
|
|
|
|
|
|
|
1755
|
|
|
|
|
|
|
Note that the method returns the slice in the form of a BitVector object. |
1756
|
|
|
|
|
|
|
|
1757
|
|
|
|
|
|
|
=back |
1758
|
|
|
|
|
|
|
|
1759
|
|
|
|
|
|
|
=head3 gf_divide_by_modulus() |
1760
|
|
|
|
|
|
|
|
1761
|
|
|
|
|
|
|
=over 4 |
1762
|
|
|
|
|
|
|
|
1763
|
|
|
|
|
|
|
This method is for modular division in the Galois Field C. You must specify |
1764
|
|
|
|
|
|
|
the modulus polynomial through a bit pattern and also the value of the integer C: |
1765
|
|
|
|
|
|
|
|
1766
|
|
|
|
|
|
|
$mod = Algorithm::BitVector->new( bitstring => '100011011' ); # AES modulus |
1767
|
|
|
|
|
|
|
$n = 8; |
1768
|
|
|
|
|
|
|
$a = Algorithm::BitVector->new( bitstring => '11100010110001' ); |
1769
|
|
|
|
|
|
|
($quotient, $remainder) = $a->gf_divide_by_modulus($mod, $n); |
1770
|
|
|
|
|
|
|
print "$quotient\n"; # 00000000111010 |
1771
|
|
|
|
|
|
|
print "$remainder\n"; # 10001111 |
1772
|
|
|
|
|
|
|
|
1773
|
|
|
|
|
|
|
What this example illustrates is dividing the bitvector C<$a> by the modulus bit |
1774
|
|
|
|
|
|
|
vector C<$mod>. For a more general division of one bitvector C<$a> by another bit |
1775
|
|
|
|
|
|
|
vector C<$b>, you would carry out a multiplication of C<$a> by the MI of C<$b>, where |
1776
|
|
|
|
|
|
|
MI stands for "multiplicative inverse" as returned by a call to the method |
1777
|
|
|
|
|
|
|
C. A call to C returns two bitvectors, one for the |
1778
|
|
|
|
|
|
|
quotient and the other for the remainder. |
1779
|
|
|
|
|
|
|
|
1780
|
|
|
|
|
|
|
=back |
1781
|
|
|
|
|
|
|
|
1782
|
|
|
|
|
|
|
=head3 gf_MI() |
1783
|
|
|
|
|
|
|
|
1784
|
|
|
|
|
|
|
=over 4 |
1785
|
|
|
|
|
|
|
|
1786
|
|
|
|
|
|
|
This method returns the multiplicative inverse of a bit pattern in the Galois Field |
1787
|
|
|
|
|
|
|
C. You must specify both the modulus polynomial through its bit pattern and |
1788
|
|
|
|
|
|
|
the value of C: |
1789
|
|
|
|
|
|
|
|
1790
|
|
|
|
|
|
|
$modulus = Algorithm::BitVector->new( bitstring => '100011011' ); # AES modulus |
1791
|
|
|
|
|
|
|
$n = 8; |
1792
|
|
|
|
|
|
|
$a = Algorithm::BitVector->new( bitstring => '00110011' ); |
1793
|
|
|
|
|
|
|
print $a->gf_MI($modulus, $n); # 01101100 |
1794
|
|
|
|
|
|
|
|
1795
|
|
|
|
|
|
|
Note that the multiplicative inverse is returned as a bitvector. |
1796
|
|
|
|
|
|
|
|
1797
|
|
|
|
|
|
|
=back |
1798
|
|
|
|
|
|
|
|
1799
|
|
|
|
|
|
|
=head3 gf_multiply() |
1800
|
|
|
|
|
|
|
|
1801
|
|
|
|
|
|
|
=over 4 |
1802
|
|
|
|
|
|
|
|
1803
|
|
|
|
|
|
|
This method returns a product of two bit patterns in the Galois Field C field. |
1804
|
|
|
|
|
|
|
That is, given any two polynomials with their coefficients drawn from the 0 and 1 |
1805
|
|
|
|
|
|
|
values in C, this method returns the product polynomial. |
1806
|
|
|
|
|
|
|
|
1807
|
|
|
|
|
|
|
$a = Algorithm::BitVector->new( bitstring => '0110001' ); |
1808
|
|
|
|
|
|
|
$b = Algorithm::BitVector->new( bitstring => '0110' ); |
1809
|
|
|
|
|
|
|
print $a->gf_multiply($b); #00010100110 |
1810
|
|
|
|
|
|
|
|
1811
|
|
|
|
|
|
|
As you would expect, in general, the bit pattern returned by this method will be |
1812
|
|
|
|
|
|
|
longer than the lengths of the two operand bitvectors. The result returned by the |
1813
|
|
|
|
|
|
|
method is in the form of a bitvector. |
1814
|
|
|
|
|
|
|
|
1815
|
|
|
|
|
|
|
=back |
1816
|
|
|
|
|
|
|
|
1817
|
|
|
|
|
|
|
=head3 gf_multiply_modular() |
1818
|
|
|
|
|
|
|
|
1819
|
|
|
|
|
|
|
=over 4 |
1820
|
|
|
|
|
|
|
|
1821
|
|
|
|
|
|
|
This method carries out modular multiplication in the Galois Field C. You |
1822
|
|
|
|
|
|
|
must supply it the bitvector for the modulus polynomial and the value of C. |
1823
|
|
|
|
|
|
|
|
1824
|
|
|
|
|
|
|
$modulus = Algorithm::BitVector->new( bitstring => '100011011' ); # AES modulus |
1825
|
|
|
|
|
|
|
$n = 8; |
1826
|
|
|
|
|
|
|
$a = Algorithm::BitVector->new( bitstring => '0110001' ); |
1827
|
|
|
|
|
|
|
$b = Algorithm::BitVector->new( bitstring => '0110' ); |
1828
|
|
|
|
|
|
|
print $a->gf_multiply_modular($b, $modulus, $n); # 10100110 |
1829
|
|
|
|
|
|
|
|
1830
|
|
|
|
|
|
|
This example returns the product of the bit patterns C<$a> and C<$b> modulo the bit |
1831
|
|
|
|
|
|
|
pattern C<$modulus> in C. The result returned by the method is in the form |
1832
|
|
|
|
|
|
|
of a bitvector. |
1833
|
|
|
|
|
|
|
|
1834
|
|
|
|
|
|
|
=back |
1835
|
|
|
|
|
|
|
|
1836
|
|
|
|
|
|
|
=head3 hamming_distance() |
1837
|
|
|
|
|
|
|
|
1838
|
|
|
|
|
|
|
=over 4 |
1839
|
|
|
|
|
|
|
|
1840
|
|
|
|
|
|
|
Hamming distance is commonly used to measure dissimilarity between two bitvectors of |
1841
|
|
|
|
|
|
|
the same size. |
1842
|
|
|
|
|
|
|
|
1843
|
|
|
|
|
|
|
$bv1 = Algorithm::BitVector->new( bitstring => '11111111' ); |
1844
|
|
|
|
|
|
|
$bv2 = Algorithm::BitVector->new( bitstring => '00101011' ); |
1845
|
|
|
|
|
|
|
print $bv1->hamming_distance( $bv2 ); # 4 |
1846
|
|
|
|
|
|
|
|
1847
|
|
|
|
|
|
|
This distance returns the number of bit positions in which two the bit patterns |
1848
|
|
|
|
|
|
|
differ. The method throws an exception if the two bitvectors are not of the same |
1849
|
|
|
|
|
|
|
length. The value returned is an integer. |
1850
|
|
|
|
|
|
|
|
1851
|
|
|
|
|
|
|
=back |
1852
|
|
|
|
|
|
|
|
1853
|
|
|
|
|
|
|
=head3 int_value() |
1854
|
|
|
|
|
|
|
|
1855
|
|
|
|
|
|
|
=over 4 |
1856
|
|
|
|
|
|
|
|
1857
|
|
|
|
|
|
|
You can find the integer value of a bitvector by |
1858
|
|
|
|
|
|
|
|
1859
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( intVal => 5678 ); |
1860
|
|
|
|
|
|
|
print $bv3->int_value(); # 5678 |
1861
|
|
|
|
|
|
|
|
1862
|
|
|
|
|
|
|
or, even more simply by |
1863
|
|
|
|
|
|
|
|
1864
|
|
|
|
|
|
|
print int($bv); # 5678 |
1865
|
|
|
|
|
|
|
|
1866
|
|
|
|
|
|
|
which works on account of the overloading of the C<0+> operator. |
1867
|
|
|
|
|
|
|
|
1868
|
|
|
|
|
|
|
=back |
1869
|
|
|
|
|
|
|
|
1870
|
|
|
|
|
|
|
=head3 is_power_of_2() |
1871
|
|
|
|
|
|
|
|
1872
|
|
|
|
|
|
|
=over 4 |
1873
|
|
|
|
|
|
|
|
1874
|
|
|
|
|
|
|
You can use this predicate to test if the integer value of a bitvector is a power of |
1875
|
|
|
|
|
|
|
2: |
1876
|
|
|
|
|
|
|
|
1877
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitstring => '10000000001110' ); |
1878
|
|
|
|
|
|
|
print int($bv); # 826 |
1879
|
|
|
|
|
|
|
print $bv->is_power_of_2(); # 0 |
1880
|
|
|
|
|
|
|
|
1881
|
|
|
|
|
|
|
The predicate returns 1 for true and 0 for false. |
1882
|
|
|
|
|
|
|
|
1883
|
|
|
|
|
|
|
=back |
1884
|
|
|
|
|
|
|
|
1885
|
|
|
|
|
|
|
=head3 is_power_of_2_sparse() |
1886
|
|
|
|
|
|
|
|
1887
|
|
|
|
|
|
|
=over 4 |
1888
|
|
|
|
|
|
|
|
1889
|
|
|
|
|
|
|
This does the same thing as the C method but in a way that makes it |
1890
|
|
|
|
|
|
|
faster for large bitvectors with very few bits set. |
1891
|
|
|
|
|
|
|
|
1892
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( size => 2000000 ); |
1893
|
|
|
|
|
|
|
$bv->set_bit(345234, 1); |
1894
|
|
|
|
|
|
|
print $bv->is_power_of_2_sparse(); # 1 |
1895
|
|
|
|
|
|
|
|
1896
|
|
|
|
|
|
|
=back |
1897
|
|
|
|
|
|
|
|
1898
|
|
|
|
|
|
|
=head3 jaccard_distance() |
1899
|
|
|
|
|
|
|
|
1900
|
|
|
|
|
|
|
=over 4 |
1901
|
|
|
|
|
|
|
|
1902
|
|
|
|
|
|
|
The Jaccard distance between two bitvectors is 1 minus the Jaccard similarity |
1903
|
|
|
|
|
|
|
coefficient: |
1904
|
|
|
|
|
|
|
|
1905
|
|
|
|
|
|
|
$bv1 = Algorithm::BitVector->new( bitstring => '11111111' ); |
1906
|
|
|
|
|
|
|
$bv2 = Algorithm::BitVector->new( bitstring => '10101011' ); |
1907
|
|
|
|
|
|
|
print $bv1->jaccard_distance( $bv2 ); # 0.375 |
1908
|
|
|
|
|
|
|
|
1909
|
|
|
|
|
|
|
The value returned by the method is a floating point number between 0 and 1. |
1910
|
|
|
|
|
|
|
|
1911
|
|
|
|
|
|
|
=back |
1912
|
|
|
|
|
|
|
|
1913
|
|
|
|
|
|
|
=head3 jaccard_similarity() |
1914
|
|
|
|
|
|
|
|
1915
|
|
|
|
|
|
|
=over 4 |
1916
|
|
|
|
|
|
|
|
1917
|
|
|
|
|
|
|
This method returns the Jaccard similarity coefficient between the two bitvectors |
1918
|
|
|
|
|
|
|
pointed to by C<$bv1> and C<$bv2>: |
1919
|
|
|
|
|
|
|
|
1920
|
|
|
|
|
|
|
$bv1 = Algorithm::BitVector->new( bitstring => '11111111' ); |
1921
|
|
|
|
|
|
|
$bv2 = Algorithm::BitVector->new( bitstring => '10101011' ); |
1922
|
|
|
|
|
|
|
print $bv1->jaccard_similarity( $bv2 ); # 0.675 |
1923
|
|
|
|
|
|
|
|
1924
|
|
|
|
|
|
|
The value returned by the method is a floating point number between 0 and 1. |
1925
|
|
|
|
|
|
|
|
1926
|
|
|
|
|
|
|
=back |
1927
|
|
|
|
|
|
|
|
1928
|
|
|
|
|
|
|
=head3 length() |
1929
|
|
|
|
|
|
|
|
1930
|
|
|
|
|
|
|
=over 4 |
1931
|
|
|
|
|
|
|
|
1932
|
|
|
|
|
|
|
This method returns the total number of bits in a bitvector: |
1933
|
|
|
|
|
|
|
|
1934
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( intVal => 5678 ); |
1935
|
|
|
|
|
|
|
print $bv; # 1011000101110 |
1936
|
|
|
|
|
|
|
print $bv->length(); # 13 |
1937
|
|
|
|
|
|
|
|
1938
|
|
|
|
|
|
|
Note that what C returns is the total size of a bitvector, including any |
1939
|
|
|
|
|
|
|
leading zeros. |
1940
|
|
|
|
|
|
|
|
1941
|
|
|
|
|
|
|
=back |
1942
|
|
|
|
|
|
|
|
1943
|
|
|
|
|
|
|
=head3 min_canonical() |
1944
|
|
|
|
|
|
|
|
1945
|
|
|
|
|
|
|
=over 4 |
1946
|
|
|
|
|
|
|
|
1947
|
|
|
|
|
|
|
This method returns the min-int-value circularly rotated version of a BitVector. I refer |
1948
|
|
|
|
|
|
|
to this form of a BitVector as its "min canonical form". |
1949
|
|
|
|
|
|
|
|
1950
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitstring => "00011100010010" ); |
1951
|
|
|
|
|
|
|
print $bv->min_canonical(); # 00001110001001 |
1952
|
|
|
|
|
|
|
|
1953
|
|
|
|
|
|
|
=back |
1954
|
|
|
|
|
|
|
|
1955
|
|
|
|
|
|
|
=head3 multiplicative_inverse() |
1956
|
|
|
|
|
|
|
|
1957
|
|
|
|
|
|
|
=over 4 |
1958
|
|
|
|
|
|
|
|
1959
|
|
|
|
|
|
|
This method calculates the multiplicative inverse using normal integer arithmetic. |
1960
|
|
|
|
|
|
|
For multiplicative inverses in a Galois Field C, use the method C |
1961
|
|
|
|
|
|
|
described earlier in this API. |
1962
|
|
|
|
|
|
|
|
1963
|
|
|
|
|
|
|
$modulus = Algorithm::BitVector->new( intVal => 32 ); |
1964
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( intVal => 17 ); |
1965
|
|
|
|
|
|
|
$result = $bv->multiplicative_inverse( $modulus ); |
1966
|
|
|
|
|
|
|
if ($result) { |
1967
|
|
|
|
|
|
|
print $result; # 10001 |
1968
|
|
|
|
|
|
|
} else { |
1969
|
|
|
|
|
|
|
print "No multiplicative inverse in this case\n"; |
1970
|
|
|
|
|
|
|
} |
1971
|
|
|
|
|
|
|
|
1972
|
|
|
|
|
|
|
What this example says is that the multiplicative inverse of 17 modulo 32 is 17. That |
1973
|
|
|
|
|
|
|
is because 17 times 17 in modulo 32 arithmetic equals 1. When using this method, you |
1974
|
|
|
|
|
|
|
must test the value returned for 0. If the returned value is 0, that means that the |
1975
|
|
|
|
|
|
|
number corresponding to the bitvector on which this method is invoked does not |
1976
|
|
|
|
|
|
|
possess a multiplicative inverse with respect to the modulus. |
1977
|
|
|
|
|
|
|
|
1978
|
|
|
|
|
|
|
=back |
1979
|
|
|
|
|
|
|
|
1980
|
|
|
|
|
|
|
=head3 next_set_bit() |
1981
|
|
|
|
|
|
|
|
1982
|
|
|
|
|
|
|
=over 4 |
1983
|
|
|
|
|
|
|
|
1984
|
|
|
|
|
|
|
Starting from a given bit position, this method returns the index of the next bit |
1985
|
|
|
|
|
|
|
that is set in a bitvector: |
1986
|
|
|
|
|
|
|
|
1987
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitstring => '00000000000001' ); |
1988
|
|
|
|
|
|
|
print $bv->next_set_bit(5); # 13 |
1989
|
|
|
|
|
|
|
|
1990
|
|
|
|
|
|
|
In this example, we are asking the method to return the index of the bit that is set |
1991
|
|
|
|
|
|
|
after the bit position indexed 5. The method returns -1 if there is no next set bit. |
1992
|
|
|
|
|
|
|
|
1993
|
|
|
|
|
|
|
=back |
1994
|
|
|
|
|
|
|
|
1995
|
|
|
|
|
|
|
=head3 pad_from_left() |
1996
|
|
|
|
|
|
|
|
1997
|
|
|
|
|
|
|
=over 4 |
1998
|
|
|
|
|
|
|
|
1999
|
|
|
|
|
|
|
You can pad a bitvector from the left with a designated number of zeros: |
2000
|
|
|
|
|
|
|
|
2001
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitstring => '101010' ); |
2002
|
|
|
|
|
|
|
print $bv->pad_from_left( 4 ); # 0000101010 |
2003
|
|
|
|
|
|
|
|
2004
|
|
|
|
|
|
|
The method returns the bitvector on which it is invoked. So you can think of it as |
2005
|
|
|
|
|
|
|
an in-place extension of a bitvector (although, under the hood, the extension is |
2006
|
|
|
|
|
|
|
carried out by giving a new longer C<_vector> attribute to the bitvector object). |
2007
|
|
|
|
|
|
|
|
2008
|
|
|
|
|
|
|
=back |
2009
|
|
|
|
|
|
|
|
2010
|
|
|
|
|
|
|
=head3 pad_from_right() |
2011
|
|
|
|
|
|
|
|
2012
|
|
|
|
|
|
|
=over 4 |
2013
|
|
|
|
|
|
|
|
2014
|
|
|
|
|
|
|
You can pad a bitvector from the right with a designated number of zeros: |
2015
|
|
|
|
|
|
|
|
2016
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitstring => '101010' ); |
2017
|
|
|
|
|
|
|
print $bv->pad_from_right( 4 ); # 1010100000 |
2018
|
|
|
|
|
|
|
|
2019
|
|
|
|
|
|
|
The method returns the bitvector on which it is invoked. So you can think of it as |
2020
|
|
|
|
|
|
|
an in-place extension of a bitvector (although, under the hood, the extension is |
2021
|
|
|
|
|
|
|
carried out by giving a new longer C<_vector> attribute to the bitvector object). |
2022
|
|
|
|
|
|
|
|
2023
|
|
|
|
|
|
|
|
2024
|
|
|
|
|
|
|
=back |
2025
|
|
|
|
|
|
|
|
2026
|
|
|
|
|
|
|
=head3 permute() |
2027
|
|
|
|
|
|
|
|
2028
|
|
|
|
|
|
|
=over 4 |
2029
|
|
|
|
|
|
|
|
2030
|
|
|
|
|
|
|
You can permute the bits in a bitvector with a permutation list as shown below: |
2031
|
|
|
|
|
|
|
|
2032
|
|
|
|
|
|
|
$bv1 = Algorithm::BitVector->new( intVal => 203, size => 8 ); |
2033
|
|
|
|
|
|
|
print $bv1; # 11001011 |
2034
|
|
|
|
|
|
|
$bv2 = $bv1->permute( [3, 2, 1, 0, 7, 6, 5, 4] ); |
2035
|
|
|
|
|
|
|
print $bv2; # 00111101 |
2036
|
|
|
|
|
|
|
|
2037
|
|
|
|
|
|
|
The method returns a new bitvector with permuted bits. |
2038
|
|
|
|
|
|
|
|
2039
|
|
|
|
|
|
|
=back |
2040
|
|
|
|
|
|
|
|
2041
|
|
|
|
|
|
|
=head3 rank_of_bit_set_at_index() |
2042
|
|
|
|
|
|
|
|
2043
|
|
|
|
|
|
|
=over 4 |
2044
|
|
|
|
|
|
|
|
2045
|
|
|
|
|
|
|
You can measure the "rank" of a bit that is set at a given index. Rank is the number |
2046
|
|
|
|
|
|
|
of bits that are set up to the argument position, as in |
2047
|
|
|
|
|
|
|
|
2048
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitstring => '01010101011100' ); |
2049
|
|
|
|
|
|
|
print $bv->rank_of_bit_set_at_index( 10 ); # 6 |
2050
|
|
|
|
|
|
|
|
2051
|
|
|
|
|
|
|
The value 6 returned by this call to C is the number of |
2052
|
|
|
|
|
|
|
bits set up to the position indexed 10 (including that position). The method throws |
2053
|
|
|
|
|
|
|
an exception if there is no bit set at the argument position. |
2054
|
|
|
|
|
|
|
|
2055
|
|
|
|
|
|
|
=back |
2056
|
|
|
|
|
|
|
|
2057
|
|
|
|
|
|
|
=head3 read_bits_from_file() |
2058
|
|
|
|
|
|
|
|
2059
|
|
|
|
|
|
|
=over 4 |
2060
|
|
|
|
|
|
|
|
2061
|
|
|
|
|
|
|
Constructing bitvectors from the contents of a disk file takes two steps: First you |
2062
|
|
|
|
|
|
|
must make the call shown in the first statement below. The purpose of this call is to |
2063
|
|
|
|
|
|
|
create a file handle that is associated with the variable C<$bv> in this case. |
2064
|
|
|
|
|
|
|
Subsequent invocations of C on this variable will read |
2065
|
|
|
|
|
|
|
blocks of C<$n> bits and return a bitvector for each block thus read. The variable |
2066
|
|
|
|
|
|
|
C<$n> must be a multiple of 8 for this to work. |
2067
|
|
|
|
|
|
|
|
2068
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( filename => 'testinput.txt' ); |
2069
|
|
|
|
|
|
|
$bv1 = $bv->read_bits_from_file(64); |
2070
|
|
|
|
|
|
|
$bv2 = $bv->read_bits_from_file(64); |
2071
|
|
|
|
|
|
|
... |
2072
|
|
|
|
|
|
|
... |
2073
|
|
|
|
|
|
|
$bv->close_file_handle(); |
2074
|
|
|
|
|
|
|
|
2075
|
|
|
|
|
|
|
When reading a file as shown above, you can test the attribute C of the |
2076
|
|
|
|
|
|
|
bitvector object in order to find out if there is more to be read in the file. The |
2077
|
|
|
|
|
|
|
C loop shown below reads all of a file in 64-bit blocks. |
2078
|
|
|
|
|
|
|
|
2079
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( filename => 'testinput.txt' ); |
2080
|
|
|
|
|
|
|
while ($bv->{more_to_read}) { |
2081
|
|
|
|
|
|
|
my $bv_read = $bv->read_bits_from_file( 64 ); |
2082
|
|
|
|
|
|
|
print "$bv_read\n"; |
2083
|
|
|
|
|
|
|
} |
2084
|
|
|
|
|
|
|
$bv->close_file_handle(); |
2085
|
|
|
|
|
|
|
|
2086
|
|
|
|
|
|
|
The size of the last bitvector constructed from a file corresponds to how many bytes |
2087
|
|
|
|
|
|
|
remain unread in the file at that point. It is your responsibility to zero-pad the |
2088
|
|
|
|
|
|
|
last bitvector appropriately if, say, you are doing block encryption of the whole |
2089
|
|
|
|
|
|
|
file. |
2090
|
|
|
|
|
|
|
|
2091
|
|
|
|
|
|
|
=back |
2092
|
|
|
|
|
|
|
|
2093
|
|
|
|
|
|
|
=head3 reset() |
2094
|
|
|
|
|
|
|
|
2095
|
|
|
|
|
|
|
=over 4 |
2096
|
|
|
|
|
|
|
|
2097
|
|
|
|
|
|
|
You can reset a previously constructed bitvector all either all 1's or all 0's by |
2098
|
|
|
|
|
|
|
calling this method: |
2099
|
|
|
|
|
|
|
|
2100
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( intVal => 203, size => 8 ); |
2101
|
|
|
|
|
|
|
print $bv; # 11001011 |
2102
|
|
|
|
|
|
|
$bv->reset(1); |
2103
|
|
|
|
|
|
|
print $bv; # 11111111 |
2104
|
|
|
|
|
|
|
$bv->reset(0); |
2105
|
|
|
|
|
|
|
print $bv; # 00000000 |
2106
|
|
|
|
|
|
|
|
2107
|
|
|
|
|
|
|
What the method accomplishes can be thought of as in-place resetting of the bits. The |
2108
|
|
|
|
|
|
|
method does not return anything. |
2109
|
|
|
|
|
|
|
|
2110
|
|
|
|
|
|
|
=back |
2111
|
|
|
|
|
|
|
|
2112
|
|
|
|
|
|
|
=head3 reverse() |
2113
|
|
|
|
|
|
|
|
2114
|
|
|
|
|
|
|
=over 4 |
2115
|
|
|
|
|
|
|
|
2116
|
|
|
|
|
|
|
Given a bitvector, you can construct a bitvector with all the bits reversed, in the |
2117
|
|
|
|
|
|
|
sense that what was left-to-right earlier now becomes right-to-left, as in |
2118
|
|
|
|
|
|
|
|
2119
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitstring => '01100001' ); |
2120
|
|
|
|
|
|
|
print $bv->reverse(); # 10000110 |
2121
|
|
|
|
|
|
|
|
2122
|
|
|
|
|
|
|
A call to this method returns a new bitvector whose bits are in reverse order in |
2123
|
|
|
|
|
|
|
relation to the bits in the bitvector on which the method is called. |
2124
|
|
|
|
|
|
|
|
2125
|
|
|
|
|
|
|
=back |
2126
|
|
|
|
|
|
|
|
2127
|
|
|
|
|
|
|
=head3 runs() |
2128
|
|
|
|
|
|
|
|
2129
|
|
|
|
|
|
|
=over 4 |
2130
|
|
|
|
|
|
|
|
2131
|
|
|
|
|
|
|
This method returns an array of runs of 1's and 0's in a bitvector: |
2132
|
|
|
|
|
|
|
|
2133
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitlist => [1,1,1,0,0,1] ); |
2134
|
|
|
|
|
|
|
my @bvruns = $bv->runs(); |
2135
|
|
|
|
|
|
|
print "@bvruns\n"; # 111 00 1 |
2136
|
|
|
|
|
|
|
|
2137
|
|
|
|
|
|
|
Each element of the array that is returned by C is a string of either 1's or |
2138
|
|
|
|
|
|
|
0's. |
2139
|
|
|
|
|
|
|
|
2140
|
|
|
|
|
|
|
=back |
2141
|
|
|
|
|
|
|
|
2142
|
|
|
|
|
|
|
=head3 set_bit() |
2143
|
|
|
|
|
|
|
|
2144
|
|
|
|
|
|
|
=over 4 |
2145
|
|
|
|
|
|
|
|
2146
|
|
|
|
|
|
|
With array-like indexing, you can use this method to set the individual bits of a |
2147
|
|
|
|
|
|
|
previously constructed bitvector. Both positive and negative values are allowed for |
2148
|
|
|
|
|
|
|
the bit position index. The method takes two explicit arguments, the first for the |
2149
|
|
|
|
|
|
|
position of the bit you want to set and the second for the value of the bit. |
2150
|
|
|
|
|
|
|
|
2151
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitstring => '1111' ); |
2152
|
|
|
|
|
|
|
$bv->set_bit(0,0); # set the first bit to 0 |
2153
|
|
|
|
|
|
|
$bv->set_bit(1,0); # set the next bit to 0 |
2154
|
|
|
|
|
|
|
print $bv; # 0011 |
2155
|
|
|
|
|
|
|
$bv->set_bit(-1,0); # set the last bit to 0 |
2156
|
|
|
|
|
|
|
$bv->set_bit(-2,0); # set the bit before the last bit to 0 |
2157
|
|
|
|
|
|
|
print $bv; # 0000 |
2158
|
|
|
|
|
|
|
|
2159
|
|
|
|
|
|
|
=back |
2160
|
|
|
|
|
|
|
|
2161
|
|
|
|
|
|
|
=head3 set_slice() |
2162
|
|
|
|
|
|
|
|
2163
|
|
|
|
|
|
|
=over 4 |
2164
|
|
|
|
|
|
|
|
2165
|
|
|
|
|
|
|
You can set a slice in a given BitVector by calling this method. It takes two |
2166
|
|
|
|
|
|
|
arguments, with the first argument as the range of the position index values at which |
2167
|
|
|
|
|
|
|
you want to set the bits and the second argument the bit values at those positions. |
2168
|
|
|
|
|
|
|
|
2169
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( intVal => 63437, size => 16 ); |
2170
|
|
|
|
|
|
|
$values_bv = Algorithm::BitVector->new( bitlist => [1,1,1,1] ); |
2171
|
|
|
|
|
|
|
$bv->set_slice( [4..8], $values_bv ); |
2172
|
|
|
|
|
|
|
print "BitVector after set_slice(): $bv\n"; # 1111111111001101 |
2173
|
|
|
|
|
|
|
|
2174
|
|
|
|
|
|
|
When specifying the index values with the range operator in the form C, you |
2175
|
|
|
|
|
|
|
would be setting the bits at the positions C through C. |
2176
|
|
|
|
|
|
|
|
2177
|
|
|
|
|
|
|
=back |
2178
|
|
|
|
|
|
|
|
2179
|
|
|
|
|
|
|
=head3 set_value() |
2180
|
|
|
|
|
|
|
|
2181
|
|
|
|
|
|
|
=over 4 |
2182
|
|
|
|
|
|
|
|
2183
|
|
|
|
|
|
|
This method can be used to change the bit pattern associated with a previously |
2184
|
|
|
|
|
|
|
constructed bitvector: |
2185
|
|
|
|
|
|
|
|
2186
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( intVal => 7, size => 16 ); |
2187
|
|
|
|
|
|
|
print $bv; # 0000000000000111 |
2188
|
|
|
|
|
|
|
$bv->set_value( intVal => 45 ); |
2189
|
|
|
|
|
|
|
print $bv; # 101101 |
2190
|
|
|
|
|
|
|
|
2191
|
|
|
|
|
|
|
You can think of this method as carrying out an in-place resetting of the bit array |
2192
|
|
|
|
|
|
|
in a bitvector. The method does not return anything. |
2193
|
|
|
|
|
|
|
|
2194
|
|
|
|
|
|
|
=back |
2195
|
|
|
|
|
|
|
|
2196
|
|
|
|
|
|
|
=head3 shift_left() |
2197
|
|
|
|
|
|
|
|
2198
|
|
|
|
|
|
|
=over 4 |
2199
|
|
|
|
|
|
|
|
2200
|
|
|
|
|
|
|
If you want to shift a bitvector non-circularly to the left, this is the method to |
2201
|
|
|
|
|
|
|
call: |
2202
|
|
|
|
|
|
|
|
2203
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitlist => [1,1, 1, 0, 0, 1] ); |
2204
|
|
|
|
|
|
|
$bv->shift_left(3); |
2205
|
|
|
|
|
|
|
print $bv; # 001000 |
2206
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitlist => [1,1, 1, 0, 0, 1] ); |
2207
|
|
|
|
|
|
|
$bv->shift_left(3)->shift_right(3); |
2208
|
|
|
|
|
|
|
print $bv; # 000001 |
2209
|
|
|
|
|
|
|
|
2210
|
|
|
|
|
|
|
As the bitvector is shifted non-circularly to the left, the exposed bit positions on |
2211
|
|
|
|
|
|
|
the right are filled with zeros. Note that the method returns the bitvector object |
2212
|
|
|
|
|
|
|
on which it is invoked. That is the reason why the chained invocation of the method |
2213
|
|
|
|
|
|
|
in the fifth statement above works. |
2214
|
|
|
|
|
|
|
|
2215
|
|
|
|
|
|
|
=back |
2216
|
|
|
|
|
|
|
|
2217
|
|
|
|
|
|
|
=head3 shift_right() |
2218
|
|
|
|
|
|
|
|
2219
|
|
|
|
|
|
|
=over 4 |
2220
|
|
|
|
|
|
|
|
2221
|
|
|
|
|
|
|
If you want to shift a bitvector non-circularly to the right, this is the method to |
2222
|
|
|
|
|
|
|
call: |
2223
|
|
|
|
|
|
|
|
2224
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitlist => [1,1, 1, 0, 0, 1] ); |
2225
|
|
|
|
|
|
|
$bv->shift_right(3); |
2226
|
|
|
|
|
|
|
print $bv; # 000111 |
2227
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( bitlist => [1,1, 1, 0, 0, 1] ); |
2228
|
|
|
|
|
|
|
$bv->shift_right(3)->shift_right(2); |
2229
|
|
|
|
|
|
|
print $bv; # 000001 |
2230
|
|
|
|
|
|
|
|
2231
|
|
|
|
|
|
|
As the bitvector is shifted non-circularly to the right, the exposed bit positions on |
2232
|
|
|
|
|
|
|
the left are filled with zeros. Note that the method returns the bitvector object |
2233
|
|
|
|
|
|
|
on which it is invoked. That is the reason why the chained invocation of the method |
2234
|
|
|
|
|
|
|
in the fifth statement above works. |
2235
|
|
|
|
|
|
|
|
2236
|
|
|
|
|
|
|
=back |
2237
|
|
|
|
|
|
|
|
2238
|
|
|
|
|
|
|
=head3 test_for_primality() |
2239
|
|
|
|
|
|
|
|
2240
|
|
|
|
|
|
|
=over 4 |
2241
|
|
|
|
|
|
|
|
2242
|
|
|
|
|
|
|
If the integer value of a bitvector is small (meaning smaller than C<< 0x7f_ff_ff_ff >>), |
2243
|
|
|
|
|
|
|
you can use this method to test it for its primality through the Miller-Rabin |
2244
|
|
|
|
|
|
|
probabilistic test: |
2245
|
|
|
|
|
|
|
|
2246
|
|
|
|
|
|
|
$p = 7417; |
2247
|
|
|
|
|
|
|
$bv = Algorithm::BitVector->new( intVal => $p ); |
2248
|
|
|
|
|
|
|
$check = $bv->test_for_primality(); |
2249
|
|
|
|
|
|
|
print "The primality test for $p: $check\n"; |
2250
|
|
|
|
|
|
|
# The primality test for 7417: is a prime with probability 0.99993896484375 |
2251
|
|
|
|
|
|
|
|
2252
|
|
|
|
|
|
|
The method returns one of two strings: If the primality test succeeds, the method |
2253
|
|
|
|
|
|
|
returns a string like "C". And if the test fails, |
2254
|
|
|
|
|
|
|
the method returns the string "C". |
2255
|
|
|
|
|
|
|
|
2256
|
|
|
|
|
|
|
=back |
2257
|
|
|
|
|
|
|
|
2258
|
|
|
|
|
|
|
=head3 unpermute() |
2259
|
|
|
|
|
|
|
|
2260
|
|
|
|
|
|
|
=over 4 |
2261
|
|
|
|
|
|
|
|
2262
|
|
|
|
|
|
|
This method reverses the permutation carried out by a call to the C method |
2263
|
|
|
|
|
|
|
as shown below: |
2264
|
|
|
|
|
|
|
|
2265
|
|
|
|
|
|
|
$bv1 = Algorithm::BitVector->new( intVal => 203, size => 8 ); |
2266
|
|
|
|
|
|
|
print $bv1; # 11001011 |
2267
|
|
|
|
|
|
|
$bv2 = $bv1->permute( [3, 2, 1, 0, 7, 6, 5, 4] ); |
2268
|
|
|
|
|
|
|
print $bv2; # 00111101 |
2269
|
|
|
|
|
|
|
$bv3 = $bv2->unpermute( [3, 2, 1, 0, 7, 6, 5, 4] ); |
2270
|
|
|
|
|
|
|
print $bv3; # 11001011 |
2271
|
|
|
|
|
|
|
|
2272
|
|
|
|
|
|
|
The method returns a new bitvector with unpermuted bits. Also note that the method |
2273
|
|
|
|
|
|
|
throws an exception if the permutation list is not as long as the size of the |
2274
|
|
|
|
|
|
|
bitvector on which the method is invoked. |
2275
|
|
|
|
|
|
|
|
2276
|
|
|
|
|
|
|
=back |
2277
|
|
|
|
|
|
|
|
2278
|
|
|
|
|
|
|
=head3 write_to_file() |
2279
|
|
|
|
|
|
|
|
2280
|
|
|
|
|
|
|
=over 4 |
2281
|
|
|
|
|
|
|
|
2282
|
|
|
|
|
|
|
This method writes the bitvectors in your program to a disk file: |
2283
|
|
|
|
|
|
|
|
2284
|
|
|
|
|
|
|
$bv1 = Algorithm::BitVector->new( bitstring => '00001010' ); |
2285
|
|
|
|
|
|
|
open my $FILEOUT, ">test.txt"; |
2286
|
|
|
|
|
|
|
$bv1->write_to_file( $FILEOUT ); |
2287
|
|
|
|
|
|
|
close $FILEOUT; |
2288
|
|
|
|
|
|
|
|
2289
|
|
|
|
|
|
|
The size of a bitvector must be a multiple of 8 for this write method to work. If |
2290
|
|
|
|
|
|
|
this condition is not met, the method will throw an exception. |
2291
|
|
|
|
|
|
|
|
2292
|
|
|
|
|
|
|
B When writing an internally generated bitvector out |
2293
|
|
|
|
|
|
|
to a disk file, it may be important to open the file in the binary mode, since |
2294
|
|
|
|
|
|
|
otherwise the bit pattern `00001010' ('\n') in your bitstring will be written out as |
2295
|
|
|
|
|
|
|
0000110100001010 ('\r\n') which is the line break on Windows machines. |
2296
|
|
|
|
|
|
|
|
2297
|
|
|
|
|
|
|
=back |
2298
|
|
|
|
|
|
|
|
2299
|
|
|
|
|
|
|
=head1 REQUIRED |
2300
|
|
|
|
|
|
|
|
2301
|
|
|
|
|
|
|
This module imports the following modules: |
2302
|
|
|
|
|
|
|
|
2303
|
|
|
|
|
|
|
Math::BigInt |
2304
|
|
|
|
|
|
|
List::Util |
2305
|
|
|
|
|
|
|
Math::Random |
2306
|
|
|
|
|
|
|
Fcntl |
2307
|
|
|
|
|
|
|
|
2308
|
|
|
|
|
|
|
|
2309
|
|
|
|
|
|
|
=head1 THE C DIRECTORY |
2310
|
|
|
|
|
|
|
|
2311
|
|
|
|
|
|
|
The C directory contains the following script that invokes all of the |
2312
|
|
|
|
|
|
|
functionality of this module: |
2313
|
|
|
|
|
|
|
|
2314
|
|
|
|
|
|
|
BitVectorDemo.pl |
2315
|
|
|
|
|
|
|
|
2316
|
|
|
|
|
|
|
In case there is any doubt about how exactly to invoke a method or how to use an |
2317
|
|
|
|
|
|
|
operator, please look at the usage in this script. |
2318
|
|
|
|
|
|
|
|
2319
|
|
|
|
|
|
|
=head1 EXPORT |
2320
|
|
|
|
|
|
|
|
2321
|
|
|
|
|
|
|
None by design. |
2322
|
|
|
|
|
|
|
|
2323
|
|
|
|
|
|
|
=head1 BUGS |
2324
|
|
|
|
|
|
|
|
2325
|
|
|
|
|
|
|
Please notify the author if you encounter any bugs. When sending email, please place |
2326
|
|
|
|
|
|
|
the string 'BitVector' in the subject line. |
2327
|
|
|
|
|
|
|
|
2328
|
|
|
|
|
|
|
=head1 INSTALLATION |
2329
|
|
|
|
|
|
|
|
2330
|
|
|
|
|
|
|
Download the archive from CPAN in any directory of your choice. Unpack the archive |
2331
|
|
|
|
|
|
|
with a command that on a Linux machine would look like: |
2332
|
|
|
|
|
|
|
|
2333
|
|
|
|
|
|
|
tar zxvf Algorithm-BitVector-1.26.tar.gz |
2334
|
|
|
|
|
|
|
|
2335
|
|
|
|
|
|
|
This will create an installation directory for you whose name will be |
2336
|
|
|
|
|
|
|
C. Enter this directory and execute the following commands |
2337
|
|
|
|
|
|
|
for a standard install of the module if you have root privileges: |
2338
|
|
|
|
|
|
|
|
2339
|
|
|
|
|
|
|
perl Makefile.PL |
2340
|
|
|
|
|
|
|
make |
2341
|
|
|
|
|
|
|
make test |
2342
|
|
|
|
|
|
|
sudo make install |
2343
|
|
|
|
|
|
|
|
2344
|
|
|
|
|
|
|
If you do not have root privileges, you can carry out a non-standard install the |
2345
|
|
|
|
|
|
|
module in any directory of your choice by: |
2346
|
|
|
|
|
|
|
|
2347
|
|
|
|
|
|
|
perl Makefile.PL prefix=/some/other/directory/ |
2348
|
|
|
|
|
|
|
make |
2349
|
|
|
|
|
|
|
make test |
2350
|
|
|
|
|
|
|
make install |
2351
|
|
|
|
|
|
|
|
2352
|
|
|
|
|
|
|
With a non-standard install, you may also have to set your PERL5LIB environment |
2353
|
|
|
|
|
|
|
variable so that this module can find the required other modules. How you do that |
2354
|
|
|
|
|
|
|
would depend on what platform you are working on. In order to install this module in |
2355
|
|
|
|
|
|
|
a Linux machine on which I use tcsh for the shell, I set the PERL5LIB environment |
2356
|
|
|
|
|
|
|
variable by |
2357
|
|
|
|
|
|
|
|
2358
|
|
|
|
|
|
|
setenv PERL5LIB /some/other/directory/lib64/perl5/:/some/other/directory/share/perl5/ |
2359
|
|
|
|
|
|
|
|
2360
|
|
|
|
|
|
|
If I used bash, I'd need to declare: |
2361
|
|
|
|
|
|
|
|
2362
|
|
|
|
|
|
|
export PERL5LIB=/some/other/directory/lib64/perl5/:/some/other/directory/share/perl5/ |
2363
|
|
|
|
|
|
|
|
2364
|
|
|
|
|
|
|
|
2365
|
|
|
|
|
|
|
=head1 THANKS |
2366
|
|
|
|
|
|
|
|
2367
|
|
|
|
|
|
|
The bug in the primality test function, whose fix resulted in Version 1.21, was |
2368
|
|
|
|
|
|
|
reported by Dana Jacobsen in a bug report filed at C. Thanks Dana! |
2369
|
|
|
|
|
|
|
|
2370
|
|
|
|
|
|
|
The restriction on the Perl version was removed on Slaven Rezic's recommendation. He |
2371
|
|
|
|
|
|
|
says the module runs fine with Perl 5.8.9. Thanks Slaven! |
2372
|
|
|
|
|
|
|
|
2373
|
|
|
|
|
|
|
Austin Nobis reported a documentation error in Version 1.24 which was fixed in Version |
2374
|
|
|
|
|
|
|
1.25. Thanks Austin! |
2375
|
|
|
|
|
|
|
|
2376
|
|
|
|
|
|
|
=head1 AUTHOR |
2377
|
|
|
|
|
|
|
|
2378
|
|
|
|
|
|
|
The author, Avinash Kak, recently finished a 17-years long "Objects Trilogy Project" |
2379
|
|
|
|
|
|
|
with the publication of the book "Designing with Objects" by John-Wiley. If |
2380
|
|
|
|
|
|
|
interested, visit his web page at Purdue to find out what this project was all |
2381
|
|
|
|
|
|
|
about. You might like "Designing with Objects" especially if you enjoyed reading |
2382
|
|
|
|
|
|
|
Harry Potter as a kid (or even as an adult, for that matter). |
2383
|
|
|
|
|
|
|
|
2384
|
|
|
|
|
|
|
For all issues related to this module, contact the author at kak@purdue.edu |
2385
|
|
|
|
|
|
|
|
2386
|
|
|
|
|
|
|
If you send email, please place the string "BitVector" in your subject line to get |
2387
|
|
|
|
|
|
|
past the author's spam filter. |
2388
|
|
|
|
|
|
|
|
2389
|
|
|
|
|
|
|
=head1 COPYRIGHT |
2390
|
|
|
|
|
|
|
|
2391
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify it under the |
2392
|
|
|
|
|
|
|
same terms as Perl itself. |
2393
|
|
|
|
|
|
|
|
2394
|
|
|
|
|
|
|
Copyright 2018 Avinash Kak |
2395
|
|
|
|
|
|
|
|
2396
|
|
|
|
|
|
|
=cut |
2397
|
|
|
|
|
|
|
|