Rewind through the descent history (#114)
All checks were successful
/ test (push) Successful in 3m39s

You can now rewind through the descent history of the last realization using the *Step* control that's been added to the diagnostics panel.

The starting value of the *Step* control depends on the realization status. After a successful realization, we show the realized state (the last step). After an unsuccessful realization, we show the initial guess (step zero).

Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo>
Reviewed-on: #114
Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net>
Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
This commit is contained in:
Vectornaut 2025-09-18 23:31:17 +00:00 committed by Glen Whitney
parent af18a8e7d1
commit 978f70aac7
6 changed files with 152 additions and 19 deletions

View file

@ -534,6 +534,7 @@ pub struct Assembly {
// realization diagnostics
pub realization_status: Signal<Result<(), String>>,
pub descent_history: Signal<DescentHistory>,
pub step: Signal<SpecifiedValue>,
}
impl Assembly {
@ -547,20 +548,33 @@ impl Assembly {
realization_trigger: create_signal(()),
realization_status: create_signal(Ok(())),
descent_history: create_signal(DescentHistory::new()),
step: create_signal(SpecifiedValue::from_empty_spec()),
};
// realize the assembly whenever the element list, the regulator list,
// a regulator's set point, or the realization trigger is updated
let assembly_for_effect = assembly.clone();
let assembly_for_realization = assembly.clone();
create_effect(move || {
assembly_for_effect.elements.track();
assembly_for_effect.regulators.with(
assembly_for_realization.elements.track();
assembly_for_realization.regulators.with(
|regs| for reg in regs {
reg.set_point().track();
}
);
assembly_for_effect.realization_trigger.track();
assembly_for_effect.realize();
assembly_for_realization.realization_trigger.track();
assembly_for_realization.realize();
});
// load a configuration from the descent history whenever the active
// step is updated
let assembly_for_step_selection = assembly.clone();
create_effect(move || {
if let Some(step) = assembly.step.with(|n| n.value) {
let config = assembly.descent_history.with_untracked(
|history| history.config[step as usize].clone()
);
assembly_for_step_selection.load_config(&config)
}
});
assembly
@ -647,6 +661,16 @@ impl Assembly {
});
}
// --- updating the configuration ---
pub fn load_config(&self, config: &DMatrix<f64>) {
for elt in self.elements.get_clone_untracked() {
elt.representation().update(
|rep| rep.set_column(0, &config.column(elt.column_index().unwrap()))
);
}
}
// --- realization ---
pub fn realize(&self) {
@ -696,11 +720,12 @@ impl Assembly {
console_log!("Loss: {}", history.scaled_loss.last().unwrap());
}
// report the loss history
// report the descent history
let step_cnt = history.config.len();
self.descent_history.set(history);
match result {
Ok(ConfigNeighborhood { config, nbhd: tangent }) => {
Ok(ConfigNeighborhood { nbhd: tangent, .. }) => {
/* DEBUG */
// report the tangent dimension
console_log!("Tangent dimension: {}", tangent.dim());
@ -708,12 +733,15 @@ impl Assembly {
// report the realization status
self.realization_status.set(Ok(()));
// 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()))
);
}
// display the last realization step
self.step.set(
if step_cnt > 0 {
let last_step = step_cnt - 1;
SpecifiedValue::try_from(last_step.to_string()).unwrap()
} else {
SpecifiedValue::from_empty_spec()
}
);
// save the tangent space
self.tangent.set_silent(tangent);
@ -723,7 +751,10 @@ impl Assembly {
// 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))
self.realization_status.set(Err(message));
// display the initial guess
self.step.set(SpecifiedValue::from(Some(0.0)));
},
}
}