-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move Point
out of cubic splines module and expand it
#12747
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much clearer code organization, better docs, and a much clearer / more motivated trait name. I also like NormedVectorSpace
: it's genuinely useful and a good standard abstraction.
I'd be open to a Normed
trait instead (better separation!), but I do like the scoped and well-motivated nature of NormedVectorSpace
. We can revisit this if we ever need a normed non-vector space I guess.
/// A type that supports the operations of a normed vector space; i.e. a norm operation in addition | ||
/// to those of [`VectorSpace`]. The implementor must guarantee that the axioms of a normed vector | ||
/// space are satisfied. | ||
pub trait NormedVectorSpace: VectorSpace { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mathematician in me also wants to see MetricSpace
and InnerProductSpace
traits with corresponding blanket impls, but I agree with Alice that we shouldn't add traits until the need arises.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree! I suspect it will come up before too long if someone tries to use NormedVectorSpace
and ends up needing a dot product.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love this!
As discussed in discord, Quat
doesn't really belong here. I also wonder if we should implement VectorSpace
on the Glam
matrix types. Either way, changing which types implement VectorSpace
deserves it's own PR.
I would prefer to see an expanded trait doc before I approve.
Makes sense! I've now rewritten the trait docs for both As a result, I'm rewriting the Migration Guide a little bit as well, just to mention the presence of zero. |
I agree with the addition of a zero element: it will make this trait much more useful. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent! Especially nice work on the docs, I'm glad you didn't get into the weeds about approximation error. Thanks for expanding those.
The zero constant seems pretty natural. I wonder if we can remove Default
from VectorSpace
now. IIRC we may have used it implicitly as the zero vector somewhere and it's now the only parent trait with somewhat unspecified behavior.
Every elegant. Now lets add FiniteGroup
, AproxRing
, AproxModule
and AproxField
traits! /s
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks fantastic! I have some very pedantic nits as suggestions, but none are worth blocking over if anyone disagrees with me.
/// - (Associativity of addition) For all `u, v, w: Self`, `(u + v) + w == u + (v + w)`. | ||
/// - (Commutativity of addition) For all `u, v: Self`, `u + v == v + u`. | ||
/// - (Additive identity) For all `v: Self`, `v + Self::ZERO == v`. | ||
/// - (Additive inverse) For all `v: Self`, `v - v == v + v * (-1) == Self::ZERO`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// - (Additive inverse) For all `v: Self`, `v - v == v + v * (-1) == Self::ZERO`. | |
/// - (Additive inverse) For all `u: Self` there exists a `v: Self` such that, `u + v == Self::ZERO`. |
The existence of an additive inverse doesn't necessarily imply that it will always equal -1*v
. The "Compatibility of multiplication" rule below will when combined with this requirement.
As an aside, should the trait Neg
be included? Feels strange to require scalar multiplication without it, especially if we require the additive inverse be defined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Existential quantifiers really don't belong in algebraic constraints in my opinion. I agree that it's phrased differently from usual, but there are a couple of things at play:
- The "right" thing is probably
v + (-v) == ZERO
, but we don't demand theNeg
trait despite the fact that we have enough data to implement it ourselves (we could change this) - Subtraction is, in practice, one of the most important operations in the API, even if mathematically speaking it originates from addition and negation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's just add Neg and define it as the inverse.
/// - (Commutativity of addition) For all `u, v: Self`, `u + v == v + u`. | ||
/// - (Additive identity) For all `v: Self`, `v + Self::ZERO == v`. | ||
/// - (Additive inverse) For all `v: Self`, `v - v == v + v * (-1) == Self::ZERO`. | ||
/// - (Compatibility of multiplication) For all `a, b: f32`, `v: Self`, `v * (a * b) == (v * a) * b`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// - (Compatibility of multiplication) For all `a, b: f32`, `v: Self`, `v * (a * b) == (v * a) * b`. | |
/// - (Compatibility of scalar multiplication) For all `a, b: f32`, `v: Self`, `v * (a * b) == (v * a) * b`. |
Worth calling this explicitly scalar multiplication to allow for possible future definition of vector multiplication in another trait.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wrote "multiplication" because really it's "compatibility of scalar multiplication with field multiplication", which was too many words. I'm also not sure how confusing it would be in the future anyway, since vector multiplication is almost always called something else anyway (e.g. inner product, dot product, etc.).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly, that's fair. Until this trait is generic over the scalar field (probably never) I think that's specific enough language already.
/// - (Additive identity) For all `v: Self`, `v + Self::ZERO == v`. | ||
/// - (Additive inverse) For all `v: Self`, `v - v == v + v * (-1) == Self::ZERO`. | ||
/// - (Compatibility of multiplication) For all `a, b: f32`, `v: Self`, `v * (a * b) == (v * a) * b`. | ||
/// - (Multiplicative identity) For all `v: Self`, `v * 1.0 == v`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// - (Multiplicative identity) For all `v: Self`, `v * 1.0 == v`. | |
/// - (Multiplicative scalar identity) For all `v: Self`, `v * 1.0 == v`. |
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
…bevy into vector-spaces
…riangle (#12766) # Objective When I wrote #12747 I neglected to translate random samples from triangles back to the point where they originated, so they would be sampled near the origin instead of at the actual triangle location. ## Solution Translate by the first vertex location so that the samples follow the actual triangle.
Thank you to everyone involved with the authoring or reviewing of this PR! This work is relatively important and needs release notes! Head over to bevyengine/bevy-website#1291 if you'd like to help out. |
Objective
Previously, the
Point
trait, which abstracts all of the operations of a real vector space, was sitting in the submodule ofbevy_math
for cubic splines. However, the trait has broader applications than merely cubic splines, and we should use it when possible to avoid code duplication when performing vector operations.Solution
Point
has been moved into a new submodule inbevy_math
namedcommon_traits
. Furthermore, it has been renamed toVectorSpace
, which is more descriptive, and an additional traitNormedVectorSpace
has been introduced to expand the API to cover situations involving geometry in addition to algebra. Additionally,VectorSpace
itself now requires aZERO
constant andNeg
. It also supports alerp
function as an automatic trait method.Here is what that looks like:
Furthermore, this PR also demonstrates the use of the
NormedVectorSpace
combined API to implementShapeSample
forTriangle2d
andTriangle3d
simultaneously. Such deduplication is one of the drivers for developing these APIs.Changelog
Point
fromcubic_splines
becomesVectorSpace
, exported asbevy::math::VectorSpace
.VectorSpace
requiresNeg
andVectorSpace::ZERO
in addition to its existing prerequisites.bevy::math::NormedVectorSpace
for generic geometry tasks involving vectors.ShapeSample
forTriangle2d
andTriangle3d
.Migration Guide
Since
Point
no longer exists, any projects using it must switch tobevy::math::VectorSpace
. Additionally, third-party implementations of this trait now require theNeg
trait; the constantVectorSpace::ZERO
must be provided as well.Discussion
Design considerations
Originally, the
NormedVectorSpace::norm
method was part of a separate traitNormed
. However, I think that was probably too broad and, more importantly, the semantics of having it inNormedVectorSpace
are much clearer.As it currently stands, the API exposed here is pretty minimal, and there is definitely a lot more that we could do, but there are more questions to answer along the way. As a silly example, we could implement
NormedVectorSpace::length
as an alias forNormedVectorSpace::norm
, but this overlaps with methods in all of the glam types, so we would want to make sure that the implementations are effectively identical (for what it's worth, I think they are already).Future directions
One example of something that could belong in the
NormedVectorSpace
API is normalization. Actually, such a thing previously existed on this branch before I decided to shelve it because of concerns with namespace collision. It looked like this:With this kind of thing in hand, it might be worth considering eventually making the passage from vectors to directions fully generic by employing a wrapper type. (Of course, for our concrete types, we would leave the existing names in place as aliases.) That is, something like:
Utterly separately, the reason that I implemented
ShapeSample
forTriangle2d
/Triangle3d
was to prototype uniform sampling of abstract meshes, so that's also a future direction.