line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# |
2
|
|
|
|
|
|
|
# CayleyDickson.pm - Cayley-Dickson constructions and algebriac manipulations |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# author: Jeffrey B Anderson - truejeffanderson at gmail.com |
5
|
|
|
|
|
|
|
# |
6
|
|
|
|
|
|
|
# reference: https://en.wikipedia.org/wiki/Cayley-Dickson_construction |
7
|
|
|
|
|
|
|
# |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
package CayleyDickson; |
11
|
5
|
|
|
5
|
|
272432
|
use strict; |
|
5
|
|
|
|
|
41
|
|
|
5
|
|
|
|
|
119
|
|
12
|
5
|
|
|
5
|
|
21
|
no warnings; |
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
161
|
|
13
|
5
|
|
|
5
|
|
4913
|
use overload qw(- subtract + add * multiply / divide "" as_string eq eq); |
|
5
|
|
|
|
|
4403
|
|
|
5
|
|
|
|
|
27
|
|
14
|
5
|
|
|
5
|
|
899
|
use constant SYMBOLS => ['', 'i' .. 'z', map('a' . $_, ('a' .. 'z')), ( map('b' . $_, ('a' .. 'z')) ) x 100]; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
3054
|
|
15
|
|
|
|
|
|
|
our $VERSION = 0.04; |
16
|
|
|
|
|
|
|
|
17
|
5
|
|
|
5
|
|
31
|
use constant DEBUG => 0; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
185
|
|
18
|
5
|
|
|
5
|
|
23
|
use constant VERBOSE => 0; |
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
288
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# |
21
|
|
|
|
|
|
|
# DOUBLING_PRODUCT: multiplication rules for (a,b)×(c,d) |
22
|
|
|
|
|
|
|
# |
23
|
|
|
|
|
|
|
# valid string options... |
24
|
|
|
|
|
|
|
# |
25
|
|
|
|
|
|
|
# P0 => ( c×a - B×d , d×A + b×c ) |
26
|
|
|
|
|
|
|
# P1 => ( c×a - d×B , A×d + c×b ) |
27
|
|
|
|
|
|
|
# P2 => ( a×c - B×d , d×A + b×c ) |
28
|
|
|
|
|
|
|
# P3 => ( a×c - d×B , A×d + c×b ) |
29
|
|
|
|
|
|
|
# Pt0 => ( c×a - b×D , a×d + C×b ) |
30
|
|
|
|
|
|
|
# Pt1 => ( c×a - D×b , d×a + b×C ) |
31
|
|
|
|
|
|
|
# Pt2 => ( a×c - b×D , a×d + C×b ) |
32
|
|
|
|
|
|
|
# Pt3 => ( a×c - D×b , d×a + b×C ) |
33
|
|
|
|
|
|
|
# |
34
|
|
|
|
|
|
|
# ...where lower case is the value and upper case is the conjugate. |
35
|
|
|
|
|
|
|
# |
36
|
|
|
|
|
|
|
# ref: http://jwbales.us/cdproducts.html |
37
|
|
|
|
|
|
|
# |
38
|
|
|
|
|
|
|
#use constant DOUBLING_PRODUCT => 'P3'; |
39
|
5
|
|
|
5
|
|
29
|
use constant DOUBLING_PRODUCT => 'Pt3'; |
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
216
|
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
# |
44
|
|
|
|
|
|
|
# I_SQUARED is the square of the first imaginary unit i. |
45
|
|
|
|
|
|
|
# valid number options: |
46
|
|
|
|
|
|
|
# |
47
|
|
|
|
|
|
|
# 1 => Split numbers |
48
|
|
|
|
|
|
|
# 0 => Dual numbers |
49
|
|
|
|
|
|
|
# -1 => Cayley-Dickson numbers # default/tested |
50
|
|
|
|
|
|
|
# |
51
|
|
|
|
|
|
|
|
52
|
5
|
|
|
5
|
|
23
|
use constant I_SQUARED => -1; |
|
5
|
|
|
|
|
7
|
|
|
5
|
|
|
|
|
7750
|
|
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# |
57
|
|
|
|
|
|
|
# Conjugate: z* = (a,b)* = (a*,-b) |
58
|
|
|
|
|
|
|
# |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub conjugate { |
61
|
1137208
|
|
|
1137208
|
1
|
1213686
|
my $m = shift; |
62
|
|
|
|
|
|
|
|
63
|
1137208
|
100
|
|
|
|
1315038
|
my $a_conjugate = $m->is_complex ? $m->a : $m->a->conjugate; |
64
|
1137208
|
|
|
|
|
1506399
|
my $negative_b = -$m->b; |
65
|
|
|
|
|
|
|
|
66
|
1137208
|
|
|
|
|
1729567
|
(ref $m)->new($a_conjugate, $negative_b) |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# |
72
|
|
|
|
|
|
|
# Invert: 1/z = z⁻¹ = (a,b)⁻¹ = (a,b)*/(norm(a,b)²) |
73
|
|
|
|
|
|
|
# |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub inverse { |
76
|
0
|
|
|
0
|
1
|
0
|
my $m = shift; |
77
|
|
|
|
|
|
|
|
78
|
0
|
|
|
|
|
0
|
my $conjugate = $m->conjugate; |
79
|
0
|
|
|
|
|
0
|
my $norm = $m->norm; |
80
|
0
|
|
|
|
|
0
|
$conjugate / ($norm ** 2) |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# |
86
|
|
|
|
|
|
|
# Norm: z->norm = √(norm(a)²+norm(b)²) and norm(number) = number |
87
|
|
|
|
|
|
|
# |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub norm { |
90
|
302628
|
|
|
302628
|
1
|
504596
|
my $m = shift; |
91
|
|
|
|
|
|
|
|
92
|
302628
|
100
|
|
|
|
371845
|
my $a = $m->is_complex ? $m->a : $m->a->norm; |
93
|
302628
|
100
|
|
|
|
414575
|
my $b = $m->is_complex ? $m->b : $m->b->norm; |
94
|
|
|
|
|
|
|
|
95
|
302628
|
|
|
|
|
650275
|
sqrt($a ** 2 + $b ** 2) |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# |
101
|
|
|
|
|
|
|
# Addition: z1+z2 = (a,b)+(c,d) = (a+c,b+d) |
102
|
|
|
|
|
|
|
# |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
sub add { |
105
|
751287
|
|
|
751287
|
1
|
973182
|
my ( $m, $o ) = @_; |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
|
108
|
751287
|
|
|
|
|
923079
|
my $a = $m->a; |
109
|
751287
|
|
|
|
|
990332
|
my $b = $m->b; |
110
|
751287
|
|
|
|
|
928885
|
my $c = $o->a; |
111
|
751287
|
|
|
|
|
906457
|
my $d = $o->b; |
112
|
|
|
|
|
|
|
|
113
|
751287
|
|
|
|
|
1277712
|
my $sum = (ref $m)->new($a + $c, $b + $d); |
114
|
751287
|
|
|
|
|
862328
|
printf("Add: (%s) + (%s) = (%s)\n", $m, $o, $sum) if DEBUG; |
115
|
751287
|
|
|
|
|
1224006
|
$sum |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# |
121
|
|
|
|
|
|
|
# Subtraction: (a,b)-(c,d) = (a-c,b-d) |
122
|
|
|
|
|
|
|
# |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
sub subtract { |
125
|
326055
|
|
|
326055
|
1
|
616326
|
my ( $m, $o, $swap ) = @_; |
126
|
|
|
|
|
|
|
|
127
|
326055
|
100
|
|
|
|
619993
|
$o = (ref $m)->new((my $v = $o), 0) unless ref $o; |
128
|
|
|
|
|
|
|
|
129
|
326055
|
100
|
|
|
|
542312
|
my $a = $swap ? $o->a : $m->a; |
130
|
326055
|
100
|
|
|
|
474312
|
my $b = $swap ? $o->b : $m->b; |
131
|
326055
|
100
|
|
|
|
457754
|
my $c = $swap ? $m->a : $o->a; |
132
|
326055
|
100
|
|
|
|
459848
|
my $d = $swap ? $m->b : $o->b; |
133
|
|
|
|
|
|
|
|
134
|
326055
|
|
|
|
|
598464
|
my $difference = (ref $m)->new($a - $c, $b - $d); |
135
|
326055
|
|
|
|
|
383264
|
printf("Sub: (%s) - (%s) = (%s)\n", ($swap ? ($o, $m) : ($m, $o)), $difference) if DEBUG; |
136
|
326055
|
|
|
|
|
559784
|
$difference |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# |
142
|
|
|
|
|
|
|
# Divide: z1/z2 = (a,b) × (c,d)⁻¹ = (a,b) × inverse(c,d) |
143
|
|
|
|
|
|
|
# |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub divide { |
146
|
80080
|
|
|
80080
|
1
|
119426
|
my ( $m, $o, $swap ) = @_; |
147
|
|
|
|
|
|
|
|
148
|
80080
|
|
|
|
|
85999
|
my ( $a, $b ); |
149
|
80080
|
50
|
|
|
|
103441
|
$a = $swap ? $m->inverse : $m; |
150
|
80080
|
50
|
|
|
|
123783
|
$b = $swap ? $o : (ref $o ? $o->inverse : 1 / $o); |
|
|
50
|
|
|
|
|
|
151
|
|
|
|
|
|
|
|
152
|
80080
|
50
|
|
|
|
124298
|
$swap ? $a * $b : $b * $a |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# |
158
|
|
|
|
|
|
|
# Multiply: (a,b)×(c,d) = (a×c - d*×b, d×a + b×c*) where x* = conjugate(x) or x if x is a number |
159
|
|
|
|
|
|
|
# |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub multiply { |
162
|
1811732
|
|
|
1811732
|
1
|
2908127
|
my ( $m, $o, $swap ) = @_; |
163
|
|
|
|
|
|
|
|
164
|
1811732
|
|
|
|
|
1750300
|
printf "Mult: (%s) x (%s)\n", ($swap ? ($o, $m) : ($m, $o)) if DEBUG; |
165
|
|
|
|
|
|
|
|
166
|
1811732
|
|
|
|
|
2093585
|
my ( $ii, $a, $as, $b, $bs, $c, $cs, $d, $ds ); |
167
|
|
|
|
|
|
|
|
168
|
1811732
|
|
|
|
|
2257885
|
$ii = $m->i_squared; |
169
|
1811732
|
|
|
|
|
2311533
|
$a = $m->a; |
170
|
1811732
|
|
|
|
|
2252415
|
$b = $m->b; |
171
|
1811732
|
100
|
|
|
|
2240184
|
if ($m->is_complex) { |
172
|
1533048
|
|
|
|
|
1653386
|
$as = $a; |
173
|
1533048
|
|
|
|
|
1565325
|
$bs = $b; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
else { |
176
|
278684
|
|
|
|
|
370023
|
$as = $m->a->conjugate; |
177
|
278684
|
|
|
|
|
398184
|
$bs = $m->b->conjugate; |
178
|
|
|
|
|
|
|
} |
179
|
1811732
|
100
|
|
|
|
2598803
|
if (ref $o) { |
180
|
1234040
|
|
|
|
|
1516238
|
$c = $o->a; |
181
|
1234040
|
|
|
|
|
1542489
|
$d = $o->b; |
182
|
1234040
|
100
|
|
|
|
1511258
|
if ($o->is_complex) { |
183
|
1028332
|
|
|
|
|
1076890
|
$cs = $c; |
184
|
1028332
|
|
|
|
|
1036666
|
$ds = $d; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
else { |
187
|
205708
|
|
|
|
|
273151
|
$cs = $o->a->conjugate; |
188
|
205708
|
|
|
|
|
293965
|
$ds = $o->b->conjugate; |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
else { |
192
|
577692
|
|
|
|
|
583074
|
$c = $o; |
193
|
577692
|
|
|
|
|
570415
|
$cs = $o; |
194
|
577692
|
|
|
|
|
589014
|
$d = 0; |
195
|
577692
|
|
|
|
|
568598
|
$ds = 0; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
1811732
|
|
|
|
|
1951875
|
my $p; |
199
|
1811732
|
|
|
|
|
2238112
|
my $dp = $m->doubling_product; |
200
|
|
|
|
|
|
|
|
201
|
1811732
|
50
|
|
|
|
5433201
|
if ($dp eq 'P0' ) { $p = (ref $m)->new($c * $a + $ii * $bs * $d , $d * $as + $b * $c ) } |
|
0
|
50
|
|
|
|
0
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
202
|
0
|
|
|
|
|
0
|
elsif ($dp eq 'P1' ) { $p = (ref $m)->new($c * $a + $ii * $d * $bs, $as * $d + $c * $b ) } |
203
|
0
|
|
|
|
|
0
|
elsif ($dp eq 'P2' ) { $p = (ref $m)->new($a * $c + $ii * $bs * $d , $d * $as + $b * $c ) } # <= special twist pattern? |
204
|
0
|
|
|
|
|
0
|
elsif ($dp eq 'P3' ) { $p = (ref $m)->new($a * $c + $ii * $d * $bs, $as * $d + $c * $b ) } |
205
|
0
|
|
|
|
|
0
|
elsif ($dp eq 'Pt0') { $p = (ref $m)->new($c * $a + $ii * $b * $ds, $a * $d + $cs * $b ) } # <= default |
206
|
0
|
|
|
|
|
0
|
elsif ($dp eq 'Pt1') { $p = (ref $m)->new($c * $a + $ii * $ds * $b , $d * $a + $b * $cs) } |
207
|
0
|
|
|
|
|
0
|
elsif ($dp eq 'Pt2') { $p = (ref $m)->new($a * $c + $ii * $b * $ds, $a * $d + $cs * $b ) } |
208
|
1811732
|
|
|
|
|
3768326
|
elsif ($dp eq 'Pt3') { $p = (ref $m)->new($a * $c + $ii * $ds * $b , $d * $a + $b * $cs) } # <= default for REAL? |
209
|
|
|
|
|
|
|
|
210
|
1811732
|
|
|
|
|
2328037
|
printf("Calculated: (%s) x (%s) = (%s)\n", ($swap ? ($o, $m) : ($m, $o)), $p) if DEBUG; |
211
|
1811732
|
|
|
|
|
3403006
|
$p |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
# |
217
|
|
|
|
|
|
|
# Tensor: $a->tensor($b) = A⊗ B = (a,b)⊗ (c,d) = (ac,ad,bc,bd) |
218
|
|
|
|
|
|
|
# |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
sub tensor { |
221
|
0
|
|
|
0
|
1
|
0
|
my ( $m, $o ) = @_; |
222
|
|
|
|
|
|
|
|
223
|
0
|
|
|
|
|
0
|
my @pair; |
224
|
0
|
0
|
|
|
|
0
|
if ($m->is_complex) { |
225
|
0
|
|
|
|
|
0
|
@pair = ($m->a * $o, $m->b * $o) |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
else { |
228
|
0
|
|
|
|
|
0
|
@pair = ($m->a->tensor($o), $m->b->tensor($o)) |
229
|
|
|
|
|
|
|
} |
230
|
0
|
|
|
|
|
0
|
(ref $m)->new(@pair) |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
# |
236
|
|
|
|
|
|
|
# Creates a new CayleyDickson object |
237
|
|
|
|
|
|
|
# expects a list of two (powers of 2) numbers or objects ... |
238
|
|
|
|
|
|
|
# |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
sub new { |
241
|
4373872
|
|
|
4373872
|
1
|
5255443
|
my $class = shift; |
242
|
4373872
|
|
|
|
|
5834116
|
my @values = @_; |
243
|
4373872
|
|
|
|
|
4754080
|
my $elements = scalar @values; |
244
|
4373872
|
|
|
|
|
4465294
|
my @pair; |
245
|
4373872
|
100
|
|
|
|
5454187
|
if ($elements > 2) { |
246
|
26900
|
|
|
|
|
58081
|
@pair = ( ($class->new( @values[0 .. $elements/2 - 1] )) , |
247
|
|
|
|
|
|
|
($class->new( @values[$elements/2 .. $elements - 1] )) ) |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
else { |
250
|
4346972
|
|
|
|
|
5402347
|
@pair = ( $values[0] , |
251
|
|
|
|
|
|
|
$values[1] ) |
252
|
|
|
|
|
|
|
} |
253
|
4373872
|
|
|
|
|
5600653
|
bless [ $class->prepare(@pair) ] => $class; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# |
259
|
|
|
|
|
|
|
# allows subclassing to modify the object pair just prior to creating the object. |
260
|
|
|
|
|
|
|
# |
261
|
|
|
|
|
|
|
|
262
|
4373872
|
|
|
4373872
|
0
|
4356036
|
sub prepare { shift; @_ } |
|
4373872
|
|
|
|
|
8858631
|
|
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
# |
267
|
|
|
|
|
|
|
# hold the left number/object in a and the right number/object in b. |
268
|
|
|
|
|
|
|
# |
269
|
|
|
|
|
|
|
|
270
|
11920124
|
|
|
11920124
|
1
|
11380750
|
sub a { ${(shift)}[0] } |
|
11920124
|
|
|
|
|
17892288
|
|
271
|
7128286
|
|
|
7128286
|
1
|
6870719
|
sub b { ${(shift)}[1] } |
|
7128286
|
|
|
|
|
8871453
|
|
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
# |
276
|
|
|
|
|
|
|
# flat: list of the scalar values pointed to by a,b references in the object references in order ... |
277
|
|
|
|
|
|
|
# |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
sub flat { |
280
|
3602
|
|
|
3602
|
1
|
3740
|
my $m = shift; |
281
|
3602
|
100
|
|
|
|
4134
|
$m->is_complex ? ($m->a, $m->b) : ($m->a->flat, $m->b->flat) |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
# |
286
|
|
|
|
|
|
|
# print the beautiful objects in terse human format ... |
287
|
|
|
|
|
|
|
# |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
sub as_string { |
290
|
372
|
|
|
372
|
1
|
590
|
my $m = shift; |
291
|
|
|
|
|
|
|
|
292
|
372
|
|
|
|
|
484
|
my $string = ''; |
293
|
372
|
|
|
|
|
416
|
my $i = 0; |
294
|
|
|
|
|
|
|
|
295
|
372
|
|
|
|
|
606
|
my @flat = $m->flat; |
296
|
372
|
|
|
|
|
683
|
foreach my $t (@flat) { |
297
|
3974
|
100
|
|
|
|
5159
|
if ($t) { |
298
|
2711
|
|
|
|
|
3680
|
my ($sign, $value, $unit) = ('','',''); |
299
|
2711
|
100
|
|
|
|
4570
|
if ($t < 0) { |
|
|
100
|
|
|
|
|
|
300
|
689
|
|
|
|
|
760
|
$sign = '-'; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
elsif (length $string) { |
303
|
1775
|
|
|
|
|
1952
|
$sign = '+'; |
304
|
|
|
|
|
|
|
} |
305
|
2711
|
100
|
100
|
|
|
4857
|
unless (abs($t) == 1 and $i) { |
306
|
|
|
|
|
|
|
#if (abs($t) !=1 or not $i) { |
307
|
2609
|
|
|
|
|
2904
|
$value = abs($t); |
308
|
|
|
|
|
|
|
} |
309
|
2711
|
|
|
|
|
2666
|
$unit = ${ SYMBOLS() }[$i]; |
|
2711
|
|
|
|
|
3855
|
|
310
|
2711
|
|
|
|
|
8048
|
$string .= sprintf '%s%s%s', $sign, $value, $unit; |
311
|
|
|
|
|
|
|
} |
312
|
3974
|
|
|
|
|
4832
|
$i ++ |
313
|
|
|
|
|
|
|
} |
314
|
372
|
50
|
|
|
|
4137
|
$string || '0'; |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
sub as_polarity { |
318
|
0
|
|
|
0
|
0
|
0
|
my $m = shift; |
319
|
0
|
|
|
|
|
0
|
my $string = ''; |
320
|
0
|
|
|
|
|
0
|
foreach my $t ($m->flat) { |
321
|
0
|
0
|
|
|
|
0
|
$string .= $t > 0 ? '+' : ($t < 0 ? '-' : '0'); |
|
|
0
|
|
|
|
|
|
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
$string |
324
|
0
|
|
|
|
|
0
|
} |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
sub as_e { |
328
|
0
|
|
|
0
|
0
|
0
|
my $m = shift; |
329
|
|
|
|
|
|
|
|
330
|
0
|
|
|
|
|
0
|
my $string = ''; |
331
|
0
|
|
|
|
|
0
|
my $i = 0; |
332
|
|
|
|
|
|
|
|
333
|
0
|
|
|
|
|
0
|
foreach my $t ($m->flat) { |
334
|
0
|
0
|
|
|
|
0
|
if ($t) { |
335
|
0
|
|
|
|
|
0
|
my ($sign, $value, $unit) = ('+','',''); |
336
|
0
|
0
|
|
|
|
0
|
if ($t < 0) { |
|
|
0
|
|
|
|
|
|
337
|
0
|
|
|
|
|
0
|
$sign = '-'; |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
elsif (length $string) { |
340
|
0
|
|
|
|
|
0
|
$sign = '+'; |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
#if (abs($t) != 1 or $i == 0) { |
343
|
0
|
0
|
|
|
|
0
|
if (abs($t)) { |
344
|
0
|
|
|
|
|
0
|
$value = abs($t); |
345
|
|
|
|
|
|
|
} |
346
|
0
|
|
|
|
|
0
|
$unit = 'e' . $i; |
347
|
0
|
|
|
|
|
0
|
$string .= sprintf '%s%s%s', $sign, $value, $unit; |
348
|
|
|
|
|
|
|
#$string .= sprintf '%s%s%s', $sign, '', ''; |
349
|
|
|
|
|
|
|
} |
350
|
0
|
|
|
|
|
0
|
$i ++ |
351
|
|
|
|
|
|
|
} |
352
|
0
|
0
|
|
|
|
0
|
$string || '0' |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
# |
358
|
|
|
|
|
|
|
# compare the string format of this object to the given string |
359
|
|
|
|
|
|
|
# |
360
|
|
|
|
|
|
|
|
361
|
0
|
|
|
0
|
0
|
0
|
sub eq { shift->as_string eq shift } |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
# |
366
|
|
|
|
|
|
|
# override these methods to test other algebras or the dual and split number systems ... |
367
|
|
|
|
|
|
|
# |
368
|
|
|
|
|
|
|
# doubling_product:See DOUBLING constant above for option choices. Override this method in your subclass if you like. |
369
|
|
|
|
|
|
|
# |
370
|
|
|
|
|
|
|
# i_squared: algebra selection. See I_SQUARED constant above for option choices. Override this method in your subclass if you like. |
371
|
|
|
|
|
|
|
# |
372
|
|
|
|
|
|
|
|
373
|
1811732
|
|
|
1811732
|
1
|
2253107
|
sub doubling_product { DOUBLING_PRODUCT } |
374
|
1811732
|
|
|
1811732
|
1
|
2047837
|
sub i_squared { I_SQUARED } |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
# |
379
|
|
|
|
|
|
|
# additional meta tools ... |
380
|
|
|
|
|
|
|
# |
381
|
|
|
|
|
|
|
|
382
|
0
|
|
|
0
|
0
|
0
|
sub is_real { 0 } # you could not be here if you are real |
383
|
4791838
|
|
|
4791838
|
1
|
5691972
|
sub is_complex { not ref (shift->a) } |
384
|
0
|
|
|
0
|
1
|
|
sub is_quaternion { shift->_child_is('is_complex' ) } |
385
|
0
|
|
|
0
|
1
|
|
sub is_octonion { shift->_child_is('is_quaternion' ) } |
386
|
0
|
|
|
0
|
1
|
|
sub is_sedenion { shift->_child_is('is_octonion' ) } |
387
|
0
|
|
|
0
|
1
|
|
sub is_trigintaduonions { shift->_child_is('is_sedenion' ) } |
388
|
0
|
|
|
0
|
1
|
|
sub is_sexagintaquatronions { shift->_child_is('is_trigintaduonions' ) } |
389
|
0
|
|
|
0
|
1
|
|
sub is_centumduodetrigintanions { shift->_child_is('is_sexagintaquatronions' ) } |
390
|
0
|
|
|
0
|
1
|
|
sub is_ducentiquinquagintasexions { shift->_child_is('is_centumduodetrigintanions' ) } |
391
|
|
|
|
|
|
|
#sub is_etc ... |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
# |
395
|
|
|
|
|
|
|
# determine if the child is of the given type by common cayley dickson name ... |
396
|
|
|
|
|
|
|
# |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
sub _child_is { |
399
|
0
|
|
|
0
|
|
|
my $m = shift; |
400
|
0
|
|
|
|
|
|
my $method = shift; |
401
|
0
|
0
|
0
|
|
|
|
not $m->is_complex and $m->a->can($method) and $m->a->$method; |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
=encoding utf8 |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
=pod |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
=head1 NAME |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
CayleyDickson - create and operate with hypercomplex numbers |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
=head1 SYNOPSIS |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
=over 4 |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
use Tangle; |
417
|
|
|
|
|
|
|
my $q1 = Tangle->new(1,0); |
418
|
|
|
|
|
|
|
print "q1 = $q1\n"; |
419
|
|
|
|
|
|
|
$q1->x_gate; |
420
|
|
|
|
|
|
|
print "X(q1) = $q1\n"; |
421
|
|
|
|
|
|
|
$q1->hadamard; |
422
|
|
|
|
|
|
|
print "H(X(q1)) = $q1\n"; |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
my $q2 = Tangle->new(1,0); |
425
|
|
|
|
|
|
|
print "q2 = $q2\n"; |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
# perform CNOT($q1 ⊗ $q2) |
428
|
|
|
|
|
|
|
$q1->cnot($q2); |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
print "q1 = $q1\n"; |
431
|
|
|
|
|
|
|
print "q2 = $q2\n"; |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
$q1->x_gate; |
434
|
|
|
|
|
|
|
print "X(q1) = $q1\n"; |
435
|
|
|
|
|
|
|
print "entanglement causes q2 to automatically changed: $q2\n"; |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
=back |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
=head1 DESCRIPTION |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
=over 3 |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
Cayley-Dickson construction and operations are defined here: https://en.wikipedia.org/wiki/Cayley–Dickson_construction |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
This object provides natural and intuitive operations on these numbers by overriding the native numeric operations (+,-,/,*) |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
=back |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=head1 USAGE |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
=head2 new() |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
=over 3 |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
# create a new CayleyDickson number "i" ... |
457
|
|
|
|
|
|
|
my $q1 = CayleyDickson->new(0,1); |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
# create a new CayleyDickson number "1+2i+3j+4k" ... |
461
|
|
|
|
|
|
|
my $q2 = CayleyDickson->new(1,2,3,4); |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
# create a bigger CayleyDickson number (a Sedenion) ... |
465
|
|
|
|
|
|
|
my $q3 = CayleyDickson->new(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16); |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
# create a CayleyDickson number from others ... |
469
|
|
|
|
|
|
|
my $one = CayleyDickson->new(0,1); |
470
|
|
|
|
|
|
|
my $zero = CayleyDickson->new(1,0); |
471
|
|
|
|
|
|
|
my $quaternion = CayleyDickson->new($one,$zero); |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
=back |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
=head2 conjugate() |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
=over 3 |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
if z = (a,b) |
480
|
|
|
|
|
|
|
then conjugate z = z* = (a,b)* = (a*,-b) |
481
|
|
|
|
|
|
|
or conjugate(number) = number |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
printf "The conjugate of q1 is: %s\n", $q1->conjugate; |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
=back |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
=head2 inverse() |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
=over 3 |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
if z = (a,b) |
492
|
|
|
|
|
|
|
then inverse z = z⁻¹ = (a,b)⁻¹ = (a,b)*/(norm(a,b)²) |
493
|
|
|
|
|
|
|
or inverse(number) = number |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
printf "The inverse of q1 is: %s\n", $q1->inverse; |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
=back |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
=head2 norm() |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
=over 3 |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
if z = (a,b) |
504
|
|
|
|
|
|
|
then norm z = norm(a,b) = √(norm(a)²+norm(b)²) |
505
|
|
|
|
|
|
|
or norm(number) = number |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
printf "The norm of q1 is: %s\n", $q1->norm; |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
=back |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
=head2 add() |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
=over 3 |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
# ass z1 + z2 = (a,b)+(c,d) = (a+c,b+d) |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
printf "The sum of q1 + q2 is: %s\n", $q1 + $q2; |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
=back |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
=head2 subtract() |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=over 3 |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
# subtract z1 - z2 = (a,b)-(c,d) = (a-c,b-d) |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
printf "The difference of q1 - q2 is: %s\n", $q1 - $q2; |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
=back |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
=head2 divide() |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
=over 3 |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
# divide z1 / z2 = z1 × inverse(z2) |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
printf "The division of q1 / q2 is: %s\n", $q1 / $q2; |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=back |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
=head2 multiply() |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
=over 3 |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
# Multiply: (a,b)×(c,d) = (a×c - d*×b, d×a + b×c*) where x* = conjugate(x) or x if x is a number |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
printf "The product of q1 * q2 is: %s\n", $q1 * $q2; |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
=back |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
=head2 new() |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
=over 3 |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
create a new CayleyDickson number of any size ... |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
# create the number 1+j-k ... |
558
|
|
|
|
|
|
|
my $c = CayleyDickson->new( -1, 0, 1, -1 ); |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
# create an octonion ... |
561
|
|
|
|
|
|
|
my $c = CayleyDickson->new( 3, 7, -2, 8, 0, 3, 3, 5 ); |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
# create a representation of the Horne bell state |+-> ... |
564
|
|
|
|
|
|
|
my $c = CayleyDickson->new( 1/2, 1/2, 1/2 ,-1/2 ); |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
# create a 128 number construction: 1+2i+3j+4k+ .. + 128 .... |
567
|
|
|
|
|
|
|
my $c = CayleyDickson->new(1 .. 128); |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
=back |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
=head2 tensor() |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
=over 3 |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
Tensors two Cayley Dickson numbers to calculate a new number of higher dimensional construction. |
576
|
|
|
|
|
|
|
reference: https://en.wikipedia.org/wiki/Tensor_product |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
# calculate the tensor of c1 ⊗ c2 ... |
579
|
|
|
|
|
|
|
$d = $c1->tensor($c2); |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
$d will be a number of the product of the dimensions of c1 and c2. |
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
=back |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
=head2 a() |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
=head2 b() |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
=over 3 |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
returns the two objects or numbers held by this object |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
=back |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
=head2 flat() |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
=over 3 |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
return all the coefficients of the number as an array |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
printf "[%s]\n", join( ', ', $q1->flat); |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
=back |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
=head2 as_string() |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
=over 3 |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
called automatically when this object is requested in a string form. |
611
|
|
|
|
|
|
|
if you want to force the object to be resolved as a string ... |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
printf "q1 as a string = %s\n", $q1->as_string; |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
=back |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
=head2 i_squared() |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
=over 3 |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
returns the square of i: i² = -1 |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
normally this will be -1, but you can change it to +1 or 0 using the constant I_SQUARED |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
=back |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
=head2 doubling_product() |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
=over 3 |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
something |
634
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
=back |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
=head2 is_complex() |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
=head2 is_quaternion() |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
=head2 is_octonion() |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
=head2 is_sedenion() |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
=head2 is_trigintaduonions() |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
=head2 is_sexagintaquatronions() |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
=head2 is_centumduodetrigintanions() |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
=head2 is_ducentiquinquagintasexions() |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
returns true if the given object has depth equal to the function name |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
if ($q1->is_octionion) { |
656
|
|
|
|
|
|
|
print "q1 is an Octonion\n"; |
657
|
|
|
|
|
|
|
} |
658
|
|
|
|
|
|
|
else { |
659
|
|
|
|
|
|
|
print "q1 is NOT an Octonion\n"; |
660
|
|
|
|
|
|
|
} |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
=back |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
=head1 SUMMARY |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
=over 3 |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
This object holds Cayley Dickson numbers and provides math operations on them. |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
=back |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
=head1 AUTHOR |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
Jeff Anderson |
675
|
|
|
|
|
|
|
truejeffanderson@gmail.com |
676
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
=cut |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
1; |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
__END__ |