Skip to main content

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 serde::{Deserialize, Serialize};
22use std::collections::HashMap;
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    #[allow(dead_code)]
155    stability: f64,
156}
157
158/// Event in integration history
159#[derive(Debug, Clone)]
160pub struct IntegrationEvent {
161    pub event_type: IntegrationType,
162    pub selves_involved: Vec<Uuid>,
163    pub timestamp: u64,
164    pub outcome: f64,
165}
166
167#[derive(Debug, Clone, PartialEq)]
168pub enum IntegrationType {
169    Merge,
170    Split,
171    Activation,
172    Deactivation,
173    Conflict,
174    Resolution,
175}
176
177impl MultipleSelvesSystem {
178    /// Create a new multiple selves system
179    pub fn new() -> Self {
180        Self {
181            selves: Vec::new(),
182            dominant: None,
183            executive: ExecutiveFunction::new(0.7),
184            coherence: SelfCoherence::new(),
185            integration_history: Vec::new(),
186        }
187    }
188
189    /// Add a new sub-personality
190    pub fn add_self(&mut self, name: &str, emotional_tone: EmotionalTone) -> Uuid {
191        let id = Uuid::new_v4();
192        self.selves.push(SubPersonality {
193            id,
194            name: name.to_string(),
195            beliefs: Vec::new(),
196            goals: Vec::new(),
197            emotional_tone,
198            activation: 0.5,
199            age: 0,
200            relationships: HashMap::new(),
201        });
202
203        if self.dominant.is_none() {
204            self.dominant = Some(id);
205        }
206
207        id
208    }
209
210    /// Measure overall coherence
211    pub fn measure_coherence(&mut self) -> f64 {
212        if self.selves.is_empty() {
213            return 1.0; // Single self = perfectly coherent
214        }
215
216        // Calculate belief consistency
217        let belief_coherence = self.calculate_belief_coherence();
218
219        // Calculate goal alignment
220        let goal_alignment = self.calculate_goal_alignment();
221
222        // Calculate relationship harmony
223        let harmony = self.calculate_harmony();
224
225        // Overall coherence
226        self.coherence.score = (belief_coherence + goal_alignment + harmony) / 3.0;
227        self.coherence.integration = (belief_coherence + goal_alignment) / 2.0;
228        self.coherence.conflict = 1.0 - harmony;
229
230        self.coherence.score
231    }
232
233    fn calculate_belief_coherence(&self) -> f64 {
234        if self.selves.len() < 2 {
235            return 1.0;
236        }
237
238        let mut total_similarity = 0.0;
239        let mut count = 0;
240
241        for i in 0..self.selves.len() {
242            for j in i + 1..self.selves.len() {
243                let sim = self.belief_similarity(&self.selves[i], &self.selves[j]);
244                total_similarity += sim;
245                count += 1;
246            }
247        }
248
249        if count > 0 {
250            total_similarity / count as f64
251        } else {
252            1.0
253        }
254    }
255
256    fn belief_similarity(&self, a: &SubPersonality, b: &SubPersonality) -> f64 {
257        if a.beliefs.is_empty() || b.beliefs.is_empty() {
258            return 0.5; // Neutral if no beliefs
259        }
260
261        // Compare emotional tones as proxy for beliefs
262        let valence_diff = (a.emotional_tone.valence - b.emotional_tone.valence).abs();
263        let arousal_diff = (a.emotional_tone.arousal - b.emotional_tone.arousal).abs();
264
265        1.0 - (valence_diff + arousal_diff) / 2.0
266    }
267
268    fn calculate_goal_alignment(&self) -> f64 {
269        if self.selves.len() < 2 {
270            return 1.0;
271        }
272
273        // Check if goals point in same direction
274        let mut total_alignment = 0.0;
275        let mut count = 0;
276
277        for self_entity in &self.selves {
278            for goal in &self_entity.goals {
279                total_alignment += goal.priority * goal.progress;
280                count += 1;
281            }
282        }
283
284        if count > 0 {
285            (total_alignment / count as f64).min(1.0)
286        } else {
287            0.5
288        }
289    }
290
291    fn calculate_harmony(&self) -> f64 {
292        let mut positive_relationships = 0;
293        let mut total_relationships = 0;
294
295        for self_entity in &self.selves {
296            for (_, rel) in &self_entity.relationships {
297                total_relationships += 1;
298                if matches!(
299                    rel.relationship_type,
300                    RelationshipType::Ally
301                        | RelationshipType::Protector
302                        | RelationshipType::Neutral
303                ) {
304                    positive_relationships += 1;
305                }
306            }
307        }
308
309        if total_relationships > 0 {
310            positive_relationships as f64 / total_relationships as f64
311        } else {
312            0.5 // Neutral if no relationships
313        }
314    }
315
316    /// Activate a sub-personality
317    pub fn activate(&mut self, self_id: Uuid, level: f64) {
318        if let Some(self_entity) = self.selves.iter_mut().find(|s| s.id == self_id) {
319            self_entity.activation = level.clamp(0.0, 1.0);
320
321            self.integration_history.push(IntegrationEvent {
322                event_type: IntegrationType::Activation,
323                selves_involved: vec![self_id],
324                timestamp: std::time::SystemTime::now()
325                    .duration_since(std::time::UNIX_EPOCH)
326                    .map(|d| d.as_secs())
327                    .unwrap_or(0),
328                outcome: level,
329            });
330        }
331
332        // Update dominant if necessary
333        self.update_dominant();
334    }
335
336    fn update_dominant(&mut self) {
337        self.dominant = self
338            .selves
339            .iter()
340            .max_by(|a, b| a.activation.partial_cmp(&b.activation).unwrap())
341            .map(|s| s.id);
342    }
343
344    /// Create conflict between selves
345    pub fn create_conflict(&mut self, self1: Uuid, self2: Uuid) {
346        if let Some(s1) = self.selves.iter_mut().find(|s| s.id == self1) {
347            s1.relationships.insert(
348                self2,
349                Relationship {
350                    other_id: self2,
351                    relationship_type: RelationshipType::Rival,
352                    strength: 0.7,
353                },
354            );
355        }
356
357        if let Some(s2) = self.selves.iter_mut().find(|s| s.id == self2) {
358            s2.relationships.insert(
359                self1,
360                Relationship {
361                    other_id: self1,
362                    relationship_type: RelationshipType::Rival,
363                    strength: 0.7,
364                },
365            );
366        }
367
368        self.integration_history.push(IntegrationEvent {
369            event_type: IntegrationType::Conflict,
370            selves_involved: vec![self1, self2],
371            timestamp: std::time::SystemTime::now()
372                .duration_since(std::time::UNIX_EPOCH)
373                .map(|d| d.as_secs())
374                .unwrap_or(0),
375            outcome: -0.5,
376        });
377    }
378
379    /// Resolve conflict through executive function
380    pub fn resolve_conflict(&mut self, self1: Uuid, self2: Uuid) -> Option<Uuid> {
381        let winner = self.executive.arbitrate(&self.selves, self1, self2);
382
383        if winner.is_some() {
384            // Update relationship to neutral
385            if let Some(s1) = self.selves.iter_mut().find(|s| s.id == self1) {
386                if let Some(rel) = s1.relationships.get_mut(&self2) {
387                    rel.relationship_type = RelationshipType::Neutral;
388                }
389            }
390
391            if let Some(s2) = self.selves.iter_mut().find(|s| s.id == self2) {
392                if let Some(rel) = s2.relationships.get_mut(&self1) {
393                    rel.relationship_type = RelationshipType::Neutral;
394                }
395            }
396
397            self.integration_history.push(IntegrationEvent {
398                event_type: IntegrationType::Resolution,
399                selves_involved: vec![self1, self2],
400                timestamp: std::time::SystemTime::now()
401                    .duration_since(std::time::UNIX_EPOCH)
402                    .map(|d| d.as_secs())
403                    .unwrap_or(0),
404                outcome: 0.8,
405            });
406        }
407
408        winner
409    }
410
411    /// Merge two sub-personalities
412    pub fn merge(&mut self, self1: Uuid, self2: Uuid) -> Option<Uuid> {
413        let s1_idx = self.selves.iter().position(|s| s.id == self1)?;
414        let s2_idx = self.selves.iter().position(|s| s.id == self2)?;
415
416        // Create merged self
417        let merged_id = Uuid::new_v4();
418        let s1 = &self.selves[s1_idx];
419        let s2 = &self.selves[s2_idx];
420
421        let merged = SubPersonality {
422            id: merged_id,
423            name: format!("{}-{}", s1.name, s2.name),
424            beliefs: [s1.beliefs.clone(), s2.beliefs.clone()].concat(),
425            goals: [s1.goals.clone(), s2.goals.clone()].concat(),
426            emotional_tone: EmotionalTone {
427                valence: (s1.emotional_tone.valence + s2.emotional_tone.valence) / 2.0,
428                arousal: (s1.emotional_tone.arousal + s2.emotional_tone.arousal) / 2.0,
429                dominance: (s1.emotional_tone.dominance + s2.emotional_tone.dominance) / 2.0,
430            },
431            activation: (s1.activation + s2.activation) / 2.0,
432            age: s1.age.max(s2.age),
433            relationships: HashMap::new(),
434        };
435
436        // Remove old selves (handle indices carefully)
437        let (first, second) = if s1_idx > s2_idx {
438            (s1_idx, s2_idx)
439        } else {
440            (s2_idx, s1_idx)
441        };
442        self.selves.remove(first);
443        self.selves.remove(second);
444
445        self.selves.push(merged);
446
447        self.integration_history.push(IntegrationEvent {
448            event_type: IntegrationType::Merge,
449            selves_involved: vec![self1, self2, merged_id],
450            timestamp: std::time::SystemTime::now()
451                .duration_since(std::time::UNIX_EPOCH)
452                .map(|d| d.as_secs())
453                .unwrap_or(0),
454            outcome: 1.0,
455        });
456
457        Some(merged_id)
458    }
459
460    /// Get dominant self
461    pub fn get_dominant(&self) -> Option<&SubPersonality> {
462        self.dominant
463            .and_then(|id| self.selves.iter().find(|s| s.id == id))
464    }
465
466    /// Get all selves
467    pub fn all_selves(&self) -> &[SubPersonality] {
468        &self.selves
469    }
470
471    /// Get self count
472    pub fn self_count(&self) -> usize {
473        self.selves.len()
474    }
475
476    /// Get coherence
477    pub fn coherence(&self) -> &SelfCoherence {
478        &self.coherence
479    }
480}
481
482impl Default for MultipleSelvesSystem {
483    fn default() -> Self {
484        Self::new()
485    }
486}
487
488impl ExecutiveFunction {
489    /// Create new executive function
490    pub fn new(strength: f64) -> Self {
491        Self {
492            strength,
493            threshold: 0.6,
494            decisions: Vec::new(),
495            style: ResolutionStyle::Negotiation,
496        }
497    }
498
499    /// Arbitrate between two selves
500    pub fn arbitrate(&mut self, selves: &[SubPersonality], id1: Uuid, id2: Uuid) -> Option<Uuid> {
501        let s1 = selves.iter().find(|s| s.id == id1)?;
502        let s2 = selves.iter().find(|s| s.id == id2)?;
503
504        let outcome = match self.style {
505            ResolutionStyle::Dominance => {
506                // Most activated wins
507                if s1.activation > s2.activation {
508                    DecisionOutcome::Majority(id1, s1.activation - s2.activation)
509                } else {
510                    DecisionOutcome::Majority(id2, s2.activation - s1.activation)
511                }
512            }
513            ResolutionStyle::Averaging => {
514                // Neither wins clearly
515                DecisionOutcome::Conflict
516            }
517            ResolutionStyle::Negotiation => {
518                // Executive decides based on strength
519                if self.strength > self.threshold {
520                    let winner = if s1.emotional_tone.dominance > s2.emotional_tone.dominance {
521                        id1
522                    } else {
523                        id2
524                    };
525                    DecisionOutcome::Executive(winner)
526                } else {
527                    DecisionOutcome::Conflict
528                }
529            }
530            ResolutionStyle::TurnTaking => {
531                // Alternate based on history
532                let last_winner = self.decisions.last().and_then(|d| match &d.outcome {
533                    DecisionOutcome::Unanimous(id)
534                    | DecisionOutcome::Majority(id, _)
535                    | DecisionOutcome::Executive(id) => Some(*id),
536                    _ => None,
537                });
538
539                let winner = match last_winner {
540                    Some(w) if w == id1 => id2,
541                    Some(w) if w == id2 => id1,
542                    _ => id1,
543                };
544                DecisionOutcome::Majority(winner, 0.5)
545            }
546        };
547
548        let winner = match &outcome {
549            DecisionOutcome::Unanimous(id)
550            | DecisionOutcome::Majority(id, _)
551            | DecisionOutcome::Executive(id) => Some(*id),
552            DecisionOutcome::Conflict => None,
553        };
554
555        self.decisions.push(Decision {
556            id: Uuid::new_v4(),
557            participants: vec![id1, id2],
558            outcome,
559            timestamp: std::time::SystemTime::now()
560                .duration_since(std::time::UNIX_EPOCH)
561                .map(|d| d.as_secs())
562                .unwrap_or(0),
563        });
564
565        winner
566    }
567
568    /// Set resolution style
569    pub fn set_style(&mut self, style: ResolutionStyle) {
570        self.style = style;
571    }
572}
573
574impl SelfCoherence {
575    /// Create new coherence tracker
576    pub fn new() -> Self {
577        Self {
578            score: 1.0,
579            conflict: 0.0,
580            integration: 1.0,
581            stability: 1.0,
582        }
583    }
584
585    /// Get coherence score
586    pub fn score(&self) -> f64 {
587        self.score
588    }
589
590    /// Get conflict level
591    pub fn conflict(&self) -> f64 {
592        self.conflict
593    }
594
595    /// Get integration level
596    pub fn integration(&self) -> f64 {
597        self.integration
598    }
599}
600
601impl Default for SelfCoherence {
602    fn default() -> Self {
603        Self::new()
604    }
605}
606
607#[cfg(test)]
608mod tests {
609    use super::*;
610
611    #[test]
612    fn test_multiple_selves_creation() {
613        let system = MultipleSelvesSystem::new();
614        assert_eq!(system.self_count(), 0);
615    }
616
617    #[test]
618    fn test_add_selves() {
619        let mut system = MultipleSelvesSystem::new();
620
621        let id1 = system.add_self(
622            "Protector",
623            EmotionalTone {
624                valence: 0.3,
625                arousal: 0.7,
626                dominance: 0.8,
627            },
628        );
629
630        let id2 = system.add_self(
631            "Inner Child",
632            EmotionalTone {
633                valence: 0.8,
634                arousal: 0.6,
635                dominance: 0.3,
636            },
637        );
638
639        assert_eq!(system.self_count(), 2);
640        assert_ne!(id1, id2);
641    }
642
643    #[test]
644    fn test_coherence_measurement() {
645        let mut system = MultipleSelvesSystem::new();
646
647        // Single self = high coherence
648        system.add_self(
649            "Core",
650            EmotionalTone {
651                valence: 0.5,
652                arousal: 0.5,
653                dominance: 0.5,
654            },
655        );
656
657        let coherence = system.measure_coherence();
658        assert!(coherence >= 0.0 && coherence <= 1.0);
659    }
660
661    #[test]
662    fn test_activation() {
663        let mut system = MultipleSelvesSystem::new();
664
665        let id = system.add_self(
666            "Test",
667            EmotionalTone {
668                valence: 0.5,
669                arousal: 0.5,
670                dominance: 0.5,
671            },
672        );
673
674        system.activate(id, 0.9);
675
676        let dominant = system.get_dominant();
677        assert!(dominant.is_some());
678        assert_eq!(dominant.unwrap().id, id);
679    }
680
681    #[test]
682    fn test_conflict_and_resolution() {
683        let mut system = MultipleSelvesSystem::new();
684
685        let id1 = system.add_self(
686            "Self1",
687            EmotionalTone {
688                valence: 0.8,
689                arousal: 0.5,
690                dominance: 0.7,
691            },
692        );
693
694        let id2 = system.add_self(
695            "Self2",
696            EmotionalTone {
697                valence: 0.2,
698                arousal: 0.5,
699                dominance: 0.3,
700            },
701        );
702
703        system.create_conflict(id1, id2);
704        let initial_coherence = system.measure_coherence();
705
706        system.resolve_conflict(id1, id2);
707        let final_coherence = system.measure_coherence();
708
709        // Coherence should improve after resolution
710        assert!(final_coherence >= initial_coherence);
711    }
712
713    #[test]
714    fn test_merge() {
715        let mut system = MultipleSelvesSystem::new();
716
717        let id1 = system.add_self(
718            "Part1",
719            EmotionalTone {
720                valence: 0.6,
721                arousal: 0.4,
722                dominance: 0.5,
723            },
724        );
725
726        let id2 = system.add_self(
727            "Part2",
728            EmotionalTone {
729                valence: 0.4,
730                arousal: 0.6,
731                dominance: 0.5,
732            },
733        );
734
735        assert_eq!(system.self_count(), 2);
736
737        let merged_id = system.merge(id1, id2);
738        assert!(merged_id.is_some());
739        assert_eq!(system.self_count(), 1);
740    }
741
742    #[test]
743    fn test_executive_function() {
744        let mut exec = ExecutiveFunction::new(0.8);
745
746        let selves = vec![
747            SubPersonality {
748                id: Uuid::new_v4(),
749                name: "Strong".to_string(),
750                beliefs: Vec::new(),
751                goals: Vec::new(),
752                emotional_tone: EmotionalTone {
753                    valence: 0.5,
754                    arousal: 0.5,
755                    dominance: 0.9,
756                },
757                activation: 0.8,
758                age: 10,
759                relationships: HashMap::new(),
760            },
761            SubPersonality {
762                id: Uuid::new_v4(),
763                name: "Weak".to_string(),
764                beliefs: Vec::new(),
765                goals: Vec::new(),
766                emotional_tone: EmotionalTone {
767                    valence: 0.5,
768                    arousal: 0.5,
769                    dominance: 0.1,
770                },
771                activation: 0.2,
772                age: 5,
773                relationships: HashMap::new(),
774            },
775        ];
776
777        let winner = exec.arbitrate(&selves, selves[0].id, selves[1].id);
778        assert!(winner.is_some());
779    }
780}