From d28b65df07cb0db099029c90365713e7865efe26 Mon Sep 17 00:00:00 2001 From: itsubaki <1759459+itsubaki@users.noreply.github.com> Date: Mon, 13 Jan 2025 11:33:27 +0900 Subject: [PATCH 1/3] Add AddControlled API --- quantum/gate/gate.go | 21 +++++++++++ quantum/gate/gate_test.go | 73 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/quantum/gate/gate.go b/quantum/gate/gate.go index 0dfd15f..44b3252 100644 --- a/quantum/gate/gate.go +++ b/quantum/gate/gate.go @@ -133,7 +133,27 @@ func RZ(theta float64) matrix.Matrix { } } +// AddControlled returns a controlled-u gate with control bit. +// u is a (2**n x 2**n) unitary matrix and returns a (2**n x 2**n) matrix. +func AddControlled(u matrix.Matrix, n int, c int) matrix.Matrix { + s := 1 << n + g := I(n) + + for i := 0; i < s; i++ { + if (i>>(n-1-c))&1 == 0 { + continue + } + + for j := 0; j < s; j++ { + g[i][j] = u[i][j] + } + } + + return g +} + // Controlled returns a controlled-u gate. +// u is a (2x2) unitary matrix and returns a (2**n x 2**n) matrix. func Controlled(u matrix.Matrix, n int, c []int, t int) matrix.Matrix { var mask int for _, bit := range c { @@ -360,6 +380,7 @@ func ControlledModExp2(n, a, j, N, c int, t []int) matrix.Matrix { return g } +// TensorProduct returns the tensor product of 'u' at specified indices over 'n' qubits. func TensorProduct(u matrix.Matrix, n int, index []int) matrix.Matrix { idx := make(map[int]bool) for _, i := range index { diff --git a/quantum/gate/gate_test.go b/quantum/gate/gate_test.go index 51210f5..bbf4c17 100644 --- a/quantum/gate/gate_test.go +++ b/quantum/gate/gate_test.go @@ -3,6 +3,7 @@ package gate_test import ( "fmt" "math" + "math/rand/v2" "strconv" "testing" @@ -167,6 +168,78 @@ func ExampleTensorProduct() { // [(0+0i) (1+0i) (0+0i) (0+0i)] } +func TestAddControlled(t *testing.T) { + u := gate.U(rand.Float64(), rand.Float64(), rand.Float64()) + + cases := []struct { + in matrix.Matrix + want matrix.Matrix + n, bit int + }{ + { + in: gate.TensorProduct(gate.X(), 2, []int{1}), + want: gate.ControlledNot(2, []int{0}, 1), + n: 2, + bit: 0, + }, + { + in: gate.ControlledNot(3, []int{0}, 2), + want: gate.ControlledNot(3, []int{0, 1}, 2), + n: 3, + bit: 1, + }, + { + in: gate.ControlledNot(3, []int{0}, 2), + want: gate.ControlledNot(3, []int{0}, 2), + n: 3, + bit: 0, + }, + { + in: gate.Controlled(u, 3, []int{0}, 1), + want: gate.Controlled(u, 3, []int{0, 2}, 1), + n: 3, + bit: 2, + }, + { + in: gate.Controlled(u, 3, []int{0}, 2), + want: gate.Controlled(u, 3, []int{0, 1}, 2), + n: 3, + bit: 1, + }, + { + in: gate.Controlled(u, 3, []int{1}, 2), + want: gate.Controlled(u, 3, []int{0, 1}, 2), + n: 3, + bit: 0, + }, + { + in: gate.Controlled(u, 3, []int{1}, 0), + want: gate.Controlled(u, 3, []int{1, 2}, 0), + n: 3, + bit: 2, + }, + { + in: gate.Controlled(u, 3, []int{2}, 0), + want: gate.Controlled(u, 3, []int{2, 1}, 0), + n: 3, + bit: 1, + }, + { + in: gate.Controlled(u, 3, []int{2}, 1), + want: gate.Controlled(u, 3, []int{0, 2}, 1), + n: 3, + bit: 0, + }, + } + + for _, c := range cases { + got := gate.AddControlled(c.in, c.n, c.bit) + if !got.Equals(c.want) { + t.Fail() + } + } +} + func TestControlledModExp2(t *testing.T) { g1 := matrix.Apply( gate.CNOT(7, 3, 5), From 45e0a56bbabaaafc0de9316723d8a4cd888a7f45 Mon Sep 17 00:00:00 2001 From: itsubaki <1759459+itsubaki@users.noreply.github.com> Date: Mon, 13 Jan 2025 11:35:59 +0900 Subject: [PATCH 2/3] Update AddControlled --- quantum/gate/gate.go | 9 +++++---- quantum/gate/gate_test.go | 17 ++++------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/quantum/gate/gate.go b/quantum/gate/gate.go index 44b3252..85d3bd1 100644 --- a/quantum/gate/gate.go +++ b/quantum/gate/gate.go @@ -135,16 +135,17 @@ func RZ(theta float64) matrix.Matrix { // AddControlled returns a controlled-u gate with control bit. // u is a (2**n x 2**n) unitary matrix and returns a (2**n x 2**n) matrix. -func AddControlled(u matrix.Matrix, n int, c int) matrix.Matrix { - s := 1 << n +func AddControlled(u matrix.Matrix, c int) matrix.Matrix { + d, _ := u.Dimension() + n := number.Log2(d) g := I(n) - for i := 0; i < s; i++ { + for i := 0; i < d; i++ { if (i>>(n-1-c))&1 == 0 { continue } - for j := 0; j < s; j++ { + for j := 0; j < d; j++ { g[i][j] = u[i][j] } } diff --git a/quantum/gate/gate_test.go b/quantum/gate/gate_test.go index bbf4c17..bae715c 100644 --- a/quantum/gate/gate_test.go +++ b/quantum/gate/gate_test.go @@ -172,68 +172,59 @@ func TestAddControlled(t *testing.T) { u := gate.U(rand.Float64(), rand.Float64(), rand.Float64()) cases := []struct { - in matrix.Matrix - want matrix.Matrix - n, bit int + in matrix.Matrix + want matrix.Matrix + bit int }{ { in: gate.TensorProduct(gate.X(), 2, []int{1}), want: gate.ControlledNot(2, []int{0}, 1), - n: 2, bit: 0, }, { in: gate.ControlledNot(3, []int{0}, 2), want: gate.ControlledNot(3, []int{0, 1}, 2), - n: 3, bit: 1, }, { in: gate.ControlledNot(3, []int{0}, 2), want: gate.ControlledNot(3, []int{0}, 2), - n: 3, bit: 0, }, { in: gate.Controlled(u, 3, []int{0}, 1), want: gate.Controlled(u, 3, []int{0, 2}, 1), - n: 3, bit: 2, }, { in: gate.Controlled(u, 3, []int{0}, 2), want: gate.Controlled(u, 3, []int{0, 1}, 2), - n: 3, bit: 1, }, { in: gate.Controlled(u, 3, []int{1}, 2), want: gate.Controlled(u, 3, []int{0, 1}, 2), - n: 3, bit: 0, }, { in: gate.Controlled(u, 3, []int{1}, 0), want: gate.Controlled(u, 3, []int{1, 2}, 0), - n: 3, bit: 2, }, { in: gate.Controlled(u, 3, []int{2}, 0), want: gate.Controlled(u, 3, []int{2, 1}, 0), - n: 3, bit: 1, }, { in: gate.Controlled(u, 3, []int{2}, 1), want: gate.Controlled(u, 3, []int{0, 2}, 1), - n: 3, bit: 0, }, } for _, c := range cases { - got := gate.AddControlled(c.in, c.n, c.bit) + got := gate.AddControlled(c.in, c.bit) if !got.Equals(c.want) { t.Fail() } From d8458c204d1e350e3d23bfb42be235a925e08334 Mon Sep 17 00:00:00 2001 From: itsubaki <1759459+itsubaki@users.noreply.github.com> Date: Mon, 13 Jan 2025 11:45:53 +0900 Subject: [PATCH 3/3] Update test --- quantum/gate/gate_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/quantum/gate/gate_test.go b/quantum/gate/gate_test.go index bae715c..9e42cde 100644 --- a/quantum/gate/gate_test.go +++ b/quantum/gate/gate_test.go @@ -181,6 +181,11 @@ func TestAddControlled(t *testing.T) { want: gate.ControlledNot(2, []int{0}, 1), bit: 0, }, + { + in: gate.TensorProduct(gate.X(), 2, []int{0}), + want: gate.ControlledNot(2, []int{1}, 0), + bit: 1, + }, { in: gate.ControlledNot(3, []int{0}, 2), want: gate.ControlledNot(3, []int{0, 1}, 2),