Files
wifi-densepose/vendor/ruvector/crates/ruvector-domain-expansion/src/lib.rs

592 lines
20 KiB
Rust

//! # Domain Expansion Engine
//!
//! Cross-domain transfer learning for general problem-solving capability.
//!
//! ## Core Insight
//!
//! True IQ growth appears when a kernel trained on Domain 1 improves Domain 2
//! faster than Domain 2 alone. That is generalization.
//!
//! ## Two-Layer Architecture
//!
//! **Policy learning layer**: Meta Thompson Sampling with Beta priors across
//! context buckets. Chooses strategies via uncertainty-aware selection.
//! Transfer happens through compact priors — not raw trajectories.
//!
//! **Operator layer**: Deterministic domain kernels (Rust synthesis, planning,
//! tool orchestration) that generate tasks, evaluate solutions, and produce
//! embeddings into a shared representation space.
//!
//! ## Domains
//!
//! - **Rust Program Synthesis**: Generate Rust functions from specifications
//! - **Structured Planning**: Multi-step plans with dependencies and resources
//! - **Tool Orchestration**: Coordinate multiple tools/agents for complex goals
//!
//! ## Transfer Protocol
//!
//! 1. Train on Domain 1, extract `TransferPrior` (posterior summaries)
//! 2. Initialize Domain 2 with dampened priors from Domain 1
//! 3. Measure acceleration: cycles to convergence with/without transfer
//! 4. A delta is promotable only if it improves target without regressing source
//!
//! ## Population-Based Policy Search
//!
//! Run a population of `PolicyKernel` variants in parallel.
//! Each variant tunes knobs (skip mode, prepass, speculation thresholds).
//! Keep top performers on holdouts, mutate, repeat.
//!
//! ## Acceptance Test
//!
//! Domain 2 must converge faster than Domain 1 to target accuracy, cost,
//! robustness, and zero policy violations.
#![warn(missing_docs)]
pub mod cost_curve;
pub mod domain;
pub mod meta_learning;
pub mod planning;
pub mod policy_kernel;
pub mod rust_synthesis;
pub mod tool_orchestration;
pub mod transfer;
/// RVF format integration: segment serialization, witness chains, AGI packaging.
///
/// Requires the `rvf` feature to be enabled.
#[cfg(feature = "rvf")]
pub mod rvf_bridge;
// Re-export core types.
pub use cost_curve::{
AccelerationEntry, AccelerationScoreboard, ConvergenceThresholds, CostCurve, CostCurvePoint,
ScoreboardSummary,
};
pub use domain::{Domain, DomainEmbedding, DomainId, Evaluation, Solution, Task};
pub use meta_learning::{
CuriosityBonus, DecayingBeta, MetaLearningEngine, MetaLearningHealth, ParetoFront, ParetoPoint,
PlateauAction, PlateauDetector, RegretSummary, RegretTracker,
};
pub use planning::PlanningDomain;
pub use policy_kernel::{PolicyKernel, PolicyKnobs, PopulationSearch, PopulationStats};
pub use rust_synthesis::RustSynthesisDomain;
pub use tool_orchestration::ToolOrchestrationDomain;
pub use transfer::{
ArmId, BetaParams, ContextBucket, DualPathResult, MetaThompsonEngine, TransferPrior,
TransferVerification,
};
use std::collections::HashMap;
/// The domain expansion orchestrator.
///
/// Manages multiple domains, transfer learning between them,
/// population-based policy search, and the acceleration scoreboard.
///
/// The `meta` field provides five composable learning improvements:
/// regret tracking, decaying priors, plateau detection, Pareto front
/// optimization, and curiosity-driven exploration.
pub struct DomainExpansionEngine {
/// Registered domains.
domains: HashMap<DomainId, Box<dyn Domain>>,
/// Meta Thompson Sampling engine for cross-domain transfer.
pub thompson: MetaThompsonEngine,
/// Population-based policy search.
pub population: PopulationSearch,
/// Acceleration scoreboard tracking convergence across domains.
pub scoreboard: AccelerationScoreboard,
/// Meta-learning engine: regret, plateau, Pareto, curiosity, decay.
pub meta: MetaLearningEngine,
/// Holdout tasks per domain for verification.
holdouts: HashMap<DomainId, Vec<Task>>,
/// Counterexample set: failed solutions that inform future decisions.
counterexamples: HashMap<DomainId, Vec<(Task, Solution, Evaluation)>>,
}
impl DomainExpansionEngine {
/// Create a new domain expansion engine with default configuration.
///
/// Initializes the three core domains and the transfer engine.
pub fn new() -> Self {
let arms = vec![
"greedy".into(),
"exploratory".into(),
"conservative".into(),
"speculative".into(),
];
let mut engine = Self {
domains: HashMap::new(),
thompson: MetaThompsonEngine::new(arms),
population: PopulationSearch::new(8),
scoreboard: AccelerationScoreboard::new(),
meta: MetaLearningEngine::new(),
holdouts: HashMap::new(),
counterexamples: HashMap::new(),
};
// Register the three core domains.
engine.register_domain(Box::new(RustSynthesisDomain::new()));
engine.register_domain(Box::new(PlanningDomain::new()));
engine.register_domain(Box::new(ToolOrchestrationDomain::new()));
engine
}
/// Register a new domain.
pub fn register_domain(&mut self, domain: Box<dyn Domain>) {
let id = domain.id().clone();
self.thompson.init_domain_uniform(id.clone());
self.domains.insert(id, domain);
}
/// Generate holdout tasks for verification.
pub fn generate_holdouts(&mut self, tasks_per_domain: usize, difficulty: f32) {
for (id, domain) in &self.domains {
let tasks = domain.generate_tasks(tasks_per_domain, difficulty);
self.holdouts.insert(id.clone(), tasks);
}
}
/// Generate training tasks for a specific domain.
pub fn generate_tasks(&self, domain_id: &DomainId, count: usize, difficulty: f32) -> Vec<Task> {
self.domains
.get(domain_id)
.map(|d| d.generate_tasks(count, difficulty))
.unwrap_or_default()
}
/// Evaluate a solution and record the outcome.
pub fn evaluate_and_record(
&mut self,
domain_id: &DomainId,
task: &Task,
solution: &Solution,
bucket: ContextBucket,
arm: ArmId,
) -> Evaluation {
let eval = self
.domains
.get(domain_id)
.map(|d| d.evaluate(task, solution))
.unwrap_or_else(|| Evaluation::zero(vec!["Domain not found".into()]));
// Record outcome in Thompson engine.
self.thompson.record_outcome(
domain_id,
bucket.clone(),
arm.clone(),
eval.score,
1.0, // unit cost for now
);
// Record in meta-learning engine (regret + curiosity + decaying beta).
self.meta.record_decision(&bucket, &arm, eval.score);
// Store counterexamples for poor solutions.
if eval.score < 0.3 {
self.counterexamples
.entry(domain_id.clone())
.or_default()
.push((task.clone(), solution.clone(), eval.clone()));
}
eval
}
/// Embed a solution into the shared representation space.
pub fn embed(&self, domain_id: &DomainId, solution: &Solution) -> Option<DomainEmbedding> {
self.domains.get(domain_id).map(|d| d.embed(solution))
}
/// Initiate transfer from source domain to target domain.
/// Extracts priors from source and seeds target.
pub fn initiate_transfer(&mut self, source: &DomainId, target: &DomainId) {
if let Some(prior) = self.thompson.extract_prior(source) {
self.thompson
.init_domain_with_transfer(target.clone(), &prior);
}
}
/// Verify a transfer delta: did it improve target without regressing source?
pub fn verify_transfer(
&self,
source: &DomainId,
target: &DomainId,
source_before: f32,
source_after: f32,
target_before: f32,
target_after: f32,
baseline_cycles: u64,
transfer_cycles: u64,
) -> TransferVerification {
TransferVerification::verify(
source.clone(),
target.clone(),
source_before,
source_after,
target_before,
target_after,
baseline_cycles,
transfer_cycles,
)
}
/// Evaluate all policy kernels on holdout tasks.
pub fn evaluate_population(&mut self) {
let holdout_snapshot: HashMap<DomainId, Vec<Task>> = self.holdouts.clone();
let domain_ids: Vec<DomainId> = self.domains.keys().cloned().collect();
for i in 0..self.population.population().len() {
for domain_id in &domain_ids {
if let Some(holdout_tasks) = holdout_snapshot.get(domain_id) {
let mut total_score = 0.0f32;
let mut count = 0;
for task in holdout_tasks {
if let Some(domain) = self.domains.get(domain_id) {
if let Some(ref_sol) = domain.reference_solution(task) {
let eval = domain.evaluate(task, &ref_sol);
total_score += eval.score;
count += 1;
}
}
}
let avg_score = if count > 0 {
total_score / count as f32
} else {
0.0
};
if let Some(kernel) = self.population.kernel_mut(i) {
kernel.record_score(domain_id.clone(), avg_score, 1.0);
}
}
}
}
}
/// Evolve the policy kernel population and update Pareto front.
pub fn evolve_population(&mut self) {
// Record current population into Pareto front before evolving.
let gen = self.population.generation();
for kernel in self.population.population() {
let accuracy = kernel.fitness();
let cost = if kernel.cycles > 0 {
kernel.total_cost / kernel.cycles as f32
} else {
0.0
};
// Robustness approximated by consistency across domains.
let robustness = if kernel.holdout_scores.len() > 1 {
let mean = accuracy;
let var: f32 = kernel
.holdout_scores
.values()
.map(|s| (s - mean).powi(2))
.sum::<f32>()
/ kernel.holdout_scores.len() as f32;
(1.0 - var.sqrt()).max(0.0)
} else {
accuracy
};
self.meta
.record_kernel(&kernel.id, accuracy, cost, robustness, gen);
}
self.population.evolve();
}
/// Get the best policy kernel found so far.
pub fn best_kernel(&self) -> Option<&PolicyKernel> {
self.population.best()
}
/// Get population statistics.
pub fn population_stats(&self) -> PopulationStats {
self.population.stats()
}
/// Get the scoreboard summary.
pub fn scoreboard_summary(&self) -> ScoreboardSummary {
self.scoreboard.summary()
}
/// Get registered domain IDs.
pub fn domain_ids(&self) -> Vec<DomainId> {
self.domains.keys().cloned().collect()
}
/// Get counterexamples for a domain.
pub fn counterexamples(&self, domain_id: &DomainId) -> &[(Task, Solution, Evaluation)] {
self.counterexamples
.get(domain_id)
.map(|v| v.as_slice())
.unwrap_or(&[])
}
/// Select best arm for a context using Thompson Sampling.
pub fn select_arm(&self, domain_id: &DomainId, bucket: &ContextBucket) -> Option<ArmId> {
let mut rng = rand::thread_rng();
self.thompson.select_arm(domain_id, bucket, &mut rng)
}
/// Check if dual-path speculation should be triggered.
pub fn should_speculate(&self, domain_id: &DomainId, bucket: &ContextBucket) -> bool {
self.thompson.is_uncertain(domain_id, bucket, 0.15)
}
/// Select arm with curiosity-boosted Thompson Sampling.
///
/// Combines the standard Thompson sample with a UCB-style exploration
/// bonus that favors under-visited bucket/arm combinations.
pub fn select_arm_curious(
&self,
domain_id: &DomainId,
bucket: &ContextBucket,
) -> Option<ArmId> {
let mut rng = rand::thread_rng();
// Get all arms and compute boosted scores
let prior = self.thompson.extract_prior(domain_id)?;
let arms: Vec<ArmId> = prior
.bucket_priors
.get(bucket)
.map(|m| m.keys().cloned().collect())
.unwrap_or_default();
if arms.is_empty() {
return self.thompson.select_arm(domain_id, bucket, &mut rng);
}
let mut best_arm = None;
let mut best_score = f32::NEG_INFINITY;
for arm in &arms {
let params = prior.get_prior(bucket, arm);
let sample = params.sample(&mut rng);
let boosted = self.meta.boosted_score(bucket, arm, sample);
if boosted > best_score {
best_score = boosted;
best_arm = Some(arm.clone());
}
}
best_arm.or_else(|| self.thompson.select_arm(domain_id, bucket, &mut rng))
}
/// Get meta-learning health diagnostics.
pub fn meta_health(&self) -> MetaLearningHealth {
self.meta.health_check()
}
/// Check cost curve for plateau and get recommended action.
pub fn check_plateau(&mut self, domain_id: &DomainId) -> PlateauAction {
if let Some(curve) = self.scoreboard.curves.get(domain_id) {
self.meta.check_plateau(&curve.points)
} else {
PlateauAction::Continue
}
}
/// Get regret summary across all learning contexts.
pub fn regret_summary(&self) -> RegretSummary {
self.meta.regret.summary()
}
/// Get the Pareto front of non-dominated policy kernels.
pub fn pareto_front(&self) -> &ParetoFront {
&self.meta.pareto
}
}
impl Default for DomainExpansionEngine {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_engine_creation() {
let engine = DomainExpansionEngine::new();
let ids = engine.domain_ids();
assert_eq!(ids.len(), 3);
}
#[test]
fn test_generate_tasks_all_domains() {
let engine = DomainExpansionEngine::new();
for domain_id in engine.domain_ids() {
let tasks = engine.generate_tasks(&domain_id, 5, 0.5);
assert_eq!(tasks.len(), 5);
}
}
#[test]
fn test_arm_selection() {
let engine = DomainExpansionEngine::new();
let bucket = ContextBucket {
difficulty_tier: "medium".into(),
category: "general".into(),
};
for domain_id in engine.domain_ids() {
let arm = engine.select_arm(&domain_id, &bucket);
assert!(arm.is_some());
}
}
#[test]
fn test_evaluate_and_record() {
let mut engine = DomainExpansionEngine::new();
let domain_id = DomainId("rust_synthesis".into());
let tasks = engine.generate_tasks(&domain_id, 1, 0.3);
let task = &tasks[0];
let solution = Solution {
task_id: task.id.clone(),
content:
"fn double(values: &[i64]) -> Vec<i64> { values.iter().map(|&x| x * 2).collect() }"
.into(),
data: serde_json::Value::Null,
};
let bucket = ContextBucket {
difficulty_tier: "easy".into(),
category: "transform".into(),
};
let arm = ArmId("greedy".into());
let eval = engine.evaluate_and_record(&domain_id, task, &solution, bucket, arm);
assert!(eval.score >= 0.0 && eval.score <= 1.0);
}
#[test]
fn test_cross_domain_embedding() {
let engine = DomainExpansionEngine::new();
let rust_sol = Solution {
task_id: "rust".into(),
content: "fn foo() { for i in 0..10 { if i > 5 { } } }".into(),
data: serde_json::Value::Null,
};
let plan_sol = Solution {
task_id: "plan".into(),
content: "allocate cpu then schedule parallel jobs".into(),
data: serde_json::json!({"steps": []}),
};
let rust_emb = engine
.embed(&DomainId("rust_synthesis".into()), &rust_sol)
.unwrap();
let plan_emb = engine
.embed(&DomainId("structured_planning".into()), &plan_sol)
.unwrap();
// Embeddings should be same dimension.
assert_eq!(rust_emb.dim, plan_emb.dim);
// Cross-domain similarity should be defined.
let sim = rust_emb.cosine_similarity(&plan_emb);
assert!(sim >= -1.0 && sim <= 1.0);
}
#[test]
fn test_transfer_flow() {
let mut engine = DomainExpansionEngine::new();
let source = DomainId("rust_synthesis".into());
let target = DomainId("structured_planning".into());
// Record some outcomes in source domain.
let bucket = ContextBucket {
difficulty_tier: "medium".into(),
category: "algorithm".into(),
};
for _ in 0..30 {
engine.thompson.record_outcome(
&source,
bucket.clone(),
ArmId("greedy".into()),
0.85,
1.0,
);
}
// Initiate transfer.
engine.initiate_transfer(&source, &target);
// Verify the transfer.
let verification = engine.verify_transfer(
&source, &target, 0.85, // source before
0.845, // source after (within tolerance)
0.3, // target before
0.7, // target after
100, // baseline cycles
45, // transfer cycles
);
assert!(verification.promotable);
assert!(verification.acceleration_factor > 1.0);
}
#[test]
fn test_population_evolution() {
let mut engine = DomainExpansionEngine::new();
engine.generate_holdouts(3, 0.3);
engine.evaluate_population();
let stats_before = engine.population_stats();
assert_eq!(stats_before.generation, 0);
engine.evolve_population();
let stats_after = engine.population_stats();
assert_eq!(stats_after.generation, 1);
}
#[test]
fn test_speculation_trigger() {
let engine = DomainExpansionEngine::new();
let bucket = ContextBucket {
difficulty_tier: "hard".into(),
category: "unknown".into(),
};
// With uniform priors, should be uncertain.
assert!(engine.should_speculate(&DomainId("rust_synthesis".into()), &bucket,));
}
#[test]
fn test_counterexample_tracking() {
let mut engine = DomainExpansionEngine::new();
let domain_id = DomainId("rust_synthesis".into());
let tasks = engine.generate_tasks(&domain_id, 1, 0.9);
let task = &tasks[0];
// Submit a terrible solution.
let solution = Solution {
task_id: task.id.clone(),
content: "".into(), // empty = bad
data: serde_json::Value::Null,
};
let bucket = ContextBucket {
difficulty_tier: "hard".into(),
category: "algorithm".into(),
};
let arm = ArmId("speculative".into());
let eval = engine.evaluate_and_record(&domain_id, task, &solution, bucket, arm);
assert!(eval.score < 0.3);
// Should be recorded as counterexample.
assert!(!engine.counterexamples(&domain_id).is_empty());
}
}