Copyright | (c) Justus Sagemüller 2015 |
---|---|
License | GPL v3 |
Maintainer | (@) sagemueller $ geo.uni-koeln.de |
Stability | experimental |
Portability | portable |
Safe Haskell | None |
Language | Haskell2010 |
This is the second prototype of a manifold class. It appears to give considerable
advantages over Manifold
, so that class will probably soon be replaced
with the one we define here (though PseudoAffine
does not follow the standard notion
of a manifold very closely, it should work quite equivalently for pretty much all
Haskell types that qualify as manifolds).
Manifolds are interesting as objects of various categories, from continuous to diffeomorphic. At the moment, we mainly focus on region-wise differentiable functions, which are a promising compromise between flexibility of definition and provability of analytic properties. In particular, they are well-suited for visualisation purposes.
The classes in this module are mostly aimed at manifolds without boundary.
Manifolds with boundary (which we call MWBound
, never manifold!)
are more or less treated as a disjoint sum of the interior and the boundary.
To understand how this module works, best first forget about boundaries – in this case,
, Interior
x ~ xfromInterior
and toInterior
are trivial, and
.+~|
, |-~.
and betweenBounds
are irrelevant.
The manifold structure of the boundary itself is not considered at all here.
- class (PseudoAffine m, LinearManifold (Needle m), Interior m ~ m) => Manifold m
- class (AdditiveGroup (Needle x), Interior (Interior x) ~ Interior x) => Semimanifold x where
- type Needle' x = DualSpace (Needle x)
- class (Semimanifold x, Semimanifold (Interior x), Needle (Interior x) ~ Needle x, Interior (Interior x) ~ Interior x) => PseudoAffine x where
- type Metric x = HerMetric (Needle x)
- type Metric' x = HerMetric' (Needle x)
- euclideanMetric :: EuclidSpace x => proxy x -> Metric x
- type RieMetric x = x -> Metric x
- type RieMetric' x = x -> Metric' x
- type RealDimension r = (PseudoAffine r, Interior r ~ r, Needle r ~ r, HasMetric r, DualSpace r ~ r, Scalar r ~ r, RealFloat r, r ~ ℝ)
- type AffineManifold m = (PseudoAffine m, Interior m ~ m, AffineSpace m, Needle m ~ Diff m, LinearManifold' (Diff m))
- type LinearManifold x = (AffineManifold x, Needle x ~ x, HasMetric x)
- type WithField s c x = (c x, s ~ Scalar (Needle x))
- type HilbertSpace x = (LinearManifold x, InnerSpace x, Interior x ~ x, Needle x ~ x, DualSpace x ~ x, Floating (Scalar x))
- type EuclidSpace x = (AffineManifold x, InnerSpace (Diff x), DualSpace (Diff x) ~ Diff x, Floating (Scalar (Diff x)))
- type LocallyScalable s x = (PseudoAffine x, HasMetric (Needle x), s ~ Scalar (Needle x))
- type LocalLinear x y = Linear (Scalar (Needle x)) (Needle x) (Needle y)
- type LocalAffine x y = (Needle y, LocalLinear x y)
- alerpB :: forall x. (AffineSpace x, VectorSpace (Diff x), Scalar (Diff x) ~ ℝ) => x -> x -> D¹ -> x
- palerp :: forall x. Manifold x => Interior x -> Interior x -> Option (Scalar (Needle x) -> x)
- palerpB :: forall x. WithField ℝ Manifold x => Interior x -> Interior x -> Option (D¹ -> x)
- class (PseudoAffine x, PseudoAffine ξ, Scalar (Needle x) ~ Scalar (Needle ξ)) => LocallyCoercible x ξ where
- locallyTrivialDiffeomorphism :: x -> ξ
- class ImpliesMetric s where
- type MetricRequirement s x :: Constraint
- inferMetric :: (MetricRequirement s x, HasMetric (Needle x)) => s x -> Option (Metric x)
- inferMetric' :: (MetricRequirement s x, HasMetric (Needle x)) => s x -> Option (Metric' x)
Manifold class
class (PseudoAffine m, LinearManifold (Needle m), Interior m ~ m) => Manifold m Source
See Semimanifold
and PseudoAffine
for the methods.
(PseudoAffine m, LinearManifold (Needle m), (~) * (Interior m) m) => Manifold m Source |
class (AdditiveGroup (Needle x), Interior (Interior x) ~ Interior x) => Semimanifold x where Source
The space of “natural” ways starting from some reference point
and going to some particular target point. Hence,
the name: like a compass needle, but also with an actual length.
For affine spaces, Needle
is simply the space of
line segments (aka vectors) between two points, i.e. the same as Diff
.
The AffineManifold
constraint makes that requirement explicit.
This space should be isomorphic to the tangent space (and is in fact used somewhat synonymously).
Manifolds with boundary are a bit tricky. We support such manifolds, but carry out most calculations only in “the fleshy part” – the interior, which is an “infinite space”, so you can arbitrarily scale paths.
The default implementation is
, which corresponds
to a manifold that has no boundary to begin with.Interior
x = x
(.+~^) :: Interior x -> Needle x -> x infixl 6 Source
Generalised translation operation. Note that the result will always also be in the interior; scaling up the needle can only get you ever closer to a boundary.
fromInterior :: Interior x -> x Source
id
sans boundary.
toInterior :: x -> Option (Interior x) Source
translateP :: Tagged x (Interior x -> Needle x -> Interior x) Source
The signature of .+~^
should really be
,
only, this is not possible because it only consists of non-injective type families.
The solution is this tagged signature, which is of course rather unwieldy. That's
why Interior
x -> Needle
x -> Interior
x.+~^
has the stronger, but easier usable signature. Without boundary, these
functions should be equivalent, i.e. translateP = Tagged (.+~^)
.
(.-~^) :: Interior x -> Needle x -> x infixl 6 Source
Shorthand for \p v -> p .+~^
, which should obey the asymptotic lawnegateV
v
p .-~^ v .+~^ v ≅ p
Meaning: if v
is scaled down with sufficiently small factors η, then
the difference (p.-~^v.+~^v) .-~. p
should scale down even faster:
as O (η²). For large vectors, it will however behave differently,
except in flat spaces (where all this should be equivalent to the AffineSpace
instance).
Semimanifold Double Source | |
Semimanifold Rational Source | |
Semimanifold D¹ Source | |
Semimanifold ℝP² Source | |
Semimanifold S² Source | |
Semimanifold S¹ Source | |
Semimanifold S⁰ Source | |
Semimanifold (ZeroDim k) Source | |
AffineManifold x => Semimanifold (ShadeTree x) Source | Experimental. There might be a more powerful instance possible. |
AffineManifold x => Semimanifold (Shade' x) Source | |
AffineManifold x => Semimanifold (Shade x) Source | |
(Semimanifold a, Semimanifold b) => Semimanifold (a, b) Source | |
(HasMetric a, FiniteDimensional b, (~) * (Scalar a) (Scalar b)) => Semimanifold ((:-*) a b) Source | |
Semimanifold x => Semimanifold (WithAny x y) Source | |
(Semimanifold a, Semimanifold b, Semimanifold c) => Semimanifold (a, b, c) Source | |
(HasMetric a, FiniteDimensional b, (~) * (Scalar a) s, (~) * (Scalar b) s) => Semimanifold (Linear s a b) Source |
type Needle' x = DualSpace (Needle x) Source
A co-needle can be understood as a “paper stack”, with which you can measure the length that a needle reaches in a given direction by counting the number of holes punched through them.
class (Semimanifold x, Semimanifold (Interior x), Needle (Interior x) ~ Needle x, Interior (Interior x) ~ Interior x) => PseudoAffine x where Source
This is the class underlying manifolds. (Manifold
only precludes boundaries
and adds an extra constraint that would be circular if it was in a single
class. You can always just use Manifold
as a constraint in your signatures,
but you must define only PseudoAffine
for manifold types –
the Manifold
instance follows universally from this, if 'Interior x ~ x
.)
The interface is (boundaries aside) almost identical to the better-known
AffineSpace
class, but we don't require associativity of .+~^
with ^+^
– except in an asymptotic sense for small vectors.
That innocent-looking change makes the class applicable to vastly more general types:
while an affine space is basically nothing but a vector space without particularly
designated origin, a pseudo-affine space can have nontrivial topology on the global
scale, and yet be used in practically the same way as an affine space. At least the
usual spheres and tori make good instances, perhaps the class is in fact equivalent to
manifolds in their usual maths definition (with an atlas of charts: a family of
overlapping regions of the topological space, each homeomorphic to the Needle
vector space or some simply-connected subset thereof).
(.-~.) :: x -> Interior x -> Option (Needle x) infix 6 Source
The path reaching from one point to another.
Should only yield Nothing
if
- The points are on disjoint segments of a non–path-connected space.
- Either of the points is on the boundary. Use
|-~.
to deal with this.
On manifolds, the identity
p .+~^ (q.-~.p) ≡ q
should hold, at least save for floating-point precision limits etc..
.-~.
and .+~^
only really work in manifolds without boundary. If you consider
the path between two points, one of which lies on the boundary, it can't really
be possible to scale this path any longer – it would have to reach “out of the
manifold”. To adress this problem, these functions basically consider only the
interior of the space.
(.-~!) :: x -> Interior x -> Needle x Source
Unsafe version of .-~.
. If the two points lie in disjoint regions,
the behaviour is undefined.
PseudoAffine Double Source | |
PseudoAffine Rational Source | |
PseudoAffine D¹ Source | |
PseudoAffine ℝP² Source | |
PseudoAffine S² Source | |
PseudoAffine S¹ Source | |
PseudoAffine S⁰ Source | |
PseudoAffine (ZeroDim k) Source | |
(PseudoAffine a, PseudoAffine b) => PseudoAffine (a, b) Source | |
(HasMetric a, FiniteDimensional b, (~) * (Scalar a) (Scalar b)) => PseudoAffine ((:-*) a b) Source | |
PseudoAffine x => PseudoAffine (WithAny x y) Source | |
(PseudoAffine a, PseudoAffine b, PseudoAffine c) => PseudoAffine (a, b, c) Source | |
(HasMetric a, FiniteDimensional b, (~) * (Scalar a) s, (~) * (Scalar b) s) => PseudoAffine (Linear s a b) Source |
Type definitions
Metrics
type Metric x = HerMetric (Needle x) Source
The word “metric” is used in the sense as in general relativity. Cf. HerMetric
.
type Metric' x = HerMetric' (Needle x) Source
euclideanMetric :: EuclidSpace x => proxy x -> Metric x Source
type RieMetric x = x -> Metric x Source
A Riemannian metric assigns each point on a manifold a scalar product on the tangent space. Note that this association is not continuous, because the charts/tangent spaces in the bundle are a priori disjoint. However, for a proper Riemannian metric, all arising expressions of scalar products from needles between points on the manifold ought to be differentiable.
type RieMetric' x = x -> Metric' x Source
Constraints
type RealDimension r = (PseudoAffine r, Interior r ~ r, Needle r ~ r, HasMetric r, DualSpace r ~ r, Scalar r ~ r, RealFloat r, r ~ ℝ) Source
The RealFloat
class plus manifold constraints.
type AffineManifold m = (PseudoAffine m, Interior m ~ m, AffineSpace m, Needle m ~ Diff m, LinearManifold' (Diff m)) Source
The AffineSpace
class plus manifold constraints.
type LinearManifold x = (AffineManifold x, Needle x ~ x, HasMetric x) Source
Basically just an “updated” version of the VectorSpace
class.
Every vector space is a manifold, this constraint makes it explicit.
(Actually, LinearManifold
is stronger than VectorSpace
at the moment, since
HasMetric
requires FiniteDimensional
. This might be lifted in the future.)
type WithField s c x = (c x, s ~ Scalar (Needle x)) Source
Require some constraint on a manifold, and also fix the type of the manifold's
underlying field. For example, WithField ℝ
constrains
HilbertSpace
vv
to be a real (i.e., Double
-) Hilbert space.
Note that for this to compile, you will in
general need the -XLiberalTypeSynonyms
extension (except if the constraint
is an actual type class (like Manifold
): only those can always be partially
applied, for type
constraints this is by default not allowed).
type HilbertSpace x = (LinearManifold x, InnerSpace x, Interior x ~ x, Needle x ~ x, DualSpace x ~ x, Floating (Scalar x)) Source
A Hilbert space is a complete inner product space. Being a vector space, it is also a manifold.
(Stricly speaking, that doesn't have much to do with the completeness criterion;
but since Manifold
s are at the moment confined to finite dimension, they are in
fact (trivially) complete.)
type EuclidSpace x = (AffineManifold x, InnerSpace (Diff x), DualSpace (Diff x) ~ Diff x, Floating (Scalar (Diff x))) Source
An euclidean space is a real affine space whose tangent space is a Hilbert space.
type LocallyScalable s x = (PseudoAffine x, HasMetric (Needle x), s ~ Scalar (Needle x)) Source
Local functions
type LocalAffine x y = (Needle y, LocalLinear x y) Source
Misc
alerpB :: forall x. (AffineSpace x, VectorSpace (Diff x), Scalar (Diff x) ~ ℝ) => x -> x -> D¹ -> x Source
Like alerp
, but actually restricted to the interval between the points.
palerp :: forall x. Manifold x => Interior x -> Interior x -> Option (Scalar (Needle x) -> x) Source
Interpolate between points, approximately linearly. For points that aren't close neighbours (i.e. lie in an almost flat region), the pathway is basically undefined – save for its end points.
A proper, really well-defined (on global scales) interpolation
only makes sense on a Riemannian manifold, as Geodesic
.
palerpB :: forall x. WithField ℝ Manifold x => Interior x -> Interior x -> Option (D¹ -> x) Source
Like palerp
, but actually restricted to the interval between the points,
with a signature like geodesicBetween
rather than alerp
.
class (PseudoAffine x, PseudoAffine ξ, Scalar (Needle x) ~ Scalar (Needle ξ)) => LocallyCoercible x ξ where Source
Instances of this class must be diffeomorphic manifolds, and even have
canonically isomorphic tangent spaces, so that
defines a meaningful “representational identity“ between these spaces.fromPackedVector
. asPackedVector
:: Needle
x -> Needle
ξ
locallyTrivialDiffeomorphism :: x -> ξ Source
Must be compatible with the canonical isomorphism on the tangent spaces,
i.e.
locallyTrivialDiffeomorphism (p .+~^
fromPackedVector
v)
≡ locallyTrivialDiffeomorphism p .+~^ fromPackedVector
v
LocallyCoercible ℝ ℝ Source | |
(PseudoAffine a, PseudoAffine b, PseudoAffine c) => LocallyCoercible ((a, b), c) (a, (b, c)) Source | |
LocallyCoercible ((ℝ, ℝ), ℝ) ((ℝ, ℝ), ℝ) Source | |
(PseudoAffine a, PseudoAffine b, PseudoAffine c) => LocallyCoercible (a, (b, c)) ((a, b), c) Source | |
LocallyCoercible (ℝ, (ℝ, ℝ)) (ℝ, (ℝ, ℝ)) Source | |
LocallyCoercible (ℝ, ℝ) (ℝ, ℝ) Source | |
(PseudoAffine a, PseudoAffine b, PseudoAffine c) => LocallyCoercible ((a, b), c) (a, b, c) Source | |
(PseudoAffine a, PseudoAffine b, PseudoAffine c) => LocallyCoercible (a, (b, c)) (a, b, c) Source | |
(PseudoAffine a, PseudoAffine b, PseudoAffine c) => LocallyCoercible (a, b, c) (a, (b, c)) Source | |
(PseudoAffine a, PseudoAffine b, PseudoAffine c) => LocallyCoercible (a, b, c) ((a, b), c) Source |
class ImpliesMetric s where Source
type MetricRequirement s x :: Constraint Source
inferMetric :: (MetricRequirement s x, HasMetric (Needle x)) => s x -> Option (Metric x) Source
inferMetric' :: (MetricRequirement s x, HasMetric (Needle x)) => s x -> Option (Metric' x) Source