chore: wrap at 80 characters #128

Open
glen wants to merge 3 commits from glen/dyna3:aroundLineInEightyChars into main
6 changed files with 259 additions and 224 deletions
Showing only changes of commit 760e811ee4 - Show all commits

View file

@ -261,8 +261,8 @@ impl ProblemPoser for Sphere {
let index = self.column_index().expect( let index = self.column_index().expect(
indexing_error("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
index, &self.representation.get_clone_untracked()); .set_column(index, &self.representation.get_clone_untracked());
} }
} }
@ -368,8 +368,8 @@ impl ProblemPoser for Point {
indexing_error("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
index, &self.representation.get_clone_untracked()); .set_column(index, &self.representation.get_clone_untracked());
} }
} }
@ -414,8 +414,8 @@ 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()
|subj| subj.representation()); .map(|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|
@ -584,8 +584,11 @@ 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(Point::NORM_COMPONENT, problem.frozen.push(
col, point(x,y,z)[Point::NORM_COMPONENT]); Point::NORM_COMPONENT,
col,
point(x,y,z)[Point::NORM_COMPONENT]

Our current convention is to put spaces after the commas between arguments.

Our current convention is to put spaces after the commas between arguments.
);
} }
} }
}); });
@ -684,8 +687,8 @@ 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
|elts_by_id| elts_by_id.insert(id, elt_rc.clone())); .update(|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() {
@ -760,8 +763,8 @@ 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()
|rep| rep.set_column( .update(|rep| rep.set_column(
0, &config.column(elt.column_index().unwrap())) 0, &config.column(elt.column_index().unwrap()))
); );
} }
@ -907,19 +910,16 @@ 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
|tan| tan.proj(&elt_motion.velocity, column_index) .with(|tan| tan.proj(&elt_motion.velocity, column_index));
);
} else { } else {
// 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 = let unif_to_std = elt_motion.element.representation()
elt_motion.element.representation().with_untracked( .with_untracked(|rep| local_unif_to_std(rep.as_view()));
|rep| local_unif_to_std(rep.as_view())
);
target_column += unif_to_std * elt_motion.velocity; target_column += unif_to_std * elt_motion.velocity;
} }
} }
@ -973,10 +973,9 @@ mod tests {
inversive distance regulator writes problem data")] 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]
|k| Rc::new( .map(|k| Rc::new(Sphere::default(format!("sphere{k}"), k))
Sphere::default(format!("sphere{k}"), k)) as Rc<dyn Element> as Rc<dyn Element>);

I find (2) above most readable when more than one dot item is chained, so I guess I'd be fine with switching back to Python-style hanging indent for single method calls. I realize that this is what you had in the previous commit, and I apologize for the flip-flop. I think I'm going to have to give up on finding a compromise position on (1) and just deal with formatting I find difficult to read until we use Husht to switch to a non-C-like syntax.

I find (2) above most readable when more than one dot item is chained, so I guess I'd be fine with switching back to Python-style hanging indent for single method calls. I realize that this is what you had in the previous commit, and I apologize for the flip-flop. I think I'm going to have to give up on finding a compromise position on (1) and just deal with formatting I find difficult to read until we use Husht to switch to a non-C-like syntax.
);
subjects[0].set_column_index(0); subjects[0].set_column_index(0);
InversiveDistanceRegulator { InversiveDistanceRegulator {
subjects: subjects, subjects: subjects,
@ -1011,10 +1010,10 @@ mod tests {
// 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
|elts_by_id| elts_by_id[sphere_id].clone()); .with(|elts_by_id| elts_by_id[sphere_id].clone());
let velocity = let velocity
DVector::from_column_slice(&[0.0, 0.0, STEP_SIZE, 0.0]); = 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![

View file

@ -50,8 +50,8 @@ impl SceneSpheres {
} }
fn len_i32(&self) -> i32 { fn len_i32(&self) -> i32 {
self.representations.len().try_into().expect( self.representations.len().try_into()
"Number of spheres must fit in a 32-bit integer") .expect("Number of spheres must fit in a 32-bit integer")
} }
fn push( fn push(
@ -128,12 +128,14 @@ impl DisplayItem for Sphere {
const HIGHLIGHT: f32 = 0.2; const HIGHLIGHT: f32 = 0.2;
let representation = self.representation.get_clone_untracked(); let representation = self.representation.get_clone_untracked();
let color = let color = if selected {
if selected { self.color.map(|channel| 0.2 + 0.8*channel) } self.color.map(|channel| 0.2 + 0.8*channel)
else { self.color }; } else {
let opacity = self.color
if self.ghost.get() { GHOST_OPACITY } };
else { DEFAULT_OPACITY }; let opacity = if self.ghost.get() {
GHOST_OPACITY
} else { DEFAULT_OPACITY };
let highlight = if selected { 1.0 } else { HIGHLIGHT }; let highlight = if selected { 1.0 } else { HIGHLIGHT };
scene.spheres.push(representation, color, opacity, highlight); scene.spheres.push(representation, color, opacity, highlight);
} }
@ -150,8 +152,8 @@ impl DisplayItem for Sphere {
// `a*u^2 + b*u + c` by the linear function `b*u + c` // `a*u^2 + b*u + c` by the linear function `b*u + c`
const DEG_THRESHOLD: f64 = 1e-9; const DEG_THRESHOLD: f64 = 1e-9;
let rep = self.representation.with_untracked( let rep = self.representation
|rep| assembly_to_world * rep); .with_untracked(|rep| assembly_to_world * rep);
let a = -rep[3] * dir.norm_squared(); let a = -rep[3] * dir.norm_squared();
let b = rep.rows_range(..3).dot(&dir); let b = rep.rows_range(..3).dot(&dir);
let c = -rep[4]; let c = -rep[4];
@ -192,9 +194,9 @@ impl DisplayItem for Point {
const HIGHLIGHT: f32 = 0.5; const HIGHLIGHT: f32 = 0.5;
let representation = self.representation.get_clone_untracked(); let representation = self.representation.get_clone_untracked();
let color = let color = if selected {
if selected { self.color.map(|channel| 0.2 + 0.8*channel) } self.color.map(|channel| 0.2 + 0.8*channel)
else { self.color }; } else { self.color };
let opacity = if self.ghost.get() { GHOST_OPACITY } else { 1.0 }; let opacity = if self.ghost.get() { GHOST_OPACITY } else { 1.0 };
let highlight = if selected { 1.0 } else { HIGHLIGHT }; let highlight = if selected { 1.0 } else { HIGHLIGHT };
scene.points.push(representation, color, opacity, highlight, selected); scene.points.push(representation, color, opacity, highlight, selected);
@ -207,8 +209,8 @@ impl DisplayItem for Point {
assembly_to_world: &DMatrix<f64>, assembly_to_world: &DMatrix<f64>,
pixel_size: f64, pixel_size: f64,
) -> Option<f64> { ) -> Option<f64> {
let rep = self.representation.with_untracked( let rep = self.representation
|rep| assembly_to_world * rep); .with_untracked(|rep| assembly_to_world * rep);
if rep[2] < 0.0 { if rep[2] < 0.0 {
// this constant should be kept synchronized with `point.frag` // this constant should be kept synchronized with `point.frag`
const POINT_RADIUS_PX: f64 = 4.0; const POINT_RADIUS_PX: f64 = 4.0;
@ -366,12 +368,12 @@ fn event_dir(event: &MouseEvent) -> (Vector3<f64>, f64) {
// this constant should be kept synchronized with `spheres.frag` and // this constant should be kept synchronized with `spheres.frag` and
// `point.vert` // `point.vert`
const FOCAL_SLOPE: f64 = 0.3; const FOCAL_SLOPE: f64 = 0.3;
let horizontal = f64::from(event.client_x()) - rect.left(); let x_relative = f64::from(event.client_x()) - rect.left();
let vertical = rect.bottom() - f64::from(event.client_y()); let y_relative = rect.bottom() - f64::from(event.client_y());
( (
Vector3::new( Vector3::new(
FOCAL_SLOPE * (2.0*horizontal - width) / shortdim, FOCAL_SLOPE * (2.0*x_relative - width) / shortdim,
FOCAL_SLOPE * (2.0*vertical - height) / shortdim, FOCAL_SLOPE * (2.0*y_relative - height) / shortdim,
-1.0, -1.0,
), ),
FOCAL_SLOPE * 2.0 / shortdim, FOCAL_SLOPE * 2.0 / shortdim,
@ -455,8 +457,8 @@ pub fn Display() -> View {
let performance = window().unwrap().performance().unwrap(); let performance = window().unwrap().performance().unwrap();
// get the display canvas // get the display canvas
let canvas = let canvas
display.get().unchecked_into::<web_sys::HtmlCanvasElement>(); = display.get().unchecked_into::<web_sys::HtmlCanvasElement>();
let ctx = canvas let ctx = canvas
.get_context("webgl2") .get_context("webgl2")
.unwrap() .unwrap()
@ -469,8 +471,10 @@ pub fn Display() -> View {
// set blend mode // set blend mode
ctx.enable(WebGl2RenderingContext::BLEND); ctx.enable(WebGl2RenderingContext::BLEND);
ctx.blend_func(WebGl2RenderingContext::SRC_ALPHA, ctx.blend_func(
WebGl2RenderingContext::ONE_MINUS_SRC_ALPHA); WebGl2RenderingContext::SRC_ALPHA,
WebGl2RenderingContext::ONE_MINUS_SRC_ALPHA,
);
// set up the sphere rendering program // set up the sphere rendering program
let sphere_program = set_up_program( let sphere_program = set_up_program(
@ -500,19 +504,19 @@ pub fn Display() -> View {
// capped at 1024 elements // capped at 1024 elements
console::log_2( console::log_2(
&ctx.get_parameter( &ctx.get_parameter(
WebGl2RenderingContext::MAX_FRAGMENT_UNIFORM_VECTORS).unwrap(), WebGl2RenderingContext::MAX_FRAGMENT_UNIFORM_VECTORS
).unwrap(),
&JsValue::from("uniform vectors available"), &JsValue::from("uniform vectors available"),
); );
// find the sphere program's vertex attribute // find the sphere program's vertex attribute
let viewport_position_attr = let viewport_position_attr = ctx
ctx.get_attrib_location(&sphere_program, "position") as u32; .get_attrib_location(&sphere_program, "position") as u32;
// find the sphere program's uniforms // find the sphere program's uniforms
const SPHERE_MAX: usize = 200; const SPHERE_MAX: usize = 200;
let sphere_cnt_loc = ctx.get_uniform_location( let sphere_cnt_loc = ctx
&sphere_program, "sphere_cnt" .get_uniform_location(&sphere_program, "sphere_cnt");
);
let sphere_sp_locs = get_uniform_array_locations::<SPHERE_MAX>( let sphere_sp_locs = get_uniform_array_locations::<SPHERE_MAX>(
&ctx, &sphere_program, "sphere_list", Some("sp") &ctx, &sphere_program, "sphere_list", Some("sp")
); );
@ -525,18 +529,14 @@ pub fn Display() -> View {
let sphere_highlight_locs = get_uniform_array_locations::<SPHERE_MAX>( let sphere_highlight_locs = get_uniform_array_locations::<SPHERE_MAX>(
&ctx, &sphere_program, "highlight_list", None &ctx, &sphere_program, "highlight_list", None
); );
let resolution_loc = ctx.get_uniform_location( let resolution_loc = ctx
&sphere_program, "resolution" .get_uniform_location(&sphere_program, "resolution");
); let shortdim_loc = ctx
let shortdim_loc = ctx.get_uniform_location( .get_uniform_location(&sphere_program, "shortdim");
&sphere_program, "shortdim" let layer_threshold_loc = ctx
); .get_uniform_location(&sphere_program, "layer_threshold");
let layer_threshold_loc = ctx.get_uniform_location( let debug_mode_loc = ctx
&sphere_program, "layer_threshold" .get_uniform_location(&sphere_program, "debug_mode");
);
let debug_mode_loc = ctx.get_uniform_location(
&sphere_program, "debug_mode"
);
// load the viewport vertex positions into a new vertex buffer object // load the viewport vertex positions into a new vertex buffer object
const VERTEX_CNT: usize = 6; const VERTEX_CNT: usize = 6;
@ -550,18 +550,18 @@ pub fn Display() -> View {
1.0, 1.0, 0.0, 1.0, 1.0, 0.0,
1.0, -1.0, 0.0, 1.0, -1.0, 0.0,
]; ];
let viewport_position_buffer = let viewport_position_buffer
load_new_buffer(&ctx, &viewport_positions); = load_new_buffer(&ctx, &viewport_positions);
// find the point program's vertex attributes // find the point program's vertex attributes
let point_position_attr = let point_position_attr = ctx
ctx.get_attrib_location(&point_program, "position") as u32; .get_attrib_location(&point_program, "position") as u32;
let point_color_attr = let point_color_attr = ctx
ctx.get_attrib_location(&point_program, "color") as u32; .get_attrib_location(&point_program, "color") as u32;
let point_highlight_attr = let point_highlight_attr = ctx
ctx.get_attrib_location(&point_program, "highlight") as u32; .get_attrib_location(&point_program, "highlight") as u32;
let point_selection_attr = let point_selection_attr = ctx
ctx.get_attrib_location(&point_program, "selected") as u32; .get_attrib_location(&point_program, "selected") as u32;
// set up a repainting routine // set up a repainting routine
let (_, start_animation_loop, _) = create_raf(move || { let (_, start_animation_loop, _) = create_raf(move || {
@ -625,8 +625,8 @@ pub fn Display() -> View {
let realization_successful = state.assembly.realization_status.with( let realization_successful = state.assembly.realization_status.with(
|status| status.is_ok() |status| status.is_ok()
); );
let step_val = let step_val = state.assembly
state.assembly.step.with_untracked(|step| step.value); .step.with_untracked(|step| step.value);
let on_init_step = step_val.is_some_and(|n| n == 0.0); let on_init_step = step_val.is_some_and(|n| n == 0.0);
let on_last_step = step_val.is_some_and( let on_last_step = step_val.is_some_and(
|n| state.assembly.descent_history.with_untracked( |n| state.assembly.descent_history.with_untracked(
@ -637,7 +637,8 @@ pub fn Display() -> View {
!realization_successful && on_init_step !realization_successful && on_init_step
|| realization_successful && on_last_step; || realization_successful && on_last_step;
if on_manipulable_step if on_manipulable_step
&& state.selection.with(|sel| sel.len() == 1) { && state.selection.with(|sel| sel.len() == 1)
{
let sel = state.selection.with( let sel = state.selection.with(
|sel| sel.into_iter().next().unwrap().clone() |sel| sel.into_iter().next().unwrap().clone()
); );
@ -682,8 +683,8 @@ pub fn Display() -> View {
// measure mean frame interval // measure mean frame interval
frames_since_last_sample += 1; frames_since_last_sample += 1;
if frames_since_last_sample >= SAMPLE_PERIOD { if frames_since_last_sample >= SAMPLE_PERIOD {
mean_frame_interval.set( let SP64 = SAMPLE_PERIOD as f64;
(time - last_sample_time) / (SAMPLE_PERIOD as f64)); mean_frame_interval.set((time - last_sample_time) / SP64);

Well that's how it was, but i was trying to accommodate the preference for breaking at a method call instead of within the arguments.

Oh, I see. Like I said above, I may have to just accept going back to Python-style hanging indent for function calls and deal with the cognitive dissonance until we get to a non-C-like syntax with Husht.

What else might we call the local abbreviation for the coercion of the global constant with the very long name?

I'd use sample_period_f64.

> Well that's how it was, but i was trying to accommodate the preference for breaking at a method call instead of within the arguments. Oh, I see. Like I said [above](https://code.studioinfinity.org/StudioInfinity/dyna3/pulls/128#issuecomment-3492), I may have to just accept going back to Python-style hanging indent for function calls and deal with the cognitive dissonance until we get to a non-C-like syntax with Husht. > What else might we call the local abbreviation for the coercion of the global constant with the very long name? I'd use `sample_period_f64`.

Well, that's too long to avoid the line break, so ok, I will revert to the function call being split across lines.

Well, that's too long to avoid the line break, so ok, I will revert to the function call being split across lines.

Oh, actually it fits on two lines like this

                    mean_frame_interval
                        .set((time - last_sample_time) / SAMPLE_PERIOD as f64);

which I presume you like better. Don't know why I didn't see that before. So will do that in the next revision.

Oh, actually it fits on two lines like this ``` mean_frame_interval .set((time - last_sample_time) / SAMPLE_PERIOD as f64); ``` which I presume you like better. Don't know why I didn't see that before. So will do that in the next revision.
last_sample_time = time; last_sample_time = time;
frames_since_last_sample = 0; frames_since_last_sample = 0;
} }
@ -708,8 +709,8 @@ pub fn Display() -> View {
// set up the scene // set up the scene
state.assembly.elements.with_untracked( state.assembly.elements.with_untracked(
|elts| for elt in elts { |elts| for elt in elts {
let selected = let selected = state.selection
state.selection.with(|sel| sel.contains(elt)); .with(|sel| sel.contains(elt));
elt.show(&mut scene, selected); elt.show(&mut scene, selected);
} }
); );
@ -724,8 +725,8 @@ pub fn Display() -> View {
ctx.enable_vertex_attrib_array(viewport_position_attr); ctx.enable_vertex_attrib_array(viewport_position_attr);
// write the spheres in world coordinates // write the spheres in world coordinates
let sphere_reps_world: Vec<_> = let sphere_reps_world: Vec<_> = scene.spheres.representations
scene.spheres.representations.into_iter().map( .into_iter().map(
|rep| (&asm_to_world * rep).cast::<f32>() |rep| (&asm_to_world * rep).cast::<f32>()
).collect(); ).collect();
@ -763,12 +764,14 @@ pub fn Display() -> View {
// bind the viewport vertex position buffer to the position // bind the viewport vertex position buffer to the position
// attribute in the vertex shader // attribute in the vertex shader
bind_to_attribute(&ctx, viewport_position_attr, bind_to_attribute(
SPACE_DIM as i32, &viewport_position_buffer); &ctx, viewport_position_attr,
SPACE_DIM as i32, &viewport_position_buffer,
);
// draw the scene // draw the scene
ctx.draw_arrays(WebGl2RenderingContext::TRIANGLES, 0, ctx.draw_arrays(
VERTEX_CNT as i32); WebGl2RenderingContext::TRIANGLES, 0, VERTEX_CNT as i32);
// disable the sphere program's vertex attribute // disable the sphere program's vertex attribute
ctx.disable_vertex_attrib_array(viewport_position_attr); ctx.disable_vertex_attrib_array(viewport_position_attr);
@ -796,19 +799,28 @@ pub fn Display() -> View {
// load the point positions and colors into new buffers and // load the point positions and colors into new buffers and
// bind them to the corresponding attributes in the vertex // bind them to the corresponding attributes in the vertex
// shader // shader
bind_new_buffer_to_attribute(&ctx, point_position_attr, bind_new_buffer_to_attribute(
SPACE_DIM as i32, point_positions.as_slice()); &ctx, point_position_attr,
SPACE_DIM as i32, point_positions.as_slice(),
);
bind_new_buffer_to_attribute(&ctx, point_color_attr, bind_new_buffer_to_attribute(&ctx, point_color_attr,
(COLOR_SIZE + 1) as i32, (COLOR_SIZE + 1) as i32,
scene.points.colors_with_opacity.concat().as_slice()); scene.points.colors_with_opacity.concat().as_slice());
bind_new_buffer_to_attribute(&ctx, point_highlight_attr, bind_new_buffer_to_attribute(
1i32, scene.points.highlights.as_slice()); &ctx, point_highlight_attr,
bind_new_buffer_to_attribute(&ctx, point_selection_attr, 1i32, scene.points.highlights.as_slice(),
1i32, scene.points.selections.as_slice()); );
bind_new_buffer_to_attribute(
&ctx, point_selection_attr,
1i32, scene.points.selections.as_slice(),
);
// draw the scene // draw the scene
ctx.draw_arrays(WebGl2RenderingContext::POINTS, 0, ctx.draw_arrays(
point_positions.ncols() as i32); WebGl2RenderingContext::POINTS,
0,
point_positions.ncols() as i32,
);
// disable the point program's vertex attributes // disable the point program's vertex attributes
ctx.disable_vertex_attrib_array(point_position_attr); ctx.disable_vertex_attrib_array(point_position_attr);
@ -957,9 +969,9 @@ pub fn Display() -> View {
.into_iter() .into_iter()
.filter(|elt| !elt.ghost().get()); .filter(|elt| !elt.ghost().get());
for elt in tangible_elts { for elt in tangible_elts {
let target = assembly_to_world.with( let hit = assembly_to_world.with(
|asm_to_world| elt.cast(dir, asm_to_world, pixel_size)); |asm_to_world| elt.cast(dir, asm_to_world, pixel_size));
match target { match hit {
Some(depth) => match clicked { Some(depth) => match clicked {
Some((_, best_depth)) => { Some((_, best_depth)) => {
if depth < best_depth { if depth < best_depth {

View file

@ -63,8 +63,8 @@ fn RegulatorInput(regulator: Rc<dyn Regulator>) -> View {
placeholder = measurement.with(|result| result.to_string()), placeholder = measurement.with(|result| result.to_string()),
bind:value = value, bind:value = value,
on:change = move |_| { on:change = move |_| {
let specification = let specification
SpecifiedValue::try_from(value.get_clone_untracked()); = SpecifiedValue::try_from(value.get_clone_untracked());

Since this is a single use temporary introduced just for the sake of an abbreviation, and its single use is on the very next line, I just called it val.

Since this is a single use temporary introduced just for the sake of an abbreviation, and its single use is on the very next line, I just called it `val`.
valid.set( valid.set(
match specification { match specification {
Ok(set_pt) => { Ok(set_pt) => {
@ -179,8 +179,10 @@ fn ElementOutlineItem(element: Rc<dyn Element>) -> View {
move |event: KeyboardEvent| { move |event: KeyboardEvent| {
match event.key().as_str() { match event.key().as_str() {
"Enter" => { "Enter" => {
state.select(&element_for_handler, state.select(
event.shift_key()); &element_for_handler,
event.shift_key(),
);
event.prevent_default(); event.prevent_default();
}, },
"ArrowRight" if regulated.get() => { "ArrowRight" if regulated.get() => {
@ -210,8 +212,8 @@ fn ElementOutlineItem(element: Rc<dyn Element>) -> View {
let state_for_handler = state.clone(); let state_for_handler = state.clone();
let element_for_handler = element.clone(); let element_for_handler = element.clone();
move |event: MouseEvent| { move |event: MouseEvent| {
state_for_handler.select(&element_for_handler, state_for_handler.select(
event.shift_key()); &element_for_handler, event.shift_key());
event.stop_propagation(); event.stop_propagation();
event.prevent_default(); event.prevent_default();
} }
@ -224,8 +226,8 @@ fn ElementOutlineItem(element: Rc<dyn Element>) -> View {
input( input(
r#type = "checkbox", r#type = "checkbox",
bind:checked = element.ghost(), bind:checked = element.ghost(),
on:click = on:click
|event: MouseEvent| event.stop_propagation() = |event: MouseEvent| event.stop_propagation()
) )
} }
} }

View file

@ -225,8 +225,8 @@ void main() {
// highlight cusps // highlight cusps
float cusp_cos = abs(dot(dir, frag.normal)); float cusp_cos = abs(dot(dir, frag.normal));
float cusp_threshold = 2.*sqrt( float cusp_threshold
ixn_threshold * sphere_list[hit.id].lt.s); = 2.*sqrt( ixn_threshold * sphere_list[hit.id].lt.s);
float cusp_highlight = highlight * (1. - smoothstep( float cusp_highlight = highlight * (1. - smoothstep(
2./3.*cusp_threshold, 1.5*cusp_threshold, cusp_cos)); 2./3.*cusp_threshold, 1.5*cusp_threshold, cusp_cos));
frag.color = mix(frag.color, vec4(1.), cusp_highlight); frag.color = mix(frag.color, vec4(1.), cusp_highlight);

View file

@ -167,36 +167,37 @@ fn load_low_curvature(assembly: &Assembly) {
let curvature = plane.regulators().with_untracked( let curvature = plane.regulators().with_untracked(
|regs| regs.first().unwrap().clone() |regs| regs.first().unwrap().clone()
); );
curvature.set_point().set( curvature.set_point()
SpecifiedValue::try_from("0".to_string()).unwrap()); .set(SpecifiedValue::try_from("0".to_string()).unwrap());
} }
let all_perpendicular = [central.clone()].into_iter() let all_perpendicular = [central.clone()].into_iter()
.chain(sides.clone()) .chain(sides.clone())
.chain(corners.clone()); .chain(corners.clone());
for sphere in all_perpendicular { for sphere in all_perpendicular {
// make each side and packed sphere perpendicular to the assembly plane // make each side and packed sphere perpendicular to the assembly plane
let right_angle = InversiveDistanceRegulator::new( let right_angle
[sphere, assemb_plane.clone()]); = InversiveDistanceRegulator::new([sphere, assemb_plane.clone()]);
right_angle.set_point.set( right_angle.set_point
SpecifiedValue::try_from("0".to_string()).unwrap()); .set(SpecifiedValue::try_from("0".to_string()).unwrap());
assembly.insert_regulator(Rc::new(right_angle)); assembly.insert_regulator(Rc::new(right_angle));
} }
for sphere in sides.clone().chain(corners.clone()) { for sphere in sides.clone().chain(corners.clone()) {
// make each side and corner sphere tangent to the central sphere // make each side and corner sphere tangent to the central sphere
let tangency = InversiveDistanceRegulator::new( let tangency = InversiveDistanceRegulator::new([
[sphere.clone(), central.clone()]); sphere.clone(), central.clone()
tangency.set_point.set( ]);
SpecifiedValue::try_from("-1".to_string()).unwrap()); tangency.set_point
.set(SpecifiedValue::try_from("-1".to_string()).unwrap());
assembly.insert_regulator(Rc::new(tangency)); assembly.insert_regulator(Rc::new(tangency));
} }
for (side_index, side) in sides.enumerate() { for (side_index, side) in sides.enumerate() {
// make each side tangent to the two adjacent corner spheres // make each side tangent to the two adjacent corner spheres
for (corner_index, corner) in corners.clone().enumerate() { for (corner_index, corner) in corners.clone().enumerate() {
if side_index != corner_index { if side_index != corner_index {
let tangency = InversiveDistanceRegulator::new( let tangency
[side.clone(), corner]); = InversiveDistanceRegulator::new([side.clone(), corner]);
tangency.set_point.set( tangency.set_point
SpecifiedValue::try_from("-1".to_string()).unwrap()); .set(SpecifiedValue::try_from("-1".to_string()).unwrap());
assembly.insert_regulator(Rc::new(tangency)); assembly.insert_regulator(Rc::new(tangency));
} }
} }
@ -226,13 +227,13 @@ fn load_pointed(assembly: &Assembly) {
let y = index_y as f64 - 0.5; let y = index_y as f64 - 0.5;
let x32 = x as f32; let x32 = x as f32;
let y32 = y as f32; let y32 = y as f32;
let coords = let color
[0.5*(1.0 + x32), 0.5*(1.0 + y32), 0.5*(1.0 - x32*y32)]; = [0.5*(1.0 + x32), 0.5*(1.0 + y32), 0.5*(1.0 - x32*y32)];
let _ = assembly.try_insert_element( let _ = assembly.try_insert_element(
Sphere::new( Sphere::new(
format!("sphere{index_x}{index_y}"), format!("sphere{index_x}{index_y}"),
format!("Sphere {index_x}{index_y}"), format!("Sphere {index_x}{index_y}"),
coords, color,
engine::sphere(x, y, 0.0, 1.0), engine::sphere(x, y, 0.0, 1.0),
) )
); );
@ -241,7 +242,7 @@ fn load_pointed(assembly: &Assembly) {
Point::new( Point::new(
format!("point{index_x}{index_y}"), format!("point{index_x}{index_y}"),
format!("Point {index_x}{index_y}"), format!("Point {index_x}{index_y}"),
coords, color,
engine::point(x, y, 0.0), engine::point(x, y, 0.0),
) )
); );
@ -332,7 +333,8 @@ fn load_tridiminished_icosahedron(assembly: &Assembly) {
COLOR_FACE, COLOR_FACE,
engine::sphere_with_offset( engine::sphere_with_offset(
frac_2_sqrt_6, -frac_1_sqrt_6, -frac_1_sqrt_6, frac_2_sqrt_6, -frac_1_sqrt_6, -frac_1_sqrt_6,
-frac_1_sqrt_6, 0.0), -frac_1_sqrt_6, 0.0
),
), ),
Sphere::new( Sphere::new(
"face2".to_string(), "face2".to_string(),
@ -340,7 +342,8 @@ fn load_tridiminished_icosahedron(assembly: &Assembly) {
COLOR_FACE, COLOR_FACE,
engine::sphere_with_offset( engine::sphere_with_offset(
-frac_1_sqrt_6, frac_2_sqrt_6, -frac_1_sqrt_6, -frac_1_sqrt_6, frac_2_sqrt_6, -frac_1_sqrt_6,
-frac_1_sqrt_6, 0.0), -frac_1_sqrt_6, 0.0
),
), ),
Sphere::new( Sphere::new(
"face3".to_string(), "face3".to_string(),
@ -348,7 +351,8 @@ fn load_tridiminished_icosahedron(assembly: &Assembly) {
COLOR_FACE, COLOR_FACE,
engine::sphere_with_offset( engine::sphere_with_offset(
-frac_1_sqrt_6, -frac_1_sqrt_6, frac_2_sqrt_6, -frac_1_sqrt_6, -frac_1_sqrt_6, frac_2_sqrt_6,
-frac_1_sqrt_6, 0.0), -frac_1_sqrt_6, 0.0
),
), ),
]; ];
for face in faces { for face in faces {
@ -373,10 +377,11 @@ fn load_tridiminished_icosahedron(assembly: &Assembly) {
let vertex_a = assembly.elements_by_id.with_untracked( let vertex_a = assembly.elements_by_id.with_untracked(
|elts_by_id| elts_by_id[&format!("a{j}")].clone() |elts_by_id| elts_by_id[&format!("a{j}")].clone()
); );
let incidence_a = InversiveDistanceRegulator::new( let incidence_a = InversiveDistanceRegulator::new([
[face.clone(), vertex_a.clone()]); face.clone(), vertex_a.clone()
incidence_a.set_point.set( ]);
SpecifiedValue::try_from("0".to_string()).unwrap()); incidence_a.set_point
.set(SpecifiedValue::try_from("0".to_string()).unwrap());
assembly.insert_regulator(Rc::new(incidence_a)); assembly.insert_regulator(Rc::new(incidence_a));
// regulate the B-C vertex distances // regulate the B-C vertex distances
@ -398,16 +403,18 @@ fn load_tridiminished_icosahedron(assembly: &Assembly) {
let vertex = assembly.elements_by_id.with_untracked( let vertex = assembly.elements_by_id.with_untracked(
|elts_by_id| elts_by_id[&format!("{series}{k}")].clone() |elts_by_id| elts_by_id[&format!("{series}{k}")].clone()
); );
let incidence = InversiveDistanceRegulator::new( let incidence = InversiveDistanceRegulator::new([
[face.clone(), vertex.clone()]); face.clone(), vertex.clone()
incidence.set_point.set( ]);
SpecifiedValue::try_from("0".to_string()).unwrap()); incidence.set_point
.set(SpecifiedValue::try_from("0".to_string()).unwrap());
assembly.insert_regulator(Rc::new(incidence)); assembly.insert_regulator(Rc::new(incidence));
// regulate the A-B and A-C vertex distances // regulate the A-B and A-C vertex distances
assembly.insert_regulator( assembly.insert_regulator(
Rc::new(InversiveDistanceRegulator::new( Rc::new(InversiveDistanceRegulator::new([
[vertex_a.clone(), vertex])) vertex_a.clone(), vertex
]))
); );
} }
} }
@ -523,16 +530,18 @@ fn load_dodecahedral_packing(assembly: &Assembly) {
// make each face sphere perpendicular to the substrate // make each face sphere perpendicular to the substrate
for face in faces { for face in faces {
let right_angle = InversiveDistanceRegulator::new( let right_angle = InversiveDistanceRegulator::new([
[face, substrate.clone()]); face, substrate.clone()
right_angle.set_point.set( ]);
SpecifiedValue::try_from("0".to_string()).unwrap()); right_angle.set_point
.set(SpecifiedValue::try_from("0".to_string()).unwrap());
assembly.insert_regulator(Rc::new(right_angle)); assembly.insert_regulator(Rc::new(right_angle));
} }
// set up the tangencies that define the packing // set up the tangencies that define the packing
for [long_edge_plane, short_edge_plane] for [long_edge_plane, short_edge_plane]
in [["a", "b"], ["b", "c"], ["c", "a"]] { in [["a", "b"], ["b", "c"], ["c", "a"]]
{
for k in 0..2 { for k in 0..2 {
let long_edge_ids = [ let long_edge_ids = [
format!("{long_edge_plane}{k}0"), format!("{long_edge_plane}{k}0"),
@ -551,20 +560,20 @@ fn load_dodecahedral_packing(assembly: &Assembly) {
); );
// set up the short-edge tangency // set up the short-edge tangency
let short_tangency = InversiveDistanceRegulator::new( let short_tangency
short_edge.clone()); = InversiveDistanceRegulator::new(short_edge.clone());
if k == 0 { if k == 0 {
short_tangency.set_point.set( short_tangency.set_point
SpecifiedValue::try_from("-1".to_string()).unwrap()); .set(SpecifiedValue::try_from("-1".to_string()).unwrap());
} }
assembly.insert_regulator(Rc::new(short_tangency)); assembly.insert_regulator(Rc::new(short_tangency));
// set up the side tangencies // set up the side tangencies
for i in 0..2 { for i in 0..2 {
for j in 0..2 { for j in 0..2 {
let side_tangency = InversiveDistanceRegulator::new( let side_tangency = InversiveDistanceRegulator::new([
[long_edge[i].clone(), short_edge[j].clone()] long_edge[i].clone(), short_edge[j].clone()
); ]);
if i == 0 && k == 0 { if i == 0 && k == 0 {
side_tangency.set_point.set( side_tangency.set_point.set(
SpecifiedValue::try_from("-1".to_string()).unwrap() SpecifiedValue::try_from("-1".to_string()).unwrap()
@ -633,8 +642,8 @@ fn load_balanced(assembly: &Assembly) {
// initial configuration deliberately violates these constraints // initial configuration deliberately violates these constraints
for inner in [a, b] { for inner in [a, b] {
let tangency = InversiveDistanceRegulator::new([outer.clone(), inner]); let tangency = InversiveDistanceRegulator::new([outer.clone(), inner]);
tangency.set_point.set( tangency.set_point
SpecifiedValue::try_from("1".to_string()).unwrap()); .set(SpecifiedValue::try_from("1".to_string()).unwrap());
assembly.insert_regulator(Rc::new(tangency)); assembly.insert_regulator(Rc::new(tangency));
} }
} }
@ -799,10 +808,11 @@ fn load_radius_ratio(assembly: &Assembly) {
} }
// put the vertices on the faces // put the vertices on the faces
let incidence_regulator = InversiveDistanceRegulator::new( let incidence_regulator = InversiveDistanceRegulator::new([
[face_j.clone(), vertex_k.clone()]); face_j.clone(), vertex_k.clone()
incidence_regulator.set_point.set( ]);
SpecifiedValue::try_from("0".to_string()).unwrap()); incidence_regulator.set_point
.set(SpecifiedValue::try_from("0".to_string()).unwrap());
assembly.insert_regulator(Rc::new(incidence_regulator)); assembly.insert_regulator(Rc::new(incidence_regulator));
} }
} }
@ -897,32 +907,37 @@ fn load_irisawa_hexlet(assembly: &Assembly) {
) )
); );
for (chain_sphere, chain_sphere_next) for (chain_sphere, chain_sphere_next)
in chain.clone().zip(chain.cycle().skip(1)) { in chain.clone().zip(chain.cycle().skip(1))
for (other_sphere, inversive_distance) in [ {
(outer.clone(), "1"), for (other_sphere, inversive_distance)
in [(outer.clone(), "1"),
(sun.clone(), "-1"), (sun.clone(), "-1"),
(moon.clone(), "-1"), (moon.clone(), "-1"),
(chain_sphere_next.clone(), "-1"), (chain_sphere_next.clone(), "-1"),
] { ] {
let tangency = InversiveDistanceRegulator::new( let tangency = InversiveDistanceRegulator::new([
[chain_sphere.clone(), other_sphere]); chain_sphere.clone(), other_sphere
]);
tangency.set_point.set( tangency.set_point.set(
SpecifiedValue::try_from( SpecifiedValue::try_from(
inversive_distance.to_string()).unwrap()); inversive_distance.to_string()).unwrap()
);
assembly.insert_regulator(Rc::new(tangency)); assembly.insert_regulator(Rc::new(tangency));
} }
} }
let outer_sun_tangency = InversiveDistanceRegulator::new( let outer_sun_tangency = InversiveDistanceRegulator::new([
[outer.clone(), sun]); outer.clone(), sun
outer_sun_tangency.set_point.set( ]);
SpecifiedValue::try_from("1".to_string()).unwrap()); outer_sun_tangency.set_point
.set(SpecifiedValue::try_from("1".to_string()).unwrap());
assembly.insert_regulator(Rc::new(outer_sun_tangency)); assembly.insert_regulator(Rc::new(outer_sun_tangency));
let outer_moon_tangency = InversiveDistanceRegulator::new( let outer_moon_tangency = InversiveDistanceRegulator::new([
[outer.clone(), moon]); outer.clone(), moon
outer_moon_tangency.set_point.set( ]);
SpecifiedValue::try_from("1".to_string()).unwrap()); outer_moon_tangency.set_point
.set(SpecifiedValue::try_from("1".to_string()).unwrap());
assembly.insert_regulator(Rc::new(outer_moon_tangency)); assembly.insert_regulator(Rc::new(outer_moon_tangency));
} }

View file

@ -10,10 +10,9 @@ pub fn point(x: f64, y: f64, z: f64) -> DVector<f64> {
// the sphere with the given center and radius, with inward-pointing normals // the sphere with the given center and radius, with inward-pointing normals
pub fn sphere(center_x: f64, center_y: f64, center_z: f64, radius: f64) pub fn sphere(center_x: f64, center_y: f64, center_z: f64, radius: f64)
-> DVector<f64> -> DVector<f64> {
{ let center_norm_sq
let center_norm_sq = = center_x * center_x + center_y * center_y + center_z * center_z;
Vectornaut marked this conversation as resolved

I'd match the convention used for sphere_with_offset:

pub fn sphere(
    center_x: f64, center_y: f64, center_z: f64, radius: f64
) -> DVector<f64> {
I'd match the convention used for `sphere_with_offset`: ```rust pub fn sphere( center_x: f64, center_y: f64, center_z: f64, radius: f64 ) -> DVector<f64> { ```

Here I very much don't see a need for a strict uniform "convention" but rather most readable layout on a case-by-case basis, you said you like function-call open and close on same line when possible, I really universally dislike paren on next line, and of all the places to break functionName(parameter1: Type1, parameter2: Type2) -> ReturnType { just before the arrow seems by far the cleanest to me: before an operator, clean semantic break between the calling convention on the one hand and the return type on the other, arrow makes it nice and clear this is a function. So I would advocate that breakpoint as the very first to use when needed, and only break the parameter list when it simply won't fit on one line.

Thoughts?

Here I very much don't see a need for a strict uniform "convention" but rather most readable layout on a case-by-case basis, you said you like function-call open and close on same line when possible, I really universally dislike paren on next line, and of all the places to break `functionName(parameter1: Type1, parameter2: Type2) -> ReturnType {` just before the arrow seems by far the cleanest to me: before an operator, clean semantic break between the calling convention on the one hand and the return type on the other, arrow makes it nice and clear this is a function. So I would advocate that breakpoint as the very first to use when needed, and only break the parameter list when it simply won't fit on one line. Thoughts?

The main thing I find confusing about the current formatting is that the -> DVector<f64> is part of the function declaration, but no indentation is used to show this. If you find bracket on next line more palatable than parenthesis on next line, I'd find something like this more readable than the current formatting:

pub fn sphere(center_x: f64, center_y: f64, center_z: f64, radius: f64)
    -> DVector<f64>
{
The main thing I find confusing about the current formatting is that the `-> DVector<f64>` is part of the function declaration, but no indentation is used to show this. If you find bracket on next line more palatable than parenthesis on next line, I'd find something like this more readable than the current formatting: ```rust pub fn sphere(center_x: f64, center_y: f64, center_z: f64, radius: f64) -> DVector<f64> { ```

I'll admit I am looking for a two-line solution here. I don't see any reason to indent the -> just as there is no reason to
indent the else of an if -- to me, the -> reads as a companion keyword to fn. So for the upcoming revision, I will try moving just the parenthesis to the next line to see if you like that better. As little as I like a linebreak before a paren, I like wasting lines less ;-)

I'll admit I am looking for a two-line solution here. I don't see any reason to indent the `->` just as there is no reason to indent the `else` of an `if` -- to me, the `->` reads as a companion keyword to `fn`. So for the upcoming revision, I will try moving just the parenthesis to the next line to see if you like that better. As little as I like a linebreak before a paren, I like wasting lines less ;-)

I'll admit I am looking for a two-line solution here.

All of the reasonable two-line solutions I can think of seem equally hard to read to me, and equally in violation of the Rust and Python style guides. Here's one last suggestion, which is inspired by (but in violation of) the Python style guide. You're welcome to choose between this formatting and the current one.

pub fn sphere(center_x: f64, center_y: f64, center_z: f64, radius: f64)
        -> DVector<f64> {
    /* function body */
> I'll admit I am looking for a two-line solution here. All of the reasonable two-line solutions I can think of seem equally hard to read to me, and equally in violation of the [Rust](https://doc.rust-lang.org/beta/style-guide/index.html) and [Python](https://peps.python.org/pep-0008/#indentation) style guides. Here's one last suggestion, which is inspired by (but in violation of) the Python style guide. You're welcome to choose between this formatting and the current one. ```rust pub fn sphere(center_x: f64, center_y: f64, center_z: f64, radius: f64) -> DVector<f64> { /* function body */ ```

Well, from my point of view we discarded double-indent patterns for if and for so I am loath to revive them here, so I think we are settling on

pub fn foo(long: stuff
) -> ReturnType {
    // body
}

Please confirm, thanks.

Well, from my point of view we discarded double-indent patterns for `if` and `for` so I am loath to revive them here, so I think we are settling on ``` pub fn foo(long: stuff ) -> ReturnType { // body } ``` Please confirm, thanks.

Please confirm, thanks.

Confirmed.

> Please confirm, thanks. Confirmed.
center_x * center_x + center_y * center_y + center_z * center_z;
DVector::from_column_slice(&[ DVector::from_column_slice(&[
center_x / radius, center_x / radius,
center_y / radius, center_y / radius,
@ -27,8 +26,8 @@ pub fn sphere(center_x: f64, center_y: f64, center_z: f64, radius: f64)
// `off * dir` and normal `dir`, where `dir` is a unit vector. setting the // `off * dir` and normal `dir`, where `dir` is a unit vector. setting the
// curvature to zero gives a plane // curvature to zero gives a plane
pub fn sphere_with_offset( pub fn sphere_with_offset(
dir_x: f64, dir_y: f64, dir_z: f64, off: f64, curv: f64) -> DVector<f64> dir_x: f64, dir_y: f64, dir_z: f64, off: f64, curv: f64
{ ) -> DVector<f64> {
let norm_sp = 1.0 + off * curv; let norm_sp = 1.0 + off * curv;
DVector::from_column_slice(&[ DVector::from_column_slice(&[
norm_sp * dir_x, norm_sp * dir_x,
@ -156,9 +155,7 @@ impl ConfigSubspace {
// space for `assembly_dim` elements. we consider an eigenvector to be part // space for `assembly_dim` elements. we consider an eigenvector to be part
// of the kernel if its eigenvalue is smaller than the constant `THRESHOLD` // of the kernel if its eigenvalue is smaller than the constant `THRESHOLD`
fn symmetric_kernel( fn symmetric_kernel(
a: DMatrix<f64>, a: DMatrix<f64>, proj_to_std: DMatrix<f64>, assembly_dim: usize
proj_to_std: DMatrix<f64>,
assembly_dim: usize,
) -> Self { ) -> Self {
// find a basis for the kernel. the basis is expressed in the projection // find a basis for the kernel. the basis is expressed in the projection
// coordinates, and it's orthonormal with respect to the projection // coordinates, and it's orthonormal with respect to the projection
@ -206,8 +203,7 @@ impl ConfigSubspace {
// projection coordinates, and the projection is done with respect to the // projection coordinates, and the projection is done with respect to the
// projection inner product // projection inner product
pub fn proj(&self, v: &DVectorView<f64>, column_index: usize) pub fn proj(&self, v: &DVectorView<f64>, column_index: usize)
-> DMatrix<f64> -> DMatrix<f64> {
{
if self.dim() == 0 { if self.dim() == 0 {
const ELEMENT_DIM: usize = 5; const ELEMENT_DIM: usize = 5;
DMatrix::zeros(ELEMENT_DIM, self.assembly_dim) DMatrix::zeros(ELEMENT_DIM, self.assembly_dim)
@ -423,8 +419,8 @@ pub fn realize_gram(
for _ in 0..max_descent_steps { for _ in 0..max_descent_steps {
// find the negative gradient of the loss function // find the negative gradient of the loss function
let neg_grad = 4.0 * &*Q * &state.config * &state.err_proj; let neg_grad = 4.0 * &*Q * &state.config * &state.err_proj;
let mut neg_grad_stacked = let mut neg_grad_stacked = neg_grad.clone()
neg_grad.clone().reshape_generic(Dyn(total_dim), Const::<1>); .reshape_generic(Dyn(total_dim), Const::<1>);
history.neg_grad.push(neg_grad.clone()); history.neg_grad.push(neg_grad.clone());
// find the negative Hessian of the loss function // find the negative Hessian of the loss function
@ -489,8 +485,8 @@ pub fn realize_gram(
}, },
}; };
let base_step_stacked = hess_cholesky.solve(&neg_grad_stacked); let base_step_stacked = hess_cholesky.solve(&neg_grad_stacked);
let base_step = base_step_stacked.reshape_generic( let base_step = base_step_stacked
Dyn(element_dim), Dyn(assembly_dim)); .reshape_generic(Dyn(element_dim), Dyn(assembly_dim));
history.base_step.push(base_step.clone()); history.base_step.push(base_step.clone());
// use backtracking line search to find a better configuration // use backtracking line search to find a better configuration
@ -520,11 +516,12 @@ pub fn realize_gram(
} }
// find the kernel of the Hessian. give it the uniform inner product // find the kernel of the Hessian. give it the uniform inner product
let tangent = let tangent
ConfigSubspace::symmetric_kernel(hess, unif_to_std, assembly_dim); = ConfigSubspace::symmetric_kernel(hess, unif_to_std, assembly_dim);
Ok(ConfigNeighborhood { Ok(ConfigNeighborhood {
#[cfg(feature = "dev")] config: state.config, nbhd: tangent #[cfg(feature = "dev")] config: state.config,
nbhd: tangent,
}) })
} else { } else {
Err("Failed to reach target accuracy".to_string()) Err("Failed to reach target accuracy".to_string())
@ -625,7 +622,10 @@ pub mod examples {
// diagonal and hinge edges // diagonal and hinge edges
for k in j..2 { for k in j..2 {
problem.gram.push_sym( problem.gram.push_sym(
block + j, block + k, if j == k { 0.0 } else { -0.5 }); block + j,
block + k,
if j == k { 0.0 } else { -0.5 }
Vectornaut marked this conversation as resolved

In our current convention, this argument list needs a trailing comma on the last line.

In our current convention, this argument list needs a trailing comma on the last line.
);
} }
// non-hinge edges // non-hinge edges
@ -720,7 +720,9 @@ mod tests {
for j in 0..2 { for j in 0..2 {
for k in j..2 { for k in j..2 {
problem.gram.push_sym( problem.gram.push_sym(
j, k, if (j, k) == (1, 1) { 1.0 } else { 0.0 }); j, k,
if (j, k) == (1, 1) { 1.0 } else { 0.0 }
Vectornaut marked this conversation as resolved

In our current convention, this argument list needs a trailing comma on the last line.

In our current convention, this argument list needs a trailing comma on the last line.
);
} }
} }
problem.frozen.push(3, 0, problem.guess[(3, 0)]); problem.frozen.push(3, 0, problem.guess[(3, 0)]);
@ -747,8 +749,9 @@ mod tests {
// check against Irisawa's solution // check against Irisawa's solution
let entry_tol = SCALED_TOL.sqrt(); let entry_tol = SCALED_TOL.sqrt();
let solution_diams = let solution_diams = [
[30.0, 10.0, 6.0, 5.0, 15.0, 10.0, 3.75, 2.5, 2.0 + 8.0/11.0]; 30.0, 10.0, 6.0, 5.0, 15.0, 10.0, 3.75, 2.5, 2.0 + 8.0/11.0
];
for (k, diam) in solution_diams.into_iter().enumerate() { for (k, diam) in solution_diams.into_iter().enumerate() {
assert!((config[(3, k)] - 1.0 / diam).abs() < entry_tol); assert!((config[(3, k)] - 1.0 / diam).abs() < entry_tol);
} }
@ -816,18 +819,18 @@ mod tests {
let tol_sq = ((element_dim * assembly_dim) as f64) let tol_sq = ((element_dim * assembly_dim) as f64)
* SCALED_TOL * SCALED_TOL; * SCALED_TOL * SCALED_TOL;
for (motion_unif, motion_std) for (motion_unif, motion_std)
in tangent_motions_unif.into_iter().zip(tangent_motions_std) { in tangent_motions_unif.into_iter().zip(tangent_motions_std)
let motion_proj: DMatrix<_> = {
motion_unif.column_iter().enumerate().map( let motion_proj: DMatrix<_>
|(k, v)| tangent.proj(&v, k) = motion_unif.column_iter().enumerate()
).sum(); .map(|(k, v)| tangent.proj(&v, k))
.sum();
assert!((motion_std - motion_proj).norm_squared() < tol_sq); assert!((motion_std - motion_proj).norm_squared() < tol_sq);
} }
} }
fn translation_motion_unif(vel: &Vector3<f64>, assembly_dim: usize) fn translation_motion_unif(vel: &Vector3<f64>, assembly_dim: usize)
-> Vec<DVector<f64>> -> Vec<DVector<f64>> {
{
let mut elt_motion = DVector::zeros(4); let mut elt_motion = DVector::zeros(4);
elt_motion.fixed_rows_mut::<3>(0).copy_from(vel); elt_motion.fixed_rows_mut::<3>(0).copy_from(vel);
iter::repeat(elt_motion).take(assembly_dim).collect() iter::repeat(elt_motion).take(assembly_dim).collect()
@ -888,10 +891,12 @@ mod tests {
[ [
DVector::from_column_slice(&[0.0, 0.0, 5.0, 0.0]), DVector::from_column_slice(&[0.0, 0.0, 5.0, 0.0]),
DVector::from_column_slice(&[0.0, 0.0, 1.0, 0.0]), DVector::from_column_slice(&[0.0, 0.0, 1.0, 0.0]),
DVector::from_column_slice( DVector::from_column_slice(&[
&[-vel_vert_x, -vel_vert_y, -3.0, 0.0]), -vel_vert_x, -vel_vert_y, -3.0, 0.0
DVector::from_column_slice( ]),
&[vel_vert_x, vel_vert_y, -3.0, 0.0]), DVector::from_column_slice(&[
vel_vert_x, vel_vert_y, -3.0, 0.0
]),
] ]
} }
).collect::<Vec<_>>(), ).collect::<Vec<_>>(),
@ -914,7 +919,8 @@ mod tests {
let tol_sq = ((element_dim * assembly_dim) as f64) let tol_sq = ((element_dim * assembly_dim) as f64)
* SCALED_TOL * SCALED_TOL; * SCALED_TOL * SCALED_TOL;
for (motion_unif, motion_std) for (motion_unif, motion_std)
in tangent_motions_unif.into_iter().zip(tangent_motions_std) { in tangent_motions_unif.into_iter().zip(tangent_motions_std)
{
let motion_proj: DMatrix<_> = let motion_proj: DMatrix<_> =
motion_unif.into_iter().enumerate().map( motion_unif.into_iter().enumerate().map(
|(k, v)| tangent.proj(&v.as_view(), k) |(k, v)| tangent.proj(&v.as_view(), k)
@ -947,10 +953,10 @@ mod tests {
problem_orig.gram.push_sym(0, 0, 1.0); problem_orig.gram.push_sym(0, 0, 1.0);
problem_orig.gram.push_sym(1, 1, 1.0); problem_orig.gram.push_sym(1, 1, 1.0);
problem_orig.gram.push_sym(0, 1, 0.5); problem_orig.gram.push_sym(0, 1, 0.5);
let Realization { result: result_orig, history: history_orig } = let Realization { result: result_orig, history: history_orig }
realize_gram(&problem_orig, SCALED_TOL, 0.5, 0.9, 1.1, 200, 110); = realize_gram(&problem_orig, SCALED_TOL, 0.5, 0.9, 1.1, 200, 110);
let ConfigNeighborhood { config: config_orig, nbhd: tangent_orig } = let ConfigNeighborhood { config: config_orig, nbhd: tangent_orig }
result_orig.unwrap(); = result_orig.unwrap();
assert_eq!(config_orig, problem_orig.guess); assert_eq!(config_orig, problem_orig.guess);
assert_eq!(history_orig.scaled_loss.len(), 1); assert_eq!(history_orig.scaled_loss.len(), 1);
@ -968,10 +974,10 @@ mod tests {
frozen: problem_orig.frozen, frozen: problem_orig.frozen,
guess: guess_tfm, guess: guess_tfm,
}; };
let Realization { result: result_tfm, history: history_tfm } = let Realization { result: result_tfm, history: history_tfm }
realize_gram(&problem_tfm, SCALED_TOL, 0.5, 0.9, 1.1, 200, 110); = realize_gram(&problem_tfm, SCALED_TOL, 0.5, 0.9, 1.1, 200, 110);
let ConfigNeighborhood { config: config_tfm, nbhd: tangent_tfm } = let ConfigNeighborhood { config: config_tfm, nbhd: tangent_tfm }
result_tfm.unwrap(); = result_tfm.unwrap();
assert_eq!(config_tfm, problem_tfm.guess); assert_eq!(config_tfm, problem_tfm.guess);
assert_eq!(history_tfm.scaled_loss.len(), 1); assert_eq!(history_tfm.scaled_loss.len(), 1);
@ -982,8 +988,9 @@ mod tests {
// project the equivalent nudge to the tangent space of the solution // project the equivalent nudge to the tangent space of the solution
// variety at the transformed solution // variety at the transformed solution
let motion_tfm = DVector::from_column_slice( let motion_tfm = DVector::from_column_slice(&[
&[FRAC_1_SQRT_2, 0.0, FRAC_1_SQRT_2, 0.0]); FRAC_1_SQRT_2, 0.0, FRAC_1_SQRT_2, 0.0
]);
let motion_tfm_proj = tangent_tfm.proj(&motion_tfm.as_view(), 0); let motion_tfm_proj = tangent_tfm.proj(&motion_tfm.as_view(), 0);
// take the transformation that sends the original solution to the // take the transformation that sends the original solution to the