Skip to content

Commit a9007c9

Browse files
committed
Update density matrix
1 parent 040d3d2 commit a9007c9

File tree

3 files changed

+66
-142
lines changed

3 files changed

+66
-142
lines changed

q_test.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,9 +1148,8 @@ func Example_densityMatrix() {
11481148
}
11491149

11501150
rho := density.NewPureState(qsim.Underlying())
1151-
qb := rho.Qubits()
1152-
s1 := rho.PartialTrace(qb[0])
1153-
s0 := rho.PartialTrace(qb[1])
1151+
s1 := rho.PartialTrace(0) // trace out qubit 0
1152+
s0 := rho.PartialTrace(1) // trace out qubit 1
11541153

11551154
fmt.Printf("trace: %.2v, purity: %.2v\n", rho.Trace(), rho.Purity())
11561155
fmt.Printf("trace: %.2v, purity: %.2v\n", s1.Trace(), s1.Purity())

quantum/density/matrix.go

Lines changed: 17 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package density
22

33
import (
4-
"fmt"
54
"iter"
65
"math"
76
"strings"
@@ -13,24 +12,6 @@ import (
1312
"github.com/itsubaki/q/quantum/qubit"
1413
)
1514

16-
// Qubit is a quantum bit.
17-
type Qubit int
18-
19-
// Index returns the index of qubit.
20-
func (q Qubit) Index() int {
21-
return int(q)
22-
}
23-
24-
// Index returns the indices of the given qubits.
25-
func Index(qb ...Qubit) []int {
26-
idx := make([]int, len(qb))
27-
for i, q := range qb {
28-
idx[i] = q.Index()
29-
}
30-
31-
return idx
32-
}
33-
3415
// Matrix is a density matrix.
3516
type Matrix struct {
3617
rho *matrix.Matrix
@@ -67,29 +48,6 @@ func NewZeroState(n ...int) *Matrix {
6748
return NewPureState(qubit.Zero(n...))
6849
}
6950

70-
// Qubits returns the qubits of the density matrix.
71-
func (m *Matrix) Qubits() []Qubit {
72-
n := m.NumQubits()
73-
74-
qubits := make([]Qubit, n)
75-
for i := range n {
76-
qubits[i] = Qubit(i)
77-
}
78-
79-
return qubits
80-
}
81-
82-
func (m *Matrix) ComputationalBasis() []*qubit.Qubit {
83-
n := m.NumQubits()
84-
85-
basis := make([]*qubit.Qubit, 1<<n)
86-
for i := range 1 << n {
87-
basis[i] = qubit.From(fmt.Sprintf("%0*b", n, i))
88-
}
89-
90-
return basis
91-
}
92-
9351
// At returns a value of matrix at (i,j).
9452
func (m *Matrix) At(i, j int) complex128 {
9553
return m.rho.At(i, j)
@@ -185,17 +143,17 @@ func (m *Matrix) TensorProduct(n *Matrix) *Matrix {
185143
// PartialTrace returns the partial trace of the density matrix.
186144
// The length of index must be less than or equal to n - 1,
187145
// where n is the number of qubits in the matrix.
188-
func (m *Matrix) PartialTrace(idx ...Qubit) *Matrix {
146+
func (m *Matrix) PartialTrace(qb ...int) *Matrix {
189147
n := m.NumQubits()
190-
d := number.Pow(2, n-len(idx))
148+
d := number.Pow(2, n-len(qb))
191149
p, q := m.Dim()
192150

193151
rho := matrix.Zero(d, d)
194152
for i := range p {
195-
k, kr := take(n, i, idx)
153+
k, kr := take(n, i, qb)
196154

197155
for j := range q {
198-
l, lr := take(n, j, idx)
156+
l, lr := take(n, j, qb)
199157

200158
if k != l {
201159
continue
@@ -228,10 +186,10 @@ func (m *Matrix) PartialTrace(idx ...Qubit) *Matrix {
228186
// Depolarizing returns the depolarizing channel.
229187
// It applies the identity with probability (1 - p),
230188
// and applies each of the Pauli gates X, Y, and Z with probability p/3.
231-
func (m *Matrix) Depolarizing(p float64, qb Qubit) *Matrix {
189+
func (m *Matrix) Depolarizing(p float64, qb int) *Matrix {
232190
n := m.NumQubits()
233191

234-
idx := Index(qb)
192+
idx := []int{qb}
235193
id := m.rho.Mul(complex(1-p, 0))
236194
xg := gate.TensorProduct(gate.X(), n, idx)
237195
yg := gate.TensorProduct(gate.Y(), n, idx)
@@ -248,14 +206,14 @@ func (m *Matrix) Depolarizing(p float64, qb Qubit) *Matrix {
248206

249207
// ApplyChannel applies a channel to the density matrix.
250208
// It applies the identity with probability 1-p, and applies the gate g with probability p.
251-
func (m *Matrix) ApplyChannel(p float64, u *matrix.Matrix, qb ...Qubit) *Matrix {
252-
n, idx := m.NumQubits(), Index(qb...)
209+
func (m *Matrix) ApplyChannel(p float64, u *matrix.Matrix, qb ...int) *Matrix {
210+
n := m.NumQubits()
253211

254212
e0 := gate.I().Mul(complex(math.Sqrt(1-p), 0))
255213
e1 := u.Mul(complex(math.Sqrt(p), 0))
256214

257-
k0 := gate.TensorProduct(e0, n, idx)
258-
k1 := gate.TensorProduct(e1, n, idx)
215+
k0 := gate.TensorProduct(e0, n, qb)
216+
k1 := gate.TensorProduct(e1, n, qb)
259217

260218
rho := matrix.ZeroLike(m.rho)
261219
rho = rho.Add(matrix.MatMul(k0, m.rho, k0.Dagger()))
@@ -267,24 +225,24 @@ func (m *Matrix) ApplyChannel(p float64, u *matrix.Matrix, qb ...Qubit) *Matrix
267225
}
268226

269227
// BitFlip applies a bit flip channel to the density matrix.
270-
func (m *Matrix) BitFlip(p float64, qb Qubit) *Matrix {
228+
func (m *Matrix) BitFlip(p float64, qb int) *Matrix {
271229
return m.ApplyChannel(p, gate.X(), qb)
272230
}
273231

274232
// BitPhaseFlip applies a bit-phase flip channel to the density matrix.
275-
func (m *Matrix) BitPhaseFlip(p float64, qb Qubit) *Matrix {
233+
func (m *Matrix) BitPhaseFlip(p float64, qb int) *Matrix {
276234
return m.ApplyChannel(p, gate.Y(), qb)
277235
}
278236

279237
// PhaseFlip applies a phase flip channel to the density matrix.
280-
func (m *Matrix) PhaseFlip(p float64, qb Qubit) *Matrix {
238+
func (m *Matrix) PhaseFlip(p float64, qb int) *Matrix {
281239
return m.ApplyChannel(p, gate.Z(), qb)
282240
}
283241

284-
func take(n, i int, idx []Qubit) (string, string) {
285-
target := make(map[int]struct{}, len(idx))
286-
for _, j := range idx {
287-
target[j.Index()] = struct{}{}
242+
func take(n, i int, qb []int) (string, string) {
243+
target := make(map[int]struct{}, len(qb))
244+
for _, j := range qb {
245+
target[j] = struct{}{}
288246
}
289247

290248
var out, remain strings.Builder

0 commit comments

Comments
 (0)