# Quaternion-, and up to, sedenion-valued neural networks: Parallelizing Hamilton product on GPUs/CUDA

**URL:** <https://discourse.julialang.org/t/quaternion-and-up-to-sedenion-valued-neural-networks-parallelizing-hamilton-product-on-gpus-cuda/48442>\
**Category:** Machine Learning\
**Tags:** gpu\
**Created:** [October 15, 2020, 4:59pm UTC](https://discourse.julialang.org/t/quaternion-and-up-to-sedenion-valued-neural-networks-parallelizing-hamilton-product-on-gpus-cuda/48442 "2020-10-15T16:59:41Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [October 15, 2020, 4:59pm UTC](https://discourse.julialang.org/t/quaternion-and-up-to-sedenion-valued-neural-networks-parallelizing-hamilton-product-on-gpus-cuda/48442/1 "2020-10-15T16:59:41Z")

</div>

[Edit: See my next comment on August 2020 Sedenion-networks, and there and here a bit on Octonion-networks. I changed the title yet again replacing Octonion with Sedenion as to not make it too long.]

> **[A survey of quaternion neural networks - Artificial Intelligence Review](https://link.springer.com/article/10.1007/s10462-019-09752-1)**
>
> Quaternion neural networks have recently received an increasing interest due to noticeable improvements over real-valued neural networks on real world tasks such as image, speech and signal processing. The extension of quaternion numbers to neural...

> The specific four dimensional algebra of quaternion numbers, including the _Hamilton product_ allows quaternion-valued models to consistently outperform equivalent real-valued neural networks.

Last time I checked complex-valued ANNs weren’t mainstream (people I asked didn’t even know of), and I first now read about quaternion-valued, neither brand-new, in fact very old idea, and it seems it could be a killer application for Julia. I think Julia would be ideal to explore this gap:

> The _Hamilton product_ is a powerful but expensive operation. In current implementations, this operation is not fully parallelized on GPUs, implying a longer training time for quaternion neural networks. A proper CUDA implementation of this product would drastically reduce this computation time and makes of QNNs a mandatory alternative to real-valued NNs.

All-else-equal, it seems quternion-valued would be better, but everything else isn’t equal, architectures are quckly evolivng with e.g. transformer networks (not mentioned in the survey article), and capsule-networks, it may not help only extending outdated convolutional to QCNN:

> _New architectures_ Despite a recent QCNN and QRNN, new neural networks architectures are still missing. For example, capsule networks, or generative adversarial neural networks could benefits from the introduction of quaternion numbers.

See also:

> Then, while bigger neural networks allow better performances, quaternion neural networks make it possible to obtain comparable or better results on the same task, but with four times less neural model parameters. Indeed, a 4-number quaternion weight linking two 4-number quaternion units only has four degrees of freedom, whereas a standard neural net parametrization has 4×4=16, i.e., a fourfold saving in memory. Therefore, the natural multidimensional representation of quaternions alongside with their ability to drastically reduce the number of parameters indicate that hyper-complex numbers are a better fit than real numbers to create more efficient models in multidimensional spaces.

and:

> _New learning algorithms_ Real world applications of current QNN architectures are based on the straighforward extension of the real-valued backpropagation to the quaternion domain. The recent GHR calculus makes it possible to propose well-adapted learning algorithms that can speed-up the training, and increase the performances due to a better consideration of the quaternion algebra. Such learning algorithms must be improved and deployed in state-of-the-art QNN architectures to fully expose the potential of the GHR calculus.

and:

> New data preprocessing methods have to be investigated to naturally project the features into the quaternion space, such as the quaternion Fourier transform (Hitzer [2007](https://link.springer.com/article/10.1007/s10462-019-09752-1#ref-CR37)).

[EDIT]

> **[Introduction to Quaternion Neural Networks](https://www.simonwenkel.com/projects/introduction-to-quaternion-neural-networks.html)**
>
> Providing practical tutorials and unconventional views on AI for physical world applications.

> [..] it seems like [complex-valued neural networks can outperform real-valued NNs](https://www.simonwenkel.com/2019/07/15/Capsule-Networks-and-other-neural-architectures.html). [that link is to interesting papers and code]
> 
> [list of papers]
> 
> ## There is more …
> 
> Well, if quaternions are still to simple, then have a look at [octernions](https://arxiv.org/abs/1903.08478). It seems like they could outperform quaternions by a tiny bit. And if that is to complicated for you, then drop back to complex numbers 😉

Three papers from last year that seem interesting:

# Deep Octonion Networks

> **[Deep Octonion Networks](https://arxiv.org/abs/1903.08478)**
>
> Deep learning is a research hot topic in the field of machine learning. Real-value neural networks (Real NNs), especially deep real networks (DRNs), have been widely used in many research fields. In recent years, the deep complex networks (DCNs) and...

> **[Deep quaternion neural networks for spoken language understanding](https://hal.science/hal-02107630)**
>
> The availability of open-source software is playing a remarkable role in the popularization of speech recognition and deep learning. Kaldi, for instance, is nowadays an established framework used to develop state-of-the-art speech recognizers....

> Quaternion-valued multi-layer per-  
> ceptrons (QMLP), and autoencoders (QAE) have been intro-  
> duced to capture such latent dependencies, alongside to rep-  
> resent multidimensional data. Nonetheless, a three-layered  
> neural network does not benefit from the high abstraction  
> capability of DNNs. The paper proposes first to extend the  
> hyper-complex algebra to deep neural networks (QDNN) and,  
> then, introduces pre-trained deep quaternion neural networks  
> (QDNN-AE) with dedicated quaternion encoder-decoders  
> (QAE). The experiments conduced on a theme identification  
> task of spoken dialogues from the DECODA data set show,  
> inter alia, that the QDNN-AE reaches a promising gain of  
> 2.2% compared to the standard real-valued DNN-AE.

> **[Quaternion Recurrent Neural Networks](https://arxiv.org/abs/1806.04418)**
>
> Recurrent neural networks (RNNs) are powerful architectures to model sequential data, due to their capability to learn short and long-term dependencies between the basic elements of a sequence. Nonetheless, popular tasks such as speech or images...

> Similarly to capsules, quaternions allow the QRNN to code internal dependencies by composing and processing multidimensional features as single entities, while the recurrent operation reveals correlations between the elements composing the sequence. We show that both QRNN and QLSTM achieve better performances than RNN and LSTM in a realistic application of automatic speech recognition. Finally, we show that QRNN and QLSTM reduce by a maximum factor of 3.3x the number of free parameters needed, compared to real-valued RNNs and LSTMs to reach better results, leading to a more compact representation of the relevant information.

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [October 15, 2020, 7:07pm UTC](https://discourse.julialang.org/t/quaternion-and-up-to-sedenion-valued-neural-networks-parallelizing-hamilton-product-on-gpus-cuda/48442/2 "2020-10-15T19:07:48Z")

</div>

Add info here on Sedenion networks from August 2020 paper. First what I wrote before seeing that:

> have a look at [octernions](https://arxiv.org/abs/1903.08478). It seems like they could outperform quaternions by a tiny bit.

Octonion networks are probably worth a better look. From that paper, fig. 5, yes, accuracy curve is best, while only a little better than quaterions, but both much better than for real, and complex comes close at epoch 20.

However, number of parameters is 481,150 half of quaterions, and real-valued has 7.5x as many. It seems to roughly half for each step from real-\>complex-\>quaternions-\>octanions.

So I thought, since there are even higher-order complex number, lets look up sedenions.

There are also other ways to squeeze networks, where the original is e.g. 50x larger, while unclear why you shouldn’t be able to get 50\*7.5=375 factor from such methods plus above, and maybe an additional 2x factor with below:

[https://www.researchgate.net/publication/343255151\_Metacognitive\_Sedenion-Valued\_Neural\_Network\_and\_Its\_Learning\_Algorithm](https://www.researchgate.net/publication/343255151_Metacognitive_Sedenion-Valued_Neural_Network_and_Its_Learning_Algorithm)

> In this paper, a metacognitive sedenion-valued neural network (Mc-SVNN) and its learning algorithm are proposed. Its application to diverse time-series prediction problems is presented. The Mc-SVNN contains two components: a sedenion-valued neural network that represents the cognitive component, and a metacognitive component, which serves to self-regulate the learning algorithm. At each epoch, the metacognitive component decides what, how, and when learning occurs. The algorithm deletes unnecessary samples and stores only those that are used. This decision is determined by the sedenion magnitude and the 15 sedenion phases. The Mc-SVNN is applied to four real-world forecasting problems: USD-to-euro currency exchange rate forecasting, the sunspot number time series, power demand forecasting, and daily temperature prediction in Abu Dhabi. Compared to existing methods, the Mc-SVNN demonstrates superior performance in time-series forecasting while using a smaller number of parameters.

This is the first time I’ve heard of a real application of (let alone higher order, that I only first now hear about):

> **[Sedenion](https://en.wikipedia.org/wiki/Sedenion)**
>
> Octonions (
>   
>     
>       
>         
> O
>         
>       
>     
> {\\displaystyle \\mathbb {O} }
>   
> ) Sedenions (
>   
>     
>       
>         
> S
>         
>       
>     
> {\\displaystyle \\mathbb {S} }
>   
> )
> In abstract algebra, the sedenions form a 16-dimensional noncommutative and nonassociative algebra over the real numbers, usually represented by the capital letter S, boldface S or blackboard bold 
>   
>     
>       
>         
> S
>         
>       
>     
> {\\displaystyle \\mathbb {S} ...

> Applying the Cayley–Dickson construction to the sedenions yields a 32-dimensional algebra, sometimes called the _32-ions_ or _trigintaduonions_.[[1]](https://en.wikipedia.org/wiki/Sedenion#cite_note-1) It is possible to apply the Cayley–Dickson construction to the sedenions arbitrarily many times.

So I had to look up trigintaduonions, which do not have their own Wikipedia page and I couldn’t find anything relating them to neural networks, there’s however:

2014 paper:  
[https://www.researchgate.net/publication/267097033\_An\_algorithm\_for\_multiplication\_of\_trigintaduonions](https://www.researchgate.net/publication/267097033_An_algorithm_for_multiplication_of_trigintaduonions)

> In this paper we introduce efficient algorithm for the multiplication of trigintaduonions. The direct multiplication of two trigintaduonions requires 1024 real multiplications and 992 real additions. We show how to compute a trigintaduonion product with 498 real multiplications and 943 real additions. During synthesis of the discussed algorithm we use a fact that trigintaduonion multipli-cation may be represented by a vector-matrix product. Such representation provides a possibility to discover repeating elements in the matrix structure and to use specific properties of their mutual placement to decrease the number of real multiplications needed to compute the product of two trigintaduonions.

2013 paper:  
[https://www.researchgate.net/publication/256720850\_An\_algorithm\_for\_fast\_multiplication\_of\_sedenions](https://www.researchgate.net/publication/256720850_An_algorithm_for_fast_multiplication_of_sedenions)

> In this work a rationalized algorithm for calculating the product of sedenions is presented which reduces the number of underlying multiplications. Therefore, reducing the number of multiplications in VLSI processor design is usually a desirable task. The computation of a sedenion product using the naive method takes 256 multiplications and 240 additions, while the proposed algorithm can compute the same result in only 122 multiplications (or multipliers – in hardware implementation case) and 298 additions.

@chakravala, I thought you might know anything about this stuff, or at least be interested, and @Elrod, an idea if we can make these calculations fast in Julia (faster then competing neural network libraries can, I doubt any of them even have this implemented yet, except for naively).

> A sedenion is a 16-dimensional hypercomplex  
> number that is obtained by applying the Cayley–Dickson  
> construction to octonion complex numbers. Its algebra is  
> non-commutative, non-associative, and non-alternative, but  
> power-associative

This is from memory what I remembered, you loose one more each time, here no longer alternative (I’m familiar with preceding), I guess with trigintaduonions you next lose power-associative, but I’m curious what happens for the next higher, 64-ions, that do not even have a name. What propertiy more is there to lose?

Even if these higher-order are slower, they might be worthwhile, as you pay the training cost once. And accuracy is very important. I’m not sure how this affects inference, same order of slowdown for calculations, but since your network is smaller, you may be limited by memory bandwidth thee too anyway (but less so).

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [October 15, 2020, 7:48pm UTC](https://discourse.julialang.org/t/quaternion-and-up-to-sedenion-valued-neural-networks-parallelizing-hamilton-product-on-gpus-cuda/48442/3 "2020-10-15T19:48:35Z")

</div>

> [@Palli](#):
>
> @Elrod, an idea if we can make these calculations fast in Julia (faster then competing neural network libraries can, I doubt any of them even have this implemented yet, except for naively).

I’d take a struct of arrays approach, and just spill some registers on CPUs without AVX512\*.  
Preferably, arrange the data of `S = size(A)` array as either  
`(W, 16, cld(S[1], W), S[2:end]...)` in one array, where `W` is the SIMD vector width of the host CPU, and the 16 corresponds to `e_0, e_1, ..., e_15`, or  
`(S[1], 16, S[2:end]...)` if the former is too complicated.  
You don’t literally want a struct of arrays, because that’d be 16 arrays, which would eat a lot of integer registers, and involve accessing memory spread out through the cache. It also will allow for the possibility of aliasing, which will force LLVM to be more conservative when optimizing.  
The advantage of the former (where you split the first dim into pieces of length `W`) is that now each vector load is a constant offset from one another, rather than a stride multiple apart, which will require more indexing calculations and again occupy more integer registers.

\*Although you may be able to look at the operations and see an order which doesn’t require spilling. The lazy way would be to just generate the code, and see if LLVM can figure it out.

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [October 15, 2020, 9:33pm UTC](https://discourse.julialang.org/t/quaternion-and-up-to-sedenion-valued-neural-networks-parallelizing-hamilton-product-on-gpus-cuda/48442/4 "2020-10-15T21:33:02Z")

</div>

A sedenion is “only” 16 numbers, so to multiply (or add or whatever) two of those you need to access 32 numbers, so not all can be in registers (one of, i.e. 16 sub-numbers, could be in registers on x86-64). With SIMD maybe, with many sub-number sharing one register. I actually have an idea related to that before anyone starts implementing stuff.

Did you have the naive method in mind?

> The computation of a sedenion product using the naive method takes 256 multiplications and 240 additions, while the proposed algorithm can compute the same result in only 122 multiplications (or multipliers – in hardware implementation case) and 298 additions.

It seems to be like matrix multiply, could use loops, while the other way isn’t regular (I guess, haven’t looked at that paper yet), so might be more complicated to implement (potentially code generatein in Julia could help).

I’ve now however read the Sedations-neural network paper, e.g.:

> An SVNN that takes one sedenion input and predicts one  
> sedenion output uses 2 × N 1 sedenion multiplications, which  
> is equivalent to 16 × 16 × 2 × N 1 = 512 × N 1 real-  
> valued multiplications. The comparable real-valued network  
> with 16 inputs and outputs requires 32 × N 1 real-valued  
> multiplications. The use of sedenion numbers increases the  
> number of multiplications by a factor of 16. We would like to  
> note that despite the increase in multiplication costs, SVNNs  
> converge faster than real-valued networks.

But for inference of a network, you would pay 16x for sedenions (and I guess lower) multiply tax for the forward phase. That should be ok, with the best alternative, LSTM and LSTM-SARIMA having 211200/496 = 425x more parameters.

And that 16x is 512/32 seemingly assuming the naive approach, that could be improved.

To answer my own question here:

> I’m curious what happens for the next higher, 64-ions, that do not even have a name. What propertiy more is there to lose?

> **[Cayley–Dickson construction](https://en.wikipedia.org/wiki/Cayley%E2%80%93Dickson_construction)**
>
> In mathematics, the Cayley–Dickson construction, named after Arthur Cayley and Leonard Eugene Dickson, produces a sequence of algebras over the field of real numbers, each with twice the dimension of the previous one. The algebras produced by this process are known as Cayley–Dickson algebras, for example complex numbers, quaternions, and octonions. These examples are useful composition algebras frequently applied in mathematical physics.
> The Cayley–Dickson construction defines a new algebra as a...

indicates to me in the table there, that nothing changes after sedenions, 64-ions, 128-ions, etc. Could those higher order help even more in neural networks, why stop at 16-dimensional?

4-dimensional numbers were said to help e.g. because colors are 3-d, RGB, so maybe more than quaternions doesn’t help depending on applications. That might be wrong thinking, as in some sense a 2D picture is e.g. 1024 dimensions even for a tiny greyscale 32x32 icon. In color, times three, requring at least 12 hidden layers:

I guess many think the universal approximation theory requires only one hidden layer. Actually it’s only for scalar functions, for 2 and 3 dimensional it requires 2 hidden layers, and in general log2(dimensions) hidden layers. I saw this in a recent paper proving it, clearing up for me why deep learning is a thing, when networks shouldn’t have needed that.

The proof is likely affected by such hyper-complex numbers, assuming such or complex not used.

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [October 15, 2020, 9:54pm UTC](https://discourse.julialang.org/t/quaternion-and-up-to-sedenion-valued-neural-networks-parallelizing-hamilton-product-on-gpus-cuda/48442/5 "2020-10-15T21:54:57Z")

</div>

> [@Palli](#):
>
> A sedenion is “only” 16 numbers, so to multiply (or add or whatever) two of those you need to access 32 numbers, so not all can be in registers (one of, i.e. 16 sub-numbers, could be in registers on x86-64). With SIMD maybe, with many sub-number sharing one register. I actually have an idea related to that before anyone starts implementing stuff.

AVX512 has 32 vector registers, which would help.  
However, I would prefer to have each register contain multiple of the same piece from different sedenions. E.g.,  
`v_1 = <e0_1, e0_2, e0_3, e0_4, e0_5, e0_6, e0_7, e0_8>`, the `e0` value from sedenions 1 through 8.  
You could search for a pattern of minimum shuffles to actually get SIMD on your adds/multiplies, but I’d prefer to look for a pattern that may minimize reads/writes.

What operations are being performed?  
If we have matrix multiplication, without AVX512 I’d look into calculating e0-e7 in one dot product, and then getting the remaining e8-e15 in a second dot product.  
You then consume 8 registers in the accumulation. Note that this would mean each dot product calculates half of `W` sedenions, where `W` is the vector width.  
You’re loading up to 32 registers total for `x[i] * y[i]`, but then I’d look for patterns of updating e0-e7 (and similarly for e8-e15) while minimizing the number of live values you need at a time. E.g., maybe you can load e0\_x and use it for everything it is needed for, and then replace it with e1\_x.

> Did you have the naive method in mind?

I’m not actually familiar with sedenions, so yes.

> The computation of a sedenion product using the naive method takes 256 multiplications and 240 additions, while the proposed algorithm can compute the same result in only 122 multiplications (or multipliers – in hardware implementation case) and 298 additions.

How many fmas can we use? 240 fmas + 16 multiplications is faster than 122 fmas and 186 additions.

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [October 15, 2020, 10:03pm UTC](https://discourse.julialang.org/t/quaternion-and-up-to-sedenion-valued-neural-networks-parallelizing-hamilton-product-on-gpus-cuda/48442/6 "2020-10-15T22:03:17Z")

</div>

> [@Elrod](#):
>
> What operations are being performed?  
> If we have matrix multiplication

I was actually just thinking of multiplying two such “numbers”, but you’re right, it would be matrix-multiply of those, similar for other neural networks. In their case they have 10 neurons in hidden layer and only 1 input, but it could be a fully connected layer, and I’m just not up-to-speed. I think it’s matrix-vector? At least not matrix-matrix.

And while you have AVX512 (wasn’t aware it’s 32 registers there, assuming less for regular AVX), not all do, and you likely want this on a GPU. I’m just not sure about the size of the register files there.

Did you see about future Intel chips, with an extra 8KB register file for matrix multiply, some special instructions? If I recall, coming next year.

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [October 15, 2020, 10:15pm UTC](https://discourse.julialang.org/t/quaternion-and-up-to-sedenion-valued-neural-networks-parallelizing-hamilton-product-on-gpus-cuda/48442/7 "2020-10-15T22:15:27Z")

</div>

> [@Palli](#):
>
> I was actually just thinking of multiplying two such “numbers”, but you’re right, it would be matrix-multiply of those, similar for other neural networks. In their case they have 10 neurons in hidden layer and only 1 input, but it could be a fully connected layer, and I’m just not up-to-speed. I think it’s matrix-vector? At least not matrix-matrix.

Ideally, we could also carry some of the loaded numbers (e.g. from the vector) from one iteration to the next. If you really want to optimize this, I’d use a pen and paper to try and compare strategies, maybe even going so far as to build a jump model of the problem and architecture to try and minimize the number of loads and stores.

> [@Palli](#):
>
> you likely want this on a GPU. I’m just not sure about the size of the register files there.

I’m not either.

> [@Palli](#):
>
> Did you see about future Intel chips, with an extra 8KB register file for matrix multiply, some special instructions? If I recall, coming next year.

For reference, AVX(2) has 0.5 KiB (16 registers \* 32 bytes/register) and AVX512 has 2 KiB (32 registers \* 64 bytes/register).  
This 8 KiB (8 matrix registers; each register is 16 rows of 64 bytes for 1 KiB/register) is in addition to AVX512; they’re separate registers.  
The matrix multiply on these tiles will only support `(U)Int8` and `BFloat16`, at least on the first CPUs supporting it.

> **[Advanced Matrix Extension (AMX) - x86 - WikiChip](https://en.wikichip.org/wiki/x86/amx)**
>
> Advanced Matrix Extension (AMX) is an x86 extension that introduces a matrix register file and new instructions for operating on matrices.

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [October 17, 2020, 11:34pm UTC](https://discourse.julialang.org/t/quaternion-and-up-to-sedenion-valued-neural-networks-parallelizing-hamilton-product-on-gpus-cuda/48442/8 "2020-10-17T23:34:29Z")

</div>

FYI: If there’s anyone interested in sedenions (or the other hyper-complex numbers), and/or networks based on them, there’s a package for them. Not a package for networks using those, but Julia wouldn’t surprise me if I could just use this package and NN code and extended types just work.

The package is just outdated, and I’m trying to upgrade a package for the first time, maybe I’m doing it wrong (I made the file) and/or the package was to old for the upgrade process:

```julia
pharaldsson_sym:~/myjulia/julia/CayleyDickson.jl$ ~/julia-1.5.1/bin/julia gen_project.jl 
ERROR: LoadError: UndefVarError: METADATA_compatible_uuid not defined
Stacktrace:
 [1] uuid(::SubString{String}) at /home/pharaldsson_sym/myjulia/julia/CayleyDickson.jl/gen_project.jl:45
 [2] top-level scope at /home/pharaldsson_sym/myjulia/julia/CayleyDickson.jl/gen_project.jl:118
 [3] include(::Function, ::Module, ::String) at ./Base.jl:380
 [4] include(::Module, ::String) at ./Base.jl:368
 [5] exec_options(::Base.JLOptions) at ./client.jl:296
 [6] _start() at ./client.jl:506
in expression starting at /home/pharaldsson_sym/myjulia/julia/CayleyDickson.jl/gen_project.jl:98

```
