/* ============================================================================ * PLASTICITY TRACKER - Nodal Growth Metrics * Fractal Brain Cheat Sheet: Nodal Growth = Plasticity * = Grid's ability to reshape itself to find a "cooler" path * ============================================================================ */ #include #include #include #include #include #include #include #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #define NX 1024 #define NY 1024 #define NN (NX * NY) #define Q 9 #define BLOCK 256 #define GBLK(n) (((n) + BLOCK - 1) / BLOCK) #define TOTAL_STEPS 300000 // ~1 minute #define STEPS_PER_BATCH 500 #define SAMPLE_INTERVAL 10000 #define OMEGA 1.0f /* ---- Plasticity Parameters --------------------------------------------- */ #define PLASTICITY_RATE 0.001f // How fast connections adapt #define MIN_STRENGTH 0.1f // Minimum connection strength #define MAX_STRENGTH 5.0f // Maximum connection strength #define ADAPTATION_WINDOW 1000 // Steps for adaptation measurement /* ---- Connection Structure ---------------------------------------------- */ typedef struct { float strength[Q]; // Connection strength for each direction float usage[Q]; // How much each direction is used float efficiency; // Current flow efficiency (0-1) float last_adaptation; // When last adapted float plasticity; // Current plasticity level (0-1) } NodeConnections; NodeConnections* connections = nullptr; // Will allocate on host /* ---- Plasticity Metrics ------------------------------------------------ */ float total_plasticity = 0.0f; // Sum of all node plasticity float avg_adaptation_rate = 0.0f; // Average adaptation rate float grid_efficiency = 0.0f; // Overall grid efficiency float structural_change = 0.0f; // How much grid has changed /* ---- D2Q9 --------------------------------------------------------------- */ __constant__ int d_ex[Q] = { 0, 1, 0,-1, 0, 1,-1,-1, 1 }; __constant__ int d_ey[Q] = { 0, 0, 1, 0,-1, 1, 1,-1,-1 }; __constant__ float d_w[Q] = { 4.f/9, 1.f/9, 1.f/9, 1.f/9, 1.f/9, 1.f/36,1.f/36,1.f/36,1.f/36 }; /* ======================================================================== */ /* K E R N E L S */ /* ======================================================================== */ /* ---- LBM collide & stream with plasticity ----------------------------- */ __global__ void lbm_collide_stream_plastic(const float* __restrict__ f_src, float* __restrict__ f_dst, float* __restrict__ rho, float* __restrict__ ux, float* __restrict__ uy, float* __restrict__ strength, float* __restrict__ usage, float omega, int nx, int ny) { const int idx = blockIdx.x * blockDim.x + threadIdx.x; const int N = nx * ny; if (idx >= N) return; const int x = idx % nx, y = idx / nx; float fl[Q]; float total_strength = 0.0f; // Apply connection strengths for (int i = 0; i < Q; i++) { int sx = (x - d_ex[i] + nx) % nx; int sy = (y - d_ey[i] + ny) % ny; float s = strength[i * N + sy * nx + sx]; fl[i] = f_src[i * N + sy * nx + sx] * s; total_strength += s; } // Normalize by total strength if (total_strength > 0.0f) { float inv = 1.0f / total_strength; for (int i = 0; i < Q; i++) { fl[i] *= inv; } } float rho_val = 0.f, ux_val = 0.f, uy_val = 0.f; for (int i = 0; i < Q; i++) { rho_val += fl[i]; ux_val += (float)d_ex[i] * fl[i]; uy_val += (float)d_ey[i] * fl[i]; } float inv = 1.f / fmaxf(rho_val, 1e-10f); ux_val *= inv; uy_val *= inv; rho[idx] = rho_val; ux[idx] = ux_val; uy[idx] = uy_val; const float u2 = ux_val * ux_val + uy_val * uy_val; for (int i = 0; i < Q; i++) { float eu = (float)d_ex[i] * ux_val + (float)d_ey[i] * uy_val; float feq = d_w[i] * rho_val * (1.f + 3.f*eu + 4.5f*eu*eu - 1.5f*u2); f_dst[i * N + idx] = fl[i] - omega * (fl[i] - feq); // Track usage (how much this direction is used) float usage_val = fabsf(fl[i] - feq); atomicAdd(&usage[i * N + idx], usage_val); } } /* ---- Update connection strengths (plasticity) ------------------------- */ __global__ void update_plasticity(float* strength, float* usage, float plasticity_rate, int nx, int ny) { const int idx = blockIdx.x * blockDim.x + threadIdx.x; const int N = nx * ny; if (idx >= N) return; // Find most used direction float max_usage = 0.0f; int best_dir = 0; float total_usage = 0.0f; for (int i = 0; i < Q; i++) { float u = usage[i * N + idx]; total_usage += u; if (u > max_usage) { max_usage = u; best_dir = i; } } // Strengthen most used direction, weaken others if (total_usage > 0.0f) { for (int i = 0; i < Q; i++) { float current = strength[i * N + idx]; if (i == best_dir) { // Strengthen strength[i * N + idx] = fminf(current + plasticity_rate, MAX_STRENGTH); } else { // Weaken strength[i * N + idx] = fmaxf(current - plasticity_rate * 0.1f, MIN_STRENGTH); } } } // Reset usage for next measurement window for (int i = 0; i < Q; i++) { usage[i * N + idx] = 0.0f; } } /* ======================================================================== */ /* P L A S T I C I T Y M E T R I C S */ /* ======================================================================== */ void calculate_plasticity_metrics(float* h_strength, float* initial_strength, uint64_t current_step, int adaptation_cycles) { if (adaptation_cycles == 0) return; float total_change = 0.0f; float total_efficiency = 0.0f; int adaptive_nodes = 0; for (int idx = 0; idx < NN; idx++) { float node_change = 0.0f; float node_efficiency = 0.0f; float max_strength = 0.0f; float strength_sum = 0.0f; for (int i = 0; i < Q; i++) { float current = h_strength[i * NN + idx]; float initial = initial_strength[i * NN + idx]; float change = fabsf(current - initial); node_change += change; node_efficiency += current * d_w[i]; // Weight by lattice weight strength_sum += current; if (current > max_strength) max_strength = current; } total_change += node_change / Q; // Average per direction total_efficiency += (max_strength / strength_sum); // Directionality efficiency // Count adaptive nodes (significant change) if (node_change / Q > 0.1f) { adaptive_nodes++; } } // Update global metrics structural_change = total_change / NN; grid_efficiency = total_efficiency / NN; avg_adaptation_rate = structural_change / adaptation_cycles; total_plasticity = (float)adaptive_nodes / NN; // Percentage of adaptive nodes // Update node connections on host for (int idx = 0; idx < NN; idx++) { connections[idx].plasticity = 0.0f; connections[idx].efficiency = 0.0f; for (int i = 0; i < Q; i++) { connections[idx].strength[i] = h_strength[i * NN + idx]; connections[idx].efficiency += h_strength[i * NN + idx] * d_w[i]; } // Calculate node plasticity (how much it has changed recently) float node_change = 0.0f; for (int i = 0; i < Q; i++) { float initial = initial_strength[i * NN + idx]; float current = h_strength[i * NN + idx]; node_change += fabsf(current - initial); } connections[idx].plasticity = node_change / Q; connections[idx].last_adaptation = node_change; } } /* ---- Save Plasticity Metrics ------------------------------------------ */ void save_plasticity_metrics(uint64_t current_step, int adaptation_cycles) { // Summary CSV FILE* csv = fopen("plasticity_summary.csv", "w"); if (!csv) return; fprintf(csv, "step,structural_change,grid_efficiency,adaptation_rate,total_plasticity,adaptive_nodes,adaptation_cycles\n"); fprintf(csv, "%llu,%.6f,%.6f,%.6f,%.6f,%d,%d\n", current_step, structural_change, grid_efficiency, avg_adaptation_rate, total_plasticity, (int)(total_plasticity * NN), adaptation_cycles); fclose(csv); // Detailed node metrics (sample every 100th node) FILE* detail = fopen("plasticity_nodes.csv", "w"); if (!detail) return; fprintf(detail, "node_id,x,y,plasticity,efficiency,avg_strength,max_strength,strength_variance\n"); for (int idx = 0; idx < NN; idx += 100) { // Sample 1% of nodes int x = idx % NX; int y = idx / NX; float avg_strength = 0.0f; float max_strength = 0.0f; float variance = 0.0f; for (int i = 0; i < Q; i++) { float s = connections[idx].strength[i]; avg_strength += s; if (s > max_strength) max_strength = s; } avg_strength /= Q; for (int i = 0; i < Q; i++) { float diff = connections[idx].strength[i] - avg_strength; variance += diff * diff; } variance /= Q; fprintf(detail, "%d,%d,%d,%.6f,%.6f,%.6f,%.6f,%.6f\n", idx, x, y, connections[idx].plasticity, connections[idx].efficiency, avg_strength, max_strength, variance); } fclose(detail); // JSON summary FILE* json = fopen("plasticity_metrics.json", "w"); if (!json) return; fprintf(json, "{\n"); fprintf(json, " \"current_step\": %llu,\n", current_step); fprintf(json, " \"structural_change\": %.6f,\n", structural_change); fprintf(json, " \"grid_efficiency\": %.6f,\n", grid_efficiency); fprintf(json, " \"adaptation_rate\": %.6f,\n", avg_adaptation_rate); fprintf(json, " \"total_plasticity\": %.6f,\n", total_plasticity); fprintf(json, " \"adaptive_nodes\": %d,\n", (int)(total_plasticity * NN)); fprintf(json, " \"adaptation_cycles\": %d,\n", adaptation_cycles); fprintf(json, " \"plasticity_rate\": %.6f\n", PLASTICITY_RATE); fprintf(json, "}\n"); fclose(json); } /* ======================================================================== */ /* M A I N T E S T */ /* ======================================================================== */ int main() { printf("=======================================================================\n"); printf(" PLASTICITY TRACKER - Nodal Growth Metrics\n"); printf(" Fractal Brain: Plasticity = Grid reshaping to find cooler path\n"); printf("=======================================================================\n\n"); printf("PLASTICITY DEFINITION:\n"); printf(" Nodal Growth = Grid's ability to reshape itself\n"); printf(" Goal: Find \"cooler\" paths (lower resistance, more efficient)\n"); printf(" Rate: %.6f per adaptation cycle\n\n", PLASTICITY_RATE); // CUDA setup cudaDeviceProp prop; cudaGetDeviceProperties(&prop, 0); printf("[CUDA] %s SM %d.%d SMs: %d\n", prop.name, prop.major, prop.minor, prop.multiProcessorCount); // NVML power monitoring nvmlInit(); nvmlDevice_t nvml_dev; nvmlDeviceGetHandleByIndex(0, &nvml_dev); unsigned int power_mW; nvmlDeviceGetPowerUsage(nvml_dev, &power_mW); printf("[NVML] Idle power: %.1f W\n", power_mW / 1000.0f); // Allocate memory float *f0, *f1, *rho, *ux, *uy; float *strength, *usage; float *h_strength, *initial_strength; cudaMalloc(&f0, Q * NN * sizeof(float)); cudaMalloc(&f1, Q * NN * sizeof(float)); cudaMalloc(&rho, NN * sizeof(float)); cudaMalloc(&ux, NN * sizeof(float)); cudaMalloc(&uy, NN * sizeof(float)); cudaMalloc(&strength, Q * NN * sizeof(float)); cudaMalloc(&usage, Q * NN * sizeof(float)); h_strength = (float*)malloc(Q * NN * sizeof(float)); initial_strength = (float*)malloc(Q * NN * sizeof(float)); // Allocate host connections connections = (NodeConnections*)malloc(NN * sizeof(NodeConnections)); // Initialize distribution float* h_f0 = (float*)malloc(Q * NN * sizeof(float)); for (int i = 0; i < Q * NN; i++) { h_f0[i] = 1.0f + 0.01f * (rand() / (float)RAND_MAX - 0.5f); } cudaMemcpy(f0, h_f0, Q * NN * sizeof(float), cudaMemcpyHostToDevice); free(h_f0); // Initialize connection strengths (uniform) for (int i = 0; i < Q * NN; i++) { h_strength[i] = 1.0f; // Start with uniform strength initial_strength[i] = 1.0f; } cudaMemcpy(strength, h_strength, Q * NN * sizeof(float), cudaMemcpyHostToDevice); cudaMemset(usage, 0, Q * NN * sizeof(float)); // Initialize node connections for (int idx = 0; idx < NN; idx++) { for (int i = 0; i < Q; i++) { connections[idx].strength[i] = 1.0f; connections[idx].usage[i] = 0.0f; } connections[idx].efficiency = 1.0f; connections[idx].last_adaptation = 0.0f; connections[idx].plasticity = 0.0f; } // Prepare telemetry FILE* telemetry = fopen("plasticity_telemetry.csv", "w"); fprintf(telemetry, "step,power_w,steps_per_sec,structural_change,grid_efficiency,adaptation_rate,total_plasticity\n"); auto t0 = std::chrono::steady_clock::now(); uint64_t total_steps = 0; int cur = 0; int adaptation_cycles = 0; printf("\n[EXPERIMENT] Tracking plasticity (nodal growth)...\n"); printf(" Steps | Power | Steps/sec | Structure | Efficiency | Plasticity\n"); printf(" --------|-------|-----------|-----------|------------|------------\n"); int batches = TOTAL_STEPS / STEPS_PER_BATCH; for (int batch = 0; batch < batches; batch++) { // Run LBM steps with plasticity for (int s = 0; s < STEPS_PER_BATCH; s++) { lbm_collide_stream_plastic<<>>( (cur == 0) ? f0 : f1, (cur == 0) ? f1 : f0, rho, ux, uy, strength, usage, OMEGA, NX, NY); cudaDeviceSynchronize(); cur = 1 - cur; } total_steps += STEPS_PER_BATCH; // Update plasticity every ADAPTATION_WINDOW steps if (total_steps % ADAPTATION_WINDOW == 0) { update_plasticity<<>>(strength, usage, PLASTICITY_RATE, NX, NY); cudaDeviceSynchronize(); adaptation_cycles++; // Copy strengths back to host for metrics cudaMemcpy(h_strength, strength, Q * NN * sizeof(float), cudaMemcpyDeviceToHost); calculate_plasticity_metrics(h_strength, initial_strength, total_steps, adaptation_cycles); } // Report every SAMPLE_INTERVAL steps if (total_steps % SAMPLE_INTERVAL == 0) { nvmlDeviceGetPowerUsage(nvml_dev, &power_mW); float power_W = power_mW / 1000.0f; auto t_now = std::chrono::steady_clock::now(); double elapsed = std::chrono::duration(t_now - t0).count(); float steps_per_sec = total_steps / elapsed; fprintf(telemetry, "%llu,%.1f,%.0f,%.6f,%.6f,%.6f,%.6f\n", total_steps, power_W, steps_per_sec, structural_change, grid_efficiency, avg_adaptation_rate, total_plasticity); printf(" %7llu | %5.0f | %9.0f | %9.6f | %10.6f | %10.6f\n", total_steps, power_W, steps_per_sec, structural_change, grid_efficiency, total_plasticity); // Save detailed metrics every 50k steps if (total_steps % 50000 == 0) { save_plasticity_metrics(total_steps, adaptation_cycles); } } // Check time limit (1 minute) auto t_now = std::chrono::steady_clock::now(); double elapsed = std::chrono::duration(t_now - t0).count(); if (elapsed > 60.0) { printf("\n[TIME] 1 minute reached\n"); break; } } auto t_end = std::chrono::steady_clock::now(); double runtime = std::chrono::duration(t_end - t0).count(); // Final results printf("\n=======================================================================\n"); printf(" PLASTICITY TRACKER - FINAL METRICS\n"); printf("=======================================================================\n"); printf("\nEXPERIMENT SUMMARY:\n"); printf(" Total steps: %llu\n", total_steps); printf(" Runtime: %.1f seconds (%.2f minutes)\n", runtime, runtime / 60.0); printf(" Steps/sec: %.0f\n", total_steps / runtime); printf(" Adaptation cycles: %d\n", adaptation_cycles); nvmlDeviceGetPowerUsage(nvml_dev, &power_mW); printf(" Final power: %.1f W\n", power_mW / 1000.0f); printf("\nPLASTICITY METRICS:\n"); printf(" Structural change: %.6f (0-1 scale)\n", structural_change); printf(" Grid efficiency: %.6f (0-1 scale)\n", grid_efficiency); printf(" Adaptation rate: %.6f change/cycle\n", avg_adaptation_rate); printf(" Total plasticity: %.6f (%% of adaptive nodes)\n", total_plasticity); printf(" Adaptive nodes: %d / %d\n", (int)(total_plasticity * NN), NN); printf("\nPLASTICITY CLASSIFICATION:\n"); if (structural_change > 0.5f) { printf(" ✅ HIGH PLASTICITY: Grid significantly reshaped\n"); printf(" Strong nodal growth and adaptation\n"); } else if (structural_change > 0.1f) { printf(" ⚠️ MODERATE PLASTICITY: Some grid adaptation\n"); printf(" Moderate nodal growth\n"); } else { printf(" ⚠️ LOW PLASTICITY: Limited grid adaptation\n"); printf(" May need higher plasticity rate or longer runtime\n"); } if (grid_efficiency > 0.7f) { printf(" ✅ HIGH EFFICIENCY: Grid found \"cooler\" paths\n"); printf(" Effective adaptation to flow patterns\n"); } else if (grid_efficiency > 0.4f) { printf(" ⚠️ MODERATE EFFICIENCY: Some path optimization\n"); } else { printf(" ⚠️ LOW EFFICIENCY: Limited path optimization\n"); printf(" Grid not effectively finding cooler paths\n"); } // Save final metrics save_plasticity_metrics(total_steps, adaptation_cycles); printf("\nOUTPUT FILES:\n"); printf(" plasticity_telemetry.csv - Time-series telemetry\n"); printf(" plasticity_summary.csv - Summary metrics\n"); printf(" plasticity_nodes.csv - Detailed node metrics (1%% sample)\n"); printf(" plasticity_metrics.json - JSON summary\n"); printf("\nANALYSIS:\n"); printf(" Plasticity (Nodal Growth) measures:\n"); printf(" 1. Structural change: How much grid reshapes\n"); printf(" 2. Grid efficiency: How well it finds \"cooler\" paths\n"); printf(" 3. Adaptation rate: Speed of change\n"); printf(" 4. Adaptive nodes: Percentage of nodes that change\n"); // Cleanup fclose(telemetry); cudaFree(f0); cudaFree(f1); cudaFree(rho); cudaFree(ux); cudaFree(uy); cudaFree(strength); cudaFree(usage); free(h_strength); free(initial_strength); free(connections); nvmlShutdown(); return 0; }