quantum-kernel / julia /braid_diff.jl
SNAPKITTYWEST's picture
push from SNAPKITTYWEST/quantum-kernel
5c61046 verified
Raw
History Blame Contribute Delete
8.32 kB
# braid_diff.jl β€” Differentiable Artin Generators on Heavy-Hex
module BraidDiff
using LinearAlgebra
using Random
export BraidWord, braid_to_circuit, gumbel_softmax_braid, markov_loss
export apply_braid_relations
# ═══════════════════════════════════════════════════════════════════════
# Types
# ═══════════════════════════════════════════════════════════════════════
struct BraidWord
generators::Vector{Int}
edge_indices::Vector{Int}
n_strands::Int
end
BraidWord(n_strands::Int) = BraidWord(Int[], Int[], n_strands)
const HERON_EDGES_0 = [
(0, 1), (1, 2),
(0, 3), (1, 3), (1, 4), (2, 4), (2, 5),
(3, 4), (4, 5), (5, 6),
(3, 7), (4, 7), (4, 8), (5, 8), (5, 9), (6, 9),
(7, 8), (8, 9)
]
const HERON_EDGE_INDEX = Dict(edge => i for (i, edge) in enumerate(HERON_EDGES_0))
# ═══════════════════════════════════════════════════════════════════════
# Braid Word Operations
# ═══════════════════════════════════════════════════════════════════════
Base.length(bw::BraidWord) = length(bw.generators)
function Base.:(==)(bw1::BraidWord, bw2::BraidWord)
bw1.generators == bw2.generators && bw1.edge_indices == bw2.edge_indices
end
function Base.hash(bw::BraidWord, h::UInt)
hash(bw.generators, hash(bw.edge_indices, hash(bw.n_strands, h)))
end
function Base.inv(bw::BraidWord)::BraidWord
BraidWord(reverse(-bw.generators), reverse(bw.edge_indices), bw.n_strands)
end
function Base.:*(bw1::BraidWord, bw2::BraidWord)::BraidWord
@assert bw1.n_strands == bw2.n_strands
BraidWord(vcat(bw1.generators, bw2.generators),
vcat(bw1.edge_indices, bw2.edge_indices),
bw1.n_strands)
end
# ═══════════════════════════════════════════════════════════════════════
# Braid β†’ Circuit (CX/H sequences on Heron edges)
# ═══════════════════════════════════════════════════════════════════════
struct BraidCircuitOp
gate::String
qubits::Vector{Int}
params::Vector{Float64}
end
"""
braid_to_circuit_ops(bw::BraidWord, n_qubits::Int) -> Vector{BraidCircuitOp}
Map Artin generators to SWAP/CX sequences on Heron edges.
Οƒ_i β†’ H(t) Β· CX(c,t) Β· H(t) Β· CX(c,t) Β· H(t)
Οƒ_i⁻¹ β†’ inverse sequence
"""
function braid_to_circuit_ops(bw::BraidWord, n_qubits::Int)::Vector{BraidCircuitOp}
ops = BraidCircuitOp[]
for (gen, edge_idx) in zip(bw.generators, bw.edge_indices)
if edge_idx > length(HERON_EDGES_0)
continue
end
q1, q2 = HERON_EDGES_0[edge_idx]
if q1 >= n_qubits || q2 >= n_qubits
continue
end
if gen > 0
push!(ops, BraidCircuitOp("H", [q2], Float64[]))
push!(ops, BraidCircuitOp("CX", [q1, q2], Float64[]))
push!(ops, BraidCircuitOp("H", [q2], Float64[]))
push!(ops, BraidCircuitOp("CX", [q1, q2], Float64[]))
push!(ops, BraidCircuitOp("H", [q2], Float64[]))
else
push!(ops, BraidCircuitOp("H", [q2], Float64[]))
push!(ops, BraidCircuitOp("CX", [q2, q1], Float64[]))
push!(ops, BraidCircuitOp("H", [q2], Float64[]))
push!(ops, BraidCircuitOp("CX", [q2, q1], Float64[]))
push!(ops, BraidCircuitOp("H", [q2], Float64[]))
end
end
return ops
end
# ═══════════════════════════════════════════════════════════════════════
# Gumbel-Softmax Braid (Differentiable Selection)
# ═══════════════════════════════════════════════════════════════════════
"""
gumbel_softmax_braid(logits, Ο„=1.0)
Differentiable braid generator selection via Gumbel-Softmax.
logits: [n_generators, n_positions]
"""
function gumbel_softmax_braid(logits::Matrix{Float64}, Ο„::Float64=1.0)::BraidWord
n_gens, n_pos = size(logits)
generators = Int[]
edge_indices = Int[]
for pos in 1:n_pos
gumbel = -log.(-log.(rand(n_gens) .+ 1e-20) .+ 1e-20)
y = (logits[:, pos] .+ gumbel) ./ Ο„
y_max = maximum(y)
probs = exp.(y .- y_max) ./ sum(exp.(y .- y_max))
gen_idx = argmax(probs)
sign = rand() < 0.5 ? 1 : -1
push!(generators, sign * gen_idx)
if gen_idx <= length(HERON_EDGES_0)
edge = HERON_EDGES_0[gen_idx]
push!(edge_indices, HERON_EDGE_INDEX[edge])
else
push!(edge_indices, 1)
end
end
BraidWord(generators, edge_indices, n_gens + 1)
end
# ═══════════════════════════════════════════════════════════════════════
# Markov Loss
# ═══════════════════════════════════════════════════════════════════════
function markov_loss(bw::BraidWord, kernel_fidelity::Float64, gate_count::Int;
Ξ»_length::Float64=0.01, Ξ»_gates::Float64=0.001)::Float64
length_penalty = Ξ»_length * length(bw)
gate_penalty = Ξ»_gates * gate_count
return -kernel_fidelity + length_penalty + gate_penalty
end
# ═══════════════════════════════════════════════════════════════════════
# Braid Group Relations (Artin Presentation)
# ═══════════════════════════════════════════════════════════════════════
function shares_vertex(e1::Int, e2::Int)::Bool
if e1 > length(HERON_EDGES_0) || e2 > length(HERON_EDGES_0)
return false
end
q1a, q1b = HERON_EDGES_0[e1]
q2a, q2b = HERON_EDGES_0[e2]
return q1a == q2a || q1a == q2b || q1b == q2a || q1b == q2b
end
"""
apply_braid_relations(bw::BraidWord)
Apply Artin relations:
1. Οƒ_i Οƒ_j = Οƒ_j Οƒ_i for |i-j| > 1 (far commutativity)
2. Οƒ_i Οƒ_{i+1} Οƒ_i = Οƒ_{i+1} Οƒ_i Οƒ_{i+1} (braid relation)
"""
function apply_braid_relations(bw::BraidWord)::BraidWord
gens = copy(bw.generators)
edges = copy(bw.edge_indices)
changed = true
while changed
changed = false
i = 1
while i <= length(gens) - 1
e1, e2 = edges[i], edges[i+1]
if !shares_vertex(e1, e2)
gens[i], gens[i+1] = gens[i+1], gens[i]
edges[i], edges[i+1] = edges[i+1], edges[i]
changed = true
i += 1
elseif shares_vertex(e1, e2) && i <= length(gens) - 2
g1, g3 = gens[i], gens[i+2]
e3 = edges[i+2]
if g1 == g3 && e1 == e3
g2 = gens[i+1]
gens[i], gens[i+1], gens[i+2] = g2, g1, g2
edges[i], edges[i+1], edges[i+2] = e2, e1, e2
changed = true
i += 2
else
i += 1
end
else
i += 1
end
end
end
BraidWord(gens, edges, bw.n_strands)
end
end # module BraidDiff