use spintronics::ai::MagnonReservoir;
use spintronics::vector3::Vector3;
fn main() {
println!("=== Physical Reservoir Computing with Magnons ===\n");
let n_spins = 30;
let n_input = 5;
let n_readout = 10;
let mut reservoir = MagnonReservoir::uniform_distribution(
n_spins, n_input, n_readout, 1.0e-20, 0.01, );
println!("Reservoir Configuration:");
println!(" Total spins: {}", n_spins);
println!(" Input nodes: {}", n_input);
println!(" Readout nodes: {}", n_readout);
println!(
" State dimension: {} (3 components × {} nodes)",
n_readout * 3,
n_readout
);
println!();
println!("--- Task 1: Constant Function ---\n");
let inputs_const = vec![
vec![0.1, 0.2, 0.15, 0.3, 0.1],
vec![0.3, 0.1, 0.25, 0.2, 0.15],
vec![0.2, 0.3, 0.1, 0.15, 0.25],
vec![0.15, 0.25, 0.3, 0.1, 0.2],
vec![0.25, 0.15, 0.2, 0.3, 0.05],
];
let targets_const = vec![1.0, 1.0, 1.0, 1.0, 1.0];
println!("Training to output constant 1.0 regardless of input...");
let h_ext = Vector3::new(0.0, 0.0, 1.0e5);
let evolution_steps = 10;
let dt = 1.0e-13;
let mse_result = reservoir.train(&inputs_const, &targets_const, h_ext, evolution_steps, dt);
match mse_result {
Ok(mse) => {
println!(" Training MSE: {:.6}", mse);
println!();
println!("Testing on training data:");
for (i, input) in inputs_const.iter().enumerate() {
reservoir.reset();
let output = reservoir.process(input, h_ext, evolution_steps, dt);
println!(
" Input {:?} → Output: {:.4} (Target: {:.1})",
&input[..2],
output,
targets_const[i]
);
}
println!();
},
Err(e) => {
println!(" Training error: {}", e);
println!();
},
}
println!("--- Task 2: Linear Function ---\n");
let mut reservoir2 = MagnonReservoir::uniform_distribution(25, 4, 8, 1.0e-20, 0.01);
let inputs_linear = vec![
vec![0.0, 0.0, 0.0, 0.0],
vec![0.1, 0.0, 0.0, 0.0],
vec![0.2, 0.0, 0.0, 0.0],
vec![0.3, 0.0, 0.0, 0.0],
vec![0.0, 0.1, 0.0, 0.0],
vec![0.0, 0.2, 0.0, 0.0],
];
let targets_linear: Vec<f64> = inputs_linear.iter().map(|inp| inp[0] + inp[1]).collect();
println!("Training to compute f(x) = x[0] + x[1]...");
let mse_result2 = reservoir2.train(&inputs_linear, &targets_linear, h_ext, 8, dt);
match mse_result2 {
Ok(mse) => {
println!(" Training MSE: {:.6}", mse);
println!();
println!("Testing:");
for (i, input) in inputs_linear.iter().enumerate() {
reservoir2.reset();
let output = reservoir2.process(input, h_ext, 8, dt);
println!(
" [{:.1}, {:.1}] → {:.4} (Target: {:.2})",
input[0], input[1], output, targets_linear[i]
);
}
println!();
},
Err(e) => {
println!(" Training error: {}", e);
println!();
},
}
println!("--- Task 3: Non-linear Pattern Recognition ---\n");
let mut reservoir3 = MagnonReservoir::uniform_distribution(40, 2, 12, 1.0e-20, 0.01);
let inputs_nonlinear = vec![
vec![0.0, 0.0], vec![0.0, 0.5], vec![0.5, 0.0], vec![0.5, 0.5], vec![0.1, 0.1], vec![0.4, 0.4], ];
let targets_nonlinear = vec![0.0, 1.0, 1.0, 0.0, 0.0, 0.0];
println!("Training XOR-like function (output high when inputs differ)...");
let mse_result3 = reservoir3.train(&inputs_nonlinear, &targets_nonlinear, h_ext, 12, dt);
match mse_result3 {
Ok(mse) => {
println!(" Training MSE: {:.6}", mse);
println!();
println!("Testing:");
for (i, input) in inputs_nonlinear.iter().enumerate() {
reservoir3.reset();
let output = reservoir3.process(input, h_ext, 12, dt);
println!(
" [{:.1}, {:.1}] → {:.4} (Target: {:.1})",
input[0], input[1], output, targets_nonlinear[i]
);
}
println!();
},
Err(e) => {
println!(" Training error: {}", e);
println!();
},
}
println!("--- Reservoir Properties ---\n");
reservoir.reset();
let initial_state = reservoir.extract_state();
println!("Initial state (all spins along +z):");
println!(" State vector dimension: {}", initial_state.len());
println!(
" First few components: [{:.3}, {:.3}, {:.3}, ...]",
initial_state[0], initial_state[1], initial_state[2]
);
println!();
let test_input = vec![0.2, 0.3];
reservoir.process(&test_input, h_ext, 10, dt);
let evolved_state = reservoir.extract_state();
println!(
"After processing input [{:.1}, {:.1}]:",
test_input[0], test_input[1]
);
println!(
" First few components: [{:.3}, {:.3}, {:.3}, ...]",
evolved_state[0], evolved_state[1], evolved_state[2]
);
println!();
println!("=== Summary ===");
println!();
println!("Physical Reservoir Computing leverages the non-linear dynamics of spin waves:");
println!();
println!("1. Input Layer:");
println!(" - Scalar inputs encoded as magnetic field modulation");
println!(" - Applied to specific spins in the chain");
println!();
println!("2. Reservoir Layer (physical substrate):");
println!(" - Spin chain with LLG dynamics (non-linear)");
println!(" - Exchange coupling creates spatial interactions");
println!(" - Gilbert damping provides dissipation");
println!(" - High-dimensional state space (N_spins × 3 components)");
println!();
println!("3. Readout Layer (trained):");
println!(" - Linear combination of reservoir states");
println!(" - Weights trained via gradient descent");
println!(" - Only layer that requires training");
println!();
println!("Advantages:");
println!(" - No need to train the complex reservoir dynamics");
println!(" - Physical hardware naturally provides non-linearity");
println!(" - Energy-efficient computation");
println!(" - Potential for ultra-fast processing (GHz rates)");
println!();
println!("Applications:");
println!(" - Time series prediction");
println!(" - Pattern classification");
println!(" - Signal processing");
println!(" - Neuromorphic computing");
}