mod.rs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. use gate::Gate;
  2. use traits::Backend;
  3. use failure::Error;
  4. use num_complex::{Complex, Complex32};
  5. use ocl::{Buffer, MemFlags, ProQue};
  6. use rand::random;
  7. use std::fmt;
  8. // OpenCL Kernel
  9. pub static KERNEL: &'static str = include_str!("kernel.cl");
  10. #[derive(Debug)]
  11. pub struct OpenCL {
  12. /// OpenCL Buffer for the state vector
  13. pub buffer: Buffer<Complex<f32>>,
  14. pro_que: ProQue,
  15. num_qubits: u8,
  16. }
  17. impl OpenCL {
  18. /// Initialize a new OpenCL Backend
  19. ///
  20. /// Takes an argument of the number of qubits to use
  21. /// in the register, and returns a result with the backend.
  22. pub fn new(num_qubits: u8) -> Result<OpenCL, Error> {
  23. // How many amplitudes needed?
  24. let num_amps = 2_usize.pow(u32::from(num_qubits)) as usize;
  25. let ocl_pq = ProQue::builder()
  26. .src(KERNEL)
  27. .device(1)
  28. .dims(num_amps)
  29. .build()?;
  30. let buffer: Buffer<Complex32> = Buffer::builder()
  31. .queue(ocl_pq.queue().clone())
  32. .flags(MemFlags::new().read_write())
  33. .len(num_amps)
  34. .build()?;
  35. let apply = ocl_pq
  36. .kernel_builder("initialize_register")
  37. .arg(&buffer)
  38. .arg(0)
  39. .build()?;
  40. unsafe {
  41. apply.enq()?;
  42. }
  43. Ok(OpenCL {
  44. pro_que: ocl_pq,
  45. buffer,
  46. num_qubits,
  47. })
  48. }
  49. /// Note that this method doesn't mutate the state, thus
  50. /// a new vector must be created, which means you will have to have
  51. /// enough memory to store another object half the size of the
  52. /// state vector
  53. ///
  54. /// **This methods is very likely to change!**
  55. fn get_probabilities(&self) -> Result<Vec<f32>, Error> {
  56. let result_buffer: Buffer<f32> = self.pro_que.create_buffer()?;
  57. let apply = self
  58. .pro_que
  59. .kernel_builder("calculate_probabilities")
  60. .arg(&self.buffer)
  61. .arg(&result_buffer)
  62. .build()?;
  63. unsafe {
  64. apply.enq()?;
  65. }
  66. let mut vec_result = vec![0.0f32; self.buffer.len()];
  67. result_buffer.read(&mut vec_result).enq()?;
  68. Ok(vec_result)
  69. }
  70. }
  71. impl Backend for OpenCL {
  72. fn apply_gate(&mut self, gate: Gate, target: u8) -> Result<(), Error> {
  73. let apply = self
  74. .pro_que
  75. .kernel_builder("apply_gate")
  76. .global_work_size(&self.buffer.len() / 2)
  77. .arg(&self.buffer)
  78. .arg(i32::from(target))
  79. .arg(gate.a)
  80. .arg(gate.b)
  81. .arg(gate.c)
  82. .arg(gate.d)
  83. .build()?;
  84. unsafe {
  85. apply.enq()?;
  86. }
  87. Ok(())
  88. }
  89. fn apply_controlled_gate(&mut self, gate: Gate, control: u8, target: u8) -> Result<(), Error> {
  90. let apply = self
  91. .pro_que
  92. .kernel_builder("apply_controlled_gate")
  93. .global_work_size(&self.buffer.len() / 2)
  94. .arg(&self.buffer)
  95. .arg(i32::from(control))
  96. .arg(i32::from(target))
  97. .arg(gate.a)
  98. .arg(gate.b)
  99. .arg(gate.c)
  100. .arg(gate.d)
  101. .build()?;
  102. unsafe {
  103. apply.enq()?;
  104. }
  105. Ok(())
  106. }
  107. /// Measure the whole register, leaving the register in
  108. /// the measured state
  109. ///
  110. /// Note: Currently this leaves the register in the unmeasured state.
  111. fn measure(&mut self) -> Result<u64, Error> {
  112. let probabilities = self.get_probabilities()?;
  113. // A key must be generated on the host, as most
  114. // external accelerators do not have in built support
  115. // for random number generation
  116. let mut key = random::<f32>();
  117. if key > 1.0 {
  118. key %= 1.0;
  119. }
  120. let mut i = 0;
  121. while i < probabilities.len() {
  122. key -= probabilities[i];
  123. if key <= 0.0 {
  124. break;
  125. }
  126. i += 1;
  127. }
  128. Ok(i as u64)
  129. }
  130. /// Measure the value of a single qubit, leaving the register in
  131. /// the state where only that qubit (or any entangled qubits) have
  132. /// been collapsed
  133. fn measure_qubit(&mut self, _target: u8) -> Result<u64, Error> {
  134. unimplemented!()
  135. }
  136. /// Get the number of qubits that this backend was initialized for
  137. fn num_qubits(&self) -> u8 {
  138. self.num_qubits
  139. }
  140. }
  141. impl fmt::Display for OpenCL {
  142. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  143. let mut first = true;
  144. let mut vec_result = vec![Complex32::new(0.0, 0.0); self.buffer.len()];
  145. self.buffer
  146. .read(&mut vec_result)
  147. .enq()
  148. .expect("Error Reading Memory From Device");
  149. for (idx, item) in vec_result.iter().enumerate() {
  150. if !first {
  151. write!(f, ", ")?;
  152. } else {
  153. first = false;
  154. }
  155. write!(f, "[{}]: ", idx)?;
  156. // Do we print the imaginary part?
  157. if item.im == 0.0 {
  158. write!(f, "{}", item.re)?;
  159. } else if item.re == 0.0 {
  160. write!(f, "{}i", item.im)?;
  161. } else {
  162. write!(f, "{}", item)?;
  163. }
  164. }
  165. Ok(())
  166. }
  167. }