#!/usr/bin/env python3
"""
Swarm Learning System

Learn from swarm performance and continuously improve the system.

This class provides:
- Experience management
- Pattern recognition
- Strategy evolution
- Adaptive learning
"""

import time
import json
import math
from typing import Dict, List, Any, Optional
from collections import defaultdict
class ExperienceDatabase:
    """
    Database for storing swarm experiences.
    """
    
    def __init__(self):
        self.experiences = []
        self.experience_index = {}
        
    def store(self, experience: Dict[str, Any]):
        """
        Store an experience.

        Args:
            experience: Experience data
        """
        self.experiences.append(experience)
        
        # Update index by category
        for key, value in experience.items():
            if isinstance(value, list) and len(value) > 0:
                category = key
                if category not in self.experience_index:
                    self.experience_index[category] = []
                self.experience_index[category].extend(value)
        
        # Keep only recent experiences
        if len(self.experiences) > 1000:
            self.experiences = self.experiences[-1000:]
            
    def get_recent_experiences(self, limit: int = 100) -> List[Dict[str, Any]]:
        """
        Get recent experiences.

        Args:
            limit: Maximum number of experiences to return

        Returns:
            List of recent experiences
        """
        return self.experiences[-limit:]
        
    def get_experiences_by_category(self, category: str) -> List[Dict[str, Any]]:
        """
        Get experiences by category.

        Args:
            category: Category to filter by

        Returns:
            List of experiences
        """
        return self.experience_index.get(category, [])
        
    def get_experiences_by_agent(self, agent_id: str) -> List[Dict[str, Any]]:
        """
        Get experiences by agent.

        Args:
            agent_id: Agent identifier

        Returns:
            List of experiences
        """
        return [exp for exp in self.experiences if exp.get("agent_id") == agent_id]
class PatternRecognizer:
    """
    Recognize patterns in swarm experiences.
    """
    
    def extract_patterns(self, experiences: List[Dict[str, Any]]) -> Dict[str, Any]:
        """
        Extract patterns from experiences.

        Args:
            experiences: List of experiences

        Returns:
            Extracted patterns
        """
        patterns = {
            "successful_strategies": [],
            "failed_strategies": [],
            "agent_performance_trends": {},
            "environmental_impacts": {},
            "conflict_patterns": []
        }
        
        # Analyze successful strategies
        patterns["successful_strategies"] = self.identify_successful_strategies(experiences)
        
        # Analyze failed strategies
        patterns["failed_strategies"] = self.identify_failed_strategies(experiences)
        
        # Analyze agent performance trends
        patterns["agent_performance_trends"] = self.analyze_performance_trends(experiences)
        
        # Analyze environmental impacts
        patterns["environmental_impacts"] = self.analyze_environmental_impacts(experiences)
        
        # Identify conflict patterns
        patterns["conflict_patterns"] = self.identify_conflict_patterns(experiences)
        
        return patterns
        
    def identify_successful_strategies(self, experiences: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """
        Identify successful strategies.

        Args:
            experiences: List of experiences

        Returns:
            List of successful strategies
        """
        successful_strategies = []
        
        for experience in experiences:
            outcomes = experience.get("outcomes", {})
            for strategy, outcome in outcomes.items():
                if outcome.get("success", False):
                    successful_strategies.append({
                        "strategy": strategy,
                        "success_rate": outcome.get("success_rate", 0.0),
                        "average_outcome": outcome.get("average_outcome", 0.0),
                        "agent_ids": experience.get("agent_ids", []),
                        "environmental_factors": experience.get("environmental_factors", {})
                    })
                    
        return successful_strategies
        
    def identify_failed_strategies(self, experiences: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """
        Identify failed strategies.

        Args:
            experiences: List of experiences

        Returns:
            List of failed strategies
        """
        failed_strategies.education = []
        
        for experience in experiences:
            outcomes = experience.get("outcomes", {})
            for strategy, outcome in outcomes.items():
                if not outcome.get("success", False):
                    failed_strategies.education.append({
                        "strategy": strategy,
                        "failure_rate": outcome.get("failure_rate", 0.0),
                        "negative_outcome": outcome.get("negative_outcome", 0.0),
                        "agent_ids": experience.get("agent_ids", []),
                        "environmental_factors": experience.get("environmental_factors", {})
                    })
                    
        return failed_strategies
        
    def analyze_performance_trends(self, experiences: List[Dict[str, Any]]) -> Dict[str, Any]:
        """
        Analyze agent performance trends.

        Args:
            experiences: List of experiences

        Returns:
            Performance trends analysis
        """
        trends = {}
        
        for experience in experiences:
            agent_id = experience.get("agent_id")
            if not agent_id:
                continue
                
            if agent_id not in trends:
                trends[agent_id] = {
                    "performance_history": [],
                    "improvement_rate": 0.0,
                    "consistency_score": 0.0
                }
                
            outcomes = experience.get("outcomes", {})
            performance_scores = []
            
            for strategy, outcome in outcomes.items():
                score = outcome.get("success_rate", 0.0) * 100 + outcome.get("average_outcome", 0.0)
                performance_scores.append(score)
                
            if performance_scores:
                average_score = sum(performance_scores) / len(performance_scores)
                trends[agent_id]["performance_history"].append(average_score)
                
        # Calculate improvement rates and consistency scores
        for agent_id, trend_data in trends.items():
            history = trend_data["performance_history"]
            if len(history) >= 2:
                trend_data["improvement_rate"] = self.calculate_trend_rate(history)
                trend_data["consistency_score"] = self.calculate_consistency_score(history)
                
        return trends
        
    def analyze_environmental_impacts(self, experiences: List[Dict[str, Any]]) -> Dict[str, Any]:
        """
        Analyze environmental impacts on performance.

        Args:
            experiences: List of experiences

        Returns:
            Environmental impacts analysis
        """
        impacts = {}
        
        for experience in experiences:
            environmental_factors = experience.get("environmental_factors", {})
            outcomes = experience.get("outcomes", {})
            
            for factor, value in environmental_factors.items():
                if factor not in impacts:
                    impacts[factor] = {"positive": [], "negative": [], "neutral": []}
                    
                for strategy, outcome in outcomes.items():
                    if outcome.get("success", False):
                        impacts[factor]["positive"].append(value)
                    elif not outcome.get("success", False):
                        impacts[factor]["negative"].append(value)
                    else:
                        impacts[factor]["neutral"].append(value)
                        
        return impacts
        
    def identify_conflict_patterns(self, experiences: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """
        Identify conflict patterns.

        Args:
            experiences: List of experiences

        Returns:
            List of conflict patterns
        """
        conflict_patterns = []
        
        for experience in experiences:
            conflicts = experience.get("conflicts", [])
            for conflict in conflicts:
                conflict_patterns.append({
                    "type": conflict.get("type"),
                    "severity": conflict.get("severity"),
                    "resolution_strategy": conflict.get("resolution_strategy"),
                    "outcomes": conflict.get("outcomes", []),
                    "affected_agents": conflict.get("affected_agents", [])
                })
                
        return conflict_patterns
        
    def calculate_trend_rate(self, data: List[float]) -> float:
        """
        Calculate trend rate for data series.

        Args:
            data: Data series

        Returns:
            Trend rate (-1.0 to 1.0)
        """
        if len(data) < 2:
            return 0.0
            
        x_values = list(range(len(data)))
        y_values = data
        
        # Simple linear regression
        n = len(x_values)
        sum_x = sum(x_values)
        sum_y = sum(y_values)
        sum_xy = sum(x * y for x, y in zip(x_values, y_values))
        sum_x2 = sum(x ** 2 for x in x_values)
        sum_y2 = sum(y ** 2 for y in y_values)
        
        slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x ** 2)
        intercept = (sum_y - slope * sum_x) / n
        
        return slope
        
    def calculate_consistency_score(self, data: List[float]) -> float:
        """
        Calculate consistency score for data series.

        Args:
            data: Data series

        Returns:
            Consistency score (0.0 to 1.0)
        """
        if len(data) < 2:
            return 1.0
            
        mean = sum(data) / len(data)
        variance = sum((x - mean) ** 2 for x in data) / len(data)
        
        if variance == 0:
            return 1.0
            
        std_dev = variance ** 0.5
        cv = std_dev / mean if mean != 0 else 0
        
        return max(0.0, 1.0 - cv)
class EvolutionEngine:
    """
    Evolve swarm strategies based on patterns.
    """
    
    def __init__(self):
        self.strategies = {}
        self.mutation_rate = 0.1
        self.crossover_rate = 0.3
        
    def evolve_strategies(self, patterns: Dict[str, Any]):
        """
        Evolve strategies based on patterns.

        Args:
            patterns: Extracted patterns
        """
        # Evolve successful strategies
        self.evolve_successful_strategies(patterns["successful_strategies"])
        
        # Mutate failed strategies
        self.mutate_failed_strategies(patterns["failed_strategies"])
        
        # Adapt to environmental impacts
        self.adapt_to_environmental_impacts(patterns["environmental_impacts"])
        
    def evolve_successful_strategies(self, successful_strategies: List[Dict[str, Any]]):
        """
        Evolve successful strategies.

        Args:
            successful_strategies: Successful strategies
        """
        for strategy in successful_strategies:
            strategy_id = f"strategy_{len(self.strategies)}"
            
            self.strategies[strategy_id] = {
                "base_strategy": strategy["strategy"],
                "success_rate": strategy["success_rate"],
                "average_outcome": strategy["average_outcome"],
                "environmental_factors": strategy["environmental_factors"],
                "fitness_score": self.calculate_fitness_score(strategy),
                "mutations": []
            }
            
    def mutate_failed_strategies(self, failed_strategies: List[Dict[str, Any]]):
        """
        Mutate failed strategies.

        Args:
            failed_strategies: Failed strategies
        """
        for strategy in failed_strategies:
            # Create mutated version
            mutated_strategy = self.mutate_strategy(strategy["strategy"])
            
            strategy_id = f"mutated_strategy_{len(self.strategies)}"
            
            self.strategies[strategy_id] = {
                "base_strategy": mutated_strategy,
                "success_rate": strategy["success_rate"],
                "average_outcome": strategy["average_outcome"],
                "environmental_factors": strategy["environmental_factors"],
                "fitness_score": self.calculate_fitness_score(strategy) * 0.5,
                "mutations": ["failed_strategy_mutation"]
            }
            
    def adapt_to_environmental_impacts(self, environmental_impacts: Dict[str, Any]):
        """
        Adapt strategies based on environmental impacts.

        Args:
            environmental_impacts: Environmental impacts
        """
        for factor, impacts in environmental_impacts.items():
            for impact_type in ["positive", "negative", "neutral"]:
                for value in impacts[impact_type]:
                    # Adjust strategy fitness based on impact
                    self.adjust_strategy_fitness_by_factor(factor, impact_type, value)
                    
    def calculate_fitness_score(self, strategy: Dict[str, Any]) -> float:
        """
        Calculate fitness score for a strategy.

        Args:
            strategy: Strategy data

        Returns:
            Fitness score (0.0 to 1.0)
        """
        success_score = strategy["success_rate"] / 100.0
        outcome_score = min(strategy["average_outcome"] / 10.0, 1.0)
        
        return (success_score + outcome_score) / 2.0
        
    def mutate_strategy(self, strategy: str) -> str:
        """
        Mutate a strategy.

        Args:
            strategy: Strategy to mutate

        Returns:
            Mutated strategy
        """
        # Simple mutation: add random variations
        variations = ["improved_", "optimized_", "adapted_", "enhanced_"]
        return variations[hash(strategy) % len(variations)] + strategy
        
    def adjust_strategy_fitness_by_factor(self, factor: str, impact_type: str, value: Any):
        """
        Adjust strategy fitness based on factor.

        Args:
            factor: Environmental factor
            impact_type: Type of impact (positive, negative, neutral)
            value: Impact value
        """
        pass
class AdaptiveLearner:
    """
    Learn from swarm performance and adapt strategies.
    """
    
    def __init__(self):
        self.learned_patterns = {}
        self.strategy_memory = {}
        self.performance_history = []
        
    def learn_from_experience(self, experience_data: Dict[str, Any], outcomes: Dict[str, Any]):
        """
        Learn from swarm experience.

        Args:
            experience_data: Experience data
            outcomes: Outcomes from experience
        """
        # Store experience
        self.performance_history.append({
            "experience": experience_data,
            "outcomes": outcomes,
            "timestamp": time.time()
        })
        
        # Extract and learn patterns
        self.extract_and_learn_patterns(experience_data, outcomes)
        
        # Update strategy memory
        self.update_strategy_memory(experience_data, outcomes)
        
    def extract_and_learn_patterns(self, experience_data: Dict[str, Any], outcomes: Dict[str, Any]):
        """
        Extract and learn patterns from experience.

        Args:
            experience_data: Experience data
            outcomes: Outcomes from experience
        """
        # Identify successful patterns
        successful_patterns = self.identify_successful_patterns(outcomes)
        
        # Learn from successful patterns
        for pattern in successful_patterns:
            self.learned_patterns[pattern["id"]] = {
                "pattern": pattern,
                "success_rate": pattern["success_rate"],
                "instances": pattern["instances"],
                "last_updated": time.time()
            }
            
    def update_strategy_memory(self, experience_data: Dict[str, Any], outcomes: Dict[str, Any]):
        """
        Update strategy memory.

        Args:
            experience_data: Experience data
            outcomes: Outcomes from experience
        """
        for strategy, outcome in outcomes.items():
            if strategy not in self.strategy_memory:
                self.strategy_memory[strategy] = {
                    "success_rate": 0.0,
                    "failure_rate": 0.0,
                    "average_outcome": 0.0,
                    "instance_count": 0,
                    "last_performance": 0.0
                }
                
            memory = self.strategy_memory[strategy]
            memory["success_rate"] = (memory["success_rate"] * memory["instance_count"] + 
                                     (1.0 if outcome.get("success", False) else 0.0)) / (memory["instance_count"] + 1)
            memory["failure_rate"] = 1.0 - memory["success_rate"]
            memory["average_outcome"] = (memory["average_outcome"] * memory["instance_count"] + 
                                       outcome.get("outcome", 0.0)) / (memory["instance_count"] + 1)
            memory["instance_count"] += 1
            memory["last_performance"] = outcome.get("success", False)
            memory["last_updated"] = time.time()
            
    def identify_successful_patterns(self, outcomes: Dict[str, Any]) -> List[Dict[str, Any]]:
        """
        Identify successful patterns from outcomes.

        Args:
            outcomes: Outcomes to analyze

        Returns:
            List of successful patterns
        """
        patterns = []
        
        for strategy, outcome in outcomes.items():
            success_rate = outcome.get("success", False)
            if success_rate:
                pattern_id = f"pattern_{strategy}_{int(time.time())}"
                patterns.append({
                    "id": pattern_id,
                    "strategy": strategy,
                    "success_rate": success_rate,
                    "instances": outcome.get("instances", 1),
                    "context": outcome.get("context", {})
                })
                
        return patterns