// Code written by Andy Huchala based on a joint program written with Jonathan Lee.
// This implementation uses long long so I think it needs to run on a 64 bit machine.

// This program computes dimensions for which there exist 8 or more non-isomorphic irreducible E6 representations.
// See OEIS A343266.

// Compile the program with the following command: g++ e6_new.cpp -o e6_new.exe -w

// This implementation takes advantage of the dualities present in the E6 dynkin diagram.
// Invariant under swapping both dual pairs at same time: x0<-> x4, x1<-> x3 in the ordering imported from mathematica.

#include <iostream>
#include <queue>
#include <fstream>
#include <stdio.h>
#include <math.h>
#include <set>

// Requires this file in the same directory, available at https://github.com/sercantutar/infint/blob/master/InfInt.h
#include "InfInt.h" 


class Pair {
public:
	// Stores coordinates in 96 bits: 64 + 32 bit
	std::pair<long long, int> coordinates;
	long double log;

	Pair(const std::pair<long long, int> & coordinates, const long double & log) {
		this->coordinates = coordinates;
		this->log = log;
	}
};

bool operator<(const Pair & p1, const Pair & p2) {
    return p1.log > p2.log;
}

int main() {

// checking up to 2^16 should get you at least 65 digits, i.e. [2^16-1,0,0,0,0,0] has dim 432199258280946504763829243161882977114556067368648124986539450368
	const unsigned short int UPPER_BOUND_FACTOR = -1;

	long double* cachedLogs = (long double*) malloc(sizeof (long double) * UPPER_BOUND_FACTOR);
	const long long i1 = 1LL;
	const long long i16 = 16LL;
	const long long i32 = 32LL;
	const long long i48 = 48LL;

	const int i1_32bit = 1;

	const int i16_32bit = 16;

	const long i1shift16 = (1LL << 16LL) - 1LL;

	const int i1shift16_32bit = (1 << 16) - 1;

	const int cums[4] = {0, 16, 32, 48};

	const InfInt denom = "23361421521715200000";
	InfInt dim1 = "1";
	InfInt dim2 = "0";

	for (long i = 1; i < UPPER_BOUND_FACTOR; i++) {
		cachedLogs[i] = std::log ( i);
    }

    std::pair<long long, int> newPair = {0LL, 0};

    std::priority_queue<Pair> fringe;
	std::set<std::pair<long long, int>> seen;
	
	const long long numToCompute = 20000;

	int numSeen = 1;

	fringe.push(Pair(newPair, 99.6740257330631));

	long double lastLog = 0.0;

	long long newCoord;
	
	long double newIrrep;
	long long curCoord1;
	int curCoord2;

	unsigned short int x0; unsigned short int x1; unsigned short int x2;
	unsigned short int x3; unsigned short int x4; unsigned short int x5;
	std::cout<< "Initialization complete\n";

	std::ofstream myfile ("e6_rep.txt");
	if (myfile.is_open()) {

		int triple = 0;
		int quad = 0;
		int quint = 0;
		int hext = 0;
		int sept = 0;
		int oct = 0;
		int count_double = 0;

		while (numSeen < numToCompute) {
			Pair cur = fringe.top();
			fringe.pop();
			seen.erase(cur.coordinates);
			curCoord1 = cur.coordinates.first;
			curCoord2 = cur.coordinates.second;

			x0 = (unsigned short int) (curCoord1 & i1shift16) + 1;
			x1 = (unsigned short int) ((curCoord1 >> i16) & i1shift16) + 1;
			x2 = (unsigned short int) ((curCoord1 >> i32) & i1shift16) + 1;
			x3 = (unsigned short int) ((curCoord1 >> i48) & i1shift16) + 1;
			x4 = (unsigned short int) (curCoord2 & i1shift16_32bit) + 1;
			x5 = (unsigned short int) ((curCoord2 >> i16_32bit) & i1shift16_32bit) + 1;

			dim1 = "1";
			dim1 *= (x0);
			dim1 *= (x1);
			dim1 *= (x2);
			dim1 *= (x3);
			dim1 *= (x4);
			dim1 *= (x5);
			dim1 *= (x0+x1);
			dim1 *= (x1+x2);
			dim1 *= (x2+x3);
			dim1 *= (x2+x5);
			dim1 *= (x3+x4);
			dim1 *= (x0+x1+x2);
			dim1 *= (x1+x2+x3);
			dim1 *= (x1+x2+x5);
			dim1 *= (x2+x3+x4);
			dim1 *= (x2+x3+x5);
			dim1 *= (x0+x1+x2+x3);
			dim1 *= (x0+x1+x2+x5);
			dim1 *= (x1+x2+x3+x4);
			dim1 *= (x1+x2+x3+x5);
			dim1 *= (x1+2*x2+x3+x5);
			dim1 *= (x2+x3+x4+x5);
			dim1 *= (x0+x1+x2+x3+x4);
			dim1 *= (x0+x1+x2+x3+x5);
			dim1 *= (x0+x1+2*x2+x3+x5);
			dim1 *= (x0+2*x1+2*x2+x3+x5);
			dim1 *= (x1+x2+x3+x4+x5);
			dim1 *= (x1+2*x2+x3+x4+x5);
			dim1 *= (x1+2*x2+2*x3+x4+x5);
			dim1 *= (x0+x1+x2+x3+x4+x5);
			dim1 *= (x0+x1+2*x2+x3+x4+x5);
			dim1 *= (x0+2*x1+2*x2+x3+x4+x5);
			dim1 *= (x0+x1+2*x2+2*x3+x4+x5);
			dim1 *= (x0+2*x1+2*x2+2*x3+x4+x5);
			dim1 *= (x0+2*x1+3*x2+2*x3+x4+x5);
			dim1 *= (x0+2*x1+3*x2+2*x3+x4+2*x5);
			dim1 /= denom;

			count_double = ((x4 > x0) && (x3 >= x1))||((x4 >= x0) && (x3 > x1));

			if (dim1 == dim2) {
				if (triple) {
					if (quad) {
						if (quint) {
							if (hext) {
								if (sept) {
									if ( oct ||  count_double) {
										myfile <<std::to_string(numSeen) + " " +(dim1.toString())+ "\n";
										// std::cout<< std::to_string(x0)+ " "+ std::to_string(x1)+ " "+ std::to_string(x2)+ " "+ std::to_string(x3)+ " "+  std::to_string(x4)+ " "+std::to_string(x5)+"\n";
										std::cout<< std::to_string(numSeen) + " " +(dim1.toString())+ "\n";
										numSeen++;
									} else {
										oct = 1;
									}
								} else {
									sept = 1;
									if (count_double) {
										oct = 1;
									}
								}
							} else {
								hext = 1;
								if (count_double) {
									sept = 1;
								}
							}
						} else {
							quint = 1;
							if (count_double) {
								hext = 1;
							}
						}
					} else {
						quad = 1;
						if (count_double) {
							quint = 1;
						}
					}
				} else{
					triple = 1;
					if (count_double) {
						quad = 1;
					}
				}
			} else if (count_double) {
				triple= 1;
				quad = 0;
				quint = 0;
				hext = 0;
				sept = 0;
				oct = 0;
			} else {
				triple= 0;
				quad = 0;
				quint = 0;
				hext = 0;
				sept = 0;
				oct = 0;
			}


			dim2 = dim1;

			for (int i = 0; i < 4; i++) {
				newCoord = curCoord1 + (i1 << cums[i]);
				newPair = {newCoord,curCoord2};
				if (seen.count(newPair)) {
					continue;
				}
				x0 = (unsigned short int) (newCoord & i1shift16) + 1;
				x1 = (unsigned short int) ((newCoord >> i16) & i1shift16) + 1;
				x2 = (unsigned short int) ((newCoord >> i32) & i1shift16) + 1;
				x3 = (unsigned short int) ((newCoord >> i48) & i1shift16) + 1;
				x4 = (unsigned short int) (curCoord2 & i1shift16_32bit) + 1;
				x5 = (unsigned short int) ((curCoord2 >> i16_32bit) & i1shift16_32bit) + 1;

				if (((x4 < x0) && (x3 <= x1))||((x4 <= x0) && (x3 < x1))) {
					continue;
				}

				// std::cout<< std::to_string(x0)+ " " +std::to_string(x1)+ " " +std::to_string(x2)+ " " +std::to_string(x3)+ " " +std::to_string(x4)+ " " +std::to_string(x5)+ " " +std::to_string(x6)+"\n";
				
				newIrrep = 0;

				newIrrep += cachedLogs[x0];
				newIrrep += cachedLogs[x1];
				newIrrep += cachedLogs[x2];
				newIrrep += cachedLogs[x3];
				newIrrep += cachedLogs[x4];
				newIrrep += cachedLogs[x5];
				newIrrep += cachedLogs[x0+x1];
				newIrrep += cachedLogs[x1+x2];
				newIrrep += cachedLogs[x2+x3];
				newIrrep += cachedLogs[x2+x5];
				newIrrep += cachedLogs[x3+x4];
				newIrrep += cachedLogs[x0+x1+x2];
				newIrrep += cachedLogs[x1+x2+x3];
				newIrrep += cachedLogs[x1+x2+x5];
				newIrrep += cachedLogs[x2+x3+x4];
				newIrrep += cachedLogs[x2+x3+x5];
				newIrrep += cachedLogs[x0+x1+x2+x3];
				newIrrep += cachedLogs[x0+x1+x2+x5];
				newIrrep += cachedLogs[x1+x2+x3+x4];
				newIrrep += cachedLogs[x1+x2+x3+x5];
				newIrrep += cachedLogs[x1+2*x2+x3+x5];
				newIrrep += cachedLogs[x2+x3+x4+x5];
				newIrrep += cachedLogs[x0+x1+x2+x3+x4];
				newIrrep += cachedLogs[x0+x1+x2+x3+x5];
				newIrrep += cachedLogs[x0+x1+2*x2+x3+x5];
				newIrrep += cachedLogs[x0+2*x1+2*x2+x3+x5];
				newIrrep += cachedLogs[x1+x2+x3+x4+x5];
				newIrrep += cachedLogs[x1+2*x2+x3+x4+x5];
				newIrrep += cachedLogs[x1+2*x2+2*x3+x4+x5];
				newIrrep += cachedLogs[x0+x1+x2+x3+x4+x5];
				newIrrep += cachedLogs[x0+x1+2*x2+x3+x4+x5];
				newIrrep += cachedLogs[x0+2*x1+2*x2+x3+x4+x5];
				newIrrep += cachedLogs[x0+x1+2*x2+2*x3+x4+x5];
				newIrrep += cachedLogs[x0+2*x1+2*x2+2*x3+x4+x5];
				newIrrep += cachedLogs[x0+2*x1+3*x2+2*x3+x4+x5];
				newIrrep += cachedLogs[x0+2*x1+3*x2+2*x3+x4+2*x5];

				fringe.push(Pair(newPair, newIrrep));
				seen.insert(newPair);
			}

			for (int i = 0; i < 2; i++) {
				newCoord = curCoord2 + (i1_32bit << cums[i]);
				newPair = {curCoord1,newCoord};
				if (seen.count(newPair)) {
					continue;
				}
				x0 = (unsigned short int) (curCoord1 & i1shift16) + 1;
				x1 = (unsigned short int) ((curCoord1 >> i16) & i1shift16) + 1;
				x2 = (unsigned short int) ((curCoord1 >> i32) & i1shift16) + 1;
				x3 = (unsigned short int) ((curCoord1 >> i48) & i1shift16) + 1;
				x4 = (unsigned short int) (newCoord & i1shift16_32bit) + 1;
				x5 = (unsigned short int) ((newCoord >> i16_32bit) & i1shift16_32bit) + 1;
				// don't add dual pairs
				if (((x4 < x0) && (x3 <= x1))||((x4 <= x0) && (x3 < x1))) {
					continue;
				}

				// std::cout<< std::to_string(x0)+ " " +std::to_string(x1)+ " " +std::to_string(x2)+ " " +std::to_string(x3)+ " " +std::to_string(x4)+ " " +std::to_string(x5)+ " " +std::to_string(x6)+"\n";
				
				newIrrep = 0;

				newIrrep += cachedLogs[x0];
				newIrrep += cachedLogs[x1];
				newIrrep += cachedLogs[x2];
				newIrrep += cachedLogs[x3];
				newIrrep += cachedLogs[x4];
				newIrrep += cachedLogs[x5];
				newIrrep += cachedLogs[x0+x1];
				newIrrep += cachedLogs[x1+x2];
				newIrrep += cachedLogs[x2+x3];
				newIrrep += cachedLogs[x2+x5];
				newIrrep += cachedLogs[x3+x4];
				newIrrep += cachedLogs[x0+x1+x2];
				newIrrep += cachedLogs[x1+x2+x3];
				newIrrep += cachedLogs[x1+x2+x5];
				newIrrep += cachedLogs[x2+x3+x4];
				newIrrep += cachedLogs[x2+x3+x5];
				newIrrep += cachedLogs[x0+x1+x2+x3];
				newIrrep += cachedLogs[x0+x1+x2+x5];
				newIrrep += cachedLogs[x1+x2+x3+x4];
				newIrrep += cachedLogs[x1+x2+x3+x5];
				newIrrep += cachedLogs[x1+2*x2+x3+x5];
				newIrrep += cachedLogs[x2+x3+x4+x5];
				newIrrep += cachedLogs[x0+x1+x2+x3+x4];
				newIrrep += cachedLogs[x0+x1+x2+x3+x5];
				newIrrep += cachedLogs[x0+x1+2*x2+x3+x5];
				newIrrep += cachedLogs[x0+2*x1+2*x2+x3+x5];
				newIrrep += cachedLogs[x1+x2+x3+x4+x5];
				newIrrep += cachedLogs[x1+2*x2+x3+x4+x5];
				newIrrep += cachedLogs[x1+2*x2+2*x3+x4+x5];
				newIrrep += cachedLogs[x0+x1+x2+x3+x4+x5];
				newIrrep += cachedLogs[x0+x1+2*x2+x3+x4+x5];
				newIrrep += cachedLogs[x0+2*x1+2*x2+x3+x4+x5];
				newIrrep += cachedLogs[x0+x1+2*x2+2*x3+x4+x5];
				newIrrep += cachedLogs[x0+2*x1+2*x2+2*x3+x4+x5];
				newIrrep += cachedLogs[x0+2*x1+3*x2+2*x3+x4+x5];
				newIrrep += cachedLogs[x0+2*x1+3*x2+2*x3+x4+2*x5];

				fringe.push(Pair(newPair, newIrrep));
				seen.insert(newPair);
			}


		}
		myfile.close();
	}
	free(cachedLogs);

    return 0;
}