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::Trit; |
6
|
|
|
|
|
|
|
|
7
|
16
|
|
|
16
|
|
153747
|
use 5.008; |
|
16
|
|
|
|
|
59
|
|
8
|
16
|
|
|
16
|
|
98
|
use strict; |
|
16
|
|
|
|
|
38
|
|
|
16
|
|
|
|
|
352
|
|
9
|
16
|
|
|
16
|
|
80
|
use warnings; |
|
16
|
|
|
|
|
43
|
|
|
16
|
|
|
|
|
460
|
|
10
|
16
|
|
|
16
|
|
77
|
use Carp qw(croak); |
|
16
|
|
|
|
|
49
|
|
|
16
|
|
|
|
|
894
|
|
11
|
16
|
|
|
16
|
|
90
|
use Scalar::Util qw(blessed); |
|
16
|
|
|
|
|
32
|
|
|
16
|
|
|
|
|
720
|
|
12
|
16
|
|
|
16
|
|
3603
|
use Role::Basic qw(with); |
|
16
|
|
|
|
|
128184
|
|
|
16
|
|
|
|
|
127
|
|
13
|
|
|
|
|
|
|
with qw(Math::Logic::Ternary::Object); |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $VERSION = '0.004'; |
16
|
|
|
|
|
|
|
our @CARP_NOT = qw(Math::Logic::Ternary Math::Logic::Ternary::Word); |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# ----- auxiliary constants ----- |
19
|
|
|
|
|
|
|
|
20
|
16
|
|
|
16
|
|
1607
|
use constant TRIT_PREFIX => '$'; |
|
16
|
|
|
|
|
37
|
|
|
16
|
|
|
|
|
1038
|
|
21
|
|
|
|
|
|
|
|
22
|
16
|
|
|
16
|
|
94
|
use constant _UINT => 0; |
|
16
|
|
|
|
|
34
|
|
|
16
|
|
|
|
|
685
|
|
23
|
16
|
|
|
16
|
|
110
|
use constant _INT => 1; |
|
16
|
|
|
|
|
32
|
|
|
16
|
|
|
|
|
649
|
|
24
|
16
|
|
|
16
|
|
89
|
use constant _NAME => 2; |
|
16
|
|
|
|
|
33
|
|
|
16
|
|
|
|
|
627
|
|
25
|
16
|
|
|
16
|
|
90
|
use constant _PNAME => 3; |
|
16
|
|
|
|
|
31
|
|
|
16
|
|
|
|
|
679
|
|
26
|
16
|
|
|
16
|
|
87
|
use constant _IS_NIL => 4; |
|
16
|
|
|
|
|
29
|
|
|
16
|
|
|
|
|
666
|
|
27
|
16
|
|
|
16
|
|
85
|
use constant _IS_TRUE => 5; |
|
16
|
|
|
|
|
43
|
|
|
16
|
|
|
|
|
653
|
|
28
|
16
|
|
|
16
|
|
82
|
use constant _IS_FALSE => 6; |
|
16
|
|
|
|
|
30
|
|
|
16
|
|
|
|
|
648
|
|
29
|
16
|
|
|
16
|
|
94
|
use constant _BOOL => 7; |
|
16
|
|
|
|
|
35
|
|
|
16
|
|
|
|
|
676
|
|
30
|
16
|
|
|
16
|
|
85
|
use constant _MODINT => 8; |
|
16
|
|
|
|
|
31
|
|
|
16
|
|
|
|
|
695
|
|
31
|
|
|
|
|
|
|
|
32
|
16
|
|
|
16
|
|
110
|
use constant _MAX_MEMOIZED_OPS => 364; |
|
16
|
|
|
|
|
30
|
|
|
16
|
|
|
|
|
21272
|
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# class backing data type for logical values: singleton arrayref |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
my @trits = |
37
|
|
|
|
|
|
|
my ($nil, $true, $false) = map { bless $_ } ( |
38
|
|
|
|
|
|
|
[0, 0, 'nil' ], |
39
|
|
|
|
|
|
|
[1, 1, 'true' ], |
40
|
|
|
|
|
|
|
[2, -1, 'false'], |
41
|
|
|
|
|
|
|
); |
42
|
|
|
|
|
|
|
foreach my $trit ($nil, $true, $false) { |
43
|
|
|
|
|
|
|
$trit->[_PNAME] = TRIT_PREFIX . $trit->[_NAME]; |
44
|
|
|
|
|
|
|
$trit->[_IS_NIL] = $trit->[_UINT] == $nil->[_UINT]; |
45
|
|
|
|
|
|
|
$trit->[_IS_TRUE] = $trit->[_UINT] == $true->[_UINT]; |
46
|
|
|
|
|
|
|
$trit->[_IS_FALSE] = $trit->[_UINT] == $false->[_UINT]; |
47
|
|
|
|
|
|
|
$trit->[_BOOL] = $trit->[_IS_NIL]? undef: $trit->[_IS_TRUE]; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# return values for trit conversions |
51
|
|
|
|
|
|
|
my %by_name = |
52
|
|
|
|
|
|
|
map { |
53
|
|
|
|
|
|
|
($_->[_NAME] => $_, $_->[_PNAME] => $_) |
54
|
|
|
|
|
|
|
} @trits; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# tables for parameter to index mappings |
57
|
|
|
|
|
|
|
my @arg3s = ( |
58
|
|
|
|
|
|
|
[[0, 1, 2], [1, 3, 4], [2, 4, 5]], |
59
|
|
|
|
|
|
|
[[1, 3, 4], [3, 6, 7], [4, 7, 8]], |
60
|
|
|
|
|
|
|
[[2, 4, 5], [4, 7, 8], [5, 8, 9]], |
61
|
|
|
|
|
|
|
); |
62
|
|
|
|
|
|
|
my @arg4s = ( |
63
|
|
|
|
|
|
|
\@arg3s, |
64
|
|
|
|
|
|
|
[ |
65
|
|
|
|
|
|
|
[[1, 3, 4], [3, 6, 7], [4, 7, 8]], |
66
|
|
|
|
|
|
|
[[3, 6, 7], [6, 10, 11], [7, 11, 12]], |
67
|
|
|
|
|
|
|
[[4, 7, 8], [7, 11, 12], [8, 12, 13]], |
68
|
|
|
|
|
|
|
], |
69
|
|
|
|
|
|
|
[ |
70
|
|
|
|
|
|
|
[[2, 4, 5], [4, 7, 8], [5, 8, 9]], |
71
|
|
|
|
|
|
|
[[4, 7, 8], [7, 11, 12], [8, 12, 13]], |
72
|
|
|
|
|
|
|
[[5, 8, 9], [8, 12, 13], [9, 13, 14]], |
73
|
|
|
|
|
|
|
], |
74
|
|
|
|
|
|
|
); |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# generic op prefixes |
77
|
|
|
|
|
|
|
my %arity = ( |
78
|
|
|
|
|
|
|
c => 0, |
79
|
|
|
|
|
|
|
u => 1, |
80
|
|
|
|
|
|
|
b => 2, |
81
|
|
|
|
|
|
|
s => 3, |
82
|
|
|
|
|
|
|
t => 3, |
83
|
|
|
|
|
|
|
q => 4, |
84
|
|
|
|
|
|
|
Q => 4, |
85
|
|
|
|
|
|
|
); |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# named operators |
88
|
|
|
|
|
|
|
my @named_ops = ( |
89
|
|
|
|
|
|
|
[sn => 'u000'], # Set to Nil |
90
|
|
|
|
|
|
|
[st => 'u111'], # Set to True |
91
|
|
|
|
|
|
|
[sf => 'u222'], # Set to False |
92
|
|
|
|
|
|
|
[id => 'u012'], # IDentity |
93
|
|
|
|
|
|
|
[not => 'u021'], # NOT |
94
|
|
|
|
|
|
|
[up => 'u120'], # increment modulo 3, UP one |
95
|
|
|
|
|
|
|
[nup => 'u210'], # swap nil/false, Not(UP(x)) |
96
|
|
|
|
|
|
|
[dn => 'u201'], # decrement modulo 3, DowN one |
97
|
|
|
|
|
|
|
[ndn => 'u102'], # swap nil/true, Not(DowN(x)) |
98
|
|
|
|
|
|
|
[eqn => 'u122'], # EQual to Nil |
99
|
|
|
|
|
|
|
[eqt => 'u212'], # EQual to True |
100
|
|
|
|
|
|
|
[eqf => 'u221'], # EQual to False |
101
|
|
|
|
|
|
|
[nen => 'u211'], # Not Equal to Nil |
102
|
|
|
|
|
|
|
[net => 'u121'], # Not Equal to True |
103
|
|
|
|
|
|
|
[nef => 'u112'], # Not Equal to False |
104
|
|
|
|
|
|
|
[hm => 'u011'], # HaMlet (x or not x) |
105
|
|
|
|
|
|
|
[uhm => 'u110'], # Up & HaMlet |
106
|
|
|
|
|
|
|
[dhm => 'u101'], # Down & HaMlet |
107
|
|
|
|
|
|
|
[orn => 'u010'], # OR Nil |
108
|
|
|
|
|
|
|
[uorn => 'u100'], # Up & OR Nil |
109
|
|
|
|
|
|
|
[dorn => 'u001'], # Down & OR Nil |
110
|
|
|
|
|
|
|
[qt => 'u022'], # QuanTum (x and not x) |
111
|
|
|
|
|
|
|
[uqt => 'u220'], # Up & QuanTum |
112
|
|
|
|
|
|
|
[dqt => 'u202'], # Down & QuanTum |
113
|
|
|
|
|
|
|
[ann => 'u002'], # ANd Nil |
114
|
|
|
|
|
|
|
[uann => 'u020'], # Up & ANd Nil |
115
|
|
|
|
|
|
|
[dann => 'u200'], # Down & ANd Nil |
116
|
|
|
|
|
|
|
[and => 'b002012222'], # AND |
117
|
|
|
|
|
|
|
[or => 'b010111012'], # OR |
118
|
|
|
|
|
|
|
[xor => 'b000021012'], # eXclusive OR |
119
|
|
|
|
|
|
|
[eqv => 'b000012021'], # EQuiValent |
120
|
|
|
|
|
|
|
[imp => 'b010012111'], # IMPlication (x ==> y) |
121
|
|
|
|
|
|
|
[rep => 'b001111021'], # REPlication (x <== y) |
122
|
|
|
|
|
|
|
[nand => 'b001021111'], # Not AND |
123
|
|
|
|
|
|
|
[nor => 'b020222021'], # Not OR |
124
|
|
|
|
|
|
|
[cmp => 'b021101220'], # CoMPare, false < nil < true |
125
|
|
|
|
|
|
|
[asc => 'b012202110'], # ASCending |
126
|
|
|
|
|
|
|
[tlr => 'b002012222'], # The LesseR |
127
|
|
|
|
|
|
|
[tgr => 'b010111012'], # The GreateR |
128
|
|
|
|
|
|
|
[eq => 'b122212221'], # EQual to |
129
|
|
|
|
|
|
|
[ne => 'b211121112'], # Not Equal to |
130
|
|
|
|
|
|
|
[lt => 'b212222112'], # Less Than |
131
|
|
|
|
|
|
|
[ge => 'b121111221'], # Greater or Equal |
132
|
|
|
|
|
|
|
[gt => 'b221121222'], # Greater Than |
133
|
|
|
|
|
|
|
[le => 'b112212111'], # Less or Equal |
134
|
|
|
|
|
|
|
[cmpu => 'b022102110'], # CoMPare (Unbalanced), nil < true < false |
135
|
|
|
|
|
|
|
[ascu => 'b011201220'], # ASCending (Unbalanced) |
136
|
|
|
|
|
|
|
[tlru => 'b000011012'], # The LesseR (Unbalanced) |
137
|
|
|
|
|
|
|
[tgru => 'b012112222'], # The GreateR (Unbalanced) |
138
|
|
|
|
|
|
|
[ltu => 'b211221222'], # Less Than (Unbalanced) |
139
|
|
|
|
|
|
|
[geu => 'b122112111'], # Greater or Equal (Unbalanced) |
140
|
|
|
|
|
|
|
[gtu => 'b222122112'], # Greater Than (Unbalanced) |
141
|
|
|
|
|
|
|
[leu => 'b111211221'], # Less or Equal (Unbalanced) |
142
|
|
|
|
|
|
|
[incr => 'b012120201'], # INCRement |
143
|
|
|
|
|
|
|
[incc => 'b000010002'], # INCrement Carry |
144
|
|
|
|
|
|
|
[inccu => 'b000001011'], # INCrement Carry (Unbalanced) |
145
|
|
|
|
|
|
|
[inccv => 'b001000020'], # INCrement Carry (negatiVe base) |
146
|
|
|
|
|
|
|
[decr => 'b021102210'], # DECRement |
147
|
|
|
|
|
|
|
[decc => 'b000002010'], # DECrement Carry |
148
|
|
|
|
|
|
|
[deccu => 'b011001000'], # DECrement Carry (Unbalanced) |
149
|
|
|
|
|
|
|
[deccv => 'b020000001'], # DECrement Carry (negatiVe base) |
150
|
|
|
|
|
|
|
[pty => 'b021210102'], # PariTY |
151
|
|
|
|
|
|
|
[dpl => 'b012201120'], # DuPLicate |
152
|
|
|
|
|
|
|
[dplc => 'b000110202'], # DuPLication Carry |
153
|
|
|
|
|
|
|
[dplcu => 'b000011112'], # DuPLication Carry (Unbalanced) |
154
|
|
|
|
|
|
|
[dplcv => 'b001020222'], # DuPLication Carry (negatiVe base) |
155
|
|
|
|
|
|
|
# [hlv => 'b011022211'], # HaLVe |
156
|
|
|
|
|
|
|
# [hlvc => 'b011100100'], # HaLVing Carry |
157
|
|
|
|
|
|
|
# [hlvs => 'b002010002'], # HaLVing Second carry |
158
|
|
|
|
|
|
|
# [hlvu => 'b000000000'], # HaLVe (Unbalanced) |
159
|
|
|
|
|
|
|
# [hlvcu => 'b000000000'], # HaLVing Carry (Unbalanced) |
160
|
|
|
|
|
|
|
# [hlvsu => 'b000000000'], # HaLVing Second carry (Unbalanced) |
161
|
|
|
|
|
|
|
[negcv => 'b000100110'], # NEGation Carry (negatiVe base) |
162
|
|
|
|
|
|
|
[mulcu => 'b000000001'], # MULtiplication Carry (Unbalanced) |
163
|
|
|
|
|
|
|
[add => 's0122010120'], # ADDition |
164
|
|
|
|
|
|
|
[addc => 's0001021002'], # ADDition Carry |
165
|
|
|
|
|
|
|
[addcu => 's0000111112'], # ADDition Carry (Unbalanced) |
166
|
|
|
|
|
|
|
[addcv => 't001000020000020220020220222'], # ADDition Carry (negatiVe base) |
167
|
|
|
|
|
|
|
[addcx => 't001000101000020001020220000'], # ADDition Carry (miXed base) |
168
|
|
|
|
|
|
|
[subt => 't021210102102021210210102021'], # SUBTraction |
169
|
|
|
|
|
|
|
[subc => 't000010002002000202010110000'], # SUBTraction Carry |
170
|
|
|
|
|
|
|
[subcu => 't011111112001011111000001011'], # SUBTraction Carry (Unbal.) |
171
|
|
|
|
|
|
|
[subcv => 't020220222000020220001000020'], # SUBTraction Carry (nV.b.) |
172
|
|
|
|
|
|
|
# [amn => 't000000000000000000000000000'], # Arithmetic MeaN |
173
|
|
|
|
|
|
|
# [amnc => 't000000000000000000000000000'], # Arithmetic MeaN Carry |
174
|
|
|
|
|
|
|
# [amncu => 't000000000000000000000000000'], # Arithmetic MeaN Carry (Unbal.) |
175
|
|
|
|
|
|
|
[ipqc => 's0211020210'], # InterPolation Quadratic Coeff |
176
|
|
|
|
|
|
|
[cmin => 't000221000121121121000220000'], # ternary Comparison to MINimum |
177
|
|
|
|
|
|
|
[cmed => 't121102121010212010121001121'], # ternary Comparison to MEDian |
178
|
|
|
|
|
|
|
[cmax => 't212010212202000202212112212'], # ternary Comparison to MAXimum |
179
|
|
|
|
|
|
|
[cvld => 't100010001001111021010012111'], # ternary Comparison VaLiDation |
180
|
|
|
|
|
|
|
[min => 's0020221222'], # MINimum of three |
181
|
|
|
|
|
|
|
[med => 's0001021122'], # MEDian of three |
182
|
|
|
|
|
|
|
[max => 's0101101112'], # MAXimum of three |
183
|
|
|
|
|
|
|
[minu => 's0000001112'], # MINimum of three (Unbalanced) |
184
|
|
|
|
|
|
|
[medu => 's0001121122'], # MEDian of three (Unbalanced) |
185
|
|
|
|
|
|
|
[maxu => 's0121221222'], # MAXimum of three (Unbalanced) |
186
|
|
|
|
|
|
|
[sum => 'q012201012012012'], # SUMmation |
187
|
|
|
|
|
|
|
[sumc => 'q000102100211022'], # SUMmation Carry |
188
|
|
|
|
|
|
|
[sumcu => 'q000011111211222'], # SUMmation Carry (Unbalanced) |
189
|
|
|
|
|
|
|
); |
190
|
|
|
|
|
|
|
# names of arithmetic operators with mode-dependent variants |
191
|
|
|
|
|
|
|
my %is_ar = map {($_ => 0, $_ . 'u' => 1, $_ . 'v' => 2)} qw( |
192
|
|
|
|
|
|
|
asc cmp ge gt le lt max med min tgr tlr |
193
|
|
|
|
|
|
|
addc decc dplc incc negc subc sumc |
194
|
|
|
|
|
|
|
); |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# ----- private variables ----- |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
# operator memoizer |
199
|
|
|
|
|
|
|
# initialized with some special cases |
200
|
|
|
|
|
|
|
# maps name to [argc, sub] |
201
|
|
|
|
|
|
|
my %OP = ( |
202
|
|
|
|
|
|
|
'c0' => [0, sub { 0 }], |
203
|
|
|
|
|
|
|
'c1' => [0, sub { 1 }], |
204
|
|
|
|
|
|
|
'c2' => [0, sub { 2 }], |
205
|
|
|
|
|
|
|
'u012' => [1, sub { $_[0] }], |
206
|
|
|
|
|
|
|
); |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# ----- other initializations ----- |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
_load_generated_methods(); |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# ----- private subroutines ----- |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
# raw unary op factory, takes 3 values |
215
|
|
|
|
|
|
|
sub _unary { |
216
|
385
|
|
|
385
|
|
1136
|
my @val = @_; |
217
|
385
|
|
|
36625
|
|
1436
|
return sub { $val[$_[0]] }; |
|
36625
|
|
|
|
|
125725
|
|
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
# argument shifter, takes 1 operator, yields 1 operator |
221
|
|
|
|
|
|
|
sub _shiftarg { |
222
|
17
|
|
|
17
|
|
48
|
my $op = $_[0]; |
223
|
17
|
|
|
71
|
|
115
|
return sub { shift; $op->(@_) }; |
|
71
|
|
|
|
|
93
|
|
|
71
|
|
|
|
|
135
|
|
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# argument chooser, takes 3 operators, yields 1 operator with extra parameter |
227
|
|
|
|
|
|
|
sub _mpx { |
228
|
1610
|
|
|
1610
|
|
3292
|
my @op = @_; |
229
|
1610
|
|
|
34494
|
|
6508
|
return sub { my $i = shift; $op[$i]->(@_) }; |
|
34494
|
|
|
|
|
43375
|
|
|
34494
|
|
|
|
|
58972
|
|
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
# symmetric ternary op factory, takes 10 values |
233
|
|
|
|
|
|
|
sub _symmetric_3adic { |
234
|
160
|
|
|
160
|
|
649
|
my @val = @_; |
235
|
160
|
|
|
4955
|
|
687
|
return sub { $val[$arg3s[$_[0]]->[$_[1]]->[$_[2]]] }; |
|
4955
|
|
|
|
|
18689
|
|
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
# symmetric quaternary op factory, takes 15 values |
239
|
|
|
|
|
|
|
sub _symmetric_4adic { |
240
|
48
|
|
|
48
|
|
251
|
my @val = @_; |
241
|
48
|
|
|
6156
|
|
237
|
return sub { $val[$arg4s[$_[0]]->[$_[1]]->[$_[2]]->[$_[3]]] }; |
|
6156
|
|
|
|
|
21199
|
|
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
# raw operator factory, takes a name |
245
|
|
|
|
|
|
|
sub _OP { |
246
|
6855
|
|
|
6855
|
|
10595
|
my ($name) = @_; |
247
|
6855
|
100
|
|
|
|
17501
|
return $OP{$name} if exists $OP{$name}; |
248
|
3133
|
|
|
|
|
3968
|
my $op; |
249
|
3133
|
100
|
|
|
|
10703
|
if ($name =~ /^u([012])([012])([012])\z/) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
250
|
1297
|
100
|
100
|
|
|
4659
|
if ($1 eq $2 && $1 eq $3) { |
251
|
929
|
|
|
|
|
3317
|
return $OP{"c$1"}; |
252
|
|
|
|
|
|
|
} |
253
|
368
|
|
|
|
|
631
|
$op = [1, _unary($1, $2, $3)]; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
elsif ($name =~ /^b([012]{3})([012]{3})([012]{3})\z/) { |
256
|
1462
|
100
|
100
|
|
|
4291
|
if ($1 eq $2 && $1 eq $3) { |
257
|
17
|
|
|
|
|
78
|
return $OP{$name} = [2, _shiftarg(_unary(split //, $1))]; |
258
|
|
|
|
|
|
|
} |
259
|
1445
|
|
|
|
|
4127
|
$op = [2, _mpx(map {_OP($_)->[1]} "u$1", "u$2", "u$3")]; |
|
4335
|
|
|
|
|
7510
|
|
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
elsif ($name =~ /^s([012]{10})\z/) { |
262
|
160
|
|
|
|
|
685
|
$op = [3, _symmetric_3adic(split //, $1)]; |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
elsif ($name =~ /^t([012]{9})([012]{9})([012]{9})\z/) { |
265
|
164
|
|
|
|
|
658
|
$op = [3, _mpx(map {_OP($_)->[1]} "b$1", "b$2", "b$3")]; |
|
492
|
|
|
|
|
865
|
|
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
elsif ($name =~ /^q([012]{15})\z/) { |
268
|
48
|
|
|
|
|
241
|
$op = [4, _symmetric_4adic(split //, $1)]; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
elsif ($name =~ /^Q([012]{27})([012]{27})([012]{27})\z/) { |
271
|
1
|
|
|
|
|
12
|
$op = [4, _mpx(map {_OP($_)->[1]} "t$1", "t$2", "t$3")]; |
|
3
|
|
|
|
|
9
|
|
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
else { |
274
|
1
|
|
|
|
|
116
|
croak qq{unknown operator name "$name"}; |
275
|
|
|
|
|
|
|
} |
276
|
2186
|
100
|
|
|
|
5527
|
if (keys(%OP) < _MAX_MEMOIZED_OPS) { |
277
|
1933
|
|
|
|
|
4227
|
$OP{$name} = $op; |
278
|
|
|
|
|
|
|
} |
279
|
2186
|
|
|
|
|
4532
|
return $op; |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
sub _generic { |
283
|
2025
|
|
|
2025
|
|
2645
|
my ($argc, $op) = @{_OP($_[0])}; |
|
2025
|
|
|
|
|
3385
|
|
284
|
|
|
|
|
|
|
return sub { |
285
|
50286
|
100
|
|
50286
|
|
99386
|
if (@_ < $argc) { |
286
|
1
|
|
|
|
|
6
|
my $missing = $argc - @_; |
287
|
1
|
|
|
|
|
180
|
croak "too few arguments, expected $missing more"; |
288
|
|
|
|
|
|
|
} |
289
|
50285
|
|
|
|
|
94123
|
my @args = map { $_->res_mod3 } @_[0..$argc-1]; |
|
113181
|
|
|
|
|
164806
|
|
290
|
50285
|
|
|
|
|
84996
|
return $trits[ $op->(@args) ]; |
291
|
2024
|
|
|
|
|
12772
|
}; |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
sub _load_generated_methods { |
295
|
16
|
|
|
16
|
|
40
|
foreach my $arec (@named_ops) { |
296
|
1456
|
|
|
|
|
2335
|
my ($method, $gen_method) = @{$arec}; |
|
1456
|
|
|
|
|
2662
|
|
297
|
|
|
|
|
|
|
# use fully qualified method names to avoid clashes with builtins |
298
|
1456
|
|
|
|
|
2727
|
my $tm = __PACKAGE__ . '::' . $method; |
299
|
16
|
|
|
16
|
|
125
|
no strict 'refs'; |
|
16
|
|
|
|
|
34
|
|
|
16
|
|
|
|
|
19299
|
|
300
|
1456
|
|
|
|
|
2393
|
*$tm = _generic($gen_method); |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
# ----- class methods ----- |
305
|
|
|
|
|
|
|
|
306
|
92
|
|
|
92
|
1
|
966
|
sub nil { $nil } |
307
|
53
|
|
|
53
|
1
|
566
|
sub true { $true } |
308
|
55
|
|
|
55
|
1
|
585
|
sub false { $false } |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
sub from_bool { |
311
|
11
|
|
|
11
|
1
|
420
|
my $bool = $_[1]; |
312
|
11
|
100
|
|
|
|
40
|
return $true if $bool; |
313
|
7
|
100
|
|
|
|
19
|
return $false if defined $bool; |
314
|
3
|
|
|
|
|
30
|
return $nil; |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
5
|
|
|
5
|
1
|
1090
|
sub from_sign { $trits[$_[1] <=> 0] } |
318
|
5
|
|
|
5
|
1
|
1075
|
sub from_remainder { $trits[$_[1] % 3] } |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
sub from_int { |
321
|
361
|
|
|
361
|
1
|
2032
|
my $int = $_[1]; |
322
|
361
|
100
|
100
|
|
|
1229
|
croak qq{integer "$int" out of range -1..1} if $int < -1 || 1 < $int; |
323
|
357
|
|
|
|
|
794
|
return $trits[$int]; |
324
|
|
|
|
|
|
|
} |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
sub from_int_u { |
327
|
383
|
|
|
383
|
1
|
3753
|
my $int = $_[1]; |
328
|
383
|
100
|
100
|
|
|
1128
|
croak qq{integer "$int" out of range 0..2} if $int < 0 || 2 < $int; |
329
|
381
|
|
|
|
|
692
|
return $trits[$int]; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
sub from_string { |
333
|
20
|
|
|
20
|
1
|
1177
|
my $name = lc $_[1]; |
334
|
20
|
100
|
|
|
|
353
|
croak qq{unknown trit name "$_[1]"} if !exists $by_name{$name}; |
335
|
17
|
|
|
|
|
49
|
return $by_name{$name}; |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
sub from_modint { |
339
|
3
|
|
|
3
|
1
|
3816
|
my $mi = $_[1]; |
340
|
3
|
|
|
|
|
7
|
my ($mod, $res) = eval { $mi->modulus, $mi->residue }; |
|
3
|
|
|
|
|
23
|
|
341
|
3
|
100
|
100
|
|
|
529
|
croak qq{modular integer with modulus 3 expected} if !$mod || 3 != $mod; |
342
|
1
|
|
|
|
|
6
|
return $trits[$res]; |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
sub from_various { |
346
|
13
|
|
|
13
|
1
|
4360
|
my ($class, $item) = @_; |
347
|
13
|
|
|
|
|
40
|
my $type = blessed $item; |
348
|
13
|
100
|
|
|
|
93
|
if ($type) { |
349
|
6
|
100
|
|
|
|
14
|
if (eval { $item->DOES('Math::Logic::Ternary::Object') }) { |
|
6
|
|
|
|
|
68
|
|
350
|
1
|
|
|
|
|
15
|
return $class->from_int($item->as_int); |
351
|
|
|
|
|
|
|
} |
352
|
5
|
100
|
|
|
|
12
|
if (eval { $item->isa('Math::BigInt') }) { |
|
5
|
|
|
|
|
26
|
|
353
|
3
|
|
|
|
|
10
|
my $is_two = 2 == $item; # for Devel::Cover |
354
|
3
|
100
|
|
|
|
338
|
return $is_two? $false: $class->from_int($item); |
355
|
|
|
|
|
|
|
} |
356
|
2
|
100
|
|
|
|
6
|
if (eval { $item->isa('Math::ModInt') }) { |
|
2
|
|
|
|
|
17
|
|
357
|
1
|
|
|
|
|
5
|
return $class->from_modint($item); |
358
|
|
|
|
|
|
|
} |
359
|
1
|
|
|
|
|
88
|
croak qq{cannot convert "$type" object to a trit}; |
360
|
|
|
|
|
|
|
} |
361
|
7
|
|
|
|
|
12
|
$type = ref $item; |
362
|
7
|
100
|
|
|
|
15
|
if ($type) { |
363
|
1
|
|
|
|
|
98
|
croak qq{cannot convert $type reference to a trit}; |
364
|
|
|
|
|
|
|
} |
365
|
6
|
100
|
|
|
|
13
|
if (!defined $item) { |
366
|
1
|
|
|
|
|
4
|
return $nil; |
367
|
|
|
|
|
|
|
} |
368
|
5
|
100
|
|
|
|
27
|
if ($item =~ /^[\+\-]?\d+\z/) { |
369
|
3
|
100
|
|
|
|
11
|
return 2 == $item? $false: $class->from_int($item); |
370
|
|
|
|
|
|
|
} |
371
|
2
|
|
|
|
|
7
|
return $class->from_string($item); |
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
|
374
|
2
|
|
|
2
|
1
|
868
|
sub make_generic { _generic($_[1]) } |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
sub trit_operators { |
377
|
|
|
|
|
|
|
return ( |
378
|
|
|
|
|
|
|
[nil => 0, 0, 1], |
379
|
|
|
|
|
|
|
[true => 0, 0, 1], |
380
|
|
|
|
|
|
|
[false => 0, 0, 1], |
381
|
|
|
|
|
|
|
( |
382
|
|
|
|
|
|
|
map { |
383
|
20
|
|
|
20
|
1
|
126
|
my ($name, $gname) = @{$_}; |
|
1820
|
|
|
|
|
2350
|
|
|
1820
|
|
|
|
|
2894
|
|
384
|
|
|
|
|
|
|
[ |
385
|
|
|
|
|
|
|
$name, |
386
|
|
|
|
|
|
|
$arity{substr $gname, 0, 1}, |
387
|
|
|
|
|
|
|
0, |
388
|
|
|
|
|
|
|
1, |
389
|
1820
|
100
|
|
|
|
5054
|
exists($is_ar{$name})? $is_ar{$name}: () |
390
|
|
|
|
|
|
|
] |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
@named_ops |
393
|
|
|
|
|
|
|
), |
394
|
|
|
|
|
|
|
[mpx => 4, 0, 1], |
395
|
|
|
|
|
|
|
); |
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
# ----- object methods ----- |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
sub Mpx { |
401
|
341
|
100
|
|
341
|
1
|
755
|
if (@_ < 4) { |
402
|
2
|
|
|
|
|
7
|
my $missing = 4 - @_; |
403
|
2
|
|
|
|
|
215
|
croak "too few arguments, expected $missing more"; |
404
|
|
|
|
|
|
|
} |
405
|
339
|
|
|
|
|
564
|
my ($this, $case_n, $case_t, $case_f) = @_; |
406
|
339
|
|
|
|
|
584
|
return ($case_n, $case_t, $case_f)[$this->res_mod3]; |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
109
|
|
|
109
|
1
|
1448
|
sub mpx { $trits[shift->Mpx(@_)->res_mod3] } |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
sub generic { |
412
|
567
|
|
|
567
|
1
|
2183
|
my ($this, $method, @params) = @_; |
413
|
567
|
|
|
|
|
1126
|
return _generic($method)->($this, @params); |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
|
416
|
44780
|
|
|
44780
|
1
|
153037
|
sub is_nil { $_[0]->[_IS_NIL] } |
417
|
966
|
|
|
966
|
1
|
3649
|
sub is_true { $_[0]->[_IS_TRUE] } |
418
|
471
|
|
|
471
|
1
|
1391
|
sub is_false { $_[0]->[_IS_FALSE] } |
419
|
8748
|
|
|
8748
|
1
|
28130
|
sub as_bool { $_[0]->[_BOOL] } |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
sub as_modint { |
422
|
2
|
|
|
2
|
1
|
5
|
my ($this) = @_; |
423
|
2
|
|
|
|
|
3
|
my $mi = $this->[_MODINT]; |
424
|
2
|
100
|
|
|
|
7
|
if (!defined $mi) { |
425
|
1
|
50
|
|
|
|
2
|
eval { require Math::ModInt } |
|
1
|
|
|
|
|
9
|
|
426
|
|
|
|
|
|
|
or croak 'perl extension Math::ModInt is not available'; |
427
|
1
|
|
|
|
|
6
|
$mi = $this->[_MODINT] = Math::ModInt->new($this->[_UINT], 3); |
428
|
|
|
|
|
|
|
} |
429
|
2
|
|
|
|
|
54
|
return $mi; |
430
|
|
|
|
|
|
|
} |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
# role: ternary object |
433
|
|
|
|
|
|
|
|
434
|
14
|
100
|
|
14
|
1
|
490
|
sub is_equal { $_[1]->Rtrits <= 1 && $_[0]->as_int == $_[1]->Trit(0)->as_int } |
435
|
30
|
100
|
|
30
|
1
|
164
|
sub Rtrits { $_[0]->[_IS_NIL]? (wantarray? (): 0): (wantarray? $_[0]: 1) } |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
436
|
|
|
|
|
|
|
|
437
|
11
|
|
|
11
|
1
|
876
|
sub Sign { $_[0] } |
438
|
23
|
100
|
|
23
|
1
|
100
|
sub Trit { ($_[0])[$_[1]] || $nil } |
439
|
204
|
100
|
|
204
|
1
|
514
|
sub Trits { wantarray? $_[0]: 1 } |
440
|
25208
|
|
|
25208
|
1
|
96519
|
sub as_int { $_[0]->[_INT] } |
441
|
19043
|
|
|
19043
|
1
|
113599
|
sub as_int_u { $_[0]->[_UINT] } |
442
|
30
|
|
|
30
|
1
|
80
|
sub as_int_v { $_[0]->[_UINT] } |
443
|
113628
|
|
|
113628
|
1
|
191237
|
sub res_mod3 { $_[0]->[_UINT] } |
444
|
3
|
|
|
3
|
1
|
13
|
sub as_string { $_[0]->[_PNAME] } |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
1; |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
__END__ |