Skip to content

Instantly share code, notes, and snippets.

@SoulFireMage
Created May 27, 2023 07:50
Show Gist options
  • Save SoulFireMage/b8bf7dbbb1f59a63cde2db3630aa718b to your computer and use it in GitHub Desktop.
Save SoulFireMage/b8bf7dbbb1f59a63cde2db3630aa718b to your computer and use it in GitHub Desktop.
Octonions - A GPT 4 built implmentation
///In an effort to get some kind of intuition around what an octonion even is - I'm not a mathematician! - I asked GPT4 for help.
///During this conversation it gave me the outline of an octonion in C#. Running with this, I prompted for the main operations and built
///this up, sparked by the fact there wasn't an implementation out there (according to GPT4 - which probably is not true).
///Still, posting this up for my future reference as I'm interested in the notion of using such in a neural network
///Though I'm more likely to review abstracts of others who have actually code such CNNs already! :)
public struct Octonion
{
public double w, x, y, z, u, v, t, s; // the eight components of the octonion
public Octonion(double w, double x, double y, double z, double u, double v, double t, double s)
{
this.w = w;
this.x = x;
this.y = y;
this.z = z;
this.u = u;
this.v = v;
this.t = t;
this.s = s;
}
public static Octonion operator *(Octonion a, Octonion b)
{
return new Octonion(
a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z - a.u * b.u - a.v * b.v - a.t * b.t - a.s * b.s,
a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y + a.u * b.s - a.v * b.t + a.t * b.v + a.s * b.u,
a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x - a.u * b.t - a.v * b.s + a.t * b.u - a.s * b.v,
a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w + a.u * b.v + a.v * b.u - a.t * b.s - a.s * b.t,
a.w * b.u - a.x * b.s + a.y * b.t + a.z * b.v - a.u * b.w - a.v * b.x + a.t * b.y + a.s * b.z,
a.w * b.v + a.x * b.t - a.y * b.s - a.z * b.u + a.u * b.x - a.v * b.w - a.t * b.z + a.s * b.y,
a.w * b.t - a.x * b.v + a.y * b.u + a.z * b.s - a.u * b.y + a.v * b.z - a.t * b.w - a.s * b.x,
a.w * b.s + a.x * b.u - a.y * b.v + a.z * b.t + a.u * b.z - a.v * b.y + a.t * b.x - a.s * b.w
);
}
public static Octonion operator +(Octonion a, Octonion b)
{
return new Octonion(
a.w + b.w,
a.x + b.x,
a.y + b.y,
a.z + b.z,
a.u + b.u,
a.v + b.v,
a.t + b.t,
a.s + b.s
);
}
public static Octonion operator -(Octonion a, Octonion b)
{
return new Octonion(
a.w - b.w,
a.x - b.x,
a.y - b.y,
a.z - b.z,
a.u - b.u,
a.v - b.v,
a.t - b.t,
a.s - b.s
);
}
public Octonion Conjugate()
{
return new Octonion(
this.w,
-this.x,
-this.y,
-this.z,
-this.u,
-this.v,
-this.t,
-this.s
);
}
public double Norm()
{
return Math.Sqrt(w * w + x * x + y * y + z * z + u * u + v * v + t * t + s * s);
}
public Octonion Normalize()
{
double norm = this.Norm();
if (norm == 0)
throw new InvalidOperationException("Cannot normalize a zero octonion.");
return new Octonion(
this.w / norm,
this.x / norm,
this.y / norm,
this.z / norm,
this.u / norm,
this.v / norm,
this.t / norm,
this.s / norm
);
}
// Real Part
public double RealPart()
{
return this.w;
}
// Imaginary Part
public (double, double, double, double, double, double, double) ImaginaryPart()
{
return (this.x, this.y, this.z, this.u, this.v, this.t, this.s);
}
// Inverse
public Octonion Inverse()
{
double normSquared = this.Norm() * this.Norm();
if (normSquared == 0)
throw new InvalidOperationException("Cannot invert a zero octonion.");
Octonion conjugate = this.Conjugate();
return new Octonion(
conjugate.w / normSquared,
conjugate.x / normSquared,
conjugate.y / normSquared,
conjugate.z / normSquared,
conjugate.u / normSquared,
conjugate.v / normSquared,
conjugate.t / normSquared,
conjugate.s / normSquared
);
}
// Division
public static Octonion operator /(Octonion a, Octonion b)
{
return a * b.Inverse();
}
}
public static class OctonionExtensions
{
public static Octonion ToOctonion(this (double, double, double, double, double, double, double, double) tuple)
{
return new Octonion(tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, tuple.Item5, tuple.Item6, tuple.Item7, tuple.Item8);
}
}
@JesusCastroFernandez
Copy link

El código proporcionado implementa una estructura llamada "Octonion" en C#. Esta estructura representa un octonión y proporciona operaciones matemáticas básicas sobre los octoniones, como multiplicación, suma, resta, conjugado, inverso, división y algunas funciones auxiliares.

Aquí hay algunas sugerencias para mejorar el código:

Comentarios: Aunque el código ya contiene algunos comentarios, sería beneficioso agregar más comentarios para explicar el propósito de las funciones y cualquier otro detalle relevante. Esto ayudará a otros programadores (incluido tu yo futuro) a comprender y utilizar el código de manera más efectiva.

Documentación XML: Considera agregar documentación XML para las clases y los miembros públicos. Esto permitirá que las herramientas de desarrollo, como IntelliSense, muestren información útil sobre el código cuando se esté utilizando.

Validación de argumentos: En los métodos que realizan operaciones matemáticas, sería útil agregar validación de argumentos para garantizar que los octoniones pasados como argumentos sean válidos. Por ejemplo, al calcular la inversa o normalizar un octonión, se podría verificar si el octonión tiene norma cero o lanzar una excepción en consecuencia.

Operador de igualdad: Podrías considerar implementar el operador de igualdad (==) y el operador de desigualdad (!=) para comparar dos octoniones. Esto puede resultar útil en algunas situaciones y mejorar la usabilidad de la estructura.

Uso de propiedades autoimplementadas: En lugar de utilizar campos públicos para los componentes del octonión, puedes convertirlos en propiedades autoimplementadas. Esto proporcionará encapsulación y facilitará posibles cambios futuros en la implementación interna de la estructura sin afectar el código que la utiliza.

Control de estilo: Para mejorar la legibilidad del código, asegúrate de seguir las convenciones de nomenclatura de C# y el estilo de codificación. Por ejemplo, utiliza nombres de métodos y propiedades en formato PascalCase y agrega espacios en blanco adecuados alrededor de los operadores y después de las comas.

Pruebas unitarias: Es una buena práctica agregar pruebas unitarias para verificar que el código funcione correctamente en diferentes casos de uso. Puedes utilizar un marco de pruebas como NUnit o MSTest para escribir pruebas y ejecutarlas regularmente.

Estas son solo algunas sugerencias generales para mejorar el código. Ten en cuenta que las necesidades y requisitos específicos pueden variar según el contexto de uso.

A continuación se muestra el código mejorado teniendo en cuenta las mejoras propuestas:

`using System;

///


/// Represents an octonion.
///

public struct Octonion
{
public double W { get; }
public double X { get; }
public double Y { get; }
public double Z { get; }
public double U { get; }
public double V { get; }
public double T { get; }
public double S { get; }

public Octonion(double w, double x, double y, double z, double u, double v, double t, double s)
{
    W = w;
    X = x;
    Y = y;
    Z = z;
    U = u;
    V = v;
    T = t;
    S = s;
}

/// <summary>
/// Multiplies two octonions.
/// </summary>
public static Octonion operator *(Octonion a, Octonion b)
{
    return new Octonion(
        a.W * b.W - a.X * b.X - a.Y * b.Y - a.Z * b.Z - a.U * b.U - a.V * b.V - a.T * b.T - a.S * b.S,
        a.W * b.X + a.X * b.W + a.Y * b.Z - a.Z * b.Y + a.U * b.S - a.V * b.T + a.T * b.V + a.S * b.U,
        a.W * b.Y - a.X * b.Z + a.Y * b.W + a.Z * b.X - a.U * b.T - a.V * b.S + a.T * b.U - a.S * b.V,
        a.W * b.Z + a.X * b.Y - a.Y * b.X + a.Z * b.W + a.U * b.V + a.V * b.U - a.T * b.S - a.S * b.T,
        a.W * b.U - a.X * b.S + a.Y * b.T + a.Z * b.V - a.U * b.W - a.V * b.X + a.T * b.Y + a.S * b.Z,
        a.W * b.V + a.X * b.T - a.Y * b.S - a.Z * b.U + a.U * b.X - a.V * b.W - a.T * b.Z + a.S * b.Y,
        a.W * b.T - a.X * b.V + a.Y * b.U + a.Z * b.S - a.U * b.Y + a.V * b.Z - a.T * b.W - a.S * b.X,
        a.W * b.S + a.X * b.U - a.Y * b.V + a.Z * b.T + a.U * b.Z - a.V * b.Y + a.T * b.X - a.S * b.W
    );
}

/// <summary>
/// Adds two octonions.
/// </summary>
public static Octonion operator +(Octonion a, Octonion b)
{
    return new Octonion(
        a.W + b.W,
        a.X + b.X,
        a.Y + b.Y,
        a.Z + b.Z,
        a.U + b.U,
        a.V + b.V,
        a.T + b.T,
        a.S + b.S
    );
}

/// <summary>
/// Subtracts one octonion from another.
/// </summary>
public static Octonion operator -(Octonion a, Octonion b)
{
    return new Octonion(
        a.W - b.W,
        a.X - b.X,
        a.Y - b.Y,
        a.Z - b.Z,
        a.U - b.U,
        a.V - b.V,
        a.T - b.T,
        a.S - b.S
    );
}

/// <summary>
/// Computes the conjugate of the octonion.
/// </summary>
public Octonion Conjugate()
{
    return new Octonion(
        W,
        -X,
        -Y,
        -Z,
        -U,
        -V,
        -T,
        -S
    );
}

/// <summary>
/// Computes the norm of the octonion.
/// </summary>
public double Norm()
{
    return Math.Sqrt(W * W + X * X + Y * Y + Z * Z + U * U + V * V + T * T + S * S);
}

/// <summary>
/// Normalizes the octonion.
/// </summary>
public Octonion Normalize()
{
    double norm = Norm();

    if (norm == 0)
        throw new InvalidOperationException("Cannot normalize a zero octonion.");

    return new Octonion(
        W / norm,
        X / norm,
        Y / norm,
        Z / norm,
        U / norm,
        V / norm,
        T / norm,
        S / norm
    );
}

/// <summary>
/// Gets the real part of the octonion.
/// </summary>
public double RealPart()
{
    return W;
}

/// <summary>
/// Gets the imaginary part of the octonion.
/// </summary>
public (double, double, double, double, double, double, double) ImaginaryPart()
{
    return (X, Y, Z, U, V, T, S);
}

/// <summary>
/// Computes the inverse of the octonion.
/// </summary>
public Octonion Inverse()
{
    double normSquared = Norm() * Norm();
    if (normSquared == 0)
        throw new InvalidOperationException("Cannot invert a zero octonion.");

    Octonion conjugate = Conjugate();
    return new Octonion(
        conjugate.W / normSquared,
        conjugate.X / normSquared,
        conjugate.Y / normSquared,
        conjugate.Z / normSquared,
        conjugate.U / normSquared,
        conjugate.V / normSquared,
        conjugate.T / normSquared,
        conjugate.S / normSquared
    );
}

/// <summary>
/// Divides one octonion by another.
/// </summary>
public static Octonion operator /(Octonion a, Octonion b)
{
    return a * b.Inverse();
}

}

///


/// Provides extension methods for converting tuples to octonions.
///

public static class OctonionExtensions
{
///
/// Converts a tuple to an octonion.
///

public static Octonion ToOctonion(this (double, double, double, double, double, double, double, double) tuple)
{
return new Octonion(tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, tuple.Item5, tuple.Item6, tuple.Item7, tuple.Item8);
}
}
`

Recuerda que este código es una mejora del original, basado en las sugerencias proporcionadas. Sin embargo, ten en cuenta que el uso de octoniones puede ser complejo y requiere un conocimiento matemático sólido para comprenderlo y aplicarlo correctamente.

@SoulFireMage
Copy link
Author

I was having a bit of fun seeing if I could get something like this as a means of grasping what the mathematical object even was. Thank you however :)

@alphanumericaracters
Copy link

1- Ok, I'm not a mathematician, but I'm a 3D designer (Rhino + Grasshopper), which allows the insertion of Scripts in C#, VB and Python, as well as the creation of plugins that allow you to extend the capabilities of Grasshopper within Rhino.

2- This code (for me) is a breakthrough in the field of design and my interests in "higher dimensions" for different purposes beyond the simple "rotation in space of a body" (to which the structure of a quaternion is always attributed).

3- To make it clearer what I mean, I must first explain to you (long story short) that the algebra of a quaternion, as well as that of an octonion, is hypercomplex in the sense that it is a numerical set that encompasses complex numbers:

              * Real Number > Complex Number > Quaternions > Octonions
  • A bit of history is necessary to understand what is to come.

Where quaternions and octonions belong to the hypercomplex group, It was "created/discovered" (quaternions) by William Rowan Hamilton in 1843 and used by Maxwell for his equations on electromagnetism, but as its operation was difficult to perform, came Heaviside reformulated Maxwell's equations and criticized Hamilton and his quaternions (Alice in Wonderland alludes to quaternions) and together with Grassman created vector analysis, which is nothing more than an absurd attempt to poterate the commutativity of multiplication (which is lost in the quaternions). [You know; orthodoxy in science].

A terrible intellectual mathematical battle was waged at that time, where at the same time Clifford appeared (the mathematician, not the giant red dog), who came to calm the waters a little with his algebra, who did nothing more than expand vector analysis to its original quaternion form, only using (separately) the rotation matrices (rotors). To which everyone was "happy", but this was accompanied by its own "tradeoff", which allowed the commutativity of multiplication to be protected in exchange for carrying out many more operations.

Then came Graves with the octonions, who only realized what Clifford did, revealing that it was just a more expensive way to get to quaternions, but inspired by the way Clifford managed to get to a quaternion using vectors and how Hamilton had "created/discovered" the quaternions, Graves did the same thing as Clifford, only applied to quaternions, thus creating octonions.

But mathematicians only care about structures and conventions and stuff, and physicists care that the cow or train remains round circles that don't exceed the speed of light.

With the advent of Einstein and his theory of relativity and the creation of tensors (which can easily be obtained as interpolated curves between quaternions), the use of quaternions and octonions was forgotten until much later, when topology, knots and Lie groups were mature (and answers were not found in "low dimensions")

              End

4- What the world of copy paste does not understand (and will not understand) simply because they are not interested in understanding, is that "dimensions" in the language of the time meant "elements or components".

So a mathematical object that had 4 elements or components, was formally taught as "4 dimensions", and as I said before, with the advent of Einstein and his theories, the word "dimension" took on another meaning, so when the study of hypercomplex algebras was resumed, minds were already molded to the new meaning of "dimension" and that is why it is believed that they are "high dimensions". as if they were something mystical belonging to metaphysics or metamathematics.

5- To understand the above, I will explain how a vector is formed and a quaternion is obtained (without complex mathematics):
T [temperature]=2x+2y where Y = 2x+1 (and Y it's evaluated when x = 2)
So Y = 2*2+1 = 5 and T = 25+4 = 29 [if you plot it it gives you the point (x=2, y=5) as the coordinate].

But wait! I now have 3 values!!! the value of X, the value of Y, the value of T, and the plane only allows me to plot 2 values as a point, so I'll have to add another axis to be able to plot the value of T, how do I do it?...

I know! I will create a "complex axis" called Z that I can use to graph the value of T, and I call it complex because you must imagine it to see it, because the only way to relate it to the other 2 axes will be through an imaginary rotation of the plane which I will represent with the letter "i"

So now I will "compact" the plane x,y into the variable "a", and the variable Z will be equal to T (which I will call it "b") multiplied by the imaginary rotation "i", in such a way that the plane x,y = 5 and Z = 29 leaving as a general formula a + bi = 5 + 29i

Congratulations! You created your first complex number!!

And what if now (to further compact and make the calculations "less complex") to the "distance" from point 0.0 to point 5+29i and call it "vector"??

So vector = square_root of (a^2 + b^2) and everything compact and pretty.

Congratulations! Now you've created your first vector!

So if I now do the same for 2 more vectors, I will be able to express temperature, pressure, and velocity of a "body or particle", which by extension (by squaring its components [dimensions], I will get a [scalar] point that will represent the total energy of the system), such that:

A = (v1^2)+(v2^2)+(v3^2)

So now my object or particle might as well be a cube, and if I want to give it a direction and orientation how do I do it?

I know!!! I'll add another "i" rotation to each axis, so you can unambiguously identify its position in space at all times.

So now my point on the plane will be P= A+{(a+bi)+i} + {(a+bi)+i} + {(a+bi)+i} where a+bi =vector1 for the x-axis, a+bi =vector2 for the y-axis, a+bi =vector1 for the z-axis. Leaving P = A+(v1i)+ (v2i) + (v3*i)

What an arduous task of calculation it is to represent a cube with orientation, direction, velocity, temperature and pressure, and its total energy in space, I wish there was a faster and easier way to represent it and ease the burden of calculations.

Maybe there is? But what kind of tradeoff should I do to achieve this? It may lose some mathematical property, such as commutativity in multiplication, because rotations on all axes lead to its loss.

I wish someone had created a lighter algebra (in calculus) for him to achieve that, so that Q= A+Xi+Yj+Zk and called it Quaternion, because of its four elements/components/dimensions, I wouldn't mind losing the commutativity, because I would use it in many other ways, I could even use it to find the shortest rotation from one point to another.

Congratulations! Now you've created your first Quaternion!

And what would happen if I put several quaternions together to represent even more (complete) particles?? What property would I have to give in exchange for facilitating the calculations???, surely it is "associativity".

But by doing so, it could be invariant to any reference point, it would be completely "evolutionary" (forward), it would no longer have the uncertainty that my particle travels backwards in time, which would well explain the entropy and thermodynamics of the universe, it could also interpolate all the points generated by the quaternions, in such a way that it gives me a curve (trajectory) with the shortest path from one point to another passing through all the points. It would have a shape that would not correspond to its value, as if it were deformed, as if it had a "Tensioner" that forced it to curve and adopt a "geodesic" shape, As well as representing a kind of "uniformly accelerated intrinsic motion" that could well be called Spin, which is quite unique, since it only "exists for the sake of it", just imagine that something like this exists!! a scalar with a kind of hyper-complex rotation that happens in all planes at once.

Congratulations! Now you've created your first Octonion!

But that math and physics is pure science fiction, because in our universe both cows and trains are a circle/sphere on the blackboard..

Naaaaaa... I'd rather stick with the old, well-known orthodoxy.

6- Now that you know what an equation, function, scalar, vector, quaternion, and octonion are, you'll get a lot better at the code and comments in it.

As well as, knowing that the 3rd "dimension" never goes out, but that all the properties of an object or particle can be represented more easily than in a common way, since the phrase "higher dimension" only refers to the fact that it has more components.

it's not like it literally comes from the dimension of Dormamu, Cuthulu, Pleiadians or Spidervers and that weed-smoking stuff.

7- As for me, I'm just looking for a way to integrate quaternions and octonions into Grasshopper for Rhino, so I can improve the calculations and efficiency in my designs (research, development and scientific innovation), but I lack good knowledge in C# (it's a much better language than VB and Python).

8- What I explained here, you won't find anywhere or in any LLM or university, it's many years of reading, interpreting and calculating. I hope it will be useful for your development (personal and professional).

Jonatha Urbina (Argentina).

@SoulFireMage & @JesusCastroFernandez

@alphanumericaracters
Copy link

  • [Español] Sinceramente estoy inspeccionando la matemática del código, para que se corresponda con el álgebra de los cuaterniones y octoniones (conmutatividad y asociatividad), para que funcione como deba.

  • [English] I am honestly inspecting the mathematics of the code, so that it corresponds to the algebra of quaternions and octonions (commutativity and associativity), so that it works as it should.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment