PageSourceSearch

https://www.powermem.ai/assets/js/6d78941f.eb069253.js

js powermem.ai collected 2026-10-05 12:27:03 UTC 50,868 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkwebsite_docusaurus=globalThis.webpackChunkwebsite_docusaurus||[]).push([[3706],{5687(e,n,t){t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>o,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"guides/ebbinghaus_forgetting_curve","title":"ebbinghaus_forgetting_curve","description":"Prerequisites","source":"@site/docs/guides/0008-ebbinghaus_forgetting_curve.md","sourceDirName":"guides","slug":"/guides/ebbinghaus_forgetting_curve","permalink":"/docs/guides/ebbinghaus_forgetting_curve","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":8,"frontMatter":{},"sidebar":"docsSidebar","previous":{"title":"multimodal","permalink":"/docs/guides/multimodal"},"next":{"title":"Integrations Guide","permalink":"/docs/guides/integrations"}}');var r=t(4848),s=t(8453);const o={},a=void 0,l={},d=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Configuration",id:"configuration",level:2},{value:"Create <code>.env</code> File",id:"create-env-file",level:3},{value:"Using JSON/Dictionary Configuration",id:"using-jsondictionary-configuration",level:3},{value:"What is the Ebbinghaus Forgetting Curve?",id:"what-is-the-ebbinghaus-forgetting-curve",level:2},{value:"Key Insights",id:"key-insights",level:3},{value:"Why This Matters for AI Memory Systems",id:"why-this-matters-for-ai-memory-systems",level:3},{value:"Use Cases",id:"use-cases",level:3},{value:"Guide Overview",id:"guide-overview",level:2},{value:"Understanding the Forgetting Curve Formula",id:"understanding-the-forgetting-curve-formula",level:2},{value:"Mathematical Foundation",id:"mathematical-foundation",level:3},{value:"Implementation Approach",id:"implementation-approach",level:3},{value:"Why This Formula Works",id:"why-this-formula-works",level:3},{value:"Customization Options",id:"customization-options",level:3},{value:"Add Memories with Timestamps",id:"add-memories-with-timestamps",level:2},{value:"Why Track Timestamps?",id:"why-track-timestamps",level:3},{value:"Implementation Strategy",id:"implementation-strategy",level:3},{value:"Best Practices",id:"best-practices",level:3},{value:"Example Implementation",id:"example-implementation",level:3},{value:"Calculate Retention Scores for Memories",id:"calculate-retention-scores-for-memories",level:2},{value:"What Are Retention Scores?",id:"what-are-retention-scores",level:3},{value:"How to Use Retention Scores",id:"how-to-use-retention-scores",level:3},{value:"Implementation Workflow",id:"implementation-workflow",level:3},{value:"Interpreting Results",id:"interpreting-results",level:3},{value:"Apply Time-Based Weighting to Search Results",id:"apply-time-based-weighting-to-search-results",level:2},{value:"The Problem with Pure Semantic Search",id:"the-problem-with-pure-semantic-search",level:3},{value:"The Solution: Combined Scoring",id:"the-solution-combined-scoring",level:3},{value:"When to Use Weighted Search",id:"when-to-use-weighted-search",level:3},{value:"Implementation Strategy",id:"implementation-strategy-1",level:3},{value:"Tuning the Weighting",id:"tuning-the-weighting",level:3},{value:"Visualize the Forgetting Curve",id:"visualize-the-forgetting-curve",level:2},{value:"Why Visualize?",id:"why-visualize",level:3},{value:"Key Visualization Elements",id:"key-visualization-elements",level:3},{value:"Interpreting the Visualization",id:"interpreting-the-visualization",level:3},{value:"Customization Options",id:"customization-options-1",level:3},{value:"Implement Spaced Repetition System",id:"implement-spaced-repetition-system",level:2},{value:"What is Spaced Repetition?",id:"what-is-spaced-repetition",level:3},{value:"How It Works with the Forgetting Curve",id:"how-it-works-with-the-forgetting-curve",level:3},{value:"Review Schedule Strategy",id:"review-schedule-strategy",level:3},{value:"Implementation Components",id:"implementation-components",level:3},{value:"Best Practices",id:"best-practices-1",level:3},{value:"Use Cases",id:"use-cases-1",level:3},{value:"Best Practices and Tips",id:"best-practices-and-tips",level:2},{value:"When to Use Forgetting Curve Features",id:"when-to-use-forgetting-curve-features",level:3},{value:"Performance Considerations",id:"performance-considerations",level:3},{value:"Common Pitfalls",id:"common-pitfalls",level:3},{value:"Advanced Techniques",id:"advanced-techniques",level:3}];function c(e){const n={blockquote:"blockquote",code:"code",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Python 3.11+"}),"\n",(0,r.jsxs)(n.li,{children:["powermem installed (",(0,r.jsx)(n.code,{children:"pip install powermem"}),")"]}),"\n",(0,r.jsx)(n.li,{children:"matplotlib and numpy for visualization (optional)"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"configuration",children:"Configuration"}),"\n",(0,r.jsxs)(n.h3,{id:"create-env-file",children:["Create ",(0,r.jsx)(n.code,{children:".env"})," File"]}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"Copy the example configuration file:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"cp .env.example .env\n"})}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:["Edit the ",(0,r.jsx)(n.code,{children:".env"})," file and configure your settings"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.blockquote,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"Note:"})," When you call ",(0,r.jsx)(n.code,{children:"Memory()"}),", powermem will automatically load configuration from the ",(0,r.jsx)(n.code,{children:".env"})," file."]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"using-jsondictionary-configuration",children:"Using JSON/Dictionary Configuration"}),"\n",(0,r.jsxs)(n.p,{children:["Instead of using ",(0,r.jsx)(n.code,{children:".env"})," files, you can also pass configuration directly as a Python dictionary (JSON-like format). This is useful when:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"You want to load configuration from a JSON file"}),"\n",(0,r.jsx)(n.li,{children:"You need to programmatically generate configuration"}),"\n",(0,r.jsx)(n.li,{children:"You're embedding configuration in your application code"}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Here's an example using a dictionary configuration:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"from powermem import Memory\n\n# Define configuration as a dictionary (JSON-like format)\nconfig = {\n    'llm': {\n        'provider': 'qwen',\n        'config': {\n            'api_key': 'your_api_key_here',\n            'model': 'qwen-plus',\n            'temperature': 0.7\n        }\n    },\n    'embedder': {\n        'provider': 'qwen',\n        'config': {\n            'api_key': 'your_api_key_here',\n            'model': 'text-embedding-v4'\n        }\n    },\n    'vector_store': {\n        'provider': 'oceanbase',\n        'config': {\n            'collection_name': 'memories',\n            'connection_args': {\n                'host': '127.0.0.1',\n                'port': 2881,\n                'user': 'root@sys',\n                'password': 'password',\n                'db_name': 'powermem'\n            },\n            'embedding_model_dims': 1536,\n            'index_type': 'IVF_FLAT',\n            'vidx_metric_type': 'cosine'\n        }\n    }\n}\n\n# Create memory instance with dictionary config\nmemory = Memory(config=config)\n\nprint(\"\u2713 Memory initialized with JSON config!\")\n"})}),"\n",(0,r.jsx)(n.h2,{id:"what-is-the-ebbinghaus-forgetting-curve",children:"What is the Ebbinghaus Forgetting Curve?"}),"\n",(0,r.jsx)(n.p,{children:"The Ebbinghaus Forgetting Curve, discovered by German psychologist Hermann Ebbinghaus in the 1880s, describes how information is lost over time when there is no attempt to retain it. This fundamental principle of cognitive psychology has profou
1nd implications for memory systems in AI applications."}),"\n",(0,r.jsx)(n.h3,{id:"key-insights",children:"Key Insights"}),"\n",(0,r.jsx)(n.p,{children:"The curve reveals that memory retention follows a predictable exponential decay pattern:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Immediate retention"}),": 100% immediately after learning"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"20 minutes"}),": ~58% retention"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"1 hour"}),": ~44% retention"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"9 hours"}),": ~36% retention"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"1 day"}),": ~33% retention"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"2 days"}),": ~28% retention"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"6 days"}),": ~25% retention"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"31 days"}),": ~21% retention"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"why-this-matters-for-ai-memory-systems",children:"Why This Matters for AI Memory Systems"}),"\n",(0,r.jsx)(n.p,{children:"In traditional memory systems, all memories are treated equally regardless of when they were created. However, the forgetting curve suggests that:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Recency matters"}),": Recently created or accessed memories are more likely to be relevant"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Time-based weighting"}),": Older memories should have lower priority in search results"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Spaced repetition"}),": Memories should be reviewed at optimal intervals to maintain retention"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Automatic decay"}),": Without intervention, memory relevance naturally decreases over time"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"use-cases",children:"Use Cases"}),"\n",(0,r.jsx)(n.p,{children:"Implementing forgetting curve principles in powermem enables:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Intelligent search ranking"}),": Prioritize recent memories that are more likely to be relevant"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Memory freshness tracking"}),": Identify stale memories that may need updating"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Spaced repetition systems"}),": Build learning and review systems that optimize retention"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Context-aware retrieval"}),": Weight search results based on both semantic similarity and temporal relevance"]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"guide-overview",children:"Guide Overview"}),"\n",(0,r.jsx)(n.p,{children:"This guide will walk you through:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Understanding the formula"}),": Learn how to mathematically model the forgetting curve"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Tracking memory timestamps"}),": Store and retrieve creation/access times"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Calculating retention scores"}),': Compute how "fresh" each memory is']}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Weighted search"}),": Combine semantic similarity with temporal relevance"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Visualization"}),": Create charts to understand memory decay patterns"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Spaced repetition"}),": Implement review scheduling based on retention thresholds"]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"understanding-the-forgetting-curve-formula",children:"Understanding the Forgetting Curve Formula"}),"\n",(0,r.jsx)(n.h3,{id:"mathematical-foundation",children:"Mathematical Foundation"}),"\n",(0,r.jsx)(n.p,{children:"The forgetting curve can be mathematically modeled using an exponential decay function. The core principle is that memory retention decreases exponentially over time, following the formula:"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"R(t) = e^(-\u03bbt)"})}),"\n",(0,r.jsx)(n.p,{children:"Where:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"R(t)"})," is the retention rate at time t"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\u03bb"})," (lambda) is the decay constant"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"t"})," is the time elapsed since learning"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"implementation-approach",children:"Implementation Approach"}),"\n",(0,r.jsx)(n.p,{children:"In our implementation, we use a simplified model based on Ebbinghaus's empirical observations:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"We calibrate the decay constant to match the 44% retention rate after 1 hour"}),"\n",(0,r.jsx)(n.li,{children:"We set a minimum retention threshold (20%) to prevent memories from becoming completely irrelevant"}),"\n",(0,r.jsx)(n.li,{children:"The formula ensures smooth decay that matches observed human memory patterns"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"why-this-formula-works",children:"Why This Formula Works"}),"\n",(0,r.jsx)(n.p,{children:"The exponential decay model captures several important characteristics:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Rapid initial decay"}),": Most forgetting happens in the first few hours"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Gradual long-term decay"}),": After the initial drop, retention stabilizes"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Predictable patterns"}),": The curve allows us to calculate retention at any point in t
1ime"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Practical thresholds"}),": Minimum retention ensures old memories aren't completely discarded"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"customization-options",children:"Customization Options"}),"\n",(0,r.jsx)(n.p,{children:"You can adjust the formula parameters to match your specific use case:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Decay rate"}),": Faster or slower forgetting depending on memory importance"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Minimum retention"}),": How much weight to give to very old memories"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Base retention"}),": Calibrate to different time points (e.g., 1 hour, 1 day)"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Here's the implementation:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'import math\nfrom datetime import datetime, timedelta\n\ndef calculate_retention(time_elapsed_hours, decay_rate=0.5):\n    """\n    Calculate memory retention based on Ebbinghaus forgetting curve.\n    \n    Args:\n        time_elapsed_hours: Hours since memory was created/accessed\n        decay_rate: Decay rate (default 0.5 for Ebbinghaus curve)\n    \n    Returns:\n        Retention score between 0 and 1\n    """\n    # Ebbinghaus formula: R = e^(-t/S)\n    # where R is retention, t is time, S is strength\n    # Using a simplified exponential decay model\n    if time_elapsed_hours <= 0:\n        return 1.0\n    \n    # Base retention after 1 hour (approximately 44%)\n    base_retention_1h = 0.44\n    \n    # Calculate decay constant\n    decay_constant = -math.log(base_retention_1h)\n    \n    # Calculate retention\n    retention = math.exp(-decay_constant * time_elapsed_hours)\n    \n    # Ensure retention doesn\'t go below a minimum threshold (e.g., 20%)\n    return max(retention, 0.2)\n\n# Test the function\nprint("Ebbinghaus Forgetting Curve - Retention Over Time:")\nprint("=" * 60)\ntime_points = [0, 0.33, 1, 9, 24, 48, 144, 744]  # hours\ntime_labels = ["0h", "20min", "1h", "9h", "1d", "2d", "6d", "31d"]\n\nfor hours, label in zip(time_points, time_labels):\n    retention = calculate_retention(hours)\n    print(f"{label:>6}: {retention*100:>5.1f}% retention")\n'})}),"\n",(0,r.jsx)(n.h2,{id:"add-memories-with-timestamps",children:"Add Memories with Timestamps"}),"\n",(0,r.jsx)(n.h3,{id:"why-track-timestamps",children:"Why Track Timestamps?"}),"\n",(0,r.jsx)(n.p,{children:"To apply the forgetting curve, we need to know when each memory was created or last accessed. This temporal information allows us to:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Calculate how much time has elapsed since memory creation"}),"\n",(0,r.jsx)(n.li,{children:"Determine the current retention score for each memory"}),"\n",(0,r.jsx)(n.li,{children:"Prioritize memories based on recency"}),"\n",(0,r.jsx)(n.li,{children:"Schedule reviews for spaced repetition"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"implementation-strategy",children:"Implementation Strategy"}),"\n",(0,r.jsxs)(n.p,{children:["powermem's ",(0,r.jsx)(n.code,{children:"metadata"})," field is perfect for storing timestamp information. We'll:"]}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsx)(n.li,{children:"Store the creation time as an ISO-formatted string in metadata"}),"\n",(0,r.jsx)(n.li,{children:"Include additional context (category, subject) for better organization"}),"\n",(0,r.jsx)(n.li,{children:"Use the timestamp to calculate retention scores later"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"best-practices",children:"Best Practices"}),"\n",(0,r.jsx)(n.p,{children:"When adding timestamps to memories:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Use ISO format"}),": Store timestamps as ISO 8601 strings for easy parsing (",(0,r.jsx)(n.code,{children:"datetime.isoformat()"}),")"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Store creation time"}),": Always record when the memory was first created"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Track access time"}),": Optionally update ",(0,r.jsx)(n.code,{children:"last_accessed"})," when memories are retrieved"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Include context"}),": Add metadata like category, tags, or importance for richer filtering"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"example-implementation",children:"Example Implementation"}),"\n",(0,r.jsx)(n.p,{children:"Let's add memories and track their creation time:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'from powermem import Memory, auto_config\nfrom datetime import datetime, timedelta\n\nmemory = Memory(config=auto_config())\nuser_id = "student_001"\n\n# Add memories with timestamps in metadata\nmemories_data = [\n    {\n        "content": "Python is a high-level programming language",\n        "created_at": datetime.now() - timedelta(days=31),  # 31 days ago\n    },\n    {\n        "content": "Lists in Python are mutable sequences",\n        "created_at": datetime.now() - timedelta(days=6),  # 6 days ago\n    },\n    {\n        "content": "Dictionaries use key-value pairs",\n        "created_at": datetime.now() - timedelta(days=2),  # 2 days ago\n    },\n    {\n        "content": "Functions are defined with the \'def\' keyword",\n        "created_at": datetime.now() - timedelta(hours=9),  # 9 hours ago\n    },\n    {\n        "content": "Classes are blueprints for creating objects",\n        "created_at": datetime.now() - timedelta(hours=1),  # 1 hour ago\n    },\n    {\n        "content": "Decorators modify function behavior",\n        "created_at": datetime.now() - timedelta(minutes=20),  # 20 minutes ago\n    },\n]\n\nprint("Adding memories with timestamps...")\nmemory_ids = []\nfor mem_data in memories_data:\n    result = memory.add(\n        messages=mem_data["content"],\n        user_id=user_id,\n        metadata={\n            "created_at": mem_data["created_at"].isoformat(),\n            "category": "programming",\n            "subject": "Python"\
1n        }\n    )\n    results_list = result.get(\'results\', [])\n    if results_list:\n        memory_ids.append(results_list[0].get(\'id\'))\n    print(f"  \u2713 Added: {mem_data[\'content\'][:50]}...")\n\nprint(f"\\n\u2713 Added {len(memory_ids)} memories")\n'})}),"\n",(0,r.jsx)(n.h2,{id:"calculate-retention-scores-for-memories",children:"Calculate Retention Scores for Memories"}),"\n",(0,r.jsx)(n.h3,{id:"what-are-retention-scores",children:"What Are Retention Scores?"}),"\n",(0,r.jsx)(n.p,{children:'A retention score quantifies how "fresh" or relevant a memory is based on the forgetting curve. It\'s a value between 0 and 1 where:'}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"1.0"}),": Memory was just created (100% retention)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"0.44"}),": Memory is 1 hour old (44% retention, per Ebbinghaus)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"0.2"}),": Memory is very old (minimum threshold)"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"how-to-use-retention-scores",children:"How to Use Retention Scores"}),"\n",(0,r.jsx)(n.p,{children:"Retention scores enable several powerful capabilities:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Memory freshness analysis"}),": Identify which memories are stale and may need updating"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Search result ranking"}),": Boost recent memories in search results"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Review scheduling"}),": Determine when memories should be reviewed"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Memory cleanup"}),": Identify memories that have decayed below a useful threshold"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"implementation-workflow",children:"Implementation Workflow"}),"\n",(0,r.jsx)(n.p,{children:"The process involves:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Retrieve memories"}),": Get all memories for a user"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Extract timestamps"}),": Parse creation times from metadata"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Calculate elapsed time"}),": Compute hours/days since creation"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Apply formula"}),": Use the forgetting curve formula to get retention"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Display results"}),": Show memory age and retention in a readable format"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"interpreting-results",children:"Interpreting Results"}),"\n",(0,r.jsx)(n.p,{children:"When analyzing retention scores:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsxs)(n.strong,{children:["High retention (",(0,r.jsx)(n.code,{children:">0.7"}),")"]}),": Very recent memories, likely highly relevant"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Medium retention (0.3-0.7)"}),": Moderately old, may need review soon"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsxs)(n.strong,{children:["Low retention (",(0,r.jsx)(n.code,{children:"<0.3"}),")"]}),": Old memories, consider updating or reviewing"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Now let's retrieve memories and calculate their retention scores:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"from powermem import Memory, auto_config\nfrom datetime import datetime\nimport math\n\ndef calculate_retention(time_elapsed_hours):\n    \"\"\"Calculate retention based on Ebbinghaus curve.\"\"\"\n    if time_elapsed_hours <= 0:\n        return 1.0\n    base_retention_1h = 0.44\n    decay_constant = -math.log(base_retention_1h)\n    retention = math.exp(-decay_constant * time_elapsed_hours)\n    return max(retention, 0.2)\n\nmemory = Memory(config=auto_config())\nuser_id = \"student_001\"\n\n# Get all memories\nall_memories = memory.get_all(user_id=user_id)\nmemories = all_memories.get('results', [])\n\nprint(\"Memory Retention Analysis:\")\nprint(\"=\" * 80)\nprint(f\"{'Memory':<50} {'Age':<12} {'Retention':<12} {'Score':<10}\")\nprint(\"-\" * 80)\n\nnow = datetime.now()\nscored_memories = []\n\nfor mem in memories:\n    content = mem.get('memory', '')[:48]\n    metadata = mem.get('metadata', {})\n    created_at_str = metadata.get('created_at', '')\n    \n    if created_at_str:\n        created_at = datetime.fromisoformat(created_at_str)\n        time_elapsed 
1= now - created_at\n        hours_elapsed = time_elapsed.total_seconds() / 3600\n        \n        retention = calculate_retention(hours_elapsed)\n        \n        # Format age\n        if hours_elapsed < 24:\n            age_str = f\"{hours_elapsed:.1f}h\"\n        else:\n            age_str = f\"{hours_elapsed/24:.1f}d\"\n        \n        scored_memories.append({\n            'memory': mem,\n            'retention': retention,\n            'hours_elapsed': hours_elapsed,\n            'age_str': age_str\n        })\n        \n        print(f\"{content:<50} {age_str:<12} {retention*100:>5.1f}%      {retention:.3f}\")\n\nprint(f\"\\nTotal memories analyzed: {len(scored_memories)}\")\n"})}),"\n",(0,r.jsx)(n.h2,{id:"apply-time-based-weighting-to-search-results",children:"Apply Time-Based Weighting to Search Results"}),"\n",(0,r.jsx)(n.h3,{id:"the-problem-with-pure-semantic-search",children:"The Problem with Pure Semantic Search"}),"\n",(0,r.jsxs)(n.p,{children:["Traditional semantic search ranks results purely by similarity to the query. However, this ignores an important factor: ",(0,r.jsx)(n.strong,{children:"temporal relevance"}),". A memory that perfectly matches your query but was created 6 months ago might be less useful than a slightly less similar memory created yesterday."]}),"\n",(0,r.jsx)(n.h3,{id:"the-solution-combined-scoring",children:"The Solution: Combined Scoring"}),"\n",(0,r.jsx)(n.p,{children:"By combining semantic similarity with retention scores, we create a more intelligent ranking system:"}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Combined Score = Semantic Similarity \xd7 Retention Score"})}),"\n",(0,r.jsx)(n.p,{children:"This approach ensures that:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Highly relevant AND recent memories rank highest"}),"\n",(0,r.jsx)(n.li,{children:"Very old memories are deprioritized even if semantically similar"}),"\n",(0,r.jsx)(n.li,{children:"Recent memories get a boost even if similarity is moderate"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"when-to-use-weighted-search",children:"When to Use Weighted Search"}),"\n",(0,r.jsx)(n.p,{children:"Time-based weighting is particularly useful for:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"User preferences"}),": Recent preferences are more likely to be current"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Learning systems"}),": Recent lessons are more relevant than old ones"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Conversational AI"}),": Recent context is more important than historical context"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Dynamic information"}),": When information changes over time (prices, availability, etc.)"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"implementation-strategy-1",children:"Implementation Strategy"}),"\n",(0,r.jsx)(n.p,{children:"The weighted search function:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Performs standard search"}),": Gets top candidates by similarity"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Calculates retention"}),": Determines how fresh each result is"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Combines scores"}),": Multiplies similarity by retention"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Re-ranks results"}),": Sorts by combined score instead of similarity alone"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Returns top results"}),": Provides the most relevant AND recent memories"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"tuning-the-weighting",children:"Tuning the Weighting"}),"\n",(0,r.jsx)(n.p,{children:"You can adjust the weighting strategy:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Pure similarity"}),": Use only semantic similarity (retention = 1.0 for all)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Balanced"}),": Multiply similarity \xd7 retention (current approach)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Recency boost"}),": Add a bonus for recent memories: ",(0,r.jsx)(n.code,{children:"similarity + (retention \xd7 0.2)"})]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Threshold filtering"}),": Filter out memories below a retention threshold"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Let's enhance search results by applying retention-based weighting:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"from powermem import Memory, auto_config\nfrom datetime import datetime\nimport math\n\ndef calculate_retention(time_elapsed_hours):\n    \"\"\"Calculate retention based on Ebbinghaus curve.\"\"\"\n    if time_elapsed_hours <= 0:\n        return 1.0\n    base_retention_1h = 0.44\n    decay_constant = -math.log(base_retention_1h)\n    retention = math.exp(-decay_constant * time_elapsed_hours)\n    return max(retention, 0.2)\n\ndef search_with_retention_weighting(memory, query, user_id, limit=10):\n    \"\"\"\n    Search memories and apply retention-based weighting.\n    \n    Returns results sorted by combined score (similarity * retention).\n    \"\"\"\n    # Perform standard search\n    results = memory.search(query=query, user_id=user_id, limit=limit * 2)\n    \n    now = datetime.now()\n    weighted_results = []\n    \n    for mem in results.get('results', []):\n        # Get similarity score\n        similarity_score = mem.get('score', 0.0)\n        \n        # Get creation time from metadata\n        metadata = mem.get('metadata', {})\n        created_at_str = metadata.get('created_at', '')\n        \n        if created_at_str:\n            created_at = datetime.fromisoformat(created_at_str)\n            time_elapsed 
1= now - created_at\n            hours_elapsed = time_elapsed.total_seconds() / 3600\n            retention = calculate_retention(hours_elapsed)\n        else:\n            # If no timestamp, assume recent (high retention)\n            retention = 0.9\n            hours_elapsed = 0\n        \n        # Combined score: similarity * retention\n        combined_score = similarity_score * retention\n        \n        weighted_results.append({\n            'memory': mem.get('memory', ''),\n            'similarity': similarity_score,\n            'retention': retention,\n            'combined_score': combined_score,\n            'hours_elapsed': hours_elapsed,\n            'metadata': metadata\n        })\n    \n    # Sort by combined score (descending)\n    weighted_results.sort(key=lambda x: x['combined_score'], reverse=True)\n    \n    return weighted_results[:limit]\n\n# Example usage\nmemory = Memory(config=auto_config())\nuser_id = \"student_001\"\n\nquery = \"Python programming concepts\"\nprint(f\"\\nSearching for: '{query}'\")\nprint(\"=\" * 80)\nprint(f\"{'Memory':<50} {'Similarity':<12} {'Retention':<12} {'Combined':<10}\")\nprint(\"-\" * 80)\n\nweighted_results = search_with_retention_weighting(memory, query, user_id, limit=5)\n\nfor i, result in enumerate(weighted_results, 1):\n    content = result['memory'][:48]\n    print(f\"{i}. {content:<48} {result['similarity']:.3f}      \"\n          f\"{result['retention']*100:>5.1f}%      {result['combined_score']:.3f}\")\n"})}),"\n",(0,r.jsx)(n.h2,{id:"visualize-the-forgetting-curve",children:"Visualize the Forgetting Curve"}),"\n",(0,r.jsx)(n.h3,{id:"why-visualize",children:"Why Visualize?"}),"\n",(0,r.jsx)(n.p,{children:"Visualizing the forgetting curve helps you:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Understand the pattern"}),": See how retention decays over time"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Identify key intervals"}),": Recognize when most forgetting occurs"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Plan review schedules"}),": Determine optimal review timing"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Communicate concepts"}),": Share insights with team members or stakeholders"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"key-visualization-elements",children:"Key Visualization Elements"}),"\n",(0,r.jsx)(n.p,{children:"A good forgetting curve visualization should include:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Smooth curve"}),": Show the continuous decay pattern"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Key milestones"}),": Mark important time points (20 min, 1 hour, 1 day, etc.)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Retention percentages"}),": Display exact retention values at each milestone"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Clear labels"}),": Make time and retention axes easy to read"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Professional styling"}),": Use colors and formatting that enhance readability"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"interpreting-the-visualization",children:"Interpreting the Visualization"}),"\n",(0,r.jsx)(n.p,{children:"When viewing the curve:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Steep initial drop"}),": Notice how retention drops rapidly in the first few hours"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Stabilization"}),": See how the curve flattens after the first day"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Minimum threshold"}),": Observe where the curve levels off (20% in our model)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Review windows"}),": Identify optimal times for spaced repetition reviews"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"customization-options-1",children:"Customization Options"}),"\n",(0,r.jsx)(n.p,{children:"You can customize the visualization:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Time range"}),": Extend beyond 31 days for longer-term analysis"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Decay parameters"}),": Adjust to show different forgetting rates"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Multiple curves"}),": Compare different decay models side-by-side"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Interactive plots"}),": Use libraries like Plotly for interactive exploration"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Let's create a visualization of the forgetting curve:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:"import matplotlib.pyplot as plt\nimport numpy as np\nimport math\nimport os\nfrom datetime import datetime, timedelta\n\ndef calculate_retention(time_elapsed_hours):\n    \"\"\"Calculate retention based on Ebbinghaus curve.\"\"\"\n    if time_elapsed_hours <= 0:\n        return 1.0\n    base_retention_1h = 0.44\n    decay_constant = -math.log(base_retention_1h)\n    retention = math.exp(-decay_constant * time_elapsed_hours)\n    return max(retention, 0.2)\n\n# Generate time points (0 to 31 days in hours)\nhours = np.linspace(0, 744, 1000)  # 31 days = 744 hours\nretentions = [calculate_retention(h) for h in hours]\n\n# Create the plot with improved styling\nplt.figure(figsize=(12, 6))\nplt.plot(hours / 24, [r * 100 for r in retentions], 'b-', linewidth=2.5, \n         label='Ebbinghaus Forgetting Curve', color='#2E86AB')\n\n# Mark key points with annotations\nkey_points = [\n    (0, \"Immediate\"),\n    (0.33, \"20 min\"),\n    (1, \"1 hour\"),\n    (9, \"9 hours\"),\n    (24, \"1 day\"),\n    (48, \"2 days\"),\n    (144, \"6 days\"),\n    (744, \"31 days\")\n]\n\nfor hours_val, label in key_points:\n    retention = calculate_retention(hours_val)\n    plt.plot(hours_val / 24, retention * 100, 'ro', markersize=10, \n             markeredgecolor='darkred', markeredgewidth=1.5)\n    plt.annotate(f'{label}\\n{retention*100:.1f}%', \n                xy=(hours_val / 24, retention * 100),\n                xytext=(10, 10), textcoords='offset points',\n                bbox=dict(boxstyle='round,pad=0.4', facecolor='#FFE66D', \n                         alpha=0.8, edgecolor='#333', linewidth=1),\n                arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=0',\n                               color='#333', lw=1.5),\n                fontsize=9, fontweight='bold')\n\nplt.xlabel('Time (days)', fontsize=13, fontweight='bold')\nplt.ylabel('Retention (%)', fontsize=13, fontweight='bold')\nplt.title('Ebbinghaus Forgetting Curve', fontsize=16, fontweight='bold', pad=20)\nplt.grid(True, alpha=0.3, linestyle='--', linewidth=0.8)\nplt.legend(loc='upper right', fontsize=11, framealpha=0.9)\nplt.xlim(0, 31)\nplt.ylim(0, 105)\n\n# Add a subtle background color\nplt.gca().set_facecolor('#F8F9FA')\n\nplt.tight_layout()\n\n# Save the figure (optional: save to docs/examples/data directory if it exists)\nsave_path = 'ebbinghaus_curve.png'\ndata_dir = 'data'\nif os.path.exists(data_dir):\n    save_path = os.path.join(data_dir, 'ebbinghaus_curve.png')\n\ntry:\n    plt.savefig(save_path, dpi=1
150, bbox_inches='tight', facecolor='white')\n    print(f\"\u2713 Saved visualization to '{save_path}'\")\nexcept Exception as e:\n    print(f\"\u26a0 Could not save figure: {e}\")\n    print(\"  (Figure will still be displayed)\")\n\nplt.show()\n"})}),"\n",(0,r.jsx)(n.h2,{id:"implement-spaced-repetition-system",children:"Implement Spaced Repetition System"}),"\n",(0,r.jsx)(n.h3,{id:"what-is-spaced-repetition",children:"What is Spaced Repetition?"}),"\n",(0,r.jsx)(n.p,{children:"Spaced repetition is a learning technique that involves reviewing information at increasing intervals. The principle is simple: review memories just before you're about to forget them, which strengthens retention and extends the forgetting curve."}),"\n",(0,r.jsx)(n.h3,{id:"how-it-works-with-the-forgetting-curve",children:"How It Works with the Forgetting Curve"}),"\n",(0,r.jsx)(n.p,{children:"The forgetting curve tells us when retention drops below useful thresholds. Spaced repetition uses this information to:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Detect low retention"}),": Identify memories that have decayed significantly"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Schedule reviews"}),": Suggest optimal times to review each memory"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Reset the curve"}),": After review, the memory's retention resets, extending its useful life"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Optimize intervals"}),": Use increasingly longer intervals between reviews"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"review-schedule-strategy",children:"Review Schedule Strategy"}),"\n",(0,r.jsx)(n.p,{children:"Based on Ebbinghaus's research, optimal review intervals are:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"20 minutes"}),": First review (catches early forgetting)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"1 hour"}),": Second review (reinforces initial learning)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"9 hours"}),": Third review (before significant overnight decay)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"1 day"}),": Fourth review (daily reinforcement)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"2-6 days"}),": Subsequent reviews (extending retention)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"2-4 weeks"}),": Long-term reviews (maintaining knowledge)"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"implementation-components",children:"Implementation Components"}),"\n",(0,r.jsx)(n.p,{children:"A spaced repetition system needs:"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Retention calculation"}),": Determine current retention for each memory"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Review schedule"}),": Define optimal review intervals"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Review detection"}),": Identify memories that need review now"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Next review prediction"}),": Calculate when each memory should be reviewed next"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Review tracking"}),": Update ",(0,r.jsx)(n.code,{children:"last_reviewed"})," timestamp after review"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"best-practices-1",children:"Best Practices"}),"\n",(0,r.jsx)(n.p,{children:"When implementing spaced repetition:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Set thresholds"}),": Define minimum retention before review is needed (e.g., 50%)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Track reviews"}),": Update metadata with ",(0,r.jsx)(n.code,{children:"last_reviewed"})," timestamp after each review"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Adaptive intervals"}),": Adjust intervals based on review success/failure"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Batch reviews"}),": Group memories by review time for efficient processing"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"User preferences"}),': Allow users to mark memories as "mastered" to skip reviews']}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"use-cases-1",children:"Use Cases"}),"\n",(0,r.jsx)(n.p,{children:"Spaced repetition is ideal for:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Learning systems"}),": Language learning, skill acquisition, knowledge retention"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Training programs"}),": Employee onboarding, certification preparation"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Personal knowledge bases"}),": Maintaining familiarity with stored information"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"AI tutoring systems"}),": Optimizing when to revisit concepts with students"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Based on the forgetting curve, we can implement a spaced repetition system that suggests when to review memories:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'from powermem import Memory, auto_config\nfrom datetime import datetime, timedelta\nimport math\n\ndef calculate_retention(time_elapsed_hours):\n    """Calculate retention based on Ebbinghaus curve."""\n    if time_elapsed_hours <= 0:\n        return 1.0\n    base_retention_1h = 0.44\n    decay_constant = -math.log(base_retention_1h)\n    retention = math.exp(-decay_constant * time_elapsed_hours)\n    return max(retention, 0.2)\n\ndef get_review_schedule(retention_threshold=0.5):\n    """\n    Get optimal review intervals based on forgetting curve.\n    \n    Returns list of (hours, description) tuples.\n    """\n    intervals = [\n        (0.33, "20 minutes"),\n        (1, "1 hour"),\n        (9, "9 hours"),\n        (24, "1 day"),\n        (48, "2 days"),\n        (144, "6 days"),\n        (336, "14 days"),\n        (744, "31 days")\n    ]\n    return intervals\n\ndef get_next_review_time(memory, retention_threshold=0.5):\n    """\n    Calculate when a memory should be reviewed next.\n    \n    Args:\n        memory: Memory dict with metadata\n        retention_threshold: Minimum retention before review needed\n    \n    Returns:\n        Tuple of (hours_until_review, review_needed_now)\n    """\n    metadata = memory.get(\'metadata\', {})\n    created_at_str = metadata.get(\'created_at\', \'\')\n    last_reviewed_str = metadata.get(\'last_reviewed\', \'\')\n    \n    if not created_at_str:\n        return None, False\n    \n    # Use last_reviewed if available, otherwise use created_at\n    if last_reviewed_str:\n        reference_time = datetime.fromisoformat(last_reviewed_str)\n    else:\n        reference_time = datetime.fromisoformat(created_at_str)\n    \n    now = datetime.now()\n    time_elapsed 
1= now - reference_time\n    hours_elapsed = time_elapsed.total_seconds() / 3600\n    \n    current_retention = calculate_retention(hours_elapsed)\n    \n    if current_retention < retention_threshold:\n        return 0, True  # Review needed now\n    \n    # Find next optimal review time\n    schedule = get_review_schedule()\n    for hours, _ in schedule:\n        if hours > hours_elapsed:\n            hours_until = hours - hours_elapsed\n            return hours_until, False\n    \n    # If past all scheduled reviews, suggest immediate review\n    return 0, True\n\n# Example: Get review recommendations\nmemory = Memory(config=auto_config())\nuser_id = "student_001"\n\nall_memories = memory.get_all(user_id=user_id)\nmemories = all_memories.get(\'results\', [])\n\nprint("Spaced Repetition Review Schedule:")\nprint("=" * 80)\nprint(f"{\'Memory\':<50} {\'Retention\':<12} {\'Review Status\':<20}")\nprint("-" * 80)\n\nnow = datetime.now()\nfor mem in memories:\n    content = mem.get(\'memory\', \'\')[:48]\n    metadata = mem.get(\'metadata\', {})\n    created_at_str = metadata.get(\'created_at\', \'\')\n    \n    if created_at_str:\n        created_at = datetime.fromisoformat(created_at_str)\n        time_elapsed = now - created_at\n        hours_elapsed = time_elapsed.total_seconds() / 3600\n        retention = calculate_retention(hours_elapsed)\n        \n        hours_until, needs_review = get_next_review_time(mem, retention_threshold=0.5)\n        \n        if needs_review:\n            status = "\u26a0 Review NOW"\n        elif hours_until < 24:\n            status = f"Review in {hours_until:.1f}h"\n        else:\n            status = f"Review in {hours_until/24:.1f}d"\n        \n        print(f"{content:<50} {retention*100:>5.1f}%      {status:<20}")\n'})}),"\n",(0,r.jsx)(n.h2,{id:"best-practices-and-tips",children:"Best Practices and Tips"}),"\n",(0,r.jsx)(n.h3,{id:"when-to-use-forgetting-curve-features",children:"When to Use Forgetting Curve Features"}),"\n",(0,r.jsx)(n.p,{children:"The forgetting curve approach is most valuable when:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Information changes over time"}),": User preferences, product availability, prices"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Recency matters"}),": Recent context is more relevant than historical context"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Learning systems"}),": Building educational or training applications"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Large memory stores"}),": When you have many memories and need intelligent prioritization"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"performance-considerations",children:"Performance Considerations"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Metadata storage"}),": Storing timestamps adds minimal overhead"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Calculation cost"}),": Retention calculations are fast (simple math operations)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Search optimization"}),": Weighted search may require fetching more candidates initially"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Indexing"}),": Consider indexing metadata fields for faster timestamp queries"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"common-pitfalls",children:"Common Pitfalls"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Missing timestamps"}),": Always store ",(0,r.jsx)(n.code,{children:"created_at"})," when adding memories"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Timezone issues"}),": Use UTC or consistent timezone for all timestamps"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Over-weighting recency"}),": Don't completely ignore old memories that might still be relevant"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Fixed thresholds"}),": Adjust retention thresholds based on your use case"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"advanced-techniques",children:"Advanced Techniques"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Adaptive decay"}),": Adjust decay rates based on memory importance or type"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Access-based retention"}),": Reset retention when memories are accessed (not just reviewed)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Category-specific curves"}),": Use different decay rates for different memory categories"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Machine learning"}),": Train models to predict optimal review times based on user behavior"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(c,{...e})}):c(e)}},8453(e,n,t){t.d(n,{R:()=>o,x:()=>a});var i=t(6540);const r={},s=i.createContext(r);function o(e){const n=i.useContext(s);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),i.createElement(s.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.