use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub struct DomainId(pub String);
impl fmt::Display for DomainId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Task {
pub id: String,
pub domain_id: DomainId,
pub difficulty: f32,
pub spec: serde_json::Value,
pub constraints: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Solution {
pub task_id: String,
pub content: String,
pub data: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Evaluation {
pub score: f32,
pub correctness: f32,
pub efficiency: f32,
pub elegance: f32,
pub constraint_results: Vec<bool>,
pub notes: Vec<String>,
}
impl Evaluation {
pub fn zero(notes: Vec<String>) -> Self {
Self {
score: 0.0,
correctness: 0.0,
efficiency: 0.0,
elegance: 0.0,
constraint_results: Vec::new(),
notes,
}
}
pub fn composite(correctness: f32, efficiency: f32, elegance: f32) -> Self {
let score = 0.6 * correctness + 0.25 * efficiency + 0.15 * elegance;
Self {
score: score.clamp(0.0, 1.0),
correctness,
efficiency,
elegance,
constraint_results: Vec::new(),
notes: Vec::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DomainEmbedding {
pub vector: Vec<f32>,
pub domain_id: DomainId,
pub dim: usize,
}
impl DomainEmbedding {
pub fn new(vector: Vec<f32>, domain_id: DomainId) -> Self {
let dim = vector.len();
Self {
vector,
domain_id,
dim,
}
}
pub fn cosine_similarity(&self, other: &DomainEmbedding) -> f32 {
assert_eq!(self.dim, other.dim, "Embedding dimensions must match");
let mut dot = 0.0f32;
let mut norm_a = 0.0f32;
let mut norm_b = 0.0f32;
for i in 0..self.dim {
dot += self.vector[i] * other.vector[i];
norm_a += self.vector[i] * self.vector[i];
norm_b += other.vector[i] * other.vector[i];
}
let denom = (norm_a.sqrt() * norm_b.sqrt()).max(1e-10);
dot / denom
}
}
pub trait Domain: Send + Sync {
fn id(&self) -> &DomainId;
fn name(&self) -> &str;
fn generate_tasks(&self, count: usize, difficulty: f32) -> Vec<Task>;
fn evaluate(&self, task: &Task, solution: &Solution) -> Evaluation;
fn embed(&self, solution: &Solution) -> DomainEmbedding;
fn embedding_dim(&self) -> usize;
fn reference_solution(&self, task: &Task) -> Option<Solution>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_domain_id_display() {
let id = DomainId("rust_synthesis".to_string());
assert_eq!(format!("{}", id), "rust_synthesis");
}
#[test]
fn test_evaluation_zero() {
let eval = Evaluation::zero(vec!["compile error".to_string()]);
assert_eq!(eval.score, 0.0);
assert_eq!(eval.notes.len(), 1);
}
#[test]
fn test_evaluation_composite() {
let eval = Evaluation::composite(1.0, 0.8, 0.6);
assert!((eval.score - 0.89).abs() < 1e-4);
}
#[test]
fn test_embedding_cosine_similarity() {
let id = DomainId("test".to_string());
let a = DomainEmbedding::new(vec![1.0, 0.0, 0.0], id.clone());
let b = DomainEmbedding::new(vec![1.0, 0.0, 0.0], id.clone());
assert!((a.cosine_similarity(&b) - 1.0).abs() < 1e-6);
let c = DomainEmbedding::new(vec![0.0, 1.0, 0.0], id);
assert!(a.cosine_similarity(&c).abs() < 1e-6);
}
#[test]
fn test_evaluation_clamp() {
let eval = Evaluation::composite(1.0, 1.0, 1.0);
assert!(eval.score <= 1.0);
}
}