Curvature regulators #80

Merged
glen merged 21 commits from Vectornaut/dyna3:curvature-regulators into main 2025-04-21 23:40:43 +00:00
2 changed files with 95 additions and 31 deletions
Showing only changes of commit 7c40d60103 - Show all commits

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())