Coverage for qml_essentials/ansaetze.py: 90%

403 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2025-01-23 11:23 +0000

1from abc import ABC, abstractmethod 

2from typing import Any, Optional 

3import pennylane.numpy as np 

4import pennylane as qml 

5 

6from typing import List 

7 

8import logging 

9 

10log = logging.getLogger(__name__) 

11 

12 

13class Circuit(ABC): 

14 def __init__(self): 

15 pass 

16 

17 @abstractmethod 

18 def n_params_per_layer(n_qubits: int) -> int: 

19 return 

20 

21 @abstractmethod 

22 def get_control_indices(self, n_qubits: int) -> List[int]: 

23 """ 

24 Returns the indices for the controlled rotation gates for one layer. 

25 Indices should slice the list of all parameters for one layer as follows: 

26 [indices[0]:indices[1]:indices[2]] 

27 

28 Parameters 

29 ---------- 

30 n_qubits : int 

31 Number of qubits in the circuit 

32 

33 Returns 

34 ------- 

35 Optional[np.ndarray] 

36 List of all controlled indices, or None if the circuit does not 

37 contain controlled rotation gates. 

38 """ 

39 return 

40 

41 def get_control_angles(self, w: np.ndarray, n_qubits: int) -> Optional[np.ndarray]: 

42 """ 

43 Returns the angles for the controlled rotation gates from the list of 

44 all parameters for one layer. 

45 

46 Parameters 

47 ---------- 

48 w : np.ndarray 

49 List of parameters for one layer 

50 n_qubits : int 

51 Number of qubits in the circuit 

52 

53 Returns 

54 ------- 

55 Optional[np.ndarray] 

56 List of all controlled parameters, or None if the circuit does not 

57 contain controlled rotation gates. 

58 """ 

59 indices = self.get_control_indices(n_qubits) 

60 if indices is None: 

61 return None 

62 

63 return w[indices[0] : indices[1] : indices[2]] 

64 

65 @abstractmethod 

66 def build(self, n_qubits: int, n_layers: int): 

67 return 

68 

69 def __call__(self, *args: Any, **kwds: Any) -> Any: 

70 self.build(*args, **kwds) 

71 

72 

73class Gates: 

74 def noise_gate(wires, noise_params=None): 

75 if noise_params is not None: 

76 if isinstance(wires, int): 

77 wires = [wires] # single qubit gate 

78 # iterate for multi qubit gates 

79 for wire in wires: 

80 qml.BitFlip(noise_params.get("BitFlip", 0.0), wires=wire) 

81 qml.PhaseFlip(noise_params.get("PhaseFlip", 0.0), wires=wire) 

82 qml.DepolarizingChannel( 

83 noise_params.get("DepolarizingChannel", 0.0), wires=wire 

84 ) 

85 

86 def Rot(phi, theta, omega, wires, noise_params=None): 

87 qml.Rot(phi, theta, omega, wires=wires) 

88 Gates.noise_gate(wires, noise_params) 

89 

90 def RX(w, wires, noise_params=None): 

91 qml.RX(w, wires=wires) 

92 Gates.noise_gate(wires, noise_params) 

93 

94 def RY(w, wires, noise_params=None): 

95 qml.RY(w, wires=wires) 

96 Gates.noise_gate(wires, noise_params) 

97 

98 def RZ(w, wires, noise_params=None): 

99 qml.RZ(w, wires=wires) 

100 Gates.noise_gate(wires, noise_params) 

101 

102 def CRX(w, wires, noise_params=None): 

103 qml.CRX(w, wires=wires) 

104 Gates.noise_gate(wires, noise_params) 

105 

106 def CRY(w, wires, noise_params=None): 

107 qml.CRY(w, wires=wires) 

108 Gates.noise_gate(wires, noise_params) 

109 

110 def CRZ(w, wires, noise_params=None): 

111 qml.CRZ(w, wires=wires) 

112 Gates.noise_gate(wires, noise_params) 

113 

114 def CX(wires, noise_params=None): 

115 qml.CNOT(wires=wires) 

116 Gates.noise_gate(wires, noise_params) 

117 

118 def CY(wires, noise_params=None): 

119 qml.CY(wires=wires) 

120 Gates.noise_gate(wires, noise_params) 

121 

122 def CZ(wires, noise_params=None): 

123 qml.CZ(wires=wires) 

124 Gates.noise_gate(wires, noise_params) 

125 

126 def H(wires, noise_params=None): 

127 qml.Hadamard(wires=wires) 

128 Gates.noise_gate(wires, noise_params) 

129 

130 

131class Ansaetze: 

132 

133 def get_available(): 

134 return [ 

135 Ansaetze.No_Ansatz, 

136 Ansaetze.Circuit_1, 

137 Ansaetze.Circuit_2, 

138 Ansaetze.Circuit_3, 

139 Ansaetze.Circuit_4, 

140 Ansaetze.Circuit_6, 

141 Ansaetze.Circuit_9, 

142 Ansaetze.Circuit_10, 

143 Ansaetze.Circuit_15, 

144 Ansaetze.Circuit_16, 

145 Ansaetze.Circuit_17, 

146 Ansaetze.Circuit_18, 

147 Ansaetze.Circuit_19, 

148 Ansaetze.No_Entangling, 

149 Ansaetze.Strongly_Entangling, 

150 Ansaetze.Hardware_Efficient, 

151 ] 

152 

153 class No_Ansatz(Circuit): 

154 @staticmethod 

155 def n_params_per_layer(n_qubits: int) -> int: 

156 return 0 

157 

158 @staticmethod 

159 def get_control_indices(n_qubits: int) -> Optional[np.ndarray]: 

160 return None 

161 

162 @staticmethod 

163 def build(w: np.ndarray, n_qubits: int, noise_params=None): 

164 pass 

165 

166 class Hardware_Efficient(Circuit): 

167 @staticmethod 

168 def n_params_per_layer(n_qubits: int) -> int: 

169 if n_qubits < 2: 

170 log.warning("Number of Qubits < 2, no entanglement available") 

171 return n_qubits * 3 

172 

173 @staticmethod 

174 def get_control_indices(n_qubits: int) -> Optional[np.ndarray]: 

175 return None 

176 

177 @staticmethod 

178 def build(w: np.ndarray, n_qubits: int, noise_params=None): 

179 """ 

180 Creates a Hardware-Efficient ansatz, as proposed in 

181 https://arxiv.org/pdf/2309.03279 

182 

183 Length of flattened vector must be n_qubits*3 

184 

185 Args: 

186 w (np.ndarray): weight vector of size n_layers*(n_qubits*3) 

187 n_qubits (int): number of qubits 

188 """ 

189 w_idx = 0 

190 for q in range(n_qubits): 

191 Gates.RY(w[w_idx], wires=q, noise_params=noise_params) 

192 w_idx += 1 

193 Gates.RZ(w[w_idx], wires=q, noise_params=noise_params) 

194 w_idx += 1 

195 Gates.RY(w[w_idx], wires=q, noise_params=noise_params) 

196 w_idx += 1 

197 

198 if n_qubits > 1: 

199 for q in range(n_qubits // 2): 

200 Gates.CX(wires=[(2 * q), (2 * q + 1)], noise_params=noise_params) 

201 for q in range((n_qubits - 1) // 2): 

202 Gates.CX( 

203 wires=[(2 * q + 1), (2 * q + 2)], noise_params=noise_params 

204 ) 

205 if n_qubits > 2: 

206 Gates.CX(wires=[(n_qubits - 1), 0], noise_params=noise_params) 

207 

208 class Circuit_19(Circuit): 

209 @staticmethod 

210 def n_params_per_layer(n_qubits: int) -> int: 

211 if n_qubits > 1: 

212 return n_qubits * 3 

213 else: 

214 log.warning("Number of Qubits < 2, no entanglement available") 

215 return 2 

216 

217 @staticmethod 

218 def get_control_indices(n_qubits: int) -> Optional[np.ndarray]: 

219 if n_qubits > 1: 

220 return [-n_qubits, None, None] 

221 else: 

222 return None 

223 

224 @staticmethod 

225 def build(w: np.ndarray, n_qubits: int, noise_params=None): 

226 """ 

227 Creates a Circuit19 ansatz. 

228 

229 Length of flattened vector must be n_qubits*3-1 

230 because for >1 qubits there are three gates 

231 

232 Args: 

233 w (np.ndarray): weight vector of size n_layers*(n_qubits*3-1) 

234 n_qubits (int): number of qubits 

235 """ 

236 w_idx = 0 

237 for q in range(n_qubits): 

238 Gates.RX(w[w_idx], wires=q, noise_params=noise_params) 

239 w_idx += 1 

240 Gates.RZ(w[w_idx], wires=q, noise_params=noise_params) 

241 w_idx += 1 

242 

243 if n_qubits > 1: 

244 for q in range(n_qubits): 

245 Gates.CRX( 

246 w[w_idx], 

247 wires=[n_qubits - q - 1, (n_qubits - q) % n_qubits], 

248 noise_params=noise_params, 

249 ) 

250 w_idx += 1 

251 

252 class Circuit_18(Circuit): 

253 @staticmethod 

254 def n_params_per_layer(n_qubits: int) -> int: 

255 if n_qubits > 1: 

256 return n_qubits * 3 

257 else: 

258 log.warning("Number of Qubits < 2, no entanglement available") 

259 return 2 

260 

261 @staticmethod 

262 def get_control_indices(n_qubits: int) -> Optional[np.ndarray]: 

263 if n_qubits > 1: 

264 return [-n_qubits, None, None] 

265 else: 

266 return None 

267 

268 @staticmethod 

269 def build(w: np.ndarray, n_qubits: int, noise_params=None): 

270 """ 

271 Creates a Circuit18 ansatz. 

272 

273 Length of flattened vector must be n_qubits*3 

274 

275 Args: 

276 w (np.ndarray): weight vector of size n_layers*(n_qubits*3) 

277 n_qubits (int): number of qubits 

278 """ 

279 w_idx = 0 

280 for q in range(n_qubits): 

281 Gates.RX(w[w_idx], wires=q, noise_params=noise_params) 

282 w_idx += 1 

283 Gates.RZ(w[w_idx], wires=q, noise_params=noise_params) 

284 w_idx += 1 

285 

286 if n_qubits > 1: 

287 for q in range(n_qubits): 

288 Gates.CRZ( 

289 w[w_idx], 

290 wires=[n_qubits - q - 1, (n_qubits - q) % n_qubits], 

291 noise_params=noise_params, 

292 ) 

293 w_idx += 1 

294 

295 class Circuit_15(Circuit): 

296 @staticmethod 

297 def n_params_per_layer(n_qubits: int) -> int: 

298 if n_qubits > 1: 

299 return n_qubits * 2 

300 else: 

301 log.warning("Number of Qubits < 2, no entanglement available") 

302 return 2 

303 

304 @staticmethod 

305 def get_control_indices(n_qubits: int) -> Optional[np.ndarray]: 

306 return None 

307 

308 @staticmethod 

309 def build(w: np.ndarray, n_qubits: int, noise_params=None): 

310 """ 

311 Creates a Circuit15 ansatz. 

312 

313 Length of flattened vector must be n_qubits*2 

314 because for >1 qubits there are three gates 

315 

316 Args: 

317 w (np.ndarray): weight vector of size n_layers*(n_qubits*2) 

318 n_qubits (int): number of qubits 

319 """ 

320 w_idx = 0 

321 for q in range(n_qubits): 

322 Gates.RY(w[w_idx], wires=q, noise_params=noise_params) 

323 w_idx += 1 

324 

325 if n_qubits > 1: 

326 for q in range(n_qubits): 

327 Gates.CX( 

328 wires=[n_qubits - q - 1, (n_qubits - q) % n_qubits], 

329 noise_params=noise_params, 

330 ) 

331 

332 for q in range(n_qubits): 

333 Gates.RY(w[w_idx], wires=q, noise_params=noise_params) 

334 w_idx += 1 

335 

336 if n_qubits > 1: 

337 for q in range(n_qubits): 

338 Gates.CX( 

339 wires=[(q - 1) % n_qubits, (q - 2) % n_qubits], 

340 noise_params=noise_params, 

341 ) 

342 

343 class Circuit_9(Circuit): 

344 @staticmethod 

345 def n_params_per_layer(n_qubits: int) -> int: 

346 return n_qubits 

347 

348 @staticmethod 

349 def get_control_indices(n_qubits: int) -> Optional[np.ndarray]: 

350 return None 

351 

352 @staticmethod 

353 def build(w: np.ndarray, n_qubits: int, noise_params=None): 

354 """ 

355 Creates a Circuit9 ansatz. 

356 

357 Length of flattened vector must be n_qubits 

358 

359 Args: 

360 w (np.ndarray): weight vector of size n_layers*n_qubits 

361 n_qubits (int): number of qubits 

362 """ 

363 w_idx = 0 

364 for q in range(n_qubits): 

365 Gates.H(wires=q, noise_params=noise_params) 

366 

367 if n_qubits > 1: 

368 for q in range(n_qubits - 1): 

369 Gates.CZ( 

370 wires=[n_qubits - q - 2, n_qubits - q - 1], 

371 noise_params=noise_params, 

372 ) 

373 

374 for q in range(n_qubits): 

375 Gates.RX(w[w_idx], wires=q, noise_params=noise_params) 

376 w_idx += 1 

377 

378 class Circuit_6(Circuit): 

379 @staticmethod 

380 def n_params_per_layer(n_qubits: int) -> int: 

381 if n_qubits > 1: 

382 return n_qubits * 3 + n_qubits**2 

383 else: 

384 log.warning("Number of Qubits < 2, no entanglement available") 

385 return 4 

386 

387 @staticmethod 

388 def get_control_indices(n_qubits: int) -> Optional[np.ndarray]: 

389 if n_qubits > 1: 

390 return [-n_qubits, None, None] 

391 else: 

392 return None 

393 

394 @staticmethod 

395 def build(w: np.ndarray, n_qubits: int, noise_params=None): 

396 """ 

397 Creates a Circuit6 ansatz. 

398 

399 Length of flattened vector must be 

400 n_qubits * 4 + n_qubits * (n_qubits - 1) = 

401 n_qubits * 3 + n_qubits**2 

402 

403 Args: 

404 w (np.ndarray): weight vector of size 

405 n_layers * (n_qubits * 3 + n_qubits**2) 

406 n_qubits (int): number of qubits 

407 """ 

408 w_idx = 0 

409 for q in range(n_qubits): 

410 Gates.RX(w[w_idx], wires=q, noise_params=noise_params) 

411 w_idx += 1 

412 Gates.RZ(w[w_idx], wires=q, noise_params=noise_params) 

413 w_idx += 1 

414 

415 if n_qubits > 1: 

416 for ql in range(n_qubits): 

417 for q in range(n_qubits): 

418 if q == ql: 

419 continue 

420 Gates.CRX( 

421 w[w_idx], 

422 wires=[n_qubits - ql - 1, (n_qubits - q - 1) % n_qubits], 

423 noise_params=noise_params, 

424 ) 

425 w_idx += 1 

426 

427 for q in range(n_qubits): 

428 Gates.RX(w[w_idx], wires=q, noise_params=noise_params) 

429 w_idx += 1 

430 Gates.RZ(w[w_idx], wires=q, noise_params=noise_params) 

431 w_idx += 1 

432 

433 class Circuit_1(Circuit): 

434 @staticmethod 

435 def n_params_per_layer(n_qubits: int) -> int: 

436 return n_qubits * 2 

437 

438 @staticmethod 

439 def get_control_indices(n_qubits: int) -> Optional[np.ndarray]: 

440 return None 

441 

442 @staticmethod 

443 def build(w: np.ndarray, n_qubits: int, noise_params=None): 

444 """ 

445 Creates a Circuit1 ansatz. 

446 

447 Length of flattened vector must be n_qubits*2 

448 

449 Args: 

450 w (np.ndarray): weight vector of size n_layers*(n_qubits*2) 

451 n_qubits (int): number of qubits 

452 """ 

453 w_idx = 0 

454 for q in range(n_qubits): 

455 Gates.RX(w[w_idx], wires=q, noise_params=noise_params) 

456 w_idx += 1 

457 Gates.RZ(w[w_idx], wires=q, noise_params=noise_params) 

458 w_idx += 1 

459 

460 class Circuit_2(Circuit): 

461 @staticmethod 

462 def n_params_per_layer(n_qubits: int) -> int: 

463 return n_qubits * 2 

464 

465 @staticmethod 

466 def get_control_indices(n_qubits: int) -> Optional[np.ndarray]: 

467 return None 

468 

469 @staticmethod 

470 def build(w: np.ndarray, n_qubits: int, noise_params=None): 

471 """ 

472 Creates a Circuit2 ansatz. 

473 

474 Length of flattened vector must be n_qubits*2 

475 

476 Args: 

477 w (np.ndarray): weight vector of size n_layers*(n_qubits*2) 

478 n_qubits (int): number of qubits 

479 """ 

480 w_idx = 0 

481 for q in range(n_qubits): 

482 Gates.RX(w[w_idx], wires=q, noise_params=noise_params) 

483 w_idx += 1 

484 Gates.RZ(w[w_idx], wires=q, noise_params=noise_params) 

485 w_idx += 1 

486 

487 if n_qubits > 1: 

488 for q in range(n_qubits - 1): 

489 Gates.CX( 

490 wires=[n_qubits - q - 1, n_qubits - q - 2], 

491 noise_params=noise_params, 

492 ) 

493 

494 class Circuit_3(Circuit): 

495 @staticmethod 

496 def n_params_per_layer(n_qubits: int) -> int: 

497 return n_qubits * 3 - 1 

498 

499 @staticmethod 

500 def get_control_indices(n_qubits: int) -> Optional[np.ndarray]: 

501 return None 

502 

503 @staticmethod 

504 def build(w: np.ndarray, n_qubits: int, noise_params=None): 

505 """ 

506 Creates a Circuit3 ansatz. 

507 

508 Length of flattened vector must be n_qubits*3-1 

509 

510 Args: 

511 w (np.ndarray): weight vector of size n_layers*(n_qubits*3-1) 

512 n_qubits (int): number of qubits 

513 """ 

514 w_idx = 0 

515 for q in range(n_qubits): 

516 Gates.RX(w[w_idx], wires=q, noise_params=noise_params) 

517 w_idx += 1 

518 Gates.RZ(w[w_idx], wires=q, noise_params=noise_params) 

519 w_idx += 1 

520 

521 if n_qubits > 1: 

522 for q in range(n_qubits - 1): 

523 Gates.CRZ( 

524 w[w_idx], 

525 wires=[n_qubits - q - 1, n_qubits - q - 2], 

526 noise_params=noise_params, 

527 ) 

528 w_idx += 1 

529 

530 class Circuit_4(Circuit): 

531 @staticmethod 

532 def n_params_per_layer(n_qubits: int) -> int: 

533 return n_qubits * 3 - 1 

534 

535 @staticmethod 

536 def get_control_indices(n_qubits: int) -> Optional[np.ndarray]: 

537 return None 

538 

539 @staticmethod 

540 def build(w: np.ndarray, n_qubits: int, noise_params=None): 

541 """ 

542 Creates a Circuit4 ansatz. 

543 

544 Length of flattened vector must be n_qubits*3-1 

545 

546 Args: 

547 w (np.ndarray): weight vector of size n_layers*(n_qubits*3-1) 

548 n_qubits (int): number of qubits 

549 """ 

550 w_idx = 0 

551 for q in range(n_qubits): 

552 Gates.RX(w[w_idx], wires=q, noise_params=noise_params) 

553 w_idx += 1 

554 Gates.RZ(w[w_idx], wires=q, noise_params=noise_params) 

555 w_idx += 1 

556 

557 if n_qubits > 1: 

558 for q in range(n_qubits - 1): 

559 Gates.CRX( 

560 w[w_idx], 

561 wires=[n_qubits - q - 1, n_qubits - q - 2], 

562 noise_params=noise_params, 

563 ) 

564 w_idx += 1 

565 

566 class Circuit_10(Circuit): 

567 @staticmethod 

568 def n_params_per_layer(n_qubits: int) -> int: 

569 return n_qubits * 2 # constant gates not considered yet. has to be fixed 

570 

571 @staticmethod 

572 def get_control_indices(n_qubits: int) -> Optional[np.ndarray]: 

573 return None 

574 

575 @staticmethod 

576 def build(w: np.ndarray, n_qubits: int, noise_params=None): 

577 """ 

578 Creates a Circuit10 ansatz. 

579 

580 Length of flattened vector must be n_qubits 

581 

582 Args: 

583 w (np.ndarray): weight vector of size n_layers*n_qubits 

584 n_qubits (int): number of qubits 

585 """ 

586 w_idx = 0 

587 # constant gates, independent of layers. has to be fixed 

588 for q in range(n_qubits): 

589 Gates.RY(w[w_idx], wires=q, noise_params=noise_params) 

590 w_idx += 1 

591 

592 if n_qubits > 1: 

593 for q in range(n_qubits - 1): 

594 Gates.CZ( 

595 wires=[ 

596 (n_qubits - q - 2) % n_qubits, 

597 (n_qubits - q - 1) % n_qubits, 

598 ], 

599 noise_params=noise_params, 

600 ) 

601 if n_qubits > 2: 

602 Gates.CZ(wires=[n_qubits - 1, 0], noise_params=noise_params) 

603 

604 for q in range(n_qubits): 

605 Gates.RY(w[w_idx], wires=q, noise_params=noise_params) 

606 w_idx += 1 

607 

608 class Circuit_16(Circuit): 

609 @staticmethod 

610 def n_params_per_layer(n_qubits: int) -> int: 

611 return n_qubits * 3 - 1 

612 

613 @staticmethod 

614 def get_control_indices(n_qubits: int) -> Optional[np.ndarray]: 

615 return None 

616 

617 @staticmethod 

618 def build(w: np.ndarray, n_qubits: int, noise_params=None): 

619 """ 

620 Creates a Circuit16 ansatz. 

621 

622 Length of flattened vector must be n_qubits*3-1 

623 

624 Args: 

625 w (np.ndarray): weight vector of size n_layers*n_qubits*3-1 

626 n_qubits (int): number of qubits 

627 """ 

628 w_idx = 0 

629 for q in range(n_qubits): 

630 Gates.RX(w[w_idx], wires=q, noise_params=noise_params) 

631 w_idx += 1 

632 Gates.RZ(w[w_idx], wires=q, noise_params=noise_params) 

633 w_idx += 1 

634 

635 if n_qubits > 1: 

636 for q in range(n_qubits // 2): 

637 Gates.CRZ( 

638 w[w_idx], 

639 wires=[(2 * q + 1), (2 * q)], 

640 noise_params=noise_params, 

641 ) 

642 w_idx += 1 

643 

644 for q in range((n_qubits - 1) // 2): 

645 Gates.CRZ( 

646 w[w_idx], 

647 wires=[(2 * q + 2), (2 * q + 1)], 

648 noise_params=noise_params, 

649 ) 

650 w_idx += 1 

651 

652 class Circuit_17(Circuit): 

653 @staticmethod 

654 def n_params_per_layer(n_qubits: int) -> int: 

655 return n_qubits * 3 - 1 

656 

657 @staticmethod 

658 def get_control_indices(n_qubits: int) -> Optional[np.ndarray]: 

659 return None 

660 

661 @staticmethod 

662 def build(w: np.ndarray, n_qubits: int, noise_params=None): 

663 """ 

664 Creates a Circuit17 ansatz. 

665 

666 Length of flattened vector must be n_qubits*3-1 

667 

668 Args: 

669 w (np.ndarray): weight vector of size n_layers*n_qubits*3-1 

670 n_qubits (int): number of qubits 

671 """ 

672 w_idx = 0 

673 for q in range(n_qubits): 

674 Gates.RX(w[w_idx], wires=q, noise_params=noise_params) 

675 w_idx += 1 

676 Gates.RZ(w[w_idx], wires=q, noise_params=noise_params) 

677 w_idx += 1 

678 

679 if n_qubits > 1: 

680 for q in range(n_qubits // 2): 

681 Gates.CRX( 

682 w[w_idx], 

683 wires=[(2 * q + 1), (2 * q)], 

684 noise_params=noise_params, 

685 ) 

686 w_idx += 1 

687 

688 for q in range((n_qubits - 1) // 2): 

689 Gates.CRX( 

690 w[w_idx], 

691 wires=[(2 * q + 2), (2 * q + 1)], 

692 noise_params=noise_params, 

693 ) 

694 w_idx += 1 

695 

696 class Strongly_Entangling(Circuit): 

697 @staticmethod 

698 def n_params_per_layer(n_qubits: int) -> int: 

699 if n_qubits < 2: 

700 log.warning("Number of Qubits < 2, no entanglement available") 

701 return n_qubits * 6 

702 

703 @staticmethod 

704 def get_control_indices(n_qubits: int) -> Optional[np.ndarray]: 

705 return None 

706 

707 @staticmethod 

708 def build(w: np.ndarray, n_qubits: int, noise_params=None) -> None: 

709 """ 

710 Creates a StronglyEntanglingLayers ansatz. 

711 

712 Args: 

713 w (np.ndarray): weight vector of size n_layers*(n_qubits*6) 

714 n_qubits (int): number of qubits 

715 """ 

716 w_idx = 0 

717 for q in range(n_qubits): 

718 Gates.Rot( 

719 w[w_idx], 

720 w[w_idx + 1], 

721 w[w_idx + 2], 

722 wires=q, 

723 noise_params=noise_params, 

724 ) 

725 w_idx += 3 

726 

727 if n_qubits > 1: 

728 for q in range(n_qubits): 

729 Gates.CX(wires=[q, (q + 1) % n_qubits], noise_params=noise_params) 

730 

731 for q in range(n_qubits): 

732 Gates.Rot( 

733 w[w_idx], 

734 w[w_idx + 1], 

735 w[w_idx + 2], 

736 wires=q, 

737 noise_params=noise_params, 

738 ) 

739 w_idx += 3 

740 

741 if n_qubits > 1: 

742 for q in range(n_qubits): 

743 Gates.CX( 

744 wires=[q, (q + n_qubits // 2) % n_qubits], 

745 noise_params=noise_params, 

746 ) 

747 

748 class No_Entangling(Circuit): 

749 @staticmethod 

750 def n_params_per_layer(n_qubits: int) -> int: 

751 return n_qubits * 3 

752 

753 @staticmethod 

754 def get_control_indices(n_qubits: int) -> Optional[np.ndarray]: 

755 return None 

756 

757 @staticmethod 

758 def build(w: np.ndarray, n_qubits: int, noise_params=None): 

759 """ 

760 Creates a circuit without entangling, but with U3 gates on all qubits 

761 

762 Length of flattened vector must be n_qubits*3 

763 

764 Args: 

765 w (np.ndarray): weight vector of size n_layers*(n_qubits*3) 

766 n_qubits (int): number of qubits 

767 """ 

768 w_idx = 0 

769 for q in range(n_qubits): 

770 Gates.Rot( 

771 w[w_idx], 

772 w[w_idx + 1], 

773 w[w_idx + 2], 

774 wires=q, 

775 noise_params=noise_params, 

776 ) 

777 w_idx += 3