Let's Make a Deal

The latest version of this notebook is available on https://github.com/qiskit/qiskit-tutorial.

For more information about how to use the IBM Q experience (QX), consult the tutorials, or check out the community.


Contributors

Pierre Decoodt, Université Libre de Bruxelles


In [1]:
# useful additional packages 
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import time
from pprint import pprint

# importing Qiskit
from qiskit import Aer, IBMQ
from qiskit.backends.ibmq import least_busy
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister, execute

# import basic plot tools
from qiskit.tools.visualization import plot_histogram

In [2]:
IBMQ.load_accounts()

Introduction

The Monty Hall problem, named after the original host of the television show "Let's Make a Deal" is well known. The game master asks the player to designate between three doors the one behind which a valuable prize has been hidden, such as a luxury car. Goats are hidden behind the other two doors. When the player has issued a preference, the game master opens one of the two remaining doors and one of the goats appears. The player then has the opportunity to choose the closed door remaining instead of the door chosen in first intention.

Is it wise, indifferent or unwise to stick with one's first choice, whatever it may have been? Much has been written on about the optimal strategy because the actual solution is counter-intuitive.

This tutorial is not intended to illustrate one of the many quantum models proposed on this subject and including many variations. It simply describes a model of the original game that can be played many times by players to convince them of the validity of the optimal strategic solution. This kind of simulation was proposed using conventional hardware, like a shell game, a card deck or a programmed pseudo random number generator.

The present game uses the $ |W_{3} \rangle$ creator circuit described in the tutorial "W State 1 : Multi-qubit systems" as a true$^1$ random number generator.

The following state is created and measured: $ |W_{3} \rangle = \frac{1}{\sqrt{3}} \: (|1 0 0 \rangle \: + |0 1 0 \rangle\: + |0 0 1\rangle) $

Each of the three qubits used represents one of the doors. The car is hidden behind the one corresponding to the qubit measured as 1 (excited) during the measurement.

With the help of Hadamard gates, a second true random number generator uses the two-qubit state:

$$ H^{\otimes 2}|0_{a}0_{b}\rangle=|+_{a}\rangle \:|+_{b}\rangle=\frac{|0_{a}\rangle|0_{b}\rangle+|0_{a}\rangle|1_{b}\rangle+|1_{a}\rangle|0_{b}\rangle+|1_{a}\rangle|1_{b}\rangle}{2}$$

From the binary value of the measurement $c_{a} c_{b}$, the following quantity represents the result of a coin flipping: $c_{a} \oplus c_{b}$. This two-qubit model of true$^1$ random generator was chosen because bias is minimized on the real device.

This result is used to determine which of the two doors hiding a goat is opened each time the player has chosen the door that hides the car. This phase is obviously not necessary when the player has chosen a door hiding a goat: the game master can not open the door hiding a car, nor the door chosen by the player$^2$.

$^1$ If used on the simulator, it remains a pseudo random number generator.

$^2$ This is a hint for finding the optimal strategy: how many times on average is the game master exempt from tossing a coin?

It's time to play!

You may have noticed that the optimal solution has not been hitherto explicitly given. Chances are you already know the answer, and what follows will only comfort you in your belief. For those who are not familiar with this problem, the suspense is preserved and for those who still doubt, this is an opportunity to review your opinion. Play the game a sufficient number of times. Even if you only rely on your intuition for each game, you can use your own success statistics to figure out what is the best strategy.

You will first be asked to choose between the simulator (a good choice to start) or a real device.


In [3]:
"Choice of the backend"
# local qasm simulator
backend = Aer.get_backend('qasm_simulator')

# The flag_qx2 must be "True" for using the ibmqx2. 
# "True" is also better when using the simulator

# Use the IBM Quantum Experience
# backend = least_busy(IBMQ.backends(simulator=False))

flag_qx2 = True
if backend == 'ibmqx4':
        flag_qx2 = False
        
print("Your choice for the backend is: ", backend.name(), "flag_qx2 is: ", flag_qx2)


Your choice for the backend is:  qasm_simulator_py flag_qx2 is:  True

In [4]:
# Here, two useful routine
# Define a F_gate
def F_gate(circ,q,i,j,n,k) :
    theta = np.arccos(np.sqrt(1/(n-k+1)))
    circ.ry(-theta,q[j])       
    circ.cz(q[i],q[j])
    circ.ry(theta,q[j])
    circ.barrier(q[i])
# Define the cxrv gate which uses reverse CNOT instead of CNOT
def  cxrv(circ,q,i,j) :
    circ.h(q[i])
    circ.h(q[j])
    circ.cx(q[j],q[i])
    circ.h(q[i])
    circ.h(q[j])
    circ.barrier(q[i],q[j])

In [5]:
# 3-qubit W state
q = QuantumRegister(5) 
c = ClassicalRegister(5)
W_states = QuantumCircuit(q,c) 
        
W_states.x(q[2]) #start is |100>
F_gate(W_states,q,2,1,3,1) # Applying F12
F_gate(W_states,q,1,0,3,2) # Applying F23

if flag_qx2 : # option ibmqx2 
    W_states.cx(q[1],q[2]) # cNOT 21
    W_states.cx(q[0],q[1]) # cNOT 32
    
else :        # option ibmqx4  
    cxrv(W_states,q,1,2)
    cxrv(W_states,q,0,1)
    
# Coin tossing
W_states.h(q[3]) 
W_states.h(q[4])

for i in range(5) :
    W_states.measure(q[i] , c[i])

In [6]:
"Dotted alphabet"
top_bottom = "███████████████"
blank = "█             █"
chosen = []
chosen = chosen + ["███████████████"]
chosen = chosen + ["███████████  ██"]
chosen = chosen + ["██████████  ███"]
chosen = chosen + ["█████████  ████"]
chosen = chosen + ["████████  █████"]
chosen = chosen + ["█  ████  ██████"]
chosen = chosen + ["██  ██  ███████"]
chosen = chosen + ["███    ████████"]
chosen = chosen + ["████  █████████"]
chosen = chosen + ["███████████████"]

here_left = []
here_left = here_left + ["███████████████"]
here_left = here_left + ["███████████████"]
here_left = here_left + ["███   █████████"]
here_left = here_left + ["███   █████████"]
here_left = here_left + ["███   █████████"]
here_left = here_left + ["███   █████████"]
here_left = here_left + ["███   █████████"]
here_left = here_left + ["███        ████"]
here_left = here_left + ["███████████████"]
here_left = here_left + ["███████████████"]
here_center = []
here_center = here_center + ["███████████████"]
here_center = here_center + ["███████████████"]
here_center = here_center + ["█████      ████"]
here_center = here_center + ["███   █████████"]
here_center = here_center + ["███   █████████"]
here_center = here_center + ["███   █████████"]
here_center = here_center + ["███   █████████"]
here_center = here_center + ["█████      ████"]
here_center = here_center + ["███████████████"]
here_center = here_center + ["███████████████"]
here_right = []
here_right = here_right + ["███████████████"]
here_right = here_right + ["███████████████"]
here_right = here_right + ["███       █████"]
here_right = here_right + ["███   ███   ███"]
here_right = here_right + ["███   ███   ███"]
here_right = here_right + ["███       █████"]
here_right = here_right + ["███   ██   ████"]
here_right = here_right + ["███   ███   ███"]
here_right = here_right + ["███████████████"]
here_right = here_right + ["███████████████"]

goa=["█             █","█   (     )   █","█    (   )    █","█  / O   O \  █","█     )|(     █","█      @      █","█      =      █","█      Y      █","█             █"]
car=["█             █","█   _______   █","█  /       \  █","█ ° _______ ° █","█  /       \  █","█ (O) ### (O) █","█  =+=====+=  █","█  ||     ||  █","█             █"]

In [7]:
"(RE)INITIATES STATISTICS"
nb_randomnb = 0
nb_left =  0
nb_center =  0
nb_right =  0
nb_switches = 0
nb_stays = 0
nb_won_switching = 0
nb_won_sticking = 0
nb_games = 0
n_won = 0

In [9]:
"HERE START THE GAME"
"Hiding the car and the two goats behind the three doors"
Label = ["left", "central", "right"]
shots = 1
repeat = "Y"
while repeat == "Y":
    nb_of_cars = 4
    while nb_of_cars != 1:
        result = execute(W_states, backend=backend, shots=shots)
        c5str = str(result.result().get_counts(W_states))
        nb_of_cars = int(c5str[4]) + int(c5str[5]) + int(c5str[6])

        #this is for checking results from the real computer:
        if nb_of_cars == 0:
            print("They managed to hide three goats and no car behind the doors! Restarting the hiding process...")
        if nb_of_cars >= 2: 
            print("They managed to hide", nb_of_cars, "cars behind the doors! Restarting the hiding process...")

    print(top_bottom," ",top_bottom," ",top_bottom)
    for i in range(9):
        print(here_left[i]," ",here_center[i]," ",here_right[i])
    print(top_bottom," ",top_bottom," ",top_bottom,"\n")        
    door = input("Game master: Your choice? letter l: left door, c: central door, r: right door + enter\n").upper()
    
    picl = here_left
    picc = here_center
    picr = here_right
    if (door == "L"):
        Doorchosen = 1
        nb_left =  nb_left + 1
        picl = chosen
    else:
        if (door == "C"):
            Doorchosen = 2
            nb_center =  nb_center + 1
            picc=chosen
        else:
            Doorchosen = 3
            nb_right = nb_right + 1
            picr = chosen
            
    print('Game master:   Your choice was the',Label[Doorchosen-1], "door")

    "AN OPPORTUNITY TO CHANGE YOUR MIND"

    c5str = str(result.result().get_counts(W_states))

    randomnb = (int(c5str[2]) + int(c5str[3])) %2  

    if c5str[4] == "1":    #car behind left door 
        Doorwinning = 1        
        if Doorchosen == 1:
            Dooropen = 2 + randomnb
            Doorswitch = 3 - randomnb            
        if Doorchosen == 2:
            Dooropen = 3
            Doorswitch = 1
        if Doorchosen == 3:
            Dooropen = 2
            Doorswitch = 1    

    if c5str[5] == "1":     #car behind central door 
        Doorwinning = 2
        if Doorchosen == 2:
            Dooropen = 1 + 2*randomnb 
            Doorswitch = 3 - 2*randomnb 
        if Doorchosen == 1:
            Dooropen = 3            
            Doorswitch = 2
        if Doorchosen == 3:
            Dooropen = 1            
            Doorswitch = 2

    if c5str[6] == "1":     #car behind right door 
        Doorwinning = 3
        if Doorchosen == 3:
            Dooropen = randomnb + 1
            Doorswitch = 2 - randomnb
        if Doorchosen == 1:
            Dooropen = 2         
            Doorswitch = 3
        if Doorchosen == 2:
            Dooropen = 1            
            Doorswitch = 3
            
    if Dooropen == 1:
        picl = goa
    if Dooropen == 2:   
        picc = goa
    if Dooropen == 3:   
        picr = goa        
    
    print(top_bottom," ",top_bottom," ",top_bottom)
    for i in range(9):
        print(picl[i]," ",picc[i]," ",picr[i])        
    print(top_bottom," ",top_bottom," ",top_bottom,"\n")
    print('I opened the', Label[Dooropen-1], 'door and you see a goat')
    print('You get now an opportunity to change your choice!')
    print("Do you want to switch for the ",Label[Doorswitch-1], " door?")
    I_switch = input("    Answer by (y/n) + enter\n").upper()

    if (I_switch == "Y"):
        Doorfinal = Doorswitch
    else:
        Doorfinal = Doorchosen

    "FINAL ANNOUNCE"
    if Doorfinal == Doorwinning:
        if Doorfinal == 1:
            picl = car
        if Doorfinal == 2:   
            picc = car
        if Doorfinal == 3:   
            picr = car 
        endmessage = 'won the car! Congratulations!'
    else:
        if Doorfinal == 1:
            picl = goa
        if Doorfinal == 2:   
            picc = goa
        if Doorfinal == 3:   
            picr = goa
        endmessage = 'won a goat! Sorry!'
    
    print(top_bottom," ",top_bottom," ",top_bottom)
    for i in range(9):
        print(picl[i]," ",picc[i]," ",picr[i])        
    print(top_bottom," ",top_bottom," ",top_bottom,"\n")
    print('Game master: You opened the',Label[Doorfinal-1],'door and', endmessage)
   
    "STATISTICS"
    nb_games = nb_games + 1
    nb_randomnb = nb_randomnb + randomnb
    
    if Doorfinal == Doorswitch:
        nb_switches = nb_switches +1
        if c5str[Doorfinal+3] == "1":
            nb_won_switching = nb_won_switching + 1
    else:
        nb_stays = nb_stays+1
        if c5str[Doorfinal+3] == "1":
            nb_won_sticking = nb_won_sticking + 1
    n_won = nb_won_switching + nb_won_sticking
    print()    
    print("YOUR STATS")    
    print("nb of games: ", nb_games,"     total nb won:", n_won, "     first choice:  left",nb_left," center", nb_center,"right", nb_right)
    print("nb sticking: ",nb_stays," nb won when sticking: ",nb_won_sticking,"nb switching:",nb_switches," nb won when switching:",nb_won_switching)    
    repeat = input("Another game?   Answer by (y/n) + enter\n").upper()
print("Game over")


███████████████   ███████████████   ███████████████
███████████████   ███████████████   ███████████████
███████████████   ███████████████   ███████████████
███   █████████   █████      ████   ███       █████
███   █████████   ███   █████████   ███   ███   ███
███   █████████   ███   █████████   ███   ███   ███
███   █████████   ███   █████████   ███       █████
███   █████████   ███   █████████   ███   ██   ████
███        ████   █████      ████   ███   ███   ███
███████████████   ███████████████   ███████████████
███████████████   ███████████████   ███████████████ 

Game master: Your choice? letter l: left door, c: central door, r: right door + enter
l
Game master:   Your choice was the left door
███████████████   ███████████████   ███████████████
███████████████   █             █   ███████████████
███████████  ██   █   (     )   █   ███████████████
██████████  ███   █    (   )    █   ███       █████
█████████  ████   █  / O   O \  █   ███   ███   ███
████████  █████   █     )|(     █   ███   ███   ███
█  ████  ██████   █      @      █   ███       █████
██  ██  ███████   █      =      █   ███   ██   ████
███    ████████   █      Y      █   ███   ███   ███
████  █████████   █             █   ███████████████
███████████████   ███████████████   ███████████████ 

I opened the central door and you see a goat
You get now an opportunity to change your choice!
Do you want to switch for the  right  door?
    Answer by (y/n) + enter
n
███████████████   ███████████████   ███████████████
█             █   █             █   ███████████████
█   _______   █   █   (     )   █   ███████████████
█  /       \  █   █    (   )    █   ███       █████
█ ° _______ ° █   █  / O   O \  █   ███   ███   ███
█  /       \  █   █     )|(     █   ███   ███   ███
█ (O) ### (O) █   █      @      █   ███       █████
█  =+=====+=  █   █      =      █   ███   ██   ████
█  ||     ||  █   █      Y      █   ███   ███   ███
█             █   █             █   ███████████████
███████████████   ███████████████   ███████████████ 

Game master: You opened the left door and won the car! Congratulations!

YOUR STATS
nb of games:  2      total nb won: 1      first choice:  left 1  center 1 right 0
nb sticking:  2  nb won when sticking:  1 nb switching: 0  nb won when switching: 0
Another game?   Answer by (y/n) + enter
n
Game over

In [ ]: