Let the elements and regulators write the problem

When we realize an assembly, each element and regulator now writes its
own data into the constraint problem.
This commit is contained in:
Aaron Fenyes 2025-03-25 02:15:03 -07:00
parent c6e6e7be9f
commit 677d770738
2 changed files with 95 additions and 31 deletions

View file

@ -121,15 +121,43 @@ impl Element {
None
}
}
fn write_to_problem(&self, problem: &mut ConstraintProblem) {
if let Some(index) = self.column_index {
problem.gram.push_sym(index, index, 1.0);
problem.guess.set_column(index, &self.representation.get_clone_untracked());
} else {
panic!("Tried to write problem data from an unindexed element: \"{}\"", self.id);
}
}
}
#[derive(Clone, Copy)]
pub struct Regulator {
pub struct ProductRegulator {
pub subjects: (ElementKey, ElementKey),
pub measurement: ReadSignal<f64>,
pub set_point: Signal<SpecifiedValue>
}
impl ProductRegulator {
fn write_to_problem(&self, problem: &mut ConstraintProblem, elts: &Slab<Element>) {
self.set_point.with_untracked(|set_pt| {
if let Some(val) = set_pt.value {
let subjects = self.subjects;
let subject_column_indices = (
elts[subjects.0].column_index,
elts[subjects.1].column_index
);
if let (Some(row), Some(col)) = subject_column_indices {
problem.gram.push_sym(row, col, val);
} else {
panic!("Tried to write problem data from a regulator with an unindexed subject");
}
}
});
}
}
// the velocity is expressed in uniform coordinates
pub struct ElementMotion<'a> {
pub key: ElementKey,
@ -143,7 +171,7 @@ type AssemblyMotion<'a> = Vec<ElementMotion<'a>>;
pub struct Assembly {
// elements and regulators
pub elements: Signal<Slab<Element>>,
pub regulators: Signal<Slab<Regulator>>,
pub regulators: Signal<Slab<ProductRegulator>>,
// solution variety tangent space. the basis vectors are stored in
// configuration matrix format, ordered according to the elements' column
@ -214,7 +242,7 @@ impl Assembly {
);
}
fn insert_regulator(&self, regulator: Regulator) {
fn insert_regulator(&self, regulator: ProductRegulator) {
let subjects = regulator.subjects;
let key = self.regulators.update(|regs| regs.insert(regulator));
let subject_regulators = self.elements.with(
@ -236,7 +264,7 @@ impl Assembly {
}
);
let set_point = create_signal(SpecifiedValue::from_empty_spec());
self.insert_regulator(Regulator {
self.insert_regulator(ProductRegulator {
subjects: subjects,
measurement: measurement,
set_point: set_point
@ -263,7 +291,7 @@ impl Assembly {
// edited while acting as a constraint
create_effect(move || {
console::log_1(&JsValue::from(
format!("Updated constraint with subjects ({}, {})", subjects.0, subjects.1)
format!("Updated regulator with subjects {:?}", subjects)
));
if set_point.with(|set_pt| set_pt.is_present()) {
self.realize();
@ -274,11 +302,6 @@ impl Assembly {
// --- realization ---
pub fn realize(&self) {
// create a blank constraint problem
let mut problem = ConstraintProblem::new(
self.elements.with_untracked(|elts| elts.len())
);
// index the elements
self.elements.update_silent(|elts| {
for (index, (_, elt)) in elts.into_iter().enumerate() {
@ -286,29 +309,18 @@ impl Assembly {
}
});
// set up the Gram matrix and the initial configuration matrix
self.elements.with_untracked(|elts| {
// set up the off-diagonal part of the Gram matrix
// set up the constraint problem
let problem = self.elements.with_untracked(|elts| {
let mut problem_to_be = ConstraintProblem::new(elts.len());
for (_, elt) in elts {
elt.write_to_problem(&mut problem_to_be);
}
self.regulators.with_untracked(|regs| {
for (_, reg) in regs {
reg.set_point.with_untracked(|set_pt| {
if let Some(val) = set_pt.value {
let subjects = reg.subjects;
let row = elts[subjects.0].column_index.unwrap();
let col = elts[subjects.1].column_index.unwrap();
problem.gram.push_sym(row, col, val);
}
});
reg.write_to_problem(&mut problem_to_be, elts);
}
});
// set up the initial configuration matrix and the diagonal of the
// Gram matrix
for (_, elt) in elts {
let index = elt.column_index.unwrap();
problem.gram.push_sym(index, index, 1.0);
problem.guess.set_column(index, &elt.representation.get_clone_untracked());
}
problem_to_be
});
/* DEBUG */
@ -464,4 +476,56 @@ impl Assembly {
// sync
self.realize();
}
}
#[cfg(test)]
mod tests {
use crate::engine;
use super::*;
#[test]
#[should_panic(expected = "Tried to write problem data from an unindexed element: \"sphere\"")]
fn unindexed_element_test() {
let _ = create_root(|| {
Element::new(
"sphere".to_string(),
"Sphere".to_string(),
[1.0_f32, 1.0_f32, 1.0_f32],
engine::sphere(0.0, 0.0, 0.0, 1.0)
).write_to_problem(&mut ConstraintProblem::new(1));
});
}
#[test]
#[should_panic(expected = "Tried to write problem data from a regulator with an unindexed subject")]
fn unindexed_subject_test() {
let _ = create_root(|| {
let mut elts = Slab::new();
let subjects = (
elts.insert(
Element::new(
"sphere0".to_string(),
"Sphere 0".to_string(),
[1.0_f32, 1.0_f32, 1.0_f32],
engine::sphere(0.0, 0.0, 0.0, 1.0)
)
),
elts.insert(
Element::new(
"sphere1".to_string(),
"Sphere 1".to_string(),
[1.0_f32, 1.0_f32, 1.0_f32],
engine::sphere(0.0, 0.0, 0.0, 1.0)
)
)
);
elts[subjects.0].column_index = Some(0);
ProductRegulator {
subjects: subjects,
measurement: create_memo(|| 0.0),
set_point: create_signal(SpecifiedValue::try_from("0.0".to_string()).unwrap())
}.write_to_problem(&mut ConstraintProblem::new(2), &elts);
});
}
}

View file

@ -9,13 +9,13 @@ use web_sys::{
use crate::{
AppState,
assembly,
assembly::{ElementKey, Regulator, RegulatorKey},
assembly::{ElementKey, ProductRegulator, RegulatorKey},
specified::SpecifiedValue
};
// an editable view of a regulator
#[component(inline_props)]
fn RegulatorInput(regulator: Regulator) -> View {
fn RegulatorInput(regulator: ProductRegulator) -> View {
let valid = create_signal(true);
let value = create_signal(
regulator.set_point.with_untracked(|set_pt| set_pt.spec.clone())