ベスパリブ

プログラミングを主とした日記・備忘録です。ベスパ持ってないです。

IBM Quantum Challenge: Spring 2023 参加記録

はじめに

5/17 - 5/25 の9日間で開催されたIBM Quantum Spring Challenge 2023 に参加しました。その記録です。

Lab1

Dynamic Circuit (動的回路)を使おうのLab。

動的回路とは、量子回路の途中で測定を行い、その測定結果によって量子演算を作用させるかさせないかを動的に決めれる回路のこと。要はif文が量子回路で使える。

リファレンス

Exercise 1

量子回路で使えるif文である if_test を使うエクササイズ。

実行のたびに量子ビットと古典ビットの名前が変わって嫌だったので、少しプログラムを変更した。

量子ビットと古典ビットに名前をつけたいなら、QuantumRegisterオブジェクトの第2引数nameに指定すれば、実行のたびに0から連番してくれて嬉しくなる。

qr = QuantumRegister(2, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)

q0, q1 = qr
b0, b1 = cr

qc.h(q0)
qc.measure(q0, b0)

####### your code goes here #######
with qc.if_test((b0, 0)) as else_:
    # q0 の測定値が 0 なら q1 に X ゲートを適用する
    qc.x(q1)
with else_:
    # q0 の測定値が 1 なら q1 にアダマールゲートを適用する
    qc.h(q1)

qc.measure(q1, b1)
qc.draw(output="mpl", idle_wires=False)

量子回路

Exercise 2

言われたとおりに実装するだけ。

def trial(
    circuit: QuantumCircuit,
    target: QuantumRegister,
    controls: QuantumRegister,
    measures: ClassicalRegister,
):
    """Probabilistically perform Rx(theta) on the target, where cos(theta) = 3/5."""

    ####### your code goes here #######
    # Step1
    circuit.h(controls)
    circuit.h(target)
    
    # Step2
    circuit.ccx(controls[0], controls[1], target)
    
    # Step3
    circuit.s(target)

    # Step4
    circuit.ccx(controls[0], controls[1], target)

    # Step5
    circuit.h(controls)
    circuit.h(target)

    # Step6
    circuit.measure(controls, measures)

qc = base.copy_empty_like()
trial(qc, target, controls, mid_measure)
qc.draw("mpl", cregbundle=False)

Exercise 3

if_test を使って、測定結果が1だったらXゲートを適用させる回路を作る。

def reset_controls(
    circuit: QuantumCircuit, controls: QuantumRegister, measures: ClassicalRegister
):
    """Reset the control qubits if they are in |1>."""

    ####### your code goes here #######
    with circuit.if_test((measures[0], 1)) as else_:
        # measures[0] == 1 => Xゲート適用
        circuit.x(controls[0])
    with circuit.if_test((measures[1], 1)):
        circuit.x(controls[1])

qc = base.copy_empty_like()
trial(qc, target, controls, mid_measure)
reset_controls(qc, controls, mid_measure)
qc.measure(controls, mid_measure)
qc.draw("mpl", cregbundle=False)

実行結果

Exercise 4

# Set the maximum number of trials
max_trials = 2

# Create a clean circuit with the same structure (bits, registers, etc)
# as the initial base we set up.
circuit = base.copy_empty_like()

# The first trial does not need to reset its inputs, since the controls
# are guaranteed to start in the |0> state.
trial(circuit, target, controls, mid_measure)

# Manually add the rest of the trials.  In the future, we will be
# able to use a dynamic `while` loop to do this, but for now, we
# statically add each loop iteration with a manual condition check
# on each one.  This involves more classical synchronizations than
# the while loop, but will suffice for now.
for _ in range(max_trials - 1):
    reset_controls(circuit, controls, mid_measure)
    with circuit.if_test((mid_measure, 0b00)) as else_:
        # This is the success path, but Qiskit can't directly
        # represent a negative condition yet, so we have an
        # empty `true` block in order to use the `else` branch.
        pass
    with else_:
        ####### your code goes here #######
        circuit.x(target)
        trial(circuit, target, controls, mid_measure)

# We need to measure the control qubits again to ensure we
# get their final results; this is a hardware limitation.
circuit.measure(controls, mid_measure)

# Finally, let's measure our target, to check that we're
# getting the rotation we desired.
circuit.measure(target, final_measure)

circuit.draw("mpl", cregbundle=False)

実行結果

Lab2

量子テレポーテーションのLab。

Exercise 1

from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.circuit import Qubit, Clbit


def create_bell_pair(qr: QuantumRegister, cr: ClassicalRegister) -> QuantumCircuit:
    """Creates a bell pair between qubits a and b."""
    qc = QuantumCircuit(qr, cr)
    # unpack qubits
    # the first qubit is s but we won't be using it in this exercise
    _, a, b = qr

    ####### your code goes here #######
    qc.h(a)
    qc.cx(a,b)

    return qc
qr = QuantumRegister(3, name="q")
cr = ClassicalRegister(3, name="c")
qc = create_bell_pair(qr, cr)

qc.draw("mpl")

実行結果

Exercise 2

def alice_gates(qr: QuantumRegister, cr: ClassicalRegister):
    """Creates Alices's gates"""
    qc = create_bell_pair(qr, cr)
    qc.barrier()  # Use barrier to separate steps
    s, a, b = qr

    ####### your code goes here #######
    qc.cx(s, a)
    qc.h(s)

    return qc
qc = alice_gates(qr, cr)
qc.draw("mpl")

実行結果

Exercise 3

def measure_and_send(qr: QuantumRegister, cr: ClassicalRegister):
    """Measures qubits a & b and 'sends' the results to Bob"""
    qc = alice_gates(qr, cr)
    qc.barrier()  # Use barrier to separate steps
    s, a, b = qr
    c0, c1, c2 = cr

    ####### your code goes here #######
    qc.measure([a,s], [c0,c1])

    return qc
qc = measure_and_send(qr, cr)
qc.draw("mpl", cregbundle=False)

実行結果

Exercise 4

問題文

def bob_gates(qr: QuantumRegister, cr: ClassicalRegister):
    """Uses qc.if_test to control which gates are dynamically added"""
    qc = measure_and_send(qr, cr)
    qc.barrier()  # Use barrier to separate steps
    s, a, b = qr
    c0, c1, c2 = cr

    ####### your code goes here #######
    with qc.if_test((c0,0)) as else_:
        pass
    with else_:
        qc.x(b)
    
    with qc.if_test((c1,1)):
        qc.z(b)
                        
    return qc
qc = bob_gates(qr, cr)
qc.draw("mpl", cregbundle=False)

実行結果

Exercise 5

import math

teleport_superposition_circuit: QuantumCircuit

####### your code goes here #######
def ex5_circuit(teleportation_circuit: QuantumCircuit) -> QuantumCircuit:
    qr = QuantumRegister(3, name="q")
    cr = ClassicalRegister(3, name="c")
    qc = QuantumCircuit(qr, cr)
    qc.rx(math.pi/4, qr[0])

    qc.append(teleportation_circuit.to_instruction(), qr, cr)
    return qc

teleport_superposition_circuit = ex5_circuit(teleportation_circuit)

# Uncomment this line to draw your circuit
teleport_superposition_circuit.draw("mpl", cregbundle=False)

実行結果

ヒストグラムを表示する。

from qiskit import transpile
from qiskit_aer import AerSimulator
from qiskit.visualization import plot_histogram

sim = AerSimulator()
transpiled_circuit = transpile(teleport_superposition_circuit, sim)

# run job
shots = 1000
job = sim.run(transpiled_circuit, shots=shots, dynamic=True)

# Get the results and display them
exp_result = job.result()
exp_counts = exp_result.get_counts()
plot_histogram(exp_counts)

結果のヒストグラム

ボブの測定値だけのヒストグラムを作りたい場合、marginal_counts を使うといいらしいという学び。

# trace out Bob's results on qubit 2
from qiskit.result import marginal_counts

bobs_counts = marginal_counts(exp_counts, [qr.index(b)])
plot_histogram(bobs_counts)

ボブの測定値だけのヒストグラム

Lab3 反復位相推定

今回のChallengeの最難関ともいえる。

ipynbのソースと説明文を読んでも頭に入らないとき、紙に写経してまとめるとすっと理解できることがある。

IPEアルゴリズムまとめ

Sゲートの位相推定

Exercise 1

問題文

from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
import numpy as np


def step_1_circuit(qr: QuantumRegister, cr: ClassicalRegister) -> QuantumCircuit:
    # qr is a quantum register with 2 qubits
    # cr is a classical register with 2 bits

    qc = QuantumCircuit(qr, cr)

    ####### your code goes here #######
    # 1.初期化
    qc.h(qr[0]) # 補助量子ビット
    qc.x(qr[1]) # ターゲット量子ビット
    qc.barrier()

    # 2.制御S^2ゲートを適用する
    qc.cp(np.pi, qr[0], qr[1])
    qc.barrier()

    # 3.X基底で補助量子ビットを測定
    qc.h(qr[0])
    qc.measure(qr[0], cr[0])

    return qc


qr = QuantumRegister(2, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
qc = step_1_circuit(qr, cr)
qc.draw("mpl")

実行結果

Exercise 2

問題文

def step_2_circuit(qr: QuantumRegister, cr: ClassicalRegister) -> QuantumCircuit:
    # qr is a quantum register with 2 qubits
    # cr is a classical register with 2 bits

    # begin with the circuit from Step 1
    qc = step_1_circuit(qr, cr)

    ####### your code goes here #######
    # 1.補助量子ビットをリセットして再初期化
    qc.reset(qr[0])
    qc.h(qr[0])

    # 2.制御ユニタリーゲートを適用する
    qc.cp(np.pi/2, qr[0], qr[1])

    # Z軸の周りを角度 (-pi φ_m)/2 で位相補正する
    with qc.if_test((cr[0], 0)) as else_:
        # 0を測定すれば、角度0度なので何もしない
        pass
    with else_:
        # 1を測定すれば、-pi/2 で位相補正する
        qc.rz(-np.pi/2, qr[0])


    # 3. X基底で測定する
    qc.h(qr[0])
    qc.measure(qr[0], cr[1])

    return qc


qr = QuantumRegister(2, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
qc = step_2_circuit(qr, cr)
qc.draw("mpl")

実行結果

Exercise 3

問題文

かなり詰まった。

固有値固有ベクトルを求め、いくつの量子ビットが必要か求める

Tゲートの累乗表

from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
import numpy as np

"""2023/05/24"""
def t_gate_ipe_circuit(qr: QuantumRegister, cr: ClassicalRegister) -> QuantumCircuit:
    # qr is a quantum register with 2 qubits
    # cr is a classical register with 3 bits

    qc = QuantumCircuit(qr, cr)

    ####### your code goes here #######
    m = 3 # 使用する量子ビットの数

    """最初のステップ"""
    qc.h(qr[0])
    qc.x(qr[1])
    qc.cp(np.pi, qr[0], qr[1])
    qc.h(qr[0])
    qc.measure(qr[0], cr[0])

    """2回目のステップ"""
    # 初期化
    qc.reset(qr[0])
    qc.h(qr[0])

    # Z軸周りの角度wの回転で位相補正
    with qc.if_test((cr[0], 1)):
        qc.p(-2*np.pi/(2**2), qr[0])
        # qc.p(-np.pi/2, qr[0])

    # 制御Uを適用
    qc.cp(np.pi/(2**(m-2)), qr[0], qr[1])

    # X基底でq0を測定
    qc.h(qr[0])
    qc.measure(qr[0], cr[1])

    """3回目のステップ"""
    # 初期化
    qc.reset(qr[0])
    qc.h(qr[0])        
    
    # Z軸周りの角度wの回転で位相補正
    with qc.if_test((cr[0], 1)):
        qc.p(-2*np.pi/(2**3), qr[0])
        # qc.p(-np.pi/4, qr[0])
    with qc.if_test((cr[1], 1)):
        qc.p(-2*np.pi/(2**2), qr[0])
        # qc.p(-np.pi/2, qr[0])

    # 制御Uを適用
    qc.cp(np.pi/(2**(m-1)), qr[0], qr[1])

    # X基底でq0を測定
    qc.h(qr[0])
    qc.measure(qr[0], cr[2])

    return qc

qr = QuantumRegister(2, "q")
cr = ClassicalRegister(3, "c")
qc = QuantumCircuit(qr, cr)
qc = t_gate_ipe_circuit(qr, cr)
qc.draw("mpl")

実行結果

Exercise 4

無限小数になる場合の位相推定

step1_bit: int

####### your code goes here #######
step1_bit = 0
if counts['1'] >= 8:
    step1_bit = 1
    
print(step1_bit)

Exercise 5

問題文

問題文の意味が把握しづらかったが、「最初のビットは常に正しい値を測定するようにする」=「1を測定するようにする」とエスパーしたら通った。

from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
import numpy as np


def u_circuit(qr: QuantumRegister, cr: ClassicalRegister) -> QuantumCircuit:
    # qr is a quantum register with 2 qubits
    # cr is a classical register with 2 bits

    qc = QuantumCircuit(qr, cr)

    ####### your code goes here #######
    q0, q1 = qr
    c0, c1 = cr

    # Initialization
    qc.x(q0)
    qc.x(q1)
    qc.measure(q0, c0)

    """2ビット目を測定するための回路"""
    # Initialization
    qc.reset(q0)
    qc.h(q0)
    with qc.if_test((c0, 1)):
        qc.p(-np.pi / 2, q0)

    # Apply control-U operator as many times as needed to get the least significant phase bit
    # u_angle = 2 * np.pi / 3
    u_angle = np.pi / 12
    k = 2
    cphase_angle = u_angle * 2**k
    qc.cp(cphase_angle, q0, q1)

    # Measure the auxiliary qubit in x-basis
    qc.h(q0)
    qc.measure(q0, c1)

    return qc


qr = QuantumRegister(2, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
qc = u_circuit(qr, cr)
qc.draw("mpl")

実行結果

Lab 4

エラー訂正のLab。

Exercise 1

# Creating a simple decoder for the classical case
def create_decoder(qr: QuantumRegister, cr: ClassicalRegister) -> QuantumCircuit:
    # Expect a bit being encoded in the first 3 qubits and decode it into the 4th qubit
    # Make sure values of the first 3 qubit stays the same

    qc = QuantumCircuit(qr, cr)
    q0, q1, q2, q3 = qr
    (c0,) = cr

    ####### your code goes here #######
    # (q2,q1,q0) のうちに2個以上1があったら q3を|1>にする。
    # 制御ゲートccxを使えばOK
    qc.ccx(q0,q1,q3)
    qc.ccx(q1,q2,q3)
    qc.ccx(q2,q0,q3)
                
    return qc

Exercise 2

問題文

量子ビットの割り当てと、量子ビットエンコード

量子ビットのデコード。スタビライザーの測定。

Exercise 2の解き方

# Add functions such that the classical bits can be used to see which qubit is flipped in the case a single qubit is flipped.
# Use 2 classical bits for it.
# 0 = 00 = no qubit flipped
# 1 = 01 = first qubit (qubit 0) flipped
# 2 = 10 second qubit (qubit 1) flipped
# 3 = 11 = third qubit (qubit 2) flipped
def measure_syndrome_bit(qc, encoding, stabilizer):
    qc.barrier()
    encoding_q0, encoding_q1, encoding_q2 = encoding
    stabilizer_q0, stabilizer_q1 = stabilizer

    ####### your code goes here #######
    # q0が反転(1)していたらスタビライザーが01になるようにする
    qc.cx(encoding_q0, stabilizer_q0)

    # q1が反転(1)していたらスタビライザーが10になるようにする
    qc.cx(encoding_q1, stabilizer_q1)

    # q2が反転(1)していたらスタビライザーが11になるようにする
    qc.cx(encoding_q2, stabilizer_q0)
    qc.cx(encoding_q2, stabilizer_q1)

    ####### don't edit the code below #######
    qc.barrier()
    qc.measure(stabilizer, syndrome)
    with qc.if_test((syndrome_b0, 1)):
        qc.x(stabilizer_q0)
    with qc.if_test((syndrome_b1, 1)):
        qc.x(stabilizer_q1)

    return qc


syndrome_circuit = measure_syndrome_bit(initialize_circuit(), encoding, stabilizer)

complete_circuit = initial_state.compose(encoding_circuit).compose(syndrome_circuit)
complete_circuit.draw("mpl")

実行結果

Exercise 3

問題文

if_test で条件分岐すればOK。

# Correct the errors, remember how we encoded the errors above!
def apply_correction_bit(qc, encoding, syndrome):
    qc.barrier()
    encoding_q0, encoding_q1, encoding_q2 = encoding

    ####### your code goes here #######
    syndrome_b0, syndrome_b1 = syndrome
    with qc.if_test((syndrome_b0, 0)) as else0:
        with qc.if_test((syndrome_b1, 0)) as else1:
            # シンドロームが00の場合
            pass
        with else1:
            # シンドロームが10の場合、q1をエラー訂正
            qc.x(encoding_q1)
    with else0:
        with qc.if_test((syndrome_b1, 0)) as else1:
            # シンドロームが01の場合、q0をエラー訂正
            qc.x(encoding_q0)
        with else1:
            # シンドロームが11の場合、q2をエラー訂正
            qc.x(encoding_q2)

    return qc


correction_circuit = apply_correction_bit(initialize_circuit(), encoding, syndrome)
complete_circuit = (
    initial_state.compose(encoding_circuit)
    .compose(syndrome_circuit)
    .compose(correction_circuit)
)
complete_circuit.draw(output="mpl")

実行結果

Exercise 4

問題文

Exercise 4の解き方

# Add some errors as defined above (only add errors to the encoding qubits)
def make_some_noise(qc, encoding, syndrome, error_percentage):
    encoding_q0, encoding_q1, encoding_q2 = encoding
    syndrome_b0, syndrome_b1 = syndrome

    ####### your code goes here #######
    p = error_percentage/100
    q = 1 - p
    theta = math.acos(math.sqrt(q))*2

    # q0の確率的エラー回路
    qc.rx(theta, encoding_q0)

    # q1の確率的エラー回路
    qc.rx(theta, encoding_q1)

    # q2の確率的エラー回路
    qc.rx(theta, encoding_q2)

    return qc


# Constructing a circuit with 10% error rate (for each of the encoding qubit)
noise_circuit = make_some_noise(initialize_circuit(), encoding, syndrome, 10)
noise_circuit.draw(output="mpl")

実行結果

Lab 5

127量子ビットを使ってDHZ状態を作ろうのLab。

Exercise 1

問題文

Exercise 1の考え方

すべての量子ビットが互いに接続されているなら、ナイーブに実装すればOK。

"""すべての量子ビットが互いに接続されているバージョン"""
def generate_ghz127():
    qc = QuantumCircuit(quantum_register, classical_register)

    ####### your code goes here #######
    qc.h(ghz_qubits[0])

    for idx in range(1, 127):
        qc.cx(0, idx)

    return qc


ghz_circuit = generate_ghz127()
print(ghz_circuit.depth())
# 127

しかしこの問題はレイアウトを考慮して実装しなければならない。レイアウトは以下である。

127量子ビットの接続状態

CNOTゲートを数珠つなぎで適用させるイメージで、エンタングルを作ることができる。

CNOTゲートを数珠つなぎでエンタングルを作る

実装は以下のようになった。

"""実機デバイスの接続状態を考慮バージョン"""
def generate_ghz127():
    qc = QuantumCircuit(quantum_register, classical_register)

    ####### your code goes here #######
    qc.h(ghz_qubits[0])

    # 隣同士のcxゲートをつなげてエンタングルメントを伝播させる
    for i in range(0,13):
        qc.cx(i,i+1)
    qc.cx(0,14)
    qc.cx(4,15)
    qc.cx(8,16)
    qc.cx(12,17)
    qc.cx(14,18)
    for i in range(18,32):
        qc.cx(i,i+1)
    qc.cx(20,33)
    qc.cx(24,34)
    qc.cx(28,35)
    qc.cx(32,36)
    qc.cx(36,51)
    for i in range(51,37,-1):
        qc.cx(i,i-1)
    qc.cx(37,52)
    qc.cx(41,53)
    qc.cx(45,54)
    qc.cx(49,55)
    qc.cx(52,56)
    for i in range(56,70):
        qc.cx(i,i+1)
    qc.cx(58,71)
    qc.cx(62,72)
    qc.cx(66,73)
    qc.cx(70,74)
    qc.cx(74,89)
    for i in range(89,75,-1):
        qc.cx(i,i-1)
    qc.cx(75,90)
    qc.cx(79,91)
    qc.cx(83,92)
    qc.cx(87,93)
    qc.cx(90,94)
    for i in range(94,108):
        qc.cx(i,i+1)
    qc.cx(96,109)
    qc.cx(100,110)
    qc.cx(104,111)
    qc.cx(108,112)
    qc.cx(112,126)
    for i in range(126,113,-1):
        qc.cx(i,i-1)
    return qc


ghz_circuit = generate_ghz127()
print(ghz_circuit.depth())
# 97

回路の深さも短くなったのでヨシ。

Exercise 2

問題文

Exercise 2の考え方

アンエンタングルエンタングルを解除)するには、アンエンタングルしたいビットをターゲットに、CNOTゲートを再度適用させればよい。

アンエンタングルは再度同じCXゲートを適用する

"""実機デバイスの接続状態を考慮バージョン"""
def deentangle_qubits():
    qc = QuantumCircuit(quantum_register, classical_register)

    ####### your code goes here #######
    # スタビライザーのエンタングルメントをキャンセルする
    for i in range(0,13,2):
        qc.cx(i,i+1)
    qc.cx(0,14)
    qc.cx(4,15)
    qc.cx(8,16)
    qc.cx(12,17)
    for i in range(18,32,2):
        qc.cx(i,i+1)
    qc.cx(20,33)
    qc.cx(24,34)
    qc.cx(28,35)
    qc.cx(32,36)
    for i in range(51,37,-2):
        qc.cx(i,i-1)
    qc.cx(37,52)
    qc.cx(41,53)
    qc.cx(45,54)
    qc.cx(49,55)
    for i in range(56,70,2):
        qc.cx(i,i+1)
    qc.cx(58,71)
    qc.cx(62,72)
    qc.cx(66,73)
    qc.cx(70,74)
    for i in range(89,75,-2):
        qc.cx(i,i-1)
    qc.cx(75,90)
    qc.cx(79,91)
    qc.cx(83,92)
    qc.cx(87,93)
    for i in range(94,108,2):
        qc.cx(i,i+1)
    qc.cx(96,109)
    qc.cx(100,110)
    qc.cx(104,111)
    qc.cx(108,112)
    for i in range(126,113,-2):
        qc.cx(i,i-1)

    return qc


unentangle_circuit = deentangle_qubits()
print(unentangle_circuit.depth())
# 2

complete_circuit = ghz_circuit.compose(unentangle_circuit)

最終的に実機デバイスで動くように回路をトランスパイルしたqc_transpiledの深さは以下になった。

# First we transpile the GHZ-state for the actual device
qc_transpiled = transpile(simple_ghz, backend, initial_layout=initial_layout)

qc_transpiled.depth()
# 277

Discordを見ると56くらいにしてる猛者がいた。

実機のレイアウトを考慮していますか?

Exercise 3

問題文

写経。

data は以下の形式のデータが与えられるので、GHZ状態がどのくらい「良い」のか評価関数を作れという問題。

fakedata=['0001010000000001000000001110100110100101110110111101011010110101100110100111010110101111001010000001011000000010000001111100000',
 '1011000001101000001010101001101100100101001101001100111000101010101110100001010101010101010011101010110010101001001010111000101',
 '1001101010101001001010101010101010000101011011010101000010101010101010110111101101010110000000101010101010101010001011010100101',
 '1010110110101000001010100010101010010101010101011101001010111010110010110110001101010110001000101010101011001000001011010110001',
 '0000000000000000000000011001100110100000001110001101000000000000000010110101010100011000001000000011110000000010000000010000000',
 '1010101010101000001010101010101100010101001011011001010010101011000010100101010101010101010000000110101010101000001001111010101',
 '1010101111000000001010101011111010010101010101010100100000001011010110100000000001101101011010101010101001101011001011010000011',
 '0000011011000010011100011011100110010101000000001101000010101000011110100011010100100000001001000000000000001010000000001100000']
# A function to test the quality of a GHZ-state. The lower the better
def test_ghz(data):
    ghz_qubits = [
        0,
        2,
        4,
        6,
        8,
        10,
        12,
        18,
        20,
        22,
        24,
        26,
        28,
        30,
        32,
        37,
        39,
        41,
        43,
        45,
        47,
        49,
        51,
        56,
        58,
        60,
        62,
        64,
        66,
        68,
        70,
        75,
        77,
        79,
        81,
        83,
        85,
        87, # Errata
        89,
        94,
        96,
        98,
        100,
        102,
        104,
        106,
        108,
        114,
        116,
        118,
        120,
        122,
        124,
        126,
    ]

    ####### your code goes here #######
    # GHZ状態がどれほど「良い」か?
    # 理想的なGHZ状態は、ghz_qubitsのどれか1だったらすべて1、どれか0だったらすべて0
    # なので、以下のような方針になる
    # - ghz_qubitsの54ビットがすべて1 => 最良
    # - ghz_qubitsの54ビットがすべて0 => 最良
    # - ghz_qubitsの27ビットが0、27ビットが1 => 最悪
    ans = 0
    for i in range(len(data)):
        # 0と1の個数を数える
        one_num, zero_num = 0, 0
        for idx in ghz_qubits:
            if data[i][idx] == "0":
                zero_num += 1
            else:
                one_num += 1

        # 評価関数は、one_numとzero_numが同数に近ければ値が大きく、離れていたら値が小さくなるようにする
        eval = min(zero_num, one_num) / max(zero_num, one_num)
        ans += eval
    
    # 評価値の平均を返す
    ans /= len(data)
    return ans

# !!!!! fakedata !!!!!
# data = fakedata
test_ghz(data)

まとめと感想

  • Qiskitに動的回路が実装!ただ if_test の書き方は少しクセある
  • 位相推定アルゴリズム難しい
  • 実機のレイアウトを考慮するというのが泥臭く大変だった
  • 127量子ビット動かしたったv(´・_・`)v
  • 今回は追加のヒューリスティックチャレンジは特になかった
  • 今回もバッジを貰えてめでたし