E8 System Visualization

Hi,

I have begin to read about the E8 space
(something similar to the human 4D space { x, y, z, w } but with 8 dimensions instead)

I have coded this OpenGL E8 root visualisation that use the {r,g,b,a] vertex components in addition the { x, y, z, t} compenents for to simulate a 8D space and want add to it somes E8 particularities

This 8D space seem particulary “magic”, I begin now to understand why it is used into things as differents as modular forms, self-dual lattices, unifying fundamental forces, symmetries in black hole entropy or others quasicrystals high-dimensional symmetries or symmetry-based musical structures

#include <GL/glut.h>
#include
#include
#include
#include
#include  // pour rand() et srand()
#include    // pour time()

// Structure pour représenter une racine de E8 (8 dimensions)
struct E8Root {
float coords\[8\];
bool isType1; // Vrai si c'est une racine de type 1 (2 ±1, le reste à 0)
};

// Structure pour représenter une arête (entre deux racines)
struct Edge {
int root1;
int root2;
int diffDim; // Dimension qui diffère entre root1 et root2 (0=x, 1=y, 2=z, etc.)
};

// Variables globales
std::vector E8_ROOTS;  // Stockera les 240 racines
std::vector EDGES;      // Stockera les arêtes entre les racines
float timeOffset = -1.0f;     // Commence à t = -1
float deltaT = 1.0f;         // Largeur de la tranche de temps (1.0f pour voir tout le cube)
bool animateTime = false;    // Désactivé par défaut pour voir le cube complet
int rotationAngle = 0;       // Angle de rotation

// Fonction pour générer les racines de type 1 (±1, ±1, 0, ..., 0)
void generateType1Roots() {
for (int i = 0; i < 8; ++i) {
for (int j = i + 1; j < 8; ++j) {
for (int sign1 : {-1, 1}) {
for (int sign2 : {-1, 1}) {
E8Root root;
for (int k = 0; k < 8; ++k) {
if (k == i) root.coords\[k\] = sign1;
else if (k == j) root.coords\[k\] = sign2;
else root.coords\[k\] = 0;
}
root.isType1 = true;
E8_ROOTS.push_back(root);
}
}
}
}
}

// Fonction pour générer les racines de type 2 (±1/2, ..., ±1/2) avec un nombre pair de -1/2
void generateType2Roots() {
for (int mask = 0; mask < (1 << 8); ++mask) {
int negativeCount = 0;
E8Root root;
for (int i = 0; i < 8; ++i) {
if (mask & (1 << i)) {
root.coords\[i\] = -0.5f;
negativeCount++;
} else {
root.coords\[i\] = 0.5f;
}
}
if (negativeCount % 2 == 0) {
root.isType1 = false;
E8_ROOTS.push_back(root);
}
}
}

// Fonction pour pré-calculer les arêtes entre les racines de type 1
void precomputeEdges() {
for (size_t i = 0; i < E8_ROOTS.size(); ++i) {
if (!E8_ROOTS\[i\].isType1) continue;
for (size_t j = i + 1; j < E8_ROOTS.size(); ++j) {
if (!E8_ROOTS\[j\].isType1) continue;
int diffCount = 0;
int diffDim = -1;
for (int k = 0; k < 8; ++k) {
if (E8_ROOTS\[i\].coords\[k\] != E8_ROOTS\[j\].coords\[k\]) {
diffCount++;
diffDim = k;
}
}
if (diffCount == 1) { // Une seule coordonnée diffère → arête du cube
EDGES.push_back({(int)i, (int)j, diffDim});
}
}
}
}

void init() {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);  // Fond noir
glEnable(GL_DEPTH_TEST);              // Activer le test de profondeur
glEnable(GL_BLEND);                   // Activer la transparence
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPointSize(3.0f);                    // Taille des points
glLineWidth(1.5f);                    // Épaisseur des arêtes

// Générer les racines et les arêtes
E8_ROOTS.clear();
EDGES.clear();
generateType1Roots();
generateType2Roots();
precomputeEdges();
std::cout << "Nombre total de racines : " << E8_ROOTS.size() << std::endl;
std::cout << "Nombre d'arêtes : " << EDGES.size() << std::endl;

}

void drawBackground() {
glBegin(GL_POINTS);
for (int i = 0; i < 2000; ++i) {
float x = (rand() % 1000 - 500) / 200.0f;
float y = (rand() % 1000 - 500) / 200.0f;
float z = (rand() % 1000 - 500) / 200.0f;
float brightness = (rand() % 100) / 100.0f;
glColor4f(brightness, brightness, brightness, 1.0f);
glVertex3f(x, y, z);
}
glEnd();
}

void drawPoints() {
glBegin(GL_POINTS);
for (const auto& root : E8_ROOTS) {
float t = root.coords\[3\];
if (t >= timeOffset && t <= timeOffset + deltaT) {
float x = root.coords\[0\];
float y = root.coords\[1\];
float z = root.coords\[2\];

        if (root.isType1) {
            glColor4f(1.0f, 1.0f, 1.0f, 1.0f);  // Blanc pour les sommets
        } else {
            // Couleur pour les racines de type 2
            float r = (root.coords[4] + 1.0f) / 2.0f;
            float g = (root.coords[5] + 1.0f) / 2.0f;
            float b = (root.coords[6] + 1.0f) / 2.0f;
            float a = (root.coords[7] + 1.0f) / 2.0f;
            glColor4f(r, g, b, a);
        }
        glVertex3f(x, y, z);
    }
}
glEnd();
}

void drawEdges() {
glBegin(GL_LINES);
for (const auto& edge : EDGES) {
const auto& root1 = E8_ROOTS\[edge.root1\];
const auto& root2 = E8_ROOTS\[edge.root2\];
float t1 = root1.coords\[3\];
float t2 = root2.coords\[3\];
if ((t1 >= timeOffset && t1 <= timeOffset + deltaT) &&
(t2 >= timeOffset && t2 <= timeOffset + deltaT)) {
        // Couleur en fonction de la dimension qui diffère (0=x, 1=y, 2=z, etc.)
        if (edge.diffDim == 0) {
            glColor4f(1.0f, 0.3f, 0.3f, 0.7f);  // Rouge pour x
        } else if (edge.diffDim == 1) {
            glColor4f(0.3f, 1.0f, 0.3f, 0.7f);  // Vert pour y
        } else if (edge.diffDim == 2) {
            glColor4f(0.3f, 0.3f, 1.0f, 0.7f);  // Bleu pour z
        } else {
            glColor4f(0.7f, 0.7f, 0.7f, 0.7f);  // Gris pour les autres dimensions
        }

        glVertex3f(root1.coords[0], root1.coords[1], root1.coords[2]);
        glVertex3f(root2.coords[0], root2.coords[1], root2.coords[2]);
    }
}
glEnd();
}

void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Positionner la caméra
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, 1.0, 0.1, 100.0);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, 5.0,  // Position de la caméra
          0.0, 0.0, 0.0,  // Point visé
          0.0, 1.0, 0.0); // Vecteur "up"

// Appliquer une rotation
glRotatef(rotationAngle, 0.5f, 1.0f, 0.0f);

// Dessiner le fond étoilé
// drawBackground();

// Dessiner les arêtes en premier (pour qu'elles soient derrière les points)
drawEdges();

// Dessiner les points
drawPoints();

glutSwapBuffers();

}

void timer(int value) {
if (animateTime) {
timeOffset += 0.01f;
if (timeOffset > 1.0f) {
timeOffset = -1.0f;
}
}
rotationAngle += 1;
if (rotationAngle > 360) {
rotationAngle = 0;
}
glutPostRedisplay();
glutTimerFunc(16, timer, 0);  // 60 FPS
}

void keyboard(unsigned char key, int x, int y) {
if (key == ' ') {
animateTime = !animateTime;
std::cout << "Animation temporelle : " << (animateTime ? "ACTIVÉE" : "DÉSACTIVÉE") << std::endl;
}
if (key == 'a' || key == 'A') {
deltaT = (deltaT == 0.2f) ? 1.0f : 0.2f;
std::cout << "deltaT = " << deltaT << " (";
std::cout << (deltaT == 1.0f ? "Cube complet" : "Balayage temporel") << ")" << std::endl;
}
if (key == 27) {  // Échap
exit(0);
}
}

int main(int argc, char\*\* argv) {
// Initialiser le générateur de nombres aléatoires pour le fond étoilé
srand(time(0));

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 600);
glutCreateWindow("E8 Roots Animation (GLUT) - Arêtes colorées + Fond étoilé");

init();

glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutTimerFunc(0, timer, 0);

std::cout << "Contrôles : " << std::endl;
std::cout << "- ESPACE : Pause/Reprise de l'animation temporelle" << std::endl;
std::cout << "- A : Basculer entre cube complet (deltaT=1.0) et balayage (deltaT=0.2)" << std::endl;
std::cout << "- ÉCHAP : Quitter" << std::endl;

glutMainLoop();
return 0;

}

It only compute/display the 240 roots for the instant but this E8 space seem be very mathematicaly/physicaly/géometrically “magic” and I want to add the dispaly of somes others “quasi-magics” particularities of the 8D space

Note than E8 is a fascinating mathematical object that bridges algebra, geometry, physics, and even computer science. Its 240-root system and exceptional symmetry make it a recurring theme in a lot of (very very) advanced theories

@+
Cyclone

Can you include some screenshots of an output? :thinking: Because I’m too much lazy to build it by my own :grimacing: