﻿#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <time.h>

// --- System Constants ---
#define PHI 1.6180339887
#define MAX_INSTANCES 8388608
#define SLOTS_PER_INSTANCE 4
#define MAX_SLOTS (MAX_INSTANCES * SLOTS_PER_INSTANCE)
#define CHUNK_SIZE 1048576 // 1M slots per chunk
#define MSB_MASK (1ULL << 63) // Mask for the Most Significant Bit of a uint64_t

// --- Future MPI and Base-4096 Constants ---
#define BASE_4096_BPC 12        // Bits per Character (4096 = 2^12)
#define MPI_INITIAL_WORDS 1     // Initial allocation size for MPI structures
#define MPI_ZERO_WORD 0ULL      // Canonical zero for MPI operations

// Fibonacci and prime tables
static const float fib_table[] = {1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987};
static const float prime_table[] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
static const int fib_len = 16;
static const int prime_len = 16;

// Helper for generating normalized random double
double get_normalized_rand() {
    return (double)rand() / RAND_MAX;
}

// Macro for generating 64-bit random seed (Placeholder for get_random_bytes in kernel)
#define GET_RANDOM_UINT64() (((uint64_t)rand() << 32) | rand())

// â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”
// FUTURE-PROOF MPI (Multi-Word Integer) and State Flags
// â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”

// Multi-Word Integer (MPI) Structure for arbitrarily large metadata
typedef struct {
    uint64_t *words;        // Array of 64-bit words for the number
    size_t num_words;       // Number of words currently allocated
    uint8_t sign;           // 0: Positive, 1: Negative
} MPI;

// State Flags Definitions for Implied Precision
#define APA_FLAG_SIGN_NEG           (1 << 0) // Mantissa is negative
#define APA_FLAG_IS_NAN             (1 << 1) // Not a Number
#define APA_FLAG_GOI                (1 << 2) // Gradual Overflow Infinity
#define APA_FLAG_GUZ                (1 << 3) // Gradual Underflow Zero


// â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”
// Slot4096: Arbitrary Precision Architecture (APA) Structure
// â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”

typedef struct {
    // --- Core Precision Fields ---
    uint64_t *mantissa_words;   // Multi-word array for high-precision mantissa

    // FUTURE-PROOF FIELDS (Conceptual, for 4096^4096+ scaling)
    MPI num_words_mantissa;     // The COUNT of mantissa_words (Arbitrarily wide)
    MPI exponent_mpi;           // The exponent value (Arbitrarily wide)

    // State and Base Control Fields
    uint16_t exponent_base;     // Base of the floating-point system (e.g., 2 or 4096)
    uint32_t state_flags;       // Flags for NaN, Sign, GOI, GUZ
    MPI source_of_infinity;     // Records magnitude for Gradual Overflow Infinity (GOI)

    // LEGACY FIELDS (Used by current 4096-bit functional code)
    size_t num_words;           // Legacy Count of 64-bit words allocated
    int64_t exponent;           // Legacy Signed exponent (Base 2)
    float base;                 // Dynamic base (Ï†-scaled)
    int bits_mant;              // Actual software-managed bit width (e.g., 4096)
    int bits_exp;               // Exponent bit width

} Slot4096;

// -----------------------------------------------------------------------------
// GLOBAL HIGH-PRECISION CONSTANT SLOTS
// -----------------------------------------------------------------------------
static Slot4096 APA_CONST_PHI;  // Target slot for full precision Golden Ratio
static Slot4096 APA_CONST_PI;   // Target slot for full precision Pi


// Forward Declarations for APA Operations
void ap_normalize_legacy(Slot4096 *slot);
void ap_add_legacy(Slot4096 *A, const Slot4096 *B);
void ap_free(Slot4096 *slot);
void ap_copy(Slot4096 *dest, const Slot4096 *src);
double ap_to_double(const Slot4096 *slot);
Slot4096* ap_from_double(double value, int bits_mant, int bits_exp);
void ap_shift_right_legacy(uint64_t *mantissa_words, size_t num_words, int64_t shift_amount);

// Forward Declarations for new MPI/Future APA Operations (Conceptual)
void mpi_init(MPI *m, size_t initial_words);
void mpi_free(MPI *m);
void mpi_copy(MPI *dest, const MPI *src);
void mpi_resize(MPI *m, size_t new_words);
void mpi_set_value(MPI *m, uint64_t value, uint8_t sign);
int mpi_compare(const MPI *A, const MPI *B);
void mpi_add(MPI *A, const MPI *B);
void mpi_subtract(MPI *A, const MPI *B);
size_t mpi_get_effective_words(const MPI *m);
int mpi_count_leading_zeros(const MPI *m);
void ap_shift_right_mpi(uint64_t *mantissa_words, const MPI *num_words, const MPI *shift_amount);
void ap_add_mpi(Slot4096 *A, const Slot4096 *B);

// Wrappers to maintain the main API calls
void ap_add(Slot4096 *A, const Slot4096 *B);
void ap_normalize(Slot4096 *slot) { ap_normalize_legacy(slot); }
void ap_shift_right(uint64_t *mantissa_words, size_t num_words, int64_t shift_amount) { ap_shift_right_legacy(mantissa_words, num_words, shift_amount); }

// -----------------------------------------------------------------------------
// CONCEPTUAL MPI FUNCTION IMPLEMENTATIONS (Placeholder for V3)
// -----------------------------------------------------------------------------

void mpi_init(MPI *m, size_t initial_words) {
    m->words = calloc(initial_words, sizeof(uint64_t));
    m->num_words = initial_words;
    m->sign = 0;
}
void mpi_free(MPI *m) {
    if (m->words) free(m->words);
    m->words = NULL;
    m->num_words = 0;
}
void mpi_copy(MPI *dest, const MPI *src) {
    mpi_free(dest);
    dest->num_words = src->num_words;
    dest->words = (uint64_t*)malloc(src->num_words * sizeof(uint64_t));
    if (src->words && dest->words) {
        memcpy(dest->words, src->words, src->num_words * sizeof(uint64_t));
    }
    dest->sign = src->sign;
}

// Minimal placeholder implementations
void mpi_resize(MPI *m, size_t new_words) { /* TBD */ }
void mpi_set_value(MPI *m, uint64_t value, uint8_t sign) { if (m->words) m->words[0] = value; m->sign = sign; }
int mpi_compare(const MPI *A, const MPI *B) { return 0; }
void mpi_add(MPI *A, const MPI *B) { /* TBD */ }
void mpi_subtract(MPI *A, const MPI *B) { /* TBD */ }
size_t mpi_get_effective_words(const MPI *m) { return m->num_words; }
int mpi_count_leading_zeros(const MPI *m) { return 64; }

void ap_shift_right_mpi(uint64_t *mantissa_words, const MPI *num_words, const MPI *shift_amount) { /* TBD */ }
void ap_add_mpi(Slot4096 *A, const Slot4096 *B) { /* TBD */ }

// -----------------------------------------------------------------------------
// APA UTILITY FUNCTIONS
// -----------------------------------------------------------------------------

// Initialize slot with dynamic precision and APA allocation
Slot4096 slot_init_apa(int bits_mant, int bits_exp) {
    Slot4096 slot = {0};
    slot.bits_mant = bits_mant;
    slot.bits_exp = bits_exp;

    slot.num_words = (bits_mant + 63) / 64;
    slot.mantissa_words = (uint64_t*)calloc(slot.num_words, sizeof(uint64_t));

    // FUTURE-PROOF MPI INITIALIZATION
    mpi_init(&slot.exponent_mpi, MPI_INITIAL_WORDS);
    mpi_init(&slot.num_words_mantissa, MPI_INITIAL_WORDS);
    mpi_init(&slot.source_of_infinity, MPI_INITIAL_WORDS);

    if (!slot.mantissa_words) {
        fprintf(stderr, "Error: Failed to allocate multi-word mantissa.\n");
        return slot;
    }

    if (slot.num_words > 0) {
        slot.mantissa_words[0] = GET_RANDOM_UINT64();
        slot.mantissa_words[0] |= MSB_MASK;
    }

    int64_t exp_range = 1LL << bits_exp;
    int64_t exp_bias = 1LL << (bits_exp - 1);
    slot.exponent = (rand() % exp_range) - exp_bias;
    slot.base = PHI + get_normalized_rand() * 0.01;

    // Set the target base for future MPI operations
    slot.exponent_base = 4096;

    // Synchronize Legacy with MPI (critical for V3 transition)
    mpi_set_value(&slot.exponent_mpi, (uint64_t)llabs(slot.exponent), slot.exponent < 0 ? 1 : 0);
    mpi_set_value(&slot.num_words_mantissa, (uint64_t)slot.num_words, 0);

    return slot;
}

// Helper to free single APA slot's dynamic members (Includes MPI cleanup)
void ap_free(Slot4096 *slot) {
    if (slot) {
        if (slot->mantissa_words) {
            free(slot->mantissa_words);
            slot->mantissa_words = NULL;
        }
        // FUTURE-PROOF MPI CLEANUP
        mpi_free(&slot->exponent_mpi);
        mpi_free(&slot->num_words_mantissa);
        mpi_free(&slot->source_of_infinity);
        slot->num_words = 0;
    }
}

// Deep copy of APA slot (Includes MPI deep copy)
void ap_copy(Slot4096 *dest, const Slot4096 *src) {
    ap_free(dest);

    *dest = *src; // Shallow copy of struct members

    // Deep copy mantissa
    dest->mantissa_words = (uint64_t*)malloc(src->num_words * sizeof(uint64_t));
    if (!dest->mantissa_words) {
        fprintf(stderr, "Error: Failed deep copy allocation.\n");
        dest->num_words = 0;
        return;
    }
    memcpy(dest->mantissa_words, src->mantissa_words, src->num_words * sizeof(uint64_t));

    // Deep copy MPI structs
    mpi_copy(&dest->exponent_mpi, &src->exponent_mpi);
    mpi_copy(&dest->num_words_mantissa, &src->num_words_mantissa);
    mpi_copy(&dest->source_of_infinity, &src->source_of_infinity);
}

// Converts APA to double (Lossy, for display/recursion input)
double ap_to_double(const Slot4096 *slot) {
    if (!slot || slot->num_words == 0 || !slot->mantissa_words) return 0.0;

    // Scale the first word to the range [0.0, 1.0)
    double mantissa_double = (double)slot->mantissa_words[0] / (double)UINT64_MAX;

    return mantissa_double * pow(2.0, (double)slot->exponent);
}

// Converts double to APA slot (Used for the increment_value)
Slot4096* ap_from_double(double value, int bits_mant, int bits_exp) {
    Slot4096 temp_slot = slot_init_apa(bits_mant, bits_exp);
    Slot4096 *slot = (Slot4096*)malloc(sizeof(Slot4096));
    if (!slot) { ap_free(&temp_slot); return NULL; }
    *slot = temp_slot;

    if (value == 0.0) return slot;

    int exp_offset;
    // Breaks value into [0.5, 1.0) * 2^exp_offset
    double mant_val = frexp(value, &exp_offset);

    slot->mantissa_words[0] = (uint64_t)(mant_val * (double)UINT64_MAX);
    slot->exponent = (int64_t)exp_offset;

    // Synchronize Legacy with MPI (critical for V3 transition)
    mpi_set_value(&slot->exponent_mpi, (uint64_t)llabs(slot->exponent), slot->exponent < 0 ? 1 : 0);

    return slot;
}

/**
 * LEGACY Multi-word right shift (Improved safety and clarity)
 */
void ap_shift_right_legacy(uint64_t *mantissa_words, size_t num_words, int64_t shift_amount) {
    if (shift_amount <= 0 || num_words == 0) return;

    if (shift_amount >= (int64_t)num_words * 64) {
        memset(mantissa_words, 0, num_words * sizeof(uint64_t));
        return;
    }

    int64_t word_shift = shift_amount / 64;
    int bit_shift = (int)(shift_amount % 64);

    if (word_shift > 0) {
        // Shift words down (from high index to low index)
        for (size_t i = num_words; i-- > word_shift; ) {
            mantissa_words[i] = mantissa_words[i - word_shift];
        }
        // Zero out the high-order words
        memset(mantissa_words, 0, word_shift * sizeof(uint64_t));
    }

    if (bit_shift > 0) {
        int reverse_shift = 64 - bit_shift;

        // Shift bits within the remaining words
        for (size_t i = num_words; i-- > 0; ) {
            uint64_t upper_carry = 0;
            if (i > 0) {
                // Carry is from the lower word's most significant bits
                upper_carry = mantissa_words[i - 1] << reverse_shift;
            }
            mantissa_words[i] = (mantissa_words[i] >> bit_shift) | upper_carry;
        }
    }
}


// -----------------------------------------------------------------------------
// APA CORE ARITHMETIC FUNCTIONS (FUNCTIONAL WITH ALIGNMENT)
// -----------------------------------------------------------------------------

// Performs multi-word normalization to maintain canonical range [0.5, 1.0)
void ap_normalize_legacy(Slot4096 *slot) {
    if (slot->num_words == 0) return;

    // --- Shift Left (Underflow Correction: Mantissa < 0.5) ---
    while (!(slot->mantissa_words[0] & MSB_MASK)) {
        if (slot->exponent <= -(1LL << (slot->bits_exp - 1))) {
            slot->state_flags |= APA_FLAG_GUZ;
            break;
        }

        uint64_t carry = 0;
        for (size_t i = slot->num_words; i-- > 0; ) {
            uint64_t next_carry = (slot->mantissa_words[i] & MSB_MASK) ? 1 : 0;
            slot->mantissa_words[i] = (slot->mantissa_words[i] << 1) | carry;
            carry = next_carry;
        }
        slot->exponent--;
    }

    // --- Shift Right (Cleanup: Handle Zero) ---
    if (slot->mantissa_words[0] == 0) {
        slot->exponent = 0;
    }
}


// LEGACY Addition with alignment (Called by ap_add wrapper)
void ap_add_legacy(Slot4096 *A, const Slot4096 *B) {
    if (A->num_words != B->num_words) {
        fprintf(stderr, "Error: APA addition failed due to unaligned word counts.\n");
        return;
    }

    Slot4096 B_aligned;
    ap_copy(&B_aligned, B);

    // --- 1. Exponent Alignment (Legacy int64_t logic) ---
    int64_t exp_diff = A->exponent - B_aligned.exponent;

    if (exp_diff > 0) {
        ap_shift_right(B_aligned.mantissa_words, B_aligned.num_words, exp_diff);
        B_aligned.exponent = A->exponent;

    } else if (exp_diff < 0) {
        int64_t shift_amount = -exp_diff;
        ap_shift_right(A->mantissa_words, A->num_words, shift_amount);
        A->exponent = B_aligned.exponent;
    }

    // --- 2. Multi-Word Addition ---
    uint64_t carry = 0;
    size_t num_words = A->num_words;

    for (size_t i = num_words; i-- > 0; ) {
        uint64_t sum = A->mantissa_words[i] + B_aligned.mantissa_words[i] + carry;
        // Check for overflow (sum < initial value or carry from initial value)
        carry = (sum < A->mantissa_words[i] || (sum == A->mantissa_words[i] && carry)) ? 1 : 0;
        A->mantissa_words[i] = sum;
    }

    // --- 3. Final Carry Handling (Future-Proof GOI Check) ---
    if (carry) {
        if (A->exponent >= (1LL << (A->bits_exp - 1))) {
            A->state_flags |= APA_FLAG_GOI;
            // Record magnitude for GOI (conceptual: mpi_copy to source_of_infinity here)
        } else {
            A->exponent += 1;
            // Perform 1-bit right shift using the wrapper (improved logic)
            ap_shift_right(A->mantissa_words, num_words, 1);
            A->mantissa_words[0] |= MSB_MASK; // Re-normalize MSB bit for canonical form
        }
    }

    // --- 4. Final Normalization and Sync (Legacy with MPI) ---
    ap_normalize(A);
    // Synchronize the exponent MPI field *after* normalization
    mpi_set_value(&A->exponent_mpi, (uint64_t)llabs(A->exponent), A->exponent < 0 ? 1 : 0);

    ap_free(&B_aligned);
}

// Public wrapper for addition (Future-proof: Will switch to ap_add_mpi)
void ap_add(Slot4096 *A, const Slot4096 *B) {
    // This function will eventually call ap_add_mpi when MPI is fully implemented.
    ap_add_legacy(A, B);
}


// â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”
// HDGL Lattice (Modified to use APA)
// â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”

typedef struct {
    Slot4096 *slots;
    size_t allocated;
} HDGLChunk;

typedef struct {
    HDGLChunk **chunks;
    int num_chunks;
    int num_instances;
    int slots_per_instance;
    double omega;
    double time;
} HDGLLattice;

// Initialize lattice
HDGLLattice* lattice_init(int num_instances, int slots_per_instance) {
    HDGLLattice *lat = (HDGLLattice*)malloc(sizeof(HDGLLattice));
    if (!lat) return NULL;

    lat->num_instances = num_instances;
    lat->slots_per_instance = slots_per_instance;
    lat->omega = 0.0;
    lat->time = 0.0;

    int total_slots = num_instances * slots_per_instance;
    lat->num_chunks = (total_slots + CHUNK_SIZE - 1) / CHUNK_SIZE;
    lat->chunks = (HDGLChunk**)calloc(lat->num_chunks, sizeof(HDGLChunk*));
    if (!lat->chunks) { free(lat); return NULL; }

    return lat;
}

// Get chunk, allocate if needed
HDGLChunk* lattice_get_chunk(HDGLLattice *lat, int chunk_idx) {
    if (chunk_idx >= lat->num_chunks) return NULL;

    if (!lat->chunks[chunk_idx]) {
        HDGLChunk *chunk = (HDGLChunk*)malloc(sizeof(HDGLChunk));
        if (!chunk) return NULL;

        /* Only allocate as many slots as actually belong to this chunk.
         * CHUNK_SIZE (1M) is the maximum; real lattices are far smaller
         * and allocating 1M APA slots with malloc-per-slot causes OOM/crash. */
        int total_slots    = lat->num_instances * lat->slots_per_instance;
        int chunk_start    = chunk_idx * CHUNK_SIZE;
        int slots_in_chunk = total_slots - chunk_start;
        if (slots_in_chunk > CHUNK_SIZE) slots_in_chunk = CHUNK_SIZE;
        if (slots_in_chunk <= 0) { free(chunk); return NULL; }

        chunk->allocated = (size_t)slots_in_chunk;
        chunk->slots = (Slot4096*)malloc((size_t)slots_in_chunk * sizeof(Slot4096));
        if (!chunk->slots) { free(chunk); return NULL; }

        for (int i = 0; i < slots_in_chunk; i++) {
            int bits_mant = 4096 + (i % 8) * 64;
            int bits_exp  = 16   + (i % 8) * 2;
            chunk->slots[i] = slot_init_apa(bits_mant, bits_exp);
        }
        lat->chunks[chunk_idx] = chunk;
    }

    return lat->chunks[chunk_idx];
}

// Get slot pointer
Slot4096* lattice_get_slot(HDGLLattice *lat, int idx) {
    int chunk_idx = idx / CHUNK_SIZE;
    int local_idx = idx % CHUNK_SIZE;
    HDGLChunk *chunk = lattice_get_chunk(lat, chunk_idx);
    if (!chunk) return NULL;
    return &chunk->slots[local_idx];
}

// Prismatic recursion function (MUST use lossy double for calculation input)
double prismatic_recursion(HDGLLattice *lat, int idx, double val) {
    double phi_harm = pow(PHI, (double)(idx % 16));
    double fib_harm = fib_table[idx % fib_len];
    double dyadic = (double)(1 << (idx % 16));
    double prime_harm = prime_table[idx % prime_len];
    double omega_val = 0.5 + 0.5 * sin(lat->time + idx * 0.01);
    double r_dim = pow(val, (double)((idx % 7) + 1));

    return sqrt(phi_harm * fib_harm * dyadic * prime_harm * omega_val) * r_dim;
}

// CPU step with APA processing
void lattice_step_cpu(HDGLLattice *lat, double tick) {
    int total_slots = lat->num_instances * lat->slots_per_instance;

    for (int i = 0; i < total_slots; i++) {
        Slot4096 *slot = lattice_get_slot(lat, i);
        if (!slot) continue;

        // Check for Implied Precision State
        if (slot->state_flags & (APA_FLAG_GOI | APA_FLAG_IS_NAN)) {
            continue;
        }

        double val = ap_to_double(slot);
        double r = prismatic_recursion(lat, i, val);

        double increment_value = pow(slot->base, (double)slot->exponent) * tick + 0.05 * r;

        Slot4096 *increment_apa = ap_from_double(
            increment_value, slot->bits_mant, slot->bits_exp
        );
        if (!increment_apa) continue;

        ap_add(slot, increment_apa);

        ap_free(increment_apa);
        free(increment_apa);
    }

    lat->omega += 0.01 * tick;
    lat->time += tick;
}

// Prismatic folding: double instance count
void lattice_fold(HDGLLattice *lat) {
    int old_instances = lat->num_instances;
    int new_instances = old_instances * 2;
    if (new_instances > MAX_INSTANCES) return;

    int old_total = old_instances * lat->slots_per_instance;
    int new_total = new_instances * lat->slots_per_instance;
    int old_chunks = lat->num_chunks;
    int new_chunks = (new_total + CHUNK_SIZE - 1) / CHUNK_SIZE;

    HDGLChunk **new_chunks_ptr = (HDGLChunk**)realloc(lat->chunks, new_chunks * sizeof(HDGLChunk*));
    if (!new_chunks_ptr) {
        fprintf(stderr, "Failed to allocate memory for folding\n");
        return;
    }
    lat->chunks = new_chunks_ptr;

    for (int i = old_chunks; i < new_chunks; i++) {
        lat->chunks[i] = NULL;
    }

    for (int i = 0; i < old_total; i++) {
        Slot4096 *old_slot = lattice_get_slot(lat, i);
        Slot4096 *new_slot = lattice_get_slot(lat, old_total + i);

        if (old_slot && new_slot) {
            ap_copy(new_slot, old_slot);

            double perturbation = fib_table[i % fib_len] * 0.01;
            Slot4096 *pert_apa = ap_from_double(perturbation, new_slot->bits_mant, new_slot->bits_exp);

            if (pert_apa) {
                ap_add(new_slot, pert_apa);
                ap_free(pert_apa);
                free(pert_apa);
            }

            new_slot->base += get_normalized_rand() * 0.001;
        }
    }

    lat->num_instances = new_instances;
    lat->num_chunks = new_chunks;
}

// Free lattice: MUST handle freeing multi-word mantissa in every slot
void lattice_free(HDGLLattice *lat) {
    if (!lat) return;

    for (int i = 0; i < lat->num_chunks; i++) {
        if (lat->chunks[i]) {
            for (size_t j = 0; j < CHUNK_SIZE; j++) {
                ap_free(&lat->chunks[i]->slots[j]);
            }
            free(lat->chunks[i]->slots);
            free(lat->chunks[i]);
        }
    }
    free(lat->chunks);
    free(lat);
}

// â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”
// Bootloader Integration and Main Demo
// â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”â”

// New function to initialize the high-precision constant slots
void init_apa_constants() {
    APA_CONST_PHI = slot_init_apa(4096, 16);
    APA_CONST_PI = slot_init_apa(4096, 16);

    // Placeholder: Set with double precision for demonstration
    Slot4096 *temp_phi = ap_from_double(1.6180339887, APA_CONST_PHI.bits_mant, APA_CONST_PHI.bits_exp);
    ap_copy(&APA_CONST_PHI, temp_phi);
    ap_free(temp_phi);
    free(temp_phi);

    Slot4096 *temp_pi = ap_from_double(3.1415926535, APA_CONST_PI.bits_mant, APA_CONST_PI.bits_exp);
    ap_copy(&APA_CONST_PI, temp_pi);
    ap_free(temp_pi);
    free(temp_pi);

    printf("[Bootloader] High-precision constant slots (PHI, PI) initialized.\n");
}

void bootloader_init_lattice(HDGLLattice *lat, int steps) {
    printf("[Bootloader] Initializing HDGL lattice with FUTURE-PROOF APA V2.1...\n");
    if (!lat) { printf("[Bootloader] ERROR: Lattice allocation failed.\n"); return; }

    init_apa_constants();

    printf("[Bootloader] %d instances, %d total slots\n",
           lat->num_instances, lat->num_instances * lat->slots_per_instance);

    for (int i = 0; i < steps; i++) {
        lattice_step_cpu(lat, 0.01);
    }

    printf("[Bootloader] Lattice seeded with %d steps\n", steps);
    printf("[Bootloader] Omega: %.6f, Time: %.6f\n", lat->omega, lat->time);
}

int main() {
    srand(time(NULL));

    printf("=== HDGL Unified System (Future-Proof APA V2.1: MPI API Defined) ===\n\n");

    HDGLLattice *lat = lattice_init(4096, 4);
    if (!lat) { fprintf(stderr, "Fatal: Could not initialize lattice.\n"); return 1; }

    bootloader_init_lattice(lat, 50);

    // Show high-precision constant values
    printf("\nHigh-Precision Constants (Legacy Display):\n");
    printf("  PHI: value=%.10e exp=%ld words=%zu\n", ap_to_double(&APA_CONST_PHI), APA_CONST_PHI.exponent, APA_CONST_PHI.num_words);
    printf("  PI: value=%.10e exp=%ld words=%zu\n", ap_to_double(&APA_CONST_PI), APA_CONST_PI.exponent, APA_CONST_PI.num_words);

    // Show some slot values (Display is lossy, but internal state is 4096-bit)
    printf("\nFirst 8 slot values (after seeding):\n");
    for (int i = 0; i < 8; i++) {
        Slot4096 *slot = lattice_get_slot(lat, i);
        if (slot) {
            printf("  D%d: value=%.6e base=%.6f exp=%ld bits=%d/%d words=%zu flags=%d\n",
                    i+1, ap_to_double(slot), slot->base, slot->exponent,
                    slot->bits_mant, slot->bits_exp, slot->num_words, slot->state_flags);
        }
    }

    printf("\nTesting prismatic folding...\n");
    lattice_fold(lat);
    printf("  After:  %d instances\n", lat->num_instances);

    // Clean up global constants
    ap_free(&APA_CONST_PHI);
    ap_free(&APA_CONST_PI);

    lattice_free(lat);

    printf("\n=== System is structurally ready for MPI scaling to 4096^4096 ===\n");
    return 0;
}
