Anders and Briegel in Python
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

147 lignes
4.7KB

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. """
  4. Exposes a few basic QI operators
  5. And a circuit-model simulator
  6. """
  7. import numpy as np
  8. import itertools as it
  9. from fractions import Fraction
  10. def hermitian_conjugate(u):
  11. """ Shortcut to the Hermitian conjugate """
  12. return np.conjugate(np.transpose(u))
  13. # Constants
  14. ir2 = 1 / np.sqrt(2)
  15. # Operators
  16. id = np.array(np.eye(2, dtype=complex))
  17. px = np.array([[0, 1], [1, 0]], dtype=complex)
  18. py = np.array([[0, -1j], [1j, 0]], dtype=complex)
  19. pz = np.array([[1, 0], [0, -1]], dtype=complex)
  20. ha = hadamard = np.array([[1, 1], [1, -1]], dtype=complex) * ir2
  21. ph = np.array([[1, 0], [0, 1j]], dtype=complex)
  22. t = np.array([[1, 0], [0, np.exp(1j * np.pi / 4)]], dtype=complex)
  23. sqx = np.array(
  24. [[1. + 0.j, -0. + 1.j], [-0. + 1.j, 1. - 0.j]], dtype=complex) * ir2
  25. msqx = np.array(
  26. [[1. + 0.j, 0. - 1.j], [0. - 1.j, 1. - 0.j]], dtype=complex) * ir2
  27. sqy = np.array(
  28. [[1. + 0.j, 1. + 0.j], [-1. - 0.j, 1. - 0.j]], dtype=complex) * ir2
  29. msqy = np.array(
  30. [[1. + 0.j, -1. - 0.j], [1. + 0.j, 1. - 0.j]], dtype=complex) * ir2
  31. sqz = np.array(
  32. [[1. + 1.j, 0. + 0.j], [0. + 0.j, 1. - 1.j]], dtype=complex) * ir2
  33. msqz = np.array(
  34. [[1. - 1.j, 0. + 0.j], [0. + 0.j, 1. + 1.j]], dtype=complex) * ir2
  35. # CZ gate
  36. cz = np.array(np.eye(4), dtype=complex)
  37. cz[3, 3] = -1
  38. # States
  39. zero = np.array([[1], [0]], dtype=complex)
  40. one = np.array([[0], [1]], dtype=complex)
  41. plus = np.array([[1], [1]], dtype=complex) / np.sqrt(2)
  42. bond = cz.dot(np.kron(plus, plus))
  43. nobond = np.kron(plus, plus)
  44. # Labelling stuff
  45. common_us = id, px, py, pz, ha, ph, sqz, msqz, sqy, msqy, sqx, msqx
  46. names = "identity", "px", "py", "pz", "hadamard", "phase", "sqz", "msqz", "sqy", "msqy", "sqx", "msqx"
  47. by_name = dict(list(zip(names, common_us)))
  48. paulis = px, py, pz
  49. operators = id, px, py, pz
  50. def normalize_global_phase(m):
  51. """ Normalize the global phase of a matrix """
  52. v = next((x for x in m.flatten() if np.abs(x) > 0.001))
  53. phase = np.arctan2(v.imag, v.real) % np.pi
  54. rot = np.exp(-1j * phase)
  55. return rot * m if rot * v > 0 else -rot * m
  56. class CircuitModel(object):
  57. def __init__(self, nqubits):
  58. self.nqubits = nqubits
  59. self.d = 2 ** nqubits
  60. self.state = np.zeros((self.d, 1), dtype=complex)
  61. self.state[0, 0] = 1
  62. def act_cz(self, control, target):
  63. """ Act a CU somewhere. """
  64. control = 1 << control
  65. target = 1 << target
  66. for i in range(self.d):
  67. if (i & control) and (i & target):
  68. self.state[i, 0] *= -1
  69. def act_cnot(self, control, target):
  70. """ Act a CNOT. """
  71. self.act_hadamard(target)
  72. self.act_cz(control, target)
  73. self.act_hadamard(target)
  74. def act_hadamard(self, qubit):
  75. """ Act a hadamard somewhere. """
  76. where = 1 << qubit
  77. output = np.zeros((self.d, 1), dtype=complex)
  78. for i, v in enumerate(self.state):
  79. q = int(i & where > 0)
  80. output[i] += v * ha[q, q]
  81. output[i ^ where] += v * ha[int(not q), q]
  82. self.state = output
  83. def act_local_rotation(self, qubit, u):
  84. """ Act a local unitary somwhere. """
  85. where = 1 << qubit
  86. output = np.zeros((self.d, 1), dtype=complex)
  87. for i, v in enumerate(self.state):
  88. q = int(i & where > 0)
  89. output[i] += v * u[q, q]
  90. output[i ^ where] += v * u[int(not q), q]
  91. self.state = output
  92. def act_circuit(self, circuit):
  93. """ Act a sequence of gates. """
  94. for node, operation in circuit:
  95. if operation == "cz":
  96. self.act_cz(*node)
  97. else:
  98. self.act_local_rotation(node, operation)
  99. def __eq__(self, other):
  100. """ Check whether two quantum states are the same or not,
  101. up to a global phase. """
  102. a = normalize_global_phase(self.state)
  103. b = normalize_global_phase(other.state)
  104. return np.allclose(a, b)
  105. def __setitem__(self, key, value):
  106. """ Set a matrix element """
  107. self.state[key] = value
  108. def __getitem__(self, key):
  109. """ Get a matrix element """
  110. return self.state[key]
  111. def __str__(self):
  112. s = ""
  113. for i in range(self.d):
  114. label = bin(i)[2:].rjust(self.nqubits, "0")[::-1]
  115. if abs(self.state[i, 0]) > 0.00001:
  116. term = self.state[i, 0]
  117. real_sign = " " if term.real>=0 else "-"
  118. real_frac = Fraction(str(term.real**2)).limit_denominator()
  119. imag_sign = "+" if term.imag>=0 else "-"
  120. imag_frac = Fraction(str(term.imag**2)).limit_denominator()
  121. s += "|{}❭: \t{}√{}\t{} i √{}\n".format(
  122. label, real_sign, real_frac, imag_sign, imag_frac)
  123. return s