burn_quantum_visualization 0.3.0

Interactive Bevy workbench for quantum circuits, states, photonic fabrics and optimization
Documentation
use super::{plot::PlotCache, theme::*};
use crate::{app::Explorer, model::VisualizationDocument};
use bevy::prelude::*;
pub(super) fn build(
    p: &mut PlotCache,
    bounds: Rect,
    state: &Explorer,
    doc: &VisualizationDocument,
) {
    if doc.optimization.is_empty() {
        p.text(
            bounds.center() + Vec2::new(0., -25.),
            "Watch a quantum model learn.",
            25.,
            TEXT,
        );
        p.text(
            bounds.center() + Vec2::new(0., 15.),
            "Choose the optimization experiment for an actual QN-SPSA trajectory.",
            13.,
            MUTED,
        );
        p.description = "No optimization history attached".into();
        return;
    }
    let points = &doc.optimization;
    let area = Rect::from_corners(
        bounds.min + Vec2::new(75., 85.),
        bounds.max - Vec2::new(35., 100.),
    );
    let scale = points.iter().map(|p| p.loss.abs()).fold(1f64, f64::max);
    let lo = points
        .iter()
        .map(|x| x.loss / scale)
        .fold(f64::INFINITY, f64::min)
        .min(0.);
    let hi = points
        .iter()
        .map(|x| x.loss / scale)
        .fold(f64::NEG_INFINITY, f64::max)
        .max(lo + 1e-5);
    let range = (hi - lo) * 1.15;
    let to_point = |i: usize, loss: f64| {
        let raw = Vec2::new(
            area.min.x + area.width() * i as f32 / points.len().saturating_sub(1).max(1) as f32,
            area.max.y - area.height() * ((loss - lo) / range) as f32,
        );
        area.center() + (raw - area.center()) * state.zoom + state.pan
    };
    p.text(
        Vec2::new(bounds.center().x, bounds.min.y + 25.),
        "Optimization history",
        21.,
        TEXT,
    );
    p.text(
        Vec2::new(bounds.center().x, bounds.min.y + 51.),
        if scale > 1e5 {
            format!("Objective axis / {scale:.3e}")
        } else {
            "Recorded objective at each parameter iterate".into()
        },
        12.,
        MUTED,
    );
    if state.grid {
        for i in 0..=4 {
            let v = lo + range * i as f64 / 4.;
            let y = to_point(0, v).y;
            p.line(Vec2::new(area.min.x, y), Vec2::new(area.max.x, y), GUIDE);
            p.text(
                Vec2::new(area.min.x - 35., y),
                if scale > 1e5 {
                    format!("{v:.2}")
                } else {
                    format!("{:.2}", v * scale)
                },
                11.,
                MUTED,
            );
        }
    }
    for i in 0..=4 {
        let index = i * (points.len() - 1) / 4;
        let x = to_point(index, lo).x;
        p.text(
            Vec2::new(x, area.max.y + 13.),
            points[index].iteration.to_string(),
            11.,
            MUTED,
        );
    }
    p.text(
        Vec2::new(area.center().x, area.max.y + 47.),
        "Completed optimizer updates",
        11.,
        MUTED,
    );
    let stride = points.len().div_ceil(256).max(1);
    let mut last = None;
    for (i, point) in points.iter().enumerate().step_by(stride) {
        let xy = to_point(i, point.loss / scale);
        if let Some(prev) = last {
            p.line(prev, xy, BLUE.with_alpha(0.3));
        }
        last = Some(xy);
    }
    let current = state.frame.min(points.len() - 1);
    let mut last = None;
    for (i, point) in points.iter().enumerate().take(current + 1).step_by(stride) {
        let xy = to_point(i, point.loss / scale);
        if let Some(prev) = last {
            p.line(prev, xy, ACCENT);
        }
        p.dot(xy, 2., ACCENT);
        last = Some(xy);
    }
    let selected = &points[current];
    let xy = to_point(current, selected.loss / scale);
    p.line(
        Vec2::new(xy.x, area.min.y),
        Vec2::new(xy.x, area.max.y),
        GOLD.with_alpha(0.5),
    );
    p.dot(xy, 6., GOLD);
    p.text(
        Vec2::new(area.center().x, area.max.y + 70.),
        format!(
            "Iteration {} · objective {}",
            selected.iteration,
            if selected.loss.abs() > 1e5 {
                format!("{:.3e}", selected.loss)
            } else {
                format!("{:.5}", selected.loss)
            }
        ),
        15.,
        TEXT,
    );
    p.text(
        Vec2::new(area.center().x, area.max.y + 92.),
        format!(
            "{} loss evaluations  +  {} fidelity evaluations",
            selected.loss_evaluations, selected.fidelity_evaluations
        ),
        12.,
        MUTED,
    );
    p.description = format!(
        "{} optimizer iterates\n≤256 points per curve · actual evaluation costs",
        points.len()
    );
}