summaryrefslogtreecommitdiffstats
path: root/ml/dlib/examples/quantum_computing_ex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ml/dlib/examples/quantum_computing_ex.cpp')
-rw-r--r--ml/dlib/examples/quantum_computing_ex.cpp337
1 files changed, 337 insertions, 0 deletions
diff --git a/ml/dlib/examples/quantum_computing_ex.cpp b/ml/dlib/examples/quantum_computing_ex.cpp
new file mode 100644
index 000000000..fcc7c845f
--- /dev/null
+++ b/ml/dlib/examples/quantum_computing_ex.cpp
@@ -0,0 +1,337 @@
+// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
+/*
+ This is an example illustrating the use of the quantum computing
+ simulation classes from the dlib C++ Library.
+
+ This example assumes you are familiar with quantum computing and
+ Grover's search algorithm and Shor's 9 bit error correcting code
+ in particular. The example shows how to simulate both of these
+ algorithms.
+
+
+ The code to simulate Grover's algorithm is primarily here to show
+ you how to make custom quantum gate objects. The Shor ECC example
+ is simpler and uses just the default gates that come with the
+ library.
+
+*/
+
+
+#include <iostream>
+#include <complex>
+#include <ctime>
+#include <dlib/quantum_computing.h>
+#include <dlib/string.h>
+
+
+using namespace std;
+using namespace dlib;
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+// This declares a random number generator that we will be using below
+dlib::rand rnd;
+
+// ----------------------------------------------------------------------------------------
+
+void shor_encode (
+ quantum_register& reg
+)
+/*!
+ requires
+ - reg.num_bits() == 1
+ ensures
+ - #reg.num_bits() == 9
+ - #reg == the Shor error coding of the input register
+!*/
+{
+ DLIB_CASSERT(reg.num_bits() == 1,"");
+
+ quantum_register zeros;
+ zeros.set_num_bits(8);
+ reg.append(zeros);
+
+ using namespace dlib::quantum_gates;
+ const gate<1> h = hadamard();
+ const gate<1> i = noop();
+
+ // Note that the expression (h,i) represents the tensor product of the 1 qubit
+ // h gate with the 1 qubit i gate and larger versions of this expression
+ // represent even bigger tensor products. So as you see below, we make gates
+ // big enough to apply to our quantum register by listing out all the gates we
+ // want to go into the tensor product and then we just apply the resulting gate
+ // to the quantum register.
+
+ // Now apply the gates that constitute Shor's encoding to the input register.
+ (cnot<3,0>(),i,i,i,i,i).apply_gate_to(reg);
+ (cnot<6,0>(),i,i).apply_gate_to(reg);
+ (h,i,i,h,i,i,h,i,i).apply_gate_to(reg);
+ (cnot<1,0>(),i,cnot<1,0>(),i,cnot<1,0>(),i).apply_gate_to(reg);
+ (cnot<2,0>(),cnot<2,0>(),cnot<2,0>()).apply_gate_to(reg);
+}
+
+// ----------------------------------------------------------------------------------------
+
+void shor_decode (
+ quantum_register& reg
+)
+/*!
+ requires
+ - reg.num_bits() == 9
+ ensures
+ - #reg.num_bits() == 1
+ - #reg == the decoded qubit that was in the given input register
+!*/
+{
+ DLIB_CASSERT(reg.num_bits() == 9,"");
+
+ using namespace dlib::quantum_gates;
+ const gate<1> h = hadamard();
+ const gate<1> i = noop();
+
+ // Now apply the gates that constitute Shor's decoding to the input register
+
+ (cnot<2,0>(),cnot<2,0>(),cnot<2,0>()).apply_gate_to(reg);
+ (cnot<1,0>(),i,cnot<1,0>(),i,cnot<1,0>(),i).apply_gate_to(reg);
+
+ (toffoli<0,1,2>(),toffoli<0,1,2>(),toffoli<0,1,2>()).apply_gate_to(reg);
+
+ (h,i,i,h,i,i,h,i,i).apply_gate_to(reg);
+
+ (cnot<6,0>(),i,i).apply_gate_to(reg);
+ (cnot<3,0>(),i,i,i,i,i).apply_gate_to(reg);
+ (toffoli<0,3,6>(),i,i).apply_gate_to(reg);
+
+ // Now that we have decoded the value we don't need the extra 8 bits any more so
+ // remove them from the register.
+ for (int i = 0; i < 8; ++i)
+ reg.measure_and_remove_bit(0,rnd);
+}
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+// This is the function we will use in Grover's search algorithm. In this
+// case the value we are searching for is 257.
+bool is_key (unsigned long n)
+{
+ return n == 257;
+}
+
+// ----------------------------------------------------------------------------------------
+
+template <int bits>
+class uf_gate;
+
+namespace dlib {
+template <int bits>
+struct gate_traits<uf_gate<bits> >
+{
+ static const long num_bits = bits;
+ static const long dims = dlib::qc_helpers::exp_2_n<num_bits>::value;
+};}
+
+template <int bits>
+class uf_gate : public gate_exp<uf_gate<bits> >
+{
+ /*!
+ This gate represents the black box function in Grover's search algorithm.
+ That is, it is the gate defined as follows:
+ Uf|x>|y> = |x>|y XOR is_key(x)>
+
+ See the documentation for the gate_exp object for the details regarding
+ the compute_state_element() and operator() functions defined below.
+ !*/
+public:
+ uf_gate() : gate_exp<uf_gate>(*this) {}
+
+ static const long num_bits = gate_traits<uf_gate>::num_bits;
+ static const long dims = gate_traits<uf_gate>::dims;
+
+ const qc_scalar_type operator() (long r, long c) const
+ {
+ unsigned long output = c;
+ // if the input control bit is set
+ if (is_key(output>>1))
+ {
+ output = output^0x1;
+ }
+
+ if ((unsigned long)r == output)
+ return 1;
+ else
+ return 0;
+ }
+
+ template <typename exp>
+ qc_scalar_type compute_state_element (
+ const matrix_exp<exp>& reg,
+ long row_idx
+ ) const
+ {
+ unsigned long output = row_idx;
+ // if the input control bit is set
+ if (is_key(output>>1))
+ {
+ output = output^0x1;
+ }
+
+ return reg(output);
+ }
+};
+
+// ----------------------------------------------------------------------------------------
+
+template <int bits>
+class w_gate;
+
+namespace dlib {
+template <int bits>
+struct gate_traits<w_gate<bits> >
+{
+ static const long num_bits = bits;
+ static const long dims = dlib::qc_helpers::exp_2_n<num_bits>::value;
+}; }
+
+template <int bits>
+class w_gate : public gate_exp<w_gate<bits> >
+{
+ /*!
+ This is the W gate from the Grover algorithm
+ !*/
+public:
+
+ w_gate() : gate_exp<w_gate>(*this) {}
+
+ static const long num_bits = gate_traits<w_gate>::num_bits;
+ static const long dims = gate_traits<w_gate>::dims;
+
+ const qc_scalar_type operator() (long r, long c) const
+ {
+ qc_scalar_type res = 2.0/dims;
+ if (r != c)
+ return res;
+ else
+ return res - 1.0;
+ }
+
+ template <typename exp>
+ qc_scalar_type compute_state_element (
+ const matrix_exp<exp>& reg,
+ long row_idx
+ ) const
+ {
+ qc_scalar_type temp = sum(reg)*2.0/dims;
+ // compute this value: temp = temp - reg(row_idx)*2.0/dims + reg(row_idx)*(2.0/dims - 1.0)
+ temp = temp - reg(row_idx);
+
+ return temp;
+ }
+};
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+int main()
+{
+ // seed the random number generator
+ rnd.set_seed(cast_to_string(time(0)));
+
+ // Pick out some of the gates we will be using below
+ using namespace dlib::quantum_gates;
+ const gate<1> h = quantum_gates::hadamard();
+ const gate<1> z = quantum_gates::z();
+ const gate<1> x = quantum_gates::x();
+ const gate<1> i = quantum_gates::noop();
+
+ quantum_register reg;
+
+ // We will be doing the 12 qubit version of Grover's search algorithm.
+ const int bits=12;
+ reg.set_num_bits(bits);
+
+
+ // set the quantum register to its initial state
+ (i,i, i,i,i,i,i, i,i,i,i,x).apply_gate_to(reg);
+
+ // Print out the starting bits
+ cout << "starting bits: ";
+ for (int i = reg.num_bits()-1; i >= 0; --i)
+ cout << reg.probability_of_bit(i);
+ cout << endl;
+
+
+ // Now apply the Hadamard gate to all the input bits
+ (h,h, h,h,h,h,h, h,h,h,h,h).apply_gate_to(reg);
+
+ // Here we do the grover iteration
+ for (int j = 0; j < 35; ++j)
+ {
+ (uf_gate<bits>()).apply_gate_to(reg);
+ (w_gate<bits-1>(),i).apply_gate_to(reg);
+
+
+ cout << j << " probability: bit 1 = " << reg.probability_of_bit(1) << ", bit 9 = " << reg.probability_of_bit(9) << endl;
+ }
+
+ cout << endl;
+
+ // Print out the final probability of measuring a 1 for each of the bits
+ for (int i = reg.num_bits()-1; i >= 1; --i)
+ cout << "probability for bit " << i << " = " << reg.probability_of_bit(i) << endl;
+ cout << endl;
+
+ cout << "The value we want grover's search to find is 257 which means we should measure a bit pattern of 00100000001" << endl;
+ cout << "Measured bits: ";
+ // finally, measure all the bits and print out what they are.
+ for (int i = reg.num_bits()-1; i >= 1; --i)
+ cout << reg.measure_bit(i,rnd);
+ cout << endl;
+
+
+
+
+
+ // Now let's test out the Shor 9 bit encoding
+ cout << "\n\n\n\nNow let's try playing around with Shor's 9bit error correcting code" << endl;
+
+ // Reset the quantum register to contain a single bit
+ reg.set_num_bits(1);
+ // Set the state of this single qubit to some random mixture of the two computational bases
+ reg.state_vector()(0) = qc_scalar_type(rnd.get_random_double(),rnd.get_random_double());
+ reg.state_vector()(1) = qc_scalar_type(rnd.get_random_double(),rnd.get_random_double());
+ // Make sure the state of the quantum register is a unit vector
+ reg.state_vector() /= sqrt(sum(norm(reg.state_vector())));
+
+ cout << "state: " << trans(reg.state_vector());
+
+ shor_encode(reg);
+ cout << "x bit corruption on bit 8" << endl;
+ (x,i,i,i,i,i,i,i,i).apply_gate_to(reg); // mess up the high order bit
+ shor_decode(reg); // try to decode the register
+
+ cout << "state: " << trans(reg.state_vector());
+
+ shor_encode(reg);
+ cout << "x bit corruption on bit 1" << endl;
+ (i,i,i,i,i,i,i,x,i).apply_gate_to(reg);
+ shor_decode(reg);
+
+ cout << "state: " << trans(reg.state_vector());
+
+ shor_encode(reg);
+ cout << "z bit corruption on bit 8" << endl;
+ (z,i,i,i,i,i,i,i,i).apply_gate_to(reg);
+ shor_decode(reg);
+
+ cout << "state: " << trans(reg.state_vector());
+
+ cout << "\nThe state of the input qubit survived all the corruptions in tact so the code works." << endl;
+
+}
+
+