Skip to content
This repository was archived by the owner on Jul 28, 2023. It is now read-only.

Fix issue with parameters in metadata #1095

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions qiskit/providers/ibmq/utils/json_encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,33 @@
class IQXJsonEncoder(json.JSONEncoder):
"""A json encoder for qobj"""

def __encode(self, param: Any) -> Any:
"""
Convert dictionary to contain only JSON serializable types. For example,
if the key is a Parameter we convert it to a string.
"""
if isinstance(param, dict):
param_bind_str = {}
for key in param.keys():
value = self.__encode(param[key])

if isinstance(key, (bool, float, int, str)) or key is None:
param_bind_str[key] = value
else:
param_bind_str[str(key)] = value
return param_bind_str
elif isinstance(param, list):
return [self.__encode(p) for p in param]
else:
return param

def encode(self, o: Any) -> str:
"""
Return a JSON string representation of a Python data structure.
"""
new_o = self.__encode(o)
return super().encode(new_o)

def default(self, o: Any) -> Any:
# Convert numpy arrays:
if hasattr(o, 'tolist'):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
fixes:
- |
Fix delivered in `#1065 <https://github.com/Qiskit/qiskit-ibmq-provider/pull/1065>`__ for the
issue where job kept crashing when ``Parameter`` was passed in circuit metadata.

41 changes: 40 additions & 1 deletion test/ibmq/test_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
from unittest import SkipTest, skipIf
from typing import Any, Dict, Optional

import json
import dateutil.parser
from qiskit.test.reference_circuits import ReferenceCircuits
from qiskit.test import slow_test
from qiskit.providers.ibmq import least_busy
from qiskit import transpile, schedule, QuantumCircuit
from qiskit import transpile, schedule, assemble
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.providers.ibmq.utils.json_encoder import IQXJsonEncoder
from qiskit.circuit import Parameter
from qiskit.version import VERSION as terra_version
Expand Down Expand Up @@ -178,6 +180,43 @@ def test_convert_complex(self):
self.assertEqual(val[0], 0.2)
self.assertEqual(val[1], 0.1)

def test_exception_message(self):
"""Test executing job with Parameter in methadata."""
qr = QuantumRegister(1)
cr = ClassicalRegister(1)
my_circ_str = 'test_metadata'
my_circ = QuantumCircuit(qr, cr, name=my_circ_str, metadata={Parameter('φ'): 0.2})
qobj = assemble(my_circ)
qobj_dict = qobj.to_dict()
json.dumps(qobj_dict, cls=IQXJsonEncoder)
# There is no self.assert method because if we cannot pass Parameter as metadata
# the last line throw:
# "TypeError: keys must be str, int, float, bool or None, not Parameter"

def test_encode_no_replace(self):
"""Test encode where there is no invalid key to replace."""
test_dir = {
't1': 1,
None: None,
'list': [1, 2, {'ld': 1, 2: 3}]
}

self.assertEqual('{"t1": 1, "null": null, "list": [1, 2, {"ld": 1, "2": 3}]}',
IQXJsonEncoder().encode(test_dir))

def test_encode_replace(self):
"""Test encode where there is no invalid key to replace."""
test_dir = {
't1': 1,
None: None,
Parameter('a'): 0.2,
'list': [1, 2, {'ld': 1, 2: 3, Parameter('alfa'): 0.1}]
}

self.assertEqual(
'{"t1": 1, "null": null, "a": 0.2, "list": [1, 2, {"ld": 1, "2": 3, "alfa": 0.1}]}',
IQXJsonEncoder().encode(test_dir))


def _find_potential_encoded(data: Any, c_key: str, tally: set) -> None:
"""Find data that may be in JSON serialized format.
Expand Down