mirror of
https://github.com/davisking/dlib.git
synced 2024-11-01 10:14:53 +08:00
Adding a new example program.
--HG-- extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%402758
This commit is contained in:
parent
2eebb8d5c1
commit
e492187c08
@ -48,6 +48,7 @@ add_example(member_function_pointer_ex)
|
||||
add_example(mlp_ex)
|
||||
add_example(multithreaded_object_ex)
|
||||
add_example(pipe_ex)
|
||||
add_example(quantum_computing_ex)
|
||||
add_example(queue_ex)
|
||||
add_example(rank_features_ex)
|
||||
add_example(rvm_ex)
|
||||
|
313
examples/quantum_computing_ex.cpp
Normal file
313
examples/quantum_computing_ex.cpp
Normal file
@ -0,0 +1,313 @@
|
||||
/*
|
||||
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 "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::float_1a 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 : 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 = bits;
|
||||
static const long dims = dlib::qc_helpers::exp_2_n<num_bits>::value;
|
||||
|
||||
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 : 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 = bits;
|
||||
static const long dims = dlib::qc_helpers::exp_2_n<num_bits>::value;
|
||||
|
||||
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 lets test out the Shor 9 bit encoding
|
||||
cout << "\n\n\n\nNow lets 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;
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user