Make element representations opaque to the assembly module #90

Open
opened 2025-06-04 22:47:22 +00:00 by Vectornaut · 2 comments
Member

We'd like to keep engine-specific code within the engine module as much as possible. Up through pull request #87, we've allowed engine-specific details to leak into the assembly module by assuming that each element is represented by a DVector<f64>. Upcoming elements, like lines, will violate this assumption, so now is a good time to redesign the assembly module so that it no longer needs to know which data types we use to represent elements.

A question to keep in mind

When an element has a "compound representation," how do we decide whether that detail is engine-independent enough to use outside the engine module? To see how the decision might depend on how things are implemented, consider the following ways of representing a line segment:

  • A pair of points (seems pretty engine-independent).
  • A basis for a 2d subspace of \mathbb{R}^{4,1} (much more engine-specific).

Proposed redesign

In the engine module

Introduce a new ElementRepresentation trait, and new SphereRepresentation and PointRepresentation structures that implement it. In the future, we might also want to implement ElementRepresentation for compound representation types, like [PointRepresentation].

In the assembly module

Change the Element trait in one of these ways:

  • Make it generic over a representation type that implements ElementRepresentation.
  • Change the return type of its representation method to something like Signal<dyn ElementRepresentation>.

Change the type of the representation field to:

  • Signal<SphereRepresentation> in the Sphere structure.
  • Signal<PointRepresentation> in the Point structure.

If we can implement ElementRepresentation for compound representation types, as expected, we could also eventually have a field type like Signal<[PointRepresentation; 3]> for a hypothetical Triangle structure. This would make it clear that we don't have perfect redundancy between element and representation structures.

Move the engine-specific parts of the ProblemPoser implementations into the engine module. Some ideas about how:

  • Implement ProblemPoser for both Sphere and SphereRepresentation, letting Sphere partially or fully forwards calls to pose. Treat other element and representation structures similarly.
  • Make engine::ElementRepresentation a subtrait of ProblemPoser and call pose on whatever an element's representation method returns.
We'd like to keep engine-specific code within the `engine` module as much as possible. Up through pull request #87, we've allowed engine-specific details to leak into the `assembly` module by assuming that each element is represented by a `DVector<f64>`. Upcoming elements, like lines, will violate this assumption, so now is a good time to redesign the `assembly` module so that it no longer needs to know which data types we use to represent elements. ### A question to keep in mind When an element has a "compound representation," how do we decide whether that detail is engine-independent enough to use outside the `engine` module? To see how the decision might depend on how things are implemented, consider the following ways of representing a line segment: - A pair of points (seems pretty engine-independent). - A basis for a 2d subspace of $\mathbb{R}^{4,1}$ (much more engine-specific). ### Proposed redesign #### In the `engine` module Introduce a new `ElementRepresentation` trait, and new `SphereRepresentation` and `PointRepresentation` structures that implement it. In the future, we might also want to implement `ElementRepresentation` for compound representation types, like `[PointRepresentation]`. #### In the `assembly` module Change the `Element` trait in one of these ways: - Make it generic over a representation type that implements `ElementRepresentation`. - Change the return type of its `representation` method to something like `Signal<dyn ElementRepresentation>`. Change the type of the `representation` field to: - `Signal<SphereRepresentation>` in the `Sphere` structure. - `Signal<PointRepresentation>` in the `Point` structure. If we can implement `ElementRepresentation` for compound representation types, as expected, we could also eventually have a field type like `Signal<[PointRepresentation; 3]>` for a hypothetical `Triangle` structure. This would make it clear that we don't have perfect redundancy between element and representation structures. Move the engine-specific parts of the `ProblemPoser` implementations into the `engine` module. Some ideas about how: - Implement `ProblemPoser` for both `Sphere` and `SphereRepresentation`, letting `Sphere` partially or fully forwards calls to `pose`. Treat other element and representation structures similarly. - Make `engine::ElementRepresentation` a subtrait of `ProblemPoser` and call `pose` on whatever an element's `representation` method returns.
Vectornaut added the
design
label 2025-06-04 22:47:22 +00:00
glen changed title from Make the data types of element representations opaque to the assembly module to Make element representations opaque to the assembly module 2025-10-06 22:36:13 +00:00
Owner

Going further, not just the data types of element representations, but really any details of the element representations should not be part of the assembly module. This modularization will be necessary whenever we next want to experiment with a different engine. So the assembly should not know the order or meanings of any representation data. We could imagine that there was an engine that internally dealt with polar coordinates; the assembly should not know about what those coordinates were or anything about their arrangements or semantics.

Thus, information like Point::NORM_COMPONENT and Point::WEIGHT_COMPONENT should be purged from assembly.rs. So the ProblemPoser implementation that freezes the WEIGHT_COMPONENT should be removed from assembly.rs. Instead, there should be some protocol that specifies to the engine that such and such an entity is a "Point", and then (in our case), the engine should be translating that specification to freezing the appropriate component(s).

Presuming the coordinate-regulators PR #118 is merged, another example is the code that freezes the norm component when all of the spatial coordinates are frozen. That should not be happening in the assembly. Instead, perhaps, the engine should be checking if all but one of the coordinates of an entity are frozen, and if so, freeze the third.

Likely to do all these things, we need an abstract constraint specification system, and a layer that translates the abstract specifications to the solver in use. So switching engines would involve writing the new translation layer and then sending the specification to the new solver. This architecture should also allow a given problem to be sent to multiple solvers at once (by being translated into all of them) so that as they come back their solutions can be used.

Going further, not just the data types of element representations, but really any details of the element representations should not be part of the assembly module. This modularization will be necessary whenever we next want to experiment with a different engine. So the assembly should not know the order or meanings of any representation data. We could imagine that there was an engine that internally dealt with polar coordinates; the assembly should not know about what those coordinates were or anything about their arrangements or semantics. Thus, information like Point::NORM_COMPONENT and Point::WEIGHT_COMPONENT should be purged from assembly.rs. So the ProblemPoser implementation that freezes the WEIGHT_COMPONENT should be removed from assembly.rs. Instead, there should be some protocol that specifies to the engine that such and such an entity is a "Point", and then (in our case), the engine should be translating that specification to freezing the appropriate component(s). Presuming the coordinate-regulators PR #118 is merged, another example is the code that freezes the norm component when all of the spatial coordinates are frozen. That should not be happening in the assembly. Instead, perhaps, the engine should be checking if all but one of the coordinates of an entity are frozen, and if so, freeze the third. Likely to do all these things, we need an abstract constraint specification system, and a layer that translates the abstract specifications to the solver in use. So switching engines would involve writing the new translation layer and then sending the specification to the new solver. This architecture should also allow a given problem to be sent to multiple solvers at once (by being translated into all of them) so that as they come back their solutions can be used.
Author
Member

Instead, perhaps, the engine should be checking if all but one of the coordinates of an entity are frozen, and if so, freeze the third.

I'll expand on this a little, since we talked about it during our check-in meeting. We concluded that the engine or the problem translation layer should be responsible for freezing the last component, because it seems like a problem simplification step that depends on the engine and might happen as a prelude to the engine's realization routine.

> Instead, perhaps, the engine should be checking if all but one of the coordinates of an entity are frozen, and if so, freeze the third. I'll expand on this a little, since we talked about it during our check-in meeting. We concluded that the engine or the problem translation layer should be responsible for freezing the last component, because it seems like a problem simplification step that depends on the engine and might happen as a prelude to the engine's realization routine.
Sign in to join this conversation.
No description provided.