|
1 | 1 | import Base: isapprox |
2 | 2 |
|
3 | | -""" |
4 | | - Base class for Pauli transfer matrix classes. |
5 | | -""" |
6 | | -abstract type PauliTransferMatrix{B1, B2} end |
7 | | - |
8 | | - |
9 | | -""" |
10 | | - DensePauliTransferMatrix(B1, B2, data) |
11 | | -
|
12 | | -DensePauliTransferMatrix stored as a dense matrix. |
13 | | -""" |
14 | | -mutable struct DensePauliTransferMatrix{B1,B2,T<:Matrix} <: PauliTransferMatrix{B1, B2} |
15 | | - basis_l::B1 |
16 | | - basis_r::B2 |
17 | | - data::T |
18 | | - function DensePauliTransferMatrix(basis_l::BL, basis_r::BR, data::T) where {BL, |
19 | | - BR, |
20 | | - T<:Matrix} |
21 | | - if length(basis_l[1])*length(basis_l[2]) != size(data, 1) || |
22 | | - length(basis_r[1])*length(basis_r[2]) != size(data, 2) |
23 | | - throw(DimensionMismatch()) |
24 | | - end |
25 | | - new{BL, BR, T}(basis_l, basis_r, data) |
26 | | - end |
27 | | -end |
28 | | - |
29 | | -PauliTransferMatrix(ptm::DensePauliTransferMatrix) = ptm |
30 | | - |
31 | | -function *(ptm0::DensePauliTransferMatrix{B, B},ptm1::DensePauliTransferMatrix{B, B}) where B |
32 | | - return DensePauliTransferMatrix(ptm0.basis_l, ptm1.basis_r, ptm0.data*ptm1.data) |
33 | | -end |
34 | | - |
35 | | -""" |
36 | | - Base class for χ (process) matrix classes. |
37 | | -""" |
38 | | -abstract type ChiMatrix{B1, B2} end |
39 | | - |
40 | | -""" |
41 | | - DenseChiMatrix(b, b, data) |
42 | | -
|
43 | | -DenseChiMatrix stored as a dense matrix. |
44 | | -""" |
45 | | -mutable struct DenseChiMatrix{B1,B2,T<:Matrix} <: PauliTransferMatrix{B1, B2} |
46 | | - basis_l::B1 |
47 | | - basis_r::B2 |
48 | | - data::T |
49 | | - function DenseChiMatrix(basis_l::BL, basis_r::BR, data::T) where {BL,BR,T<:Matrix} |
50 | | - if length(basis_l[1])*length(basis_l[2]) != size(data, 1) || |
51 | | - length(basis_r[1])*length(basis_r[2]) != size(data, 2) |
52 | | - throw(DimensionMismatch()) |
53 | | - end |
54 | | - new{BL, BR, T}(basis_l, basis_r, data) |
55 | | - end |
56 | | -end |
57 | | - |
58 | | -ChiMatrix(chi_matrix::DenseChiMatrix) = chi_matrix |
59 | | - |
60 | | -""" |
61 | | -A dictionary that represents the Pauli algebra - for a pair of Pauli operators |
62 | | -σᵢσⱼ information about their product is given under the key "ij". The first |
63 | | -element of the dictionary value is the Pauli operator, and the second is the |
64 | | -scalar multiplier. For example, σ₀σ₁ = σ₁, and `"01" => ("1", 1)`. |
65 | | -""" |
66 | | -const pauli_multiplication_dict = Dict( |
67 | | - "00" => ("0", 1.0+0.0im), |
68 | | - "23" => ("1", 0.0+1.0im), |
69 | | - "30" => ("3", 1.0+0.0im), |
70 | | - "22" => ("0", 1.0+0.0im), |
71 | | - "21" => ("3", -0.0-1.0im), |
72 | | - "10" => ("1", 1.0+0.0im), |
73 | | - "31" => ("2", 0.0+1.0im), |
74 | | - "20" => ("2", 1.0+0.0im), |
75 | | - "01" => ("1", 1.0+0.0im), |
76 | | - "33" => ("0", 1.0+0.0im), |
77 | | - "13" => ("2", -0.0-1.0im), |
78 | | - "32" => ("1", -0.0-1.0im), |
79 | | - "11" => ("0", 1.0+0.0im), |
80 | | - "03" => ("3", 1.0+0.0im), |
81 | | - "12" => ("3", 0.0+1.0im), |
82 | | - "02" => ("2", 1.0+0.0im), |
83 | | -) |
84 | | - |
85 | | -""" |
86 | | - multiply_pauli_matirices(i4::String, j4::String) |
87 | | -
|
88 | | -A function to algebraically determine result of multiplying two |
89 | | -(N-qubit) Pauli matrices. Each Pauli matrix is represented by a string |
90 | | -in base 4. For example, σ₃⊗σ₀⊗σ₂ would be "302". The product of any pair of |
91 | | -Pauli matrices will itself be a Pauli matrix multiplied by any of the 1/4 roots |
92 | | -of 1. |
93 | | -""" |
94 | | -cache_multiply_pauli_matrices() = begin |
95 | | - local pauli_multiplication_cache = Dict() |
96 | | - function _multiply_pauli_matirices(i4, j4) |
97 | | - if (i4, j4) ∉ keys(pauli_multiplication_cache) |
98 | | - pauli_multiplication_cache[(i4, j4)] = mapreduce(x -> pauli_multiplication_dict[prod(x)], |
99 | | - (x,y) -> (x[1] * y[1], x[2] * y[2]), |
100 | | - zip(i4, j4)) |
101 | | - end |
102 | | - return pauli_multiplication_cache[(i4, j4)] |
103 | | - end |
104 | | -end |
105 | | -multiply_pauli_matirices = cache_multiply_pauli_matrices() |
106 | | - |
107 | | -function *(chi_matrix0::DenseChiMatrix{B, B},chi_matrix1::DenseChiMatrix{B, B}) where B |
108 | | - |
109 | | - num_qubits = length(chi_matrix0.basis_l[1].shape) |
110 | | - sop_dim = 2 ^ prod(chi_matrix0.basis_l[1].shape) |
111 | | - ret = zeros(ComplexF64, (sop_dim, sop_dim)) |
112 | 3 |
|
113 | | - for ijkl in Iterators.product(0:(sop_dim-1), |
114 | | - 0:(sop_dim-1), |
115 | | - 0:(sop_dim-1), |
116 | | - 0:(sop_dim-1)) |
117 | | - i, j, k, l = ijkl |
118 | | - if (chi_matrix0.data[i+1, j+1] != 0.0) & (chi_matrix1.data[k+1, l+1] != 0.0) |
119 | | - i4, j4, k4, l4 = map(x -> string(x, base=4, pad=2), ijkl) |
120 | | - |
121 | | - pauli_product_ik = multiply_pauli_matirices(i4, k4) |
122 | | - pauli_product_lj = multiply_pauli_matirices(l4, j4) |
123 | | - |
124 | | - ret[parse(Int, pauli_product_ik[1], base=4)+1, |
125 | | - parse(Int, pauli_product_lj[1], base=4)+1] += (pauli_product_ik[2] * pauli_product_lj[2] * chi_matrix0.data[i+1, j+1] * chi_matrix1.data[k+1, l+1]) |
126 | | - end |
127 | | - end |
128 | | - return DenseChiMatrix(chi_matrix0.basis_l, chi_matrix0.basis_r, ret / 2^num_qubits) |
129 | | -end |
130 | | - |
131 | | - |
132 | | -# TODO MAKE A GENERATOR FUNCTION |
133 | | -""" |
134 | | - pauli_operators(num_qubits::Integer) |
135 | | -
|
136 | | -Generate a list of N-qubit Pauli operators. |
137 | | -""" |
138 | | -function pauli_operators(num_qubits::Integer) |
139 | | - pauli_funcs = (identityoperator, sigmax, sigmay, sigmaz) |
140 | | - po = [] |
141 | | - for paulis in Iterators.product((pauli_funcs for _ in 1:num_qubits)...) |
142 | | - basis_vector = reduce(⊗, f(SpinBasis(1//2)) for f in paulis) |
143 | | - push!(po, basis_vector) |
144 | | - end |
145 | | - return po |
146 | | -end |
147 | | - |
148 | | -""" |
149 | | - pauli_basis_vectors(num_qubits::Integer) |
150 | | -
|
151 | | -Generate a matrix of basis vectors in the Pauli representation given a number |
152 | | -of qubits. |
153 | | -""" |
154 | | -function pauli_basis_vectors(num_qubits::Integer) |
155 | | - po = pauli_operators(num_qubits) |
156 | | - sop_dim = 4 ^ num_qubits |
157 | | - return mapreduce(x -> sparse(reshape(x.data, sop_dim)), (x, y) -> [x y], po) |
158 | | -end |
159 | | - |
160 | | -""" |
161 | | - PauliTransferMatrix(sop::DenseSuperOpType) |
162 | | -
|
163 | | -Convert a superoperator to its representation as a Pauli transfer matrix. |
164 | | -""" |
165 | 4 | function PauliTransferMatrix(sop::DenseSuperOpType) |
166 | 5 | num_qubits = nsubsystems(sop.basis_l[1]) |
167 | 6 | pbv = pauli_basis_vectors(num_qubits) |
@@ -253,12 +92,3 @@ SuperOperator(chi_matrix::DenseChiMatrix) = SuperOperator(PauliTransferMatrix(ch |
253 | 92 | Convert a Pauli transfer matrix to its representation as a χ matrix. |
254 | 93 | """ |
255 | 94 | ChiMatrix(ptm::DensePauliTransferMatrix) = ChiMatrix(SuperOperator(ptm)) |
256 | | - |
257 | | -"""Equality for all varieties of superoperators.""" |
258 | | -==(sop1::T, sop2::T) where T<:Union{DensePauliTransferMatrix, DenseSuperOpType, DenseChiMatrix} = sop1.data == sop2.data |
259 | | -==(sop1::Union{DensePauliTransferMatrix, DenseSuperOpType, DenseChiMatrix}, sop2::Union{DensePauliTransferMatrix, DenseSuperOpType, DenseChiMatrix}) = false |
260 | | - |
261 | | -"""Approximate equality for all varieties of superoperators.""" |
262 | | -function isapprox(sop1::T, sop2::T; kwargs...) where T<:Union{DensePauliTransferMatrix, DenseSuperOpType, DenseChiMatrix} |
263 | | - return isapprox(sop1.data, sop2.data; kwargs...) |
264 | | -end |
0 commit comments