backend.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import os
  2. import pyopencl as cl
  3. import pyopencl.array as pycl_array
  4. import numpy as np
  5. # Get the OpenCL kernel
  6. kernel_path = os.path.join(
  7. os.path.dirname(__file__),
  8. "kernels/brute-force.cl"
  9. )
  10. kernel = open(kernel_path, "r").read()
  11. class Backend:
  12. """
  13. A class for the OpenCL backend to the simulator.
  14. This class shouldn't be used directly, as many of the
  15. methods don't have the same input checking as the State
  16. class.
  17. """
  18. def __init__(self, num_qubits, dtype=np.complex64):
  19. """
  20. Initialize a new OpenCL Backend
  21. Takes an argument of the number of qubits to use
  22. in the register, and returns the backend.
  23. """
  24. self.num_qubits = num_qubits
  25. self.dtype = dtype
  26. # Setup the opencl context, queue and program
  27. self.context = cl.create_some_context()
  28. self.queue = cl.CommandQueue(self.context)
  29. self.program = cl.Program(self.context, kernel).build()
  30. # Buffer for the state vector
  31. self.buffer = pycl_array.to_device(
  32. self.queue,
  33. np.eye(2**num_qubits, 1, dtype=dtype)
  34. )
  35. def apply_gate(self, gate, target):
  36. """Applies a gate to the quantum register"""
  37. kernel = self.program.apply_gate
  38. kernel.set_scalar_arg_dtypes([
  39. None,
  40. np.int32,
  41. self.dtype,
  42. self.dtype,
  43. self.dtype,
  44. self.dtype,
  45. ])
  46. kernel(
  47. self.queue,
  48. [self.buffer.shape[0] / 2],
  49. None,
  50. self.buffer.data,
  51. np.int32(target),
  52. gate.a,
  53. gate.b,
  54. gate.c,
  55. gate.d
  56. )
  57. def apply_controlled_gate(self, gate, control, target):
  58. """Applies a controlled gate to the quantum register"""
  59. kernel = self.program.apply_controlled_gate
  60. kernel.set_scalar_arg_dtypes([
  61. None,
  62. np.int32,
  63. np.int32,
  64. self.dtype,
  65. self.dtype,
  66. self.dtype,
  67. self.dtype,
  68. ])
  69. kernel(
  70. self.queue,
  71. [self.buffer.shape[0] / 2],
  72. None,
  73. self.buffer.data,
  74. np.int32(control),
  75. np.int32(target),
  76. gate.a,
  77. gate.b,
  78. gate.c,
  79. gate.d
  80. )
  81. def amplitudes(self):
  82. """Gets the probability amplitudes"""
  83. return self.buffer.get()
  84. def probabilities(self):
  85. """Gets the squared absolute value of each of the amplitudes"""
  86. out = pycl_array.to_device(
  87. self.queue,
  88. np.zeros(2**self.num_qubits, dtype=np.float32)
  89. )
  90. self.program.calculate_probabilities(
  91. self.queue,
  92. self.buffer.shape,
  93. None,
  94. self.buffer.data,
  95. out.data
  96. )
  97. return out.get()