123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- typedef float2 complex_f;
- /*
- * Addition of two complex numbers:
- *
- * a + b = (Re(a) + Re(b)) + i(Im(a) + Im(b))
- */
- static complex_f add(complex_f a, complex_f b)
- {
- return (complex_f)(a.x + b.x, a.y + b.y);
- }
- /*
- * Negation of a complex numbers:
- *
- * -a = -(Re(a) - i(Im(a))
- */
- static complex_f neg(complex_f a)
- {
- return (complex_f)(-a.x, -a.y);
- }
- /*
- * Multiplication of two complex numbers:
- *
- * a * b =
- * ((Re(a) * Re(b)) - (Im(a) * Im(b)))
- * + ((Im(a) * Re(b)) + (Re(a) * Im(b)))i
- */
- static complex_f mul(complex_f a, complex_f b)
- {
- return (complex_f)(
- (a.x * b.x) - (a.y * b.y),
- (a.y * b.x) + (a.x * b.y));
- }
- /**
- * Absolute value of a complex number
- *
- * |a| = √(Re(a)^2 + Im(a)^2)
- */
- static float complex_abs(complex_f a)
- {
- return sqrt((a.x * a.x) + (a.y * a.y));
- }
- static complex_f cexp(float a) {
- return (complex_f)(cos(a), sin(a));
- }
- /*
- * Returns the nth number where a given digit
- * is cleared in the binary representation of the number
- */
- static uint nth_cleared(uint n, uint target)
- {
- uint mask = (1 << target) - 1;
- uint not_mask = ~mask;
- return (n & mask) | ((n & not_mask) << 1);
- }
- ///////////////////////////////////////////////
- // KERNELS
- ///////////////////////////////////////////////
- /*
- * Applies a single qubit gate to the register.
- * The gate matrix must be given in the form:
- *
- * A B
- * C D
- */
- __kernel void apply_gate(
- __global complex_f *amplitudes,
- uint target,
- complex_f A,
- complex_f B,
- complex_f C,
- complex_f D)
- {
- uint const global_id = get_global_id(0);
- uint const zero_state = nth_cleared(global_id, target);
- // uint const zero_state = state & (~(1 << target)); // Could just be state
- uint const one_state = zero_state | (1 << target);
- complex_f const zero_amp = amplitudes[zero_state];
- complex_f const one_amp = amplitudes[one_state];
- amplitudes[zero_state] = add(mul(A, zero_amp), mul(B, one_amp));
- amplitudes[one_state] = add(mul(D, one_amp), mul(C, zero_amp));
- }
- /*
- * Applies a controlled single qubit gate to the register.
- */
- __kernel void apply_controlled_gate(
- __global complex_f *amplitudes,
- uint control,
- uint target,
- complex_f A,
- complex_f B,
- complex_f C,
- complex_f D)
- {
- uint const global_id = get_global_id(0);
- uint const zero_state = nth_cleared(global_id, target);
- uint const one_state = zero_state | (1 << target); // Set the target bit
- uint const control_val_zero = (((1 << control) & zero_state) > 0) ? 1 : 0;
- uint const control_val_one = (((1 << control) & one_state) > 0) ? 1 : 0;
- complex_f const zero_amp = amplitudes[zero_state];
- complex_f const one_amp = amplitudes[one_state];
- if (control_val_zero == 1)
- {
- amplitudes[zero_state] = add(mul(A, zero_amp), mul(B, one_amp));
- }
- if (control_val_one == 1)
- {
- amplitudes[one_state] = add(mul(D, one_amp), mul(C, zero_amp));
- }
- }
- /*
- * Applies a controlled-controlled single qubit gate to the register.
- * NOT MIGRATED
- */
- __kernel void apply_controlled_controlled_gate(
- __global complex_f *const amplitudes,
- __global complex_f *amps,
- uint control1,
- uint control2,
- uint target,
- complex_f A,
- complex_f B,
- complex_f C,
- complex_f D)
- {
- uint const state = get_global_id(0);
- complex_f const amp = amplitudes[state];
- uint const zero_state = state & (~(1 << target));
- uint const one_state = state | (1 << target);
- uint const bit_val = (((1 << target) & state) > 0) ? 1 : 0;
- uint const control1_val = (((1 << control1) & state) > 0) ? 1 : 0;
- uint const control2_val = (((1 << control2) & state) > 0) ? 1 : 0;
- if (control1_val == 0 || control2_val == 0)
- {
- // Control is 0, don't apply gate
- amps[state] = amp;
- }
- else
- {
- // control is 1, apply gate.
- if (bit_val == 0)
- {
- // Bitval = 0
- amps[state] = add(mul(A, amp), mul(B, amplitudes[one_state]));
- }
- else
- {
- amps[state] = add(mul(D, amp), mul(C, amplitudes[zero_state]));
- }
- }
- }
- /*
- * Swaps the states of two qubits in the register
- * NOT MIGRATED
- */
- __kernel void swap(
- __global complex_f *const amplitudes,
- __global complex_f *amps,
- uint first_qubit,
- uint second_qubit)
- {
- uint const state = get_global_id(0);
- uint const first_bit_mask = 1 << first_qubit;
- uint const second_bit_mask = 1 << second_qubit;
- uint const new_second_bit = ((state & first_bit_mask) >> first_qubit) << second_qubit;
- uint const new_first_bit = ((state & second_bit_mask) >> second_qubit) << first_qubit;
- uint const new_state = (state & !first_bit_mask & !second_bit_mask) | new_first_bit | new_second_bit;
- amps[new_state] = amplitudes[state];
- }
- /**
- * Calculates The Probabilities Of A State Vector
- */
- __kernel void calculate_probabilities(
- __global complex_f *const amplitudes,
- __global float *probabilities)
- {
- uint const state = get_global_id(0);
- complex_f amp = amplitudes[state];
- probabilities[state] = complex_abs(mul(amp, amp));
- }
- /**
- * Initializes a register to the value 1|0..100...0>
- * ^ target
- */
- __kernel void initialize_register(
- __global complex_f *amplitudes,
- uint const target)
- {
- uint const state = get_global_id(0);
- if (state == target)
- {
- amplitudes[state] = (complex_f)(1, 0);
- }
- else
- {
- amplitudes[state] = (complex_f)(0, 0);
- }
- }
|