1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
//! Generates performant geometric products for any dimension of space.
//!
//! The crate provides a macro [`generate_geometric_product!`]. Given a function
//! identifier and a nonnegative integer literal, the macro generates a function
//! that computes the geometric product of two coefficient representations of
//! multivectors.
//!
//! For example, `generate_geometric_product!(my_product, 3)` generates the
//! following function:
//!
//! ```
//! pub fn my_product<A, B, T>(a: &A, b: &B) -> [T; 8]
//! where
//! A: ::core::ops::Index<usize, Output = T>,
//! B: ::core::ops::Index<usize, Output = T>,
//! T: Copy +
//! ::core::ops::Mul<Output = T> +
//! ::core::ops::Add<Output = T> +
//! ::core::ops::Sub<Output = T>,
//! {
//! [
//! a[0] * b[0] - a[1] * b[1] - a[2] * b[2] - a[3] * b[3] - a[4] * b[4] - a[5] * b[5] - a[6] * b[6] + a[7] * b[7],
//! a[0] * b[1] + a[1] * b[0] + a[2] * b[3] - a[3] * b[2] + a[4] * b[5] - a[5] * b[4] - a[6] * b[7] - a[7] * b[6],
//! a[0] * b[2] - a[1] * b[3] + a[2] * b[0] + a[3] * b[1] + a[4] * b[6] + a[5] * b[7] - a[6] * b[4] + a[7] * b[5],
//! a[0] * b[3] + a[1] * b[2] - a[2] * b[1] + a[3] * b[0] - a[4] * b[7] + a[5] * b[6] - a[6] * b[5] - a[7] * b[4],
//! a[0] * b[4] - a[1] * b[5] - a[2] * b[6] - a[3] * b[7] + a[4] * b[0] + a[5] * b[1] + a[6] * b[2] - a[7] * b[3],
//! a[0] * b[5] + a[1] * b[4] + a[2] * b[7] - a[3] * b[6] - a[4] * b[1] + a[5] * b[0] + a[6] * b[3] + a[7] * b[2],
//! a[0] * b[6] - a[1] * b[7] + a[2] * b[4] + a[3] * b[5] - a[4] * b[2] - a[5] * b[3] + a[6] * b[0] - a[7] * b[1],
//! a[0] * b[7] + a[1] * b[6] - a[2] * b[5] + a[3] * b[4] + a[4] * b[3] - a[5] * b[2] + a[6] * b[1] + a[7] * b[0],
//! ]
//! }
//! ```
//!
//! In this example, the implementation of the function will access `a` and `b`
//! at indices `0..8`. In the general case, it will access its arguments at
//! indices `0..1 << D` and return a value of type `[T; 1 << D]`.
//!
//! # Example
//!
//! The functions are straightforward to generate and use. Pass a (small)
//! nonnegative integer to the macro and it generates the product function.
//! (Check it out with `cargo expand`.)
//!
//! ```rust
//! use algebraic_gen::generate_geometric_product;
//!
//! generate_geometric_product!(my_product, 3);
//!
//! fn main() {
//! let a: [f64; 8] = [1., 2., 3., 4., 5., 6., 7., 8.];
//! let b: [f64; 8] = [8., 7., 6., 5., 4., 3., 2., 1.];
//!
//! let c = my_product(&a, &b);
//!
//! println!("The geometric product of {:?} and {:?} is {:?}", a, b, c);
//!
//! assert_eq!(c, [-88.0, -18.0, 60.0, -18.0, 72.0, 102.0, -36.0, 114.0]);
//! }
//! ```
//!
//! # Geometric Algebra
//!
//! A [geometric algebra](https://en.wikipedia.org/wiki/Geometric_algebra) is defined with respect
//! to a given dimension `D` of space. In such an algebra, there exist objects
//! of different *degrees* from zero to `D` (inclusive). Objects of degree zero
//! are scalars, objects of degree one are vectors, and objects of degree two,
//! three, etc. are bivectors, trivectors, et cetera. These higher degree
//! objects are created by wedge product of vectors. Combining all vectors via
//! wedge product results a *pseudoscalar* of degree `D`. Objects of any degree
//! can be scaled and added to form *multivectors*.
//!
//! Importantly for this crate, any multivector can be represented uniquely as a
//! linear combination of elements of a chosen *base* with `2^D` different
//! objects, meaning that we can represent multivectors as arrays of floating
//! point numbers of that size. The return types `[T; 1]`, `[T; 2]`, `[T; 4]`,
//! `[T; 8]`, etc., of the functions generated by this crate are exactly those
//! representations of multivectors of geometric algebras of spaces with `0`,
//! `1`, `2`, `3`, etc. dimensions, respectively.
//!
//! The macro attaches documentation of the choice of base to the generated
//! function. Sticking to 3D for an example, the choice of base in this crate
//! is: one scalar (`S`), three vectors (`X`, `Y`, `Z`), three bivectors (`X∧Y`,
//! `X∧Z`, `Y∧X`), and one pseudoscalar (`X∧Y∧Z`). The generated
//! product interprets the 8-dimensional coefficient arrays as `[S, X, Y, X∧Y,
//! Z, X∧Z, Y∧Z, X∧Y∧Z]`. In the documentation attached to the respective
//! generated product functions, this is represented as `[[], [0], [1], [0,1],
//! [2], [0,2], [1,2], [0,1,2]]`.
//!
//! # On the Generation
//!
//! Maybe there is better way to get the products that doesn't use the
//! \'sledgehammer\' proc macro approach. The generation is not performant, but
//! we're talking build time.
//!
//! The generation logic is inspired by
//! [All Hail Geometric Algebra!](https://crypto.stanford.edu/~blynn/haskell/ga.html).
//!
//! Brief description of the how the macro works:
//! * Generates elements (base)
//! * Product is simple concatenation here
//! * Canonization with Bubblesort & a kind of duplication elimination
//! * Generates product sums
//! * Expand terms
//! * More products & canonization
//! * Adding/Subtracting based on sign returned by canonization
//! * A bit of formatting
//!
//! More details in the source code:
//! [`algebra_generation.rs`](../src/algebraic_gen/algebra_generation.rs.html).
use ;
use FromStr;
use TokenStream;
use quote;
use ;
/// The one macro exported by this crate