forked from StudioInfinity/dyna3
chore: remove trailing whitespace, add CR at end of file
This commit is contained in:
parent
a4b355d943
commit
3635abc562
11 changed files with 320 additions and 320 deletions
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue