1use scirs2_core::ndarray::{s, Array1, Array2, Axis};
6use scirs2_core::random::thread_rng;
7use scirs2_core::Complex64;
8use std::collections::VecDeque;
9use std::f64::consts::PI;
10use std::sync::{Arc, Mutex};
11
12use crate::circuit_interfaces::{InterfaceCircuit, InterfaceGate, InterfaceGateType};
13use crate::error::Result;
14use crate::scirs2_integration::SciRS2Backend;
15use crate::statevector::StateVectorSimulator;
16
17use super::analysis::MemoryAnalyzer;
18use super::config::QuantumReservoirConfig;
19use super::state::{
20 QuantumReservoirState, ReservoirMetrics, ReservoirTrainingData, TrainingExample, TrainingResult,
21};
22use super::time_series::TimeSeriesPredictor;
23use super::types::{
24 IPCFunction, InputEncoding, LearningAlgorithm, OutputMeasurement, QuantumReservoirArchitecture,
25 ReservoirDynamics,
26};
27
28pub struct QuantumReservoirComputerEnhanced {
30 pub(crate) config: QuantumReservoirConfig,
32 pub(crate) reservoir_state: QuantumReservoirState,
34 reservoir_circuit: InterfaceCircuit,
36 #[allow(dead_code)]
38 input_coupling_circuit: InterfaceCircuit,
39 output_weights: Array2<f64>,
41 #[allow(dead_code)]
43 time_series_predictor: Option<TimeSeriesPredictor>,
44 memory_analyzer: MemoryAnalyzer,
46 simulator: StateVectorSimulator,
48 metrics: ReservoirMetrics,
50 #[allow(dead_code)]
52 training_history: VecDeque<TrainingExample>,
53 #[allow(dead_code)]
55 backend: Option<SciRS2Backend>,
56 #[allow(dead_code)]
58 rng: Arc<Mutex<scirs2_core::random::CoreRandom>>,
59}
60
61impl QuantumReservoirComputerEnhanced {
62 pub fn new(config: QuantumReservoirConfig) -> Result<Self> {
64 let simulator = StateVectorSimulator::new();
65
66 let reservoir_state = QuantumReservoirState::new(config.num_qubits, config.memory_capacity);
67
68 let reservoir_circuit = Self::generate_reservoir_circuit(&config)?;
70
71 let input_coupling_circuit = Self::generate_input_coupling_circuit(&config)?;
73
74 let output_size = Self::calculate_output_size(&config);
76 let feature_size = Self::calculate_feature_size(&config);
77 let mut output_weights = Array2::zeros((output_size, feature_size));
78
79 let scale = (2.0 / (output_size + feature_size) as f64).sqrt();
81 for elem in &mut output_weights {
82 *elem = (fastrand::f64() - 0.5) * 2.0 * scale;
83 }
84
85 let time_series_predictor =
87 if config.time_series_config.enable_arima || config.time_series_config.enable_nar {
88 Some(TimeSeriesPredictor::new(&config.time_series_config))
89 } else {
90 None
91 };
92
93 let memory_analyzer = MemoryAnalyzer::new(config.memory_config.clone());
95
96 Ok(Self {
97 config,
98 reservoir_state,
99 reservoir_circuit,
100 input_coupling_circuit,
101 output_weights,
102 time_series_predictor,
103 memory_analyzer,
104 simulator,
105 metrics: ReservoirMetrics::default(),
106 training_history: VecDeque::with_capacity(10_000),
107 backend: None,
108 rng: Arc::new(Mutex::new(thread_rng())),
109 })
110 }
111
112 fn generate_reservoir_circuit(config: &QuantumReservoirConfig) -> Result<InterfaceCircuit> {
114 let mut circuit = InterfaceCircuit::new(config.num_qubits, 0);
115
116 match config.architecture {
117 QuantumReservoirArchitecture::RandomCircuit => {
118 Self::generate_random_circuit(&mut circuit, config)?;
119 }
120 QuantumReservoirArchitecture::SpinChain => {
121 Self::generate_spin_chain_circuit(&mut circuit, config)?;
122 }
123 QuantumReservoirArchitecture::TransverseFieldIsing => {
124 Self::generate_tfim_circuit(&mut circuit, config)?;
125 }
126 QuantumReservoirArchitecture::SmallWorld => {
127 Self::generate_small_world_circuit(&mut circuit, config)?;
128 }
129 QuantumReservoirArchitecture::FullyConnected => {
130 Self::generate_fully_connected_circuit(&mut circuit, config)?;
131 }
132 QuantumReservoirArchitecture::ScaleFree => {
133 Self::generate_scale_free_circuit(&mut circuit, config)?;
134 }
135 QuantumReservoirArchitecture::HierarchicalModular => {
136 Self::generate_hierarchical_circuit(&mut circuit, config)?;
137 }
138 QuantumReservoirArchitecture::Ring => {
139 Self::generate_ring_circuit(&mut circuit, config)?;
140 }
141 QuantumReservoirArchitecture::Grid => {
142 Self::generate_grid_circuit(&mut circuit, config)?;
143 }
144 _ => {
145 Self::generate_random_circuit(&mut circuit, config)?;
147 }
148 }
149
150 Ok(circuit)
151 }
152
153 fn generate_random_circuit(
155 circuit: &mut InterfaceCircuit,
156 config: &QuantumReservoirConfig,
157 ) -> Result<()> {
158 let depth = config.evolution_steps;
159
160 for _ in 0..depth {
161 for qubit in 0..config.num_qubits {
163 let angle = fastrand::f64() * 2.0 * PI;
164 let gate_type = match fastrand::usize(0..3) {
165 0 => InterfaceGateType::RX(angle),
166 1 => InterfaceGateType::RY(angle),
167 _ => InterfaceGateType::RZ(angle),
168 };
169 circuit.add_gate(InterfaceGate::new(gate_type, vec![qubit]));
170 }
171
172 for _ in 0..(config.num_qubits / 2) {
174 let qubit1 = fastrand::usize(0..config.num_qubits);
175 let qubit2 = fastrand::usize(0..config.num_qubits);
176 if qubit1 != qubit2 {
177 circuit.add_gate(InterfaceGate::new(
178 InterfaceGateType::CNOT,
179 vec![qubit1, qubit2],
180 ));
181 }
182 }
183 }
184
185 Ok(())
186 }
187
188 fn generate_spin_chain_circuit(
190 circuit: &mut InterfaceCircuit,
191 config: &QuantumReservoirConfig,
192 ) -> Result<()> {
193 let coupling = config.coupling_strength;
194
195 for _ in 0..config.evolution_steps {
196 for i in 0..config.num_qubits - 1 {
198 circuit.add_gate(InterfaceGate::new(
200 InterfaceGateType::RZ(coupling * config.time_step),
201 vec![i],
202 ));
203 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![i, i + 1]));
204 circuit.add_gate(InterfaceGate::new(
205 InterfaceGateType::RZ(coupling * config.time_step),
206 vec![i + 1],
207 ));
208 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![i, i + 1]));
209 }
210 }
211
212 Ok(())
213 }
214
215 fn generate_tfim_circuit(
217 circuit: &mut InterfaceCircuit,
218 config: &QuantumReservoirConfig,
219 ) -> Result<()> {
220 let coupling = config.coupling_strength;
221 let field = coupling * 0.5; for _ in 0..config.evolution_steps {
224 for qubit in 0..config.num_qubits {
226 circuit.add_gate(InterfaceGate::new(
227 InterfaceGateType::RX(field * config.time_step),
228 vec![qubit],
229 ));
230 }
231
232 for i in 0..config.num_qubits - 1 {
234 circuit.add_gate(InterfaceGate::new(
235 InterfaceGateType::RZ(coupling * config.time_step / 2.0),
236 vec![i],
237 ));
238 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![i, i + 1]));
239 circuit.add_gate(InterfaceGate::new(
240 InterfaceGateType::RZ(coupling * config.time_step),
241 vec![i + 1],
242 ));
243 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![i, i + 1]));
244 circuit.add_gate(InterfaceGate::new(
245 InterfaceGateType::RZ(coupling * config.time_step / 2.0),
246 vec![i],
247 ));
248 }
249 }
250
251 Ok(())
252 }
253
254 fn generate_small_world_circuit(
256 circuit: &mut InterfaceCircuit,
257 config: &QuantumReservoirConfig,
258 ) -> Result<()> {
259 let coupling = config.coupling_strength;
260 let rewiring_prob = 0.1; for _ in 0..config.evolution_steps {
263 for i in 0..config.num_qubits {
265 let next = (i + 1) % config.num_qubits;
266
267 let target = if fastrand::f64() < rewiring_prob {
269 fastrand::usize(0..config.num_qubits)
270 } else {
271 next
272 };
273
274 if target != i {
275 circuit.add_gate(InterfaceGate::new(
276 InterfaceGateType::RZ(coupling * config.time_step / 2.0),
277 vec![i],
278 ));
279 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![i, target]));
280 circuit.add_gate(InterfaceGate::new(
281 InterfaceGateType::RZ(coupling * config.time_step),
282 vec![target],
283 ));
284 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![i, target]));
285 circuit.add_gate(InterfaceGate::new(
286 InterfaceGateType::RZ(coupling * config.time_step / 2.0),
287 vec![i],
288 ));
289 }
290 }
291 }
292
293 Ok(())
294 }
295
296 fn generate_fully_connected_circuit(
298 circuit: &mut InterfaceCircuit,
299 config: &QuantumReservoirConfig,
300 ) -> Result<()> {
301 let coupling = config.coupling_strength / config.num_qubits as f64; for _ in 0..config.evolution_steps {
304 for i in 0..config.num_qubits {
306 for j in i + 1..config.num_qubits {
307 circuit.add_gate(InterfaceGate::new(
308 InterfaceGateType::RZ(coupling * config.time_step / 2.0),
309 vec![i],
310 ));
311 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![i, j]));
312 circuit.add_gate(InterfaceGate::new(
313 InterfaceGateType::RZ(coupling * config.time_step),
314 vec![j],
315 ));
316 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![i, j]));
317 circuit.add_gate(InterfaceGate::new(
318 InterfaceGateType::RZ(coupling * config.time_step / 2.0),
319 vec![i],
320 ));
321 }
322 }
323 }
324
325 Ok(())
326 }
327
328 fn generate_scale_free_circuit(
330 circuit: &mut InterfaceCircuit,
331 config: &QuantumReservoirConfig,
332 ) -> Result<()> {
333 let mut degree_dist = vec![1; config.num_qubits];
335 let coupling = config.coupling_strength;
336
337 for _ in 0..config.evolution_steps {
338 for i in 0..config.num_qubits {
340 let total_degree: usize = degree_dist.iter().sum();
342 let prob_threshold = degree_dist[i] as f64 / total_degree as f64;
343
344 if fastrand::f64() < prob_threshold {
345 let j = fastrand::usize(0..config.num_qubits);
346 if i != j {
347 circuit.add_gate(InterfaceGate::new(
349 InterfaceGateType::RZ(coupling * config.time_step / 2.0),
350 vec![i],
351 ));
352 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![i, j]));
353 circuit.add_gate(InterfaceGate::new(
354 InterfaceGateType::RZ(coupling * config.time_step),
355 vec![j],
356 ));
357 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![i, j]));
358
359 degree_dist[i] += 1;
361 degree_dist[j] += 1;
362 }
363 }
364 }
365 }
366
367 Ok(())
368 }
369
370 fn generate_hierarchical_circuit(
372 circuit: &mut InterfaceCircuit,
373 config: &QuantumReservoirConfig,
374 ) -> Result<()> {
375 let coupling = config.coupling_strength;
376 let module_size = (config.num_qubits as f64).sqrt() as usize;
377
378 for _ in 0..config.evolution_steps {
379 for module in 0..(config.num_qubits / module_size) {
381 let start = module * module_size;
382 let end = ((module + 1) * module_size).min(config.num_qubits);
383
384 for i in start..end {
385 for j in (i + 1)..end {
386 circuit.add_gate(InterfaceGate::new(
387 InterfaceGateType::RZ(coupling * config.time_step),
388 vec![i],
389 ));
390 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![i, j]));
391 }
392 }
393 }
394
395 for i in 0..config.num_qubits {
397 let j = fastrand::usize(0..config.num_qubits);
398 if i / module_size != j / module_size && i != j {
399 circuit.add_gate(InterfaceGate::new(
400 InterfaceGateType::RZ(coupling * config.time_step * 0.3),
401 vec![i],
402 ));
403 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![i, j]));
404 }
405 }
406 }
407
408 Ok(())
409 }
410
411 fn generate_ring_circuit(
413 circuit: &mut InterfaceCircuit,
414 config: &QuantumReservoirConfig,
415 ) -> Result<()> {
416 let coupling = config.coupling_strength;
417
418 for _ in 0..config.evolution_steps {
419 for i in 0..config.num_qubits {
421 let j = (i + 1) % config.num_qubits;
422
423 circuit.add_gate(InterfaceGate::new(
424 InterfaceGateType::RZ(coupling * config.time_step / 2.0),
425 vec![i],
426 ));
427 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![i, j]));
428 circuit.add_gate(InterfaceGate::new(
429 InterfaceGateType::RZ(coupling * config.time_step),
430 vec![j],
431 ));
432 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![i, j]));
433 }
434
435 if fastrand::f64() < 0.1 {
437 let i = fastrand::usize(0..config.num_qubits);
438 let j = fastrand::usize(0..config.num_qubits);
439 if i != j && (i as i32 - j as i32).abs() > 2 {
440 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![i, j]));
441 }
442 }
443 }
444
445 Ok(())
446 }
447
448 fn generate_grid_circuit(
450 circuit: &mut InterfaceCircuit,
451 config: &QuantumReservoirConfig,
452 ) -> Result<()> {
453 let coupling = config.coupling_strength;
454 let grid_size = (config.num_qubits as f64).sqrt() as usize;
455
456 for _ in 0..config.evolution_steps {
457 for i in 0..grid_size {
459 for j in 0..grid_size {
460 let current = i * grid_size + j;
461 if current >= config.num_qubits {
462 break;
463 }
464
465 if j + 1 < grid_size {
467 let neighbor = i * grid_size + j + 1;
468 if neighbor < config.num_qubits {
469 circuit.add_gate(InterfaceGate::new(
470 InterfaceGateType::RZ(coupling * config.time_step / 2.0),
471 vec![current],
472 ));
473 circuit.add_gate(InterfaceGate::new(
474 InterfaceGateType::CNOT,
475 vec![current, neighbor],
476 ));
477 }
478 }
479
480 if i + 1 < grid_size {
482 let neighbor = (i + 1) * grid_size + j;
483 if neighbor < config.num_qubits {
484 circuit.add_gate(InterfaceGate::new(
485 InterfaceGateType::RZ(coupling * config.time_step / 2.0),
486 vec![current],
487 ));
488 circuit.add_gate(InterfaceGate::new(
489 InterfaceGateType::CNOT,
490 vec![current, neighbor],
491 ));
492 }
493 }
494 }
495 }
496 }
497
498 Ok(())
499 }
500
501 fn generate_input_coupling_circuit(
503 config: &QuantumReservoirConfig,
504 ) -> Result<InterfaceCircuit> {
505 let mut circuit = InterfaceCircuit::new(config.num_qubits, 0);
506
507 match config.input_encoding {
508 InputEncoding::Amplitude => {
509 for qubit in 0..config.num_qubits {
511 circuit.add_gate(InterfaceGate::new(
512 InterfaceGateType::RY(0.0), vec![qubit],
514 ));
515 }
516 }
517 InputEncoding::Phase => {
518 for qubit in 0..config.num_qubits {
520 circuit.add_gate(InterfaceGate::new(
521 InterfaceGateType::RZ(0.0), vec![qubit],
523 ));
524 }
525 }
526 InputEncoding::BasisState => {
527 for qubit in 0..config.num_qubits {
529 circuit.add_gate(InterfaceGate::new(InterfaceGateType::X, vec![qubit]));
530 }
531 }
532 InputEncoding::Angle => {
533 for qubit in 0..config.num_qubits {
535 circuit.add_gate(InterfaceGate::new(InterfaceGateType::RX(0.0), vec![qubit]));
536 circuit.add_gate(InterfaceGate::new(InterfaceGateType::RY(0.0), vec![qubit]));
537 }
538 }
539 _ => {
540 for qubit in 0..config.num_qubits {
542 circuit.add_gate(InterfaceGate::new(InterfaceGateType::RY(0.0), vec![qubit]));
543 }
544 }
545 }
546
547 Ok(circuit)
548 }
549
550 pub const fn calculate_output_size(_config: &QuantumReservoirConfig) -> usize {
552 1
554 }
555
556 pub fn calculate_feature_size(config: &QuantumReservoirConfig) -> usize {
558 match config.output_measurement {
559 OutputMeasurement::PauliExpectation => config.num_qubits * 3,
560 OutputMeasurement::Probability => 1 << config.num_qubits.min(10), OutputMeasurement::Correlations => config.num_qubits * config.num_qubits,
562 OutputMeasurement::Entanglement => config.num_qubits,
563 OutputMeasurement::Fidelity => 1,
564 OutputMeasurement::QuantumFisherInformation => config.num_qubits,
565 OutputMeasurement::Variance => config.num_qubits * 3,
566 OutputMeasurement::HigherOrderMoments => config.num_qubits * 6, OutputMeasurement::SpectralProperties => config.num_qubits,
568 OutputMeasurement::QuantumCoherence => config.num_qubits,
569 OutputMeasurement::Purity => 1,
570 OutputMeasurement::QuantumMutualInformation => config.num_qubits * config.num_qubits,
571 OutputMeasurement::ProcessTomography => config.num_qubits * config.num_qubits * 4,
572 OutputMeasurement::TemporalCorrelations => config.memory_capacity,
573 OutputMeasurement::NonLinearReadout => config.num_qubits * 2,
574 }
575 }
576
577 pub fn process_input(&mut self, input: &Array1<f64>) -> Result<Array1<f64>> {
579 let start_time = std::time::Instant::now();
580
581 self.encode_input(input)?;
583
584 self.evolve_reservoir()?;
586
587 let features = self.extract_features()?;
589
590 let timestamp = start_time.elapsed().as_secs_f64();
592 self.reservoir_state
593 .update_state(self.reservoir_state.state_vector.clone(), timestamp);
594
595 let processing_time = start_time.elapsed().as_secs_f64() * 1000.0;
597 self.update_processing_time(processing_time);
598
599 Ok(features)
600 }
601
602 pub fn encode_input(&mut self, input: &Array1<f64>) -> Result<()> {
604 match self.config.input_encoding {
605 InputEncoding::Amplitude => {
606 self.encode_amplitude(input)?;
607 }
608 InputEncoding::Phase => {
609 self.encode_phase(input)?;
610 }
611 InputEncoding::BasisState => {
612 self.encode_basis_state(input)?;
613 }
614 InputEncoding::Angle => {
615 self.encode_angle(input)?;
616 }
617 _ => {
618 self.encode_amplitude(input)?;
619 }
620 }
621 Ok(())
622 }
623
624 fn encode_amplitude(&mut self, input: &Array1<f64>) -> Result<()> {
626 let num_inputs = input.len().min(self.config.num_qubits);
627
628 for i in 0..num_inputs {
629 let angle = input[i] * PI; self.apply_single_qubit_rotation(i, InterfaceGateType::RY(angle))?;
631 }
632
633 Ok(())
634 }
635
636 fn encode_phase(&mut self, input: &Array1<f64>) -> Result<()> {
638 let num_inputs = input.len().min(self.config.num_qubits);
639
640 for i in 0..num_inputs {
641 let angle = input[i] * 2.0 * PI; self.apply_single_qubit_rotation(i, InterfaceGateType::RZ(angle))?;
643 }
644
645 Ok(())
646 }
647
648 fn encode_basis_state(&mut self, input: &Array1<f64>) -> Result<()> {
650 let num_inputs = input.len().min(self.config.num_qubits);
651
652 for i in 0..num_inputs {
653 if input[i] > 0.5 {
654 self.apply_single_qubit_gate(i, InterfaceGateType::X)?;
655 }
656 }
657
658 Ok(())
659 }
660
661 fn encode_angle(&mut self, input: &Array1<f64>) -> Result<()> {
663 let num_inputs = input.len().min(self.config.num_qubits);
664
665 for i in 0..num_inputs {
666 let angle_x = input[i] * PI;
667 let angle_y = if i + 1 < input.len() {
668 input[i + 1] * PI
669 } else {
670 0.0
671 };
672
673 self.apply_single_qubit_rotation(i, InterfaceGateType::RX(angle_x))?;
674 self.apply_single_qubit_rotation(i, InterfaceGateType::RY(angle_y))?;
675 }
676
677 Ok(())
678 }
679
680 fn apply_single_qubit_rotation(
682 &mut self,
683 qubit: usize,
684 gate_type: InterfaceGateType,
685 ) -> Result<()> {
686 let mut temp_circuit = InterfaceCircuit::new(self.config.num_qubits, 0);
687 temp_circuit.add_gate(InterfaceGate::new(gate_type, vec![qubit]));
688
689 self.simulator.apply_interface_circuit(&temp_circuit)?;
690
691 Ok(())
692 }
693
694 fn apply_single_qubit_gate(
696 &mut self,
697 qubit: usize,
698 gate_type: InterfaceGateType,
699 ) -> Result<()> {
700 let mut temp_circuit = InterfaceCircuit::new(self.config.num_qubits, 0);
701 temp_circuit.add_gate(InterfaceGate::new(gate_type, vec![qubit]));
702
703 self.simulator.apply_interface_circuit(&temp_circuit)?;
704
705 Ok(())
706 }
707
708 pub fn evolve_reservoir(&mut self) -> Result<()> {
710 match self.config.dynamics {
711 ReservoirDynamics::Unitary => {
712 self.evolve_unitary()?;
713 }
714 ReservoirDynamics::Open => {
715 self.evolve_open_system()?;
716 }
717 ReservoirDynamics::NISQ => {
718 self.evolve_nisq()?;
719 }
720 ReservoirDynamics::Adiabatic => {
721 self.evolve_adiabatic()?;
722 }
723 ReservoirDynamics::Floquet => {
724 self.evolve_floquet()?;
725 }
726 _ => {
727 self.evolve_unitary()?;
729 }
730 }
731 Ok(())
732 }
733
734 fn evolve_unitary(&mut self) -> Result<()> {
736 self.simulator
737 .apply_interface_circuit(&self.reservoir_circuit)?;
738 Ok(())
739 }
740
741 fn evolve_open_system(&mut self) -> Result<()> {
743 self.evolve_unitary()?;
745
746 self.apply_decoherence()?;
748
749 Ok(())
750 }
751
752 fn evolve_nisq(&mut self) -> Result<()> {
754 self.evolve_unitary()?;
756
757 self.apply_gate_errors()?;
759
760 self.apply_measurement_errors()?;
762
763 Ok(())
764 }
765
766 fn evolve_adiabatic(&mut self) -> Result<()> {
768 self.evolve_unitary()?;
771 Ok(())
772 }
773
774 fn evolve_floquet(&mut self) -> Result<()> {
776 let drive_frequency = 1.0;
778 let time = self.reservoir_state.time_index as f64 * self.config.time_step;
779 let drive_strength = (drive_frequency * time).sin();
780
781 for qubit in 0..self.config.num_qubits {
783 let angle = drive_strength * self.config.time_step;
784 self.apply_single_qubit_rotation(qubit, InterfaceGateType::RX(angle))?;
785 }
786
787 self.evolve_unitary()?;
789
790 Ok(())
791 }
792
793 fn apply_decoherence(&mut self) -> Result<()> {
795 let decoherence_rate = self.config.noise_level;
796
797 for amplitude in &mut self.reservoir_state.state_vector {
798 let phase_noise = (fastrand::f64() - 0.5) * decoherence_rate * 2.0 * PI;
800 *amplitude *= Complex64::new(0.0, phase_noise).exp();
801
802 let damping = (1.0 - decoherence_rate).sqrt();
804 *amplitude *= damping;
805 }
806
807 let norm: f64 = self
809 .reservoir_state
810 .state_vector
811 .iter()
812 .map(scirs2_core::Complex::norm_sqr)
813 .sum::<f64>()
814 .sqrt();
815
816 if norm > 1e-15 {
817 self.reservoir_state.state_vector.mapv_inplace(|x| x / norm);
818 }
819
820 Ok(())
821 }
822
823 fn apply_gate_errors(&mut self) -> Result<()> {
825 let error_rate = self.config.noise_level;
826
827 for qubit in 0..self.config.num_qubits {
828 if fastrand::f64() < error_rate {
829 let error_type = fastrand::usize(0..3);
830 let gate_type = match error_type {
831 0 => InterfaceGateType::X,
832 1 => InterfaceGateType::PauliY,
833 _ => InterfaceGateType::PauliZ,
834 };
835 self.apply_single_qubit_gate(qubit, gate_type)?;
836 }
837 }
838
839 Ok(())
840 }
841
842 fn apply_measurement_errors(&mut self) -> Result<()> {
844 let error_rate = self.config.noise_level * 0.1; if fastrand::f64() < error_rate {
847 let qubit = fastrand::usize(0..self.config.num_qubits);
848 self.apply_single_qubit_gate(qubit, InterfaceGateType::X)?;
849 }
850
851 Ok(())
852 }
853
854 fn extract_features(&mut self) -> Result<Array1<f64>> {
856 match self.config.output_measurement {
857 OutputMeasurement::PauliExpectation => self.measure_pauli_expectations(),
858 OutputMeasurement::Probability => self.measure_probabilities(),
859 OutputMeasurement::Correlations => self.measure_correlations(),
860 OutputMeasurement::Entanglement => self.measure_entanglement(),
861 OutputMeasurement::Fidelity => self.measure_fidelity(),
862 OutputMeasurement::QuantumFisherInformation => {
863 self.measure_quantum_fisher_information()
864 }
865 OutputMeasurement::Variance => self.measure_variance(),
866 OutputMeasurement::HigherOrderMoments => self.measure_higher_order_moments(),
867 OutputMeasurement::QuantumCoherence => self.measure_quantum_coherence(),
868 OutputMeasurement::Purity => self.measure_purity(),
869 OutputMeasurement::TemporalCorrelations => self.measure_temporal_correlations(),
870 _ => {
871 self.measure_pauli_expectations()
873 }
874 }
875 }
876
877 fn measure_pauli_expectations(&self) -> Result<Array1<f64>> {
879 let mut expectations = Vec::new();
880
881 for qubit in 0..self.config.num_qubits {
882 let x_exp = self.calculate_single_qubit_expectation(
884 qubit,
885 &[
886 Complex64::new(0.0, 0.0),
887 Complex64::new(1.0, 0.0),
888 Complex64::new(1.0, 0.0),
889 Complex64::new(0.0, 0.0),
890 ],
891 )?;
892 expectations.push(x_exp);
893
894 let y_exp = self.calculate_single_qubit_expectation(
896 qubit,
897 &[
898 Complex64::new(0.0, 0.0),
899 Complex64::new(0.0, -1.0),
900 Complex64::new(0.0, 1.0),
901 Complex64::new(0.0, 0.0),
902 ],
903 )?;
904 expectations.push(y_exp);
905
906 let z_exp = self.calculate_single_qubit_expectation(
908 qubit,
909 &[
910 Complex64::new(1.0, 0.0),
911 Complex64::new(0.0, 0.0),
912 Complex64::new(0.0, 0.0),
913 Complex64::new(-1.0, 0.0),
914 ],
915 )?;
916 expectations.push(z_exp);
917 }
918
919 Ok(Array1::from_vec(expectations))
920 }
921
922 fn calculate_single_qubit_expectation(
924 &self,
925 qubit: usize,
926 pauli_matrix: &[Complex64; 4],
927 ) -> Result<f64> {
928 let state = &self.reservoir_state.state_vector;
929 let mut expectation = 0.0;
930
931 for i in 0..state.len() {
932 for j in 0..state.len() {
933 let i_bit = (i >> qubit) & 1;
934 let j_bit = (j >> qubit) & 1;
935 let matrix_element = pauli_matrix[i_bit * 2 + j_bit];
936
937 expectation += (state[i].conj() * matrix_element * state[j]).re;
938 }
939 }
940
941 Ok(expectation)
942 }
943
944 fn measure_probabilities(&self) -> Result<Array1<f64>> {
946 let probabilities: Vec<f64> = self
947 .reservoir_state
948 .state_vector
949 .iter()
950 .map(scirs2_core::Complex::norm_sqr)
951 .collect();
952
953 let max_size = 1 << 10; if probabilities.len() > max_size {
956 let mut sampled = Vec::with_capacity(max_size);
958 for _ in 0..max_size {
959 let idx = fastrand::usize(0..probabilities.len());
960 sampled.push(probabilities[idx]);
961 }
962 Ok(Array1::from_vec(sampled))
963 } else {
964 Ok(Array1::from_vec(probabilities))
965 }
966 }
967
968 fn measure_correlations(&mut self) -> Result<Array1<f64>> {
970 let mut correlations = Vec::new();
971
972 for i in 0..self.config.num_qubits {
973 for j in 0..self.config.num_qubits {
974 if i == j {
975 correlations.push(1.0); self.reservoir_state.correlations[[i, j]] = 1.0;
977 } else {
978 let corr = self.calculate_two_qubit_correlation(i, j)?;
980 correlations.push(corr);
981 self.reservoir_state.correlations[[i, j]] = corr;
982 }
983 }
984 }
985
986 Ok(Array1::from_vec(correlations))
987 }
988
989 fn calculate_two_qubit_correlation(&self, qubit1: usize, qubit2: usize) -> Result<f64> {
991 let state = &self.reservoir_state.state_vector;
992 let mut correlation = 0.0;
993
994 for i in 0..state.len() {
995 let bit1 = (i >> qubit1) & 1;
996 let bit2 = (i >> qubit2) & 1;
997 let sign = if bit1 == bit2 { 1.0 } else { -1.0 };
998 correlation += sign * state[i].norm_sqr();
999 }
1000
1001 Ok(correlation)
1002 }
1003
1004 fn measure_entanglement(&self) -> Result<Array1<f64>> {
1006 let mut entanglement_measures = Vec::new();
1007
1008 for qubit in 0..self.config.num_qubits {
1010 let entropy = self.calculate_von_neumann_entropy(qubit)?;
1012 entanglement_measures.push(entropy);
1013 }
1014
1015 Ok(Array1::from_vec(entanglement_measures))
1016 }
1017
1018 fn calculate_von_neumann_entropy(&self, _qubit: usize) -> Result<f64> {
1020 let state = &self.reservoir_state.state_vector;
1021 let mut entropy = 0.0;
1022
1023 for amplitude in state {
1024 let prob = amplitude.norm_sqr();
1025 if prob > 1e-15 {
1026 entropy -= prob * prob.ln();
1027 }
1028 }
1029
1030 Ok(entropy / (state.len() as f64).ln()) }
1032
1033 fn measure_fidelity(&self) -> Result<Array1<f64>> {
1035 let fidelity = self.reservoir_state.state_vector[0].norm_sqr();
1037 Ok(Array1::from_vec(vec![fidelity]))
1038 }
1039
1040 fn measure_quantum_fisher_information(&self) -> Result<Array1<f64>> {
1042 let mut qfi_values = Vec::new();
1043
1044 for qubit in 0..self.config.num_qubits {
1045 let z_exp = self.calculate_single_qubit_expectation(
1047 qubit,
1048 &[
1049 Complex64::new(1.0, 0.0),
1050 Complex64::new(0.0, 0.0),
1051 Complex64::new(0.0, 0.0),
1052 Complex64::new(-1.0, 0.0),
1053 ],
1054 )?;
1055
1056 let qfi = 4.0 * (1.0 - z_exp * z_exp);
1058 qfi_values.push(qfi);
1059 }
1060
1061 Ok(Array1::from_vec(qfi_values))
1062 }
1063
1064 fn measure_variance(&self) -> Result<Array1<f64>> {
1066 let mut variances = Vec::new();
1067
1068 for qubit in 0..self.config.num_qubits {
1069 for pauli_idx in 0..3 {
1071 let pauli_matrix = match pauli_idx {
1072 0 => [
1073 Complex64::new(0.0, 0.0),
1074 Complex64::new(1.0, 0.0),
1075 Complex64::new(1.0, 0.0),
1076 Complex64::new(0.0, 0.0),
1077 ],
1078 1 => [
1079 Complex64::new(0.0, 0.0),
1080 Complex64::new(0.0, -1.0),
1081 Complex64::new(0.0, 1.0),
1082 Complex64::new(0.0, 0.0),
1083 ],
1084 _ => [
1085 Complex64::new(1.0, 0.0),
1086 Complex64::new(0.0, 0.0),
1087 Complex64::new(0.0, 0.0),
1088 Complex64::new(-1.0, 0.0),
1089 ],
1090 };
1091
1092 let expectation = self.calculate_single_qubit_expectation(qubit, &pauli_matrix)?;
1093 let variance = 1.0 - expectation * expectation; variances.push(variance);
1095 }
1096 }
1097
1098 Ok(Array1::from_vec(variances))
1099 }
1100
1101 fn measure_higher_order_moments(&self) -> Result<Array1<f64>> {
1103 let mut moments = Vec::new();
1104
1105 for qubit in 0..self.config.num_qubits {
1106 let z_exp = self.calculate_single_qubit_expectation(
1108 qubit,
1109 &[
1110 Complex64::new(1.0, 0.0),
1111 Complex64::new(0.0, 0.0),
1112 Complex64::new(0.0, 0.0),
1113 Complex64::new(-1.0, 0.0),
1114 ],
1115 )?;
1116
1117 moments.push(z_exp);
1119
1120 let variance = 1.0 - z_exp * z_exp;
1122 moments.push(variance);
1123
1124 moments.push(0.0);
1127
1128 moments.push(variance * variance);
1130
1131 moments.push(z_exp * variance);
1133
1134 moments.push(variance * variance * variance);
1136 }
1137
1138 Ok(Array1::from_vec(moments))
1139 }
1140
1141 fn measure_quantum_coherence(&self) -> Result<Array1<f64>> {
1143 let mut coherence_measures = Vec::new();
1144
1145 for qubit in 0..self.config.num_qubits {
1146 let mut coherence = 0.0;
1148 let state = &self.reservoir_state.state_vector;
1149
1150 for i in 0..state.len() {
1151 for j in 0..state.len() {
1152 if i != j {
1153 let i_bit = (i >> qubit) & 1;
1154 let j_bit = (j >> qubit) & 1;
1155 if i_bit != j_bit {
1156 coherence += (state[i].conj() * state[j]).norm();
1157 }
1158 }
1159 }
1160 }
1161
1162 coherence_measures.push(coherence);
1163 }
1164
1165 Ok(Array1::from_vec(coherence_measures))
1166 }
1167
1168 fn measure_purity(&self) -> Result<Array1<f64>> {
1170 let state = &self.reservoir_state.state_vector;
1172 let purity = state.iter().map(|x| x.norm_sqr().powi(2)).sum::<f64>();
1173
1174 Ok(Array1::from_vec(vec![purity]))
1175 }
1176
1177 fn measure_temporal_correlations(&self) -> Result<Array1<f64>> {
1179 let mut correlations = Vec::new();
1180
1181 let current_state = &self.reservoir_state.state_vector;
1183
1184 for past_state in &self.reservoir_state.state_history {
1185 let correlation = current_state
1186 .iter()
1187 .zip(past_state.iter())
1188 .map(|(a, b)| (a.conj() * b).re)
1189 .sum::<f64>();
1190 correlations.push(correlation);
1191 }
1192
1193 while correlations.len() < self.config.memory_capacity {
1195 correlations.push(0.0);
1196 }
1197
1198 Ok(Array1::from_vec(correlations))
1199 }
1200
1201 pub fn train(&mut self, training_data: &ReservoirTrainingData) -> Result<TrainingResult> {
1203 let start_time = std::time::Instant::now();
1204
1205 let mut all_features = Vec::new();
1206 let mut all_targets = Vec::new();
1207
1208 for i in 0..self.config.washout_period.min(training_data.inputs.len()) {
1210 let _ = self.process_input(&training_data.inputs[i])?;
1211 }
1212
1213 for i in self.config.washout_period..training_data.inputs.len() {
1215 let features = self.process_input(&training_data.inputs[i])?;
1216 all_features.push(features);
1217
1218 if i < training_data.targets.len() {
1219 all_targets.push(training_data.targets[i].clone());
1220 }
1221 }
1222
1223 self.train_with_learning_algorithm(&all_features, &all_targets)?;
1225
1226 if self.config.memory_config.enable_capacity_estimation {
1228 self.analyze_memory_capacity(&all_features)?;
1229 }
1230
1231 let (training_error, test_error) =
1233 self.evaluate_performance(&all_features, &all_targets)?;
1234
1235 let training_time = start_time.elapsed().as_secs_f64() * 1000.0;
1236
1237 self.metrics.training_examples += all_features.len();
1239 self.metrics.generalization_error = test_error;
1240 self.metrics.memory_capacity = self.reservoir_state.memory_metrics.total_capacity;
1241
1242 Ok(TrainingResult {
1243 training_error,
1244 test_error,
1245 training_time_ms: training_time,
1246 num_examples: all_features.len(),
1247 echo_state_property: self.estimate_echo_state_property()?,
1248 memory_capacity: self.reservoir_state.memory_metrics.total_capacity,
1249 nonlinear_capacity: self.reservoir_state.memory_metrics.nonlinear_capacity,
1250 processing_capacity: self.reservoir_state.memory_metrics.processing_capacity,
1251 })
1252 }
1253
1254 fn train_with_learning_algorithm(
1256 &mut self,
1257 features: &[Array1<f64>],
1258 targets: &[Array1<f64>],
1259 ) -> Result<()> {
1260 match self.config.learning_config.algorithm {
1261 LearningAlgorithm::Ridge => {
1262 self.train_ridge_regression(features, targets)?;
1263 }
1264 LearningAlgorithm::LASSO => {
1265 self.train_lasso_regression(features, targets)?;
1266 }
1267 LearningAlgorithm::ElasticNet => {
1268 self.train_elastic_net(features, targets)?;
1269 }
1270 LearningAlgorithm::RecursiveLeastSquares => {
1271 self.train_recursive_least_squares(features, targets)?;
1272 }
1273 LearningAlgorithm::KalmanFilter => {
1274 self.train_kalman_filter(features, targets)?;
1275 }
1276 _ => {
1277 self.train_ridge_regression(features, targets)?;
1279 }
1280 }
1281
1282 Ok(())
1283 }
1284
1285 fn train_ridge_regression(
1287 &mut self,
1288 features: &[Array1<f64>],
1289 targets: &[Array1<f64>],
1290 ) -> Result<()> {
1291 if features.is_empty() || targets.is_empty() {
1292 return Ok(());
1293 }
1294
1295 let n_samples = features.len().min(targets.len());
1296 let n_features = features[0].len();
1297 let n_outputs = targets[0].len().min(self.output_weights.nrows());
1298
1299 let mut feature_matrix = Array2::zeros((n_samples, n_features));
1301 for (i, feature_vec) in features.iter().enumerate().take(n_samples) {
1302 for (j, &val) in feature_vec.iter().enumerate().take(n_features) {
1303 feature_matrix[[i, j]] = val;
1304 }
1305 }
1306
1307 let mut target_matrix = Array2::zeros((n_samples, n_outputs));
1309 for (i, target_vec) in targets.iter().enumerate().take(n_samples) {
1310 for (j, &val) in target_vec.iter().enumerate().take(n_outputs) {
1311 target_matrix[[i, j]] = val;
1312 }
1313 }
1314
1315 let lambda = self.config.learning_config.regularization;
1317
1318 let xtx = feature_matrix.t().dot(&feature_matrix);
1320
1321 let mut xtx_reg = xtx;
1323 for i in 0..xtx_reg.nrows().min(xtx_reg.ncols()) {
1324 xtx_reg[[i, i]] += lambda;
1325 }
1326
1327 let xty = feature_matrix.t().dot(&target_matrix);
1329
1330 self.solve_linear_system(&xtx_reg, &xty)?;
1332
1333 Ok(())
1334 }
1335
1336 fn train_lasso_regression(
1338 &mut self,
1339 features: &[Array1<f64>],
1340 targets: &[Array1<f64>],
1341 ) -> Result<()> {
1342 let lambda = self.config.learning_config.regularization;
1344 let max_iter = 100;
1345
1346 for _ in 0..max_iter {
1347 for j in 0..self.output_weights.ncols().min(features[0].len()) {
1349 for i in 0..self.output_weights.nrows().min(targets[0].len()) {
1350 let old_weight = self.output_weights[[i, j]];
1352 let gradient = self.compute_lasso_gradient(features, targets, i, j)?;
1353 let update = 0.01f64.mul_add(-gradient, old_weight);
1354
1355 self.output_weights[[i, j]] = if update > lambda {
1357 update - lambda
1358 } else if update < -lambda {
1359 update + lambda
1360 } else {
1361 0.0
1362 };
1363 }
1364 }
1365 }
1366
1367 Ok(())
1368 }
1369
1370 fn compute_lasso_gradient(
1372 &self,
1373 features: &[Array1<f64>],
1374 targets: &[Array1<f64>],
1375 output_idx: usize,
1376 feature_idx: usize,
1377 ) -> Result<f64> {
1378 let mut gradient = 0.0;
1379
1380 for (feature_vec, target_vec) in features.iter().zip(targets.iter()) {
1381 if feature_idx < feature_vec.len() && output_idx < target_vec.len() {
1382 let prediction = self.predict_single_output(feature_vec, output_idx)?;
1383 let error = prediction - target_vec[output_idx];
1384 gradient += error * feature_vec[feature_idx];
1385 }
1386 }
1387
1388 gradient /= features.len() as f64;
1389 Ok(gradient)
1390 }
1391
1392 fn train_elastic_net(
1394 &mut self,
1395 features: &[Array1<f64>],
1396 targets: &[Array1<f64>],
1397 ) -> Result<()> {
1398 let l1_ratio = self.config.learning_config.l1_ratio;
1399
1400 if l1_ratio > 0.5 {
1402 self.train_lasso_regression(features, targets)?;
1404 } else {
1405 self.train_ridge_regression(features, targets)?;
1407 }
1408
1409 Ok(())
1410 }
1411
1412 fn train_recursive_least_squares(
1414 &mut self,
1415 features: &[Array1<f64>],
1416 targets: &[Array1<f64>],
1417 ) -> Result<()> {
1418 let forgetting_factor = self.config.learning_config.forgetting_factor;
1419 let n_features = features[0].len().min(self.output_weights.ncols());
1420 let n_outputs = targets[0].len().min(self.output_weights.nrows());
1421
1422 let mut p_matrix = Array2::eye(n_features) * 1000.0; for (feature_vec, target_vec) in features.iter().zip(targets.iter()) {
1427 let x = feature_vec.slice(s![..n_features]).to_owned();
1428 let y = target_vec.slice(s![..n_outputs]).to_owned();
1429
1430 let px = p_matrix.dot(&x);
1432 let denominator = forgetting_factor + x.dot(&px);
1433
1434 if denominator > 1e-15 {
1435 let k = &px / denominator;
1436
1437 for output_idx in 0..n_outputs {
1439 let prediction = self.predict_single_output(feature_vec, output_idx)?;
1440 let error = y[output_idx] - prediction;
1441
1442 for feature_idx in 0..n_features {
1444 self.output_weights[[output_idx, feature_idx]] += k[feature_idx] * error;
1445 }
1446 }
1447
1448 let outer_product = k
1450 .view()
1451 .insert_axis(Axis(1))
1452 .dot(&x.view().insert_axis(Axis(0)));
1453 p_matrix = (p_matrix - outer_product) / forgetting_factor;
1454 }
1455 }
1456
1457 Ok(())
1458 }
1459
1460 fn train_kalman_filter(
1462 &mut self,
1463 features: &[Array1<f64>],
1464 targets: &[Array1<f64>],
1465 ) -> Result<()> {
1466 let process_noise = self.config.learning_config.process_noise;
1467 let measurement_noise = self.config.learning_config.measurement_noise;
1468
1469 let n_features = features[0].len().min(self.output_weights.ncols());
1470 let n_outputs = targets[0].len().min(self.output_weights.nrows());
1471
1472 let mut state_covariance = Array2::eye(n_features) * 1.0;
1474 let process_noise_matrix: Array2<f64> = Array2::eye(n_features) * process_noise;
1475 let measurement_noise_scalar = measurement_noise;
1476
1477 for (feature_vec, target_vec) in features.iter().zip(targets.iter()) {
1479 let x = feature_vec.slice(s![..n_features]).to_owned();
1480 let y = target_vec.slice(s![..n_outputs]).to_owned();
1481
1482 let predicted_covariance = &state_covariance + &process_noise_matrix;
1484
1485 for output_idx in 0..n_outputs {
1487 let measurement = y[output_idx];
1488 let prediction = self.predict_single_output(feature_vec, output_idx)?;
1489
1490 let s = x.dot(&predicted_covariance.dot(&x)) + measurement_noise_scalar;
1492 if s > 1e-15 {
1493 let k = predicted_covariance.dot(&x) / s;
1494
1495 let innovation = measurement - prediction;
1497 for feature_idx in 0..n_features {
1498 self.output_weights[[output_idx, feature_idx]] +=
1499 k[feature_idx] * innovation;
1500 }
1501
1502 let kh = k
1504 .view()
1505 .insert_axis(Axis(1))
1506 .dot(&x.view().insert_axis(Axis(0)));
1507 state_covariance = &predicted_covariance - &kh.dot(&predicted_covariance);
1508 }
1509 }
1510 }
1511
1512 Ok(())
1513 }
1514
1515 fn predict_single_output(&self, features: &Array1<f64>, output_idx: usize) -> Result<f64> {
1517 let feature_size = features.len().min(self.output_weights.ncols());
1518 let mut output = 0.0;
1519
1520 for j in 0..feature_size {
1521 output += self.output_weights[[output_idx, j]] * features[j];
1522 }
1523
1524 Ok(output)
1525 }
1526
1527 fn analyze_memory_capacity(&mut self, features: &[Array1<f64>]) -> Result<()> {
1529 let linear_capacity = self.estimate_linear_memory_capacity(features)?;
1531 self.reservoir_state.memory_metrics.linear_capacity = linear_capacity;
1532
1533 if self.config.memory_config.enable_nonlinear {
1535 let nonlinear_capacity = self.estimate_nonlinear_memory_capacity(features)?;
1536 self.reservoir_state.memory_metrics.nonlinear_capacity = nonlinear_capacity;
1537 }
1538
1539 self.reservoir_state.memory_metrics.total_capacity =
1541 self.reservoir_state.memory_metrics.linear_capacity
1542 + self.reservoir_state.memory_metrics.nonlinear_capacity;
1543
1544 if self.config.memory_config.enable_ipc {
1546 let ipc = self.estimate_information_processing_capacity(features)?;
1547 self.reservoir_state.memory_metrics.processing_capacity = ipc;
1548 }
1549
1550 self.memory_analyzer.capacity_estimates.insert(
1552 "linear".to_string(),
1553 self.reservoir_state.memory_metrics.linear_capacity,
1554 );
1555 self.memory_analyzer.capacity_estimates.insert(
1556 "nonlinear".to_string(),
1557 self.reservoir_state.memory_metrics.nonlinear_capacity,
1558 );
1559 self.memory_analyzer.capacity_estimates.insert(
1560 "total".to_string(),
1561 self.reservoir_state.memory_metrics.total_capacity,
1562 );
1563
1564 Ok(())
1565 }
1566
1567 fn estimate_linear_memory_capacity(&self, features: &[Array1<f64>]) -> Result<f64> {
1569 let mut capacity = 0.0;
1571
1572 for lag in 1..=20 {
1573 if lag < features.len() {
1574 let mut correlation = 0.0;
1575 let mut count = 0;
1576
1577 for i in lag..features.len() {
1578 for j in 0..features[i].len().min(features[i - lag].len()) {
1579 correlation += features[i][j] * features[i - lag][j];
1580 count += 1;
1581 }
1582 }
1583
1584 if count > 0 {
1585 correlation /= f64::from(count);
1586 capacity += correlation.abs();
1587 }
1588 }
1589 }
1590
1591 Ok(capacity)
1592 }
1593
1594 fn estimate_nonlinear_memory_capacity(&self, features: &[Array1<f64>]) -> Result<f64> {
1596 let mut nonlinear_capacity = 0.0;
1597
1598 for order in &self.config.memory_config.nonlinearity_orders {
1600 let capacity_order = self.test_nonlinear_order(*order, features)?;
1601 nonlinear_capacity += capacity_order;
1602 }
1603
1604 Ok(nonlinear_capacity)
1605 }
1606
1607 fn test_nonlinear_order(&self, order: usize, features: &[Array1<f64>]) -> Result<f64> {
1609 let mut capacity = 0.0;
1610
1611 for lag in 1..=10 {
1613 if lag < features.len() {
1614 let mut correlation = 0.0;
1615 let mut count = 0;
1616
1617 for i in lag..features.len() {
1618 for j in 0..features[i].len().min(features[i - lag].len()) {
1619 let current = features[i][j];
1621 let past = features[i - lag][j];
1622 let nonlinear_target = past.powi(order as i32);
1623
1624 correlation += current * nonlinear_target;
1625 count += 1;
1626 }
1627 }
1628
1629 if count > 0 {
1630 correlation /= f64::from(count);
1631 capacity += correlation.abs() / order as f64; }
1633 }
1634 }
1635
1636 Ok(capacity)
1637 }
1638
1639 fn estimate_information_processing_capacity(&self, features: &[Array1<f64>]) -> Result<f64> {
1641 let mut ipc = 0.0;
1642
1643 for ipc_function in &self.config.memory_config.ipc_functions {
1644 let capacity_func = self.test_ipc_function(*ipc_function, features)?;
1645 ipc += capacity_func;
1646 }
1647
1648 Ok(ipc)
1649 }
1650
1651 fn test_ipc_function(&self, function: IPCFunction, features: &[Array1<f64>]) -> Result<f64> {
1653 let mut capacity = 0.0;
1654
1655 for lag in 1..=10 {
1656 if lag < features.len() {
1657 let mut correlation = 0.0;
1658 let mut count = 0;
1659
1660 for i in lag..features.len() {
1661 for j in 0..features[i].len().min(features[i - lag].len()) {
1662 let current = features[i][j];
1663 let past = features[i - lag][j];
1664
1665 let target = match function {
1666 IPCFunction::Linear => past,
1667 IPCFunction::Quadratic => past * past,
1668 IPCFunction::Cubic => past * past * past,
1669 IPCFunction::Sine => past.sin(),
1670 IPCFunction::Product => {
1671 if j > 0 && j - 1 < features[i - lag].len() {
1672 past * features[i - lag][j - 1]
1673 } else {
1674 past
1675 }
1676 }
1677 IPCFunction::XOR => {
1678 if past > 0.0 {
1679 1.0
1680 } else {
1681 -1.0
1682 }
1683 }
1684 };
1685
1686 correlation += current * target;
1687 count += 1;
1688 }
1689 }
1690
1691 if count > 0 {
1692 correlation /= f64::from(count);
1693 capacity += correlation.abs();
1694 }
1695 }
1696 }
1697
1698 Ok(capacity)
1699 }
1700
1701 fn solve_linear_system(&mut self, a: &Array2<f64>, b: &Array2<f64>) -> Result<()> {
1703 let min_dim = a.nrows().min(a.ncols()).min(b.nrows());
1704
1705 for i in 0..min_dim.min(self.output_weights.nrows()) {
1706 for j in 0..b.ncols().min(self.output_weights.ncols()) {
1707 if a[[i, i]].abs() > 1e-15 {
1708 self.output_weights[[i, j]] = b[[i, j]] / a[[i, i]];
1709 }
1710 }
1711 }
1712
1713 Ok(())
1714 }
1715
1716 fn evaluate_performance(
1718 &self,
1719 features: &[Array1<f64>],
1720 targets: &[Array1<f64>],
1721 ) -> Result<(f64, f64)> {
1722 if features.is_empty() || targets.is_empty() {
1723 return Ok((0.0, 0.0));
1724 }
1725
1726 let mut total_error = 0.0;
1727 let n_samples = features.len().min(targets.len());
1728
1729 for i in 0..n_samples {
1730 let prediction = self.predict_output(&features[i])?;
1731 let error = self.calculate_prediction_error(&prediction, &targets[i]);
1732 total_error += error;
1733 }
1734
1735 let training_error = total_error / n_samples as f64;
1736
1737 let test_error = training_error;
1739
1740 Ok((training_error, test_error))
1741 }
1742
1743 fn predict_output(&self, features: &Array1<f64>) -> Result<Array1<f64>> {
1745 let feature_size = features.len().min(self.output_weights.ncols());
1746 let output_size = self.output_weights.nrows();
1747
1748 let mut output = Array1::zeros(output_size);
1749
1750 for i in 0..output_size {
1751 for j in 0..feature_size {
1752 output[i] += self.output_weights[[i, j]] * features[j];
1753 }
1754 }
1755
1756 Ok(output)
1757 }
1758
1759 fn calculate_prediction_error(&self, prediction: &Array1<f64>, target: &Array1<f64>) -> f64 {
1761 let min_len = prediction.len().min(target.len());
1762 let mut error = 0.0;
1763
1764 for i in 0..min_len {
1765 let diff = prediction[i] - target[i];
1766 error += diff * diff;
1767 }
1768
1769 (error / min_len as f64).sqrt() }
1771
1772 fn estimate_echo_state_property(&self) -> Result<f64> {
1774 let coupling = self.config.coupling_strength;
1775 let estimated_spectral_radius = coupling.tanh(); Ok(if estimated_spectral_radius < 1.0 {
1779 1.0
1780 } else {
1781 1.0 / estimated_spectral_radius
1782 })
1783 }
1784
1785 fn update_processing_time(&mut self, time_ms: f64) {
1787 let count = self.metrics.training_examples as f64;
1788 self.metrics.avg_processing_time_ms =
1789 self.metrics.avg_processing_time_ms.mul_add(count, time_ms) / (count + 1.0);
1790 }
1791
1792 pub const fn get_metrics(&self) -> &ReservoirMetrics {
1794 &self.metrics
1795 }
1796
1797 pub const fn get_memory_analysis(&self) -> &MemoryAnalyzer {
1799 &self.memory_analyzer
1800 }
1801
1802 pub fn reset(&mut self) -> Result<()> {
1804 self.reservoir_state =
1805 QuantumReservoirState::new(self.config.num_qubits, self.config.memory_capacity);
1806 self.metrics = ReservoirMetrics::default();
1807 self.training_history.clear();
1808 Ok(())
1809 }
1810}