quantum-kernel / go /main.go
SNAPKITTYWEST's picture
push from SNAPKITTYWEST/quantum-kernel
5c61046 verified
Raw
History Blame Contribute Delete
9.15 kB
package main
import (
"fmt"
"math"
"math/rand"
"time"
)
type Complex64 struct {
Real float32
Imag float32
}
type StateVector struct {
data []Complex64
numQubits int
}
func NewStateVector(n int) *StateVector {
size := 1 << n
data := make([]Complex64, size)
data[0] = Complex64{Real: 1.0, Imag: 0.0}
return &StateVector{data: data, numQubits: n}
}
func (sv *StateVector) Apply1Qubit(q int, u [2][2]Complex64) {
n := sv.numQubits
block := 1 << (q + 1)
stride := 1 << q
for base := 0; base < (1 << n); base += block {
for offset := 0; offset < stride; offset++ {
i0 := base + offset
i1 := i0 + stride
a := sv.data[i0]
b := sv.data[i1]
sv.data[i0] = Complex64{
Real: u[0][0].Real*a.Real - u[0][0].Imag*a.Imag + u[0][1].Real*b.Real - u[0][1].Imag*b.Imag,
Imag: u[0][0].Real*a.Imag + u[0][0].Imag*a.Real + u[0][1].Real*b.Imag + u[0][1].Imag*b.Real,
}
sv.data[i1] = Complex64{
Real: u[1][0].Real*a.Real - u[1][0].Imag*a.Imag + u[1][1].Real*b.Real - u[1][1].Imag*b.Imag,
Imag: u[1][0].Real*a.Imag + u[1][0].Imag*a.Real + u[1][1].Real*b.Imag + u[1][1].Imag*b.Real,
}
}
}
}
func (sv *StateVector) Apply2Qubit(q1, q2 int, u [4][4]Complex64) {
n := sv.numQubits
for i := 0; i < (1 << n); i++ {
b1 := (i >> q1) & 1
b2 := (i >> q2) & 1
idx := b1*2 + b2
if idx != 0 {
continue
}
i00 := i
i01 := i | (1 << q2)
i10 := i | (1 << q1)
i11 := i | (1 << q1) | (1 << q2)
indices := [4]int{i00, i01, i10, i11}
var vals [4]Complex64
for k := 0; k < 4; k++ {
vals[k] = sv.data[indices[k]]
}
for row := 0; row < 4; row++ {
var sum Complex64
for col := 0; col < 4; col++ {
a := u[row][col]
b := vals[col]
sum.Real += a.Real*b.Real - a.Imag*b.Imag
sum.Imag += a.Real*b.Imag + a.Imag*b.Real
}
sv.data[indices[row]] = sum
}
}
}
func (sv *StateVector) Copy() *StateVector {
newData := make([]Complex64, len(sv.data))
copy(newData, sv.data)
return &StateVector{data: newData, numQubits: sv.numQubits}
}
func (sv *StateVector) InnerProduct(other *StateVector) Complex64 {
var sum Complex64
for i := range sv.data {
a := sv.data[i]
b := other.data[i]
sum.Real += a.Real*b.Real + a.Imag*b.Imag
sum.Imag += a.Real*b.Imag - a.Imag*b.Real
}
return sum
}
func RZGate(theta float64) [2][2]Complex64 {
c := float32(math.Cos(theta / 2))
s := float32(math.Sin(theta / 2))
return [2][2]Complex64{
{{Real: c, Imag: -s}, {Real: 0, Imag: 0}},
{{Real: 0, Imag: 0}, {Real: c, Imag: s}},
}
}
func RYGate(theta float64) [2][2]Complex64 {
c := float32(math.Cos(theta / 2))
s := float32(math.Sin(theta / 2))
return [2][2]Complex64{
{{Real: c, Imag: 0}, {Real: -s, Imag: 0}},
{{Real: s, Imag: 0}, {Real: c, Imag: 0}},
}
}
func CZGate() [4][4]Complex64 {
return [4][4]Complex64{
{{Real: 1}, {}, {}, {}},
{{}, {Real: 1}, {}, {}},
{{}, {}, {Real: 1}, {}},
{{}, {}, {}, {Real: -1}},
}
}
type QuantumKernelSVM struct {
NQubits int
NLayers int
Shots int
EntGraph [][2]int
C float64
Params [][]float64
}
func NewQuantumKernelSVM(nQubits, nLayers, shots int) *QuantumKernelSVM {
entGraph := make([][2]int, nQubits-1)
for i := 0; i < nQubits-1; i++ {
entGraph[i] = [2]int{i, i + 1}
}
params := make([][]float64, nLayers)
for l := 0; l < nLayers; l++ {
params[l] = make([]float64, 3*nQubits)
for p := 0; p < 3*nQubits; p++ {
params[l][p] = 1.0 + rand.Float64()*0.2 - 0.1
}
}
return &QuantumKernelSVM{
NQubits: nQubits,
NLayers: nLayers,
Shots: shots,
EntGraph: entGraph,
C: 1.0,
Params: params,
}
}
func (svm *QuantumKernelSVM) ApplyFeatureMap(sv *StateVector, features []float64) {
for layer := 0; layer < svm.NLayers; layer++ {
for q := 0; q < svm.NQubits; q++ {
x := features[q%len(features)]
tz1 := svm.Params[layer][3*q]
ty := svm.Params[layer][3*q+1]
tz2 := svm.Params[layer][3*q+2]
sv.Apply1Qubit(q, RZGate(2*x*tz1))
sv.Apply1Qubit(q, RYGate(2*x*ty))
sv.Apply1Qubit(q, RZGate(2*x*tz2))
}
for _, edge := range svm.EntGraph {
sv.Apply2Qubit(edge[0], edge[1], CZGate())
}
}
}
func (svm *QuantumKernelSVM) KernelExact(featuresA, featuresB []float64) float64 {
svA := NewStateVector(svm.NQubits)
svm.ApplyFeatureMap(svA, featuresA)
svB := NewStateVector(svm.NQubits)
svm.ApplyFeatureMap(svB, featuresB)
ip := svA.InnerProduct(svB)
return float64(ip.Real*ip.Real + ip.Imag*ip.Imag)
}
func (svm *QuantumKernelSVM) KernelShots(featuresA, featuresB []float64) float64 {
exact := svm.KernelExact(featuresA, featuresB)
p0 := (1.0 + exact) / 2.0
countZero := 0
for s := 0; s < svm.Shots; s++ {
if rand.Float64() < p0 {
countZero++
}
}
return 2.0*float64(countZero)/float64(svm.Shots) - 1.0
}
func (svm *QuantumKernelSVM) ComputeKernelMatrix(dataset [][]float64) [][]float64 {
n := len(dataset)
K := make([][]float64, n)
for i := range K {
K[i] = make([]float64, n)
}
for i := 0; i < n; i++ {
for j := i; j < n; j++ {
kij := svm.KernelShots(dataset[i], dataset[j])
K[i][j] = kij
K[j][i] = kij
}
}
return K
}
func (svm *QuantumKernelSVM) SolveDual(K [][]float64, labels []float64) ([]float64, float64) {
n := len(labels)
alpha := make([]float64, n)
b := 0.0
for iter := 0; iter < 1000; iter++ {
maxV := 0.0
for i := 0; i < n; i++ {
grad := 1.0
for j := 0; j < n; j++ {
grad -= alpha[j] * labels[j] * K[i][j] * labels[i]
}
v := math.Abs(grad)
if v > maxV {
maxV = v
}
alpha[i] = math.Max(0, math.Min(svm.C, alpha[i]+0.01*labels[i]*grad))
}
if maxV < 1e-4 {
break
}
}
svIndices := []int{}
for i := 0; i < n; i++ {
if alpha[i] > 1e-5 && alpha[i] < svm.C-1e-5 {
svIndices = append(svIndices, i)
}
}
if len(svIndices) > 0 {
bSum := 0.0
for _, k := range svIndices {
sum := 0.0
for j := 0; j < n; j++ {
sum += alpha[j] * labels[j] * K[k][j]
}
bSum += labels[k] - sum
}
b = bSum / float64(len(svIndices))
}
return alpha, b
}
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println("============================================================")
fmt.Println("QUANTUM KERNEL SVM — 5 Qubit Hello World (Go Simulator)")
fmt.Println("State Vector Engine | Shot-Based SWAP Test | SMO Solver")
fmt.Println("============================================================")
fmt.Println()
nQubits := 5
nLayers := 2
shots := 1000
svm := NewQuantumKernelSVM(nQubits, nLayers, shots)
fmt.Printf("Qubits: %d | Layers: %d | Shots: %d\n", nQubits, nLayers, shots)
fmt.Printf("Hilbert space dim: 2^%d = %d\n", nQubits, 1<<nQubits)
fmt.Printf("Entanglement: linear chain %v\n", svm.EntGraph)
fmt.Println()
dataset := [][]float64{
{0, 0, 0, 0, 0},
{0, 1, 0, 1, 0},
{1, 0, 1, 0, 1},
{1, 1, 1, 1, 1},
{0.5, 0.5, 0.5, 0.5, 0.5},
{0.2, 0.8, 0.2, 0.8, 0.2},
{0.8, 0.2, 0.8, 0.2, 0.8},
{0.3, 0.7, 0.3, 0.7, 0.3},
}
labels := []float64{-1, 1, 1, -1, -1, 1, 1, -1}
fmt.Printf("Dataset: %d samples, %d features\n", len(dataset), len(dataset[0]))
fmt.Printf("Labels: %v\n", labels)
fmt.Println()
fmt.Println("Computing quantum kernel matrix...")
start := time.Now()
K := svm.ComputeKernelMatrix(dataset)
elapsed := time.Since(start)
fmt.Printf("Done in %v\n\n", elapsed)
fmt.Println("Kernel matrix (4x4 corner):")
for i := 0; i < 4; i++ {
fmt.Printf(" [")
for j := 0; j < 4; j++ {
fmt.Printf(" %7.4f", K[i][j])
}
fmt.Println(" ]")
}
fmt.Println()
fmt.Println("Training SVM (dual solver)...")
alpha, bias := svm.SolveDual(K, labels)
svCount := 0
for _, a := range alpha {
if a > 1e-5 {
svCount++
}
}
fmt.Printf("Support vectors: %d / %d\n", svCount, len(labels))
fmt.Printf("Bias: %.4f\n\n", bias)
fmt.Println("Predictions:")
correct := 0
for i := 0; i < len(dataset); i++ {
decision := bias
for j := 0; j < len(dataset); j++ {
decision += alpha[j] * labels[j] * K[j][i]
}
pred := 1.0
if decision < 0 {
pred = -1.0
}
match := "OK"
if pred != labels[i] {
match = "MISS"
} else {
correct++
}
fmt.Printf(" x[%d] -> decision=%.4f, pred=%+.0f, true=%+.0f [%s]\n", i, decision, pred, labels[i], match)
}
fmt.Printf("\nAccuracy: %d / %d = %.1f%%\n", correct, len(labels), 100*float64(correct)/float64(len(labels)))
fmt.Println()
fmt.Println("------------------------------------------------------------")
fmt.Println("Shot noise analysis (kernel[0,1]):")
estimates := make([]float64, 20)
for i := range estimates {
estimates[i] = svm.KernelShots(dataset[0], dataset[1])
}
mean := 0.0
for _, e := range estimates {
mean += e
}
mean /= float64(len(estimates))
variance := 0.0
for _, e := range estimates {
variance += (e - mean) * (e - mean)
}
variance /= float64(len(estimates))
exact := svm.KernelExact(dataset[0], dataset[1])
fmt.Printf(" Mean: %.6f\n", mean)
fmt.Printf(" Std: %.6f\n", math.Sqrt(variance))
fmt.Printf(" Exact: %.6f\n", exact)
fmt.Println()
fmt.Println("============================================================")
fmt.Println("HELLO WORLD COMPLETE — 5 qubit quantum kernel executed")
fmt.Println("============================================================")
}