| 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__ |