-
Notifications
You must be signed in to change notification settings - Fork 201
Expand file tree
/
Copy pathgate.h
More file actions
216 lines (174 loc) · 6.09 KB
/
gate.h
File metadata and controls
216 lines (174 loc) · 6.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// Copyright 2019 Google LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GATE_H_
#define GATE_H_
#include <algorithm>
#include <cstdint>
#include <utility>
#include <vector>
#include "matrix.h"
namespace qsim {
namespace detail {
template <typename Gate, typename GateDef>
inline void SortQubits(Gate& gate) {
for (std::size_t i = 1; i < gate.qubits.size(); ++i) {
if (gate.qubits[i - 1] > gate.qubits[i]) {
if (!GateDef::symmetric) {
auto perm = NormalToGateOrderPermutation(gate.qubits);
MatrixShuffle(perm, gate.qubits.size(), gate.matrix);
}
gate.swapped = true;
std::sort(gate.qubits.begin(), gate.qubits.end());
break;
}
}
}
} // namespace detail
template <typename Qubits = std::vector<unsigned>, typename Gate>
inline Gate& MakeControlledGate(Qubits&& controlled_by, Gate& gate) {
gate.controlled_by = std::forward<Qubits>(controlled_by);
gate.cmask = (uint64_t{1} << gate.controlled_by.size()) - 1;
std::sort(gate.controlled_by.begin(), gate.controlled_by.end());
return gate;
}
template <typename Qubits = std::vector<unsigned>, typename Gate>
inline Gate& MakeControlledGate(Qubits&& controlled_by,
const std::vector<unsigned>& control_values,
Gate& gate) {
// Assume controlled_by.size() == control_values.size().
bool sorted = true;
for (std::size_t i = 1; i < controlled_by.size(); ++i) {
if (controlled_by[i - 1] > controlled_by[i]) {
sorted = false;
break;
}
}
if (sorted) {
gate.controlled_by = std::forward<Qubits>(controlled_by);
gate.cmask = 0;
for (std::size_t i = 0; i < control_values.size(); ++i) {
gate.cmask |= (control_values[i] & 1) << i;
}
} else {
struct ControlPair {
unsigned q;
unsigned v;
};
std::vector<ControlPair> cpairs;
cpairs.reserve(controlled_by.size());
for (std::size_t i = 0; i < controlled_by.size(); ++i) {
cpairs.push_back({controlled_by[i], control_values[i]});
}
// Sort control qubits and control values.
std::sort(cpairs.begin(), cpairs.end(),
[](const ControlPair& l, const ControlPair& r) -> bool {
return l.q < r.q;
});
gate.cmask = 0;
gate.controlled_by.reserve(controlled_by.size());
for (std::size_t i = 0; i < cpairs.size(); ++i) {
gate.cmask |= (cpairs[i].v & 1) << i;
gate.controlled_by.push_back(cpairs[i].q);
}
}
return gate;
}
namespace gate {
constexpr int kDecomp = 100001; // gate from Schmidt decomposition
constexpr int kMeasurement = 100002; // measurement gate
} // namespace gate
enum GateAnyKind {
kGateAny = -1,
};
/**
* A generic gate to make it easier to use qsim with external gate sets.
*/
template <typename FP, typename GK = GateAnyKind>
struct Gate {
using fp_type = FP;
using GateKind = GK;
GateKind kind;
unsigned time;
std::vector<unsigned> qubits;
std::vector<unsigned> controlled_by;
uint64_t cmask;
std::vector<fp_type> params;
Matrix<fp_type> matrix;
bool unfusible; // If true, the gate is fused as a parent.
bool swapped; // If true, the gate qubits are swapped to make qubits
// ordered in ascending order. This does not apply to
// control qubits of explicitly-controlled gates.
template <typename Qubits = std::vector<unsigned>>
Gate&& ControlledBy(Qubits&& controlled_by) {
MakeControlledGate(std::forward<Qubits>(controlled_by), *this);
return std::move(*this);
}
template <typename Qubits = std::vector<unsigned>>
Gate&& ControlledBy(Qubits&& controlled_by,
const std::vector<unsigned>& control_values) {
MakeControlledGate(
std::forward<Qubits>(controlled_by), control_values, *this);
return std::move(*this);
}
};
template <typename Gate, typename GateDef,
typename Qubits = std::vector<unsigned>,
typename M = Matrix<typename Gate::fp_type>>
inline Gate CreateGate(unsigned time, Qubits&& qubits, M&& matrix = {},
std::vector<typename Gate::fp_type>&& params = {}) {
Gate gate = {GateDef::kind, time, std::forward<Qubits>(qubits), {}, 0,
std::move(params), std::forward<M>(matrix), false, false};
if (GateDef::kind != gate::kMeasurement) {
switch (gate.qubits.size()) {
case 1:
break;
case 2:
if (gate.qubits[0] > gate.qubits[1]) {
gate.swapped = true;
std::swap(gate.qubits[0], gate.qubits[1]);
if (!GateDef::symmetric) {
MatrixShuffle({1, 0}, 2, gate.matrix);
}
}
break;
default:
detail::SortQubits<Gate, GateDef>(gate);
}
}
return gate;
}
namespace gate {
/**
* A gate that simulates measurement of one or more qubits, collapsing the
* state vector and storing the measured results.
*/
template <typename Gate>
struct Measurement {
using GateKind = typename Gate::GateKind;
static constexpr GateKind kind = GateKind::kMeasurement;
static constexpr char name[] = "m";
static constexpr bool symmetric = false;
template <typename Qubits = std::vector<unsigned>>
static Gate Create(unsigned time, Qubits&& qubits) {
return CreateGate<Gate, Measurement>(time, std::forward<Qubits>(qubits));
}
};
} // namespace gate
template <typename fp_type>
using schmidt_decomp_type = std::vector<std::vector<std::vector<fp_type>>>;
template <typename fp_type, typename GateKind>
schmidt_decomp_type<fp_type> GetSchmidtDecomp(
GateKind kind, const std::vector<fp_type>& params);
} // namespace qsim
#endif // GATE_H_