entropicalabs / openqaoa

Multi-backend SDK for quantum optimisation
MIT License
113 stars 59 forks source link

Prevent double authentication while using `openqaoa-azure` #233

Closed vishal-ph closed 1 year ago

vishal-ph commented 1 year ago

Prerequisites

Before raising this issue, I have already checked that I am:

Describe the bug

Running a QAOA problem using the OpenQAOA workflow as described in this notebook will require web authentication twice before executing the run. For reference, see the attached screenshot.

This happens because DeviceAzure, which is defined in src/openqaoa-azure/openqaoa_azure/backends/devices.py, has a method called check_connection, that is called twice, once from within the workflow and the other time from within the backend object.

To Reproduce

Steps to reproduce the behavior:

  1. Create the Azure device object
  2. Create a qubo for a problem of choice
  3. Initialize the QAOA workflow as q = QAOA()
  4. Call the compile method and pass the QUBO via q.compile(qubo)

Expected behavior

Upon executing the above steps, the web authenticator should only prompt once for device authentication

Screenshots

image

WingCode commented 1 year ago

@vishal-ph I would like to take a stab at this issue. Could you assign it to me?

vishal-ph commented 1 year ago

NOTE: - Please branch out from openqaoa/dev and will make the PR into openqaoa/dev. Thanks

TerraVenil commented 1 year ago

Hi, @vishal-ph. I was trying to reproduce the issue with steps described above. My code is below

from openqaoa import QAOA
from openqaoa.backends import create_device

device_azure = create_device(location='azure',
                             name='ionq.simulator',
                             resource_id="/subscriptions/****/resourceGroups/****/providers/****/Workspaces/****",
                             az_location='westus')

q = QAOA()
q.set_device(device_azure)
q.set_backend_properties(n_shots=1000)
q.set_classical_optimizer(maxiter=5)

from openqaoa.problems import NumberPartition

np_integer = NumberPartition([1,2,3])
np_qubo = np_integer.qubo

q.compile(np_qubo)

and my results after the execution code above is the following: image I have only changed timeout from 300s to 3 to skip long waiting for authentication. As you can see internally the authenticator throws an exception after some period of time. May I ask you to provide code to be able to reproduce this issue locally?

The next thing regarding

This happens because DeviceAzure, which is defined in src/openqaoa-azure/openqaoa_azure/backends/devices.py, has a method called check_connection, that is called twice, once from within the workflow and the other time from within the backend object.

I found that method check_connectioncalled withing workflow here https://github.com/entropicalabs/openqaoa/blob/dev/src/openqaoa-core/openqaoa/algorithms/qaoa/qaoa_workflow.py#L218 and probably you meant this call https://github.com/entropicalabs/openqaoa/blob/dev/src/openqaoa-core/openqaoa/backends/basebackend.py#L563 inside QAOABaseBackendCloud but I can't find any reference to it in steps to reproduce.

So please give more details to have a more clear picture of what is going on.

vishal-ph commented 1 year ago

@TerraVenil, thanks for taking a look at this issue! Regarding your questions:

Let me know if you still have questions or something is unclear! Thanks

TerraVenil commented 1 year ago

Judging from your screenshot, it seems your CLI is not set up with Azure credentials. To access the devices from Azure and use them with OpenQAOA, you must first set up Azure CLI. Instructions to do that can be found here. In case, the issue is something else, please let me know!

I have installed Azure CLI and also provided the correct resourceId and location. Screenshot demonstrated that Azure Quantum iterates over a list of credentials to find the most appropriate to current user setup. So now I intentionally skipped the step of az login to reproduce an issue when to authenticate a user an interactive browser session required in Azure that corresponds to InteractiveBrowserCredential or DeviceCodeCredential. And from the screenshot we can see that eventually if you don't specify any login information Azure Quantum will throw timeout exception that an seen for both InteractiveBrowserCredential and DeviceCodeCredential. Question how you were able to achieve two sequential requests from a web authenticator still open :)

For the second part of your question, you can look here and notice that the check_connection method of the device object verifies if connections to both provider and QPU are made, and returns True if both self.provider_connected and self.qpu_connected are True, or if self.provider_connected is True and self.device_name == "" As you rightly pointed out, the check_connection is in the qaoa_workflow.py and basebackend.py. However, I think we can add conditionals, in the backend file that first check whether the device.provider_connected and device.qpu_connected are already True and skip check_connection if that's the case.

To understand if we necessarily need this check I have created small unit test to demonstrate such case

        shots = 100

        set_of_numbers = np.random.randint(1, 10, 6).tolist()
        qubo = NumberPartition(set_of_numbers).qubo

        mixer_hamil = X_mixer_hamiltonian(n_qubits=6)
        qaoa_descriptor = QAOADescriptor(qubo.hamiltonian, mixer_hamil, p=1)
        variate_params = create_qaoa_variational_params(qaoa_descriptor, 'standard', 'rand')

        azure_device = DeviceAzure(
            device_name='ionq.simulator',
            resource_id="/subscriptions/****/resourceGroups/****/providers/****/Workspaces/****",
            az_location='westus'
        )

        azure_device.check_connection()

        # here in ctor we call check_connection() again
        qiskit_backend = QAOAQiskitQPUBackend(
            qaoa_descriptor, azure_device, shots, None, None, True
        )

        # in total we called check_connection twice
        circuit = qiskit_backend.qaoa_circuit(variate_params)
        job = qiskit_backend.backend_qpu.run(circuit, shots=qiskit_backend.n_shots)

Do we really expect that the user(is it a normal/obvious/intuitive scenario?) before using QAOAQiskitQPUBackend would call check_connection on DeviceAzure? Of course we should protect code from different scenarios but for example I could't find any similar workflow in existing unit tests base. Just to be sure that we are adding a useful feature. Thanks!

TerraVenil commented 1 year ago

Ok, I found place where we want to avoid additional call to check_connection because obviously it was done before in scope of compile method and created PR.

TerraVenil commented 1 year ago

@Q-lds or @vishal-ph please assign this issue to me. Thanks.

vishal-ph commented 1 year ago

Fixed this issue in PR #249