# Import the module needed to access Qiskit Runtime
from qiskit_ibm_runtime import QiskitRuntimeService

# Save account on disk.
# QiskitRuntimeService.save_account(channel="ibm_quantum", token=<IBM Quantum API token>)

# Load your IBM Quantum account or enable the account if it's not previously saved.
service   = QiskitRuntimeService(channel="ibm_quantum")
# service = QiskitRuntimeService(channel="ibm_quantum", token=<IBM Quantum API token>)

# Specify the backend name.
options = {"backend_name": "ibmq_qasm_simulator"}

job = service.run(
    program_id="hello-world",
    options=options,
    inputs={},
)

# Get the job result - this is blocking and control may not return immediately.
result = job.result()
print(result)

from qiskit.circuit.library import RealAmplitudes

pqc = RealAmplitudes(num_qubits=2, reps=2)
pqc.measure_all()

print(f"The circuit has {pqc.num_parameters} parameters")
pqc.decompose().draw()

# You can also check the backend configuration and properties.
# Backend configuration contains (mostly) static information about the backend.
# Backend properties contains dynamic information about the backend.

backend = service.least_busy(simulator=False, min_num_qubits=5)

print(f"Backend {backend.name} has {backend.configuration().num_qubits} qubits.")
print(f"T1 value for qubit 0 is {backend.properties().t1(0)}s")

# In this workshop we will be using the simulator.

backend = "ibmq_qasm_simulator"

from qiskit_ibm_runtime import Sampler

# Use a context manager to open a session.
with Sampler(circuits=pqc, service=service, options={"backend": backend}) as sampler:
    pass

with Sampler(circuits=pqc, service=service, options={"backend": backend}) as sampler:
    result = sampler(circuits=[0], parameter_values=[[0, 1, 1, 2, 3, 5]])
    print(result)

from qiskit.circuit.library import EfficientSU2

pqc2 = EfficientSU2(num_qubits=2, reps=1)
pqc2.measure_all()

print(f"The circuit has {pqc2.num_parameters} parameters")
pqc2.decompose().draw()

from qiskit_ibm_runtime import Sampler

theta1 = [0, 1, 1, 2, 3, 5]
theta2 = [1, 2, 3, 4, 5, 6]
theta3 = [0, 1, 2, 3, 4, 5, 6, 7]

with Sampler(circuits=[pqc, pqc2], service=service, options={"backend": backend}) as sampler:    
    result = sampler(circuits=[0], parameter_values=[theta1], shots=2000)
    print(f"Result from circuit 0 with parameter {theta1}: {result}\n")
    
    result = sampler(circuits=[0, 0], parameter_values=[theta1, theta2])
    print(f"Result from circuit 0 with parameters {theta1, theta2}: {result}\n")
    
    result = sampler(circuits=[0, 1], parameter_values=[theta1, theta3])
    print(f"Result from circuits 0, 1 with parameters {theta1, theta2}: {result}")

from qiskit.circuit import Parameter, QuantumCircuit

# Create a custom parameterized circuit.
theta = Parameter('θ')
qc = QuantumCircuit(1)
qc.rx(theta, 0)
qc.measure_all()
qc.draw()

from math import pi
from qiskit_ibm_runtime import Sampler

theta_val = 0.25*pi

with Sampler(circuits=[qc], service=service, options={"backend": backend}) as sampler:
    result = sampler(circuits=[0], parameter_values=[[theta_val]], shots=100)
    
    while result.quasi_dists[0].get('1', 0) < 0.5:
        print(f"Result is {result.quasi_dists} when using theta {theta_val}")
        
        theta_val += (result.quasi_dists[0].get('1', 0.25)*pi)
        result = sampler(circuits=[0], parameter_values=[[theta_val]], shots=100)

    print(f"All done. Result is {result.quasi_dists} when using theta {theta_val}")
        

import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright