chore: remove trailing whitespace, add CR at end of file

This commit is contained in:
Glen Whitney 2025-10-10 10:20:38 -07:00
parent a4b355d943
commit 3635abc562
11 changed files with 320 additions and 320 deletions

View file

@ -45,7 +45,7 @@ static NEXT_SERIAL: AtomicU64 = AtomicU64::new(0);
pub trait Serial {
// a serial number that uniquely identifies this element
fn serial(&self) -> u64;
// take the next serial number, panicking if that was the last one left
fn next_serial() -> u64 where Self: Sized {
// the technique we use to panic on overflow is taken from _Rust Atomics
@ -101,33 +101,33 @@ pub trait ProblemPoser {
pub trait Element: Serial + ProblemPoser + DisplayItem {
// the default identifier for an element of this type
fn default_id() -> String where Self: Sized;
// the default example of an element of this type
fn default(id: String, id_num: u64) -> Self where Self: Sized;
// the default regulators that come with this element
fn default_regulators(self: Rc<Self>) -> Vec<Rc<dyn Regulator>> {
Vec::new()
}
fn id(&self) -> &String;
fn label(&self) -> &String;
fn representation(&self) -> Signal<DVector<f64>>;
fn ghost(&self) -> Signal<bool>;
// the regulators the element is subject to. the assembly that owns the
// element is responsible for keeping this set up to date
fn regulators(&self) -> Signal<BTreeSet<Rc<dyn Regulator>>>;
// project a representation vector for this kind of element onto its
// normalization variety
fn project_to_normalized(&self, rep: &mut DVector<f64>);
// the configuration matrix column index that was assigned to the element
// last time the assembly was realized, or `None` if the element has never
// been through a realization
fn column_index(&self) -> Option<usize>;
// assign the element a configuration matrix column index. this method must
// be used carefully to preserve invariant (1), described in the comment on
// the `tangent` field of the `Assembly` structure
@ -179,7 +179,7 @@ pub struct Sphere {
impl Sphere {
const CURVATURE_COMPONENT: usize = 3;
pub fn new(
id: String,
label: String,
@ -203,7 +203,7 @@ impl Element for Sphere {
fn default_id() -> String {
"sphere".to_string()
}
fn default(id: String, id_num: u64) -> Self {
Self::new(
id,
@ -212,39 +212,39 @@ impl Element for Sphere {
sphere(0.0, 0.0, 0.0, 1.0),
)
}
fn default_regulators(self: Rc<Self>) -> Vec<Rc<dyn Regulator>> {
vec![Rc::new(HalfCurvatureRegulator::new(self))]
}
fn id(&self) -> &String {
&self.id
}
fn label(&self) -> &String {
&self.label
}
fn representation(&self) -> Signal<DVector<f64>> {
self.representation
}
fn ghost(&self) -> Signal<bool> {
self.ghost
}
fn regulators(&self) -> Signal<BTreeSet<Rc<dyn Regulator>>> {
self.regulators
}
fn project_to_normalized(&self, rep: &mut DVector<f64>) {
project_sphere_to_normalized(rep);
}
fn column_index(&self) -> Option<usize> {
self.column_index.get()
}
fn set_column_index(&self, index: usize) {
self.column_index.set(Some(index));
}
@ -279,7 +279,7 @@ pub struct Point {
impl Point {
const WEIGHT_COMPONENT: usize = 3;
const NORM_COMPONENT: usize = 4;
pub fn new(
id: String,
label: String,
@ -303,7 +303,7 @@ impl Element for Point {
fn default_id() -> String {
"point".to_string()
}
fn default(id: String, id_num: u64) -> Self {
Self::new(
id,
@ -321,35 +321,35 @@ impl Element for Point {
})
.collect()
}
fn id(&self) -> &String {
&self.id
}
fn label(&self) -> &String {
&self.label
}
fn representation(&self) -> Signal<DVector<f64>> {
self.representation
}
fn ghost(&self) -> Signal<bool> {
self.ghost
}
fn regulators(&self) -> Signal<BTreeSet<Rc<dyn Regulator>>> {
self.regulators
}
fn project_to_normalized(&self, rep: &mut DVector<f64>) {
project_point_to_normalized(rep);
}
fn column_index(&self) -> Option<usize> {
self.column_index.get()
}
fn set_column_index(&self, index: usize) {
self.column_index.set(Some(index));
}
@ -420,10 +420,10 @@ impl InversiveDistanceRegulator {
)
)
});
let set_point = create_signal(SpecifiedValue::from_empty_spec());
let serial = Self::next_serial();
Self { subjects, measurement, set_point, serial }
}
}
@ -432,11 +432,11 @@ impl Regulator for InversiveDistanceRegulator {
fn subjects(&self) -> Vec<Rc<dyn Element>> {
self.subjects.clone().into()
}
fn measurement(&self) -> ReadSignal<f64> {
self.measurement
}
fn set_point(&self) -> Signal<SpecifiedValue> {
self.set_point
}
@ -475,10 +475,10 @@ impl HalfCurvatureRegulator {
let measurement = subject.representation().map(
|rep| rep[Sphere::CURVATURE_COMPONENT]
);
let set_point = create_signal(SpecifiedValue::from_empty_spec());
let serial = Self::next_serial();
Self { subject, measurement, set_point, serial }
}
}
@ -487,11 +487,11 @@ impl Regulator for HalfCurvatureRegulator {
fn subjects(&self) -> Vec<Rc<dyn Element>> {
vec![self.subject.clone()]
}
fn measurement(&self) -> ReadSignal<f64> {
self.measurement
}
fn set_point(&self) -> Signal<SpecifiedValue> {
self.set_point
}
@ -600,7 +600,7 @@ pub struct Assembly {
// elements and regulators
pub elements: Signal<BTreeSet<Rc<dyn Element>>>,
pub regulators: Signal<BTreeSet<Rc<dyn Regulator>>>,
// solution variety tangent space. the basis vectors are stored in
// configuration matrix format, ordered according to the elements' column
// indices. when you realize the assembly, every element that's present
@ -612,13 +612,13 @@ pub struct Assembly {
// in that column of the tangent space basis matrices
//
pub tangent: Signal<ConfigSubspace>,
// indexing
pub elements_by_id: Signal<BTreeMap<String, Rc<dyn Element>>>,
// realization control
pub realization_trigger: Signal<()>,
// realization diagnostics
pub realization_status: Signal<Result<(), String>>,
pub descent_history: Signal<DescentHistory>,
@ -638,7 +638,7 @@ impl Assembly {
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_realization = assembly.clone();
@ -652,7 +652,7 @@ impl Assembly {
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();
@ -664,12 +664,12 @@ impl Assembly {
assembly_for_step_selection.load_config(&config)
}
});
assembly
}
// --- inserting elements and regulators ---
// insert an element into the assembly without checking whether we already
// have an element with the same identifier. any element that does have the
// same identifier will get kicked out of the `elements_by_id` index
@ -679,13 +679,13 @@ impl Assembly {
let elt_rc = Rc::new(elt);
self.elements.update(|elts| elts.insert(elt_rc.clone()));
self.elements_by_id.update(|elts_by_id| elts_by_id.insert(id, elt_rc.clone()));
// create and insert the element's default regulators
for reg in elt_rc.default_regulators() {
self.insert_regulator(reg);
}
}
pub fn try_insert_element(&self, elt: impl Element + 'static) -> bool {
let can_insert = self.elements_by_id.with_untracked(
|elts_by_id| !elts_by_id.contains_key(elt.id())
@ -695,7 +695,7 @@ impl Assembly {
}
can_insert
}
pub fn insert_element_default<T: Element + 'static>(&self) {
// find the next unused identifier in the default sequence
let default_id = T::default_id();
@ -707,17 +707,17 @@ impl Assembly {
id_num += 1;
id = format!("{default_id}{id_num}");
}
// create and insert the default example of `T`
let _ = self.insert_element_unchecked(T::default(id, id_num));
}
pub fn insert_regulator(&self, regulator: Rc<dyn Regulator>) {
// add the regulator to the assembly's regulator list
self.regulators.update(
|regs| regs.insert(regulator.clone())
);
// add the regulator to each subject's regulator list
let subject_regulators: Vec<_> = regulator.subjects().into_iter().map(
|subj| subj.regulators()
@ -725,7 +725,7 @@ impl Assembly {
for regulators in subject_regulators {
regulators.update(|regs| regs.insert(regulator.clone()));
}
/* DEBUG */
// print an updated list of regulators
console_log!("Regulators:");
@ -748,9 +748,9 @@ impl Assembly {
}
});
}
// --- updating the configuration ---
pub fn load_config(&self, config: &DMatrix<f64>) {
for elt in self.elements.get_clone_untracked() {
elt.representation().update(
@ -758,9 +758,9 @@ impl Assembly {
);
}
}
// --- realization ---
pub fn realize(&self) {
// index the elements
self.elements.update_silent(|elts| {
@ -768,7 +768,7 @@ impl Assembly {
elt.set_column_index(index);
}
});
// set up the constraint problem
let problem = self.elements.with_untracked(|elts| {
let mut problem = ConstraintProblem::new(elts.len());
@ -782,21 +782,21 @@ impl Assembly {
});
problem
});
/* DEBUG */
// log the Gram matrix
console_log!("Gram matrix:\n{}", problem.gram);
console_log!("Frozen entries:\n{}", problem.frozen);
/* DEBUG */
// log the initial configuration matrix
console_log!("Old configuration:{:>8.3}", problem.guess);
// look for a configuration with the given Gram matrix
let Realization { result, history } = realize_gram(
&problem, 1.0e-12, 0.5, 0.9, 1.1, 200, 110
);
/* DEBUG */
// report the outcome of the search in the browser console
if let Err(ref message) = result {
@ -808,20 +808,20 @@ impl Assembly {
console_log!("Steps: {}", history.scaled_loss.len() - 1);
console_log!("Loss: {}", history.scaled_loss.last().unwrap());
}
// report the descent history
let step_cnt = history.config.len();
self.descent_history.set(history);
match result {
Ok(ConfigNeighborhood { nbhd: tangent, .. }) => {
/* DEBUG */
// report the tangent dimension
console_log!("Tangent dimension: {}", tangent.dim());
// report the realization status
self.realization_status.set(Ok(()));
// display the last realization step
self.step.set(
if step_cnt > 0 {
@ -831,7 +831,7 @@ impl Assembly {
SpecifiedValue::from_empty_spec()
}
);
// save the tangent space
self.tangent.set_silent(tangent);
},
@ -841,15 +841,15 @@ impl Assembly {
// `Err(message)` we received from the match: we're changing the
// `Ok` type from `Realization` to `()`
self.realization_status.set(Err(message));
// display the initial guess
self.step.set(SpecifiedValue::from(Some(0.0)));
},
}
}
// --- deformation ---
// project the given motion to the tangent space of the solution variety and
// move the assembly along it. the implementation is based on invariant (1)
// from above and the following additional invariant:
@ -866,7 +866,7 @@ impl Assembly {
if self.tangent.with(|tan| tan.dim() <= 0 && tan.assembly_dim() > 0) {
console::log_1(&JsValue::from("The assembly is rigid"));
}
// give a column index to each moving element that doesn't have one yet.
// this temporarily breaks invariant (1), but the invariant will be
// restored when we realize the assembly at the end of the deformation.
@ -884,7 +884,7 @@ impl Assembly {
}
next_column_index
};
// project the element motions onto the tangent space of the solution
// variety and sum them to get a deformation of the whole assembly. the
// matrix `motion_proj` that holds the deformation has extra columns for
@ -895,7 +895,7 @@ impl Assembly {
// we can unwrap the column index because we know that every moving
// element has one at this point
let column_index = elt_motion.element.column_index().unwrap();
if column_index < realized_dim {
// this element had a column index when we started, so by
// invariant (1), it's reflected in the tangent space
@ -913,7 +913,7 @@ impl Assembly {
target_column += unif_to_std * elt_motion.velocity;
}
}
// step the assembly along the deformation. this changes the elements'
// normalizations, so we restore those afterward
for elt in self.elements.get_clone_untracked() {
@ -931,7 +931,7 @@ impl Assembly {
};
});
}
// 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
@ -942,9 +942,9 @@ impl Assembly {
#[cfg(test)]
mod tests {
use super::*;
use crate::engine;
#[test]
#[should_panic(expected =
"Sphere \"sphere\" must be indexed before it writes problem data")]
@ -954,7 +954,7 @@ mod tests {
elt.pose(&mut ConstraintProblem::new(1));
});
}
#[test]
#[should_panic(expected = "Subject \"sphere1\" must be indexed before \
inversive distance regulator writes problem data")]
@ -972,7 +972,7 @@ mod tests {
}.pose(&mut ConstraintProblem::new(2));
});
}
#[test]
fn curvature_drift_test() {
const INITIAL_RADIUS: f64 = 0.25;
@ -992,7 +992,7 @@ mod tests {
engine::sphere(0.0, 0.0, 0.0, INITIAL_RADIUS),
)
);
// nudge the sphere repeatedly along the `z` axis
const STEP_SIZE: f64 = 0.0025;
const STEP_CNT: usize = 400;
@ -1008,7 +1008,7 @@ mod tests {
]
);
}
// check how much the sphere's curvature has drifted
const INITIAL_HALF_CURV: f64 = 0.5 / INITIAL_RADIUS;
const DRIFT_TOL: f64 = 0.015;