1use super::types::*;
7use crate::error::{IntegrateError, IntegrateResult};
8use scirs2_core::ndarray::{Array1, Array2, Array3, Axis};
9
10pub struct QuantumVisualizer;
12
13impl QuantumVisualizer {
14 pub fn visualize_wavefunction(
16 x: &Array1<f64>,
17 probability_density: &Array1<f64>,
18 time: f64,
19 ) -> IntegrateResult<HeatMapPlot> {
20 let mut metadata = PlotMetadata::default();
21 metadata.title = format!("Quantum State at t = {:.3}", time);
22 metadata.xlabel = "Position".to_string();
23 metadata.ylabel = "Probability Density".to_string();
24
25 Ok(HeatMapPlot {
26 x: x.clone(),
27 y: Array1::from_elem(1, 0.0), z: Array2::from_shape_vec((1, probability_density.len()), probability_density.to_vec())
29 .map_err(|e| IntegrateError::ComputationError(format!("Shape error: {e}")))?,
30 metadata,
31 })
32 }
33
34 pub fn visualize_complex_phase(
36 real_parts: &[f64],
37 imag_parts: &[f64],
38 phases: &[f64],
39 ) -> IntegrateResult<PhaseSpacePlot> {
40 let mut metadata = PlotMetadata::default();
41 metadata.title = "Complex Wave Function Phase".to_string();
42 metadata.xlabel = "Real Part".to_string();
43 metadata.ylabel = "Imaginary Part".to_string();
44
45 Ok(PhaseSpacePlot {
46 x: real_parts.to_vec(),
47 y: imag_parts.to_vec(),
48 colors: Some(phases.to_vec()),
49 metadata,
50 })
51 }
52
53 pub fn visualize_expectation_evolution(
55 times: &[f64],
56 positions: &[f64],
57 momenta: &[f64],
58 ) -> IntegrateResult<PhaseSpacePlot> {
59 let mut metadata = PlotMetadata::default();
60 metadata.title = "Quantum Expectation Values Evolution".to_string();
61 metadata.xlabel = "Position Expectation".to_string();
62 metadata.ylabel = "Momentum Expectation".to_string();
63
64 Ok(PhaseSpacePlot {
65 x: positions.to_vec(),
66 y: momenta.to_vec(),
67 colors: Some(times.to_vec()),
68 metadata,
69 })
70 }
71
72 pub fn visualize_energy_levels(
74 energies: &Array1<f64>,
75 wavefunctions: &Array2<f64>,
76 ) -> IntegrateResult<VectorFieldPlot> {
77 let n_levels = energies.len().min(5); let n_points = wavefunctions.nrows();
79
80 let x_coords = Array1::linspace(-1.0, 1.0, n_points);
81 let mut x_grid = Array2::zeros((n_levels, n_points));
82 let mut y_grid = Array2::zeros((n_levels, n_points));
83 let mut u = Array2::zeros((n_levels, n_points));
84 let mut v = Array2::zeros((n_levels, n_points));
85 let mut magnitude = Array2::zeros((n_levels, n_points));
86
87 for level in 0..n_levels {
88 for i in 0..n_points {
89 x_grid[[level, i]] = x_coords[i];
90 y_grid[[level, i]] = energies[level];
91 u[[level, i]] = wavefunctions[[i, level]];
92 v[[level, i]] = 0.0; magnitude[[level, i]] = wavefunctions[[i, level]].abs();
94 }
95 }
96
97 let mut metadata = PlotMetadata::default();
98 metadata.title = "Energy Level Diagram".to_string();
99 metadata.xlabel = "Position".to_string();
100 metadata.ylabel = "Energy".to_string();
101
102 Ok(VectorFieldPlot {
103 x_grid,
104 y_grid,
105 u,
106 v,
107 magnitude,
108 metadata,
109 })
110 }
111}
112
113pub struct FluidVisualizer;
115
116impl FluidVisualizer {
117 pub fn visualize_velocity_field(state: &FluidState) -> IntegrateResult<VectorFieldPlot> {
119 if state.velocity.len() < 2 {
120 return Err(IntegrateError::ValueError(
121 "Need at least 2 velocity components".to_string(),
122 ));
123 }
124
125 let u = &state.velocity[0];
126 let v = &state.velocity[1];
127 let (ny, nx) = u.dim();
128
129 let mut x_grid = Array2::zeros((ny, nx));
130 let mut y_grid = Array2::zeros((ny, nx));
131 let mut magnitude = Array2::zeros((ny, nx));
132
133 for i in 0..ny {
134 for j in 0..nx {
135 x_grid[[i, j]] = j as f64 * state.dx;
136 y_grid[[i, j]] = i as f64 * state.dy;
137 magnitude[[i, j]] = (u[[i, j]].powi(2) + v[[i, j]].powi(2)).sqrt();
138 }
139 }
140
141 let mut metadata = PlotMetadata::default();
142 metadata.title = format!("Velocity Field at t = {:.3}", state.time);
143 metadata.xlabel = "X Position".to_string();
144 metadata.ylabel = "Y Position".to_string();
145
146 Ok(VectorFieldPlot {
147 x_grid,
148 y_grid,
149 u: u.clone(),
150 v: v.clone(),
151 magnitude,
152 metadata,
153 })
154 }
155
156 pub fn visualize_pressure_field(state: &FluidState) -> IntegrateResult<HeatMapPlot> {
158 let (ny, nx) = state.pressure.dim();
159 let x = Array1::from_iter((0..nx).map(|i| i as f64 * state.dx));
160 let y = Array1::from_iter((0..ny).map(|i| i as f64 * state.dy));
161
162 let mut metadata = PlotMetadata::default();
163 metadata.title = format!("Pressure Field at t = {:.3}", state.time);
164 metadata.xlabel = "X Position".to_string();
165 metadata.ylabel = "Y Position".to_string();
166
167 Ok(HeatMapPlot {
168 x,
169 y,
170 z: state.pressure.clone(),
171 metadata,
172 })
173 }
174
175 pub fn visualize_vorticity(state: &FluidState) -> IntegrateResult<HeatMapPlot> {
177 if state.velocity.len() < 2 {
178 return Err(IntegrateError::ValueError(
179 "Need at least 2 velocity components".to_string(),
180 ));
181 }
182
183 let u = &state.velocity[0];
184 let v = &state.velocity[1];
185 let (ny, nx) = u.dim();
186
187 let mut vorticity = Array2::zeros((ny, nx));
188
189 for i in 1..ny - 1 {
191 for j in 1..nx - 1 {
192 let dvdx = (v[[i, j + 1]] - v[[i, j - 1]]) / (2.0 * state.dx);
193 let dudy = (u[[i + 1, j]] - u[[i - 1, j]]) / (2.0 * state.dy);
194 vorticity[[i, j]] = dvdx - dudy;
195 }
196 }
197
198 let x = Array1::from_iter((0..nx).map(|i| i as f64 * state.dx));
199 let y = Array1::from_iter((0..ny).map(|i| i as f64 * state.dy));
200
201 let mut metadata = PlotMetadata::default();
202 metadata.title = format!("Vorticity Field at t = {:.3}", state.time);
203 metadata.xlabel = "X Position".to_string();
204 metadata.ylabel = "Y Position".to_string();
205
206 Ok(HeatMapPlot {
207 x,
208 y,
209 z: vorticity,
210 metadata,
211 })
212 }
213
214 pub fn visualize_streamlines(
216 state: &FluidState,
217 n_streamlines: usize,
218 ) -> IntegrateResult<Vec<PhaseSpacePlot>> {
219 if state.velocity.len() < 2 {
220 return Err(IntegrateError::ValueError(
221 "Need at least 2 velocity components".to_string(),
222 ));
223 }
224
225 let u = &state.velocity[0];
226 let v = &state.velocity[1];
227 let (ny, nx) = u.dim();
228
229 let mut streamlines = Vec::new();
230
231 for i in 0..n_streamlines {
233 let start_x = (i as f64 / (n_streamlines - 1) as f64) * (nx - 1) as f64 * state.dx;
234 let start_y = 0.5 * (ny - 1) as f64 * state.dy; let mut x_line = vec![start_x];
237 let mut y_line = vec![start_y];
238
239 let mut current_x = start_x;
240 let mut current_y = start_y;
241
242 let dt = 0.01 * state.dx.min(state.dy);
244 for _ in 0..1000 {
245 let i_idx = (current_y / state.dy) as usize;
247 let j_idx = (current_x / state.dx) as usize;
248
249 if i_idx >= ny - 1 || j_idx >= nx - 1 || i_idx == 0 || j_idx == 0 {
250 break;
251 }
252
253 let vel_x = u[[i_idx, j_idx]];
254 let vel_y = v[[i_idx, j_idx]];
255
256 current_x += vel_x * dt;
257 current_y += vel_y * dt;
258
259 x_line.push(current_x);
260 y_line.push(current_y);
261
262 if vel_x.abs() + vel_y.abs() < 1e-6 {
264 break;
265 }
266 }
267
268 let mut metadata = PlotMetadata::default();
269 metadata.title = format!("Streamline {} at t = {:.3}", i, state.time);
270 metadata.xlabel = "X Position".to_string();
271 metadata.ylabel = "Y Position".to_string();
272
273 streamlines.push(PhaseSpacePlot {
274 x: x_line,
275 y: y_line,
276 colors: None,
277 metadata,
278 });
279 }
280
281 Ok(streamlines)
282 }
283
284 pub fn visualize_3d_velocity_magnitude(state: &FluidState3D) -> IntegrateResult<SurfacePlot> {
286 if state.velocity.len() < 3 {
287 return Err(IntegrateError::ValueError(
288 "Need 3 velocity components for 3D".to_string(),
289 ));
290 }
291
292 let u = &state.velocity[0];
293 let v = &state.velocity[1];
294 let w = &state.velocity[2];
295 let (nz, ny, nx) = u.dim();
296
297 let z_slice = nz / 2;
299 let mut x_grid = Array2::zeros((ny, nx));
300 let mut y_grid = Array2::zeros((ny, nx));
301 let mut magnitude = Array2::zeros((ny, nx));
302
303 for i in 0..ny {
304 for j in 0..nx {
305 x_grid[[i, j]] = j as f64 * state.dx;
306 y_grid[[i, j]] = i as f64 * state.dy;
307 let vel_mag = (u[[z_slice, i, j]].powi(2)
308 + v[[z_slice, i, j]].powi(2)
309 + w[[z_slice, i, j]].powi(2))
310 .sqrt();
311 magnitude[[i, j]] = vel_mag;
312 }
313 }
314
315 let mut metadata = PlotMetadata::default();
316 metadata.title = format!("3D Velocity Magnitude at t = {:.3}", state.time);
317 metadata.xlabel = "X Position".to_string();
318 metadata.ylabel = "Y Position".to_string();
319
320 Ok(SurfacePlot {
321 x: x_grid,
322 y: y_grid,
323 z: magnitude,
324 metadata,
325 })
326 }
327}
328
329pub struct FinanceVisualizer;
331
332impl FinanceVisualizer {
333 pub fn visualize_option_surface(
335 strikes: &Array1<f64>,
336 maturities: &Array1<f64>,
337 prices: &Array2<f64>,
338 ) -> IntegrateResult<SurfacePlot> {
339 let (n_maturities, n_strikes) = prices.dim();
340 let mut x_grid = Array2::zeros((n_maturities, n_strikes));
341 let mut y_grid = Array2::zeros((n_maturities, n_strikes));
342
343 for i in 0..n_maturities {
344 for j in 0..n_strikes {
345 x_grid[[i, j]] = strikes[j];
346 y_grid[[i, j]] = maturities[i];
347 }
348 }
349
350 let mut metadata = PlotMetadata::default();
351 metadata.title = "Option Price Surface".to_string();
352 metadata.xlabel = "Strike Price".to_string();
353 metadata.ylabel = "Time to Maturity".to_string();
354
355 Ok(SurfacePlot {
356 x: x_grid,
357 y: y_grid,
358 z: prices.clone(),
359 metadata,
360 })
361 }
362
363 pub fn visualize_greeks_surface(
365 strikes: &Array1<f64>,
366 spot_prices: &Array1<f64>,
367 greek_values: &Array2<f64>,
368 greek_name: &str,
369 ) -> IntegrateResult<HeatMapPlot> {
370 let mut metadata = PlotMetadata::default();
371 metadata.title = format!("{} Surface", greek_name);
372 metadata.xlabel = "Strike Price".to_string();
373 metadata.ylabel = "Spot Price".to_string();
374
375 Ok(HeatMapPlot {
376 x: strikes.clone(),
377 y: spot_prices.clone(),
378 z: greek_values.clone(),
379 metadata,
380 })
381 }
382
383 pub fn visualize_volatility_smile(
385 strikes: &Array1<f64>,
386 implied_volatilities: &Array1<f64>,
387 maturity: f64,
388 ) -> IntegrateResult<PhaseSpacePlot> {
389 let mut metadata = PlotMetadata::default();
390 metadata.title = format!("Volatility Smile (T = {:.3})", maturity);
391 metadata.xlabel = "Strike Price".to_string();
392 metadata.ylabel = "Implied Volatility".to_string();
393
394 Ok(PhaseSpacePlot {
395 x: strikes.to_vec(),
396 y: implied_volatilities.to_vec(),
397 colors: None,
398 metadata,
399 })
400 }
401
402 pub fn visualize_risk_metrics(
404 time_points: &Array1<f64>,
405 var_values: &Array1<f64>,
406 cvar_values: &Array1<f64>,
407 ) -> IntegrateResult<PhaseSpacePlot> {
408 let mut metadata = PlotMetadata::default();
409 metadata.title = "Risk Metrics Evolution".to_string();
410 metadata.xlabel = "Value at Risk".to_string();
411 metadata.ylabel = "Conditional Value at Risk".to_string();
412
413 Ok(PhaseSpacePlot {
414 x: var_values.to_vec(),
415 y: cvar_values.to_vec(),
416 colors: Some(time_points.to_vec()),
417 metadata,
418 })
419 }
420
421 pub fn visualize_portfolio_performance(
423 dates: &[String],
424 returns: &Array1<f64>,
425 benchmark_returns: &Array1<f64>,
426 ) -> IntegrateResult<PhaseSpacePlot> {
427 let mut cum_returns = vec![1.0]; let mut cum_benchmark = vec![1.0];
430
431 for i in 0..returns.len() {
432 cum_returns.push(cum_returns[i] * (1.0 + returns[i]));
433 cum_benchmark.push(cum_benchmark[i] * (1.0 + benchmark_returns[i]));
434 }
435
436 let mut metadata = PlotMetadata::default();
437 metadata.title = "Portfolio vs Benchmark Performance".to_string();
438 metadata.xlabel = "Portfolio Cumulative Return".to_string();
439 metadata.ylabel = "Benchmark Cumulative Return".to_string();
440
441 Ok(PhaseSpacePlot {
442 x: cum_returns,
443 y: cum_benchmark,
444 colors: Some((0..dates.len() + 1).map(|i| i as f64).collect()),
445 metadata,
446 })
447 }
448}
449
450pub fn specialized_visualizations(
452 visualization_type: &str,
453 data: &Array2<f64>,
454) -> IntegrateResult<HeatMapPlot> {
455 match visualization_type {
456 "quantum_probability" => {
457 let x = Array1::linspace(-5.0, 5.0, data.ncols());
458 let probability_density = data.row(0).to_owned();
459 QuantumVisualizer::visualize_wavefunction(&x, &probability_density, 0.0)
460 }
461 _ => Err(IntegrateError::ValueError(format!(
462 "Unknown visualization type: {}",
463 visualization_type
464 ))),
465 }
466}
467
468pub struct BifurcationDiagramGenerator {
470 pub parameter_range: (f64, f64),
472 pub n_parameter_samples: usize,
474 pub transient_steps: usize,
476 pub sampling_steps: usize,
478 pub fixed_point_tolerance: f64,
480 pub period_tolerance: f64,
482}
483
484impl BifurcationDiagramGenerator {
485 pub fn new(parameterrange: (f64, f64), n_parameter_samples: usize) -> Self {
487 Self {
488 parameter_range: parameterrange,
489 n_parameter_samples,
490 transient_steps: 1000,
491 sampling_steps: 500,
492 fixed_point_tolerance: 1e-8,
493 period_tolerance: 1e-6,
494 }
495 }
496
497 pub fn generate_enhanced_diagram<F>(
499 &self,
500 map_function: F,
501 initial_condition: f64,
502 ) -> IntegrateResult<BifurcationDiagram>
503 where
504 F: Fn(f64, f64) -> f64, {
506 let mut parameter_values = Vec::new();
507 let mut state_values = Vec::new();
508 let mut stability_flags = Vec::new();
509
510 let param_step = (self.parameter_range.1 - self.parameter_range.0)
511 / (self.n_parameter_samples - 1) as f64;
512
513 for i in 0..self.n_parameter_samples {
514 let param = self.parameter_range.0 + i as f64 * param_step;
515
516 let mut x = initial_condition;
518 for _ in 0..self.transient_steps {
519 x = map_function(x, param);
520 }
521
522 let mut attractor_states = Vec::new();
524 for _ in 0..self.sampling_steps {
525 x = map_function(x, param);
526 attractor_states.push(x);
527 }
528
529 let unique_count = self.count_unique_states(&attractor_states);
531 let is_stable = unique_count <= 2;
532
533 if unique_count == 1 {
535 parameter_values.push(param);
536 state_values.push(attractor_states[attractor_states.len() - 1]);
537 stability_flags.push(is_stable);
538 } else {
539 let sample_rate = (attractor_states.len() / 10).max(1);
541 for (idx, &state) in attractor_states.iter().step_by(sample_rate).enumerate() {
542 if idx < 10 {
543 parameter_values.push(param);
545 state_values.push(state);
546 stability_flags.push(is_stable);
547 }
548 }
549 }
550 }
551
552 Ok(BifurcationDiagram {
553 parameters: parameter_values,
554 states: vec![state_values],
555 stability: stability_flags,
556 bifurcation_points: vec![], })
558 }
559
560 fn count_unique_states(&self, states: &[f64]) -> usize {
561 let mut unique_states = states.to_vec();
562 unique_states.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
563 unique_states.dedup_by(|a, b| (*a - *b).abs() < self.fixed_point_tolerance);
564 unique_states.len()
565 }
566}