Curvature regulators #80

Merged
glen merged 21 commits from Vectornaut/dyna3:curvature-regulators into main 2025-04-21 23:40:43 +00:00
Showing only changes of commit 63e3d733ba - Show all commits

View file

@ -31,6 +31,10 @@ pub type ElementColor = [f32; 3];
// each assembly has a key that identifies it within the sesssion // each assembly has a key that identifies it within the sesssion
static NEXT_ELEMENT_SERIAL: AtomicU64 = AtomicU64::new(0); static NEXT_ELEMENT_SERIAL: AtomicU64 = AtomicU64::new(0);
pub trait ProblemPoser {
fn pose(&self, problem: &mut ConstraintProblem, elts: &Slab<Element>);
}
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub struct Element { pub struct Element {
pub id: String, pub id: String,
@ -123,8 +127,10 @@ impl Element {
None None
} }
} }
}
fn write_to_problem(&self, problem: &mut ConstraintProblem) {
impl ProblemPoser for Element {
fn pose(&self, problem: &mut ConstraintProblem, _elts: &Slab<Element>) {
if let Some(index) = self.column_index { if let Some(index) = self.column_index {
problem.gram.push_sym(index, index, 1.0); problem.gram.push_sym(index, index, 1.0);
problem.guess.set_column(index, &self.representation.get_clone_untracked()); problem.guess.set_column(index, &self.representation.get_clone_untracked());
@ -134,14 +140,10 @@ impl Element {
} }
} }
pub trait Regulator: OutlineItem { pub trait Regulator: ProblemPoser + OutlineItem {
// get information
fn subjects(&self) -> Vec<ElementKey>; fn subjects(&self) -> Vec<ElementKey>;
fn measurement(&self) -> ReadSignal<f64>; fn measurement(&self) -> ReadSignal<f64>;
fn set_point(&self) -> Signal<SpecifiedValue>; fn set_point(&self) -> Signal<SpecifiedValue>;
// write problem data
fn write_to_problem(&self, problem: &mut ConstraintProblem, elts: &Slab<Element>);
} }
pub struct ProductRegulator { pub struct ProductRegulator {
@ -162,8 +164,10 @@ impl Regulator for ProductRegulator {
fn set_point(&self) -> Signal<SpecifiedValue> { fn set_point(&self) -> Signal<SpecifiedValue> {
self.set_point self.set_point
} }
}
fn write_to_problem(&self, problem: &mut ConstraintProblem, elts: &Slab<Element>) {
impl ProblemPoser for ProductRegulator {
fn pose(&self, problem: &mut ConstraintProblem, elts: &Slab<Element>) {
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 subject_column_indices = self.subjects.map( let subject_column_indices = self.subjects.map(
@ -197,8 +201,10 @@ impl Regulator for HalfCurvatureRegulator {
fn set_point(&self) -> Signal<SpecifiedValue> { fn set_point(&self) -> Signal<SpecifiedValue> {
self.set_point self.set_point
} }
}
fn write_to_problem(&self, problem: &mut ConstraintProblem, elts: &Slab<Element>) {
impl ProblemPoser for HalfCurvatureRegulator {
fn pose(&self, problem: &mut ConstraintProblem, elts: &Slab<Element>) {
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 {
if let Some(col) = elts[self.subject].column_index { if let Some(col) = elts[self.subject].column_index {
@ -441,11 +447,11 @@ impl Assembly {
let problem = self.elements.with_untracked(|elts| { let problem = self.elements.with_untracked(|elts| {
let mut problem_to_be = ConstraintProblem::new(elts.len()); let mut problem_to_be = ConstraintProblem::new(elts.len());
for (_, elt) in elts { for (_, elt) in elts {
elt.write_to_problem(&mut problem_to_be); elt.pose(&mut problem_to_be, elts);
} }
self.regulators.with_untracked(|regs| { self.regulators.with_untracked(|regs| {
glen marked this conversation as resolved Outdated

It's OK with me if you just call the interior variable problem even though it's being returned out to an exterior variable named problem -- I don't think it would reduce clarity. Not necessary to change, just wanted to make sure you knew that I don't have any issue with using the same name in a case like this. And I do think that concise variable names are definitely helpful.

It's OK with me if you just call the interior variable `problem` even though it's being returned out to an exterior variable named `problem` -- I don't think it would reduce clarity. Not necessary to change, just wanted to make sure you knew that I don't have any issue with using the same name in a case like this. And I do think that concise variable names are definitely helpful.

Good to know. For now, I think it's worth clearly distinguishing the interior "builder" variable and the exterior "storage" variable, because they have some differences in usage: for example, the builder variable is mutable, and the storage variable isn't. However, I'd be fine with switching to the convention of using the same name for both.

Good to know. For now, I think it's worth clearly distinguishing the interior "builder" variable and the exterior "storage" variable, because they have some differences in usage: for example, the builder variable is mutable, and the storage variable isn't. However, I'd be fine with switching to the convention of using the same name for both.

Well, we are either going to have the convention of using the same variable name inside and outside, or always distinguishing the names. We're not going to do it one way in some places and the other way in other places. I like the "same name" convention better -- more concise with no loss in clarity. So if you are not against that change in convention, please just go ahead and change this instance to conform. We can discuss (A,B,C) from the other thread in person.

Well, we are either going to have the convention of using the same variable name inside and outside, or always distinguishing the names. We're not going to do it one way in some places and the other way in other places. I like the "same name" convention better -- more concise with no loss in clarity. So if you are not against that change in convention, please just go ahead and change this instance to conform. We can discuss (A,B,C) from the other thread in person.

I've switched to the same-name convention in commit 955220c.

I've switched to the same-name convention in commit 955220c.

Great, I see that, and this code is fine. It occurs to me that the organization that would be used for this code in some languages would be to have the problem = ConstraintProblem::new(...) outside the closure in self.elements.with_untracked(...) and then have some sort of reference to the problem be visible inside that closure. I suppose that is possible in Rust as well. If you think it's cleaner/clearer to organize it that way, feel free to refactor this, but also feel free to leave it as is if you prefer. In the latter case, please just resolve this thread.

Great, I see that, and this code is fine. It occurs to me that the organization that would be used for this code in some languages would be to have the `problem = ConstraintProblem::new(...)` outside the closure in self.elements.with_untracked(...) and then have some sort of reference to the problem be visible inside that closure. I suppose that is possible in Rust as well. If you think it's cleaner/clearer to organize it that way, feel free to refactor this, but also feel free to leave it as is if you prefer. In the latter case, please just resolve this thread.

I chose this organization so that problem could be immutable in the scope where it's used, and only mutable in the scope where it's created.

I chose this organization so that `problem` could be immutable in the scope where it's used, and only mutable in the scope where it's created.
for (_, reg) in regs { for (_, reg) in regs {
reg.write_to_problem(&mut problem_to_be, elts); reg.pose(&mut problem_to_be, elts);
} }
}); });
problem_to_be problem_to_be
@ -621,7 +627,7 @@ mod tests {
"Sphere".to_string(), "Sphere".to_string(),
[1.0_f32, 1.0_f32, 1.0_f32], [1.0_f32, 1.0_f32, 1.0_f32],
engine::sphere(0.0, 0.0, 0.0, 1.0) engine::sphere(0.0, 0.0, 0.0, 1.0)
).write_to_problem(&mut ConstraintProblem::new(1)); ).pose(&mut ConstraintProblem::new(1), &Slab::new());
}); });
} }
@ -645,7 +651,7 @@ mod tests {
subjects: subjects, subjects: subjects,
measurement: create_memo(|| 0.0), measurement: create_memo(|| 0.0),
set_point: create_signal(SpecifiedValue::try_from("0.0".to_string()).unwrap()) set_point: create_signal(SpecifiedValue::try_from("0.0".to_string()).unwrap())
}.write_to_problem(&mut ConstraintProblem::new(2), &elts); }.pose(&mut ConstraintProblem::new(2), &elts);
}); });
} }
} }