1use quantrs2_ml::autodiff::optimizers::Adam;
7use quantrs2_ml::prelude::*;
8use scirs2_core::ndarray::{s, Array1, Array2};
9use scirs2_core::random::prelude::*;
10
11fn main() -> Result<()> {
12 println!("=== Quantum Diffusion Model Demo ===\n");
13
14 println!("1. Comparing Noise Schedules...");
16 compare_noise_schedules()?;
17
18 println!("\n2. Training Quantum Diffusion Model...");
20 train_diffusion_model()?;
21
22 println!("\n3. Generating New Samples...");
24 generate_samples()?;
25
26 println!("\n4. Score-Based Diffusion Demo...");
28 score_diffusion_demo()?;
29
30 println!("\n5. Visualizing Diffusion Process...");
32 visualize_diffusion_process()?;
33
34 println!("\n=== Diffusion Model Demo Complete ===");
35
36 Ok(())
37}
38
39fn compare_noise_schedules() -> Result<()> {
41 let num_timesteps = 100;
42
43 let schedules = vec![
44 (
45 "Linear",
46 NoiseSchedule::Linear {
47 beta_start: 0.0001,
48 beta_end: 0.02,
49 },
50 ),
51 ("Cosine", NoiseSchedule::Cosine { s: 0.008 }),
52 (
53 "Quadratic",
54 NoiseSchedule::Quadratic {
55 beta_start: 0.0001,
56 beta_end: 0.02,
57 },
58 ),
59 (
60 "Sigmoid",
61 NoiseSchedule::Sigmoid {
62 beta_start: 0.0001,
63 beta_end: 0.02,
64 },
65 ),
66 ];
67
68 println!(" Noise levels at different timesteps:");
69 println!(" Time Linear Cosine Quadratic Sigmoid");
70
71 for t in (0..=100).step_by(20) {
72 let t_idx = (t * (num_timesteps - 1) / 100).min(num_timesteps - 1);
73 print!(" t={t:3}%: ");
74
75 for (_, schedule) in &schedules {
76 let model = QuantumDiffusionModel::new(2, 4, num_timesteps, *schedule)?;
77 print!("{:8.4} ", model.betas()[t_idx]);
78 }
79 println!();
80 }
81
82 Ok(())
83}
84
85fn train_diffusion_model() -> Result<()> {
87 let num_samples = 200;
89 let data = generate_two_moons(num_samples);
90
91 println!(" Generated {num_samples} samples of 2D two-moons data");
92
93 let mut model = QuantumDiffusionModel::new(
95 2, 4, 50, NoiseSchedule::Cosine { s: 0.008 },
99 )?;
100
101 println!(" Created quantum diffusion model:");
102 println!(" - Data dimension: 2");
103 println!(" - Qubits: 4");
104 println!(" - Timesteps: 50");
105 println!(" - Schedule: Cosine");
106
107 let mut optimizer = Adam::new(0.001);
109 let epochs = 100;
110 let batch_size = 32;
111
112 println!("\n Training for {epochs} epochs...");
113 let losses = model.train(&data, &mut optimizer, epochs, batch_size)?;
114
115 println!("\n Training Statistics:");
117 println!(" - Initial loss: {:.4}", losses[0]);
118 println!(" - Final loss: {:.4}", losses.last().unwrap());
119 println!(
120 " - Improvement: {:.2}%",
121 (1.0 - losses.last().unwrap() / losses[0]) * 100.0
122 );
123
124 Ok(())
125}
126
127fn generate_samples() -> Result<()> {
129 let model = QuantumDiffusionModel::new(
131 2, 4, 50, NoiseSchedule::Linear {
135 beta_start: 0.0001,
136 beta_end: 0.02,
137 },
138 )?;
139
140 let num_samples = 10;
142 println!(" Generating {num_samples} samples...");
143
144 let samples = model.generate(num_samples)?;
145
146 println!("\n Generated samples:");
147 for i in 0..num_samples.min(5) {
148 println!(
149 " Sample {}: [{:.3}, {:.3}]",
150 i + 1,
151 samples[[i, 0]],
152 samples[[i, 1]]
153 );
154 }
155
156 let mean = samples.mean_axis(scirs2_core::ndarray::Axis(0)).unwrap();
158 let std = samples.std_axis(scirs2_core::ndarray::Axis(0), 0.0);
159
160 println!("\n Sample statistics:");
161 println!(" - Mean: [{:.3}, {:.3}]", mean[0], mean[1]);
162 println!(" - Std: [{:.3}, {:.3}]", std[0], std[1]);
163
164 Ok(())
165}
166
167fn score_diffusion_demo() -> Result<()> {
169 let model = QuantumScoreDiffusion::new(
171 2, 4, 10, )?;
175
176 println!(" Created quantum score-based diffusion model");
177 println!(" - Noise levels: {:?}", model.noise_levels());
178
179 let x = Array1::from_vec(vec![0.5, -0.3]);
181 let noise_level = 0.1;
182
183 let score = model.estimate_score(&x, noise_level)?;
184 println!("\n Score estimation:");
185 println!(" - Input: [{:.3}, {:.3}]", x[0], x[1]);
186 println!(" - Noise level: {noise_level:.3}");
187 println!(" - Estimated score: [{:.3}, {:.3}]", score[0], score[1]);
188
189 println!("\n Langevin sampling:");
191 let init = Array1::from_vec(vec![2.0, 2.0]);
192 let num_steps = 100;
193 let step_size = 0.01;
194
195 let sample = model.langevin_sample(init.clone(), noise_level, num_steps, step_size)?;
196
197 println!(" - Initial: [{:.3}, {:.3}]", init[0], init[1]);
198 println!(
199 " - After {} steps: [{:.3}, {:.3}]",
200 num_steps, sample[0], sample[1]
201 );
202 println!(
203 " - Distance moved: {:.3}",
204 (sample[0] - init[0]).hypot(sample[1] - init[1])
205 );
206
207 Ok(())
208}
209
210fn visualize_diffusion_process() -> Result<()> {
212 let model = QuantumDiffusionModel::new(
213 2, 4, 20, NoiseSchedule::Linear {
217 beta_start: 0.0001,
218 beta_end: 0.02,
219 },
220 )?;
221
222 let x0 = Array1::from_vec(vec![1.0, 0.5]);
224
225 println!(" Forward diffusion process:");
226 println!(" t=0 (original): [{:.3}, {:.3}]", x0[0], x0[1]);
227
228 for t in [5, 10, 15, 19] {
230 let (xt, _) = model.forward_diffusion(&x0, t)?;
231 let noise_level = (1.0 - model.alphas_cumprod()[t]).sqrt();
232 println!(
233 " t={:2} (noise={:.3}): [{:.3}, {:.3}]",
234 t, noise_level, xt[0], xt[1]
235 );
236 }
237
238 println!("\n Reverse diffusion process:");
239
240 let mut xt = Array1::from_vec(vec![
242 2.0f64.mul_add(thread_rng().gen::<f64>(), -1.0),
243 2.0f64.mul_add(thread_rng().gen::<f64>(), -1.0),
244 ]);
245
246 println!(" t=19 (pure noise): [{:.3}, {:.3}]", xt[0], xt[1]);
247
248 for t in [15, 10, 5, 0] {
250 xt = model.reverse_diffusion_step(&xt, t)?;
251 println!(" t={:2} (denoised): [{:.3}, {:.3}]", t, xt[0], xt[1]);
252 }
253
254 println!("\n This demonstrates how diffusion models:");
255 println!(" 1. Gradually add noise to data (forward process)");
256 println!(" 2. Learn to reverse this process (backward process)");
257 println!(" 3. Generate new samples by denoising random noise");
258
259 Ok(())
260}
261
262fn generate_two_moons(n_samples: usize) -> Array2<f64> {
264 let mut data = Array2::zeros((n_samples, 2));
265 let n_samples_per_moon = n_samples / 2;
266
267 for i in 0..n_samples_per_moon {
269 let angle = std::f64::consts::PI * i as f64 / n_samples_per_moon as f64;
270 data[[i, 0]] = 0.1f64.mul_add(2.0f64.mul_add(thread_rng().gen::<f64>(), -1.0), angle.cos());
271 data[[i, 1]] = 0.1f64.mul_add(2.0f64.mul_add(thread_rng().gen::<f64>(), -1.0), angle.sin());
272 }
273
274 for i in 0..n_samples_per_moon {
276 let idx = n_samples_per_moon + i;
277 let angle = std::f64::consts::PI * i as f64 / n_samples_per_moon as f64;
278 data[[idx, 0]] = 0.1f64.mul_add(
279 2.0f64.mul_add(thread_rng().gen::<f64>(), -1.0),
280 1.0 - angle.cos(),
281 );
282 data[[idx, 1]] = 0.1f64.mul_add(
283 2.0f64.mul_add(thread_rng().gen::<f64>(), -1.0),
284 0.5 - angle.sin(),
285 );
286 }
287
288 data
289}
290
291fn advanced_diffusion_demo() -> Result<()> {
293 println!("\n6. Advanced Diffusion Techniques:");
294
295 println!("\n a) Conditional Generation:");
297 let model = QuantumDiffusionModel::new(4, 4, 50, NoiseSchedule::Cosine { s: 0.008 })?;
298 let condition = Array1::from_vec(vec![0.5, -0.5]);
299 let conditional_samples = model.conditional_generate(&condition, 5)?;
300
301 println!(
302 " Generated {} conditional samples",
303 conditional_samples.nrows()
304 );
305 println!(" Condition: [{:.3}, {:.3}]", condition[0], condition[1]);
306
307 println!("\n b) Variational Diffusion Model:");
309 let vdm = QuantumVariationalDiffusion::new(
310 4, 2, 4, )?;
314
315 let x = Array1::from_vec(vec![0.1, 0.2, 0.3, 0.4]);
316 let (mean, log_var) = vdm.encode(&x)?;
317
318 println!(" Encoded data to latent space:");
319 println!(" - Input: {:?}", x.as_slice().unwrap());
320 println!(" - Latent mean: [{:.3}, {:.3}]", mean[0], mean[1]);
321 println!(
322 " - Latent log_var: [{:.3}, {:.3}]",
323 log_var[0], log_var[1]
324 );
325
326 Ok(())
327}