everydaytok commited on
Commit
41b1dc2
Β·
verified Β·
1 Parent(s): 795b638

Create QuantumCircuits.py

Browse files
Files changed (1) hide show
  1. QuantumCircuits.py +400 -0
QuantumCircuits.py ADDED
@@ -0,0 +1,400 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ QuantumCircuits.py
3
+ Heisenberg-picture quantum circuit encoding for the Practicality Wisdom Layer.
4
+ """
5
+
6
+ from __future__ import annotations
7
+ import math
8
+ from dataclasses import dataclass, field
9
+ from typing import List, Dict, Tuple, Set, Any
10
+
11
+ # ── Gate definitions ─────────────────────────────────────────────────
12
+
13
+ GATE_TYPES = {
14
+ "Rx", "Ry", "Rz", # Parameterized rotations
15
+ "H", # Hadamard
16
+ "S", "T", # Phase gates
17
+ "CNOT", # Entangling gate
18
+ "CZ", # Controlled-Z
19
+ }
20
+
21
+ @dataclass
22
+ class QGate:
23
+ type: str
24
+ qubits: List[int]
25
+ params: List[str] = field(default_factory=list)
26
+ layer: int = 0
27
+
28
+ def validate(self):
29
+ if self.type not in GATE_TYPES:
30
+ raise ValueError(f"Unknown gate: {self.type}")
31
+ if self.type in ("Rx", "Ry", "Rz") and len(self.params) != 1:
32
+ raise ValueError(f"{self.type} requires exactly 1 parameter")
33
+ if self.type in ("CNOT", "CZ") and len(self.qubits) != 2:
34
+ raise ValueError(f"{self.type} requires exactly 2 qubits")
35
+ if self.type in ("H", "S", "T") and len(self.qubits) != 1:
36
+ raise ValueError(f"{self.type} is a single-qubit gate")
37
+
38
+ @dataclass
39
+ class QuantumCircuit:
40
+ n_qubits: int
41
+ gates: List[QGate]
42
+ param_bounds: Dict[str, Tuple[float, float]] = field(default_factory=dict)
43
+ initial_state: str = "zero"
44
+ initial_obs: Dict[str, float] = field(default_factory=dict)
45
+ target_hamiltonian: Dict[str, float] = field(default_factory=dict)
46
+ include_2body: bool = True
47
+ name: str = "QuantumCircuit"
48
+ description: str = ""
49
+
50
+ @property
51
+ def n_layers(self) -> int:
52
+ if not self.gates: return 0
53
+ return max(g.layer for g in self.gates) + 1
54
+
55
+ @property
56
+ def has_cnot(self) -> bool:
57
+ return any(g.type in ("CNOT", "CZ") for g in self.gates)
58
+
59
+ @property
60
+ def all_params(self) -> List[str]:
61
+ seen = set()
62
+ params = []
63
+ for g in self.gates:
64
+ for p in g.params:
65
+ if p not in seen:
66
+ seen.add(p)
67
+ params.append(p)
68
+ return params
69
+
70
+ # ── Observable naming ─────────────────────────────────────────────────
71
+
72
+ PAULI = ("x", "y", "z")
73
+ PAULI2 = [p1 + p2 for p1 in PAULI for p2 in PAULI]
74
+
75
+ def obs1(pauli: str, qubit: int, layer: int) -> str:
76
+ return f"{pauli}{qubit}_L{layer}"
77
+
78
+ def obs2(pauli1: str, pauli2: str, q1: int, q2: int, layer: int) -> str:
79
+ if q1 > q2:
80
+ q1, q2 = q2, q1
81
+ pauli1, pauli2 = pauli2, pauli1
82
+ return f"{pauli1}{pauli2}{q1}{q2}_L{layer}"
83
+
84
+ def _initial_obs_values(circuit: QuantumCircuit) -> Dict[str, float]:
85
+ obs = {}
86
+ if circuit.initial_state == "zero":
87
+ for q in range(circuit.n_qubits):
88
+ obs[obs1("z", q, 0)] = 1.0
89
+ obs[obs1("x", q, 0)] = 0.0
90
+ obs[obs1("y", q, 0)] = 0.0
91
+ if circuit.include_2body:
92
+ for q1 in range(circuit.n_qubits):
93
+ for q2 in range(q1 + 1, circuit.n_qubits):
94
+ for p1, p2 in PAULI2:
95
+ obs[obs2(p1, p2, q1, q2, 0)] = 1.0 if (p1 == "z" and p2 == "z") else 0.0
96
+
97
+ elif circuit.initial_state == "plus":
98
+ for q in range(circuit.n_qubits):
99
+ obs[obs1("x", q, 0)] = 1.0
100
+ obs[obs1("y", q, 0)] = 0.0
101
+ obs[obs1("z", q, 0)] = 0.0
102
+ if circuit.include_2body:
103
+ for q1 in range(circuit.n_qubits):
104
+ for q2 in range(q1 + 1, circuit.n_qubits):
105
+ for p1p2 in PAULI2:
106
+ obs[obs2(p1p2[0], p1p2[1], q1, q2, 0)] = 1.0 if p1p2 == "xx" else 0.0
107
+
108
+ elif circuit.initial_state == "custom":
109
+ obs.update(circuit.initial_obs)
110
+ return obs
111
+
112
+ # ── Heisenberg evolution constraints ─────────────────────────────────
113
+
114
+ def _rz_constraints(q: int, theta: str, layer_in: int, layer_out: int, circuit: QuantumCircuit) -> List[Dict]:
115
+ constraints = []
116
+ xq_in, yq_in, zq_in = obs1("x", q, layer_in), obs1("y", q, layer_in), obs1("z", q, layer_in)
117
+ xq_out, yq_out, zq_out = obs1("x", q, layer_out), obs1("y", q, layer_out), obs1("z", q, layer_out)
118
+
119
+ constraints.extend([
120
+ {"kind": "EQ", "expr": f"{xq_out} - cos({theta})*{xq_in} - sin({theta})*{yq_in}", "weight": 5.0},
121
+ {"kind": "EQ", "expr": f"{yq_out} + sin({theta})*{xq_in} - cos({theta})*{yq_in}", "weight": 5.0},
122
+ {"kind": "EQ", "expr": f"{zq_out} - {zq_in}", "weight": 5.0}
123
+ ])
124
+
125
+ if circuit.include_2body:
126
+ for r in range(circuit.n_qubits):
127
+ if r == q: continue
128
+ for pr in PAULI:
129
+ xpr_in, ypr_in, zpr_in = obs2("x", pr, q, r, layer_in), obs2("y", pr, q, r, layer_in), obs2("z", pr, q, r, layer_in)
130
+ xpr_out, ypr_out, zpr_out = obs2("x", pr, q, r, layer_out), obs2("y", pr, q, r, layer_out), obs2("z", pr, q, r, layer_out)
131
+ constraints.extend([
132
+ {"kind": "EQ", "expr": f"{xpr_out} - cos({theta})*{xpr_in} - sin({theta})*{ypr_in}", "weight": 5.0},
133
+ {"kind": "EQ", "expr": f"{ypr_out} + sin({theta})*{xpr_in} - cos({theta})*{ypr_in}", "weight": 5.0},
134
+ {"kind": "EQ", "expr": f"{zpr_out} - {zpr_in}", "weight": 5.0}
135
+ ])
136
+ return constraints
137
+
138
+ def _rx_constraints(q: int, theta: str, layer_in: int, layer_out: int, circuit: QuantumCircuit) -> List[Dict]:
139
+ constraints = []
140
+ xq_in, yq_in, zq_in = obs1("x", q, layer_in), obs1("y", q, layer_in), obs1("z", q, layer_in)
141
+ xq_out, yq_out, zq_out = obs1("x", q, layer_out), obs1("y", q, layer_out), obs1("z", q, layer_out)
142
+
143
+ constraints.extend([
144
+ {"kind": "EQ", "expr": f"{xq_out} - {xq_in}", "weight": 5.0},
145
+ {"kind": "EQ", "expr": f"{yq_out} - cos({theta})*{yq_in} + sin({theta})*{zq_in}", "weight": 5.0},
146
+ {"kind": "EQ", "expr": f"{zq_out} - cos({theta})*{zq_in} - sin({theta})*{yq_in}", "weight": 5.0}
147
+ ])
148
+
149
+ if circuit.include_2body:
150
+ for r in range(circuit.n_qubits):
151
+ if r == q: continue
152
+ for pr in PAULI:
153
+ xpr_in, ypr_in, zpr_in = obs2("x", pr, q, r, layer_in), obs2("y", pr, q, r, layer_in), obs2("z", pr, q, r, layer_in)
154
+ xpr_out, ypr_out, zpr_out = obs2("x", pr, q, r, layer_out), obs2("y", pr, q, r, layer_out), obs2("z", pr, q, r, layer_out)
155
+ constraints.extend([
156
+ {"kind": "EQ", "expr": f"{xpr_out} - {xpr_in}", "weight": 5.0},
157
+ {"kind": "EQ", "expr": f"{ypr_out} - cos({theta})*{ypr_in} + sin({theta})*{zpr_in}", "weight": 5.0},
158
+ {"kind": "EQ", "expr": f"{zpr_out} - cos({theta})*{zpr_in} - sin({theta})*{ypr_in}", "weight": 5.0}
159
+ ])
160
+ return constraints
161
+
162
+ def _hadamard_constraints(q: int, layer_in: int, layer_out: int, circuit: QuantumCircuit) -> List[Dict]:
163
+ constraints = []
164
+ xq_in, yq_in, zq_in = obs1("x", q, layer_in), obs1("y", q, layer_in), obs1("z", q, layer_in)
165
+ xq_out, yq_out, zq_out = obs1("x", q, layer_out), obs1("y", q, layer_out), obs1("z", q, layer_out)
166
+
167
+ constraints.extend([
168
+ {"kind": "EQ", "expr": f"{xq_out} - {zq_in}", "weight": 5.0},
169
+ {"kind": "EQ", "expr": f"{yq_out} + {yq_in}", "weight": 5.0},
170
+ {"kind": "EQ", "expr": f"{zq_out} - {xq_in}", "weight": 5.0}
171
+ ])
172
+
173
+ if circuit.include_2body:
174
+ for r in range(circuit.n_qubits):
175
+ if r == q: continue
176
+ for pr in PAULI:
177
+ xpr_in, ypr_in, zpr_in = obs2("x", pr, q, r, layer_in), obs2("y", pr, q, r, layer_in), obs2("z", pr, q, r, layer_in)
178
+ xpr_out, ypr_out, zpr_out = obs2("x", pr, q, r, layer_out), obs2("y", pr, q, r, layer_out), obs2("z", pr, q, r, layer_out)
179
+ constraints.extend([
180
+ {"kind": "EQ", "expr": f"{xpr_out} - {zpr_in}", "weight": 5.0},
181
+ {"kind": "EQ", "expr": f"{ypr_out} + {ypr_in}", "weight": 5.0},
182
+ {"kind": "EQ", "expr": f"{zpr_out} - {xpr_in}", "weight": 5.0}
183
+ ])
184
+ return constraints
185
+
186
+ def _cnot_constraints(control: int, target: int, layer_in: int, layer_out: int, circuit: QuantumCircuit) -> List[Dict]:
187
+ if not circuit.include_2body:
188
+ raise ValueError("CNOT requires include_2body=True")
189
+ k, j = control, target
190
+ constraints = []
191
+
192
+ # ── Single-qubit output
193
+ constraints.extend([
194
+ {"kind": "EQ", "expr": f"{obs1('x', k, layer_out)} - {obs2('x', 'x', k, j, layer_in)}", "weight": 5.0},
195
+ {"kind": "EQ", "expr": f"{obs1('y', k, layer_out)} - {obs2('y', 'x', k, j, layer_in)}", "weight": 5.0},
196
+ {"kind": "EQ", "expr": f"{obs1('z', k, layer_out)} - {obs1('z', k, layer_in)}", "weight": 5.0},
197
+ {"kind": "EQ", "expr": f"{obs1('x', j, layer_out)} - {obs1('x', j, layer_in)}", "weight": 5.0},
198
+ {"kind": "EQ", "expr": f"{obs1('y', j, layer_out)} - {obs2('z', 'y', k, j, layer_in)}", "weight": 5.0},
199
+ {"kind": "EQ", "expr": f"{obs1('z', j, layer_out)} - {obs2('z', 'z', k, j, layer_in)}", "weight": 5.0}
200
+ ])
201
+
202
+ # ── Two-qubit output (ctrl and tgt)
203
+ constraints.extend([
204
+ {"kind": "EQ", "expr": f"{obs2('x', 'x', k, j, layer_out)} - {obs1('x', k, layer_in)}", "weight": 5.0},
205
+ {"kind": "EQ", "expr": f"{obs2('z', 'z', k, j, layer_out)} - {obs1('z', j, layer_in)}", "weight": 5.0},
206
+ {"kind": "EQ", "expr": f"{obs2('z', 'x', k, j, layer_out)} - {obs2('z', 'x', k, j, layer_in)}", "weight": 5.0},
207
+ {"kind": "EQ", "expr": f"{obs2('x', 'z', k, j, layer_out)} + {obs2('y', 'y', k, j, layer_in)}", "weight": 5.0},
208
+ {"kind": "EQ", "expr": f"{obs2('y', 'z', k, j, layer_out)} - {obs2('x', 'y', k, j, layer_in)}", "weight": 5.0}
209
+ ])
210
+
211
+ handled_pairs = {("x","x"), ("z","z"), ("z","x"), ("x","z"), ("y","z"), ("y","x"), ("x","y"), ("z","y"), ("y","y")}
212
+ for p1p2 in PAULI2:
213
+ if (p1p2[0], p1p2[1]) not in handled_pairs:
214
+ constraints.append({
215
+ "kind": "EQ",
216
+ "expr": f"{obs2(p1p2[0], p1p2[1], k, j, layer_out)} - {obs2(p1p2[0], p1p2[1], k, j, layer_in)}",
217
+ "weight": 2.0
218
+ })
219
+ return constraints
220
+
221
+ # ── Main builder ──────────────────────────────────────────────────────
222
+
223
+ def build_quantum_axl(circuit: QuantumCircuit, axl_problem_class: Any, axl_invariant_class: Any) -> Any:
224
+ """
225
+ Builds the AXL problem.
226
+ Pass AXLProblemDef and AXLInvariant classes from your main script to avoid circular imports.
227
+ """
228
+ for g in circuit.gates: g.validate()
229
+
230
+ n = circuit.n_qubits
231
+ n_layers = circuit.n_layers
232
+ include_2b = circuit.include_2body and circuit.has_cnot
233
+
234
+ variables: List[Dict] = []
235
+
236
+ for pname in circuit.all_params:
237
+ lo, hi = circuit.param_bounds.get(pname, (-math.pi, math.pi))
238
+ variables.append({"name": pname, "lo": lo, "hi": hi})
239
+
240
+ for layer in range(n_layers + 1):
241
+ for q in range(n):
242
+ for p in PAULI:
243
+ variables.append({"name": obs1(p, q, layer), "lo": -1.0, "hi": 1.0})
244
+ if include_2b:
245
+ for q1 in range(n):
246
+ for q2 in range(q1 + 1, n):
247
+ for p1p2 in PAULI2:
248
+ variables.append({"name": obs2(p1p2[0], p1p2[1], q1, q2, layer), "lo": -1.0, "hi": 1.0})
249
+
250
+ obs_fixed = _initial_obs_values(circuit)
251
+
252
+ global_constraints: List[Dict] = []
253
+ for layer in range(n_layers + 1):
254
+ for q in range(n):
255
+ global_constraints.append({
256
+ "kind": "GEQ",
257
+ "expr": f"1.0 - {obs1('x', q, layer)}**2 - {obs1('y', q, layer)}**2 - {obs1('z', q, layer)}**2",
258
+ "weight": 2.0
259
+ })
260
+
261
+ scopes: List[Dict] = []
262
+ for layer_in in range(n_layers):
263
+ layer_out = layer_in + 1
264
+ layer_gates = [g for g in circuit.gates if g.layer == layer_in]
265
+ scope_constraints: List[Dict] = []
266
+ gates_affecting: Set[int] = set()
267
+
268
+ for gate in layer_gates:
269
+ if gate.type == "Rz":
270
+ gates_affecting.add(gate.qubits[0])
271
+ scope_constraints.extend(_rz_constraints(gate.qubits[0], gate.params[0], layer_in, layer_out, circuit))
272
+ elif gate.type == "Rx":
273
+ gates_affecting.add(gate.qubits[0])
274
+ scope_constraints.extend(_rx_constraints(gate.qubits[0], gate.params[0], layer_in, layer_out, circuit))
275
+ elif gate.type == "H":
276
+ gates_affecting.add(gate.qubits[0])
277
+ scope_constraints.extend(_hadamard_constraints(gate.qubits[0], layer_in, layer_out, circuit))
278
+ elif gate.type == "CNOT":
279
+ gates_affecting.update(gate.qubits)
280
+ scope_constraints.extend(_cnot_constraints(gate.qubits[0], gate.qubits[1], layer_in, layer_out, circuit))
281
+ elif gate.type == "S":
282
+ q = gate.qubits[0]
283
+ gates_affecting.add(q)
284
+ scope_constraints.extend([
285
+ {"kind": "EQ", "expr": f"{obs1('x', q, layer_out)} - {obs1('y', q, layer_in)}", "weight": 5.0},
286
+ {"kind": "EQ", "expr": f"{obs1('y', q, layer_out)} + {obs1('x', q, layer_in)}", "weight": 5.0},
287
+ {"kind": "EQ", "expr": f"{obs1('z', q, layer_out)} - {obs1('z', q, layer_in)}", "weight": 5.0}
288
+ ])
289
+ elif gate.type == "T":
290
+ q = gate.qubits[0]
291
+ gates_affecting.add(q)
292
+ c = round(math.cos(math.pi / 4), 8)
293
+ scope_constraints.extend([
294
+ {"kind": "EQ", "expr": f"{obs1('x', q, layer_out)} - {c}*{obs1('x', q, layer_in)} - {c}*{obs1('y', q, layer_in)}", "weight": 5.0},
295
+ {"kind": "EQ", "expr": f"{obs1('y', q, layer_out)} + {c}*{obs1('x', q, layer_in)} - {c}*{obs1('y', q, layer_in)}", "weight": 5.0},
296
+ {"kind": "EQ", "expr": f"{obs1('z', q, layer_out)} - {obs1('z', q, layer_in)}", "weight": 5.0}
297
+ ])
298
+
299
+ unaffected = [q for q in range(n) if q not in gates_affecting]
300
+ for q in unaffected:
301
+ for p in PAULI:
302
+ scope_constraints.append({"kind": "EQ", "expr": f"{obs1(p, q, layer_out)} - {obs1(p, q, layer_in)}", "weight": 5.0})
303
+ if include_2b:
304
+ for q2 in range(n):
305
+ if q2 == q or q2 in gates_affecting: continue
306
+ for p1p2 in PAULI2:
307
+ scope_constraints.append({
308
+ "kind": "EQ",
309
+ "expr": f"{obs2(p1p2[0], p1p2[1], q, q2, layer_out)} - {obs2(p1p2[0], p1p2[1], q, q2, layer_in)}",
310
+ "weight": 5.0
311
+ })
312
+
313
+ scope_var_names = []
314
+ for q in range(n):
315
+ for p in PAULI:
316
+ scope_var_names.extend([obs1(p, q, layer_in), obs1(p, q, layer_out)])
317
+ if include_2b:
318
+ for q1 in range(n):
319
+ for q2 in range(q1 + 1, n):
320
+ for p1p2 in PAULI2:
321
+ scope_var_names.extend([obs2(p1p2[0], p1p2[1], q1, q2, layer_in), obs2(p1p2[0], p1p2[1], q1, q2, layer_out)])
322
+ scope_var_names.extend(circuit.all_params)
323
+
324
+ scopes.append({
325
+ "name": f"layer_{layer_in}_to_{layer_out}",
326
+ "order": layer_in,
327
+ "vars": scope_var_names,
328
+ "constraints": scope_constraints,
329
+ })
330
+
331
+ anchors = []
332
+ if circuit.target_hamiltonian:
333
+ h_terms = []
334
+ for pauli_str, coeff in circuit.target_hamiltonian.items():
335
+ if len(pauli_str) == 2:
336
+ h_terms.append(f"({coeff})*{obs1(pauli_str[0], int(pauli_str[1:]), n_layers)}")
337
+ elif len(pauli_str) == 4:
338
+ h_terms.append(f"({coeff})*{obs2(pauli_str[0], pauli_str[1], int(pauli_str[2]), int(pauli_str[3]), n_layers)}")
339
+ if h_terms:
340
+ anchors.append(axl_invariant_class(
341
+ name="hamiltonian_expectation",
342
+ expr=" + ".join(h_terms),
343
+ tolerance=0.01,
344
+ mode="eq"
345
+ ))
346
+
347
+ for q in range(n):
348
+ anchors.append(axl_invariant_class(
349
+ name=f"bloch_q{q}",
350
+ expr=f"1.0 - {obs1('x', q, n_layers)}**2 - {obs1('y', q, n_layers)}**2 - {obs1('z', q, n_layers)}**2",
351
+ tolerance=0.05,
352
+ mode="geq"
353
+ ))
354
+
355
+ return axl_problem_class(
356
+ name=circuit.name,
357
+ description=(circuit.description or f"{n}-qubit circuit, {n_layers} layers"),
358
+ axioms={"CONTINUOUS", "CONSERVED", "TRANSITIVE", "BILINEAR", "METRIC", "SUPERPOSITION", "SYMMETRIC"},
359
+ variables=variables,
360
+ constraints=global_constraints,
361
+ scopes=scopes,
362
+ anchors=anchors,
363
+ observations=obs_fixed,
364
+ )
365
+
366
+ # ══════════════════════════════════════════════════════════════════════
367
+ # EXAMPLE CIRCUITS
368
+ # ══════════════════════════════════════════════════════════════════════
369
+
370
+ def example_bell_state() -> QuantumCircuit:
371
+ return QuantumCircuit(
372
+ n_qubits=2, name="BellStatePrep",
373
+ gates=[QGate("H", [0], layer=0), QGate("CNOT", [0, 1], layer=1)],
374
+ initial_state="zero", include_2body=True,
375
+ target_hamiltonian={"zz01": -1.0}
376
+ )
377
+
378
+ def example_vqe_h2() -> QuantumCircuit:
379
+ return QuantumCircuit(
380
+ n_qubits=2, name="VQE_H2",
381
+ gates=[
382
+ QGate("Ry", [0], ["theta0"], layer=0),
383
+ QGate("Ry", [1], ["theta1"], layer=0),
384
+ QGate("CNOT", [0, 1], layer=1),
385
+ ],
386
+ param_bounds={"theta0": (-math.pi, math.pi), "theta1": (-math.pi, math.pi)},
387
+ target_hamiltonian={"z0": -0.5, "z1": -0.5, "zz01": 0.25, "xx01": -0.5}
388
+ )
389
+
390
+ def example_qaoa_maxcut_p1() -> QuantumCircuit:
391
+ return QuantumCircuit(
392
+ n_qubits=3, name="QAOA_MaxCut",
393
+ gates=[
394
+ QGate("H", [0], layer=0), QGate("H", [1], layer=0), QGate("H", [2], layer=0),
395
+ QGate("Rz", [0], ["gamma"], layer=1), QGate("Rz", [1], ["gamma"], layer=1), QGate("Rz", [2], ["gamma"], layer=1),
396
+ QGate("Rx", [0], ["beta"], layer=2), QGate("Rx", [1], ["beta"], layer=2), QGate("Rx", [2], ["beta"], layer=2),
397
+ ],
398
+ param_bounds={"gamma": (0, math.pi), "beta": (0, math.pi / 2)},
399
+ target_hamiltonian={"zz01": -0.5, "zz12": -0.5, "zz02": -0.5}
400
+ )