use crate::Calculator;
use reputation_types::{AgentData, ReputationScore, PriorBreakdown};
#[inline(always)]
pub fn calculate_confidence_fast(n: u32, k: f64) -> f64 {
let n_f64 = n as f64;
n_f64 / (n_f64 + k)
}
#[inline(always)]
pub fn calculate_empirical_fast(average_rating: Option<f64>) -> f64 {
match average_rating {
Some(rating) => {
(rating - 1.0) * 25.0
}
None => 50.0, }
}
#[inline]
pub fn calculate_prior_fast(
agent: &AgentData,
prior_base: f64,
prior_max: f64,
) -> PriorBreakdown {
let mut bonuses = [0.0; 6];
let mut idx = 0;
bonuses[idx] = prior_base;
idx += 1;
if let Some(level) = agent.mcp_level {
bonuses[idx] = match level {
1 => 5.0,
2 => 10.0,
3 => 15.0,
_ => 0.0,
};
idx += 1;
}
if agent.identity_verified {
bonuses[idx] = 5.0;
idx += 1;
}
if agent.security_audit_passed {
bonuses[idx] = 7.0;
idx += 1;
}
if agent.open_source {
bonuses[idx] = 3.0;
idx += 1;
}
let age_days = (chrono::Utc::now() - agent.created_at).num_days();
if age_days > 365 {
bonuses[idx] = 5.0;
}
let sum: f64 = bonuses.iter().sum();
let total = sum.min(prior_max);
PriorBreakdown {
base_score: prior_base,
mcp_bonus: if agent.mcp_level.is_some() { bonuses[1] } else { 0.0 },
identity_bonus: if agent.identity_verified { 5.0 } else { 0.0 },
security_audit_bonus: if agent.security_audit_passed { 7.0 } else { 0.0 },
open_source_bonus: if agent.open_source { 3.0 } else { 0.0 },
age_bonus: if age_days > 365 { 5.0 } else { 0.0 },
total,
}
}
#[cold]
#[inline(never)]
pub fn handle_validation_error() -> crate::error::CalculationError {
crate::error::CalculationError::NaNResult
}
pub fn optimal_chunk_size() -> usize {
let cpus = std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(8);
cpus * 64 }
pub fn calculate_batch_optimized(
calculator: &Calculator,
agents: &[AgentData],
) -> Vec<Result<ReputationScore, crate::error::ReputationError>> {
use rayon::prelude::*;
let chunk_size = optimal_chunk_size();
agents
.par_chunks(chunk_size)
.flat_map(|chunk| {
chunk
.iter()
.map(|agent| calculator.calculate(agent))
.collect::<Vec<_>>()
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use reputation_types::AgentDataBuilder;
#[test]
fn test_confidence_fast() {
assert_eq!(calculate_confidence_fast(0, 15.0), 0.0);
assert_eq!(calculate_confidence_fast(15, 15.0), 0.5);
assert!((calculate_confidence_fast(100, 15.0) - 0.869565).abs() < 0.00001);
}
#[test]
fn test_empirical_fast() {
assert_eq!(calculate_empirical_fast(Some(1.0)), 0.0);
assert_eq!(calculate_empirical_fast(Some(3.0)), 50.0);
assert_eq!(calculate_empirical_fast(Some(5.0)), 100.0);
assert_eq!(calculate_empirical_fast(None), 50.0);
}
#[test]
fn test_prior_fast() {
let agent = AgentDataBuilder::new("did:test:perf")
.mcp_level(2)
.identity_verified(true)
.build()
.unwrap();
let breakdown = calculate_prior_fast(&agent, 50.0, 80.0);
assert_eq!(breakdown.base_score, 50.0);
assert_eq!(breakdown.mcp_bonus, 10.0);
assert_eq!(breakdown.identity_bonus, 5.0);
assert_eq!(breakdown.total, 65.0);
}
#[test]
fn test_optimal_chunk_size() {
let size = optimal_chunk_size();
assert!(size > 0);
assert!(size <= 10000); }
}