Spaces:
No application file
No application file
| # ==========================Factories + Engines========================== | |
| # AURA v7 — Neuro‑Symbolic Hybrid Brain | |
| # Chunk 1 / 10 | |
| # Imports, Utilities, Embedding Service | |
| # ========================== | |
| import time | |
| import re | |
| from dataclasses import dataclass, field | |
| from typing import List, Dict, Any, Optional, Iterable, Tuple, Callable | |
| import torch | |
| import networkx as nx | |
| from sentence_transformers import SentenceTransformer, util | |
| from datasets import load_dataset | |
| # ========================== | |
| # Device & Embedding Model | |
| # ========================== | |
| DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
| EMBEDDING_MODEL_NAME = "all-MiniLM-L6-v2" | |
| print("Using device:", DEVICE) | |
| # ========================== | |
| # Utility Functions | |
| # ========================== | |
| def normalize_text(text: str) -> str: | |
| """Lowercase, strip punctuation, collapse whitespace.""" | |
| if text is None: | |
| return "" | |
| text = text.lower().strip() | |
| text = re.sub(r"[^\w\s\?]", " ", text) | |
| text = re.sub(r"\s+", " ", text) | |
| return text | |
| def contains_negation(text: str) -> bool: | |
| """Detect negation words in natural language.""" | |
| neg_words = ["not", "never", "no", "doesnt", "isnt", "arent", "without", "cannot", "can't"] | |
| tokens = normalize_text(text).split() | |
| return any(w in tokens for w in neg_words) | |
| def extract_prob_modifier(text: str) -> float: | |
| """ | |
| Detect probabilistic language and convert to confidence multipliers. | |
| Examples: | |
| "always" -> 1.0 | |
| "usually" -> 0.8 | |
| "often" -> 0.7 | |
| "sometimes" -> 0.5 | |
| "rarely" -> 0.3 | |
| "never" -> 0.0 | |
| """ | |
| t = normalize_text(text) | |
| if "always" in t: | |
| return 1.0 | |
| if "usually" in t: | |
| return 0.8 | |
| if "often" in t: | |
| return 0.7 | |
| if "sometimes" in t: | |
| return 0.5 | |
| if "rarely" in t: | |
| return 0.3 | |
| if "never" in t: | |
| return 0.0 | |
| return 1.0 # default | |
| def is_variable(token: Optional[str]) -> bool: | |
| """Variables start with ? (e.g., ?x, ?y).""" | |
| return isinstance(token, str) and token.startswith("?") and len(token) > 1 | |
| # ========================== | |
| # Embedding Service | |
| # ========================== | |
| class EmbeddingService: | |
| """Wrapper around SentenceTransformer for consistent encoding.""" | |
| def __init__(self, model_name: str = EMBEDDING_MODEL_NAME, device: torch.device = DEVICE): | |
| self.model = SentenceTransformer(model_name, device=device) | |
| def encode(self, text: str) -> torch.Tensor: | |
| return self.model.encode(text, convert_to_tensor=True) | |
| def encode_batch(self, texts: Iterable[str]) -> torch.Tensor: | |
| return self.model.encode(list(texts), convert_to_tensor=True) | |
| # Global embedding service instance | |
| embedding_service = EmbeddingService() | |
| # ========================== | |
| # AURA v7 — Neuro‑Symbolic Hybrid Brain | |
| # Chunk 2 / 10 | |
| # Core Data Structures | |
| # ========================== | |
| class Fact: | |
| """ | |
| A structured fact with: | |
| - subject | |
| - predicate | |
| - object | |
| - confidence (0–1) | |
| - polarity (+1 = positive, -1 = negated) | |
| - source (manual, induced, nl_input, dataset, etc.) | |
| """ | |
| subject: str | |
| predicate: str | |
| obj: Optional[str] = None | |
| confidence: float = 1.0 | |
| polarity: int = 1 | |
| verified: bool = True | |
| source: str = "unknown" | |
| timestamp: float = field(default_factory=time.time) | |
| embedding: torch.Tensor = field(init=False, compare=False, repr=False) | |
| def __post_init__(self): | |
| # Normalize fields | |
| object.__setattr__(self, "subject", normalize_text(self.subject)) | |
| object.__setattr__(self, "predicate", normalize_text(self.predicate)) | |
| if self.obj is not None: | |
| object.__setattr__(self, "obj", normalize_text(self.obj)) | |
| # Create canonical text for embedding | |
| canonical = self.to_text(include_polarity=False) | |
| emb = embedding_service.encode(canonical) | |
| object.__setattr__(self, "embedding", emb) | |
| def to_text(self, include_polarity: bool = True) -> str: | |
| """Return human-readable representation.""" | |
| base = f"{self.subject} {self.predicate}" | |
| if self.obj: | |
| base += f" {self.obj}" | |
| if include_polarity and self.polarity == -1: | |
| base = "NOT " + base | |
| return base | |
| def key(self) -> str: | |
| """Unique key for memory storage.""" | |
| pol = "neg" if self.polarity == -1 else "pos" | |
| return f"{pol}:{self.to_text(include_polarity=False)}" | |
| class RulePattern: | |
| """ | |
| A pattern used in rules, supporting variables (?x, ?y). | |
| Includes polarity for negation-aware reasoning. | |
| """ | |
| subject: str | |
| predicate: str | |
| obj: Optional[str] = None | |
| polarity: int = 1 | |
| def normalized(self) -> "RulePattern": | |
| return RulePattern( | |
| subject=normalize_text(self.subject), | |
| predicate=normalize_text(self.predicate), | |
| obj=normalize_text(self.obj) if self.obj is not None else None, | |
| polarity=self.polarity, | |
| ) | |
| class Rule: | |
| """ | |
| A rule with: | |
| - name | |
| - list of condition patterns | |
| - conclusion pattern | |
| - confidence | |
| - source (manual, induced) | |
| """ | |
| name: str | |
| conditions: List[RulePattern] | |
| conclusion: RulePattern | |
| confidence: float = 1.0 | |
| source: str = "manual" | |
| def normalized(self) -> "Rule": | |
| return Rule( | |
| name=self.name, | |
| conditions=[c.normalized() for c in self.conditions], | |
| conclusion=self.conclusion.normalized(), | |
| confidence=self.confidence, | |
| source=self.source, | |
| ) | |
| class ReasoningEvent: | |
| """ | |
| A log entry for meta-memory: | |
| - which engine produced it | |
| - message | |
| - confidence | |
| - timestamp | |
| """ | |
| engine: str | |
| message: str | |
| confidence: float | |
| timestamp: float = field(default_factory=time.time) | |
| # ========================== | |
| # AURA v7 — Neuro‑Symbolic Hybrid Brain | |
| # Chunk 3 / 10 | |
| # Retrieval Index + Memory Systems | |
| # ========================== | |
| # ========================== | |
| # Retrieval Index | |
| # ========================== | |
| class RetrievalIndex: | |
| """ | |
| Stores embeddings for fast similarity search. | |
| Used by semantic memory and analogy engine. | |
| """ | |
| def __init__(self): | |
| self.embeddings: List[torch.Tensor] = [] | |
| self.items: List[Any] = [] | |
| def add(self, embedding: torch.Tensor, item: Any): | |
| self.embeddings.append(embedding) | |
| self.items.append(item) | |
| def search(self, query_embedding: torch.Tensor, top_k: int = 5) -> List[Tuple[Any, float]]: | |
| if not self.embeddings: | |
| return [] | |
| mat = torch.stack(self.embeddings) | |
| sims = util.cos_sim(query_embedding, mat)[0] | |
| k = min(top_k, len(sims)) | |
| topk = torch.topk(sims, k=k) | |
| results = [] | |
| for idx in topk.indices: | |
| i = idx.item() | |
| results.append((self.items[i], sims[i].item())) | |
| return results | |
| # ========================== | |
| # Sensory Memory | |
| # ========================== | |
| class SensoryMemory: | |
| """ | |
| Stores raw text entries (e.g., dataset items, Wikipedia text). | |
| Used as fallback when structured reasoning fails. | |
| """ | |
| def __init__(self): | |
| self.entries: List[str] = [] | |
| self.entry_embeddings: List[torch.Tensor] = [] | |
| def add_entry(self, text: str, embedding: Optional[torch.Tensor] = None): | |
| self.entries.append(text) | |
| if embedding is None: | |
| embedding = embedding_service.encode(normalize_text(text)) | |
| self.entry_embeddings.append(embedding) | |
| # ========================== | |
| # Working Memory | |
| # ========================== | |
| class WorkingMemory: | |
| """ | |
| Stores active facts used for reasoning. | |
| """ | |
| def __init__(self): | |
| self.facts: Dict[str, Fact] = {} | |
| def add_fact(self, fact: Fact): | |
| self.facts[fact.key()] = fact | |
| def has_fact(self, fact: Fact) -> bool: | |
| return fact.key() in self.facts | |
| def all_facts(self) -> List[Fact]: | |
| return list(self.facts.values()) | |
| # ========================== | |
| # Semantic Memory | |
| # ========================== | |
| class SemanticMemory: | |
| """ | |
| Stores long-term structured knowledge. | |
| Uses a graph + retrieval index. | |
| """ | |
| def __init__(self): | |
| self.graph = nx.DiGraph() | |
| self.index = RetrievalIndex() | |
| self.fact_map: Dict[str, Fact] = {} | |
| def add_fact(self, fact: Fact): | |
| key = fact.key() | |
| # If fact exists, keep the one with higher confidence | |
| if key in self.fact_map: | |
| existing = self.fact_map[key] | |
| if fact.confidence > existing.confidence: | |
| self.fact_map[key] = fact | |
| return | |
| self.fact_map[key] = fact | |
| self.graph.add_node(key, data=fact) | |
| self.index.add(fact.embedding, fact) | |
| def add_relation(self, source: Fact, target: Fact, relation: str, weight: float = 1.0): | |
| self.graph.add_edge(source.key(), target.key(), relation=relation, weight=weight) | |
| def search_fact(self, query_embedding: torch.Tensor, threshold: float = 0.6) -> Optional[Fact]: | |
| results = self.index.search(query_embedding, top_k=5) | |
| best = [(f, score) for f, score in results if score >= threshold] | |
| if not best: | |
| return None | |
| best.sort(key=lambda x: x[1], reverse=True) | |
| return best[0][0] | |
| # ========================== | |
| # Episodic Memory | |
| # ========================== | |
| class Episode: | |
| description: str | |
| facts: List[Fact] | |
| timestamp: float = field(default_factory=time.time) | |
| class EpisodicMemory: | |
| """ | |
| Stores episodes: groups of facts tied to a specific event or dataset item. | |
| """ | |
| def __init__(self): | |
| self.episodes: List[Episode] = [] | |
| def add_episode(self, description: str, facts: List[Fact]): | |
| self.episodes.append(Episode(description=description, facts=facts)) | |
| # ========================== | |
| # Procedural Memory | |
| # ========================== | |
| class ProceduralMemory: | |
| """ | |
| Stores learned procedures (functions). | |
| """ | |
| def __init__(self): | |
| self.procedures: Dict[str, Callable] = {} | |
| def add_procedure(self, name: str, func: Callable): | |
| self.procedures[name] = func | |
| def get_procedure(self, name: str) -> Optional[Callable]: | |
| return self.procedures.get(name) | |
| # ========================== | |
| # Meta-Memory | |
| # ========================== | |
| class MetaMemory: | |
| """ | |
| Tracks: | |
| - reasoning events | |
| - contradictions | |
| - engine reliability scores | |
| """ | |
| def __init__(self): | |
| self.contradictions: List[str] = [] | |
| self.events: List[ReasoningEvent] = [] | |
| self.engine_scores: Dict[str, float] = {} # reliability scores | |
| def log(self, engine: str, message: str, confidence: float): | |
| self.events.append(ReasoningEvent(engine=engine, message=message, confidence=confidence)) | |
| # Update engine reliability | |
| self.engine_scores[engine] = self.engine_scores.get(engine, 0.5) * 0.9 + confidence * 0.1 | |
| def add_contradiction(self, fact1: Fact, fact2: Fact): | |
| msg = f"CONTRADICTION: '{fact1.to_text()}' conflicts with '{fact2.to_text()}'" | |
| self.contradictions.append(msg) | |
| self.events.append(ReasoningEvent(engine="TMS", message=msg, confidence=0.0)) | |
| def recent_trace(self, n: int = 20) -> List[ReasoningEvent]: | |
| return self.events[-n:] | |
| # ========================== | |
| # AURA v7 — Neuro‑Symbolic Hybrid Brain | |
| # Chunk 4 / 10 | |
| # Unification Engine | |
| # ========================== | |
| from abc import ABC, abstractmethod | |
| class ReasoningEngineBase(ABC): | |
| """Abstract base class for all reasoning engines.""" | |
| name: str | |
| def reason_forward(self, engine: "CognitiveEngine") -> Tuple[List["Fact"], List[str], float]: | |
| pass | |
| def reason_backward(self, engine: "CognitiveEngine", goal: "RulePattern") -> Tuple[List["Fact"], List[str], float]: | |
| pass | |
| def unify_token(pattern: Optional[str], value: Optional[str], subst: Dict[str, str]) -> Optional[Dict[str, str]]: | |
| """ | |
| Unify a single token: | |
| - If pattern is a variable (?x), bind it. | |
| - If pattern is a constant, it must match value. | |
| """ | |
| if pattern is None and value is None: | |
| return subst | |
| if pattern is None or value is None: | |
| return None | |
| pattern = normalize_text(pattern) | |
| value = normalize_text(value) | |
| # Variable case | |
| if is_variable(pattern): | |
| var = pattern | |
| if var in subst: | |
| # Already bound → must match | |
| return subst if subst[var] == value else None | |
| # Bind new variable | |
| new_subst = dict(subst) | |
| new_subst[var] = value | |
| return new_subst | |
| # Constant case | |
| if pattern == value: | |
| return subst | |
| return None | |
| def unify_fact(pattern: "RulePattern", fact: "Fact", subst: Dict[str, str]) -> Optional[Dict[str, str]]: | |
| """ | |
| Unify a rule pattern with a fact. | |
| Includes polarity matching. | |
| """ | |
| # Polarity must match | |
| if pattern.polarity != fact.polarity: | |
| return None | |
| # Subject | |
| subst1 = unify_token(pattern.subject, fact.subject, subst) | |
| if subst1 is None: | |
| return None | |
| # Predicate | |
| subst2 = unify_token(pattern.predicate, fact.predicate, subst1) | |
| if subst2 is None: | |
| return None | |
| # Object | |
| subst3 = unify_token(pattern.obj, fact.obj, subst2) | |
| return subst3 | |
| def apply_substitution(pattern: "RulePattern", subst: Dict[str, str]) -> "RulePattern": | |
| """ | |
| Apply variable bindings to a rule pattern. | |
| """ | |
| def apply_token(token: Optional[str]) -> Optional[str]: | |
| if token is None: | |
| return None | |
| token = normalize_text(token) | |
| if is_variable(token) and token in subst: | |
| return subst[token] | |
| return token | |
| return RulePattern( | |
| subject=apply_token(pattern.subject), | |
| predicate=apply_token(pattern.predicate), | |
| obj=apply_token(pattern.obj), | |
| polarity=pattern.polarity, | |
| ) | |
| # ========================== | |
| # AURA v7 — Neuro‑Symbolic Hybrid Brain | |
| # Chunk 5 / 10 | |
| # Deductive Engine (Forward + Backward) | |
| # ========================== | |
| class DeductiveEngine(ReasoningEngineBase): | |
| name = "deductive" | |
| # --------------------------------------------------------- | |
| # Forward Chaining | |
| # --------------------------------------------------------- | |
| def reason_forward(self, engine: "CognitiveEngine") -> Tuple[List[Fact], List[str], float]: | |
| new_facts: List[Fact] = [] | |
| trace: List[str] = [] | |
| avg_conf = 0.0 | |
| count = 0 | |
| facts = engine.working.all_facts() | |
| rules = [r.normalized() for r in engine.rules] | |
| for rule in rules: | |
| matches = self._match_rule(rule, facts) | |
| for subst, cond_facts in matches: | |
| concl_pattern = apply_substitution(rule.conclusion, subst) | |
| # Polarity propagation | |
| polarity = concl_pattern.polarity | |
| # Confidence propagation | |
| conf = self._propagate_confidence(rule, cond_facts) | |
| concl_fact = Fact( | |
| subject=concl_pattern.subject, | |
| predicate=concl_pattern.predicate, | |
| obj=concl_pattern.obj, | |
| polarity=polarity, | |
| confidence=conf, | |
| verified=True, | |
| source=f"rule:{rule.name}", | |
| ) | |
| # Contradiction detection | |
| self._check_contradictions(engine, concl_fact) | |
| if not engine.working.has_fact(concl_fact): | |
| new_facts.append(concl_fact) | |
| used = ", ".join(f.to_text() for f in cond_facts) | |
| msg = ( | |
| f"[Deduction] {rule.name} with {used} " | |
| f"-> {concl_fact.to_text()} (conf={concl_fact.confidence:.2f})" | |
| ) | |
| trace.append(msg) | |
| avg_conf += concl_fact.confidence | |
| count += 1 | |
| if count > 0: | |
| avg_conf /= count | |
| else: | |
| avg_conf = 0.0 | |
| return new_facts, trace, avg_conf | |
| # --------------------------------------------------------- | |
| # Backward Chaining | |
| # --------------------------------------------------------- | |
| def reason_backward(self, engine: "CognitiveEngine", goal: RulePattern) -> Tuple[List[Fact], List[str], float]: | |
| trace: List[str] = [] | |
| proven_facts: List[Fact] = [] | |
| avg_conf = 0.0 | |
| count = 0 | |
| # 1. Check if goal already exists in working memory | |
| for f in engine.working.all_facts(): | |
| if unify_fact(goal, f, {}) is not None: | |
| proven_facts.append(f) | |
| trace.append(f"[Backward-Deduction] Goal already known: {f.to_text()}") | |
| avg_conf += f.confidence | |
| count += 1 | |
| return proven_facts, trace, avg_conf / max(count, 1) | |
| # 2. Try to prove goal using rules | |
| rules = [r.normalized() for r in engine.rules] | |
| for rule in rules: | |
| subst = unify_fact(rule.conclusion, Fact(goal.subject, goal.predicate, goal.obj, polarity=goal.polarity), {}) | |
| if subst is None: | |
| continue | |
| # Try to prove all conditions | |
| all_proven = True | |
| cond_facts: List[Fact] = [] | |
| for cond in rule.conditions: | |
| cond_goal = apply_substitution(cond, subst) | |
| pf, pt, pc = self.reason_backward(engine, cond_goal) | |
| trace.extend(pt) | |
| if not pf: | |
| all_proven = False | |
| break | |
| cond_facts.extend(pf) | |
| avg_conf += pc | |
| count += 1 | |
| if all_proven: | |
| concl_pattern = apply_substitution(rule.conclusion, subst) | |
| concl_fact = Fact( | |
| subject=concl_pattern.subject, | |
| predicate=concl_pattern.predicate, | |
| obj=concl_pattern.obj, | |
| polarity=concl_pattern.polarity, | |
| confidence=self._propagate_confidence(rule, cond_facts), | |
| verified=True, | |
| source=f"rule:{rule.name}", | |
| ) | |
| proven_facts.append(concl_fact) | |
| trace.append(f"[Backward-Deduction] Proved {concl_fact.to_text()} via {rule.name}") | |
| avg_conf += concl_fact.confidence | |
| count += 1 | |
| break | |
| if count > 0: | |
| avg_conf /= count | |
| else: | |
| avg_conf = 0.0 | |
| return proven_facts, trace, avg_conf | |
| # --------------------------------------------------------- | |
| # Rule Matching | |
| # --------------------------------------------------------- | |
| def _match_rule(self, rule: Rule, facts: List[Fact]) -> List[Tuple[Dict[str, str], List[Fact]]]: | |
| results: List[Tuple[Dict[str, str], List[Fact]]] = [] | |
| def backtrack(i: int, subst: Dict[str, str], chosen: List[Fact]): | |
| if i == len(rule.conditions): | |
| results.append((subst, chosen.copy())) | |
| return | |
| pattern = rule.conditions[i] | |
| for fact in facts: | |
| new_subst = unify_fact(pattern, fact, subst) | |
| if new_subst is not None and fact not in chosen: | |
| chosen.append(fact) | |
| backtrack(i + 1, new_subst, chosen) | |
| chosen.pop() | |
| backtrack(0, {}, []) | |
| return results | |
| # --------------------------------------------------------- | |
| # Confidence Propagation | |
| # --------------------------------------------------------- | |
| def _propagate_confidence(self, rule: Rule, cond_facts: List[Fact]) -> float: | |
| conf = rule.confidence | |
| for f in cond_facts: | |
| conf *= f.confidence | |
| return max(min(conf, 1.0), 0.0) | |
| # --------------------------------------------------------- | |
| # Contradiction Detection | |
| # --------------------------------------------------------- | |
| def _check_contradictions(self, engine: "CognitiveEngine", new_fact: Fact): | |
| """ | |
| If a fact with opposite polarity exists, log contradiction. | |
| """ | |
| opposite_key = ("neg:" if new_fact.polarity == 1 else "pos:") + new_fact.to_text(include_polarity=False) | |
| if opposite_key in engine.semantic.fact_map: | |
| engine.meta.add_contradiction(new_fact, engine.semantic.fact_map[opposite_key]) | |
| # ========================== | |
| # AURA v7 — Neuro‑Symbolic Hybrid Brain | |
| # Chunk 6 / 10 | |
| # Inductive Engine + Analogical Engine | |
| # ========================== | |
| class InductiveEngine(ReasoningEngineBase): | |
| """ | |
| Learns new rules from repeated relational patterns. | |
| Example: | |
| If we see: | |
| fire is hot | |
| touching_fire causes burn | |
| stove is hot | |
| touching_stove causes burn | |
| → Induce rule: hot things burn | |
| """ | |
| name = "inductive" | |
| def reason_forward(self, engine: "CognitiveEngine") -> Tuple[List[Fact], List[str], float]: | |
| trace: List[str] = [] | |
| new_facts: List[Fact] = [] | |
| avg_conf = 0.0 | |
| count = 0 | |
| facts = engine.working.all_facts() | |
| # Collect patterns | |
| hot_map = {} | |
| burn_map = {} | |
| for f in facts: | |
| if f.predicate == "is" and f.obj == "hot" and f.polarity == 1: | |
| hot_map[f.subject] = f | |
| if f.predicate == "causes" and f.obj == "burn" and f.subject.startswith("touching_") and f.polarity == 1: | |
| x = f.subject.replace("touching_", "") | |
| burn_map[x] = f | |
| # Look for repeated pattern | |
| common = set(hot_map.keys()) & set(burn_map.keys()) | |
| if len(common) >= 2: | |
| # Induce rule | |
| rule = Rule( | |
| name="induced_hot_things_burn_rule", | |
| conditions=[RulePattern(subject="?x", predicate="is", obj="hot", polarity=1)], | |
| conclusion=RulePattern(subject="touching_?x", predicate="causes", obj="burn", polarity=1), | |
| confidence=0.8, | |
| source="induced", | |
| ) | |
| if rule.name not in [r.name for r in engine.rules]: | |
| engine.rules.append(rule) | |
| msg = "[Induction] Learned rule: if ?x is hot → touching_?x causes burn" | |
| trace.append(msg) | |
| avg_conf = 0.8 | |
| count = 1 | |
| return new_facts, trace, avg_conf | |
| def reason_backward(self, engine: "CognitiveEngine", goal: RulePattern): | |
| # Induction is forward-only | |
| return [], [], 0.0 | |
| # ========================== | |
| # Analogical Engine | |
| # ========================== | |
| class AnalogicalEngine(ReasoningEngineBase): | |
| """ | |
| Structural analogy + embeddings. | |
| Example: | |
| fire is hot | |
| touching_fire causes burn | |
| stove is hot | |
| → touching_stove causes burn (by analogy) | |
| """ | |
| name = "analogical" | |
| def reason_forward(self, engine: "CognitiveEngine") -> Tuple[List[Fact], List[str], float]: | |
| trace = [] | |
| new_facts = [] | |
| avg_conf = 0.0 | |
| count = 0 | |
| facts = engine.working.all_facts() | |
| hot_subjects = [f for f in facts if f.predicate == "is" and f.obj == "hot" and f.polarity == 1] | |
| burn_facts = [f for f in facts if f.predicate == "causes" and f.obj == "burn" and f.subject.startswith("touching_")] | |
| for hf in hot_subjects: | |
| for bf in burn_facts: | |
| x = bf.subject.replace("touching_", "") | |
| if x == hf.subject: | |
| # Find analogous subjects | |
| for hf2 in hot_subjects: | |
| if hf2.subject == hf.subject: | |
| continue | |
| sim = util.cos_sim(hf.embedding, hf2.embedding).item() | |
| if sim > 0.6: | |
| concl = Fact( | |
| subject=f"touching_{hf2.subject}", | |
| predicate="causes", | |
| obj="burn", | |
| polarity=1, | |
| confidence=0.7 * sim, | |
| verified=False, | |
| source="analogical", | |
| ) | |
| if not engine.working.has_fact(concl): | |
| new_facts.append(concl) | |
| msg = ( | |
| f"[Analogy] From {hf.subject}~{hf2.subject} and {bf.to_text()} " | |
| f"→ {concl.to_text()} (sim={sim:.2f})" | |
| ) | |
| trace.append(msg) | |
| avg_conf += concl.confidence | |
| count += 1 | |
| if count > 0: | |
| avg_conf /= count | |
| else: | |
| avg_conf = 0.0 | |
| return new_facts, trace, avg_conf | |
| def reason_backward(self, engine: "CognitiveEngine", goal: RulePattern): | |
| # Analogy is forward-only | |
| return [], [], 0.0 | |
| # ========================== | |
| # AURA v7 — Neuro‑Symbolic Hybrid Brain | |
| # Chunk 7 / 10 | |
| # Counterfactual Engine + Meta‑Controller + CognitiveEngine | |
| # ========================== | |
| class CounterfactualEngine(ReasoningEngineBase): | |
| """ | |
| Hybrid counterfactual reasoning: | |
| - Symbolic intervention: replace a fact and re-run reasoning | |
| - Causal-ish graph reasoning via semantic memory | |
| """ | |
| name = "counterfactual" | |
| def reason_forward(self, engine: "CognitiveEngine"): | |
| # Counterfactuals are not automatically generated | |
| return [], [], 0.0 | |
| def reason_backward(self, engine: "CognitiveEngine", goal: RulePattern): | |
| # Counterfactuals require explicit user request | |
| return [], [], 0.0 | |
| def simulate(self, engine: "CognitiveEngine", intervention_fact: Fact) -> Dict[str, Any]: | |
| """ | |
| Perform a symbolic intervention: | |
| - Temporarily add the fact | |
| - Re-run forward reasoning | |
| - Observe differences | |
| """ | |
| temp_engine = engine.clone() | |
| temp_engine.add_fact(intervention_fact) | |
| temp_engine.reason_forward_until_fixpoint(max_iterations=3) | |
| return { | |
| "intervention": intervention_fact.to_text(), | |
| "new_facts": [f.to_text() for f in temp_engine.working.all_facts()], | |
| } | |
| # ========================== | |
| # Meta-Controller | |
| # ========================== | |
| class MetaController: | |
| """ | |
| Chooses which reasoning engines to trust based on: | |
| - Past performance (engine_scores) | |
| - Confidence of recent outputs | |
| """ | |
| def __init__(self, meta_memory: MetaMemory): | |
| self.meta = meta_memory | |
| def choose_engines_forward(self, engines: List[ReasoningEngineBase]) -> List[ReasoningEngineBase]: | |
| scored = [] | |
| for e in engines: | |
| score = self.meta.engine_scores.get(e.name, 0.5) | |
| scored.append((score, e)) | |
| scored.sort(key=lambda x: x[0], reverse=True) | |
| return [e for _, e in scored] | |
| def choose_engines_backward(self, engines: List[ReasoningEngineBase]) -> List[ReasoningEngineBase]: | |
| return self.choose_engines_forward(engines) | |
| # ========================== | |
| # Cognitive Engine (Core Brain) | |
| # ========================== | |
| class CognitiveEngine: | |
| """ | |
| The central orchestrator: | |
| - Holds all memory systems | |
| - Holds all reasoning engines | |
| - Runs forward/backward reasoning | |
| - Handles contradictions | |
| """ | |
| def __init__(self): | |
| # Memory systems | |
| self.sensory = SensoryMemory() | |
| self.working = WorkingMemory() | |
| self.semantic = SemanticMemory() | |
| self.episodic = EpisodicMemory() | |
| self.procedural = ProceduralMemory() | |
| self.meta = MetaMemory() | |
| # Reasoning engines | |
| self.engines: List[ReasoningEngineBase] = [ | |
| DeductiveEngine(), | |
| InductiveEngine(), | |
| AnalogicalEngine(), | |
| CounterfactualEngine(), | |
| ] | |
| # Meta-controller | |
| self.meta_controller = MetaController(self.meta) | |
| # Rule store | |
| self.rules: List[Rule] = [] | |
| # ------------------------- | |
| # Fact & Rule Management | |
| # ------------------------- | |
| def add_fact(self, fact: Fact): | |
| """ | |
| Add fact to working + semantic memory. | |
| Check for contradictions. | |
| """ | |
| # Check for contradictions | |
| opposite_key = ("neg:" if fact.polarity == 1 else "pos:") + fact.to_text(include_polarity=False) | |
| if opposite_key in self.semantic.fact_map: | |
| self.meta.add_contradiction(fact, self.semantic.fact_map[opposite_key]) | |
| self.working.add_fact(fact) | |
| self.semantic.add_fact(fact) | |
| def add_rule(self, rule: Rule): | |
| self.rules.append(rule) | |
| # ------------------------- | |
| # Forward Reasoning Loop | |
| # ------------------------- | |
| def reason_forward_until_fixpoint(self, max_iterations: int = 5): | |
| """ | |
| Run forward reasoning until no new facts are produced. | |
| """ | |
| for _ in range(max_iterations): | |
| any_new = False | |
| ordered_engines = self.meta_controller.choose_engines_forward(self.engines) | |
| for engine in ordered_engines: | |
| new_facts, trace, avg_conf = engine.reason_forward(self) | |
| if new_facts: | |
| any_new = True | |
| for f in new_facts: | |
| self.add_fact(f) | |
| for t in trace: | |
| self.meta.log(engine.name, t, avg_conf if avg_conf > 0 else 0.5) | |
| if not any_new: | |
| break | |
| # ------------------------- | |
| # Backward Reasoning | |
| # ------------------------- | |
| def reason_backward(self, goal: RulePattern) -> Tuple[List[Fact], List[str], float]: | |
| ordered_engines = self.meta_controller.choose_engines_backward(self.engines) | |
| best_facts = [] | |
| best_trace = [] | |
| best_conf = 0.0 | |
| for engine in ordered_engines: | |
| facts, trace, conf = engine.reason_backward(self, goal) | |
| if facts and conf > best_conf: | |
| best_facts = facts | |
| best_trace = trace | |
| best_conf = conf | |
| return best_facts, best_trace, best_conf | |
| # ------------------------- | |
| # Cloning (for counterfactuals) | |
| # ------------------------- | |
| def clone(self) -> "CognitiveEngine": | |
| """ | |
| Create a deep-ish clone of the engine for counterfactual simulation. | |
| """ | |
| new = CognitiveEngine() | |
| # Copy facts | |
| for f in self.working.all_facts(): | |
| new.add_fact(f) | |
| # Copy rules | |
| for r in self.rules: | |
| new.add_rule(r) | |
| return new | |
| # ========================== | |
| # AURA v7 — Neuro‑Symbolic Hybrid Brain | |
| # Chunk 8 / 10 | |
| # Natural Language Parser (Hybrid) | |
| # ========================== | |
| class NLParser: | |
| """ | |
| Hybrid natural language parser: | |
| - Rule-based parsing for simple patterns | |
| - Embedding-based fallback | |
| - Negation detection | |
| - Probabilistic modifier extraction | |
| """ | |
| def __init__(self, engine: CognitiveEngine): | |
| self.engine = engine | |
| # --------------------------------------------------------- | |
| # Assertion Parsing (creates Facts) | |
| # --------------------------------------------------------- | |
| def parse_assertion(self, text: str) -> Optional[Fact]: | |
| """ | |
| Convert natural language assertions into structured Facts. | |
| Handles: | |
| - "X is Y" | |
| - "X causes Y" | |
| - Negation ("not", "never", etc.) | |
| - Probabilistic modifiers ("usually", "rarely") | |
| """ | |
| t = normalize_text(text) | |
| neg = contains_negation(t) | |
| polarity = -1 if neg else 1 | |
| prob = extract_prob_modifier(t) | |
| # Remove negation words for cleaner parsing | |
| t_clean = re.sub(r"\bnot\b|\bnever\b|\bdoesnt\b|\bisnt\b|\barent\b", "", t).strip() | |
| # Pattern: "x is y" | |
| m = re.match(r"(.+?) is (.+)", t_clean) | |
| if m: | |
| subj = m.group(1).strip() | |
| obj = m.group(2).strip() | |
| return Fact( | |
| subject=subj, | |
| predicate="is", | |
| obj=obj, | |
| polarity=polarity, | |
| confidence=prob, | |
| source="nl_input", | |
| ) | |
| # Pattern: "x causes y" | |
| m = re.match(r"(.+?) causes (.+)", t_clean) | |
| if m: | |
| subj = m.group(1).strip() | |
| obj = m.group(2).strip() | |
| return Fact( | |
| subject=subj, | |
| predicate="causes", | |
| obj=obj, | |
| polarity=polarity, | |
| confidence=prob, | |
| source="nl_input", | |
| ) | |
| # Fallback: treat as descriptive fact | |
| return Fact( | |
| subject=t_clean, | |
| predicate="describes", | |
| obj=None, | |
| polarity=polarity, | |
| confidence=prob, | |
| source="nl_input", | |
| ) | |
| # --------------------------------------------------------- | |
| # Query Parsing (creates RulePattern) | |
| # --------------------------------------------------------- | |
| def parse_query_to_goal(self, text: str) -> RulePattern: | |
| """ | |
| Convert natural language questions into RulePatterns. | |
| Handles: | |
| - "Is X Y?" | |
| - "Does X cause Y?" | |
| - Negation ("not", "never") | |
| """ | |
| t = normalize_text(text) | |
| neg = contains_negation(t) | |
| polarity = -1 if neg else 1 | |
| # Remove negation words for cleaner parsing | |
| t_clean = re.sub(r"\bnot\b|\bnever\b|\bdoesnt\b|\bisnt\b|\barent\b", "", t).strip() | |
| # Pattern: "is x y?" | |
| m = re.match(r"is (.+?) (.+)\??", t_clean) | |
| if m: | |
| subj = m.group(1).strip() | |
| obj = m.group(2).strip() | |
| return RulePattern( | |
| subject=subj, | |
| predicate="is", | |
| obj=obj, | |
| polarity=polarity, | |
| ) | |
| # Pattern: "does x cause y?" | |
| m = re.match(r"does (.+?) cause (.+)\??", t_clean) | |
| if m: | |
| subj = m.group(1).strip() | |
| obj = m.group(2).strip() | |
| return RulePattern( | |
| subject=subj, | |
| predicate="causes", | |
| obj=obj, | |
| polarity=polarity, | |
| ) | |
| # Fallback | |
| return RulePattern( | |
| subject=t_clean, | |
| predicate="describes", | |
| obj=None, | |
| polarity=polarity, | |
| ) | |
| # ========================== | |
| # AURA v7 — Neuro‑Symbolic Hybrid Brain | |
| # Chunk 9 / 10 | |
| # Dataset Ingestion (Omniscience) | |
| # ========================== | |
| def ingest_omniscience(engine: CognitiveEngine, max_items: int = 200): | |
| """ | |
| Ingests the ArtificialAnalysis/AA-Omniscience-Public dataset | |
| into sensory, semantic, and episodic memory. | |
| Each dataset item typically contains: | |
| - "input": natural language prompt | |
| - "output": natural language answer | |
| - "metadata": optional | |
| """ | |
| print("Loading Omniscience dataset...") | |
| ds = load_dataset("ArtificialAnalysis/AA-Omniscience-Public") | |
| data = ds["train"] | |
| parser = NLParser(engine) | |
| count = 0 | |
| for item in data: | |
| text_in = item.get("input", "") | |
| text_out = item.get("output", "") | |
| if not text_in and not text_out: | |
| continue | |
| # ------------------------- | |
| # Sensory Memory | |
| # ------------------------- | |
| combined_text = f"{text_in} -> {text_out}" | |
| normalized = normalize_text(combined_text) | |
| emb = embedding_service.encode(normalized) | |
| engine.sensory.add_entry(combined_text, embedding=emb) | |
| # ------------------------- | |
| # Structured Fact Extraction | |
| # ------------------------- | |
| fact_in = parser.parse_assertion(text_in) if text_in else None | |
| fact_out = parser.parse_assertion(text_out) if text_out else None | |
| # Add to semantic + working memory | |
| local_facts = [] | |
| if fact_in: | |
| engine.add_fact(fact_in) | |
| local_facts.append(fact_in) | |
| if fact_out: | |
| engine.add_fact(fact_out) | |
| local_facts.append(fact_out) | |
| # ------------------------- | |
| # Episodic Memory | |
| # ------------------------- | |
| if local_facts: | |
| engine.episodic.add_episode( | |
| description="omniscience_item", | |
| facts=local_facts | |
| ) | |
| count += 1 | |
| if count >= max_items: | |
| break | |
| print(f"Ingested {count} items from AA-Omniscience-Public dataset.") | |
| # ========================== | |
| # AURA v7 — Neuro‑Symbolic Hybrid Brain | |
| # Chunk 10 / 10 | |
| # AURA Interface + main() | |
| # ========================== | |
| class AURAInterface: | |
| """ | |
| High-level interface for interacting with AURA: | |
| - assert_fact(text) | |
| - query(text) | |
| """ | |
| def __init__(self, engine: CognitiveEngine): | |
| self.engine = engine | |
| self.parser = NLParser(engine) | |
| # --------------------------------------------------------- | |
| # Assertions | |
| # --------------------------------------------------------- | |
| def assert_fact(self, text: str) -> Fact: | |
| fact = self.parser.parse_assertion(text) | |
| self.engine.add_fact(fact) | |
| return fact | |
| # --------------------------------------------------------- | |
| # Queries | |
| # --------------------------------------------------------- | |
| def query(self, text: str) -> Dict[str, Any]: | |
| normalized = normalize_text(text) | |
| query_embedding = embedding_service.encode(normalized) | |
| # Parse into structured goal | |
| goal = self.parser.parse_query_to_goal(text) | |
| # If negated, require explicit proof | |
| if goal.polarity == -1: | |
| facts, trace, conf = self.engine.reason_backward(goal) | |
| if facts: | |
| best = max(facts, key=lambda f: f.confidence) | |
| return { | |
| "response": "Yes", | |
| "explanation": f"Proved negated fact: '{best.to_text()}'", | |
| "confidence": float(best.confidence), | |
| "trace": trace + [e.message for e in self.engine.meta.recent_trace()], | |
| } | |
| else: | |
| return { | |
| "response": "No", | |
| "explanation": "No rule or fact supports the negated claim.", | |
| "confidence": 0.0, | |
| "trace": [e.message for e in self.engine.meta.recent_trace()], | |
| } | |
| # Try backward reasoning first | |
| facts, trace, conf = self.engine.reason_backward(goal) | |
| if facts: | |
| best = max(facts, key=lambda f: f.confidence) | |
| return { | |
| "response": "Yes" if best.polarity == 1 else "No", | |
| "explanation": f"Proved: '{best.to_text()}' via backward reasoning.", | |
| "confidence": float(best.confidence), | |
| "trace": trace + [e.message for e in self.engine.meta.recent_trace()], | |
| } | |
| # Semantic memory fallback | |
| fact = self.engine.semantic.search_fact(query_embedding, threshold=0.6) | |
| if fact: | |
| return { | |
| "response": "Yes" if fact.polarity == 1 else "No", | |
| "explanation": f"Found in semantic memory: '{fact.to_text()}'", | |
| "confidence": float(fact.confidence), | |
| "trace": [e.message for e in self.engine.meta.recent_trace()], | |
| } | |
| # Sensory memory fallback | |
| best_idx = None | |
| best_score = 0.0 | |
| for idx, emb in enumerate(self.engine.sensory.entry_embeddings): | |
| sim = util.cos_sim(query_embedding, emb).item() | |
| if sim > best_score: | |
| best_score = sim | |
| best_idx = idx | |
| if best_idx is not None and best_score >= 0.35: | |
| best_entry = self.engine.sensory.entries[best_idx] | |
| return { | |
| "response": "Possibly", | |
| "explanation": f"Sensory memory match: {best_entry[:200]}...", | |
| "confidence": float(best_score), | |
| "trace": [e.message for e in self.engine.meta.recent_trace()], | |
| } | |
| # Unknown | |
| return { | |
| "response": "Unknown", | |
| "explanation": f"No information found for '{text}'", | |
| "confidence": 0.0, | |
| "trace": [e.message for e in self.engine.meta.recent_trace()], | |
| } | |
| # ========================== | |
| # Core Knowledge Initialization | |
| # ========================== | |
| def build_core_knowledge(engine: CognitiveEngine): | |
| """ | |
| Load basic commonsense knowledge + rules. | |
| """ | |
| fire_hot = Fact(subject="fire", predicate="is", obj="hot", confidence=0.95, polarity=1, source="core") | |
| stove_hot = Fact(subject="stove", predicate="is", obj="hot", confidence=0.9, polarity=1, source="core") | |
| touching_fire_burn = Fact(subject="touching_fire", predicate="causes", obj="burn", confidence=0.95, polarity=1, source="core") | |
| engine.add_fact(fire_hot) | |
| engine.add_fact(stove_hot) | |
| engine.add_fact(touching_fire_burn) | |
| # Manual rules | |
| rule1 = Rule( | |
| name="hot_things_burn_rule", | |
| conditions=[RulePattern(subject="?x", predicate="is", obj="hot", polarity=1)], | |
| conclusion=RulePattern(subject="touching_?x", predicate="causes", obj="burn", polarity=1), | |
| confidence=0.9, | |
| source="manual", | |
| ) | |
| rule2 = Rule( | |
| name="burn_implies_danger_rule", | |
| conditions=[RulePattern(subject="touching_?x", predicate="causes", obj="burn", polarity=1)], | |
| conclusion=RulePattern(subject="?x", predicate="is", obj="dangerous", polarity=1), | |
| confidence=0.9, | |
| source="manual", | |
| ) | |
| # Negation rule example | |
| rule3 = Rule( | |
| name="cold_things_do_not_burn_rule", | |
| conditions=[RulePattern(subject="?x", predicate="is", obj="cold", polarity=1)], | |
| conclusion=RulePattern(subject="touching_?x", predicate="causes", obj="burn", polarity=-1), | |
| confidence=0.9, | |
| source="manual", | |
| ) | |
| engine.add_rule(rule1) | |
| engine.add_rule(rule2) | |
| engine.add_rule(rule3) | |
| # ========================== | |
| # Main REPL | |
| # ========================== | |
| def main(): | |
| engine = CognitiveEngine() | |
| api = AURAInterface(engine) | |
| # Load core knowledge | |
| build_core_knowledge(engine) | |
| engine.reason_forward_until_fixpoint(max_iterations=5) | |
| # Load Omniscience dataset | |
| ingest_omniscience(engine, max_items=50) | |
| print("\nAURA v7 ready. Type assertions or questions.") | |
| print("Examples:") | |
| print(" - 'fire is hot'") | |
| print(" - 'ice is cold'") | |
| print(" - 'does touching fire cause burn?'") | |
| print(" - 'does touching ice cause burn?'") | |
| print(" - 'is stove dangerous?'") | |
| print(" - 'do hot things NOT burn with fire?'") | |
| print("Type 'exit' to quit.\n") | |
| while True: | |
| try: | |
| query = input("You: ") | |
| except EOFError: | |
| break | |
| if query.lower() in {"exit", "quit"}: | |
| print("Goodbye.") | |
| break | |
| # Assertions | |
| if query.lower().startswith("assert "): | |
| fact = api.assert_fact(query[len("assert "):]) | |
| engine.reason_forward_until_fixpoint(max_iterations=3) | |
| print(f"AURA: Asserted '{fact.to_text()}' (conf={fact.confidence:.2f})\n") | |
| continue | |
| # Queries | |
| response = api.query(query) | |
| print(f"AURA Response: {response['response']}") | |
| print(f"Explanation: {response['explanation']}") | |
| print(f"Confidence: {response['confidence']:.2f}") | |
| if response.get("trace"): | |
| print("Recent reasoning trace:") | |
| for line in response["trace"][-10:]: | |
| print(" -", line) | |
| print() | |
| if __name__ == "__main__": | |
| main() | |