Add a realization status indicator

This commit is contained in:
Aaron Fenyes 2025-06-09 22:21:34 -07:00
parent 0b333ac00d
commit 402f5609c0
4 changed files with 105 additions and 29 deletions

View file

@ -11,8 +11,8 @@ pub fn print_title(title: &str) {
pub fn print_realization_diagnostics(realization_result: &RealizationResult) { pub fn print_realization_diagnostics(realization_result: &RealizationResult) {
let RealizationResult { result, history } = realization_result; let RealizationResult { result, history } = realization_result;
println!(); println!();
if let Err(ref msg) = result { if let Err(ref message) = result {
println!("❌️ {msg}"); println!("❌️ {message}");
} else { } else {
println!("✅️ Target accuracy achieved!"); println!("✅️ Target accuracy achieved!");
} }

View file

@ -18,6 +18,17 @@ body {
font-family: 'Fira Sans', sans-serif; font-family: 'Fira Sans', sans-serif;
} }
.invalid {
color: var(--text-invalid);
}
.status {
width: 20px;
text-align: center;
font-family: 'Noto Emoji';
font-style: normal;
}
/* sidebar */ /* sidebar */
#sidebar { #sidebar {
@ -138,6 +149,7 @@ details[open]:has(li) .element-switch::after {
} }
.regulator-input { .regulator-input {
margin-right: 4px;
color: inherit; color: inherit;
background-color: inherit; background-color: inherit;
border: 1px solid var(--border); border: 1px solid var(--border);
@ -159,14 +171,6 @@ details[open]:has(li) .element-switch::after {
border-color: var(--border-invalid); border-color: var(--border-invalid);
} }
.status {
width: 20px;
padding-left: 4px;
text-align: center;
font-family: 'Noto Emoji';
font-style: normal;
}
.regulator-input.invalid + .status::after, details:has(.invalid):not([open]) .status::after { .regulator-input.invalid + .status::after, details:has(.invalid):not([open]) .status::after {
content: '⚠'; content: '⚠';
color: var(--text-invalid); color: var(--text-invalid);
@ -174,8 +178,28 @@ details[open]:has(li) .element-switch::after {
/* diagnostics */ /* diagnostics */
#loss-history { #diagnostics {
margin: 10px; margin: 10px;
}
#realization-status {
display: flex;
}
#realization-status .status {
margin-right: 4px;
}
#realization-status .status::after {
content: '✓';
}
#realization-status.invalid .status::after {
content: '⚠';
}
#loss-history {
margin-top: 10px;
background-color: var(--display-background); background-color: var(--display-background);
border-radius: 8px; border-radius: 8px;
} }

View file

@ -553,6 +553,7 @@ pub struct Assembly {
pub elements_by_id: Signal<BTreeMap<String, Rc<dyn Element>>>, pub elements_by_id: Signal<BTreeMap<String, Rc<dyn Element>>>,
// realization diagnostics // realization diagnostics
pub realization_status: Signal<Result<(), String>>,
pub descent_history: Signal<DescentHistory> pub descent_history: Signal<DescentHistory>
} }
@ -563,6 +564,7 @@ impl Assembly {
regulators: create_signal(BTreeSet::new()), regulators: create_signal(BTreeSet::new()),
tangent: create_signal(ConfigSubspace::zero(0)), tangent: create_signal(ConfigSubspace::zero(0)),
elements_by_id: create_signal(BTreeMap::default()), elements_by_id: create_signal(BTreeMap::default()),
realization_status: create_signal(Ok(())),
descent_history: create_signal(DescentHistory::new()) descent_history: create_signal(DescentHistory::new())
} }
} }
@ -699,32 +701,44 @@ impl Assembly {
); );
/* DEBUG */ /* DEBUG */
// report the outcome of the search // report the outcome of the search in the browser console
if let Err(ref msg) = result { if let Err(ref message) = result {
console_log!("❌️ {msg}"); console_log!("❌️ {message}");
} else { } else {
console_log!("✅️ Target accuracy achieved!"); console_log!("✅️ Target accuracy achieved!");
} }
console_log!("Steps: {}", history.scaled_loss.len() - 1); console_log!("Steps: {}", history.scaled_loss.len() - 1);
console_log!("Loss: {}", history.scaled_loss.last().unwrap()); console_log!("Loss: {}", history.scaled_loss.last().unwrap());
// record realization diagnostics // report the loss history
self.descent_history.set(history); self.descent_history.set(history);
if let Ok(Realization { config, tangent }) = result { match result {
/* DEBUG */ Ok(Realization { config, tangent }) => {
// report the tangent dimension /* DEBUG */
console_log!("Tangent dimension: {}", tangent.dim()); // report the tangent dimension
console_log!("Tangent dimension: {}", tangent.dim());
// read out the solution
for elt in self.elements.get_clone_untracked() { // report the realization status
elt.representation().update( self.realization_status.set(Ok(()));
|rep| rep.set_column(0, &config.column(elt.column_index().unwrap()))
); // read out the solution
for elt in self.elements.get_clone_untracked() {
elt.representation().update(
|rep| rep.set_column(0, &config.column(elt.column_index().unwrap()))
);
}
// save the tangent space
self.tangent.set_silent(tangent);
},
Err(message) => {
// report the realization status. the `Err(message)` we're
// setting the status to has a different type than the
// `Err(message)` we received from the match: we're changing the
// `Ok` type from `Realization` to `()`
self.realization_status.set(Err(message))
} }
// save the tangent space
self.tangent.set_silent(tangent);
} }
} }

View file

@ -10,9 +10,37 @@ use sycamore::prelude::*;
use crate::AppState; use crate::AppState;
// a realization status indicator
#[component]
pub fn RealizationStatus() -> View {
let state = use_context::<AppState>();
let realization_status = state.assembly.realization_status;
view! {
div(
id="realization-status",
class=realization_status.with(
|status| match status {
Ok(_) => "",
Err(_) => "invalid"
}
)
) {
div(class="status")
div {
(realization_status.with(
|status| match status {
Ok(_) => "Target accuracy achieved".to_string(),
Err(message) => message.clone()
}
))
}
}
}
}
// a plot of the loss history from the last realization // a plot of the loss history from the last realization
#[component] #[component]
pub fn Diagnostics() -> View { pub fn LossHistory() -> View {
const CONTAINER_ID: &str = "loss-history"; const CONTAINER_ID: &str = "loss-history";
let state = use_context::<AppState>(); let state = use_context::<AppState>();
let renderer = WasmRenderer::new_opt(None, Some(180)).theme(Theme::Walden); let renderer = WasmRenderer::new_opt(None, Some(180)).theme(Theme::Walden);
@ -62,4 +90,14 @@ pub fn Diagnostics() -> View {
view! { view! {
div(id=CONTAINER_ID) div(id=CONTAINER_ID)
} }
}
#[component]
pub fn Diagnostics() -> View {
view! {
div(id="diagnostics") {
RealizationStatus {}
LossHistory {}
}
}
} }