Skip to main content

microscope_memory/
pattern_recognition.rs

1//! Pattern Recognition — minta felismerő és tanuló rendszer a Microscope Memory számára
2//!
3//! Képes:
4//! - Szekvenciális minták detektálására (gyakori gondolatmenetek)
5//! - Temporális mintákra (napi ritmusok, ciklikus aktivitás)
6//! - Strukturális motívumokra (architektúra gráfokban)
7//! - Cluster mintákra (memória térbeli csoportosulások)
8//! - Cross-domain korrelációra (minták átfedése különböző rétegek között)
9//!
10//! Kapcsolódások:
11//! - morphogenesis.rs → strukturális motívum detektálás
12//! - temporal_archetype.rs → időbeli mintázatok
13//! - thought_graph.rs → gondolatmenet minták
14//! - hebbian.rs → ko-aktivációs minták
15//! - archetype.rs → kikristályosodott minták
16//! - heuristic_decision.rs → minta-alapú döntéshozatal
17
18use std::collections::{HashMap, HashSet, VecDeque};
19use std::sync::{Arc, RwLock};
20use std::time::{SystemTime, UNIX_EPOCH};
21// ─── Alap Típusok ───────────────────────────────────────────────────────────
22
23/// Minta típusok
24#[derive(Debug, Clone, PartialEq, Hash)]
25pub enum PatternType {
26    /// Ismétlődő szekvencia (gondolatmenet, műveleti sor)
27    Sequence,
28    /// Időbeli ritmus (napi, heti ciklus)
29    Temporal,
30    /// Strukturális motívum (algráf minta)
31    Structural,
32    /// Térbeli klaszter (memória csoportosulás)
33    Cluster,
34    /// Több domainen átívelő minta
35    CrossDomain,
36    /// Ismeretlen / egyedi
37    Unknown,
38}
39
40/// Minta jelentőség
41#[derive(Debug, Clone)]
42pub struct PatternSignificance {
43    /// 0.0 - 1.0: mennyire biztos a minta
44    pub confidence: f64,
45    /// Hányszor detektáltuk
46    pub frequency: u64,
47    /// Utolsó egyezés időbélyege (unix ms)
48    pub last_matched_ms: u64,
49    /// Átlagos hasonlóság az egyezéseknél
50    pub avg_similarity: f64,
51    /// Tanulási ráta (mennyire adaptálódik új adathoz)
52    pub learning_rate: f64,
53}
54
55impl Default for PatternSignificance {
56    fn default() -> Self {
57        Self {
58            confidence: 0.1,
59            frequency: 0,
60            last_matched_ms: 0,
61            avg_similarity: 0.0,
62            learning_rate: 0.3,
63        }
64    }
65}
66
67/// Felismert minta sablon
68#[derive(Debug, Clone)]
69pub struct RecognizedPattern {
70    pub id: u64,
71    pub name: String,
72    pub pattern_type: PatternType,
73    /// Sablon adat (típustól függő)
74    pub template: PatternTemplate,
75    pub significance: PatternSignificance,
76    pub tags: Vec<String>,
77    /// Domain ahonnan származik (pl. "thought", "architecture", "memory")
78    pub domain: String,
79    pub metadata: HashMap<String, String>,
80}
81
82/// Minta sablon adat
83#[derive(Debug, Clone)]
84pub enum PatternTemplate {
85    /// Szekvencia: elemek sorozata (pl. block id-k)
86    Sequence(Vec<String>),
87    /// Temporális: {id, hour, day_of_week, frequency}
88    Temporal(Vec<TemporalSlice>),
89    /// Strukturális: adjacency list minta
90    Structural(Vec<(String, String, f64)>),
91    /// Cluster: középpont + sugár + elemek
92    Cluster {
93        center: (f64, f64, f64),
94        radius: f64,
95        elements: Vec<String>,
96    },
97    /// Minták kombinációja
98    Composite(Vec<u64>),
99}
100
101/// Időbeli szelet
102#[derive(Debug, Clone)]
103pub struct TemporalSlice {
104    pub hour: u8,
105    pub day_of_week: u8,
106    pub frequency: f64,
107    pub avg_intensity: f64,
108    pub activity_ids: Vec<String>,
109}
110
111/// Minta egyezés eredménye
112#[derive(Debug, Clone)]
113pub struct PatternMatch {
114    pub pattern_id: u64,
115    pub target_description: String,
116    pub similarity: f64,
117    pub timestamp_ms: u64,
118    pub matched_elements: Vec<String>,
119    pub details: String,
120}
121
122/// Konfigurációs paraméterek
123#[derive(Debug, Clone)]
124pub struct RecognitionConfig {
125    /// Minimális hasonlóság az egyezéshez (0.0 - 1.0)
126    pub min_similarity: f64,
127    /// Minimális confidence az új minta elfogadásához
128    pub min_confidence: f64,
129    /// Hány találat után tekintünk egy mintát "megerősítettnek"
130    pub confirmation_threshold: u64,
131    /// Maximális minta szám a könyvtárban
132    pub max_patterns: usize,
133    /// Cluster távolság küszöb
134    pub cluster_radius: f64,
135    /// Szekvencia ablak méret
136    pub sequence_window: usize,
137    /// Tanulási ráta (0.0 - 1.0)
138    pub learning_rate: f64,
139}
140
141impl Default for RecognitionConfig {
142    fn default() -> Self {
143        Self {
144            min_similarity: 0.6,
145            min_confidence: 0.3,
146            confirmation_threshold: 3,
147            max_patterns: 1000,
148            cluster_radius: 0.15,
149            sequence_window: 10,
150            learning_rate: 0.3,
151        }
152    }
153}
154// ─── Pattern Recognizer ──────────────────────────────────────────────────────
155
156/// A fő minta felismerő rendszer
157pub struct PatternRecognizer {
158    /// Felismert minták könyvtára
159    patterns: Arc<RwLock<Vec<RecognizedPattern>>>,
160    /// Egyezési előzmények
161    match_history: Arc<RwLock<VecDeque<PatternMatch>>>,
162    /// Konfiguráció
163    config: Arc<RwLock<RecognitionConfig>>,
164    /// Következő ID
165    next_id: Arc<RwLock<u64>>,
166    /// Domain index (pattern_id → domain)
167    domain_index: Arc<RwLock<HashMap<String, Vec<u64>>>>,
168}
169
170impl Default for PatternRecognizer {
171    fn default() -> Self {
172        Self::new()
173    }
174}
175
176impl PatternRecognizer {
177    pub fn new() -> Self {
178        Self {
179            patterns: Arc::new(RwLock::new(Vec::new())),
180            match_history: Arc::new(RwLock::new(VecDeque::with_capacity(1000))),
181            config: Arc::new(RwLock::new(RecognitionConfig::default())),
182            next_id: Arc::new(RwLock::new(1)),
183            domain_index: Arc::new(RwLock::new(HashMap::new())),
184        }
185    }
186
187    pub fn with_config(config: RecognitionConfig) -> Self {
188        Self {
189            config: Arc::new(RwLock::new(config)),
190            ..Self::new()
191        }
192    }
193
194    fn next_id(&self) -> u64 {
195        let mut id = crate::sync_guard::write_lock(&self.next_id);
196        let n = *id;
197        *id += 1;
198        n
199    }
200
201    fn now_ms(&self) -> u64 {
202        SystemTime::now()
203            .duration_since(UNIX_EPOCH)
204            .unwrap_or_default()
205            .as_millis() as u64
206    }
207
208    // ─── Pattern Register ─────────────────────────────────────────────────
209
210    /// Új minta regisztrálása
211    pub fn register_pattern(
212        &self,
213        name: &str,
214        ptype: PatternType,
215        template: PatternTemplate,
216        domain: &str,
217        tags: Vec<String>,
218    ) -> u64 {
219        let id = self.next_id();
220        let pattern = RecognizedPattern {
221            id,
222            name: name.to_string(),
223            pattern_type: ptype,
224            template,
225            significance: PatternSignificance::default(),
226            tags,
227            domain: domain.to_string(),
228            metadata: HashMap::new(),
229        };
230
231        crate::sync_guard::write_lock(&self.patterns).push(pattern);
232        crate::sync_guard::write_lock(&self.domain_index)
233            .entry(domain.to_string())
234            .or_default()
235            .push(id);
236
237        id
238    }
239
240    /// Minta törlése
241    pub fn forget_pattern(&self, id: u64) -> bool {
242        let mut patterns = crate::sync_guard::write_lock(&self.patterns);
243        if let Some(pos) = patterns.iter().position(|p| p.id == id) {
244            let p = patterns.remove(pos);
245            if let Some(ids) = crate::sync_guard::write_lock(&self.domain_index).get_mut(&p.domain)
246            {
247                ids.retain(|&i| i != id);
248            }
249            true
250        } else {
251            false
252        }
253    }
254
255    /// Minták listázása típus szerint
256    pub fn list_patterns(
257        &self,
258        ptype: Option<PatternType>,
259        domain: Option<&str>,
260    ) -> Vec<RecognizedPattern> {
261        crate::sync_guard::read_lock(&self.patterns)
262            .iter()
263            .filter(|p| {
264                let type_match = ptype.as_ref().is_none_or(|t| p.pattern_type == *t);
265                let domain_match = domain.is_none_or(|d| p.domain == d);
266                type_match && domain_match
267            })
268            .cloned()
269            .collect()
270    }
271
272    /// Minta keresés név alapján
273    pub fn find_pattern(&self, name: &str) -> Option<RecognizedPattern> {
274        crate::sync_guard::read_lock(&self.patterns)
275            .iter()
276            .find(|p| p.name == name)
277            .cloned()
278    }
279
280    /// Minta lekérése ID alapján
281    pub fn get_pattern(&self, id: u64) -> Option<RecognizedPattern> {
282        crate::sync_guard::read_lock(&self.patterns)
283            .iter()
284            .find(|p| p.id == id)
285            .cloned()
286    }
287
288    // ─── Szekvencia Detektálás ─────────────────────────────────────────────
289
290    /// Szekvencia minta felismerés: gyakori részsorozatok keresése
291    /// Bemenet: elemek sorozata (pl. block id-k, műveletek, események)
292    /// Kimenet: ismétlődő minták confidenciával
293    pub fn find_sequences(&self, elements: &[String], domain: &str) -> Vec<RecognizedPattern> {
294        let config = crate::sync_guard::read_lock(&self.config).clone();
295        let window = config.sequence_window;
296        let min_sim = config.min_similarity;
297        let mut patterns = Vec::new();
298
299        if elements.len() < 2 {
300            return patterns;
301        }
302
303        // Gyakori 2-3-4 hosszúságú részsorozatok
304        let mut seq_counts: HashMap<Vec<String>, u64> = HashMap::new();
305
306        for len in 2..=window.min(elements.len()).min(5) {
307            for i in 0..=elements.len().saturating_sub(len) {
308                let subseq: Vec<String> = elements[i..i + len].to_vec();
309                *seq_counts.entry(subseq).or_insert(0) += 1;
310            }
311        }
312
313        // Statisztikai szűrés
314        let total = elements.len() as f64;
315        for (seq, count) in &seq_counts {
316            let freq = *count as f64 / total;
317            if freq >= min_sim && seq.len() >= 2 {
318                let confidence = (freq * (1.0 - 1.0 / (seq.len() as f64))).min(1.0);
319
320                let pattern = RecognizedPattern {
321                    id: self.next_id(),
322                    name: format!("seq_{}_{}", domain, seq.first().unwrap_or(&"?".to_string())),
323                    pattern_type: PatternType::Sequence,
324                    template: PatternTemplate::Sequence(seq.clone()),
325                    significance: PatternSignificance {
326                        confidence,
327                        frequency: *count,
328                        last_matched_ms: self.now_ms(),
329                        avg_similarity: freq,
330                        learning_rate: config.learning_rate,
331                    },
332                    tags: vec!["auto_detected".to_string(), format!("len_{}", seq.len())],
333                    domain: domain.to_string(),
334                    metadata: {
335                        let mut m = HashMap::new();
336                        m.insert("frequency".to_string(), format!("{:.2}", freq));
337                        m.insert("sample_count".to_string(), count.to_string());
338                        m
339                    },
340                };
341
342                // Ellenőrizzük, hogy már létezik-e hasonló
343                let exists = crate::sync_guard::read_lock(&self.patterns)
344                    .iter()
345                    .any(|p| {
346                        if let PatternTemplate::Sequence(ref existing) = p.template {
347                            existing == seq
348                        } else {
349                            false
350                        }
351                    });
352
353                if !exists {
354                    let id = pattern.id;
355                    crate::sync_guard::write_lock(&self.patterns).push(pattern.clone());
356                    crate::sync_guard::write_lock(&self.domain_index)
357                        .entry(domain.to_string())
358                        .or_default()
359                        .push(id);
360                }
361
362                patterns.push(pattern);
363            }
364        }
365
366        patterns.sort_by(|a, b| {
367            b.significance
368                .confidence
369                .partial_cmp(&a.significance.confidence)
370                .unwrap()
371        });
372        patterns
373    }
374
375    /// Adott szekvencia egyeztetése ismert mintákkal
376    pub fn match_sequence(&self, sequence: &[String]) -> Vec<PatternMatch> {
377        let config = crate::sync_guard::read_lock(&self.config).clone();
378        let mut matches = Vec::new();
379        let now = self.now_ms();
380
381        for pattern in crate::sync_guard::read_lock(&self.patterns).iter() {
382            if let PatternTemplate::Sequence(ref pattern_seq) = pattern.template {
383                // Részsorozat keresés (pattern hosszabb lehet)
384                if pattern_seq.len() > sequence.len() {
385                    continue;
386                }
387
388                for i in 0..=sequence.len().saturating_sub(pattern_seq.len()) {
389                    let window = &sequence[i..i + pattern_seq.len()];
390                    let sim = self.sequence_similarity(window, pattern_seq);
391
392                    if sim >= config.min_similarity {
393                        matches.push(PatternMatch {
394                            pattern_id: pattern.id,
395                            target_description: format!(
396                                "{:?}..{:?}",
397                                window.first().unwrap_or(&"".to_string()),
398                                window.last().unwrap_or(&"".to_string())
399                            ),
400                            similarity: sim,
401                            timestamp_ms: now,
402                            matched_elements: window.to_vec(),
403                            details: format!(
404                                "Matched sequence pattern '{}' ({})",
405                                pattern.name, pattern.domain
406                            ),
407                        });
408
409                        // Frissítés: frequency növelés
410                        if let Some(p) = crate::sync_guard::write_lock(&self.patterns)
411                            .iter_mut()
412                            .find(|p| p.id == pattern.id)
413                        {
414                            p.significance.frequency += 1;
415                            p.significance.last_matched_ms = now;
416                            p.significance.avg_similarity =
417                                p.significance.avg_similarity * 0.7 + sim * 0.3;
418                            p.significance.confidence = (p.significance.confidence + 0.05).min(1.0);
419                        }
420                    }
421                }
422            }
423        }
424
425        crate::sync_guard::write_lock(&self.match_history).extend(matches.clone());
426        matches
427    }
428
429    /// Két szekvencia hasonlósága (Levenshtein normalizált)
430    fn sequence_similarity(&self, a: &[String], b: &[String]) -> f64 {
431        if a.is_empty() && b.is_empty() {
432            return 1.0;
433        }
434        if a.is_empty() || b.is_empty() {
435            return 0.0;
436        }
437
438        let max_len = a.len().max(b.len()) as f64;
439        let mut matches = 0u64;
440
441        for i in 0..a.len().min(b.len()) {
442            if a[i] == b[i] {
443                matches += 1;
444            }
445        }
446
447        matches as f64 / max_len
448    }
449
450    // ─── Temporális Minta Detektálás ───────────────────────────────────────
451
452    /// Temporális minták keresése időbélyeges eseményekből
453    /// Bemenet: {timestamp_ms, id, intensity} triplek
454    /// Kimenet: napi/heti ritmusok
455    pub fn find_temporal_patterns(
456        &self,
457        events: &[(u64, String, f64)],
458        domain: &str,
459    ) -> Vec<RecognizedPattern> {
460        if events.is_empty() {
461            return Vec::new();
462        }
463        let config = crate::sync_guard::read_lock(&self.config).clone();
464        let mut patterns = Vec::new();
465
466        // Csoportosítás óra × nap szerint
467        let mut hourly: HashMap<(u8, u8), Vec<f64>> = HashMap::new(); // (hour, day) → intensities
468
469        for (ts, _id, intensity) in events {
470            let secs = *ts / 1000;
471            let hour = ((secs / 3600) % 24) as u8;
472            let day = ((secs / 86400) % 7) as u8;
473            hourly.entry((hour, day)).or_default().push(*intensity);
474        }
475
476        // Mintázatok keresése
477        // 1. Csúcsidők (magas aktivitású órák)
478        let mut peak_hours: Vec<(u8, u8, f64)> = hourly
479            .iter()
480            .map(|((h, d), intensities)| {
481                let avg: f64 = intensities.iter().sum::<f64>() / intensities.len() as f64;
482                (*h, *d, avg)
483            })
484            .filter(|(_, _, avg)| *avg > 0.5)
485            .collect();
486
487        peak_hours.sort_by(|a, b| b.2.total_cmp(&a.2));
488
489        if !peak_hours.is_empty() {
490            let slices: Vec<TemporalSlice> = peak_hours
491                .iter()
492                .map(|(h, d, avg)| TemporalSlice {
493                    hour: *h,
494                    day_of_week: *d,
495                    frequency: 1.0,
496                    avg_intensity: *avg,
497                    activity_ids: Vec::new(),
498                })
499                .collect();
500
501            let confidence = (peak_hours.len() as f64 / 24.0).min(1.0) * 0.5;
502
503            let pattern = RecognizedPattern {
504                id: self.next_id(),
505                name: format!("temporal_peak_{}", domain),
506                pattern_type: PatternType::Temporal,
507                template: PatternTemplate::Temporal(slices),
508                significance: PatternSignificance {
509                    confidence,
510                    frequency: events.len() as u64,
511                    last_matched_ms: self.now_ms(),
512                    avg_similarity: confidence,
513                    learning_rate: config.learning_rate,
514                },
515                tags: vec!["auto_detected".to_string(), "peak_hours".to_string()],
516                domain: domain.to_string(),
517                metadata: {
518                    let mut m = HashMap::new();
519                    m.insert("peak_count".to_string(), peak_hours.len().to_string());
520                    m
521                },
522            };
523
524            let id = pattern.id;
525            crate::sync_guard::write_lock(&self.patterns).push(pattern.clone());
526            crate::sync_guard::write_lock(&self.domain_index)
527                .entry(domain.to_string())
528                .or_default()
529                .push(id);
530
531            patterns.push(pattern);
532        }
533
534        // 2. Napi ritmus (reggel/délután/este aktivitás)
535        let day_parts: [(&str, u8, u8); 4] = [
536            ("reggel", 6, 12),
537            ("delutan", 12, 18),
538            ("este", 18, 23),
539            ("hajnal", 0, 6),
540        ];
541
542        for (part_name, start_h, end_h) in &day_parts {
543            let count: usize = hourly
544                .iter()
545                .filter(|((h, _), _)| *h >= *start_h && *h <= *end_h)
546                .map(|(_, v)| v.len())
547                .sum();
548
549            if count > 0 {
550                let total_events: usize = events.len();
551                let ratio = count as f64 / total_events as f64;
552                if ratio > 0.4 {
553                    let slices: Vec<TemporalSlice> = hourly
554                        .iter()
555                        .filter(|((h, _), _)| *h >= *start_h && *h <= *end_h)
556                        .map(|((h, d), intensities)| {
557                            let avg = intensities.iter().sum::<f64>() / intensities.len() as f64;
558                            TemporalSlice {
559                                hour: *h,
560                                day_of_week: *d,
561                                frequency: intensities.len() as f64,
562                                avg_intensity: avg,
563                                activity_ids: Vec::new(),
564                            }
565                        })
566                        .collect();
567
568                    let pattern = RecognizedPattern {
569                        id: self.next_id(),
570                        name: format!("{}_{}", part_name, domain),
571                        pattern_type: PatternType::Temporal,
572                        template: PatternTemplate::Temporal(slices),
573                        significance: PatternSignificance {
574                            confidence: ratio * 0.6,
575                            frequency: count as u64,
576                            last_matched_ms: self.now_ms(),
577                            avg_similarity: ratio,
578                            learning_rate: config.learning_rate,
579                        },
580                        tags: vec!["auto_detected".to_string(), "daily_rhythm".to_string()],
581                        domain: domain.to_string(),
582                        metadata: HashMap::new(),
583                    };
584
585                    let id = pattern.id;
586                    crate::sync_guard::write_lock(&self.patterns).push(pattern.clone());
587                    crate::sync_guard::write_lock(&self.domain_index)
588                        .entry(domain.to_string())
589                        .or_default()
590                        .push(id);
591
592                    patterns.push(pattern);
593                }
594            }
595        }
596
597        patterns
598    }
599    // ─── Strukturális Motívum Detektálás ──────────────────────────────────
600
601    /// Strukturális motívumok keresése gráfban (pl. morphogenesis által növesztett architektúrákban)
602    /// Bemenet: adjacencia lista (from, to, weight)
603    /// Kimenet: gyakori algráf minták (motívumok)
604    pub fn find_motifs(
605        &self,
606        edges: &[(String, String, f64)],
607        domain: &str,
608    ) -> Vec<RecognizedPattern> {
609        let config = crate::sync_guard::read_lock(&self.config).clone();
610        let mut patterns = Vec::new();
611
612        if edges.is_empty() {
613            return patterns;
614        }
615
616        // Gyakori 2-3-4 node-os algráfok (motívumok)
617        // 1. Fan-out: egy node → több node
618        let mut fan_out: HashMap<String, Vec<String>> = HashMap::new();
619        for (from, to, _) in edges {
620            fan_out.entry(from.clone()).or_default().push(to.clone());
621        }
622
623        for (node, targets) in &fan_out {
624            if targets.len() >= 3 {
625                let mut motif_edges: Vec<(String, String, f64)> = Vec::new();
626                for t in targets {
627                    motif_edges.push((node.clone(), t.clone(), 1.0));
628                }
629
630                let confidence = (targets.len() as f64 / 10.0).min(1.0);
631                let pattern = RecognizedPattern {
632                    id: self.next_id(),
633                    name: format!("fan_out_{}", node),
634                    pattern_type: PatternType::Structural,
635                    template: PatternTemplate::Structural(motif_edges),
636                    significance: PatternSignificance {
637                        confidence: confidence * 0.5,
638                        frequency: targets.len() as u64,
639                        last_matched_ms: self.now_ms(),
640                        avg_similarity: confidence,
641                        learning_rate: config.learning_rate,
642                    },
643                    tags: vec!["auto_detected".to_string(), "fan_out".to_string()],
644                    domain: domain.to_string(),
645                    metadata: {
646                        let mut m = HashMap::new();
647                        m.insert("node_count".to_string(), (targets.len() + 1).to_string());
648                        m
649                    },
650                };
651
652                let id = pattern.id;
653                crate::sync_guard::write_lock(&self.patterns).push(pattern.clone());
654                crate::sync_guard::write_lock(&self.domain_index)
655                    .entry(domain.to_string())
656                    .or_default()
657                    .push(id);
658                patterns.push(pattern);
659            }
660        }
661
662        // 2. Fan-in: több node → egy node
663        let mut fan_in: HashMap<String, Vec<String>> = HashMap::new();
664        for (from, to, _) in edges {
665            fan_in.entry(to.clone()).or_default().push(from.clone());
666        }
667
668        for (node, sources) in &fan_in {
669            if sources.len() >= 3 {
670                let mut motif_edges: Vec<(String, String, f64)> = Vec::new();
671                for s in sources {
672                    motif_edges.push((s.clone(), node.clone(), 1.0));
673                }
674
675                let pattern = RecognizedPattern {
676                    id: self.next_id(),
677                    name: format!("fan_in_{}", node),
678                    pattern_type: PatternType::Structural,
679                    template: PatternTemplate::Structural(motif_edges),
680                    significance: PatternSignificance {
681                        confidence: (sources.len() as f64 / 10.0).min(1.0) * 0.5,
682                        frequency: sources.len() as u64,
683                        last_matched_ms: self.now_ms(),
684                        avg_similarity: 0.0,
685                        learning_rate: config.learning_rate,
686                    },
687                    tags: vec!["auto_detected".to_string(), "fan_in".to_string()],
688                    domain: domain.to_string(),
689                    metadata: HashMap::new(),
690                };
691
692                let id = pattern.id;
693                crate::sync_guard::write_lock(&self.patterns).push(pattern.clone());
694                crate::sync_guard::write_lock(&self.domain_index)
695                    .entry(domain.to_string())
696                    .or_default()
697                    .push(id);
698                patterns.push(pattern);
699            }
700        }
701
702        // 3. Hub: magas fokszámú node-ok
703        let mut degrees: HashMap<String, usize> = HashMap::new();
704        for (from, to, _) in edges {
705            *degrees.entry(from.clone()).or_insert(0) += 1;
706            *degrees.entry(to.clone()).or_insert(0) += 1;
707        }
708
709        let avg_degree = degrees.values().sum::<usize>() as f64 / degrees.len().max(1) as f64;
710        for (node, degree) in &degrees {
711            if *degree as f64 > avg_degree * 2.0 && *degree >= 4 {
712                let pattern = RecognizedPattern {
713                    id: self.next_id(),
714                    name: format!("hub_{}", node),
715                    pattern_type: PatternType::Structural,
716                    template: PatternTemplate::Structural(vec![(
717                        node.clone(),
718                        "__hub__".to_string(),
719                        *degree as f64,
720                    )]),
721                    significance: PatternSignificance {
722                        confidence: (*degree as f64 / 20.0).min(1.0) * 0.4,
723                        frequency: *degree as u64,
724                        last_matched_ms: self.now_ms(),
725                        avg_similarity: 0.0,
726                        learning_rate: config.learning_rate,
727                    },
728                    tags: vec!["auto_detected".to_string(), "hub".to_string()],
729                    domain: domain.to_string(),
730                    metadata: {
731                        let mut m = HashMap::new();
732                        m.insert("degree".to_string(), degree.to_string());
733                        m.insert("avg_degree".to_string(), format!("{:.1}", avg_degree));
734                        m
735                    },
736                };
737
738                let id = pattern.id;
739                crate::sync_guard::write_lock(&self.patterns).push(pattern.clone());
740                crate::sync_guard::write_lock(&self.domain_index)
741                    .entry(domain.to_string())
742                    .or_default()
743                    .push(id);
744                patterns.push(pattern);
745            }
746        }
747
748        patterns
749    }
750
751    /// Strukturális motívum keresés morphogenesis organizmusokban
752    pub fn find_motifs_in_organism(
753        &self,
754        _nodes: &[crate::morphogenesis::MorphNode],
755        connections: &[crate::morphogenesis::MorphConnection],
756    ) -> Vec<RecognizedPattern> {
757        let edges: Vec<(String, String, f64)> = connections
758            .iter()
759            .filter(|c| c.is_active)
760            .map(|c| (c.from_node.to_string(), c.to_node.to_string(), c.weight))
761            .collect();
762
763        self.find_motifs(&edges, "morphogenesis")
764    }
765
766    // ─── Cluster Detektálás ────────────────────────────────────────────────
767
768    /// Térbeli klaszterek keresése pontfelhőben (DBSCAN-szerű)
769    /// Bemenet: (x, y, z) koordináták + id
770    /// Kimenet: csoportosulások a memória térben
771    pub fn find_clusters(
772        &self,
773        points: &[(f64, f64, f64, String)],
774        domain: &str,
775    ) -> Vec<RecognizedPattern> {
776        let config = crate::sync_guard::read_lock(&self.config).clone();
777        let mut patterns = Vec::new();
778
779        if points.is_empty() {
780            return patterns;
781        }
782
783        let eps = config.cluster_radius;
784        let min_pts = 3;
785        let mut visited: HashSet<usize> = HashSet::new();
786        let mut clusters: Vec<Vec<usize>> = Vec::new();
787
788        for i in 0..points.len() {
789            if visited.contains(&i) {
790                continue;
791            }
792
793            let mut neighbors: Vec<usize> = points
794                .iter()
795                .enumerate()
796                .filter(|(j, _)| {
797                    let dist = ((points[i].0 - points[*j].0).powi(2)
798                        + (points[i].1 - points[*j].1).powi(2)
799                        + (points[i].2 - points[*j].2).powi(2))
800                    .sqrt();
801                    dist <= eps
802                })
803                .map(|(j, _)| j)
804                .collect();
805
806            if neighbors.len() < min_pts {
807                visited.insert(i);
808                continue; // noise
809            }
810
811            // Cluster kiterjesztése
812            let mut cluster: Vec<usize> = Vec::new();
813            while let Some(seed) = neighbors.pop() {
814                if visited.contains(&seed) {
815                    continue;
816                }
817                visited.insert(seed);
818                cluster.push(seed);
819
820                let seed_neighbors: Vec<usize> = points
821                    .iter()
822                    .enumerate()
823                    .filter(|(j, _)| !visited.contains(j))
824                    .filter(|(j, _)| {
825                        let dist = ((points[seed].0 - points[*j].0).powi(2)
826                            + (points[seed].1 - points[*j].1).powi(2)
827                            + (points[seed].2 - points[*j].2).powi(2))
828                        .sqrt();
829                        dist <= eps
830                    })
831                    .map(|(j, _)| j)
832                    .collect();
833
834                neighbors.extend(seed_neighbors);
835            }
836
837            if cluster.len() >= min_pts {
838                clusters.push(cluster);
839            }
840        }
841
842        // Cluster minták létrehozása
843        for (ci, cluster) in clusters.iter().enumerate() {
844            let cluster_points: Vec<&(f64, f64, f64, String)> =
845                cluster.iter().map(|&i| &points[i]).collect();
846
847            // Középpont
848            let cx = cluster_points.iter().map(|p| p.0).sum::<f64>() / cluster_points.len() as f64;
849            let cy = cluster_points.iter().map(|p| p.1).sum::<f64>() / cluster_points.len() as f64;
850            let cz = cluster_points.iter().map(|p| p.2).sum::<f64>() / cluster_points.len() as f64;
851
852            // Átlagos távolság a középponttól
853            let avg_dist: f64 = cluster_points
854                .iter()
855                .map(|p| ((p.0 - cx).powi(2) + (p.1 - cy).powi(2) + (p.2 - cz).powi(2)).sqrt())
856                .sum::<f64>()
857                / cluster_points.len() as f64;
858
859            let element_ids: Vec<String> = cluster_points.iter().map(|p| p.3.clone()).collect();
860            let density =
861                cluster.len() as f64 / (avg_dist * avg_dist * 4.0 * std::f64::consts::PI).max(0.01);
862
863            let pattern = RecognizedPattern {
864                id: self.next_id(),
865                name: format!("cluster_{}_{}", domain, ci),
866                pattern_type: PatternType::Cluster,
867                template: PatternTemplate::Cluster {
868                    center: (cx, cy, cz),
869                    radius: avg_dist,
870                    elements: element_ids.clone(),
871                },
872                significance: PatternSignificance {
873                    confidence: (density / 100.0).min(1.0),
874                    frequency: element_ids.len() as u64,
875                    last_matched_ms: self.now_ms(),
876                    avg_similarity: 1.0 - (avg_dist / 1.0).min(1.0),
877                    learning_rate: config.learning_rate,
878                },
879                tags: vec!["auto_detected".to_string(), "cluster".to_string()],
880                domain: domain.to_string(),
881                metadata: {
882                    let mut m = HashMap::new();
883                    m.insert("size".to_string(), cluster.len().to_string());
884                    m.insert("density".to_string(), format!("{:.3}", density));
885                    m
886                },
887            };
888
889            let id = pattern.id;
890            crate::sync_guard::write_lock(&self.patterns).push(pattern.clone());
891            crate::sync_guard::write_lock(&self.domain_index)
892                .entry(domain.to_string())
893                .or_default()
894                .push(id);
895            patterns.push(pattern);
896        }
897
898        patterns
899    }
900    // ─── Cross-domain Korreláció ──────────────────────────────────────────
901
902    /// Különböző domain-ekből származó minták korrelációja
903    /// Keres olyan mintákat, amelyek több domain-ben is előfordulnak
904    /// (pl. ugyanaz a szekvencia megjelenik thought és recall domain-ben is)
905    pub fn cross_correlate(&self) -> Vec<RecognizedPattern> {
906        let config = crate::sync_guard::read_lock(&self.config).clone();
907        let mut composite_patterns = Vec::new();
908
909        let patterns = crate::sync_guard::read_lock(&self.patterns);
910        let domains: Vec<String> = crate::sync_guard::read_lock(&self.domain_index)
911            .keys()
912            .cloned()
913            .collect();
914
915        if domains.len() < 2 {
916            return Vec::new();
917        }
918
919        // Domain párok keresése, ahol hasonló minták vannak
920        for i in 0..domains.len() {
921            for j in (i + 1)..domains.len() {
922                let d1 = &domains[i];
923                let d2 = &domains[j];
924
925                let p1: Vec<&RecognizedPattern> =
926                    patterns.iter().filter(|p| p.domain == *d1).collect();
927                let p2: Vec<&RecognizedPattern> =
928                    patterns.iter().filter(|p| p.domain == *d2).collect();
929
930                for pat1 in &p1 {
931                    for pat2 in &p2 {
932                        // Csak azonos típusú mintákat korrelálunk
933                        if pat1.pattern_type != pat2.pattern_type {
934                            continue;
935                        }
936
937                        let sim = match (&pat1.template, &pat2.template) {
938                            (PatternTemplate::Sequence(s1), PatternTemplate::Sequence(s2)) => {
939                                self.sequence_similarity(s1, s2)
940                            }
941                            (PatternTemplate::Structural(e1), PatternTemplate::Structural(e2)) => {
942                                let common = e1.iter().filter(|e| e2.contains(e)).count();
943                                let max = e1.len().max(e2.len()).max(1);
944                                common as f64 / max as f64
945                            }
946                            _ => 0.0,
947                        };
948
949                        if sim > config.min_similarity * 1.2 {
950                            // szigorúbb küszöb
951                            let composite_id = self.next_id();
952                            let composite = RecognizedPattern {
953                                id: composite_id,
954                                name: format!("cross_{}_{}", pat1.name, pat2.name),
955                                pattern_type: PatternType::CrossDomain,
956                                template: PatternTemplate::Composite(vec![pat1.id, pat2.id]),
957                                significance: PatternSignificance {
958                                    confidence: sim * 0.8,
959                                    frequency: pat1.significance.frequency
960                                        + pat2.significance.frequency,
961                                    last_matched_ms: self.now_ms(),
962                                    avg_similarity: sim,
963                                    learning_rate: config.learning_rate,
964                                },
965                                tags: vec!["auto_detected".to_string(), "cross_domain".to_string()],
966                                domain: format!("cross:{}:{}", d1, d2),
967                                metadata: {
968                                    let mut m = HashMap::new();
969                                    m.insert("domain_a".to_string(), d1.clone());
970                                    m.insert("domain_b".to_string(), d2.clone());
971                                    m
972                                },
973                            };
974
975                            composite_patterns.push(composite);
976                        }
977                    }
978                }
979            }
980        }
981
982        // Cross-domain minták regisztrálása
983        for cp in &composite_patterns {
984            let id = cp.id;
985            crate::sync_guard::write_lock(&self.patterns).push(cp.clone());
986            crate::sync_guard::write_lock(&self.domain_index)
987                .entry(cp.domain.clone())
988                .or_default()
989                .push(id);
990        }
991
992        composite_patterns
993    }
994
995    // ─── Konszolidáció ─────────────────────────────────────────────────────
996
997    /// Hasonló minták összevonása, gyenge minták elfelejtése
998    pub fn consolidate(&self) -> usize {
999        let config = crate::sync_guard::read_lock(&self.config).clone();
1000        let mut patterns = crate::sync_guard::write_lock(&self.patterns);
1001        let before = patterns.len();
1002
1003        // 1. Alacsony confidence-ű minták eltávolítása
1004        patterns.retain(|p| {
1005            p.significance.confidence >= config.min_confidence
1006                || p.significance.frequency >= config.confirmation_threshold
1007        });
1008
1009        // 2. Hasonló minták összevonása (azonos típus + magas hasonlóság)
1010        let mut i = 0;
1011        while i < patterns.len() {
1012            let mut j = i + 1;
1013            while j < patterns.len() {
1014                let should_merge = patterns[i].pattern_type == patterns[j].pattern_type
1015                    && patterns[i].domain == patterns[j].domain
1016                    && match (&patterns[i].template, &patterns[j].template) {
1017                        (PatternTemplate::Sequence(s1), PatternTemplate::Sequence(s2)) => {
1018                            self.sequence_similarity(s1, s2) > 0.8
1019                        }
1020                        _ => false,
1021                    };
1022
1023                if should_merge {
1024                    patterns[i].significance.frequency += patterns[j].significance.frequency;
1025                    patterns[i].significance.confidence = patterns[i]
1026                        .significance
1027                        .confidence
1028                        .max(patterns[j].significance.confidence);
1029                    patterns.remove(j);
1030                } else {
1031                    j += 1;
1032                }
1033            }
1034            i += 1;
1035        }
1036
1037        // 3. Max patterns limit
1038        while patterns.len() > config.max_patterns {
1039            // Leggyengébb eltávolítása
1040            let min_pos = (0..patterns.len())
1041                .min_by(|&a, &b| {
1042                    patterns[a]
1043                        .significance
1044                        .confidence
1045                        .partial_cmp(&patterns[b].significance.confidence)
1046                        .unwrap()
1047                })
1048                .unwrap_or(0);
1049            patterns.remove(min_pos);
1050        }
1051
1052        before - patterns.len()
1053    }
1054
1055    // ─── Statisztikák ──────────────────────────────────────────────────────
1056
1057    /// Rendszer statisztikák
1058    pub fn stats(&self) -> (usize, usize, usize, f64) {
1059        let patterns = crate::sync_guard::read_lock(&self.patterns);
1060
1061        let total = patterns.len();
1062        let seq_count = patterns
1063            .iter()
1064            .filter(|p| p.pattern_type == PatternType::Sequence)
1065            .count();
1066        let struct_count = patterns
1067            .iter()
1068            .filter(|p| p.pattern_type == PatternType::Structural)
1069            .count();
1070        let avg_confidence = if total > 0 {
1071            patterns
1072                .iter()
1073                .map(|p| p.significance.confidence)
1074                .sum::<f64>()
1075                / total as f64
1076        } else {
1077            0.0
1078        };
1079
1080        (total, seq_count, struct_count, avg_confidence)
1081    }
1082
1083    /// Friss egyezések lekérése
1084    pub fn recent_matches(&self, k: usize) -> Vec<PatternMatch> {
1085        crate::sync_guard::read_lock(&self.match_history)
1086            .iter()
1087            .rev()
1088            .take(k)
1089            .cloned()
1090            .collect()
1091    }
1092
1093    /// Konfiguráció frissítése
1094    pub fn set_config(&self, config: RecognitionConfig) {
1095        *crate::sync_guard::write_lock(&self.config) = config;
1096    }
1097
1098    /// Konfiguráció olvasása
1099    pub fn get_config(&self) -> RecognitionConfig {
1100        crate::sync_guard::read_lock(&self.config).clone()
1101    }
1102
1103    /// Domain-ek listázása
1104    pub fn list_domains(&self) -> Vec<String> {
1105        crate::sync_guard::read_lock(&self.domain_index)
1106            .keys()
1107            .cloned()
1108            .collect()
1109    }
1110
1111    /// Domain szerinti minta szám
1112    pub fn domain_pattern_count(&self, domain: &str) -> usize {
1113        crate::sync_guard::read_lock(&self.domain_index)
1114            .get(domain)
1115            .map(|ids| ids.len())
1116            .unwrap_or(0)
1117    }
1118}
1119
1120// ─── Segédfüggvények ────────────────────────────────────────────────────────
1121
1122/// PatternType Display
1123impl std::fmt::Display for PatternType {
1124    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1125        match self {
1126            PatternType::Sequence => write!(f, "Sequence"),
1127            PatternType::Temporal => write!(f, "Temporal"),
1128            PatternType::Structural => write!(f, "Structural"),
1129            PatternType::Cluster => write!(f, "Cluster"),
1130            PatternType::CrossDomain => write!(f, "CrossDomain"),
1131            PatternType::Unknown => write!(f, "Unknown"),
1132        }
1133    }
1134}
1135
1136impl std::fmt::Display for RecognizedPattern {
1137    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1138        write!(
1139            f,
1140            "Pattern #{} [{}] '{}' — {} ({:.1}% confidence, {} freq)",
1141            self.id,
1142            self.pattern_type,
1143            self.name,
1144            self.domain,
1145            self.significance.confidence * 100.0,
1146            self.significance.frequency
1147        )
1148    }
1149}