ddg.geometry.quadrics module

Quadrics

class ddg.geometry.quadrics.Quadric(Q, subspace=None, atol=None, rtol=None)[source]

Bases: LinearTransformable, NonExact

Quadric in a projective space.

Parameters:
Qnp.ndarray

Symmetric matrix representing the quadratic form in homogeneous coordinates. The matrix is interpreted as the Gram matrix with respect to the given basis of the containing subspace.

subspaceddg.Subspace or iterable of numpy.ndarray (default=None)

Subspace containing the quadric. Can be given as a list of homogeneous coordinate vectors. If None is given, uses whole space with standard basis.

Raises:
ValueError
  • If Q is not symmetric

  • If the dimension of the subspace does not match the shape of Q.

property ambient_dimension
dimension(real=True)[source]

The (real) dimension of the quadric.

More precisely, the maximum of the dimensions of the manifolds contained in the set of real points in the quadric.

Ignores affine coordinates! I.e. we don’t distinguish between the quadric lying at infinity or not.

Returns:
int

Notes

This function was fully intuited. There is no guarantee that this gives correct results.

at_infinity(affine_component=-1)[source]

Whether or not quadric is at infinity.

Parameters:
affine_componentint (default=-1)
Returns:
bool
coordinates(v)[source]

Get coordinates of vectors in terms of self.subspace’s basis.

Parameters:
vSubspace or numpy.ndarray

Subspace contained in self.subspace or Matrix representing such a subspace (or Point).

Returns:
numpy.ndarray of shape (self.subspace.dimension + 1,)
inner_product(v, w)[source]

Inner product defined by / defining the quadric.

Parameters:
v, wnumpy.ndarray of shape (ambient_dimension + 1,)

Two vectors that lie in the containing subspace.

Returns:
float

a.T @ matrix @ b, where a and b are the coordinates of v and w in terms of the given basis of the containing subspace.

cayley_klein_distance(v, w)[source]

Cayley-Klein “distance”.

This is defined as

b(v, w) ** 2 / (b(v, v) * b(w, w))

Where b is the inner product induced by the absolute. None of the points can lie on the absolute.

Parameters:
v, wnumpy.ndarray or Point

Homogeneous coordinate vectors or Point instances

Returns:
float
Raises:
ValueError

If either of the points is contained in the absolute quadric.

conjugate(S1, S2)[source]

Conjugacy of two subspaces.

Whether two subspaces are conjugate, i.e. if approximately inner_product(v, w) == 0 for all v in S1 and w in S2.

Parameters:
S1, S2ddg.geometry.subspaces.Subspace or numpy.ndarray

Subspaces contained in self.subspace. Arrays will be interpreted as matrices whose columns are points in homogeneous coordinates. In particular, 1D arrays are simply points in homogeneous coordinates.

Returns:
bool
polarize(obj)[source]

Alias for polarize(obj, self).

See also

polarize
signature(subspace=None, affine=False, affine_component=-1)[source]

Alias for signature().

normalize(affine=False, affine_component=-1)[source]

Return an equal quadric expressed in coordinates that normalize it.

Returns an equal quadric Q_normalized such that

Q_normalized.matrix == sgn.matrix

where sgn = self.signature(affine, affine_component). See ddg.math.symmetric_matrices.Signature and ddg.math.symmetric_matrices.AffineSignature for more information.

If affine=True, Q_normalized.subspace.points will be in the form [d1,…,dn, p], where n is the dimension of the subspace, d1,…,dn are directions at infinity and p is a point in the subspace not at infinity (according to affine_component). This means that the returned AffineSignature instance will always have affine_component -1.

Parameters:
affinebool (default=False)
affine_componentint (default=-1)
Returns:
Q_normalizedQuadric
property rank

Rank of self.matrix.

Returns:
int
property corank

Corank of self.matrix.

Returns:
int
property singular_subspace

Singular subspace.

Subspace containing all singular points of the quadric (points in the kernel of self.matrix).

Returns:
ddg.geometry.subspaces.Subspace of dimension corank - 1 and the
same ambient dimension as the quadric.
property non_degenerate_subspace

Non-degenerate subspace.

Complementary subspace of the kernel of self.matrix.

Returns:
ddg.geometry.subspaces.Subspace

Has dimension rank - 1 and the same ambient dimension as the quadric.

property is_degenerate

Whether the quadric is degenerate.

Returns:
bool
dualize()[source]
dual_transformation(F)[source]

Dualizes a transformation of the ambient space.

Parameters:
Fnumpy.ndarray of shape (ambient_dimension+1, ambient_dimension+1)

An invertible matrix.

Returns:
F_dualnumpy.ndarray of shape (ambient_dimension+1,ambient_dimension+1)

This is an invertible matrix that approximately satisfies F_dual @ B_dual == F @ B @ np.linalg.inv((F @ B).T @ (F @ B)), where B_dual is the subspace of the dual quadric. That is, it maps the old dual basis to the new one.

push_transformation(F)[source]

Transform the quadric by a transformation of the ambient space.

Parameters:
Fnumpy.ndarray of shape (ambient_dimension+1, ambient_dimension+1)

Invertible matrix.

pop_transformation()[source]

Pop transformation from the trafo-stack.

Returns:
function
property atol
atol_default = 1e-07

Absolute tolerance default.

Used for all purposes if atol is None.

classmethod nonexact_function(f)

Decorator to use global tolerance defaults in functions.

If None is given to the wrapped function as the value for atol or rtol, it will be replaced by the global default.

Parameters:
fcallable

Function that takes atol and rtol arguments.

Returns:
callable
classmethod reset_tol_defaults()
property rtol
rtol_default = 0.0

Relative tolerance default.

Used for all purposes if rtol is None.

transform(f)

Wrapper for push_transformation.

property transformation

Product of all matrices on the stack.

Returns:
numpy.ndarray
class ddg.geometry.quadrics.Pencil(Q1, Q2, **kwargs)[source]

Bases: LinearTransformable

Pencil of quadrics in a projective space.

Parameters:
Q1, Q2Quadric or numpy.ndarray

Quadrics spanning the pencil. If given as arrays, they will be created. If one is given as a quadric and the other as an array, the newly created one will have matching affine component to the given one, unless overridden by kwargs.

**kwargsdict

Keyword arguments to be passed to Quadric during creation of Q1 and Q2, if they are given as arrays.

Raises:
ValueError
  • If the geometries of the quadrics don’t match

  • If the quadrics are not in the same subspace

property ambient_dimension
push_transformation(f)[source]

Add a transformation to the trafo-stack.

Parameters:
fnumpy.ndarray
pop_transformation()[source]

Pop transformation from the trafo-stack.

Returns:
function
quadric(u)[source]

Return a quadric in the pencil.

The pencil is parametrized as [u1*Q1 + u2*Q2]. We identify [1, a] <-> a and [0, 1] <-> inf.

Parameters:
uarray_like (float, float) or float including inf.

A finite float will be interpreted as (1, u) and inf will be interpreted as (0, 1).

Returns:
Quadric
roots()[source]

Find values for which quadrics in the pencil are degenerate.

This function calculates the roots of the polynomial det(Q1 + lambda*Q2) and their multiplicity.

Returns:
dict {complex or inf: int}

Dictionary whose keys are the roots as complex numbers (or infinity) and whose values are their multiplicity.

degenerate_quadrics(real=True)[source]

Calculate degenerate quadrics in the pencil.

Parameters:
realbool (default=True)

If True, only use real roots.

Returns:
list of Quadric
transform(f)

Wrapper for push_transformation.

property transformation

Product of all matrices on the stack.

Returns:
numpy.ndarray
ddg.geometry.quadrics.touching_cone(p, quadric, in_subspace=False)[source]

Calculate touching cone.

The touching cone of a quadric Q and a point P is the set of lines through P that are tangent to Q.

Note that by default, this function looks at tangency in the ambient space as opposed to within quadric.subspace. This means that if the quadric is contained in a proper subspace, the function returns the join of p and quadric.

Parameters:
pnumpy.ndarray of shape (quadric.ambient_dimension+1,) or Point

Point in homogeneous coordinates. Must lie in quadric.subspace if in_subspace is True.

quadricQuadric
in_subspacebool (default=False)
Returns:
Quadric or Subspace
Raises:
ValueError

If in_subspace is True and p is not contained in quadric.subspace.

ddg.geometry.quadrics.cayley_klein_sphere(center, radius, absolute)[source]

Create a Cayley-Klein sphere from center, radius and absolute.

Let b be the inner product induced by the absolute. A Cayley-Klein sphere is defined as the solution set of:

b(center, x) ** 2 - radius * b(center, center) * b(x, x) = 0

Note that if center lies on the absolute, you will just get the polar hyperplane of center.

Parameters:
centerPoint
radiusfloat
absoluteQuadric
Returns:
Quadric
Raises:
ValueError

If center lies on absolute.

ddg.geometry.quadrics.cayley_klein_horosphere(center, radius, absolute)[source]

Create Cayley-Klein Horosphere from center, “radius” and absolute.

Let b be the inner product induced by the absolute. A Cayley-Klein sphere is defined as the solution set of:

b(center, x) ** 2 - radius * b(x, x) = 0

This allows centers to lie on the absolute quadric, at the expense of depending on the representative vector of center. The equation of a regular Cayley-Klein sphere can still be obtained by using the new radius radius * b(center, center).

Parameters:
centerPoint
radiusfloat
absoluteQuadric
Returns:
Quadric
ddg.geometry.quadrics.axis(cone, affine_component=-1)[source]

Find the axis of a non-parabolic cone.

More precisely: The axis of a non-parabolic quadric with signature (n-1, 1, 1), where n is the dimension of the containing subspace.

Parameters:
coneQuadric
affine_componentint (default=-1)
Returns:
Subspace
Raises:
ValueError

If Quadric does not have the signature mentioned above.

ddg.geometry.quadrics.normalization(quadric, affine=False, affine_component=-1)[source]

Signature and normalizing transformation.

Approximately satisfies:

F.T @ quadric.matrix @ F == sgn.matrix

See ddg.math.symmetric_matrices.Signature and ddg.math.symmetric_matrices.AffineSignature for more information.

Note that this is a transformation within the subspace as opposed to a transformation of the ambient space and thus cannot be used with quadric.transform.

Parameters:
quadricQuadric
affinebool (default=False)

Whether to normalize to projective or affine normal form.

affine_componentint (default=-1)
Returns:
sgnSignature or AffineSignature
Fnumpy.ndarray of shape (ambient_dimension+1, dimension+2)

Transformation that normalizes the quadric

ddg.geometry.quadrics.intersect_quadric_subspace(quadric, subspace)[source]

Intersect quadric with subspace

Parameters:
quadricQuadric
subspaceSubspace
Returns:
Quadric
ddg.geometry.quadrics.join_quadric_subspace(quadric, subspace)[source]

Join a quadric and a subspace.

The result will be the projective cone with top S and basis Q.

Parameters:
quadricQuadric
subspaceSubspace
Returns:
Quadric or Subspace
Raises:
ValueError

If quadric.subspace and subspace are not disjoint.

NotImplementedError
  • If quadric.subspace and subspace are not disjoint and subspace is not a point

  • If the join is an object like a “solid cone”, which we can’t represent.

ddg.geometry.quadrics.intersect_quadrics(quadric1, quadric2, affine=False, affine_component=-1, atol=1e-09, rtol=0.0)[source]

Intersection curve of certain quadrics.

Currently only works for two quadrics that are both contained in a pencil

u1 * diag([1, 1, 0, -1]) + u2 * diag([0, k, 1, -1])
     \_______  ________/        \_______  ________/
             \/                         \/
             D1                         D2

for some k in [0, 1]. The quadrics can be contained in any 3D subspace as long as they are given w.r.t. the same basis. The function checks if both quadrics are contained in a pencil like this.

If you know your two quadrics with matrices Q1, Q2 are contained in a transformed version of such a pencil, i.e.

u1 * F.T @ D1 @ F + u2 * F.T @ D2 @ F

for some known invertible F, you can make it work as well: Let B be quadric1.subspace.matrix. Then the quadrics

Quadric(inv(F.T) @ Q1 @ inv(F), subspace=(B @ inv(F)).T)
Quadric(inv(F.T) @ Q1 @ inv(F), subspace=(B @ inv(F)).T)

can be intersected with this function. Automatic detection of this is not yet implemented.

Parameters:
quadric1, quadric2Quadric
affinebool (default=False)

Whether the resulting curve should output affine or homogeneous coordinates.

affine_componentint (default=-1)

Used to dehomogenize the output curve.

atolfloat (default=1e-9)
rtolfloat(default=0.0)
Returns:
NetCollection
Raises:
ValueError
  • If the two quadrics are given in different coordinate systems.

  • If quadric1 and quadric2 do not span the above-mentioned pencil.

Notes

For visualization purposes, not all subspace bases work well, because the curve might pass through infinity.

This function uses the global tolerance defaults if atol or rtol are set to None. See ddg.abc.NonExact for details.

ddg.geometry.quadrics.polarize(obj, quadric)[source]

Polarize a geometric object with respect to a quadric.

Parameters:
objGeometric object

Currently supported: Subspace, Quadric.

quadricQuadric
Returns:
type(obj)
Raises:
TypeError

If the type of object is not supported.

ddg.geometry.quadrics.signature(quadric, subspace=None, affine=False, affine_component=-1)[source]

Signature of a quadric, optionally restricted to a subspace.

Parameters:
subspaceSubspace or None (default=None)

Subspace contained in self.subspace

affinebool (default=False)

Whether to return projective or affine signature

affine_componentint (default=-1)
Returns:
Signature or AffineSignature
Raises:
ValueError

If subspace is not contained in self.subspace.