exo_exotic/
multiple_selves.rs

1//! # Multiple Selves / Dissociation
2//!
3//! Partitioned consciousness within a single cognitive substrate, modeling
4//! competing sub-personalities and the dynamics of self-coherence.
5//!
6//! ## Key Concepts
7//!
8//! - **Sub-Personalities**: Distinct processing modes with different goals
9//! - **Attention as Arbiter**: Competition for conscious access
10//! - **Integration vs Fragmentation**: Coherence of the self
11//! - **Executive Function**: Unified decision-making across selves
12//!
13//! ## Theoretical Basis
14//!
15//! Inspired by:
16//! - Internal Family Systems (IFS) therapy
17//! - Dissociative identity research
18//! - Marvin Minsky's "Society of Mind"
19//! - Global Workspace Theory
20
21use std::collections::HashMap;
22use serde::{Serialize, Deserialize};
23use uuid::Uuid;
24
25/// System managing multiple sub-personalities
26#[derive(Debug)]
27pub struct MultipleSelvesSystem {
28    /// Collection of sub-personalities
29    selves: Vec<SubPersonality>,
30    /// Currently dominant self
31    dominant: Option<Uuid>,
32    /// Executive function (arbiter)
33    executive: ExecutiveFunction,
34    /// Overall coherence measure
35    coherence: SelfCoherence,
36    /// Integration history
37    integration_history: Vec<IntegrationEvent>,
38}
39
40/// A sub-personality with its own goals and style
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct SubPersonality {
43    pub id: Uuid,
44    /// Name/label for this self
45    pub name: String,
46    /// Core beliefs/values
47    pub beliefs: Vec<Belief>,
48    /// Goals this self pursues
49    pub goals: Vec<Goal>,
50    /// Emotional baseline
51    pub emotional_tone: EmotionalTone,
52    /// Activation level (0-1)
53    pub activation: f64,
54    /// Age/experience of this self
55    pub age: u64,
56    /// Relationships with other selves
57    pub relationships: HashMap<Uuid, Relationship>,
58}
59
60/// A belief held by a sub-personality
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct Belief {
63    pub content: String,
64    pub strength: f64,
65    pub valence: f64, // positive/negative
66}
67
68/// A goal pursued by a sub-personality
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct Goal {
71    pub description: String,
72    pub priority: f64,
73    pub progress: f64,
74}
75
76/// Emotional baseline of a sub-personality
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct EmotionalTone {
79    pub valence: f64,      // -1 (negative) to 1 (positive)
80    pub arousal: f64,      // 0 (calm) to 1 (excited)
81    pub dominance: f64,    // 0 (submissive) to 1 (dominant)
82}
83
84/// Relationship between sub-personalities
85#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct Relationship {
87    pub other_id: Uuid,
88    pub relationship_type: RelationshipType,
89    pub strength: f64,
90}
91
92#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
93pub enum RelationshipType {
94    Protector,
95    Exile,
96    Manager,
97    Firefighter,
98    Ally,
99    Rival,
100    Neutral,
101}
102
103/// Executive function that arbitrates between selves
104#[derive(Debug)]
105pub struct ExecutiveFunction {
106    /// Strength of executive control
107    strength: f64,
108    /// Decision threshold
109    threshold: f64,
110    /// Recent decisions
111    decisions: Vec<Decision>,
112    /// Conflict resolution style
113    style: ResolutionStyle,
114}
115
116#[derive(Debug, Clone)]
117pub enum ResolutionStyle {
118    /// Dominant self wins
119    Dominance,
120    /// Average all inputs
121    Averaging,
122    /// Negotiate between selves
123    Negotiation,
124    /// Let them take turns
125    TurnTaking,
126}
127
128#[derive(Debug, Clone)]
129pub struct Decision {
130    pub id: Uuid,
131    pub participants: Vec<Uuid>,
132    pub outcome: DecisionOutcome,
133    pub timestamp: u64,
134}
135
136#[derive(Debug, Clone)]
137pub enum DecisionOutcome {
138    Unanimous(Uuid),           // All agreed, winner's id
139    Majority(Uuid, f64),       // Majority, winner and margin
140    Executive(Uuid),           // Executive decided
141    Conflict,                  // Unresolved conflict
142}
143
144/// Measure of self-coherence
145#[derive(Debug)]
146pub struct SelfCoherence {
147    /// Overall coherence score (0-1)
148    score: f64,
149    /// Conflict level
150    conflict: f64,
151    /// Integration level
152    integration: f64,
153    /// Stability over time
154    stability: f64,
155}
156
157/// Event in integration history
158#[derive(Debug, Clone)]
159pub struct IntegrationEvent {
160    pub event_type: IntegrationType,
161    pub selves_involved: Vec<Uuid>,
162    pub timestamp: u64,
163    pub outcome: f64,
164}
165
166#[derive(Debug, Clone, PartialEq)]
167pub enum IntegrationType {
168    Merge,
169    Split,
170    Activation,
171    Deactivation,
172    Conflict,
173    Resolution,
174}
175
176impl MultipleSelvesSystem {
177    /// Create a new multiple selves system
178    pub fn new() -> Self {
179        Self {
180            selves: Vec::new(),
181            dominant: None,
182            executive: ExecutiveFunction::new(0.7),
183            coherence: SelfCoherence::new(),
184            integration_history: Vec::new(),
185        }
186    }
187
188    /// Add a new sub-personality
189    pub fn add_self(&mut self, name: &str, emotional_tone: EmotionalTone) -> Uuid {
190        let id = Uuid::new_v4();
191        self.selves.push(SubPersonality {
192            id,
193            name: name.to_string(),
194            beliefs: Vec::new(),
195            goals: Vec::new(),
196            emotional_tone,
197            activation: 0.5,
198            age: 0,
199            relationships: HashMap::new(),
200        });
201
202        if self.dominant.is_none() {
203            self.dominant = Some(id);
204        }
205
206        id
207    }
208
209    /// Measure overall coherence
210    pub fn measure_coherence(&mut self) -> f64 {
211        if self.selves.is_empty() {
212            return 1.0; // Single self = perfectly coherent
213        }
214
215        // Calculate belief consistency
216        let belief_coherence = self.calculate_belief_coherence();
217
218        // Calculate goal alignment
219        let goal_alignment = self.calculate_goal_alignment();
220
221        // Calculate relationship harmony
222        let harmony = self.calculate_harmony();
223
224        // Overall coherence
225        self.coherence.score = (belief_coherence + goal_alignment + harmony) / 3.0;
226        self.coherence.integration = (belief_coherence + goal_alignment) / 2.0;
227        self.coherence.conflict = 1.0 - harmony;
228
229        self.coherence.score
230    }
231
232    fn calculate_belief_coherence(&self) -> f64 {
233        if self.selves.len() < 2 {
234            return 1.0;
235        }
236
237        let mut total_similarity = 0.0;
238        let mut count = 0;
239
240        for i in 0..self.selves.len() {
241            for j in i+1..self.selves.len() {
242                let sim = self.belief_similarity(&self.selves[i], &self.selves[j]);
243                total_similarity += sim;
244                count += 1;
245            }
246        }
247
248        if count > 0 {
249            total_similarity / count as f64
250        } else {
251            1.0
252        }
253    }
254
255    fn belief_similarity(&self, a: &SubPersonality, b: &SubPersonality) -> f64 {
256        if a.beliefs.is_empty() || b.beliefs.is_empty() {
257            return 0.5; // Neutral if no beliefs
258        }
259
260        // Compare emotional tones as proxy for beliefs
261        let valence_diff = (a.emotional_tone.valence - b.emotional_tone.valence).abs();
262        let arousal_diff = (a.emotional_tone.arousal - b.emotional_tone.arousal).abs();
263
264        1.0 - (valence_diff + arousal_diff) / 2.0
265    }
266
267    fn calculate_goal_alignment(&self) -> f64 {
268        if self.selves.len() < 2 {
269            return 1.0;
270        }
271
272        // Check if goals point in same direction
273        let mut total_alignment = 0.0;
274        let mut count = 0;
275
276        for self_entity in &self.selves {
277            for goal in &self_entity.goals {
278                total_alignment += goal.priority * goal.progress;
279                count += 1;
280            }
281        }
282
283        if count > 0 {
284            (total_alignment / count as f64).min(1.0)
285        } else {
286            0.5
287        }
288    }
289
290    fn calculate_harmony(&self) -> f64 {
291        let mut positive_relationships = 0;
292        let mut total_relationships = 0;
293
294        for self_entity in &self.selves {
295            for (_, rel) in &self_entity.relationships {
296                total_relationships += 1;
297                if matches!(rel.relationship_type,
298                    RelationshipType::Ally | RelationshipType::Protector | RelationshipType::Neutral) {
299                    positive_relationships += 1;
300                }
301            }
302        }
303
304        if total_relationships > 0 {
305            positive_relationships as f64 / total_relationships as f64
306        } else {
307            0.5 // Neutral if no relationships
308        }
309    }
310
311    /// Activate a sub-personality
312    pub fn activate(&mut self, self_id: Uuid, level: f64) {
313        if let Some(self_entity) = self.selves.iter_mut().find(|s| s.id == self_id) {
314            self_entity.activation = level.clamp(0.0, 1.0);
315
316            self.integration_history.push(IntegrationEvent {
317                event_type: IntegrationType::Activation,
318                selves_involved: vec![self_id],
319                timestamp: std::time::SystemTime::now()
320                    .duration_since(std::time::UNIX_EPOCH)
321                    .map(|d| d.as_secs())
322                    .unwrap_or(0),
323                outcome: level,
324            });
325        }
326
327        // Update dominant if necessary
328        self.update_dominant();
329    }
330
331    fn update_dominant(&mut self) {
332        self.dominant = self.selves.iter()
333            .max_by(|a, b| a.activation.partial_cmp(&b.activation).unwrap())
334            .map(|s| s.id);
335    }
336
337    /// Create conflict between selves
338    pub fn create_conflict(&mut self, self1: Uuid, self2: Uuid) {
339        if let Some(s1) = self.selves.iter_mut().find(|s| s.id == self1) {
340            s1.relationships.insert(self2, Relationship {
341                other_id: self2,
342                relationship_type: RelationshipType::Rival,
343                strength: 0.7,
344            });
345        }
346
347        if let Some(s2) = self.selves.iter_mut().find(|s| s.id == self2) {
348            s2.relationships.insert(self1, Relationship {
349                other_id: self1,
350                relationship_type: RelationshipType::Rival,
351                strength: 0.7,
352            });
353        }
354
355        self.integration_history.push(IntegrationEvent {
356            event_type: IntegrationType::Conflict,
357            selves_involved: vec![self1, self2],
358            timestamp: std::time::SystemTime::now()
359                .duration_since(std::time::UNIX_EPOCH)
360                .map(|d| d.as_secs())
361                .unwrap_or(0),
362            outcome: -0.5,
363        });
364    }
365
366    /// Resolve conflict through executive function
367    pub fn resolve_conflict(&mut self, self1: Uuid, self2: Uuid) -> Option<Uuid> {
368        let winner = self.executive.arbitrate(&self.selves, self1, self2);
369
370        if winner.is_some() {
371            // Update relationship to neutral
372            if let Some(s1) = self.selves.iter_mut().find(|s| s.id == self1) {
373                if let Some(rel) = s1.relationships.get_mut(&self2) {
374                    rel.relationship_type = RelationshipType::Neutral;
375                }
376            }
377
378            if let Some(s2) = self.selves.iter_mut().find(|s| s.id == self2) {
379                if let Some(rel) = s2.relationships.get_mut(&self1) {
380                    rel.relationship_type = RelationshipType::Neutral;
381                }
382            }
383
384            self.integration_history.push(IntegrationEvent {
385                event_type: IntegrationType::Resolution,
386                selves_involved: vec![self1, self2],
387                timestamp: std::time::SystemTime::now()
388                    .duration_since(std::time::UNIX_EPOCH)
389                    .map(|d| d.as_secs())
390                    .unwrap_or(0),
391                outcome: 0.8,
392            });
393        }
394
395        winner
396    }
397
398    /// Merge two sub-personalities
399    pub fn merge(&mut self, self1: Uuid, self2: Uuid) -> Option<Uuid> {
400        let s1_idx = self.selves.iter().position(|s| s.id == self1)?;
401        let s2_idx = self.selves.iter().position(|s| s.id == self2)?;
402
403        // Create merged self
404        let merged_id = Uuid::new_v4();
405        let s1 = &self.selves[s1_idx];
406        let s2 = &self.selves[s2_idx];
407
408        let merged = SubPersonality {
409            id: merged_id,
410            name: format!("{}-{}", s1.name, s2.name),
411            beliefs: [s1.beliefs.clone(), s2.beliefs.clone()].concat(),
412            goals: [s1.goals.clone(), s2.goals.clone()].concat(),
413            emotional_tone: EmotionalTone {
414                valence: (s1.emotional_tone.valence + s2.emotional_tone.valence) / 2.0,
415                arousal: (s1.emotional_tone.arousal + s2.emotional_tone.arousal) / 2.0,
416                dominance: (s1.emotional_tone.dominance + s2.emotional_tone.dominance) / 2.0,
417            },
418            activation: (s1.activation + s2.activation) / 2.0,
419            age: s1.age.max(s2.age),
420            relationships: HashMap::new(),
421        };
422
423        // Remove old selves (handle indices carefully)
424        let (first, second) = if s1_idx > s2_idx { (s1_idx, s2_idx) } else { (s2_idx, s1_idx) };
425        self.selves.remove(first);
426        self.selves.remove(second);
427
428        self.selves.push(merged);
429
430        self.integration_history.push(IntegrationEvent {
431            event_type: IntegrationType::Merge,
432            selves_involved: vec![self1, self2, merged_id],
433            timestamp: std::time::SystemTime::now()
434                .duration_since(std::time::UNIX_EPOCH)
435                .map(|d| d.as_secs())
436                .unwrap_or(0),
437            outcome: 1.0,
438        });
439
440        Some(merged_id)
441    }
442
443    /// Get dominant self
444    pub fn get_dominant(&self) -> Option<&SubPersonality> {
445        self.dominant.and_then(|id| self.selves.iter().find(|s| s.id == id))
446    }
447
448    /// Get all selves
449    pub fn all_selves(&self) -> &[SubPersonality] {
450        &self.selves
451    }
452
453    /// Get self count
454    pub fn self_count(&self) -> usize {
455        self.selves.len()
456    }
457
458    /// Get coherence
459    pub fn coherence(&self) -> &SelfCoherence {
460        &self.coherence
461    }
462}
463
464impl Default for MultipleSelvesSystem {
465    fn default() -> Self {
466        Self::new()
467    }
468}
469
470impl ExecutiveFunction {
471    /// Create new executive function
472    pub fn new(strength: f64) -> Self {
473        Self {
474            strength,
475            threshold: 0.6,
476            decisions: Vec::new(),
477            style: ResolutionStyle::Negotiation,
478        }
479    }
480
481    /// Arbitrate between two selves
482    pub fn arbitrate(&mut self, selves: &[SubPersonality], id1: Uuid, id2: Uuid) -> Option<Uuid> {
483        let s1 = selves.iter().find(|s| s.id == id1)?;
484        let s2 = selves.iter().find(|s| s.id == id2)?;
485
486        let outcome = match self.style {
487            ResolutionStyle::Dominance => {
488                // Most activated wins
489                if s1.activation > s2.activation {
490                    DecisionOutcome::Majority(id1, s1.activation - s2.activation)
491                } else {
492                    DecisionOutcome::Majority(id2, s2.activation - s1.activation)
493                }
494            }
495            ResolutionStyle::Averaging => {
496                // Neither wins clearly
497                DecisionOutcome::Conflict
498            }
499            ResolutionStyle::Negotiation => {
500                // Executive decides based on strength
501                if self.strength > self.threshold {
502                    let winner = if s1.emotional_tone.dominance > s2.emotional_tone.dominance {
503                        id1
504                    } else {
505                        id2
506                    };
507                    DecisionOutcome::Executive(winner)
508                } else {
509                    DecisionOutcome::Conflict
510                }
511            }
512            ResolutionStyle::TurnTaking => {
513                // Alternate based on history
514                let last_winner = self.decisions.last()
515                    .and_then(|d| match &d.outcome {
516                        DecisionOutcome::Unanimous(id) |
517                        DecisionOutcome::Majority(id, _) |
518                        DecisionOutcome::Executive(id) => Some(*id),
519                        _ => None,
520                    });
521
522                let winner = match last_winner {
523                    Some(w) if w == id1 => id2,
524                    Some(w) if w == id2 => id1,
525                    _ => id1,
526                };
527                DecisionOutcome::Majority(winner, 0.5)
528            }
529        };
530
531        let winner = match &outcome {
532            DecisionOutcome::Unanimous(id) |
533            DecisionOutcome::Majority(id, _) |
534            DecisionOutcome::Executive(id) => Some(*id),
535            DecisionOutcome::Conflict => None,
536        };
537
538        self.decisions.push(Decision {
539            id: Uuid::new_v4(),
540            participants: vec![id1, id2],
541            outcome,
542            timestamp: std::time::SystemTime::now()
543                .duration_since(std::time::UNIX_EPOCH)
544                .map(|d| d.as_secs())
545                .unwrap_or(0),
546        });
547
548        winner
549    }
550
551    /// Set resolution style
552    pub fn set_style(&mut self, style: ResolutionStyle) {
553        self.style = style;
554    }
555}
556
557impl SelfCoherence {
558    /// Create new coherence tracker
559    pub fn new() -> Self {
560        Self {
561            score: 1.0,
562            conflict: 0.0,
563            integration: 1.0,
564            stability: 1.0,
565        }
566    }
567
568    /// Get coherence score
569    pub fn score(&self) -> f64 {
570        self.score
571    }
572
573    /// Get conflict level
574    pub fn conflict(&self) -> f64 {
575        self.conflict
576    }
577
578    /// Get integration level
579    pub fn integration(&self) -> f64 {
580        self.integration
581    }
582}
583
584impl Default for SelfCoherence {
585    fn default() -> Self {
586        Self::new()
587    }
588}
589
590#[cfg(test)]
591mod tests {
592    use super::*;
593
594    #[test]
595    fn test_multiple_selves_creation() {
596        let system = MultipleSelvesSystem::new();
597        assert_eq!(system.self_count(), 0);
598    }
599
600    #[test]
601    fn test_add_selves() {
602        let mut system = MultipleSelvesSystem::new();
603
604        let id1 = system.add_self("Protector", EmotionalTone {
605            valence: 0.3,
606            arousal: 0.7,
607            dominance: 0.8,
608        });
609
610        let id2 = system.add_self("Inner Child", EmotionalTone {
611            valence: 0.8,
612            arousal: 0.6,
613            dominance: 0.3,
614        });
615
616        assert_eq!(system.self_count(), 2);
617        assert_ne!(id1, id2);
618    }
619
620    #[test]
621    fn test_coherence_measurement() {
622        let mut system = MultipleSelvesSystem::new();
623
624        // Single self = high coherence
625        system.add_self("Core", EmotionalTone {
626            valence: 0.5,
627            arousal: 0.5,
628            dominance: 0.5,
629        });
630
631        let coherence = system.measure_coherence();
632        assert!(coherence >= 0.0 && coherence <= 1.0);
633    }
634
635    #[test]
636    fn test_activation() {
637        let mut system = MultipleSelvesSystem::new();
638
639        let id = system.add_self("Test", EmotionalTone {
640            valence: 0.5,
641            arousal: 0.5,
642            dominance: 0.5,
643        });
644
645        system.activate(id, 0.9);
646
647        let dominant = system.get_dominant();
648        assert!(dominant.is_some());
649        assert_eq!(dominant.unwrap().id, id);
650    }
651
652    #[test]
653    fn test_conflict_and_resolution() {
654        let mut system = MultipleSelvesSystem::new();
655
656        let id1 = system.add_self("Self1", EmotionalTone {
657            valence: 0.8,
658            arousal: 0.5,
659            dominance: 0.7,
660        });
661
662        let id2 = system.add_self("Self2", EmotionalTone {
663            valence: 0.2,
664            arousal: 0.5,
665            dominance: 0.3,
666        });
667
668        system.create_conflict(id1, id2);
669        let initial_coherence = system.measure_coherence();
670
671        system.resolve_conflict(id1, id2);
672        let final_coherence = system.measure_coherence();
673
674        // Coherence should improve after resolution
675        assert!(final_coherence >= initial_coherence);
676    }
677
678    #[test]
679    fn test_merge() {
680        let mut system = MultipleSelvesSystem::new();
681
682        let id1 = system.add_self("Part1", EmotionalTone {
683            valence: 0.6,
684            arousal: 0.4,
685            dominance: 0.5,
686        });
687
688        let id2 = system.add_self("Part2", EmotionalTone {
689            valence: 0.4,
690            arousal: 0.6,
691            dominance: 0.5,
692        });
693
694        assert_eq!(system.self_count(), 2);
695
696        let merged_id = system.merge(id1, id2);
697        assert!(merged_id.is_some());
698        assert_eq!(system.self_count(), 1);
699    }
700
701    #[test]
702    fn test_executive_function() {
703        let mut exec = ExecutiveFunction::new(0.8);
704
705        let selves = vec![
706            SubPersonality {
707                id: Uuid::new_v4(),
708                name: "Strong".to_string(),
709                beliefs: Vec::new(),
710                goals: Vec::new(),
711                emotional_tone: EmotionalTone { valence: 0.5, arousal: 0.5, dominance: 0.9 },
712                activation: 0.8,
713                age: 10,
714                relationships: HashMap::new(),
715            },
716            SubPersonality {
717                id: Uuid::new_v4(),
718                name: "Weak".to_string(),
719                beliefs: Vec::new(),
720                goals: Vec::new(),
721                emotional_tone: EmotionalTone { valence: 0.5, arousal: 0.5, dominance: 0.1 },
722                activation: 0.2,
723                age: 5,
724                relationships: HashMap::new(),
725            },
726        ];
727
728        let winner = exec.arbitrate(&selves, selves[0].id, selves[1].id);
729        assert!(winner.is_some());
730    }
731}