File Coverage

blib/lib/Math/Logic/Ternary/Calculator/State.pm
Criterion Covered Total %
statement 81 194 41.7
branch 11 36 30.5
condition 2 12 16.6
subroutine 22 44 50.0
pod 0 21 0.0
total 116 307 37.7


line stmt bran cond sub pod time code
1             # Copyright (c) 2012-2017 Martin Becker, Blaubeuren. All rights reserved.
2             # This package is free software; you can redistribute it and/or modify it
3             # under the same terms as Perl itself.
4              
5             package Math::Logic::Ternary::Calculator::State;
6              
7 3     3   44318 use 5.008;
  3         10  
8 3     3   15 use strict;
  3         5  
  3         58  
9 3     3   13 use warnings;
  3         6  
  3         72  
10 3     3   13 use Carp qw(croak);
  3         7  
  3         132  
11 3     3   462 use Math::Logic::Ternary::Calculator::Mode;
  3         6  
  3         57  
12 3     3   779 use Math::Logic::Ternary::Word;
  3         9  
  3         106  
13 3     3   937 use Math::Logic::Ternary qw(nil true false);
  3         7  
  3         197  
14              
15 3     3   16 use constant MODE => Math::Logic::Ternary::Calculator::Mode::;
  3         7  
  3         252  
16              
17             our $VERSION = '0.004';
18             our $DEFAULT_MODE = MODE->balanced;
19             our $MAX_WORD_SIZE = (Math::Logic::Ternary::Word::MAX_SIZE - 1) >> 1;
20              
21 3     3   15 use constant _WORD_SIZE => 0;
  3         4  
  3         117  
22 3     3   14 use constant _MODE => 1;
  3         5  
  3         146  
23 3     3   15 use constant _ZERO => 2;
  3         5  
  3         105  
24 3     3   13 use constant _BY_INDEX => 3;
  3         6  
  3         97  
25 3     3   14 use constant _BY_NAME => 4;
  3         5  
  3         101  
26 3     3   13 use constant _FORMAT => 5;
  3         5  
  3         101  
27 3     3   12 use constant _MAX_ABC => 6;
  3         6  
  3         3983  
28              
29             sub _check_size {
30 2     2   3 my ($size) = @_;
31 2 50       6 if (!defined $size) {
32 0         0 croak "size parameter expected";
33             }
34 2 50 33     8 if ($size < 1 || $MAX_WORD_SIZE < $size) {
35 0         0 croak "illegal size, choose from 1..$MAX_WORD_SIZE";
36             }
37             }
38              
39             sub _check_mode {
40 2     2   4 my ($mode) = @_;
41 2 50       5 if (!defined $mode) {
42 0         0 return $DEFAULT_MODE;
43             }
44 2 50       2 if (eval { $mode->isa(MODE) }) {
  2         13  
45 0         0 return $mode;
46             }
47 2         8 my @all_modes = MODE->modes;
48 2 50 33     10 if (0 <= $mode && $mode < @all_modes) {
49 2         5 return $all_modes[$mode];
50             }
51 0         0 croak "illegal mode, choose from 0..$#all_modes";
52             }
53              
54             sub _as_base27 {
55 0     0   0 my ($obj) = @_;
56 0 0       0 return $obj->can('as_base27')? $obj->as_base27: $obj->as_string;
57             }
58              
59             sub _make_format {
60 2     2   5 my ($size) = @_;
61 2         6 my $b27len = int( ($size + 5) / 3 );
62 2 50       5 if ($size > 81) {
63             return sub {
64 0     0   0 my ($this, $name, $obj) = @_;
65 0         0 my $bval = _as_base27($obj);
66 0         0 my $npad = q[ ] x ( 9 - length $name);
67 0         0 my $bpad = q[ ] x ($b27len - length $bval);
68 0         0 return "$name$npad $bpad$bval";
69 0         0 };
70             }
71 2         6 my $declen = int( log(3) * $size / log(10) + 2 );
72 2 50       4 if ($size > 36) {
73             return sub {
74 0     0   0 my ($this, $name, $obj) = @_;
75 0         0 my $as_int = $this->mode->apply('as_int');
76 0         0 my $bval = _as_base27($obj);
77 0         0 my $int = $obj->$as_int;
78 0 0       0 my $sign = $int < 0? q[]: q[+];
79 0         0 my $dval = $sign . $int;
80 0         0 my $npad = q[ ] x ( 9 - length $name);
81 0         0 my $bpad = q[ ] x ($b27len - length $bval);
82 0         0 my $dpad = q[ ] x ($declen - length $dval);
83 0         0 return "$name$npad $bpad$bval $dpad$dval";
84 0         0 };
85             }
86 2         3 my $strlen = $size + 1;
87 2 50       4 if ($strlen < 6) {
88 0         0 $strlen = 6;
89             }
90 2 100       5 if ($b27len < 6) {
91 1         2 $b27len = 6;
92             }
93 2 50       5 if ($declen < 6) {
94 0         0 $declen = 6;
95             }
96             return sub {
97 0     0   0 my ($this, $name, $obj) = @_;
98 0         0 my $as_int = $this->mode->apply('as_int');
99 0         0 my $bval = _as_base27($obj);
100 0         0 my $int = $obj->$as_int;
101 0 0       0 my $sign = $int < 0? q[]: q[+];
102 0         0 my $dval = $sign . $int;
103 0         0 my $sval = $obj->as_string;
104 0         0 my $npad = q[ ] x ( 9 - length $name);
105 0         0 my $bpad = q[ ] x ($b27len - length $bval);
106 0         0 my $dpad = q[ ] x ($declen - length $dval);
107 0         0 my $spad = q[ ] x ($strlen - length $sval);
108 0         0 return "$name$npad $bpad$bval $spad$sval $dpad$dval";
109 2         11 };
110             }
111              
112             sub _max_abc {
113 2     2   3 my ($size) = @_;
114 2         3 my $result = 0;
115 2         4 my $npower = 3;
116 2         4 while ($npower <= $size) {
117 5         7 ++$result;
118 5         9 $npower *= 3;
119             }
120 2         3 return $result;
121             }
122              
123             sub new {
124 2     2 0 5 my ($class, $size, $mode) = @_;
125 2         6 _check_size($size);
126 2         5 $mode = _check_mode($mode);
127 2         6 my $format = _make_format($size);
128 2         14 my $zero = Math::Logic::Ternary::Word->from_trits($size);
129 2         5 my $max_abc = _max_abc($size);
130 2         10 return bless [$size, $mode, $zero, [], {}, $format, $max_abc], $class;
131             }
132              
133 2     2 0 5 sub word_size { $_[0]->[_WORD_SIZE] }
134 2     2 0 6 sub mode { $_[0]->[_MODE ] }
135 0     0 0   sub zero { $_[0]->[_ZERO ] }
136 0     0 0   sub fetch { $_[0]->[_BY_INDEX ]->[$_[1]] }
137 0     0 0   sub recall { $_[0]->[_BY_NAME ]->{$_[1]} }
138 0     0 0   sub min_index { -@{$_[0]->[_BY_INDEX ]} }
  0            
139 0     0 0   sub max_index { $#{$_[0]->[_BY_INDEX ]} }
  0            
140 0     0 0   sub all_names { sort keys %{$_[0]->[_BY_NAME ]} }
  0            
141 0     0 0   sub store { $_[0]->[_BY_NAME ]->{$_[1]} = $_[2] }
142 0     0 0   sub format_value { $_[0]->[_FORMAT ]->(@_) }
143 0     0 0   sub max_abc { $_[0]->[_MAX_ABC ] }
144              
145             sub set_mode {
146 0     0 0   my ($this, $mode) = @_;
147 0 0         eval { $mode->isa('Math::Logic::Ternary::Calculator::Mode') }
  0            
148             or croak "ternary calculator mode object expected";
149 0           $this->[_MODE] = $mode;
150             }
151              
152             # @indexes = $state->append(@values);
153             sub append {
154 0     0 0   my $this = shift;
155 0           my $by_i = $this->[_BY_INDEX];
156 0           my $i = @{$by_i};
  0            
157 0           push @{$by_i}, @_;
  0            
158 0           return map { $i++ } @_;
  0            
159             }
160              
161             # $value = $state->convert_int($int);
162             sub convert_int {
163 0     0 0   my ($this, $int) = @_;
164 0           my $from_int = $this->mode->apply('from_int');
165 0           return Math::Logic::Ternary::Word->$from_int($this->word_size, $int);
166             }
167              
168             sub convert_string {
169 0     0 0   my ($this, $str) = @_;
170 0           return Math::Logic::Ternary::Word->from_string($this->word_size, $str);
171             }
172              
173             sub normalize_operands {
174 0     0 0   my ($this, @operands) = @_;
175 0           my $zero = $this->zero;
176 0 0         return @operands? (map { $zero->convert_words($_) } @operands): $zero;
  0            
177             }
178              
179             sub range {
180 0     0 0   my ($this) = @_;
181 0           my $mode = $this->mode;
182 0           my $size = $this->word_size;
183 0           my $min_int = $mode->apply('min_int');
184 0           my $max_int = $mode->apply('max_int');
185 0           my $zero = Math::Logic::Ternary::Word->from_trits($size);
186 0           return ($zero->$min_int, $zero->$max_int);
187             }
188              
189             sub rand {
190 0     0 0   my ($this) = @_;
191 0           my $size = $this->word_size;
192 0           my @trits = (nil, true, false);
193             return
194             Math::Logic::Ternary::Word->from_trits($size,
195 0           @trits[map {rand 3} 1 .. $size]
  0            
196             );
197             }
198              
199             sub abc {
200 0     0 0   my ($this, $dim) = @_;
201 0           my $mode = $this->mode;
202 0 0         my @trits = $mode->is_balanced? (true, nil, false): (false, true, nil);
203 0           my @abc = ([@trits]);
204 0           my $size = 3;
205 0           while (@abc < $dim) {
206 0           foreach my $vec (@abc) {
207 0           push @{$vec}, @{$vec}, @{$vec};
  0            
  0            
  0            
208             }
209 0           unshift @abc, [map {($_) x $size} @trits];
  0            
210 0           $size *= 3;
211             }
212             return
213 0           map { Math::Logic::Ternary::Word->from_trits($size, @{$_}) } @abc;
  0            
  0            
214             }
215              
216             sub reset {
217 0     0 0   my ($this, $what) = @_;
218 0           my @discarded = ();
219 0 0 0       if (!$what || 1 == $what) {
220 0           push @discarded, 0 + @{$this->[_BY_INDEX]};
  0            
221 0           @{$this->[_BY_INDEX]} = ();
  0            
222             }
223 0 0 0       if (!$what || 2 == $what) {
224 0           push @discarded, 0 + keys %{$this->[_BY_NAME]};
  0            
225 0           %{$this->[_BY_NAME]} = ();
  0            
226             }
227 0           return @discarded;
228             }
229              
230             1;
231             __END__