noTrailingWhitespace #126

Closed
glen wants to merge 10 commits from glen/dyna3:noTrailingWhitespace into main
2 changed files with 33 additions and 54 deletions
Showing only changes of commit 50c51ca08f - Show all commits

View file

@ -31,14 +31,11 @@ The latest prototype is in the folder `app-proto`. It includes both a user inter
3. Call `rustup target add wasm32-unknown-unknown` to add the [most generic 32-bit WebAssembly target](https://doc.rust-lang.org/nightly/rustc/platform-support/wasm32-unknown-unknown.html) 3. Call `rustup target add wasm32-unknown-unknown` to add the [most generic 32-bit WebAssembly target](https://doc.rust-lang.org/nightly/rustc/platform-support/wasm32-unknown-unknown.html)
4. Call `cargo install wasm-pack` to install the [WebAssembly toolchain](https://rustwasm.github.io/docs/wasm-pack/) 4. Call `cargo install wasm-pack` to install the [WebAssembly toolchain](https://rustwasm.github.io/docs/wasm-pack/)
5. Call `cargo install trunk` to install the [Trunk](https://trunkrs.dev/) web-build tool 5. Call `cargo install trunk` to install the [Trunk](https://trunkrs.dev/) web-build tool
- In the future, `trunk` can be updated with the same command. You may - In the future, `trunk` can be updated with the same command. You may need the `--locked` flag if your ambient version of `rustc` does not match that required by `trunk`.
need the `--locked` flag if your ambient version of `rustc` does not
match that required by `trunk`.
6. Add the `.cargo/bin` folder in your home directory to your executable search path 6. Add the `.cargo/bin` folder in your home directory to your executable search path
- This lets you call Trunk, and other tools installed by Cargo, without specifying their paths - This lets you call Trunk, and other tools installed by Cargo, without specifying their paths
- On POSIX systems, the search path is stored in the `PATH` environment variable - On POSIX systems, the search path is stored in the `PATH` environment variable
- Alternatively, if you don't want to adjust your `PATH`, you can install - Alternatively, if you don't want to adjust your `PATH`, you can install `trunk` in another directory `DIR` via `cargo install --root DIR trunk`
`trunk` in another directory `DIR` via `cargo install --root DIR trunk`
### Play with the prototype ### Play with the prototype

View file

@ -86,6 +86,14 @@ impl Ord for dyn Serial {
} }
} }
// Small helper function to generate consistent errors when there
// are indexing issues in a ProblemPoser
fn indexing_error(item: &str, name: &str, actor: &str) -> String {
format!(
"{item} \"{name}\" must be indexed before {actor} writes problem data"
)
}
pub trait ProblemPoser { pub trait ProblemPoser {
fn pose(&self, problem: &mut ConstraintProblem); fn pose(&self, problem: &mut ConstraintProblem);
} }
@ -248,19 +256,12 @@ impl Serial for Sphere {
} }
} }
fn index_message(thing: &str, name: &str, actor: &str) -> String {
format!(
"{thing} \"{name}\" must be indexed before {actor} writes problem data"
)
}
impl ProblemPoser for Sphere { impl ProblemPoser for Sphere {
fn pose(&self, problem: &mut ConstraintProblem) { fn pose(&self, problem: &mut ConstraintProblem) {
let index = self.column_index().expect( let index = self.column_index().expect(
index_message("Sphere", &self.id, "it").as_str()); indexing_error("Sphere", &self.id, "it").as_str());
problem.gram.push_sym(index, index, 1.0); problem.gram.push_sym(index, index, 1.0);
problem.guess.set_column( problem.guess.set_column(index, &self.representation.get_clone_untracked());
index, &self.representation.get_clone_untracked());
} }
} }
@ -363,11 +364,10 @@ impl Serial for Point {
impl ProblemPoser for Point { impl ProblemPoser for Point {
fn pose(&self, problem: &mut ConstraintProblem) { fn pose(&self, problem: &mut ConstraintProblem) {
let index = self.column_index().expect( let index = self.column_index().expect(
index_message("Point", &self.id, "it").as_str()); indexing_error("Point", &self.id, "it").as_str());
problem.gram.push_sym(index, index, 0.0); problem.gram.push_sym(index, index, 0.0);
problem.frozen.push(Self::WEIGHT_COMPONENT, index, 0.5); problem.frozen.push(Self::WEIGHT_COMPONENT, index, 0.5);
problem.guess.set_column( problem.guess.set_column(index, &self.representation.get_clone_untracked());
index, &self.representation.get_clone_untracked());
} }
} }
@ -412,8 +412,7 @@ pub struct InversiveDistanceRegulator {
impl InversiveDistanceRegulator { impl InversiveDistanceRegulator {
pub fn new(subjects: [Rc<dyn Element>; 2]) -> Self { pub fn new(subjects: [Rc<dyn Element>; 2]) -> Self {
let representations = subjects.each_ref().map( let representations = subjects.each_ref().map(|subj| subj.representation());
|subj| subj.representation());
let measurement = create_memo(move || { let measurement = create_memo(move || {
representations[0].with(|rep_0| representations[0].with(|rep_0|
representations[1].with(|rep_1| representations[1].with(|rep_1|
@ -455,7 +454,7 @@ impl ProblemPoser for InversiveDistanceRegulator {
if let Some(val) = set_pt.value { if let Some(val) = set_pt.value {
let [row, col] = self.subjects.each_ref().map( let [row, col] = self.subjects.each_ref().map(
|subj| subj.column_index().expect( |subj| subj.column_index().expect(
index_message("Subject", subj.id(), indexing_error("Subject", subj.id(),
"inversive distance regulator").as_str()) "inversive distance regulator").as_str())
); );
problem.gram.push_sym(row, col, val); problem.gram.push_sym(row, col, val);
@ -509,7 +508,7 @@ impl ProblemPoser for HalfCurvatureRegulator {
self.set_point.with_untracked(|set_pt| { self.set_point.with_untracked(|set_pt| {
if let Some(val) = set_pt.value { if let Some(val) = set_pt.value {
let col = self.subject.column_index().expect( let col = self.subject.column_index().expect(
index_message("Subject", &self.subject.id, indexing_error("Subject", &self.subject.id,
"half-curvature regulator").as_str()); "half-curvature regulator").as_str());
problem.frozen.push(Sphere::CURVATURE_COMPONENT, col, val); problem.frozen.push(Sphere::CURVATURE_COMPONENT, col, val);
} }
@ -546,9 +545,7 @@ impl PointCoordinateRegulator {
move |rep| rep[axis as usize] move |rep| rep[axis as usize]
); );
let set_point = create_signal(SpecifiedValue::from_empty_spec()); let set_point = create_signal(SpecifiedValue::from_empty_spec());
Self { Self { subject, axis, measurement, set_point, serial: Self::next_serial() }
subject, axis, measurement, set_point, serial: Self::next_serial()
}
} }
} }
@ -567,7 +564,7 @@ impl ProblemPoser for PointCoordinateRegulator {
self.set_point.with_untracked(|set_pt| { self.set_point.with_untracked(|set_pt| {
if let Some(val) = set_pt.value { if let Some(val) = set_pt.value {
let col = self.subject.column_index().expect( let col = self.subject.column_index().expect(
index_message("Subject", &self.subject.id, indexing_error("Subject", &self.subject.id,
"point-coordinate regulator").as_str()); "point-coordinate regulator").as_str());
problem.frozen.push(self.axis as usize, col, val); problem.frozen.push(self.axis as usize, col, val);
// If all three of the subject's spatial coordinates have been // If all three of the subject's spatial coordinates have been
@ -583,9 +580,7 @@ impl ProblemPoser for PointCoordinateRegulator {
if nset == Axis::CARDINALITY { if nset == Axis::CARDINALITY {
let [x, y, z] = coords; let [x, y, z] = coords;
problem.frozen.push( problem.frozen.push(
Point::NORM_COMPONENT, Point::NORM_COMPONENT, col, point(x,y,z)[Point::NORM_COMPONENT]);
col,
point(x,y,z)[Point::NORM_COMPONENT]);
} }
} }
}); });
@ -684,8 +679,7 @@ impl Assembly {
let id = elt.id().clone(); let id = elt.id().clone();
let elt_rc = Rc::new(elt); let elt_rc = Rc::new(elt);
self.elements.update(|elts| elts.insert(elt_rc.clone())); self.elements.update(|elts| elts.insert(elt_rc.clone()));
self.elements_by_id.update( self.elements_by_id.update(|elts_by_id| elts_by_id.insert(id, elt_rc.clone()));
|elts_by_id| elts_by_id.insert(id, elt_rc.clone()));
// create and insert the element's default regulators // create and insert the element's default regulators
for reg in elt_rc.default_regulators() { for reg in elt_rc.default_regulators() {
@ -694,9 +688,7 @@ impl Assembly {
} }
pub fn try_insert_element(&self, elt: impl Element + 'static) -> bool { pub fn try_insert_element(&self, elt: impl Element + 'static) -> bool {
let can_insert = self.elements_by_id.with_untracked( let can_insert = self.elements_by_id.with_untracked(|elts_by_id| !elts_by_id.contains_key(elt.id()));
|elts_by_id| !elts_by_id.contains_key(elt.id())
);
if can_insert { if can_insert {
self.insert_element_unchecked(elt); self.insert_element_unchecked(elt);
} }
@ -761,8 +753,7 @@ impl Assembly {
pub fn load_config(&self, config: &DMatrix<f64>) { pub fn load_config(&self, config: &DMatrix<f64>) {
for elt in self.elements.get_clone_untracked() { for elt in self.elements.get_clone_untracked() {
elt.representation().update( elt.representation().update(
|rep| rep.set_column( |rep| rep.set_column(0, &config.column(elt.column_index().unwrap()))
0, &config.column(elt.column_index().unwrap()))
); );
} }
} }
@ -907,8 +898,7 @@ impl Assembly {
if column_index < realized_dim { if column_index < realized_dim {
// this element had a column index when we started, so by // this element had a column index when we started, so by
// invariant (1), it's reflected in the tangent space // invariant (1), it's reflected in the tangent space
let mut target_columns = let mut target_columns = motion_proj.columns_mut(0, realized_dim);
motion_proj.columns_mut(0, realized_dim);
target_columns += self.tangent.with( target_columns += self.tangent.with(
|tan| tan.proj(&elt_motion.velocity, column_index) |tan| tan.proj(&elt_motion.velocity, column_index)
); );
@ -916,10 +906,9 @@ impl Assembly {
// this element didn't have a column index when we started, so // this element didn't have a column index when we started, so
// by invariant (2), it's unconstrained // by invariant (2), it's unconstrained
let mut target_column = motion_proj.column_mut(column_index); let mut target_column = motion_proj.column_mut(column_index);
let unif_to_std = elt_motion let unif_to_std = elt_motion.element.representation().with_untracked(
.element.representation() |rep| local_unif_to_std(rep.as_view())
.with_untracked( );
|rep| local_unif_to_std(rep.as_view()));
target_column += unif_to_std * elt_motion.velocity; target_column += unif_to_std * elt_motion.velocity;
} }
} }
@ -936,9 +925,7 @@ impl Assembly {
elt.project_to_normalized(rep); elt.project_to_normalized(rep);
}, },
None => { None => {
console_log!( console_log!("No velocity to unpack for fresh element \"{}\"", elt.id())
"No velocity to unpack for fresh element \"{}\"",
elt.id())
}, },
}; };
}); });
@ -973,15 +960,13 @@ inversive distance regulator writes problem data")]
fn unindexed_subject_test_inversive_distance() { fn unindexed_subject_test_inversive_distance() {
let _ = create_root(|| { let _ = create_root(|| {
let subjects = [0, 1].map( let subjects = [0, 1].map(
|k| Rc::new(Sphere::default( |k| Rc::new(Sphere::default(format!("sphere{k}"), k)) as Rc<dyn Element>
format!("sphere{k}"), k)) as Rc<dyn Element>
); );
subjects[0].set_column_index(0); subjects[0].set_column_index(0);
InversiveDistanceRegulator { InversiveDistanceRegulator {
subjects: subjects, subjects: subjects,
measurement: create_memo(|| 0.0), measurement: create_memo(|| 0.0),
set_point: create_signal( set_point: create_signal(SpecifiedValue::try_from("0.0".to_string()).unwrap()),
SpecifiedValue::try_from("0.0".to_string()).unwrap()),
serial: InversiveDistanceRegulator::next_serial() serial: InversiveDistanceRegulator::next_serial()
}.pose(&mut ConstraintProblem::new(2)); }.pose(&mut ConstraintProblem::new(2));
}); });
@ -1010,10 +995,8 @@ inversive distance regulator writes problem data")]
// nudge the sphere repeatedly along the `z` axis // nudge the sphere repeatedly along the `z` axis
const STEP_SIZE: f64 = 0.0025; const STEP_SIZE: f64 = 0.0025;
const STEP_CNT: usize = 400; const STEP_CNT: usize = 400;
let sphere = assembly.elements_by_id.with( let sphere = assembly.elements_by_id.with(|elts_by_id| elts_by_id[sphere_id].clone());
|elts_by_id| elts_by_id[sphere_id].clone()); let velocity = DVector::from_column_slice(&[0.0, 0.0, STEP_SIZE, 0.0]);
let velocity =
DVector::from_column_slice(&[0.0, 0.0, STEP_SIZE, 0.0]);
for _ in 0..STEP_CNT { for _ in 0..STEP_CNT {
assembly.deform( assembly.deform(
vec![ vec![
@ -1031,8 +1014,7 @@ inversive distance regulator writes problem data")]
let final_half_curv = sphere.representation().with_untracked( let final_half_curv = sphere.representation().with_untracked(
|rep| rep[Sphere::CURVATURE_COMPONENT] |rep| rep[Sphere::CURVATURE_COMPONENT]
); );
assert!((final_half_curv / INITIAL_HALF_CURV - 1.0).abs() assert!((final_half_curv / INITIAL_HALF_CURV - 1.0).abs() < DRIFT_TOL);
< DRIFT_TOL);
}); });
} }
} }