reputation_core/
performance.rs1use crate::Calculator;
8use reputation_types::{AgentData, ReputationScore, PriorBreakdown};
9
10#[inline(always)]
12pub fn calculate_confidence_fast(n: u32, k: f64) -> f64 {
13 let n_f64 = n as f64;
14 n_f64 / (n_f64 + k)
15}
16
17#[inline(always)]
19pub fn calculate_empirical_fast(average_rating: Option<f64>) -> f64 {
20 match average_rating {
21 Some(rating) => {
22 (rating - 1.0) * 25.0
25 }
26 None => 50.0, }
28}
29
30#[inline]
32pub fn calculate_prior_fast(
33 agent: &AgentData,
34 prior_base: f64,
35 prior_max: f64,
36) -> PriorBreakdown {
37 let mut bonuses = [0.0; 6];
39 let mut idx = 0;
40
41 bonuses[idx] = prior_base;
43 idx += 1;
44
45 if let Some(level) = agent.mcp_level {
47 bonuses[idx] = match level {
48 1 => 5.0,
49 2 => 10.0,
50 3 => 15.0,
51 _ => 0.0,
52 };
53 idx += 1;
54 }
55
56 if agent.identity_verified {
58 bonuses[idx] = 5.0;
59 idx += 1;
60 }
61
62 if agent.security_audit_passed {
64 bonuses[idx] = 7.0;
65 idx += 1;
66 }
67
68 if agent.open_source {
70 bonuses[idx] = 3.0;
71 idx += 1;
72 }
73
74 let age_days = (chrono::Utc::now() - agent.created_at).num_days();
76 if age_days > 365 {
77 bonuses[idx] = 5.0;
78 }
79
80 let sum: f64 = bonuses.iter().sum();
82 let total = sum.min(prior_max);
83
84 PriorBreakdown {
85 base_score: prior_base,
86 mcp_bonus: if agent.mcp_level.is_some() { bonuses[1] } else { 0.0 },
87 identity_bonus: if agent.identity_verified { 5.0 } else { 0.0 },
88 security_audit_bonus: if agent.security_audit_passed { 7.0 } else { 0.0 },
89 open_source_bonus: if agent.open_source { 3.0 } else { 0.0 },
90 age_bonus: if age_days > 365 { 5.0 } else { 0.0 },
91 total,
92 }
93}
94
95#[cold]
97#[inline(never)]
98pub fn handle_validation_error() -> crate::error::CalculationError {
99 crate::error::CalculationError::NaNResult
100}
101
102pub fn optimal_chunk_size() -> usize {
104 let cpus = std::thread::available_parallelism()
110 .map(|n| n.get())
111 .unwrap_or(8);
112 cpus * 64 }
114
115pub fn calculate_batch_optimized(
117 calculator: &Calculator,
118 agents: &[AgentData],
119) -> Vec<Result<ReputationScore, crate::error::ReputationError>> {
120 use rayon::prelude::*;
121
122 let chunk_size = optimal_chunk_size();
123
124 agents
125 .par_chunks(chunk_size)
126 .flat_map(|chunk| {
127 chunk
128 .iter()
129 .map(|agent| calculator.calculate(agent))
130 .collect::<Vec<_>>()
131 })
132 .collect()
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138 use reputation_types::AgentDataBuilder;
139
140 #[test]
141 fn test_confidence_fast() {
142 assert_eq!(calculate_confidence_fast(0, 15.0), 0.0);
143 assert_eq!(calculate_confidence_fast(15, 15.0), 0.5);
144 assert!((calculate_confidence_fast(100, 15.0) - 0.869565).abs() < 0.00001);
145 }
146
147 #[test]
148 fn test_empirical_fast() {
149 assert_eq!(calculate_empirical_fast(Some(1.0)), 0.0);
150 assert_eq!(calculate_empirical_fast(Some(3.0)), 50.0);
151 assert_eq!(calculate_empirical_fast(Some(5.0)), 100.0);
152 assert_eq!(calculate_empirical_fast(None), 50.0);
153 }
154
155 #[test]
156 fn test_prior_fast() {
157 let agent = AgentDataBuilder::new("did:test:perf")
158 .mcp_level(2)
159 .identity_verified(true)
160 .build()
161 .unwrap();
162
163 let breakdown = calculate_prior_fast(&agent, 50.0, 80.0);
164 assert_eq!(breakdown.base_score, 50.0);
165 assert_eq!(breakdown.mcp_bonus, 10.0);
166 assert_eq!(breakdown.identity_bonus, 5.0);
167 assert_eq!(breakdown.total, 65.0);
168 }
169
170 #[test]
171 fn test_optimal_chunk_size() {
172 let size = optimal_chunk_size();
173 assert!(size > 0);
174 assert!(size <= 10000); }
176}