from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister

qr = QuantumRegister(1)
cr = ClassicalRegister(1)
qc = QuantumCircuit(qr, cr)

####### your code goes here #######

qc.h(qr[0])
qc.measure(qr[0], cr[0])


qc.draw("mpl")

answer_0 = 2
#answer_0 = 500
print
##### Hint: Remember to run this cell after changing your value ###

# Grader Cell: Run this to submit your answer

from qc_grader.challenges.spring_2023 import grade_ex1a

grade_ex1a(answer_0)

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

qr = QuantumRegister(1)
cr = ClassicalRegister(2)
qc = QuantumCircuit(qr, cr)

# unpack the qubit and classical bits from the registers
(q0,) = qr
b0, b1 = cr

# apply Hadamard
qc.h(q0)
# measure
qc.measure(q0, b0)

# begin if test block. the contents of the block are executed if b0 == 1
with qc.if_test((b0, 1)):
    # if the condition is satisfied (b0 == 1), then flip the bit back to 0
    qc.x(q0)
# finally, measure q0 again
qc.measure(q0, b1)

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

from qiskit_aer import AerSimulator

# initialize the simulator
backend_sim = AerSimulator()

# run the circuit
reset_sim_job = backend_sim.run(qc)
# get the results
reset_sim_result = reset_sim_job.result()
# retrieve the bitstring counts
reset_sim_counts = reset_sim_result.get_counts()

print(f"Counts: {reset_sim_counts}")

from qiskit.visualization import *

# plot histogram
plot_histogram(reset_sim_counts)

qr = QuantumRegister(2)
cr = ClassicalRegister(2)
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_:
    qc.x(q1)
    
with else_:
    qc.h(q1)   


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

backend_sim = AerSimulator()

job_1 = backend_sim.run(qc)
result_1 = job_1.result()
counts_1 = result_1.get_counts()

print(f"Counts: {counts_1}")

# Submit your circuit

from qc_grader.challenges.spring_2023 import grade_ex1b

grade_ex1b(qc)

controls = QuantumRegister(2, name="control")
target = QuantumRegister(1, name="target")

mid_measure = ClassicalRegister(2, name="mid")
final_measure = ClassicalRegister(1, name="final")

base = QuantumCircuit(controls, target, mid_measure, final_measure)

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 #######
    t = target
    c0, c1 = controls
    m0, m1 = measures

    circuit.h(c0)
    circuit.h(c1)
    circuit.h(t)
    
    circuit.ccx(c0, c1, t)
    
    circuit.s(t)
    
    circuit.ccx(c0, c1, t)
    
    circuit.h(c0)
    circuit.h(c1)
    circuit.h(t)
    
    circuit.measure(c0, m0)
    circuit.measure(c1, m1)


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

# Submit your circuit
from qc_grader.challenges.spring_2023 import grade_ex1c

grade_ex1c(qc)

def reset_controls(
    circuit: QuantumCircuit, controls: QuantumRegister, measures: ClassicalRegister
):
    """Reset the control qubits if they are in |1>."""
    c0, c1 = controls
    m0, m1 = measures
    
    
    ####### your code goes here #######
    with qc.if_test((m0, 1)):
        circuit.x(c0)
    
    with qc.if_test((m1, 1)):
        circuit.x(c1) 


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)

# Submit your circuit
from qc_grader.challenges.spring_2023 import grade_ex1d

grade_ex1d(qc)

# 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()
qc = circuit
# The first trial does not need to reset its inputs, since the controls
# are guaranteed to start in the |0> state.
trial(qc, 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(qc, controls, mid_measure)
    with qc.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 #######
        qc.x(target)
        trial(qc, target, controls, mid_measure)
    
# We need to measure the control qubits again to ensure we
# get their final results; this is a hardware limitation.
qc.measure(controls, mid_measure)

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

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

# Submit your circuit
from qc_grader.challenges.spring_2023 import grade_ex1e

grade_ex1e(circuit)

sim = AerSimulator()
job = sim.run(circuit, shots=1000)
result = job.result()
counts = result.get_counts()

plot_histogram(counts)

from qiskit_ibm_provider import IBMProvider

provider = IBMProvider()

hub = "qc-spring-23-1"
group = "group-1"
project = "recIvcxUcc27LvvSh"

backend_name = "ibm_peekskill"
backend = provider.get_backend(backend_name, instance=f"{hub}/{group}/{project}")

from qiskit import transpile

qc_transpiled = transpile(circuit, backend)
job = backend.run(qc_transpiled, shots=1000, dynamic=True)


counts = job.result().get_counts()

plot_histogram(counts)

