Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
DominikVoigt committed Sep 6, 2023
1 parent 69d8cfe commit c2d882b
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 84 deletions.
65 changes: 8 additions & 57 deletions app/aws_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ******************************************************************************
from time import sleep

from qiskit import QiskitError, QuantumRegister, execute
from qiskit.ignis.mitigation import CompleteMeasFitter, complete_meas_cal
from qiskit.providers.ibmq import IBMQ
from qiskit_braket_provider import AWSBraketProvider
from qiskit.providers.jobstatus import JOB_FINAL_STATES
from qiskit.providers.exceptions import JobError, JobTimeoutError
from qiskit.providers.exceptions import QiskitBackendNotFoundError
from qiskit.providers.ibmq.api.exceptions import RequestsApiError
from qiskit import QiskitError


def get_qpu(token, qpu_name, url='https://auth.quantum-computing.ibm.com/api', hub='ibm-q', group='open', project='main'):
"""Load account from token. Get backend."""
try:
IBMQ.disable_account()
except:
pass
provider = IBMQ.enable_account(token=token, url=url, hub=hub, group=group, project=project)
def get_qpu(qpu_name):
provider = AWSBraketProvider()
backend = provider.get_backend(qpu_name)
return backend


def delete_token():
"""Delete account."""
IBMQ.delete_account()


def execute_job(transpiled_circuit, shots, backend):
"""Generate qObject from transpiled circuit and execute it. Return result."""

Expand All @@ -59,6 +42,8 @@ def execute_job(transpiled_circuit, shots, backend):
print(job_result)
job_result_dict = job_result.to_dict()
print(job_result_dict)

# TODO: I am currently not sure whether this is still consistent in AWS Braket as they use the getCounts method, we will see when we try
try:
statevector = job_result.get_statevector()
print("\nState vector:")
Expand All @@ -81,39 +66,5 @@ def execute_job(transpiled_circuit, shots, backend):
unitary = None
print("No unitary available!")
return {'job_result_raw': job_result_dict, 'statevector': statevector, 'counts': counts, 'unitary': unitary}
except (JobError, JobTimeoutError):
return None


def get_meas_fitter(token, qpu_name, shots):
"""Execute the calibration circuits on the given backend and calculate resulting matrix."""
print("Starting calculation of calibration matrix for QPU: ", qpu_name)

backend = get_qpu(token, qpu_name)

# Generate a calibration circuit for each state
qr = QuantumRegister(len(backend.properties().qubits))
meas_calibs, state_labels = complete_meas_cal(qr=qr, circlabel='mcal')

# Execute each calibration circuit and store results
print('Executing ' + str(len(meas_calibs)) + ' circuits to create calibration matrix...')
cal_results = []
for circuit in meas_calibs:
print('Executing circuit ' + circuit.name)
cal_results.append(execute_calibration_circuit(circuit, shots, backend))

# Generate calibration matrix out of measurement results
meas_fitter = CompleteMeasFitter(cal_results, state_labels, circlabel='mcal')
return meas_fitter.filter


def execute_calibration_circuit(circuit, shots, backend):
"""Execute a calibration circuit on the specified backend"""
job = execute(circuit, backend=backend, shots=shots)

job_status = job.status()
while job_status not in JOB_FINAL_STATES:
print('The execution is still running')
sleep(20)
job_status = job.status()
return job.result()
except Exception:
return None
42 changes: 27 additions & 15 deletions app/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
# ******************************************************************************
from qiskit.providers.ibmq import IBMQAccountError

from app import app, benchmarking, ibmq_handler, implementation_handler, db, parameters, circuit_analysis, analysis
from app import app, benchmarking, aws_handler, ibmq_handler, implementation_handler, db, parameters, circuit_analysis, analysis
from app.benchmark_model import Benchmark
from app.qpu_metrics import generate_deterministic_uuid, get_all_qpus_and_metrics_as_json_str
from app.result_model import Result
Expand All @@ -37,6 +37,8 @@ def transpile_circuit():
if not request.json or not 'qpu-name' in request.json:
abort(400)

# Default value is ibmq for services that do not support multiple providers and expect the IBMQ provider
provider = request.json.get('provider', 'ibmq')
qpu_name = request.json['qpu-name']
impl_language = request.json.get('impl-language', '')
input_params = request.json.get('input-params', "")
Expand All @@ -50,17 +52,6 @@ def transpile_circuit():
else:
abort(400)


credentials = {}
if 'url' in input_params:
credentials['url'] = input_params['url']
if 'hub' in input_params:
credentials['hub'] = input_params['hub']
if 'group' in input_params:
credentials['group'] = input_params['group']
if 'project' in input_params:
credentials['project'] = input_params['project']

if impl_url is not None and impl_url != "":
impl_url = request.json['impl-url']
if impl_language.lower() == 'openqasm':
Expand Down Expand Up @@ -115,13 +106,26 @@ def transpile_circuit():
app.logger.info(f"Transpile {short_impl_name} for {qpu_name}: {str(e)}")
return jsonify({'error': str(e)}), 200

backend = ibmq_handler.get_qpu(token, qpu_name, **credentials)
backend = None
if provider == 'ibmq':
credentials = {}
if 'url' in input_params:
credentials['url'] = input_params['url']
if 'hub' in input_params:
credentials['hub'] = input_params['hub']
if 'group' in input_params:
credentials['group'] = input_params['group']
if 'project' in input_params:
credentials['project'] = input_params['project']
backend = ibmq_handler.get_qpu(token, qpu_name, **credentials)
elif provider == 'aws':
backend = aws_handler.get_qpu(qpu_name)
if not backend:
# ibmq_handler.delete_token()
app.logger.warn(f"{qpu_name} not found.")
abort(404)

try:
# TODO: Not sure whether this call will work for AWS?
transpiled_circuit = transpile(circuit, backend=backend, optimization_level=3)
print("Transpiled Circuit")
print(transpiled_circuit)
Expand Down Expand Up @@ -241,6 +245,9 @@ def execute_circuit():
"""Put execution jobs in queue. Return location of the later results."""
if not request.json or not 'qpu-name' in request.json:
abort(400)

# Default value is ibmq for services that do not support multiple providers and expect the IBMQ provider
provider = request.json.get('provider', 'ibmq')
qpu_name = request.json['qpu-name']
impl_language = request.json.get('impl-language', '')
impl_url = request.json.get('impl-url')
Expand Down Expand Up @@ -280,7 +287,7 @@ def execute_circuit():
else:
abort(400)

job = app.execute_queue.enqueue('app.tasks.execute', impl_url=impl_url, impl_data=impl_data,
job = app.execute_queue.enqueue('app.tasks.execute', provider=provider, impl_url=impl_url, impl_data=impl_data,
impl_language=impl_language, transpiled_qasm=transpiled_qasm, qpu_name=qpu_name,
token=token, input_params=input_params, noise_model=noise_model,
only_measurement_errors=only_measurement_errors,
Expand Down Expand Up @@ -449,6 +456,11 @@ def get_providers():
"id": str(generate_deterministic_uuid("ibmq", "provider")),
"name": "ibmq",
"offeringURL": "https://quantum-computing.ibm.com/",
},
{
"id": str(generate_deterministic_uuid("aws", "provider")),
"name": "aws",
"offeringURL": "https://aws.amazon.com/braket/",
}
]
}
Expand Down
29 changes: 17 additions & 12 deletions app/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,13 @@
# ******************************************************************************
import datetime

from app import implementation_handler, ibmq_handler, db, app
from qiskit import transpile, QuantumCircuit
from app import implementation_handler, aws_handler, ibmq_handler, db, app
from qiskit.transpiler.exceptions import TranspilerError
from rq import get_current_job
from qiskit.providers.ibmq.managed import IBMQJobManager
from qiskit.utils.measurement_error_mitigation import get_measured_qubits
from qiskit.providers.aer import AerSimulator
from qiskit.providers.aer.noise import NoiseModel
from qiskit.providers.ibmq.api.exceptions import RequestsApiError
from qiskit.providers import QiskitBackendNotFoundError
from qiskit import IBMQ, transpile, QuantumCircuit

from app.NumpyEncoder import NumpyEncoder
Expand All @@ -37,12 +34,15 @@
import base64


def execute(impl_url, impl_data, impl_language, transpiled_qasm, input_params, token, qpu_name, optimization_level, noise_model, only_measurement_errors, shots, bearer_token, qasm_string, **kwargs):
def execute(provider, impl_url, impl_data, impl_language, transpiled_qasm, input_params, token, qpu_name, optimization_level, noise_model, only_measurement_errors, shots, bearer_token, qasm_string, **kwargs):
"""Create database entry for result. Get implementation code, prepare it, and execute it. Save result in db"""
app.logger.info("Starting execute task...")
job = get_current_job()

backend = ibmq_handler.get_qpu(token, qpu_name, **kwargs)
if provider == 'ibmq':
backend = ibmq_handler.get_qpu(token, qpu_name, **kwargs)
elif provider == 'aws':
backend = aws_handler.get_qpu(qpu_name)
if not backend:
result = Result.query.get(job.get_id())
result.result = json.dumps({'error': 'qpu-name or token wrong'})
Expand Down Expand Up @@ -111,10 +111,15 @@ def execute(impl_url, impl_data, impl_language, transpiled_qasm, input_params, t
db.session.commit()

app.logger.info('Start executing...')
job_manager = IBMQJobManager()
job_result = job_manager.run(transpiled_circuits, backend=backend)
if provider == 'ibmq':
job_manager = IBMQJobManager()
job_result = job_manager.run(transpiled_circuits, backend=backend, shots=shots)
elif provider == 'aws':
# TODO: Not sure how to do this:
# - Why does this not use the handlers?
# - Why do we 'analyze' the results here and not use handler code?
# - Does this need to execute multiple circuits?

# job_result = ibmq_handler.execute_job(transpiled_circuit, shots, backend)
if job_result:
result = Result.query.get(job.get_id())
result_counts = []
Expand All @@ -141,7 +146,7 @@ def get_measurement_qubits_from_transpiled_circuit(transpiled_circuit):
return measurement_qubits


def convertInSuitableFormat(object):
def convert_into_suitable_format(object):
"""Enables the serialization of the unserializable datetime.datetime format"""
if isinstance(object, datetime.datetime):
return object.__str__()
Expand All @@ -167,11 +172,11 @@ def execute_benchmark(transpiled_qasm, token, qpu_name, shots):
if job_result:
# once the job is finished save results in db
result = Result.query.get(job.get_id())
result.result = json.dumps(job_result, default=convertInSuitableFormat)
result.result = json.dumps(job_result, default=convert_into_suitable_format)
result.complete = True

benchmark = Benchmark.query.get(job.get_id())
benchmark.result = json.dumps(job_result, default=convertInSuitableFormat)
benchmark.result = json.dumps(job_result, default=convert_into_suitable_format)
benchmark.counts = json.dumps(job_result['counts'])
benchmark.complete = True

Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ qiskit-aer==0.10.3
qiskit-ibmq-provider==0.18.3
qiskit-ignis==0.7.0
qiskit-terra==0.20.0
qiskit_braket_provider==0.0.4
redis==4.3.1
requests==2.27.1
requests-ntlm==1.1.0
Expand Down

0 comments on commit c2d882b

Please sign in to comment.