oreilly-qc / oreilly-qc.github.io

Code samples for Programming Quantum Computers, from O'Reilly Media
130 stars 59 forks source link

Fancier teleportation code #50

Open rgobbel opened 1 year ago

rgobbel commented 1 year ago

This code is a bit messy, and I don't have time to do a proper cleanup on it, so I'm submitting it here in the hopes that someone can get some use out of it. I found the results of the sample code for Example 1-4 confusing, so I added some more code to make the output easier to understand. The Javascript version uses functions that might not be available in the context of a real quantum computer, so beware.

First the Javascript:

// Programming Quantum Computers
//   by Eric Johnston, Nic Harrigan and Mercedes Gimeno-Segovia
//   O'Reilly Media

// To run this online, go to http://oreilly-qc.github.io?p=4-1

// This sample demonstrates basic teleportation.

qc.reset(5);
qc.clearOutput();

function random_bit() {
    if (Math.random() < 0.5)
        return 0;
    else
        return 1;
}

var inPhase = 45

function random_phase() {
    if (Math.random() < 0.5)
        return inPhase;
    else
        return -inPhase;
}

function gen_payload()
{
    qc.label('gen payload');
    result = random_bit();
    qc.label('');
    qc.nop();
    return result;
}

var check = qint.new(1, 'check');
var signal = qint.new(1, 'signal');
var alice = qint.new(1, 'alice');
var ep    = qint.new(1, 'ep');
var bob   = qint.new(1, 'bob');
//var alice_out = 0;
//var ep_out = 0;
var b_in = 0;
var rphase = random_phase();

var payload = gen_payload();
signal.write(payload);
qc.print('payload='+payload+'\n');

// This will work with entangle() and alice_prep() in either order.
// Try swapping them to verify this.
entangle();
alice_prep(payload);
var [alice_out, ep_out] = alice_send();
//alice_out = outs[0];
//ep_out = outs[1];
qc.print('after send, a='+alice_out+', e='+ep_out+'\n');
bob_receive(alice_out, ep_out);
bob_verify(payload);

function entangle()
{
    // First, create an entangled pair
    qc.label('entangle');
    qc.write(0, ep.bits()|bob.bits());
    ep.had();
    bob.cnot(ep);
    qc.label('');
    qc.nop();
}

function alice_prep(pl)
{
    // Alice prepares her payload to teleport
    qc.label('prep payload');
    alice.write(pl);
    alice.had();
    qc.print('rphase='+rphase+'\n');
    alice.phase(rphase);
    alice.had();
    qc.print('ppa:'+alice.peekProbability().toFixed(2)+'\n');
    qc.label('');
    qc.nop();
}

function alice_send()
{
    // Alice sends the payload (and destroys it in the process)
    qc.label('send');
    ep.cnot(alice);
    alice.had();
    a_out = alice.read();
    e_out = ep.read();
    qc.print('in send, a='+a_out+', e='+e_out+'\n');
    qc.label('');
    qc.nop();
    return [a_out, e_out];
}

function bob_receive(a_val, ep_val)
{
    // Bob receives the payload, using the two bits Alice sent
    qc.label('receive');
    var bob_is_asleep = false;
    var use_conditonal_gates = true;

    // Option 1: Bob is asleep (can't respond to Alice's data), so he just does whatever.
    if (bob_is_asleep)
    {
        bob.not();
        bob.phase(180);
    }
    // // Option 2: Bob is responsive, and we use conditional-ops for visual clarity
    else if (use_conditonal_gates)
    {
        // Here, we use conditional gates, just for visual clarity.
        // The "conditions" are on qubits which have already been read and
        // turned into classical bits.
        bob.cnot(ep);
        bob.cz(alice);
    }
    // Option 3: Bob is responsive, and we use straightforward "if" in the code.
    else
    {
        if (ep_val)
            bob.not();
        if (a_val)
            bob.phase(180);
    }
    qc.print('ppb:'+bob.peekProbability().toFixed(2)+'\n');
    qc.label('');
    qc.nop();
}

function bob_verify(payload)
{
    // Verify that the teleportation worked
    qc.label('verify');
    bob.had();
    bob.phase(-rphase);
    bob.had();
    check.write(0);
    check.had();
    bob.exchange(signal, 0x1, check.bits());
    // bob.exchange(signal, 0x1);
    check.had();
    check.not();
    check_ok = check.read();
    //result = bob.read();
    // if (result == payload)
    if (check_ok == 1)
        qc.print('MATCH: ');
    else
        qc.print('MISMATCH: ');
    // qc.print('payload = '+payload+', result = '+result+', a_out = '+a_out+', e_out = '+e_out+' -> ('+check_ok+''+e_out+''+a_out+''+result+')\n');
    qc.print('a_out = '+a_out+', e_out = '+e_out+' -> ('+check_ok+''+e_out+''+a_out+')\n');
    qc.label('');
    qc.nop();
}

then the OpenQASM:

// Programming Quantum Computers
//   by Eric Johnston, Nic Harrigan and Mercedes Gimeno-Segovia
//   O'Reilly Media

// To run this on an actual quantum computer,
//    1. go to https://quantum-computing.ibm.com
//    2. Click "Switch to Qasm Editor" and paste in the code sample.

// To run the JS version in a browser, go to http://oreilly-qc.github.io?p=4-1

// This sample demonstrates basic teleportation (postselected).

include "qelib1.inc";
qreg check[1];
qreg signal[1]; // for checking: this register must match alice
qreg alice[1];
qreg ep[1];
qreg bob[1];
creg read_send[4];
creg results[1];

// Step 1: Create an entangled pair
h ep[0];
reset check[0];
cx ep[0], bob[0];
barrier check[0], signal[0], alice[0], ep[0], bob[0];

// Step 2: Prepare a payload
reset alice[0];
reset signal[0];
x alice[0];
x signal[0];
h alice[0];
t alice[0];
h alice[0];
barrier check[0], signal[0], alice[0], ep[0], bob[0];

// Step 3: Send
cx alice[0], ep[0];
h alice[0];
measure ep[0] -> read_send[1];
measure alice[0] -> read_send[0];
barrier alice[0], ep[0], bob[0];

// Step 4: Receive
cx ep[0], bob[0];
cz alice[0], bob[0];
barrier alice[0], ep[0], bob[0];

// Step 5: Verify
// correct results will have a 1 in the top bit,
// with the next two bits having the same value
h bob[0];
tdg bob[0];
h bob[0];
barrier check[0], signal[0], bob[0];
h check[0];
cswap check[0], signal[0], bob[0];
h check[0];
x check[0];
measure check[0] -> results[0];
barrier check[0], signal[0], bob[0];

// these two are optional, just for information, could be omitted
measure signal[0] -> read_send[2];
measure bob[0] -> read_send[3];
machinelevel commented 2 weeks ago

Thank you!