test_identitysearch.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. from sympy.external import import_module
  2. from sympy.core.mul import Mul
  3. from sympy.core.numbers import Integer
  4. from sympy.physics.quantum.dagger import Dagger
  5. from sympy.physics.quantum.gate import (X, Y, Z, H, CNOT,
  6. IdentityGate, CGate, PhaseGate, TGate)
  7. from sympy.physics.quantum.identitysearch import (generate_gate_rules,
  8. generate_equivalent_ids, GateIdentity, bfs_identity_search,
  9. is_scalar_sparse_matrix,
  10. is_scalar_nonsparse_matrix, is_degenerate, is_reducible)
  11. from sympy.testing.pytest import skip
  12. def create_gate_sequence(qubit=0):
  13. gates = (X(qubit), Y(qubit), Z(qubit), H(qubit))
  14. return gates
  15. def test_generate_gate_rules_1():
  16. # Test with tuples
  17. (x, y, z, h) = create_gate_sequence()
  18. ph = PhaseGate(0)
  19. cgate_t = CGate(0, TGate(1))
  20. assert generate_gate_rules((x,)) == {((x,), ())}
  21. gate_rules = {((x, x), ()),
  22. ((x,), (x,))}
  23. assert generate_gate_rules((x, x)) == gate_rules
  24. gate_rules = {((x, y, x), ()),
  25. ((y, x, x), ()),
  26. ((x, x, y), ()),
  27. ((y, x), (x,)),
  28. ((x, y), (x,)),
  29. ((y,), (x, x))}
  30. assert generate_gate_rules((x, y, x)) == gate_rules
  31. gate_rules = {((x, y, z), ()), ((y, z, x), ()), ((z, x, y), ()),
  32. ((), (x, z, y)), ((), (y, x, z)), ((), (z, y, x)),
  33. ((x,), (z, y)), ((y, z), (x,)), ((y,), (x, z)),
  34. ((z, x), (y,)), ((z,), (y, x)), ((x, y), (z,))}
  35. actual = generate_gate_rules((x, y, z))
  36. assert actual == gate_rules
  37. gate_rules = {
  38. ((), (h, z, y, x)), ((), (x, h, z, y)), ((), (y, x, h, z)),
  39. ((), (z, y, x, h)), ((h,), (z, y, x)), ((x,), (h, z, y)),
  40. ((y,), (x, h, z)), ((z,), (y, x, h)), ((h, x), (z, y)),
  41. ((x, y), (h, z)), ((y, z), (x, h)), ((z, h), (y, x)),
  42. ((h, x, y), (z,)), ((x, y, z), (h,)), ((y, z, h), (x,)),
  43. ((z, h, x), (y,)), ((h, x, y, z), ()), ((x, y, z, h), ()),
  44. ((y, z, h, x), ()), ((z, h, x, y), ())}
  45. actual = generate_gate_rules((x, y, z, h))
  46. assert actual == gate_rules
  47. gate_rules = {((), (cgate_t**(-1), ph**(-1), x)),
  48. ((), (ph**(-1), x, cgate_t**(-1))),
  49. ((), (x, cgate_t**(-1), ph**(-1))),
  50. ((cgate_t,), (ph**(-1), x)),
  51. ((ph,), (x, cgate_t**(-1))),
  52. ((x,), (cgate_t**(-1), ph**(-1))),
  53. ((cgate_t, x), (ph**(-1),)),
  54. ((ph, cgate_t), (x,)),
  55. ((x, ph), (cgate_t**(-1),)),
  56. ((cgate_t, x, ph), ()),
  57. ((ph, cgate_t, x), ()),
  58. ((x, ph, cgate_t), ())}
  59. actual = generate_gate_rules((x, ph, cgate_t))
  60. assert actual == gate_rules
  61. gate_rules = {(Integer(1), cgate_t**(-1)*ph**(-1)*x),
  62. (Integer(1), ph**(-1)*x*cgate_t**(-1)),
  63. (Integer(1), x*cgate_t**(-1)*ph**(-1)),
  64. (cgate_t, ph**(-1)*x),
  65. (ph, x*cgate_t**(-1)),
  66. (x, cgate_t**(-1)*ph**(-1)),
  67. (cgate_t*x, ph**(-1)),
  68. (ph*cgate_t, x),
  69. (x*ph, cgate_t**(-1)),
  70. (cgate_t*x*ph, Integer(1)),
  71. (ph*cgate_t*x, Integer(1)),
  72. (x*ph*cgate_t, Integer(1))}
  73. actual = generate_gate_rules((x, ph, cgate_t), return_as_muls=True)
  74. assert actual == gate_rules
  75. def test_generate_gate_rules_2():
  76. # Test with Muls
  77. (x, y, z, h) = create_gate_sequence()
  78. ph = PhaseGate(0)
  79. cgate_t = CGate(0, TGate(1))
  80. # Note: 1 (type int) is not the same as 1 (type One)
  81. expected = {(x, Integer(1))}
  82. assert generate_gate_rules((x,), return_as_muls=True) == expected
  83. expected = {(Integer(1), Integer(1))}
  84. assert generate_gate_rules(x*x, return_as_muls=True) == expected
  85. expected = {((), ())}
  86. assert generate_gate_rules(x*x, return_as_muls=False) == expected
  87. gate_rules = {(x*y*x, Integer(1)),
  88. (y, Integer(1)),
  89. (y*x, x),
  90. (x*y, x)}
  91. assert generate_gate_rules(x*y*x, return_as_muls=True) == gate_rules
  92. gate_rules = {(x*y*z, Integer(1)),
  93. (y*z*x, Integer(1)),
  94. (z*x*y, Integer(1)),
  95. (Integer(1), x*z*y),
  96. (Integer(1), y*x*z),
  97. (Integer(1), z*y*x),
  98. (x, z*y),
  99. (y*z, x),
  100. (y, x*z),
  101. (z*x, y),
  102. (z, y*x),
  103. (x*y, z)}
  104. actual = generate_gate_rules(x*y*z, return_as_muls=True)
  105. assert actual == gate_rules
  106. gate_rules = {(Integer(1), h*z*y*x),
  107. (Integer(1), x*h*z*y),
  108. (Integer(1), y*x*h*z),
  109. (Integer(1), z*y*x*h),
  110. (h, z*y*x), (x, h*z*y),
  111. (y, x*h*z), (z, y*x*h),
  112. (h*x, z*y), (z*h, y*x),
  113. (x*y, h*z), (y*z, x*h),
  114. (h*x*y, z), (x*y*z, h),
  115. (y*z*h, x), (z*h*x, y),
  116. (h*x*y*z, Integer(1)),
  117. (x*y*z*h, Integer(1)),
  118. (y*z*h*x, Integer(1)),
  119. (z*h*x*y, Integer(1))}
  120. actual = generate_gate_rules(x*y*z*h, return_as_muls=True)
  121. assert actual == gate_rules
  122. gate_rules = {(Integer(1), cgate_t**(-1)*ph**(-1)*x),
  123. (Integer(1), ph**(-1)*x*cgate_t**(-1)),
  124. (Integer(1), x*cgate_t**(-1)*ph**(-1)),
  125. (cgate_t, ph**(-1)*x),
  126. (ph, x*cgate_t**(-1)),
  127. (x, cgate_t**(-1)*ph**(-1)),
  128. (cgate_t*x, ph**(-1)),
  129. (ph*cgate_t, x),
  130. (x*ph, cgate_t**(-1)),
  131. (cgate_t*x*ph, Integer(1)),
  132. (ph*cgate_t*x, Integer(1)),
  133. (x*ph*cgate_t, Integer(1))}
  134. actual = generate_gate_rules(x*ph*cgate_t, return_as_muls=True)
  135. assert actual == gate_rules
  136. gate_rules = {((), (cgate_t**(-1), ph**(-1), x)),
  137. ((), (ph**(-1), x, cgate_t**(-1))),
  138. ((), (x, cgate_t**(-1), ph**(-1))),
  139. ((cgate_t,), (ph**(-1), x)),
  140. ((ph,), (x, cgate_t**(-1))),
  141. ((x,), (cgate_t**(-1), ph**(-1))),
  142. ((cgate_t, x), (ph**(-1),)),
  143. ((ph, cgate_t), (x,)),
  144. ((x, ph), (cgate_t**(-1),)),
  145. ((cgate_t, x, ph), ()),
  146. ((ph, cgate_t, x), ()),
  147. ((x, ph, cgate_t), ())}
  148. actual = generate_gate_rules(x*ph*cgate_t)
  149. assert actual == gate_rules
  150. def test_generate_equivalent_ids_1():
  151. # Test with tuples
  152. (x, y, z, h) = create_gate_sequence()
  153. assert generate_equivalent_ids((x,)) == {(x,)}
  154. assert generate_equivalent_ids((x, x)) == {(x, x)}
  155. assert generate_equivalent_ids((x, y)) == {(x, y), (y, x)}
  156. gate_seq = (x, y, z)
  157. gate_ids = {(x, y, z), (y, z, x), (z, x, y), (z, y, x),
  158. (y, x, z), (x, z, y)}
  159. assert generate_equivalent_ids(gate_seq) == gate_ids
  160. gate_ids = {Mul(x, y, z), Mul(y, z, x), Mul(z, x, y),
  161. Mul(z, y, x), Mul(y, x, z), Mul(x, z, y)}
  162. assert generate_equivalent_ids(gate_seq, return_as_muls=True) == gate_ids
  163. gate_seq = (x, y, z, h)
  164. gate_ids = {(x, y, z, h), (y, z, h, x),
  165. (h, x, y, z), (h, z, y, x),
  166. (z, y, x, h), (y, x, h, z),
  167. (z, h, x, y), (x, h, z, y)}
  168. assert generate_equivalent_ids(gate_seq) == gate_ids
  169. gate_seq = (x, y, x, y)
  170. gate_ids = {(x, y, x, y), (y, x, y, x)}
  171. assert generate_equivalent_ids(gate_seq) == gate_ids
  172. cgate_y = CGate((1,), y)
  173. gate_seq = (y, cgate_y, y, cgate_y)
  174. gate_ids = {(y, cgate_y, y, cgate_y), (cgate_y, y, cgate_y, y)}
  175. assert generate_equivalent_ids(gate_seq) == gate_ids
  176. cnot = CNOT(1, 0)
  177. cgate_z = CGate((0,), Z(1))
  178. gate_seq = (cnot, h, cgate_z, h)
  179. gate_ids = {(cnot, h, cgate_z, h), (h, cgate_z, h, cnot),
  180. (h, cnot, h, cgate_z), (cgate_z, h, cnot, h)}
  181. assert generate_equivalent_ids(gate_seq) == gate_ids
  182. def test_generate_equivalent_ids_2():
  183. # Test with Muls
  184. (x, y, z, h) = create_gate_sequence()
  185. assert generate_equivalent_ids((x,), return_as_muls=True) == {x}
  186. gate_ids = {Integer(1)}
  187. assert generate_equivalent_ids(x*x, return_as_muls=True) == gate_ids
  188. gate_ids = {x*y, y*x}
  189. assert generate_equivalent_ids(x*y, return_as_muls=True) == gate_ids
  190. gate_ids = {(x, y), (y, x)}
  191. assert generate_equivalent_ids(x*y) == gate_ids
  192. circuit = Mul(*(x, y, z))
  193. gate_ids = {x*y*z, y*z*x, z*x*y, z*y*x,
  194. y*x*z, x*z*y}
  195. assert generate_equivalent_ids(circuit, return_as_muls=True) == gate_ids
  196. circuit = Mul(*(x, y, z, h))
  197. gate_ids = {x*y*z*h, y*z*h*x,
  198. h*x*y*z, h*z*y*x,
  199. z*y*x*h, y*x*h*z,
  200. z*h*x*y, x*h*z*y}
  201. assert generate_equivalent_ids(circuit, return_as_muls=True) == gate_ids
  202. circuit = Mul(*(x, y, x, y))
  203. gate_ids = {x*y*x*y, y*x*y*x}
  204. assert generate_equivalent_ids(circuit, return_as_muls=True) == gate_ids
  205. cgate_y = CGate((1,), y)
  206. circuit = Mul(*(y, cgate_y, y, cgate_y))
  207. gate_ids = {y*cgate_y*y*cgate_y, cgate_y*y*cgate_y*y}
  208. assert generate_equivalent_ids(circuit, return_as_muls=True) == gate_ids
  209. cnot = CNOT(1, 0)
  210. cgate_z = CGate((0,), Z(1))
  211. circuit = Mul(*(cnot, h, cgate_z, h))
  212. gate_ids = {cnot*h*cgate_z*h, h*cgate_z*h*cnot,
  213. h*cnot*h*cgate_z, cgate_z*h*cnot*h}
  214. assert generate_equivalent_ids(circuit, return_as_muls=True) == gate_ids
  215. def test_is_scalar_nonsparse_matrix():
  216. numqubits = 2
  217. id_only = False
  218. id_gate = (IdentityGate(1),)
  219. actual = is_scalar_nonsparse_matrix(id_gate, numqubits, id_only)
  220. assert actual is True
  221. x0 = X(0)
  222. xx_circuit = (x0, x0)
  223. actual = is_scalar_nonsparse_matrix(xx_circuit, numqubits, id_only)
  224. assert actual is True
  225. x1 = X(1)
  226. y1 = Y(1)
  227. xy_circuit = (x1, y1)
  228. actual = is_scalar_nonsparse_matrix(xy_circuit, numqubits, id_only)
  229. assert actual is False
  230. z1 = Z(1)
  231. xyz_circuit = (x1, y1, z1)
  232. actual = is_scalar_nonsparse_matrix(xyz_circuit, numqubits, id_only)
  233. assert actual is True
  234. cnot = CNOT(1, 0)
  235. cnot_circuit = (cnot, cnot)
  236. actual = is_scalar_nonsparse_matrix(cnot_circuit, numqubits, id_only)
  237. assert actual is True
  238. h = H(0)
  239. hh_circuit = (h, h)
  240. actual = is_scalar_nonsparse_matrix(hh_circuit, numqubits, id_only)
  241. assert actual is True
  242. h1 = H(1)
  243. xhzh_circuit = (x1, h1, z1, h1)
  244. actual = is_scalar_nonsparse_matrix(xhzh_circuit, numqubits, id_only)
  245. assert actual is True
  246. id_only = True
  247. actual = is_scalar_nonsparse_matrix(xhzh_circuit, numqubits, id_only)
  248. assert actual is True
  249. actual = is_scalar_nonsparse_matrix(xyz_circuit, numqubits, id_only)
  250. assert actual is False
  251. actual = is_scalar_nonsparse_matrix(cnot_circuit, numqubits, id_only)
  252. assert actual is True
  253. actual = is_scalar_nonsparse_matrix(hh_circuit, numqubits, id_only)
  254. assert actual is True
  255. def test_is_scalar_sparse_matrix():
  256. np = import_module('numpy')
  257. if not np:
  258. skip("numpy not installed.")
  259. scipy = import_module('scipy', import_kwargs={'fromlist': ['sparse']})
  260. if not scipy:
  261. skip("scipy not installed.")
  262. numqubits = 2
  263. id_only = False
  264. id_gate = (IdentityGate(1),)
  265. assert is_scalar_sparse_matrix(id_gate, numqubits, id_only) is True
  266. x0 = X(0)
  267. xx_circuit = (x0, x0)
  268. assert is_scalar_sparse_matrix(xx_circuit, numqubits, id_only) is True
  269. x1 = X(1)
  270. y1 = Y(1)
  271. xy_circuit = (x1, y1)
  272. assert is_scalar_sparse_matrix(xy_circuit, numqubits, id_only) is False
  273. z1 = Z(1)
  274. xyz_circuit = (x1, y1, z1)
  275. assert is_scalar_sparse_matrix(xyz_circuit, numqubits, id_only) is True
  276. cnot = CNOT(1, 0)
  277. cnot_circuit = (cnot, cnot)
  278. assert is_scalar_sparse_matrix(cnot_circuit, numqubits, id_only) is True
  279. h = H(0)
  280. hh_circuit = (h, h)
  281. assert is_scalar_sparse_matrix(hh_circuit, numqubits, id_only) is True
  282. # NOTE:
  283. # The elements of the sparse matrix for the following circuit
  284. # is actually 1.0000000000000002+0.0j.
  285. h1 = H(1)
  286. xhzh_circuit = (x1, h1, z1, h1)
  287. assert is_scalar_sparse_matrix(xhzh_circuit, numqubits, id_only) is True
  288. id_only = True
  289. assert is_scalar_sparse_matrix(xhzh_circuit, numqubits, id_only) is True
  290. assert is_scalar_sparse_matrix(xyz_circuit, numqubits, id_only) is False
  291. assert is_scalar_sparse_matrix(cnot_circuit, numqubits, id_only) is True
  292. assert is_scalar_sparse_matrix(hh_circuit, numqubits, id_only) is True
  293. def test_is_degenerate():
  294. (x, y, z, h) = create_gate_sequence()
  295. gate_id = GateIdentity(x, y, z)
  296. ids = {gate_id}
  297. another_id = (z, y, x)
  298. assert is_degenerate(ids, another_id) is True
  299. def test_is_reducible():
  300. nqubits = 2
  301. (x, y, z, h) = create_gate_sequence()
  302. circuit = (x, y, y)
  303. assert is_reducible(circuit, nqubits, 1, 3) is True
  304. circuit = (x, y, x)
  305. assert is_reducible(circuit, nqubits, 1, 3) is False
  306. circuit = (x, y, y, x)
  307. assert is_reducible(circuit, nqubits, 0, 4) is True
  308. circuit = (x, y, y, x)
  309. assert is_reducible(circuit, nqubits, 1, 3) is True
  310. circuit = (x, y, z, y, y)
  311. assert is_reducible(circuit, nqubits, 1, 5) is True
  312. def test_bfs_identity_search():
  313. assert bfs_identity_search([], 1) == set()
  314. (x, y, z, h) = create_gate_sequence()
  315. gate_list = [x]
  316. id_set = {GateIdentity(x, x)}
  317. assert bfs_identity_search(gate_list, 1, max_depth=2) == id_set
  318. # Set should not contain degenerate quantum circuits
  319. gate_list = [x, y, z]
  320. id_set = {GateIdentity(x, x),
  321. GateIdentity(y, y),
  322. GateIdentity(z, z),
  323. GateIdentity(x, y, z)}
  324. assert bfs_identity_search(gate_list, 1) == id_set
  325. id_set = {GateIdentity(x, x),
  326. GateIdentity(y, y),
  327. GateIdentity(z, z),
  328. GateIdentity(x, y, z),
  329. GateIdentity(x, y, x, y),
  330. GateIdentity(x, z, x, z),
  331. GateIdentity(y, z, y, z)}
  332. assert bfs_identity_search(gate_list, 1, max_depth=4) == id_set
  333. assert bfs_identity_search(gate_list, 1, max_depth=5) == id_set
  334. gate_list = [x, y, z, h]
  335. id_set = {GateIdentity(x, x),
  336. GateIdentity(y, y),
  337. GateIdentity(z, z),
  338. GateIdentity(h, h),
  339. GateIdentity(x, y, z),
  340. GateIdentity(x, y, x, y),
  341. GateIdentity(x, z, x, z),
  342. GateIdentity(x, h, z, h),
  343. GateIdentity(y, z, y, z),
  344. GateIdentity(y, h, y, h)}
  345. assert bfs_identity_search(gate_list, 1) == id_set
  346. id_set = {GateIdentity(x, x),
  347. GateIdentity(y, y),
  348. GateIdentity(z, z),
  349. GateIdentity(h, h)}
  350. assert id_set == bfs_identity_search(gate_list, 1, max_depth=3,
  351. identity_only=True)
  352. id_set = {GateIdentity(x, x),
  353. GateIdentity(y, y),
  354. GateIdentity(z, z),
  355. GateIdentity(h, h),
  356. GateIdentity(x, y, z),
  357. GateIdentity(x, y, x, y),
  358. GateIdentity(x, z, x, z),
  359. GateIdentity(x, h, z, h),
  360. GateIdentity(y, z, y, z),
  361. GateIdentity(y, h, y, h),
  362. GateIdentity(x, y, h, x, h),
  363. GateIdentity(x, z, h, y, h),
  364. GateIdentity(y, z, h, z, h)}
  365. assert bfs_identity_search(gate_list, 1, max_depth=5) == id_set
  366. id_set = {GateIdentity(x, x),
  367. GateIdentity(y, y),
  368. GateIdentity(z, z),
  369. GateIdentity(h, h),
  370. GateIdentity(x, h, z, h)}
  371. assert id_set == bfs_identity_search(gate_list, 1, max_depth=4,
  372. identity_only=True)
  373. cnot = CNOT(1, 0)
  374. gate_list = [x, cnot]
  375. id_set = {GateIdentity(x, x),
  376. GateIdentity(cnot, cnot),
  377. GateIdentity(x, cnot, x, cnot)}
  378. assert bfs_identity_search(gate_list, 2, max_depth=4) == id_set
  379. cgate_x = CGate((1,), x)
  380. gate_list = [x, cgate_x]
  381. id_set = {GateIdentity(x, x),
  382. GateIdentity(cgate_x, cgate_x),
  383. GateIdentity(x, cgate_x, x, cgate_x)}
  384. assert bfs_identity_search(gate_list, 2, max_depth=4) == id_set
  385. cgate_z = CGate((0,), Z(1))
  386. gate_list = [cnot, cgate_z, h]
  387. id_set = {GateIdentity(h, h),
  388. GateIdentity(cgate_z, cgate_z),
  389. GateIdentity(cnot, cnot),
  390. GateIdentity(cnot, h, cgate_z, h)}
  391. assert bfs_identity_search(gate_list, 2, max_depth=4) == id_set
  392. s = PhaseGate(0)
  393. t = TGate(0)
  394. gate_list = [s, t]
  395. id_set = {GateIdentity(s, s, s, s)}
  396. assert bfs_identity_search(gate_list, 1, max_depth=4) == id_set
  397. def test_bfs_identity_search_xfail():
  398. s = PhaseGate(0)
  399. t = TGate(0)
  400. gate_list = [Dagger(s), t]
  401. id_set = {GateIdentity(Dagger(s), t, t)}
  402. assert bfs_identity_search(gate_list, 1, max_depth=3) == id_set