Skip to content

Commit 95e6c8c

Browse files
committed
Wrote pow and zero divisor examples.
1 parent 737fb63 commit 95e6c8c

File tree

3 files changed

+87
-25
lines changed

3 files changed

+87
-25
lines changed

README.md

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ The names and letter-abbreviations were taken from [this image][3] ([mirror][4])
9595

9696
## Usage Examples
9797

98-
This list follows [example.py](example.py) exactly and documents nearly all the things you can do with the hypercomplex numbers created by this package.
98+
This list follows [examples.py](examples.py) exactly and documents nearly all the things you can do with the hypercomplex numbers created by this package.
9999

100100
Every example assumes the appropriate imports are already done, e.g. `from hypercomplex import *`.
101101

@@ -137,31 +137,42 @@ Every example assumes the appropriate imports are already done, e.g. `from hyper
137137
print(R(2).inverse(), 1 / R(2)) # -> (0.5) (0.5)
138138
```
139139

140-
5. `conjugate` gives the conjugate of the number.
140+
5. Numbers can be raised to integer powers, a shortcut for repeated multiplication or division.
141+
142+
```py
143+
q = Q(0, 3, 4, 0)
144+
print(q**5) # -> (0 1875 2500 0)
145+
print(q * q * q * q * q) # -> (0 1875 2500 0)
146+
print(q**-1) # -> (0 -0.12 -0.16 0)
147+
print(1 / q) # -> (0 -0.12 -0.16 0)
148+
print(q**0) # -> (1 0 0 0)
149+
```
150+
151+
6. `conjugate` gives the conjugate of the number.
141152

142153
```py
143154
print(R(9).conjugate()) # -> (9)
144155
print(C(9, 8).conjugate()) # -> (9 -8)
145156
print(Q(9, 8, 7, 6).conjugate()) # -> (9 -8 -7 -6)
146157
```
147158

148-
6. `norm` gives the absolute value as the base type (`float` by default). There is also `norm_squared`.
159+
7. `norm` gives the absolute value as the base type (`float` by default). There is also `norm_squared`.
149160

150161
```py
151162
print(O(3, 4).norm(), type(O(3, 4).norm())) # -> 5.0 <class 'float'>
152163
print(abs(O(3, 4))) # -> 5.0
153164
print(O(3, 4).norm_squared()) # -> 25.0
154165
```
155166

156-
7. Numbers are considered equal if their coefficients all match. Non-existent coefficients are 0.
167+
8. Numbers are considered equal if their coefficients all match. Non-existent coefficients are 0.
157168

158169
```py
159170
print(R(999) == V(999)) # -> True
160171
print(C(1, 2) == Q(1, 2)) # -> True
161172
print(C(1, 2) == Q(1, 2, 0.1)) # -> False
162173
```
163174

164-
8. `coefficients` gives a tuple of the components of the number in their base type (`float` by default). The properties `real` and `imag` are shortcuts for the first two components. Indexing can also be used (but is inefficient).
175+
9. `coefficients` gives a tuple of the components of the number in their base type (`float` by default). The properties `real` and `imag` are shortcuts for the first two components. Indexing can also be used (but is inefficient).
165176

166177
```py
167178
print(R(100).coefficients()) # -> (100.0,)
@@ -171,15 +182,15 @@ Every example assumes the appropriate imports are already done, e.g. `from hyper
171182
print(q[0], q[1], q[2], q[3]) # -> 2.0 3.0 4.0 5.0
172183
```
173184

174-
9. `e(index)` of a number class gives the unit hypercomplex number where the index coefficient is 1 and all others are 0.
185+
10. `e(index)` of a number class gives the unit hypercomplex number where the index coefficient is 1 and all others are 0.
175186

176187
```py
177188
print(C.e(0)) # -> (1 0)
178189
print(C.e(1)) # -> (0 1)
179190
print(O.e(3)) # -> (0 0 0 1 0 0 0 0)
180191
```
181192

182-
10. `e_matrix` of a number class gives the multiplication table of `e(i)*e(j)`. Set `string=False` to get a 2D list instead of a string. Set `raw=True` to get the raw hypercomplex numbers.
193+
11. `e_matrix` of a number class gives the multiplication table of `e(i)*e(j)`. Set `string=False` to get a 2D list instead of a string. Set `raw=True` to get the raw hypercomplex numbers.
183194

184195
```py
185196
print(O.e_matrix()) # -> e1 e2 e3 e4 e5 e6 e7
@@ -194,7 +205,7 @@ Every example assumes the appropriate imports are already done, e.g. `from hyper
194205
print(C.e_matrix(string=False, raw=True)) # -> [[(1 0), (0 1)], [(0 1), (-1 0)]]
195206
```
196207

197-
11. A number is considered truthy if it has has non-zero coefficients. Conversion to `int`, `float` and `complex` are only valid when the coefficients beyond the dimension of those types are all 0.
208+
12. A number is considered truthy if it has has non-zero coefficients. Conversion to `int`, `float` and `complex` are only valid when the coefficients beyond the dimension of those types are all 0.
198209

199210
```py
200211
print(bool(Q())) # -> False
@@ -205,30 +216,30 @@ Every example assumes the appropriate imports are already done, e.g. `from hyper
205216
# print(float(C(1, 2))) <- invalid
206217
```
207218

208-
12. Any usual format spec for the base type can be given in an f-string.
219+
13. Any usual format spec for the base type can be given in an f-string.
209220

210221
```py
211222
o = O(0.001, 1, -2, 3.3333, 4e5)
212223
print(f"{o:.2f}") # -> (0.00 1.00 -2.00 3.33 400000.00 0.00 0.00 0.00)
213224
print(f"{R(23.9):04.0f}") # -> (0024)
214225
```
215226

216-
13. The `len` of a number is its hypercomplex dimension, i.e. the number of components or coefficients it has.
227+
14. The `len` of a number is its hypercomplex dimension, i.e. the number of components or coefficients it has.
217228

218229
```py
219230
print(len(R())) # -> 1
220231
print(len(C(7, 7))) # -> 2
221232
print(len(U())) # -> 128
222233
```
223234

224-
14. Using `in` behaves the same as if the number were a tuple of its coefficients.
235+
15. Using `in` behaves the same as if the number were a tuple of its coefficients.
225236

226237
```py
227238
print(3 in Q(1, 2, 3, 4)) # -> True
228239
print(5 in Q(1, 2, 3, 4)) # -> False
229240
```
230241

231-
15. `copy` can be used to duplicate a number (but should generally not be needed).
242+
16. `copy` can be used to duplicate a number (but should generally never be needed as all operations create a new number).
232243

233244
```py
234245
x = O(9, 8, 7)
@@ -237,7 +248,7 @@ Every example assumes the appropriate imports are already done, e.g. `from hyper
237248
print(x is y) # -> False
238249
```
239250

240-
16. `base` on a number class will return the base type the entire numbers are built upon.
251+
17. `base` on a number class will return the base type the entire numbers are built upon.
241252

242253
```py
243254
print(R.base()) # -> <class 'float'>
@@ -246,6 +257,18 @@ Every example assumes the appropriate imports are already done, e.g. `from hyper
246257
print(A.base()) # -> <class 'int'>
247258
```
248259

260+
18. Hypercomplex numbers are weird, so be careful! Here two non-zero sedenions multiply to give zero because sedenions and beyond have zero devisors.
261+
262+
```py
263+
s1 = S.e(5) + S.e(10)
264+
s2 = S.e(6) + S.e(9)
265+
print(s1) # -> (0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0)
266+
print(s2) # -> (0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0)
267+
print(s1 * s2) # -> (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
268+
print((1 / s1) * (1 / s2)) # -> (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
269+
# print(1/(s1 * s2)) <- zero division error
270+
```
271+
249272
## About
250273

251274
I wrote this package for the novelty of it and as a math and programming exercise. The operations it can perform on hypercomplex numbers are not particularly efficient due to the recursive nature of the Cayley-Dickson construction.

examples_to_markdown.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,23 @@ def examples_to_markdown():
5252

5353
if __name__ == "__main__":
5454
examples_to_markdown()
55+
56+
# This is the only multiline example and examples_to_markdown can't handle it. Saving it here to avoid manually making it again.
57+
e_matrix_example = """
58+
59+
11. `e_matrix` of a number class gives the multiplication table of `e(i)*e(j)`. Set `string=False` to get a 2D list instead of a string. Set `raw=True` to get the raw hypercomplex numbers.
60+
61+
```py
62+
print(O.e_matrix()) # -> e1 e2 e3 e4 e5 e6 e7
63+
# -e0 e3 -e2 e5 -e4 -e7 e6
64+
# -e3 -e0 e1 e6 e7 -e4 -e5
65+
# e2 -e1 -e0 e7 -e6 e5 -e4
66+
# -e5 -e6 -e7 -e0 e1 e2 e3
67+
# e4 -e7 e6 -e1 -e0 -e3 e2
68+
# e7 e4 -e5 -e2 e3 -e0 -e1
69+
# -e6 e5 e4 -e3 -e2 e1 -e0
70+
#
71+
print(C.e_matrix(string=False, raw=True)) # -> [[(1 0), (0 1)], [(0 1), (-1 0)]]
72+
```
73+
74+
"""

hypercomplex/examples.py

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,44 +45,53 @@
4545
print(R(2).inverse(), 1 / R(2))
4646

4747

48-
# %% 5. `conjugate` gives the conjugate of the number.
48+
# %% 5. Numbers can be raised to integer powers, a shortcut for repeated multiplication or division.
49+
q = Q(0, 3, 4, 0)
50+
print(q**5)
51+
print(q * q * q * q * q)
52+
print(q**-1)
53+
print(1 / q)
54+
print(q**0)
55+
56+
57+
# %% 6. `conjugate` gives the conjugate of the number.
4958
print(R(9).conjugate())
5059
print(C(9, 8).conjugate())
5160
print(Q(9, 8, 7, 6).conjugate())
5261

5362

54-
# %% 6. `norm` gives the absolute value as the base type (`float` by default). There is also `norm_squared`.
63+
# %% 7. `norm` gives the absolute value as the base type (`float` by default). There is also `norm_squared`.
5564
print(O(3, 4).norm(), type(O(3, 4).norm()))
5665
print(abs(O(3, 4)))
5766
print(O(3, 4).norm_squared())
5867

5968

60-
# %% 7. Numbers are considered equal if their coefficients all match. Non-existent coefficients are 0.
69+
# %% 8. Numbers are considered equal if their coefficients all match. Non-existent coefficients are 0.
6170
print(R(999) == V(999))
6271
print(C(1, 2) == Q(1, 2))
6372
print(C(1, 2) == Q(1, 2, 0.1))
6473

6574

66-
# %% 8. `coefficients` gives a tuple of the components of the number in their base type (`float` by default). The properties `real` and `imag` are shortcuts for the first two components. Indexing can also be used (but is inefficient).
75+
# %% 9. `coefficients` gives a tuple of the components of the number in their base type (`float` by default). The properties `real` and `imag` are shortcuts for the first two components. Indexing can also be used (but is inefficient).
6776
print(R(100).coefficients())
6877
q = Q(2, 3, 4, 5)
6978
print(q.coefficients())
7079
print(q.real, q.imag)
7180
print(q[0], q[1], q[2], q[3])
7281

7382

74-
# %% 9. `e(index)` of a number class gives the unit hypercomplex number where the index coefficient is 1 and all others are 0.
83+
# %% 10. `e(index)` of a number class gives the unit hypercomplex number where the index coefficient is 1 and all others are 0.
7584
print(C.e(0))
7685
print(C.e(1))
7786
print(O.e(3))
7887

7988

80-
# %% 10. `e_matrix` of a number class gives the multiplication table of `e(i)*e(j)`. Set `string=False` to get a 2D list instead of a string. Set `raw=True` to get the raw hypercomplex numbers.
89+
# %% 11. `e_matrix` of a number class gives the multiplication table of `e(i)*e(j)`. Set `string=False` to get a 2D list instead of a string. Set `raw=True` to get the raw hypercomplex numbers.
8190
print(O.e_matrix())
8291
print(C.e_matrix(string=False, raw=True))
8392

8493

85-
# %% 11. A number is considered truthy if it has has non-zero coefficients. Conversion to `int`, `float` and `complex` are only valid when the coefficients beyond the dimension of those types are all 0.
94+
# %% 12. A number is considered truthy if it has has non-zero coefficients. Conversion to `int`, `float` and `complex` are only valid when the coefficients beyond the dimension of those types are all 0.
8695
print(bool(Q()))
8796
print(bool(Q(0, 0, 0.01, 0)))
8897

@@ -91,35 +100,45 @@
91100
# print(float(C(1, 2))) <- invalid
92101

93102

94-
# %% 12. Any usual format spec for the base type can be given in an f-string.
103+
# %% 13. Any usual format spec for the base type can be given in an f-string.
95104
o = O(0.001, 1, -2, 3.3333, 4e5)
96105
print(f"{o:.2f}")
97106
print(f"{R(23.9):04.0f}")
98107

99108

100-
# %% 13. The `len` of a number is its hypercomplex dimension, i.e. the number of components or coefficients it has.
109+
# %% 14. The `len` of a number is its hypercomplex dimension, i.e. the number of components or coefficients it has.
101110
print(len(R()))
102111
print(len(C(7, 7)))
103112
print(len(U()))
104113

105114

106-
# %% 14. Using `in` behaves the same as if the number were a tuple of its coefficients.
115+
# %% 15. Using `in` behaves the same as if the number were a tuple of its coefficients.
107116
print(3 in Q(1, 2, 3, 4))
108117
print(5 in Q(1, 2, 3, 4))
109118

110119

111-
# %% 15. `copy` can be used to duplicate a number (but should generally not be needed).
120+
# %% 16. `copy` can be used to duplicate a number (but should generally never be needed as all operations create a new number).
112121
x = O(9, 8, 7)
113122
y = x.copy()
114123
print(x == y)
115124
print(x is y)
116125

117126

118-
# %% 16. `base` on a number class will return the base type the entire numbers are built upon.
127+
# %% 17. `base` on a number class will return the base type the entire numbers are built upon.
119128
print(R.base())
120129
print(V.base())
121130
A = cayley_dickson_algebra(20, int)
122131
print(A.base())
123132

124133

134+
# %% 18. Hypercomplex numbers are weird, so be careful! Here two non-zero sedenions multiply to give zero because sedenions and beyond have zero devisors.
135+
s1 = S.e(5) + S.e(10)
136+
s2 = S.e(6) + S.e(9)
137+
print(s1)
138+
print(s2)
139+
print(s1 * s2)
140+
print((1 / s1) * (1 / s2))
141+
# print(1/(s1 * s2)) <- zero division error
142+
143+
125144
# %%

0 commit comments

Comments
 (0)