Dedekind 0.0.0
A structuralist C++23 Module Library
Loading...
Searching...
No Matches
outer_product.cppm File Reference

Concept-side anchoring for the outer / dyadic / rank-1 product space (#535). More...

#include <concepts>
#include <cstddef>
#include <functional>
import dedekind.geometry:linear_map;
import dedekind.algebra;
Include dependency graph for outer_product.cppm:

Namespaces

namespace  dedekind::geometry::detail_ops

Concepts

concept  dedekind::geometry::IsOuterProductSpace
 W carries the outer-product structure for factor spaces U and V: there is a dyad(u, v) → W constructor representing u ⊗ v in W.

Functions

template<IsMatrixScalar F, std::size_t M, std::size_t N>
requires dedekind::category::IsField<F, std::plus<F>, std::multiplies<F>>
constexpr LinearMap< F, M, N > dedekind::geometry::dyad (const Vector< F, M > &u, const Vector< F, N > &v)
template<IsMatrixScalar F, std::size_t M, std::size_t N>
requires dedekind::category::IsField<F, std::plus<F>, std::multiplies<F>>
constexpr LinearMap< F, M, N > dedekind::geometry::operator* (const Vector< F, M > &u, const Covector< F, N > &phi)

Detailed Description

Concept-side anchoring for the outer / dyadic / rank-1 product space (#535).

@partition :outer_product

ops__Motivation

Before this partition the codebase had a single inhabitant of the outer product: the eager finite-dim free function geometry::outer(u, v) → LinearMap<F, M, N> in geometry:linear_map. No concept-level claim that the resulting carrier is the outer-product space U ⊗ V, no recognition that LinearMap inhabits such a space, and no static-assertable pin of the bilinearity / rank-1 entry laws.

This partition adds:

  • IsOuterProductSpace<W, U, V> — concept witnessing that W carries an outer-product structure for factor spaces U and V (universal-property shape: a dyad arrow U × V → W exists).
  • dyad(u, v) — the outer-product constructor under the concept's expected name; today an alias to the existing geometry::outer(u, v) free function.
  • Static_assert pins for the bilinearity laws (left and right factor) and the rank-1 entry law on a concrete Vector<double, 2> ⊗ Vector<double, 3> witness.

The intensional / any-cardinality sibling dedekind::linear_algebra::OuterProduct<U, V> (slice e of #372, landing in #534) is the lazy face of the same mathematical object; a to_dense companion arrow at finite dimensions is tracked as a follow-up on #535 (it requires a partition that imports both geometry and linear_algebra:diagonal, which neither side currently does).

ops__Universal_Property_Sketch

Mathematically, the outer product space U ⊗ V is the universal carrier of bilinear maps out of U × V: for any bilinear B: U × V → X there is a unique linear B̃: U ⊗ V → X with B(u, v) = B̃(u⊗v). The IsOuterProductSpace concept here pins the construction arrow dyad: U × V → W and the bilinearity laws value-side; the universal property itself is asserted by documentation (the C++ type system can't witness universality directly without a category-theoretic encoding that the project does not lift to this layer today).

Function Documentation

◆ dyad()

template<IsMatrixScalar F, std::size_t M, std::size_t N>
requires dedekind::category::IsField<F, std::plus<F>, std::multiplies<F>>
LinearMap< F, M, N > dedekind::geometry::dyad ( const Vector< F, M > & u,
const Vector< F, N > & v )
constexprexport

ops__Constructor

dyad(u, v) is the outer-product constructor under the concept's expected name, gated to strict-field scalars (dedekind::category::IsField<F>). This deliberately tightens past IsMatrixScalar (which today admits double under the DEDEKIND_ENABLE_DOUBLE_REAL_PROXY policy gate) — double is not a strict field (rounding-non-associativity), so the new operator surface refuses it. Rational<long> / strict-field carriers will become admissible once Vector<F, N> / LinearMap<F, M, N> broaden their IsMatrixScalar gate to admit IsField carriers (tracked on #535).

Aliased: today the body delegates to the legacy geometry::outer(u, v), which carries the looser IsMatrixScalar constraint. At sites that pin IsField, the alias is strictly stronger; on the legacy path, geometry::outer remains available.

◆ operator*()

template<IsMatrixScalar F, std::size_t M, std::size_t N>
requires dedekind::category::IsField<F, std::plus<F>, std::multiplies<F>>
LinearMap< F, M, N > dedekind::geometry::operator* ( const Vector< F, M > & u,
const Covector< F, N > & phi )
constexprexport

ops__Operator_Surface

Standard linear-algebra notation: a column vector multiplied by a row vector (covector) on the right gives the dyadic / outer product, a rank-1 LinearMap.

Vector<F, M> × Covector<F, N> → LinearMap<F, M, N>

This is the outer-product face of operator*; the dual inner-product face Covector × Vector → F lives in :inner_product. Same strict-IsField gate as dyad(u, v) above — the operator surface refuses non-field scalars (double in particular).