sov-kernel-monster / src /training_adjoint.f90
SNAPKITTYWEST's picture
chore: push full sov-kernel-monster content from local build
9425aed verified
Raw
History Blame Contribute Delete
19.5 kB
!=====================================================================
! TRAINING ADJOINT β€” Reverse-Mode AD on the Density Cone
!
! Trains {H_k} Hamiltonians via geodesic flow on (Ω, g_ρ)
! Loss: Wasserstein / Bures metric between ρ_pred and ρ_target
!
! Forward: ρ_T = T_N ∘ ... ∘ T_1 ∘ ρ_0 (jordan_fib)
! Loss: L = d_Bures(ρ_T, ρ_target)²
! Backward: Ξ»Μ‡ = i[H_k, Ξ»] (adjoint ODE, reverse)
! Ξ»_T = βˆ‡_ρ L = ρ_target - ρ_T (terminal condition)
! Gradient: βˆ‚L/βˆ‚H_k = -iΒ·dt·φ⁻¹·[Ξ»_k, ρ_k] (jordan_gradient)
! Update: H_k ← H_k - Ξ·Β·βˆ‚L/βˆ‚H_k (projected to Hermitian)
! Bifrost: sign new {H_k} β†’ WORM (every update sealed)
!
! APL glyph map:
! Forward pass ≑ \ jordan_step (scan \)
! Loss gradient ≑ ρ_target - ρ_T (array -)
! Adjoint reverse ≑ ⌽ (backward ODE) (reverse ⌽)
! Gradient accum ≑ +/ (Ξ»_k ∘.Γ— ρ_k) (outer ∘.Γ— then reduce +/)
! H update ≑ H - Ξ· Γ— βˆ‚L/βˆ‚H (scalar Γ— then -)
! Project Herm ≑ Β½ Γ— (H + ⍉ HΜ„) (conjugate transpose ⍉ ⍀ Β―)
!
! Liquid Haskell:
! {-@ bures_loss :: Density d β†’ Density d β†’ {l : Float | l β‰₯ 0} @-}
! {-@ adjoint_pass :: Vec N (Hermitian d) β†’ Vec N (Density d) β†’ Density d
! β†’ Vec N (Hermitian d) @-}
! {-@ project_hermitian :: M d d β„‚ β†’ Hermitian d @-}
! {-@ training_step :: Vec N (Hermitian d) β†’ Density d β†’ Density d
! β†’ Float β†’ {H' : Vec N (Hermitian d) | βˆ€k. hermitian H'!k} @-}
!
! Audit Spec: 4b565498-9afc-4782-af4a-c6b11a5d0058
!=====================================================================
module training_adjoint
use, intrinsic :: iso_c_binding, only: c_int64_t, c_ptr, c_f_pointer, &
c_size_t, c_loc, c_char, c_associated, c_null_ptr
use, intrinsic :: iso_fortran_env, only: int64, real64, int8
use sov_monster_kernel, only: dp, ci, czero, &
sov_zmexp_scaling_squaring, sov_apl_step_zgemm_fused, &
sov_zgetrf, sov_zgetrs, &
sov_blake3_hash_matrix, sov_bifrost_sign, &
sov_is_hermitian_matrix, sov_is_density_matrix, sov_fault, i8
use jordan_block, only: jordan_step, jordan_gradient, PHI_INV
use sov_knowledge, only: knowledge_penalty_scale, ensure_sovereign_kb, &
sovereign_kb, knowledge_chunk
implicit none
private
public :: bures_loss
public :: adjoint_pass
public :: project_hermitian
public :: training_step
public :: adam_update
public :: adam_state_t
public :: apply_knowledge_gradient_correction
real(dp), parameter :: PHI_IN2 = 0.3819660112501051518_dp
!═══════════════════════════════════════════════════════════════════
! ADAM STATE β€” momentum buffers for each Hamiltonian layer
!═══════════════════════════════════════════════════════════════════
type, bind(C) :: adam_state_t
real(dp) :: beta1 ! default 0.9
real(dp) :: beta2 ! default 0.999
real(dp) :: epsilon ! default 1e-8
real(dp) :: lr ! learning rate
integer(c_int64_t) :: t ! step counter
type(c_ptr) :: m_ptr ! first moment [N, d, d] complex
type(c_ptr) :: v_ptr ! second moment [N, d, d] real (elementwise sq)
end type
contains
!═══════════════════════════════════════════════════════════════════
! bures_loss β€” L = ‖ρ_pred βˆ’ ρ_targetβ€–Β²_F (Frobenius proxy for Bures)
!
! {-@ bures_loss :: Density d β†’ Density d β†’ {l : Float | l β‰₯ 0} @-}
!
! APL: L ← +/ , (ρ_pred - ρ_target) Γ— βŠƒ (ρ_pred - ρ_target)
! ≑ +/ , |diff|Β² β€” ravel , then reduce + over squares
!
! Note: true Bures = 2(1 - tr√(√ρ_pred ρ_target √ρ_pred))
! Frobenius is cheap, differentiable, same fixed point
!═══════════════════════════════════════════════════════════════════
function bures_loss(pred_ptr, target_ptr, d) result(L) &
bind(C, name="bures_loss")
type(c_ptr), intent(in), value :: pred_ptr, target_ptr
integer(c_int64_t), intent(in), value :: d
real(dp) :: L
complex(dp), pointer :: pred(:,:), target(:,:)
integer(c_int64_t) :: i, j
call c_f_pointer(pred_ptr, pred, [d, d])
call c_f_pointer(target_ptr, target, [d, d])
! APL: L ← +/ , |ρ_pred - ρ_target|Β²
L = 0.0_dp
!$omp parallel do collapse(2) default(none) &
!$omp shared(pred,target,d) private(i,j) reduction(+:L)
do i = 1, d
do j = 1, d
L = L + abs(pred(i,j) - target(i,j))**2
end do
end do
!$omp end parallel do
end function
!═══════════════════════════════════════════════════════════════════
! adjoint_pass β€” reverse-mode through N jordan_blocks
!
! {-@ adjoint_pass :: Vec N (Hermitian d) β†’ Vec N (Density d)
! β†’ Density d β†’ Vec N (Hermitian d) @-}
!
! APL: Ξ»_T ← ρ_target - ρ_T β€” terminal gradient (array -)
! grads ← ⌽ {jordan_gradient Ξ»_k ρ_k} over k β€” reverse ⌽
!
! Adjoint ODE (discrete):
! Ξ»_{k-1} = U_k† Ξ»_k U_k Β· φ⁻¹ + Ξ»_k Β· φ⁻² (reverse of jordan_step)
!═══════════════════════════════════════════════════════════════════
subroutine adjoint_pass(H_list_ptr, rho_list_ptr, target_ptr, n_layers, d, dt, grads_ptr, sk_ptr, pk_ptr) &
bind(C, name="adjoint_pass")
type(c_ptr), intent(in), value :: H_list_ptr, rho_list_ptr
type(c_ptr), intent(in), value :: target_ptr, grads_ptr
integer(c_int64_t), intent(in), value :: n_layers, d
real(dp), intent(in), value :: dt
type(c_ptr), intent(in), value :: sk_ptr, pk_ptr
complex(dp), pointer :: H_list(:,:,:), rho_list(:,:,:)
complex(dp), pointer :: target(:,:), grads(:,:,:)
complex(dp), allocatable, target :: lambda(:,:), lambda_prev(:,:)
complex(dp), allocatable :: U(:,:), Ut(:,:), tmp(:,:)
integer(c_int64_t) :: k, i, j, l
integer(i8) :: dummy_hash(32), dummy_sig(64)
call c_f_pointer(H_list_ptr, H_list, [n_layers, d, d])
call c_f_pointer(rho_list_ptr, rho_list, [n_layers, d, d])
call c_f_pointer(target_ptr, target, [d, d])
call c_f_pointer(grads_ptr, grads, [n_layers, d, d])
allocate(lambda(d,d), lambda_prev(d,d), U(d,d), Ut(d,d), tmp(d,d))
! APL: Ξ»_T ← ρ_target - ρ_pred β€” terminal condition: βˆ‡_ρ L
lambda = target - rho_list(n_layers,:,:)
! APL: grads ← ⌽ {jordan_gradient Ξ»_k ρ_k} β€” reverse ⌽ over layers
do k = n_layers, 1, -1
! ── Gradient for H_k: βˆ‚L/βˆ‚H_k = -iΒ·dt·φ⁻¹·[Ξ»_k, ρ_k] ──
call jordan_gradient(c_loc(rho_list(k,1,1)), c_loc(lambda(1,1)), &
d, dt, c_loc(grads(k,:,:)))
! ── Propagate adjoint backward through jordan_step ──
! Reverse of: ρ_{k} = φ⁻¹·U ρ_{k-1} U† + φ⁻²·ρ_{k-1}
! Ξ»_{k-1} = φ⁻¹·U† Ξ»_k U + φ⁻²·λ_k
U = (-ci) * dt * H_list(k,:,:)
call sov_zmexp_scaling_squaring(U, int(d))
! Ut = U† (APL: ⍉ Εͺ)
!$omp parallel do collapse(2) default(none) shared(Ut,U,d) private(i,j)
do i = 1, d; do j = 1, d
Ut(i,j) = conjg(U(j,i))
end do; end do
!$omp end parallel do
! tmp = Ut Ξ»_k U (APL: Ut +.Γ— Ξ» +.Γ— U)
tmp = matmul(Ut, matmul(lambda, U))
! APL: Ξ»_{k-1} ← (φ⁻¹ Γ— tmp) + (φ⁻² Γ— Ξ»_k)
!$omp parallel do collapse(2) default(none) &
!$omp shared(lambda_prev,tmp,lambda,d) private(i,j)
do i = 1, d; do j = 1, d
lambda_prev(i,j) = PHI_INV * tmp(i,j) + PHI_IN2 * lambda(i,j)
end do; end do
!$omp end parallel do
lambda = lambda_prev
end do
deallocate(lambda, lambda_prev, U, Ut, tmp)
end subroutine
!═══════════════════════════════════════════════════════════════════
! apply_knowledge_gradient_correction β€” sovereign trust-aware update
!
! SOVEREIGN KNOWLEDGE GRADIENT CORRECTION:
! Query KB for channel constraints; scale grads by
! (1 βˆ’ Ο† Β· unverified/total) so trust violations decay Ο†-wise.
!═══════════════════════════════════════════════════════════════════
subroutine apply_knowledge_gradient_correction(grads_ptr, n_layers, d, query_ptr, query_len) &
bind(C, name="apply_knowledge_gradient_correction")
type(c_ptr), intent(in), value :: grads_ptr, query_ptr
integer(c_int64_t), intent(in), value :: n_layers, d, query_len
complex(dp), pointer :: grads(:,:,:)
type(knowledge_chunk), allocatable :: constraint_chunks(:)
character(kind=c_char), pointer :: qbuf(:)
character(len=:), allocatable :: query
integer :: i, n_out, n_unverified, nq
real(dp) :: scale
call ensure_sovereign_kb()
call c_f_pointer(grads_ptr, grads, [n_layers, d, d])
nq = max(0, int(query_len))
n_out = 0
n_unverified = 0
if (nq > 0 .and. c_associated(query_ptr)) then
call c_f_pointer(query_ptr, qbuf, [nq])
allocate(character(len=nq) :: query)
do i = 1, nq
query(i:i) = transfer(qbuf(i), ' ')
end do
call sovereign_kb%search(query, 3, constraint_chunks, n_out)
do i = 1, n_out
if (.not. constraint_chunks(i)%is_verified) n_unverified = n_unverified + 1
if (.not. sovereign_kb%verify(constraint_chunks(i)%chunk_id)) then
n_unverified = n_unverified + 1
end if
end do
end if
scale = knowledge_penalty_scale(max(n_out, 1), n_unverified)
grads = scale * grads
end subroutine
!═══════════════════════════════════════════════════════════════════
! project_hermitian β€” ensure H stays in the symmetric cone
!
! {-@ project_hermitian :: M d d β„‚ β†’ Hermitian d @-}
!
! APL: H ← Β½ Γ— (H + ⍉ HΜ„) β€” average with conjugate transpose
! (conjugate transpose: ⍉ on transposed then Β― conjugate)
!═══════════════════════════════════════════════════════════════════
subroutine project_hermitian(H_ptr, d) &
bind(C, name="project_hermitian")
type(c_ptr), intent(in), value :: H_ptr
integer(c_int64_t), intent(in), value :: d
complex(dp), pointer :: H(:,:)
integer(c_int64_t) :: i, j
complex(dp) :: sym
call c_f_pointer(H_ptr, H, [d, d])
! APL: H ← Β½ Γ— (H + ⍉ HΜ„)
!$omp parallel do default(none) shared(H,d) private(i,j,sym)
do i = 1, d
do j = i, d
sym = 0.5_dp * (H(i,j) + conjg(H(j,i)))
H(i,j) = sym
H(j,i) = conjg(sym)
end do
end do
!$omp end parallel do
if (.not. sov_is_hermitian_matrix(H, d)) call sov_fault(901)
end subroutine
!═══════════════════════════════════════════════════════════════════
! training_step β€” one complete forward + backward + update
!
! {-@ training_step :: Vec N (Hermitian d) β†’ Density d β†’ Density d
! β†’ Float β†’ {H' | βˆ€k. hermitian H'!k} @-}
!
! APL one-liner (the whole training loop in APL):
! H ← H - Ξ· Γ— ⌽ (jordan_gradient Β¨ Ξ» ∘.⍒ ρ)
!
! Every H update sealed to WORM via Bifrost
!═══════════════════════════════════════════════════════════════════
subroutine training_step(H_list_ptr, rho0_ptr, target_ptr, n_layers, d, dt, eta, sk_ptr, pk_ptr, loss_out) &
bind(C, name="training_step")
type(c_ptr), intent(in), value :: H_list_ptr, rho0_ptr, target_ptr
integer(c_int64_t), intent(in), value :: n_layers, d
real(dp), intent(in), value :: dt, eta
type(c_ptr), intent(in), value :: sk_ptr, pk_ptr
real(dp), intent(out) :: loss_out
complex(dp), pointer :: H_list(:,:,:), rho0(:,:)
complex(dp), pointer :: target(:,:)
complex(dp), allocatable, target :: rho_list(:,:,:), grads(:,:,:)
complex(dp), allocatable, target :: rho_cur(:,:), rho_nxt(:,:)
integer(i8), allocatable, target :: receipts(:)
integer(c_int64_t) :: k, receipt_sz
integer(i8), target :: hash_buf(32), sig_buf(64)
integer(c_int64_t) :: i, j
call c_f_pointer(H_list_ptr, H_list, [n_layers, d, d])
call c_f_pointer(rho0_ptr, rho0, [d, d])
call c_f_pointer(target_ptr, target, [d, d])
receipt_sz = 96
allocate(rho_list(n_layers, d, d))
allocate(grads(n_layers, d, d))
allocate(rho_cur(d,d), rho_nxt(d,d))
allocate(receipts(n_layers * receipt_sz))
! ── APL: FORWARD PASS β€” \ jordan_step over H_list ──────────────
rho_cur = rho0
do k = 1, n_layers
call jordan_step( &
c_loc(H_list(k,1,1)), c_loc(rho_cur(1,1)), d, dt, &
sk_ptr, pk_ptr, c_loc(rho_nxt(1,1)), &
c_loc(receipts((k-1)*receipt_sz+1)), &
c_loc(receipts((k-1)*receipt_sz+33)))
rho_list(k,:,:) = rho_nxt
rho_cur = rho_nxt
end do
! ── LOSS ────────────────────────────────────────────────────────
loss_out = bures_loss(c_loc(rho_cur(1,1)), target_ptr, d)
! ── APL: BACKWARD PASS β€” ⌽ adjoint over layers ─────────────────
call adjoint_pass( &
c_loc(H_list(1,1,1)), c_loc(rho_list(1,1,1)), target_ptr, &
n_layers, d, dt, c_loc(grads(1,1,1)), sk_ptr, pk_ptr)
! ── SOVEREIGN KNOWLEDGE: Ο†-decay trust scale on gradients ──────
call apply_knowledge_gradient_correction(c_loc(grads(1,1,1)), n_layers, d, &
c_null_ptr, 0_c_int64_t)
! ── APL: UPDATE β€” H ← H - Ξ· Γ— βˆ‚L/βˆ‚H ───────────────────────────
!$omp parallel do default(none) &
!$omp shared(H_list,grads,n_layers,d,eta) private(k)
do k = 1, n_layers
do i = 1, d; do j = 1, d
H_list(k,i,j) = H_list(k,i,j) - eta * grads(k,i,j)
end do; end do
! APL: H_k ← Β½ Γ— (H_k + ⍉ HΜ„_k) β€” project to Hermitian
call project_hermitian(c_loc(H_list(k,1,1)), d)
end do
!$omp end parallel do
! ── BIFROST: seal updated Hamiltonians ──────────────────────────
do k = 1, n_layers
call sov_blake3_hash_matrix(H_list(k,:,:), int(d), c_loc(hash_buf(1)))
call sov_bifrost_sign(c_loc(hash_buf(1)), int(32,c_size_t), sk_ptr, c_loc(sig_buf(1)))
end do
deallocate(rho_list, grads, rho_cur, rho_nxt, receipts)
end subroutine
!═══════════════════════════════════════════════════════════════════
! adam_update β€” Adam optimizer on Hamiltonians
!
! {-@ adam_update :: AdamState β†’ Vec N (Hermitian d)
! β†’ Vec N (Hermitian d) β†’ Vec N (Hermitian d) @-}
!
! APL: m ← β₁ Γ— m + (1-β₁) Γ— g β€” first moment
! v ← Ξ²β‚‚ Γ— v + (1-Ξ²β‚‚) Γ— gΓ—g β€” second moment (Γ— = elementwise)
! mΜ‚ ← m Γ· (1 - β₁ᡗ) β€” bias correction
! vΜ‚ ← v Γ· (1 - Ξ²β‚‚α΅—)
! H ← H - lr Γ— mΜ‚ Γ· (√vΜ‚ + Ξ΅) β€” Adam step
! H ← Β½ Γ— (H + ⍉ HΜ„) β€” project Hermitian
!═══════════════════════════════════════════════════════════════════
subroutine adam_update(state, H_list_ptr, grads_ptr, n_layers, d) &
bind(C, name="adam_update")
type(adam_state_t), intent(inout) :: state
type(c_ptr), intent(in), value :: H_list_ptr, grads_ptr
integer(c_int64_t), intent(in), value :: n_layers, d
complex(dp), pointer :: H_list(:,:,:), grads(:,:,:)
complex(dp), pointer :: m(:,:,:)
real(dp), pointer :: v(:,:,:)
real(dp) :: bc1, bc2, lr_t
integer(c_int64_t) :: k, i, j
complex(dp) :: m_hat, g
real(dp) :: v_hat
call c_f_pointer(H_list_ptr, H_list, [n_layers, d, d])
call c_f_pointer(grads_ptr, grads, [n_layers, d, d])
call c_f_pointer(state%m_ptr, m, [n_layers, d, d])
call c_f_pointer(state%v_ptr, v, [n_layers, d, d])
state%t = state%t + 1
! Bias correction factors
bc1 = 1.0_dp - state%beta1**state%t
bc2 = 1.0_dp - state%beta2**state%t
lr_t = state%lr * sqrt(bc2) / bc1
!$omp parallel do collapse(3) default(none) &
!$omp shared(H_list,grads,m,v,state,lr_t,n_layers,d) &
!$omp private(k,i,j,g,m_hat,v_hat)
do k = 1, n_layers
do i = 1, d
do j = 1, d
g = grads(k,i,j)
! APL: m ← β₁ Γ— m + (1-β₁) Γ— g
m(k,i,j) = state%beta1 * m(k,i,j) + (1.0_dp - state%beta1) * g
! APL: v ← Ξ²β‚‚ Γ— v + (1-Ξ²β‚‚) Γ— |g|Β²
v(k,i,j) = state%beta2 * v(k,i,j) + (1.0_dp - state%beta2) * abs(g)**2
! APL: H ← H - lr_t Γ— m Γ· (√v + Ξ΅)
m_hat = m(k,i,j)
v_hat = v(k,i,j)
H_list(k,i,j) = H_list(k,i,j) - lr_t * m_hat / (sqrt(v_hat) + state%epsilon)
end do
end do
! APL: H_k ← Β½ Γ— (H_k + ⍉ HΜ„_k)
call project_hermitian(c_loc(H_list(k,1,1)), d)
end do
!$omp end parallel do
end subroutine
end module training_adjoint