Skip to content

argos-analytics.js #4

Description

@natefrog808

/**

  • ArgOS Analytics Module
  • Collects and analyzes simulation data to measure agent performance
  • and environmental dynamics
    */

import {
Actions,
SensoryData,
Memory,
Goals,
CognitiveState,
Learning,
Social,
RealityFlux,
Environmental,
Position
} from './argos-framework.js';

export class ArgOSAnalytics {
/**

  • Initialize analytics for an ArgOS simulation

  • @param {Object} world - The BitECS world object
    */
    constructor(world) {
    this.world = world;
    this.data = {
    time: 0,

    // Agent metrics
    agentCount: 0,
    successRates: [], // Success rate history
    avgSuccessRate: 0,
    avgReward: 0,
    avgAdaptability: 0,
    avgEmotionalState: 0,

    // Environmental metrics
    resourceCount: 0,
    obstacleCount: 0,
    hazardCount: 0,

    // Social metrics
    cooperationCount: 0,
    avgTrustLevel: 0,
    alliances: 0,
    rivalries: 0,

    // Reality metrics
    realityShifts: 0,
    activeFluxEffects: 0,
    teleports: 0,
    phases: 0,
    transforms: 0,

    // Historical data (for charting)
    successHistory: [],
    rewardHistory: [],
    cooperationHistory: [],
    resourceHistory: [],
    fluxHistory: []
    };

// Sampling rate (how often to record history)
this.samplingRate = 10; // Every 10 ticks

}

/**

  • Update analytics data based on current world state
  • Should be called every simulation tick
    */
    update() {
    const time = this.world.time;
    this.data.time = time;
// Count entities by type
let agentCount = 0;
let resourceCount = 0;
let obstacleCount = 0;
let hazardCount = 0;

// Agent metrics
let totalSuccessRate = 0;
let totalReward = 0;
let totalAdaptability = 0;
let totalEmotionalState = 0;

// Social metrics
let totalTrustLevel = 0;
let totalCooperationCount = 0;
let totalAlliances = 0;
let totalRivalries = 0;

// Reality metrics
let activeFluxEffects = 0;
let teleports = 0;
let phases = 0;
let transforms = 0;

// Analyze all entities
for (let i = 0; i < this.world.entities.length; i++) {
  const entity = i;
  
  // Count agent types
  if (SensoryData[entity] && Memory[entity] && Goals[entity]) {
    agentCount++;
    
    // Track action success rate
    if (Actions[entity]) {
      totalSuccessRate += Actions.successRate[entity];
    }
    
    // Track learning rewards
    if (Learning[entity]) {
      totalReward += Learning.rewardAccumulator[entity];
    }
    
    // Track cognitive metrics
    if (CognitiveState[entity]) {
      totalAdaptability += CognitiveState.adaptability[entity];
      totalEmotionalState += CognitiveState.emotionalState[entity];
    }
    
    // Track social metrics
    if (Social[entity]) {
      totalTrustLevel += Social.trustLevel[entity];
      totalCooperationCount += Social.cooperationCount[entity];
      
      // Count alliances
      for (let j = 0; j < 5; j++) {
        if (Social.allies[entity * 5 + j] !== 0) {
          totalAlliances++;
        }
        if (Social.rivals[entity * 5 + j] !== 0) {
          totalRivalries++;
        }
      }
    }
  }
  
  // Count environmental entities
  if (Environmental[entity]) {
    switch (Environmental.type[entity]) {
      case 0: resourceCount++; break;
      case 1: obstacleCount++; break;
      case 2: hazardCount++; break;
    }
  }
  
  // Count reality flux effects
  if (RealityFlux[entity] && RealityFlux.effectType[entity] > 0) {
    activeFluxEffects++;
    switch (RealityFlux.effectType[entity]) {
      case 1: teleports++; break;
      case 2: phases++; break;
      case 3: transforms++; break;
    }
  }
}

// Calculate averages
this.data.agentCount = agentCount;
this.data.avgSuccessRate = agentCount > 0 ? totalSuccessRate / agentCount : 0;
this.data.avgReward = agentCount > 0 ? totalReward / agentCount : 0;
this.data.avgAdaptability = agentCount > 0 ? totalAdaptability / agentCount : 0;
this.data.avgEmotionalState = agentCount > 0 ? totalEmotionalState / agentCount : 0;

this.data.resourceCount = resourceCount;
this.data.obstacleCount = obstacleCount;
this.data.hazardCount = hazardCount;

this.data.cooperationCount = totalCooperationCount;
this.data.avgTrustLevel = agentCount > 0 ? totalTrustLevel / agentCount : 0;
this.data.alliances = totalAlliances;
this.data.rivalries = totalRivalries;

this.data.activeFluxEffects = activeFluxEffects;
this.data.teleports = teleports;
this.data.phases = phases;
this.data.transforms = transforms;

// Count reality shifts based on time
if (time % 150 === 0 && time > 0) {
  this.data.realityShifts++;
}

// Record historical data (at sampling rate)
if (time % this.samplingRate === 0) {
  this.data.successHistory.push({
    time: time,
    value: this.data.avgSuccessRate
  });
  
  this.data.rewardHistory.push({
    time: time,
    value: this.data.avgReward
  });
  
  this.data.cooperationHistory.push({
    time: time,
    value: this.data.cooperationCount
  });
  
  this.data.resourceHistory.push({
    time: time,
    value: this.data.resourceCount
  });
  
  this.data.fluxHistory.push({
    time: time,
    value: this.data.activeFluxEffects
  });
  
  // Limit history size to prevent memory issues
  const maxHistoryLength = 100;
  if (this.data.successHistory.length > maxHistoryLength) {
    this.data.successHistory.shift();
    this.data.rewardHistory.shift();
    this.data.cooperationHistory.shift();
    this.data.resourceHistory.shift();
    this.data.fluxHistory.shift();
  }
}

return this.data;

}

/**

  • Render analytics to HTML container
  • @param {HTMLElement} container - The HTML element to render analytics into
    */
    render(container) {
    if (!container) return;
// Format data for display
const data = this.data;
const html = `
  <h3>ArgOS Analytics</h3>
  
  <div class="metrics-grid">
    <div class="metric-card">
      <h4>Simulation</h4>
      <p>Time: <span class="value">${data.time}</span></p>
      <p>Reality Shifts: <span class="value">${data.realityShifts}</span></p>
    </div>
    
    <div class="metric-card">
      <h4>Agents</h4>
      <p>Count: <span class="value">${data.agentCount}</span></p>
      <p>Success Rate: <span class="value">${data.avgSuccessRate.toFixed(1)}%</span></p>
      <p>Avg Reward: <span class="value">${data.avgReward.toFixed(1)}</span></p>
    </div>
    
    <div class="metric-card">
      <h4>Cognitive</h4>
      <p>Adaptability: <span class="value">${data.avgAdaptability.toFixed(1)}</span></p>
      <p>Emotional: <span class="value">${data.avgEmotionalState.toFixed(1)}</span></p>
    </div>
    
    <div class="metric-card">
      <h4>Social</h4>
      <p>Cooperation: <span class="value">${data.cooperationCount}</span></p>
      <p>Trust Level: <span class="value">${data.avgTrustLevel.toFixed(1)}</span></p>
      <p>Alliances: <span class="value">${data.alliances}</span></p>
    </div>
    
    <div class="metric-card">
      <h4>Environment</h4>
      <p>Resources: <span class="value">${data.resourceCount}</span></p>
      <p>Obstacles: <span class="value">${data.obstacleCount}</span></p>
      <p>Hazards: <span class="value">${data.hazardCount}</span></p>
    </div>
    
    <div class="metric-card">
      <h4>Reality Flux</h4>
      <p>Active Effects: <span class="value">${data.activeFluxEffects}</span></p>
      <p>Teleports: <span class="value">${data.teleports}</span></p>
      <p>Phases/Transforms: <span class="value">${data.phases}/${data.transforms}</span></p>
    </div>
  </div>
  
  <canvas id="analytics-chart" width="300" height="150"></canvas>
`;

container.innerHTML = html;

// Render chart if canvas and chart library available
this.renderChart();

}

/**

  • Render analytics chart using Chart.js if available
    */
    renderChart() {
    const canvas = document.getElementById('analytics-chart');
    if (!canvas) return;
// Check if Chart is available (we're assuming Chart.js is loaded)
if (typeof Chart !== 'undefined') {
  // Destroy previous chart if it exists
  if (this.chart) {
    this.chart.destroy();
  }
  
  const ctx = canvas.getContext('2d');
  
  // Create chart with history data
  this.chart = new Chart(ctx, {
    type: 'line',
    data: {
      datasets: [
        {
          label: 'Success Rate',
          data: this.data.successHistory.map(item => ({ x: item.time, y: item.value })),
          borderColor: 'rgba(52, 152, 219, 1)',
          backgroundColor: 'rgba(52, 152, 219, 0.2)',
          tension: 0.3
        },
        {
          label: 'Avg Reward',
          data: this.data.rewardHistory.map(item => ({ x: item.time, y: item.value })),
          borderColor: 'rgba(46, 204, 113, 1)',
          backgroundColor: 'rgba(46, 204, 113, 0.2)',
          tension: 0.3
        },
        {
          label: 'Cooperation',
          data: this.data.cooperationHistory.map(item => ({ x: item.time, y: item.value })),
          borderColor: 'rgba(155, 89, 182, 1)',
          backgroundColor: 'rgba(155, 89, 182, 0.2)',
          tension: 0.3
        }
      ]
    },
    options: {
      responsive: true,
      maintainAspectRatio: false,
      scales: {
        x: {
          type: 'linear',
          title: {
            display: true,
            text: 'Simulation Time'
          }
        },
        y: {
          beginAtZero: true
        }
      }
    }
  });
} else {
  // Fallback to simple text if Chart.js is not available
  canvas.style.display = 'none';
}

}

/**

  • Get a simplified data summary for export
  • @returns {Object} Data summary
    */
    getDataSummary() {
    return {
    simulationTime: this.data.time,
    realityShifts: this.data.realityShifts,
    agentMetrics: {
    count: this.data.agentCount,
    avgSuccessRate: this.data.avgSuccessRate,
    avgReward: this.data.avgReward,
    avgAdaptability: this.data.avgAdaptability
    },
    socialMetrics: {
    cooperationCount: this.data.cooperationCount,
    avgTrustLevel: this.data.avgTrustLevel,
    alliances: this.data.alliances
    },
    environmentMetrics: {
    resources: this.data.resourceCount,
    hazards: this.data.hazardCount
    },
    realityMetrics: {
    activeFluxEffects: this.data.activeFluxEffects
    }
    };
    }

/**

  • Export analytics data as CSV
  • @returns {string} CSV data
    */
    exportAsCSV() {
    const headers = [
    'Time',
    'AgentCount',
    'AvgSuccessRate',
    'AvgReward',
    'ResourceCount',
    'CooperationCount',
    'ActiveFluxEffects'
    ].join(',');
// Combine history data
const rows = [];
for (let i = 0; i < this.data.successHistory.length; i++) {
  const time = this.data.successHistory[i].time;
  const row = [
    time,
    this.data.agentCount,
    this.data.successHistory[i].value.toFixed(2),
    this.data.rewardHistory[i].value.toFixed(2),
    this.data.resourceHistory[i].value,
    this.data.cooperationHistory[i].value,
    this.data.fluxHistory[i].value
  ].join(',');
  
  rows.push(row);
}

return `${headers}\n${rows.join('\n')}`;

}

/**

  • Download analytics data as CSV file
    */
    downloadCSV() {
    const csvContent = this.exportAsCSV();
    const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
    const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.setAttribute('href', url);
link.setAttribute('download', `argos-analytics-${Date.now()}.csv`);
link.style.visibility = 'hidden';

document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);

}

/**

  • Generate a detailed analytics report
  • @returns {Object} Detailed report with analysis
    */
    generateReport() {
    const data = this.data;
// Calculate trends
let successTrend = 'stable';
let rewardTrend = 'stable';

if (this.data.successHistory.length > 5) {
  const recentSuccess = this.data.successHistory.slice(-5);
  const firstValue = recentSuccess[0].value;
  const lastValue = recentSuccess[4].value;
  
  if (lastValue > firstValue * 1.1) {
    successTrend = 'improving';
  } else if (lastValue < firstValue * 0.9) {
    successTrend = 'declining';
  }
  
  const recentReward = this.data.rewardHistory.slice(-5);
  const firstReward = recentReward[0].value;
  const lastReward = recentReward[4].value;
  
  if (lastReward > firstReward * 1.1) {
    rewardTrend = 'improving';
  } else if (lastReward < firstReward * 0.9) {
    rewardTrend = 'declining';
  }
}

// Generate insights
const insights = [];

if (data.avgSuccessRate > 80) {
  insights.push('Agents are performing exceptionally well with high success rates.');
} else if (data.avgSuccessRate < 40) {
  insights.push('Agents are struggling to achieve their goals.');
}

if (data.cooperationCount > data.agentCount * 3) {
  insights.push('High levels of cooperation observed among agents.');
} else if (data.rivalries > data.alliances) {
  insights.push('Competitive behavior dominates over cooperation.');
}

if (data.activeFluxEffects > data.agentCount * 0.5) {
  insights.push('Significant reality distortion affecting agent behavior.');
}

if (successTrend === 'improving' && rewardTrend === 'improving') {
  insights.push('Agents show clear learning and adaptation over time.');
}

return {
  summary: {
    time: data.time,
    agentCount: data.agentCount,
    resourceCount: data.resourceCount,
    realityShifts: data.realityShifts
  },
  performance: {
    avgSuccessRate: data.avgSuccessRate.toFixed(1),
    avgReward: data.avgReward.toFixed(1),
    successTrend,
    rewardTrend
  },
  social: {
    cooperationCount: data.cooperationCount,
    alliances: data.alliances,
    rivalries: data.rivalries
  },
  reality: {
    activeEffects: data.activeFluxEffects,
    totalShifts: data.realityShifts
  },
  insights
};

}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    In Progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions