Trigger realization more directly

Simplify the system that reactively triggers realizations, at the cost
of removing the preconditioning step described in issue #101 and doing
unnecessary realizations after certain kinds of updates.

The new system should trigger a realization after any update that could
affect the assembly's deformation space. For simplicity, any update to
the regulator list triggers an update, even if it doesn't affect the set
of constraints. In particular, adding a regulator triggers an
unnecessary realization.
This commit is contained in:
Aaron Fenyes 2025-07-24 14:59:21 -07:00
parent 0801200210
commit c73008d702
4 changed files with 36 additions and 96 deletions

View file

@ -16,7 +16,6 @@ use crate::{
components::{display::DisplayItem, outline::OutlineItem},
engine::{
Q,
change_half_curvature,
local_unif_to_std,
point,
project_point_to_normalized,
@ -358,16 +357,6 @@ pub trait Regulator: Serial + ProblemPoser + OutlineItem {
fn subjects(&self) -> Vec<Rc<dyn Element>>;
fn measurement(&self) -> ReadSignal<f64>;
fn set_point(&self) -> Signal<SpecifiedValue>;
// this method is used to responsively precondition the assembly for
// realization when the regulator becomes a constraint, or is edited while
// acting as a constraint. it should track the set point, do any desired
// preconditioning when the set point is present, and use its return value
// to report whether the set is present. the default implementation does no
// preconditioning
fn try_activate(&self) -> bool {
self.set_point().with(|set_pt| set_pt.is_present())
}
}
impl Hash for dyn Regulator {
@ -488,18 +477,6 @@ impl Regulator for HalfCurvatureRegulator {
fn set_point(&self) -> Signal<SpecifiedValue> {
self.set_point
}
fn try_activate(&self) -> bool {
match self.set_point.with(|set_pt| set_pt.value) {
Some(half_curv) => {
self.subject.representation().update(
|rep| change_half_curvature(rep, half_curv)
);
true
}
None => false
}
}
}
impl Serial for HalfCurvatureRegulator {
@ -552,8 +529,7 @@ pub struct Assembly {
pub elements_by_id: Signal<BTreeMap<String, Rc<dyn Element>>>,
// realization control
pub keep_realized: Signal<bool>,
pub needs_realization: Signal<bool>,
pub realization_trigger: Signal<()>,
// realization diagnostics
pub realization_status: Signal<Result<(), String>>,
@ -568,21 +544,23 @@ impl Assembly {
regulators: create_signal(BTreeSet::new()),
tangent: create_signal(ConfigSubspace::zero(0)),
elements_by_id: create_signal(BTreeMap::default()),
keep_realized: create_signal(true),
needs_realization: create_signal(false),
realization_trigger: create_signal(()),
realization_status: create_signal(Ok(())),
descent_history: create_signal(DescentHistory::new())
};
// realize the assembly whenever it becomes simultaneously true that
// we're trying to keep it realized and it needs realization
// 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();
create_effect(move || {
let should_realize = assembly_for_effect.keep_realized.get()
&& assembly_for_effect.needs_realization.get();
if should_realize {
assembly_for_effect.realize();
}
assembly_for_effect.elements.track();
assembly_for_effect.regulators.with(
|regs| for reg in regs {
reg.set_point().track();
}
);
assembly_for_effect.realization_trigger.track();
assembly_for_effect.realize();
});
assembly
@ -646,19 +624,6 @@ impl Assembly {
regulators.update(|regs| regs.insert(regulator.clone()));
}
// request a realization when the regulator becomes a constraint, or is
// edited while acting as a constraint
let self_for_effect = self.clone();
create_effect(move || {
/* DEBUG */
// log the regulator update
console_log!("Updated regulator with subjects {:?}", regulator.subjects());
if regulator.try_activate() {
self_for_effect.needs_realization.set(true);
}
});
/* DEBUG */
// print an updated list of regulators
console_log!("Regulators:");
@ -726,8 +691,10 @@ impl Assembly {
} else {
console_log!("✅️ Target accuracy achieved!");
}
console_log!("Steps: {}", history.scaled_loss.len() - 1);
console_log!("Loss: {}", history.scaled_loss.last().unwrap());
if history.scaled_loss.len() > 0 {
console_log!("Steps: {}", history.scaled_loss.len() - 1);
console_log!("Loss: {}", history.scaled_loss.last().unwrap());
}
// report the loss history
self.descent_history.set(history);
@ -750,9 +717,6 @@ impl Assembly {
// save the tangent space
self.tangent.set_silent(tangent);
// clear the realization request flag
self.needs_realization.set(false);
},
Err(message) => {
// report the realization status. the `Err(message)` we're
@ -848,10 +812,10 @@ impl Assembly {
});
}
// request a realization to bring the configuration back onto the
// trigger a realization to bring the configuration back onto the
// solution variety. this also gets the elements' column indices and the
// saved tangent space back in sync
self.needs_realization.set(true);
self.realization_trigger.set(());
}
}