| # 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 |
|
|