1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! Adaptive Memory System
//!
//! A spreading activation memory system with decay-based relationship strength.
//!
//! # Example
//!
//! ```no_run
//! use adaptive_memory::{MemoryStore, MemoryError, SearchParams};
//!
//! fn main() -> Result<(), MemoryError> {
//! let mut store = MemoryStore::open_in_memory()?;
//!
//! // Add memories
//! store.add("First memory about cats", Some("test"))?;
//! store.add("Second memory about dogs", None)?;
//!
//! // Search with default params
//! let results = store.search("cats", &SearchParams::default())?;
//! for mem in results.memories {
//! println!("{}: {} (energy: {:.2})", mem.memory.id, mem.memory.text, mem.energy);
//! }
//!
//! // Strengthen relationships
//! store.strengthen(&[1, 2])?;
//!
//! Ok(())
//! }
//! ```
use ;
// ============================================================================
// Configuration Constants
// ============================================================================
//
// ## Retrieval Bounds Documentation
//
// These constants create artificial bounds during retrieval. Analysis of why each is acceptable:
//
// ### ENERGY_THRESHOLD (0.01)
// Energy below 1% is not propagated. With energy_decay=0.5, this means ~7 hops max depth.
// Delta propagation accumulates all incoming energy before checking threshold, so weak paths
// that converge are handled correctly. Natural convergence criterion.
//
// ### MAX_SPREADING_ITERATIONS (5000)
// Safety cap for dense graphs. We process highest-energy items first (max-heap), so most
// relevant are processed even if cap is hit. Output includes `iterations` count so callers
// know if cap was reached. Could truncate results on very dense graphs (80k+ relationships).
//
// ### FTS limit (SearchParams.limit, default 100)
// Only top N BM25 matches become seeds. User-configurable via --limit. Standard practice.
//
// ### BM25 normalization floor (0.1 in search.rs)
// Worst FTS match gets 10% seed energy, best gets 100%. Ensures all matches contribute.
//
// ### Result truncation (SearchParams.limit)
// Final results truncated to limit after sorting by energy. Expected behavior.
//
// ### Bidirectional relationships and loops
// Relationships are symmetric (A↔B). Energy can bounce A→B→A but delta propagation handles
// this correctly - each round trip decays by (energy_decay * strength)^2, converging in
// ~4-5 iterations for a simple loop. ENERGY_THRESHOLD catches convergence naturally.
// MAX_SPREADING_ITERATIONS is safety valve, not loop prevention.
//
// ### Context expansion (--context N)
// Instead of pre-computed temporal relationships, context is fetched at query time.
// For each result, we can optionally fetch N memories before/after by ID.
// This is like grep -B/-A for temporal context.
/// Minimum energy threshold to continue propagation.
/// At 0.01 (1% of initial seed energy), with energy_decay=0.5, this allows ~7 hops depth.
pub const ENERGY_THRESHOLD: f64 = 0.01;
/// Maximum iterations for spreading activation (prevents runaway on dense graphs).
/// With delta propagation, typical searches use 50-300 iterations. This is a safety cap.
/// If hit, highest-energy paths are still processed (max-heap ordering).
pub const MAX_SPREADING_ITERATIONS: usize = 5000;
/// Maximum number of memories that can be strengthened at once.
pub const MAX_STRENGTHEN_SET: usize = 10;
/// Default number of results to return from search.
pub const DEFAULT_LIMIT: usize = 50;
// ============================================================================
// Runtime Configuration
// ============================================================================
/// Runtime search parameters.
///
/// All weights and decay factors are configurable at search time,
/// allowing experimentation without recompiling.
// ============================================================================
// Re-exports
// ============================================================================
pub use default_db_path;
pub use MemoryError;
pub use ;
pub use ;
pub use ;
pub use MemoryStore;