1pub mod baselines;
17pub mod optimizations;
18pub mod benchmarks;
19pub mod solvers;
20pub mod core;
21pub mod utils;
22
23pub mod optimized {
25 pub use crate::optimizations::optimized::*;
26}
27pub mod solver_integration {
28 pub use crate::solvers::solver_integration::*;
29}
30
31use ndarray::{Array1, Array2};
32use nalgebra::{DMatrix, DVector};
33use std::time::{Duration, Instant};
34use thiserror::Error;
35
36use solver_integration::{SparseMatrix, NeumannSolver};
38
39#[derive(Debug, Error)]
40pub enum TemporalSolverError {
41 #[error("Dimension mismatch: expected {expected}, got {got}")]
42 DimensionMismatch { expected: usize, got: usize },
43
44 #[error("Solver error: {0}")]
45 SolverError(String),
46
47 #[error("Numerical error: {0}")]
48 NumericalError(String),
49
50 #[error("Certificate validation failed: error {error} exceeds threshold {threshold}")]
51 CertificateError { error: f64, threshold: f64 },
52}
53
54type Result<T> = std::result::Result<T, TemporalSolverError>;
55
56#[derive(Debug, Clone)]
58pub struct Certificate {
59 pub error_bound: f64,
61 pub confidence: f64,
63 pub gate_pass: bool,
65 pub iterations: usize,
67 pub computational_work: usize,
69}
70
71pub struct KalmanFilter {
73 state: DVector<f64>,
75 covariance: DMatrix<f64>,
77 process_noise: DMatrix<f64>,
79 measurement_noise: DMatrix<f64>,
81 transition: DMatrix<f64>,
83 measurement: DMatrix<f64>,
85}
86
87impl KalmanFilter {
88 pub fn new(state_dim: usize) -> Self {
89 let full_dim = state_dim * 2; let mut transition = DMatrix::identity(full_dim, full_dim);
93 for i in 0..state_dim {
95 transition[(i, state_dim + i)] = 0.001;
96 }
97
98 let mut measurement = DMatrix::zeros(state_dim, full_dim);
99 for i in 0..state_dim {
100 measurement[(i, i)] = 1.0; }
102
103 Self {
104 state: DVector::zeros(full_dim),
105 covariance: DMatrix::identity(full_dim, full_dim) * 0.1,
106 process_noise: DMatrix::identity(full_dim, full_dim) * 0.001,
107 measurement_noise: DMatrix::identity(state_dim, state_dim) * 0.01,
108 transition,
109 measurement,
110 }
111 }
112
113 pub fn predict(&mut self) -> DVector<f64> {
115 self.state = &self.transition * &self.state;
117
118 self.covariance = &self.transition * &self.covariance * self.transition.transpose()
120 + &self.process_noise;
121
122 &self.measurement * &self.state
124 }
125
126 pub fn update(&mut self, measurement: &DVector<f64>) -> Result<()> {
128 let innovation = measurement - &self.measurement * &self.state;
130
131 let innovation_cov = &self.measurement * &self.covariance
133 * self.measurement.transpose() + &self.measurement_noise;
134
135 let kalman_gain = &self.covariance * self.measurement.transpose()
137 * innovation_cov.try_inverse()
138 .ok_or(TemporalSolverError::NumericalError("Singular matrix".into()))?;
139
140 self.state = &self.state + &kalman_gain * innovation;
142
143 let identity = DMatrix::identity(self.state.len(), self.state.len());
145 self.covariance = (identity - &kalman_gain * &self.measurement) * &self.covariance;
146
147 Ok(())
148 }
149}
150
151pub struct NeuralLayer {
153 weights: Array2<f32>,
154 bias: Array1<f32>,
155 activation: ActivationType,
156}
157
158#[derive(Clone, Copy)]
159pub enum ActivationType {
160 ReLU,
161 Tanh,
162 Linear,
163}
164
165impl NeuralLayer {
166 pub fn new(input_size: usize, output_size: usize, activation: ActivationType) -> Self {
167 use ndarray_rand::RandomExt;
168 use rand_distr::Normal;
169
170 let scale = (2.0 / input_size as f32).sqrt();
172 let dist = Normal::new(0.0, scale).unwrap();
173
174 Self {
175 weights: Array2::random((output_size, input_size), dist),
176 bias: Array1::zeros(output_size),
177 activation,
178 }
179 }
180
181 pub fn forward(&self, input: &Array1<f32>) -> Array1<f32> {
182 let z = self.weights.dot(input) + &self.bias;
183
184 match self.activation {
185 ActivationType::ReLU => z.mapv(|x| x.max(0.0)),
186 ActivationType::Tanh => z.mapv(|x| x.tanh()),
187 ActivationType::Linear => z,
188 }
189 }
190}
191
192pub struct TemporalNeuralNetwork {
194 layers: Vec<NeuralLayer>,
195}
196
197impl TemporalNeuralNetwork {
198 pub fn new(layer_sizes: &[usize], activations: &[ActivationType]) -> Self {
199 assert_eq!(layer_sizes.len() - 1, activations.len());
200
201 let mut layers = Vec::new();
202 for i in 0..layer_sizes.len() - 1 {
203 layers.push(NeuralLayer::new(
204 layer_sizes[i],
205 layer_sizes[i + 1],
206 activations[i],
207 ));
208 }
209
210 Self { layers }
211 }
212
213 pub fn forward(&self, input: &Array1<f32>) -> Array1<f32> {
214 self.layers.iter().fold(input.clone(), |x, layer| layer.forward(&x))
215 }
216
217 pub fn jacobian(&self, input: &Array1<f32>) -> Array2<f32> {
219 let output_dim = self.layers.last().unwrap().weights.shape()[0];
221 let input_dim = input.len();
222 let mut jacobian = Array2::zeros((output_dim, input_dim));
223
224 let epsilon = 1e-4;
225 let base_output = self.forward(input);
226
227 for i in 0..input_dim {
228 let mut perturbed_input = input.clone();
229 perturbed_input[i] += epsilon;
230 let perturbed_output = self.forward(&perturbed_input);
231
232 for j in 0..output_dim {
233 jacobian[[j, i]] = (perturbed_output[j] - base_output[j]) / epsilon;
234 }
235 }
236
237 jacobian
238 }
239}
240
241pub struct SolverGate {
243 epsilon: f64,
244 max_iterations: usize,
245 budget: usize,
246}
247
248impl SolverGate {
249 pub fn new(epsilon: f64, max_iterations: usize, budget: usize) -> Self {
250 Self {
251 epsilon,
252 max_iterations,
253 budget,
254 }
255 }
256
257 pub fn verify(
259 &self,
260 prediction: &Array1<f32>,
261 jacobian: &Array2<f32>,
262 ) -> Result<Certificate> {
263 let n = jacobian.shape()[0];
265 let m = jacobian.shape()[1];
266
267 let mut triplets = Vec::new();
270
271 for i in 0..n.min(m) {
273 triplets.push((i, i, 1.0));
274 }
275
276 for i in 0..n {
278 for j in 0..m {
279 if i < m && j < n {
280 let value = 0.1 * jacobian[[i, j]] * jacobian[[j, i]];
281 if value.abs() > 1e-10 {
282 triplets.push((i, j, value as f64));
283 }
284 }
285 }
286 }
287
288 let matrix = SparseMatrix::from_triplets(triplets, n.min(m), n.min(m));
289
290 let b: Vec<f64> = prediction.iter()
292 .take(n.min(m))
293 .map(|&x| x as f64)
294 .collect();
295
296 let solver = NeumannSolver::new(self.max_iterations, self.epsilon);
298 let result = solver.solve(&matrix, &b);
299
300 let solution_norm: f64 = result.solution.iter().map(|x| x * x).sum::<f64>().sqrt();
302 let residual_norm = result.residual_norm;
303 let error_bound = residual_norm / solution_norm.max(1.0);
304
305 Ok(Certificate {
307 error_bound,
308 confidence: 1.0 - error_bound.min(1.0),
309 gate_pass: error_bound < self.epsilon,
310 iterations: result.iterations,
311 computational_work: result.iterations * n, })
313 }
314}
315
316pub struct PageRankSelector {
318 damping: f64,
319 tolerance: f64,
320 max_iterations: usize,
321}
322
323impl PageRankSelector {
324 pub fn new() -> Self {
325 Self {
326 damping: 0.85,
327 tolerance: 1e-6,
328 max_iterations: 100,
329 }
330 }
331
332 pub fn select_samples(
334 &self,
335 adjacency: &Array2<f32>,
336 errors: &Array1<f32>,
337 k: usize,
338 ) -> Vec<usize> {
339 let n = adjacency.shape()[0];
340 let mut scores = Array1::from_elem(n, 1.0 / n as f32);
341 let mut new_scores = Array1::zeros(n);
342
343 for _ in 0..self.max_iterations {
345 new_scores.fill((1.0 - self.damping as f32) / n as f32);
347
348 for i in 0..n {
349 for j in 0..n {
350 if adjacency[[j, i]] > 0.0 {
351 let out_degree: f32 = (0..n).map(|k| adjacency[[j, k]]).sum();
352 if out_degree > 0.0 {
353 new_scores[i] += (self.damping as f32) * adjacency[[j, i]]
354 * scores[j] / out_degree;
355 }
356 }
357 }
358 }
359
360 for i in 0..n {
362 new_scores[i] *= 1.0 + errors[i];
363 }
364
365 let diff: f32 = (&new_scores - &scores)
367 .iter()
368 .map(|x| x.abs())
369 .sum();
370
371 scores.assign(&new_scores);
372
373 if diff < self.tolerance as f32 {
374 break;
375 }
376 }
377
378 let mut indexed_scores: Vec<(usize, f32)> =
380 scores.iter().enumerate().map(|(i, &s)| (i, s)).collect();
381 indexed_scores.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
382
383 indexed_scores.into_iter().take(k).map(|(i, _)| i).collect()
384 }
385}
386
387pub struct TemporalSolver {
389 neural_net: TemporalNeuralNetwork,
390 kalman_filter: KalmanFilter,
391 solver_gate: SolverGate,
392 pagerank: PageRankSelector,
393}
394
395impl TemporalSolver {
396 pub fn new(input_size: usize, hidden_size: usize, output_size: usize) -> Self {
397 let neural_net = TemporalNeuralNetwork::new(
398 &[input_size, hidden_size, output_size],
399 &[ActivationType::ReLU, ActivationType::Linear],
400 );
401
402 let kalman_filter = KalmanFilter::new(output_size);
403 let solver_gate = SolverGate::new(0.02, 100, 200000);
404 let pagerank = PageRankSelector::new();
405
406 Self {
407 neural_net,
408 kalman_filter,
409 solver_gate,
410 pagerank,
411 }
412 }
413
414 pub fn predict(&mut self, input: &Array1<f32>) -> Result<(Array1<f32>, Certificate, Duration)> {
416 let start = Instant::now();
417
418 let kalman_pred = self.kalman_filter.predict();
420 let prior: Array1<f32> = Array1::from_vec(
421 kalman_pred.iter().map(|&x| x as f32).collect()
422 );
423
424 let residual = self.neural_net.forward(input);
426
427 let prediction = &prior + &residual;
429
430 let jacobian = self.neural_net.jacobian(input);
432
433 let certificate = self.solver_gate.verify(&prediction, &jacobian)?;
435
436 if certificate.gate_pass {
438 let measurement = DVector::from_vec(
439 prediction.iter().map(|&x| x as f64).collect()
440 );
441 self.kalman_filter.update(&measurement)?;
442 }
443
444 let duration = start.elapsed();
445
446 Ok((prediction, certificate, duration))
447 }
448
449 pub fn train_step(
451 &mut self,
452 samples: &[Array1<f32>],
453 targets: &[Array1<f32>],
454 adjacency: &Array2<f32>,
455 ) -> Result<Vec<usize>> {
456 let mut errors = Array1::zeros(samples.len());
458 for (i, (sample, target)) in samples.iter().zip(targets.iter()).enumerate() {
459 let (pred, _, _) = self.predict(sample)?;
460 let error: f32 = (pred - target).mapv(|x| x * x).sum().sqrt();
461 errors[i] = error;
462 }
463
464 let selected_indices = self.pagerank.select_samples(adjacency, &errors, 15);
466
467 Ok(selected_indices)
468 }
469}
470
471#[cfg(test)]
472mod tests {
473 use super::*;
474
475 #[test]
476 fn test_real_kalman_filter() {
477 let mut kf = KalmanFilter::new(2);
478 let pred = kf.predict();
479 assert_eq!(pred.len(), 2);
480 }
481
482 #[test]
483 fn test_real_neural_network() {
484 let nn = TemporalNeuralNetwork::new(&[10, 5, 2], &[ActivationType::ReLU, ActivationType::Linear]);
485 let input = Array1::from_vec(vec![0.1; 10]);
486 let output = nn.forward(&input);
487 assert_eq!(output.len(), 2);
488 }
489
490 #[test]
491 fn test_real_solver_gate() {
492 let gate = SolverGate::new(0.02, 100, 10000);
493 let prediction = Array1::from_vec(vec![1.0, 2.0, 3.0]);
494 let jacobian = Array2::from_shape_vec((3, 3), vec![
495 2.0, -1.0, 0.0,
496 -1.0, 2.0, -1.0,
497 0.0, -1.0, 2.0,
498 ]).unwrap();
499
500 let cert = gate.verify(&prediction, &jacobian).unwrap();
501 println!("Certificate: {:?}", cert);
502 assert!(cert.error_bound >= 0.0);
503 }
504
505 #[test]
506 fn test_complete_system() {
507 let mut solver = TemporalSolver::new(128, 32, 4);
508 let input = Array1::from_vec(vec![0.1; 128]);
509
510 let (prediction, certificate, duration) = solver.predict(&input).unwrap();
511
512 println!("Prediction: {:?}", prediction);
513 println!("Certificate: {:?}", certificate);
514 println!("Duration: {:?}", duration);
515
516 assert_eq!(prediction.len(), 4);
517 assert!(duration.as_nanos() > 0);
518 }
519}