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

Commit

Permalink
[Stable] backport fixes for large qobj and complex in qobj (#635)
Browse files Browse the repository at this point in the history
* Fix tests for terra 0.13 (#623)

* stop using Qobj class

* fix type hint

* print all diff

* use to_dict

* copy return data

* update requirement

* remove deleted file

* don't use terra master

* use newer osx

* use pyenv

* make test more tolerant

(cherry picked from commit da6c78e)

# Conflicts:
#	CHANGELOG.md

* increase put timeout (#626)


(cherry picked from commit 3af24f7)

* Convert list to complex for Qobj (#631)

* convert list to complex for qobj

* increase timeout for qobj download

* change error type

(cherry picked from commit 2d32a1d)

# Conflicts:
#	CHANGELOG.md
  • Loading branch information
jyu00 authored Apr 22, 2020
1 parent f19612d commit f16bfdd
Show file tree
Hide file tree
Showing 19 changed files with 174 additions and 53 deletions.
18 changes: 9 additions & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ stage_linux: &stage_linux
stage_osx: &stage_osx
<<: *stage_generic
os: osx
osx_image: xcode9.2
language: generic
cache:
pip: true
Expand All @@ -60,15 +59,16 @@ stage_osx: &stage_osx
# installed manually.
|
if [ ${TRAVIS_OS_NAME} = "osx" ]; then
if [[ ! -d ~/python-interpreters/$PYTHON_VERSION ]]; then
git clone git://github.com/pyenv/pyenv.git
cd pyenv/plugins/python-build
./install.sh
cd ../../..
python-build $PYTHON_VERSION ~/python-interpreters/$PYTHON_VERSION
if [[ ! -d ~/.pyenv ]]; then
git clone git://github.com/pyenv/pyenv.git ~/.pyenv
fi
virtualenv --python ~/python-interpreters/$PYTHON_VERSION/bin/python venv
source venv/bin/activate
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
pyenv install -s $PYTHON_VERSION
pyenv local $PYTHON_VERSION
pip install --upgrade pip
pip install wheel setuptools
fi


Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ The format is based on [Keep a Changelog].

## [UNRELEASED]

### Fixed

- Increased timeout value to allow large Qobj to be uploaded. (\#626)
- Added a JSON decoder to convert lists in Qobj to complex. (\#631)

## [0.6.0] - 2020-03-26

### Added
Expand Down
4 changes: 2 additions & 2 deletions qiskit/providers/ibmq/api/rest/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def put_object_storage(self, url: str, qobj_dict: Dict[str, Any]) -> str:
"""
data = json.dumps(qobj_dict, cls=json_encoder.IQXJsonEconder)
logger.debug('Uploading Qobj to object storage.')
response = self.session.put(url, data=data, bare=True)
response = self.session.put(url, data=data, bare=True, timeout=600)
return response.text

def get_object_storage(self, url: str) -> Dict[str, Any]:
Expand All @@ -186,5 +186,5 @@ def get_object_storage(self, url: str) -> Dict[str, Any]:
JSON response.
"""
logger.debug('Downloading Qobj from object storage.')
response = self.session.get(url, bare=True).json()
response = self.session.get(url, bare=True, timeout=600).json()
return response
3 changes: 1 addition & 2 deletions qiskit/providers/ibmq/api/rest/schemas/root.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

from marshmallow.validate import OneOf
from qiskit.providers import JobStatus
from qiskit.providers.models.backendconfiguration import BackendConfigurationSchema
from qiskit.providers.ibmq.apiconstants import ApiJobKind
from qiskit.validation import BaseSchema
from qiskit.validation.fields import String, Dict, Nested, Boolean, List, Number
Expand Down Expand Up @@ -120,7 +119,7 @@ class BackendsResponseSchema(BaseSchema):
"""Schema for BackendResponse"""

# Required properties
backends = List(Nested(BackendConfigurationSchema, required=True))
backends = Dict(required=True, many=True)


class JobsRequestSchema(BaseSchema):
Expand Down
2 changes: 1 addition & 1 deletion qiskit/providers/ibmq/api/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ def request( # type: ignore[override]
final_url = self.base_url + url

# Add a timeout to the connection for non-proxy connections.
if not self.proxies:
if not self.proxies and 'timeout' not in kwargs:
kwargs.update({'timeout': self._timeout})

try:
Expand Down
10 changes: 5 additions & 5 deletions qiskit/providers/ibmq/ibmqbackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from datetime import datetime as python_datetime
from marshmallow import ValidationError

from qiskit.qobj import Qobj, validate_qobj_against_schema
from qiskit.qobj import QasmQobj, PulseQobj, validate_qobj_against_schema
from qiskit.providers.basebackend import BaseBackend # type: ignore[attr-defined]
from qiskit.providers.jobstatus import JobStatus
from qiskit.providers.models import (BackendStatus, BackendProperties,
Expand Down Expand Up @@ -114,7 +114,7 @@ def __init__(

def run(
self,
qobj: Qobj,
qobj: Union[QasmQobj, PulseQobj],
job_name: Optional[str] = None,
job_share_level: Optional[str] = None,
job_tags: Optional[List[str]] = None,
Expand Down Expand Up @@ -174,7 +174,7 @@ def run(

def _submit_job(
self,
qobj: Qobj,
qobj: Union[QasmQobj, PulseQobj],
job_name: Optional[str] = None,
job_share_level: Optional[ApiJobShareLevel] = None,
job_tags: Optional[List[str]] = None
Expand Down Expand Up @@ -517,7 +517,7 @@ def properties(

def run(
self,
qobj: Qobj,
qobj: Union[QasmQobj, PulseQobj],
job_name: Optional[str] = None,
job_share_level: Optional[str] = None,
job_tags: Optional[List[str]] = None,
Expand Down Expand Up @@ -606,7 +606,7 @@ def active_jobs(self, limit: int = 10) -> None:

def run(
self,
qobj: Qobj,
qobj: Union[QasmQobj, PulseQobj],
job_name: Optional[str] = None,
job_share_level: Optional[str] = None,
job_tags: Optional[List[str]] = None,
Expand Down
11 changes: 6 additions & 5 deletions qiskit/providers/ibmq/job/ibmqjob.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"""IBM Quantum Experience job."""

import logging
from typing import Dict, Optional, Tuple, Any, List, Callable
from typing import Dict, Optional, Tuple, Any, List, Callable, Union
import warnings
from datetime import datetime
from concurrent import futures
Expand All @@ -28,14 +28,15 @@
BaseBackend)
from qiskit.providers.jobstatus import JOB_FINAL_STATES, JobStatus
from qiskit.providers.models import BackendProperties
from qiskit.qobj import Qobj
from qiskit.qobj import QasmQobj, PulseQobj
from qiskit.result import Result
from qiskit.validation import BaseModel, ModelValidationError, bind_schema

from ..apiconstants import ApiJobStatus, ApiJobKind
from ..api.clients import AccountClient
from ..api.exceptions import ApiError, UserTimeoutExceededError
from ..utils.utils import RefreshQueue
from ..utils.qobj_utils import dict_to_qobj
from .exceptions import (IBMQJobApiError, IBMQJobFailureError,
IBMQJobTimeoutError, IBMQJobInvalidStateError)
from .queueinfo import QueueInfo
Expand Down Expand Up @@ -123,7 +124,7 @@ def __init__(self,

# Convert qobj from dictionary to Qobj.
if isinstance(kwargs.get('_qobj', None), dict):
self._qobj = Qobj.from_dict(kwargs.pop('_qobj'))
self._qobj = dict_to_qobj(kwargs.pop('_qobj'))

BaseModel.__init__(self, _backend=_backend, _job_id=_job_id,
_creation_date=_creation_date,
Expand All @@ -141,7 +142,7 @@ def __init__(self,
self._cancelled = False
self._job_error_msg = None # type: Optional[str]

def qobj(self) -> Optional[Qobj]:
def qobj(self) -> Optional[Union[QasmQobj, PulseQobj]]:
"""Return the Qobj for this job.
Returns:
Expand All @@ -159,7 +160,7 @@ def qobj(self) -> Optional[Qobj]:
with api_to_job_error():
qobj = self._api.job_download_qobj(
self.job_id(), self._use_object_storage)
self._qobj = Qobj.from_dict(qobj)
self._qobj = dict_to_qobj(qobj)

return self._qobj

Expand Down
9 changes: 0 additions & 9 deletions qiskit/providers/ibmq/jupyter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,6 @@
from qiskit.test.ibmq_mock import mock_get_backend
mock_get_backend('FakeVigo')
# TODO Remove after terra 0.13 is released.
from unittest.mock import MagicMock
from qiskit import IBMQ
backend = IBMQ.get_provider().get_backend()
backend._credentials = MagicMock(token='123456', url='https://',
hub='hub', group='group', project='project')
backend.configuration().max_experiments = 75
backend.jobs = MagicMock(return_value=[])
.. jupyter-execute::
from qiskit import IBMQ
Expand Down
10 changes: 5 additions & 5 deletions qiskit/providers/ibmq/managed/managedjob.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@

import warnings
import logging
from typing import List, Optional
from typing import List, Optional, Union
from concurrent.futures import ThreadPoolExecutor
from threading import Lock

from qiskit.providers.ibmq import IBMQBackend
from qiskit.qobj import Qobj
from qiskit.qobj import QasmQobj, PulseQobj
from qiskit.result import Result
from qiskit.providers.jobstatus import JobStatus
from qiskit.providers.exceptions import JobError
Expand Down Expand Up @@ -60,7 +60,7 @@ def __init__(

def submit(
self,
qobj: Qobj,
qobj: Union[QasmQobj, PulseQobj],
job_name: str,
backend: IBMQBackend,
executor: ThreadPoolExecutor,
Expand All @@ -87,7 +87,7 @@ def submit(

def _async_submit(
self,
qobj: Qobj,
qobj: Union[QasmQobj, PulseQobj],
job_name: str,
backend: IBMQBackend,
submit_lock: Lock,
Expand Down Expand Up @@ -216,7 +216,7 @@ def cancel(self) -> None:
logger.warning("Unable to cancel job %s for experiments %d-%d: %s",
self.job.job_id(), self.start_index, self.end_index, cancel_error)

def qobj(self) -> Optional[Qobj]:
def qobj(self) -> Optional[Union[QasmQobj, PulseQobj]]:
"""Return the Qobj for this job.
Returns:
Expand Down
4 changes: 2 additions & 2 deletions qiskit/providers/ibmq/managed/managedjobset.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from qiskit.circuit import QuantumCircuit
from qiskit.pulse import Schedule
from qiskit.compiler import assemble
from qiskit.qobj import Qobj
from qiskit.qobj import QasmQobj, PulseQobj
from qiskit.providers.jobstatus import JobStatus
from qiskit.providers.ibmq.apiconstants import ApiJobShareLevel
from qiskit.providers.ibmq.accountprovider import AccountProvider
Expand Down Expand Up @@ -401,7 +401,7 @@ def job(
'Unable to find the job for experiment {}.'.format(experiment))

@requires_submit
def qobjs(self) -> List[Qobj]:
def qobjs(self) -> List[Union[QasmQobj, PulseQobj]]:
"""Return the Qobjs for the jobs in this set.
Returns:
Expand Down
61 changes: 57 additions & 4 deletions qiskit/providers/ibmq/utils/qobj_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@

"""Utilities related to Qobj."""

from typing import Dict, Any, Optional
from typing import Dict, Any, Optional, Union, List

from qiskit.qobj import QobjHeader, Qobj
from qiskit.qobj import QobjHeader, QasmQobj, PulseQobj


def _serialize_noise_model(config: Dict[str, Any]) -> Dict[str, Any]:
Expand Down Expand Up @@ -45,10 +45,10 @@ def _serialize_noise_model(config: Dict[str, Any]) -> Dict[str, Any]:


def update_qobj_config(
qobj: Qobj,
qobj: Union[QasmQobj, PulseQobj],
backend_options: Optional[Dict] = None,
noise_model: Any = None
) -> Qobj:
) -> Union[QasmQobj, PulseQobj]:
"""Update a ``Qobj`` configuration from backend options and a noise model.
Args:
Expand Down Expand Up @@ -77,3 +77,56 @@ def update_qobj_config(
qobj.config = QobjHeader.from_dict(config)

return qobj


def dict_to_qobj(qobj_dict: Dict) -> Union[QasmQobj, PulseQobj]:
"""Convert a Qobj in dictionary format to an instance.
Args:
qobj_dict: Qobj in dictionary format.
Returns:
The corresponding QasmQobj or PulseQobj instance.
"""
if qobj_dict['type'] == 'PULSE':
_decode_pulse_qobj(qobj_dict) # Convert to proper types.
return PulseQobj.from_dict(qobj_dict)
return QasmQobj.from_dict(qobj_dict)


def _decode_pulse_qobj(pulse_qobj: Dict) -> None:
"""Decode a pulse Qobj.
Args:
pulse_qobj: Qobj to be decoded.
"""
pulse_library = pulse_qobj['config']['pulse_library']
for lib in pulse_library:
lib['samples'] = [_to_complex(sample) for sample in lib['samples']]

for exp in pulse_qobj['experiments']:
for instr in exp['instructions']:
if 'val' in instr:
instr['val'] = _to_complex(instr['val'])
if 'parameters' in instr and 'amp' in instr['parameters']:
instr['parameters']['amp'] = _to_complex(instr['parameters']['amp'])


def _to_complex(value: Union[List[float], complex]) -> complex:
"""Convert the input value to type ``complex``.
Args:
value: Value to be converted.
Returns:
Input value in ``complex``.
Raises:
TypeError: If the input value is not in the expected format.
"""
if isinstance(value, list) and len(value) == 2:
return complex(value[0], value[1])
elif isinstance(value, complex):
return value

raise TypeError("{} is not in a valid complex number format.".format(value))
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
nest-asyncio>=1.0.0,!=1.1.0
qiskit-terra>=0.10
qiskit-terra>=0.13
requests>=2.19
requests_ntlm>=1.1.0
websockets>=7,<8
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

REQUIREMENTS = [
"nest-asyncio>=1.0.0,!=1.1.0",
"qiskit-terra>=0.10",
"qiskit-terra>=0.13",
"requests>=2.19",
"requests-ntlm>=1.1.0",
"websockets>=7,<8",
Expand Down
2 changes: 1 addition & 1 deletion test/fake_account_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def job_submit(self, backend_name, qobj_dict, job_name, job_share_level,

def job_download_qobj(self, job_id, *_args, **_kwargs):
"""Retrieve and return a Qobj."""
return self._get_job(job_id).qobj
return copy.deepcopy(self._get_job(job_id).qobj)

def job_result(self, job_id, *_args, **_kwargs):
"""Return a random job result."""
Expand Down
2 changes: 1 addition & 1 deletion test/ibmq/test_ibmq_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ def final_state_callback(c_job_id, c_status, c_job, **kwargs):
# Check called within wait time.
if callback_info['last call time'] and job._status not in JOB_FINAL_STATES:
self.assertAlmostEqual(
time.time() - callback_info['last call time'], wait_time, delta=0.1)
time.time() - callback_info['last call time'], wait_time, delta=0.2)
callback_info['last call time'] = time.time()

# Put callback data in a dictionary to make it mutable.
Expand Down
3 changes: 1 addition & 2 deletions test/ibmq/test_ibmq_job_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
from qiskit.compiler import assemble, transpile
from qiskit.validation import ModelValidationError
from qiskit.validation.jsonschema import SchemaValidationError

from qiskit.providers.ibmq import IBMQJob

Expand Down Expand Up @@ -54,7 +53,7 @@ def test_invalid_qobj(self, provider):
backend=backend)

delattr(qobj, 'qobj_id')
with self.assertRaises(SchemaValidationError):
with self.assertRaises(AttributeError):
backend.run(qobj, validate_qobj=True)

def test_valid_job(self):
Expand Down
Loading

0 comments on commit f16bfdd

Please sign in to comment.