prismqueer 0.1.1

The spectral-triple substrate — five operations (focus, project, split, shift, settle), the Prism trait, zero deps. The foundation.
Documentation
! prism.f90 — A Prism IS a projection matrix.
!
! Adapted from conversation/beam/native/prism.f90 for Rust FFI.
! Same four operations, same bind(c) interface.
!
! preview = project + check nonzero.
! review  = embed via transpose.
! modify  = complement + transform.
! compose = matmul.

module optics_prism
  use iso_c_binding
  implicit none

  private
  public :: prism_preview, prism_review, prism_modify, prism_compose

  real(c_double), parameter :: EPS = 1.0d-12

contains

  ! P * source = focus. matched = 1 if ||focus|| > eps, else 0.
  subroutine prism_preview(n, projection, source, focus, matched) &
      bind(c, name="prism_preview")
    integer(c_int), value, intent(in) :: n
    real(c_double), intent(in) :: projection(n, n)
    real(c_double), intent(in) :: source(n)
    real(c_double), intent(out) :: focus(n)
    integer(c_int), intent(out) :: matched

    real(c_double) :: norm
    integer :: i

    ! Project source into subspace
    focus = matmul(projection, source)

    ! Check if anything landed — L2 norm
    norm = 0.0d0
    do i = 1, n
      norm = norm + focus(i) * focus(i)
    end do
    norm = sqrt(norm)

    if (norm > EPS) then
      matched = 1
    else
      matched = 0
    end if
  end subroutine prism_preview

  ! P^T * focus = result (embed from subspace into full space)
  subroutine prism_review(n, projection, focus, result) &
      bind(c, name="prism_review")
    integer(c_int), value, intent(in) :: n
    real(c_double), intent(in) :: projection(n, n)
    real(c_double), intent(in) :: focus(n)
    real(c_double), intent(out) :: result(n)

    ! Embed via transpose — P^T maps from subspace back to full space
    result = matmul(transpose(projection), focus)
  end subroutine prism_review

  ! (I - P) * source + T * (P * source)
  ! Keep the complement unchanged, transform the matched part.
  subroutine prism_modify(n, projection, source, transform, result) &
      bind(c, name="prism_modify")
    integer(c_int), value, intent(in) :: n
    real(c_double), intent(in) :: projection(n, n)
    real(c_double), intent(in) :: source(n)
    real(c_double), intent(in) :: transform(n, n)
    real(c_double), intent(out) :: result(n)

    real(c_double) :: projected(n), complement(n), identity(n, n)
    integer :: i

    ! Build identity
    identity = 0.0d0
    do i = 1, n
      identity(i, i) = 1.0d0
    end do

    ! Project into subspace
    projected = matmul(projection, source)

    ! Complement: (I - P) * source
    complement = matmul(identity - projection, source)

    ! Result: complement + T * projected
    result = complement + matmul(transform, projected)
  end subroutine prism_modify

  ! composed = P2 * P1 (matrix multiply — prism composition)
  subroutine prism_compose(n, p1, p2, composed) &
      bind(c, name="prism_compose")
    integer(c_int), value, intent(in) :: n
    real(c_double), intent(in) :: p1(n, n)
    real(c_double), intent(in) :: p2(n, n)
    real(c_double), intent(out) :: composed(n, n)

    composed = matmul(p2, p1)
  end subroutine prism_compose

end module optics_prism