├── .github └── workflows │ ├── docs.yml │ └── main.yml ├── .gitignore ├── .pylintrc ├── LICENSE ├── README.md ├── constraints.txt ├── docs ├── Makefile ├── _static │ ├── gallery.css │ └── no_image.png ├── _templates │ ├── autosummary │ │ └── class.rst │ ├── layout.html │ ├── theme_variables.jinja │ └── versions.html ├── conf.py ├── example_scripts │ ├── circuit_runner.rst │ └── qka.rst ├── getting_started.rst ├── images │ └── runtime_arch.png ├── index.rst ├── limitations.rst └── tutorials.rst ├── extras ├── README.md ├── images │ ├── api_token.png │ ├── ibmq_services.png │ ├── main_function.png │ ├── program_jobs.png │ ├── qva_loop.png │ ├── runtime_api.png │ ├── runtime_programs.png │ ├── sample_program.png │ ├── vqa_pre_runtime.png │ └── vqa_with_runtime.png └── qce21_runtime_tutorial.ipynb ├── pyproject.toml ├── qiskit_runtime ├── __init__.py ├── circuit_runner │ ├── __init__.py │ ├── circuit_runner.json │ └── circuit_runner.py ├── hello_world │ ├── __init__.py │ ├── hello_world.json │ └── hello_world.py ├── qaoa │ ├── qaoa.py │ └── qaoa_metadata.json ├── qka │ ├── __init__.py │ ├── aux_file │ │ ├── dataset_graph10.csv │ │ └── dataset_graph7.csv │ ├── featuremaps.py │ ├── kernel_matrix.py │ ├── qka.json │ └── qka.py ├── sample_program │ ├── __init__.py │ ├── sample_program.json │ └── sample_program.py ├── version.py └── vqe │ ├── vqe.py │ └── vqe_metadata.json ├── requirements-dev.txt ├── requirements-docs.txt ├── requirements.txt ├── setup.py ├── test ├── __init__.py ├── circuit_runner │ ├── __init__.py │ └── test_circuit_runner.py ├── fake_user_messenger.py └── hello_world │ ├── __init__.py │ └── test_sample_program.py ├── tools ├── deploy_documentation.sh └── rclone.conf.enc ├── tox.ini └── tutorials ├── 00_introduction.ipynb ├── 01_circuit_runner.ipynb ├── 02_uploading_program.ipynb ├── API_direct.ipynb ├── images ├── chip.png └── subgraphs.png ├── qka.ipynb ├── sample_expval_program ├── qiskit_runtime_expval_program.ipynb └── sample_expval.py ├── sample_vqe_program ├── qiskit_runtime_vqe_program.ipynb └── sample_vqe.py └── vqe.ipynb /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Docs Publish 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | with: 13 | fetch-depth: 0 14 | - name: Set up Python 15 | uses: actions/setup-python@v2 16 | with: 17 | python-version: '3.7.8' 18 | - name: Install dependencies 19 | run: | 20 | python -m pip install --upgrade pip 21 | pip install -U virtualenv setuptools wheel tox 22 | sudo apt-get install -y graphviz pandoc 23 | - name: Build and publish 24 | env: 25 | encrypted_rclone_key: ${{ secrets.encrypted_rclone_key }} 26 | encrypted_rclone_iv: ${{ secrets.encrypted_rclone_iv }} 27 | run: | 28 | tools/deploy_documentation.sh 29 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: 3 | push: 4 | branches: [ main, 'stable/*' ] 5 | pull_request: 6 | branches: [ main, 'stable/*' ] 7 | 8 | jobs: 9 | tests: 10 | name: tests-python${{ matrix.python-version }}-${{ matrix.os }} 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | matrix: 14 | python-version: [3.6, 3.7, 3.8, 3.9] 15 | os: ["ubuntu-latest", "macOS-latest", "windows-latest"] 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Set up Python ${{ matrix.python-version }} 19 | uses: actions/setup-python@v2 20 | with: 21 | python-version: ${{ matrix.python-version }} 22 | - name: Pip cache 23 | uses: actions/cache@v2 24 | with: 25 | path: ~/.cache/pip 26 | key: ${{ runner.os }}-${{ matrix.python-version }}-pip-tests-${{ hashFiles('requirements.txt','requirements-dev.txt') }} 27 | restore-keys: | 28 | ${{ runner.os }}-${{ matrix.python-version }}-pip-tests- 29 | ${{ runner.os }}-${{ matrix.python-version }}-pip- 30 | ${{ runner.os }}-${{ matrix.python-version }} 31 | - name: Install Deps 32 | run: | 33 | python -m pip install -U tox setuptools virtualenv wheel 34 | - name: Install and Run Tests 35 | run: tox -e py 36 | lint: 37 | name: lint 38 | runs-on: ubuntu-latest 39 | steps: 40 | - uses: actions/checkout@v2 41 | - name: setup-python-3.7 42 | uses: actions/setup-python@v2 43 | with: 44 | python-version: 3.8 45 | - name: install-requirements 46 | run: | 47 | python -m pip install --upgrade pip tox virtualenv wheel 48 | - name: docs 49 | run: tox -e lint 50 | docs: 51 | name: docs 52 | runs-on: ubuntu-latest 53 | steps: 54 | - uses: actions/checkout@v2 55 | - name: setup-python-3.7 56 | uses: actions/setup-python@v2 57 | with: 58 | python-version: 3.7 59 | - name: install-requirements 60 | run: | 61 | sudo apt-get install -y graphviz pandoc 62 | python -m pip install --upgrade pip tox virtualenv wheel 63 | - name: docs 64 | run: tox -e docs 65 | - name: Compress Artifacts 66 | run: | 67 | mkdir artifacts 68 | tar -zcvf html_docs.tar.gz docs/_build/html 69 | mv html_docs.tar.gz artifacts/. 70 | - uses: actions/upload-artifact@v2 71 | with: 72 | name: html_docs 73 | path: artifacts 74 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # SDK config file 2 | Qconfig.py 3 | 4 | # ply outputs 5 | qiskit/qasm/parser.out 6 | 7 | # editor files 8 | .vscode/ 9 | .idea/ 10 | 11 | #standard python ignores follow 12 | 13 | # Byte-compiled / optimized / DLL files 14 | __pycache__/ 15 | .pytest_cache/ 16 | *.py[cod] 17 | *$py.class 18 | 19 | # C extensions 20 | *.so 21 | 22 | # Distribution / packaging 23 | .Python 24 | env/ 25 | build/ 26 | develop-eggs/ 27 | dist/ 28 | downloads/ 29 | eggs/ 30 | .eggs/ 31 | parts/ 32 | sdist/ 33 | var/ 34 | wheels/ 35 | *.egg-info/ 36 | .installed.cfg 37 | *.egg 38 | 39 | # PyInstaller 40 | # Usually these files are written by a python script from a template 41 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 42 | *.manifest 43 | *.spec 44 | 45 | # Installer logs 46 | pip-log.txt 47 | pip-delete-this-directory.txt 48 | 49 | # Unit test / coverage reports 50 | htmlcov/ 51 | .tox/ 52 | .coverage 53 | .coverage.* 54 | .cache 55 | nosetests.xml 56 | coverage.xml 57 | *,cover 58 | .hypothesis/ 59 | test/python/*.log 60 | test/python/*.pdf 61 | test/python/*.prof 62 | .stestr/ 63 | 64 | # Translations 65 | *.mo 66 | *.pot 67 | 68 | # Django stuff: 69 | *.log 70 | local_settings.py 71 | 72 | # Flask stuff: 73 | instance/ 74 | .webassets-cache 75 | 76 | # Scrapy stuff: 77 | .scrapy 78 | 79 | # Sphinx documentation 80 | docs/_build/ 81 | 82 | # PyBuilder 83 | target/ 84 | 85 | # Jupyter Notebook 86 | .ipynb_checkpoints 87 | 88 | # pyenv 89 | .python-version 90 | 91 | # celery beat schedule file 92 | celerybeat-schedule 93 | 94 | # SageMath parsed files 95 | *.sage.py 96 | 97 | # dotenv 98 | .env 99 | 100 | # virtualenv 101 | .venv 102 | venv/ 103 | ENV/ 104 | 105 | # Spyder project settings 106 | .spyderproject 107 | 108 | # Rope project settings 109 | .ropeproject 110 | 111 | .DS_Store 112 | 113 | dummyscripts/* 114 | 115 | token.json 116 | 117 | tutorial/rst/_build/* 118 | 119 | test/python/test_qasm_python_simulator.pdf 120 | 121 | doc/_build/* 122 | 123 | doc/**/_autodoc 124 | 125 | qiskit/bin/* 126 | 127 | test/python/test_save.json 128 | 129 | test/python/*.tex 130 | 131 | out/* 132 | 133 | # CMake generates this file on the fly 134 | qiskit/providers/local/qasm_simulator_cpp 135 | qiskit/providers/legacysimulators/qasm_simulator_cpp 136 | 137 | src/qasm-simulator-cpp/test/qubit_vector_tests 138 | 139 | *.o 140 | 141 | # Cython pass 142 | qiskit/transpiler/passes/**/cython/**/*.cpp 143 | qiskit/quantum_info/states/cython/*.cpp 144 | 145 | docs/stubs/* 146 | 147 | # Notebook testing images 148 | test/ipynb/mpl/*.png 149 | test/ipynb/mpl/*.zip 150 | test/ipynb/mpl/result_test.json 151 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | 3 | # Specify a configuration file. 4 | #rcfile= 5 | 6 | # Python code to execute, usually for sys.path manipulation such as 7 | # pygtk.require(). 8 | #init-hook= 9 | 10 | # Add files or directories to the blacklist. They should be base names, not 11 | # paths. 12 | ignore=CVS 13 | 14 | # Add files or directories matching the regex patterns to the blacklist. The 15 | # regex matches against base names, not paths. 16 | ignore-patterns= 17 | 18 | # Pickle collected data for later comparisons. 19 | persistent=yes 20 | 21 | # List of plugins (as comma separated values of python modules names) to load, 22 | # usually to register additional checkers. 23 | load-plugins=pylint.extensions.docparams, # enable checking of docstring args 24 | pylint.extensions.docstyle, # basic docstring style checks 25 | 26 | # Use multiple processes to speed up Pylint. 27 | jobs=1 28 | 29 | # Allow loading of arbitrary C extensions. Extensions are imported into the 30 | # active Python interpreter and may run arbitrary code. 31 | unsafe-load-any-extension=no 32 | 33 | # A comma-separated list of package or module names from where C extensions may 34 | # be loaded. Extensions are loading into the active Python interpreter and may 35 | # run arbitrary code 36 | extension-pkg-whitelist= 37 | 38 | 39 | [MESSAGES CONTROL] 40 | 41 | # Only show warnings with the listed confidence levels. Leave empty to show 42 | # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED 43 | confidence= 44 | 45 | # Enable the message, report, category or checker with the given id(s). You can 46 | # either give multiple identifier separated by comma (,) or put this option 47 | # multiple time (only on the command line, not in the configuration file where 48 | # it should appear only once). See also the "--disable" option for examples. 49 | enable=use-symbolic-message-instead 50 | 51 | # Disable the message, report, category or checker with the given id(s). You 52 | # can either give multiple identifiers separated by comma (,) or put this 53 | # option multiple times (only on the command line, not in the configuration 54 | # file where it should appear only once).You can also use "--disable=all" to 55 | # disable everything first and then reenable specific checks. For example, if 56 | # you want to run only the similarities checker, you can use "--disable=all 57 | # --enable=similarities". If you want to run only the classes checker, but have 58 | # no Warning level messages displayed, use"--disable=all --enable=classes 59 | # --disable=W" 60 | disable=spelling, # way too noisy 61 | no-self-use, # disabled as it is too verbose 62 | fixme, # disabled as TODOs would show up as warnings 63 | protected-access, # disabled as we don't follow the public vs private 64 | # convention strictly 65 | duplicate-code, # disabled as it is too verbose 66 | redundant-returns-doc, # for @abstractmethod, it cannot interpret "pass" 67 | # disable the "too-many/few-..." refactoring hints 68 | too-many-lines, too-many-branches, too-many-locals, too-many-nested-blocks, 69 | too-many-statements, too-many-instance-attributes, too-many-arguments, 70 | too-many-public-methods, too-few-public-methods, too-many-ancestors, 71 | unnecessary-pass, # allow for methods with just "pass", for clarity 72 | no-else-return, # relax "elif" after a clause with a return 73 | docstring-first-line-empty, # relax docstring style 74 | import-outside-toplevel, 75 | bad-continuation, bad-whitespace # differences of opinion with black 76 | 77 | 78 | 79 | 80 | [REPORTS] 81 | 82 | # Set the output format. Available formats are text, parseable, colorized, msvs 83 | # (visual studio) and html. You can also give a reporter class, eg 84 | # mypackage.mymodule.MyReporterClass. 85 | output-format=text 86 | 87 | # Put messages in a separate file for each module / package specified on the 88 | # command line instead of printing them on stdout. Reports (if any) will be 89 | # written in a file name "pylint_global.[txt|html]". This option is deprecated 90 | # and it will be removed in Pylint 2.0. 91 | files-output=no 92 | 93 | # Tells whether to display a full report or only the messages 94 | reports=yes 95 | 96 | # Python expression which should return a note less than 10 (10 is the highest 97 | # note). You have access to the variables errors warning, statement which 98 | # respectively contain the number of errors / warnings messages and the total 99 | # number of statements analyzed. This is used by the global evaluation report 100 | # (RP0004). 101 | evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) 102 | 103 | # Template used to display messages. This is a python new-style format string 104 | # used to format the message information. See doc for all details 105 | #msg-template= 106 | 107 | 108 | [BASIC] 109 | 110 | # Good variable names which should always be accepted, separated by a comma 111 | # i,j,k = typical indices 112 | # n,m = typical numbers 113 | # ex = for exceptions and errors 114 | # v,w = typical vectors 115 | # x,y,z = typical axes 116 | # _ = placeholder name 117 | # q,r,qr,cr,qc = quantum and classical registers, and quantum circuit 118 | # pi = the PI constant 119 | # op = operation iterator 120 | # b = basis iterator 121 | good-names=a,b,i,j,k,d,n,m,ex,v,w,x,y,z,Run,_,logger,q,c,r,qr,cr,qc,nd,pi,op,b,ar,br,p,cp,dt, 122 | __unittest,iSwapGate,mu 123 | 124 | # Bad variable names which should always be refused, separated by a comma 125 | bad-names=foo,bar,toto,tutu,tata 126 | 127 | # Colon-delimited sets of names that determine each other's naming style when 128 | # the name regexes allow several styles. 129 | name-group= 130 | 131 | # Include a hint for the correct naming format with invalid-name 132 | include-naming-hint=no 133 | 134 | # List of decorators that produce properties, such as abc.abstractproperty. Add 135 | # to this list to register other decorators that produce valid properties. 136 | property-classes=abc.abstractproperty 137 | 138 | # Regular expression matching correct module names 139 | module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ 140 | 141 | # Naming hint for module names 142 | module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ 143 | 144 | # Regular expression matching correct constant names 145 | const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ 146 | 147 | # Naming hint for constant names 148 | const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ 149 | 150 | # Regular expression matching correct class names 151 | class-rgx=[A-Z_][a-zA-Z0-9]+$ 152 | 153 | # Naming hint for class names 154 | class-name-hint=[A-Z_][a-zA-Z0-9]+$ 155 | 156 | # Regular expression matching correct function names 157 | function-rgx=[a-z_][a-z0-9_]{2,30}$ 158 | 159 | # Naming hint for function names 160 | function-name-hint=[a-z_][a-z0-9_]{2,30}$ 161 | 162 | # Regular expression matching correct method names 163 | method-rgx=(([a-z_][a-z0-9_]{2,49})|(assert[A-Z][a-zA-Z0-9]{2,43})|(test_[_a-zA-Z0-9]{2,}))$ 164 | 165 | # Naming hint for method names 166 | method-name-hint=[a-z_][a-z0-9_]{2,30}$ or camelCase `assert*` in tests. 167 | 168 | # Regular expression matching correct attribute names 169 | attr-rgx=[a-z_][a-z0-9_]{2,30}$ 170 | 171 | # Naming hint for attribute names 172 | attr-name-hint=[a-z_][a-z0-9_]{2,30}$ 173 | 174 | # Regular expression matching correct argument names 175 | argument-rgx=[a-z_][a-z0-9_]{2,30}|ax|dt$ 176 | 177 | # Naming hint for argument names 178 | argument-name-hint=[a-z_][a-z0-9_]{2,30}$ 179 | 180 | # Regular expression matching correct variable names 181 | variable-rgx=[a-z_][a-z0-9_]{1,30}$ 182 | 183 | # Naming hint for variable names 184 | variable-name-hint=[a-z_][a-z0-9_]{1,30}$ 185 | 186 | # Regular expression matching correct class attribute names 187 | class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ 188 | 189 | # Naming hint for class attribute names 190 | class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ 191 | 192 | # Regular expression matching correct inline iteration names 193 | inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ 194 | 195 | # Naming hint for inline iteration names 196 | inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ 197 | 198 | # Regular expression which should only match function or class names that do 199 | # not require a docstring. 200 | no-docstring-rgx=^_ 201 | 202 | # Minimum line length for functions/classes that require docstrings, shorter 203 | # ones are exempt. 204 | docstring-min-length=-1 205 | 206 | 207 | [ELIF] 208 | 209 | # Maximum number of nested blocks for function / method body 210 | max-nested-blocks=5 211 | 212 | 213 | [FORMAT] 214 | 215 | # Maximum number of characters on a single line. 216 | max-line-length=105 217 | 218 | # Regexp for a line that is allowed to be longer than the limit. 219 | ignore-long-lines=^\s*(# )??$ 220 | 221 | # Allow the body of an if to be on the same line as the test if there is no 222 | # else. 223 | single-line-if-stmt=no 224 | 225 | # List of optional constructs for which whitespace checking is disabled. `dict- 226 | # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. 227 | # `trailing-comma` allows a space between comma and closing bracket: (a, ). 228 | # `empty-line` allows space-only lines. 229 | no-space-check=trailing-comma,dict-separator 230 | 231 | # Maximum number of lines in a module 232 | max-module-lines=1000 233 | 234 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 235 | # tab). 236 | indent-string=' ' 237 | 238 | # Number of spaces of indent required inside a hanging or continued line. 239 | indent-after-paren=4 240 | 241 | # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. 242 | expected-line-ending-format= 243 | 244 | 245 | [LOGGING] 246 | 247 | # Logging modules to check that the string format arguments are in logging 248 | # function parameter format 249 | logging-modules=logging 250 | 251 | 252 | [MISCELLANEOUS] 253 | 254 | # List of note tags to take in consideration, separated by a comma. 255 | notes=FIXME,XXX,TODO 256 | 257 | 258 | [SIMILARITIES] 259 | 260 | # Minimum lines number of a similarity. 261 | min-similarity-lines=4 262 | 263 | # Ignore comments when computing similarities. 264 | ignore-comments=yes 265 | 266 | # Ignore docstrings when computing similarities. 267 | ignore-docstrings=yes 268 | 269 | # Ignore imports when computing similarities. 270 | ignore-imports=no 271 | 272 | 273 | [SPELLING] 274 | 275 | # Spelling dictionary name. Available dictionaries: none. To make it working 276 | # install python-enchant package. 277 | spelling-dict= 278 | 279 | # List of comma separated words that should not be checked. 280 | spelling-ignore-words= 281 | 282 | # A path to a file that contains private dictionary; one word per line. 283 | spelling-private-dict-file=.local-spellings 284 | 285 | # Tells whether to store unknown words to indicated private dictionary in 286 | # --spelling-private-dict-file option instead of raising a message. 287 | spelling-store-unknown-words=no 288 | 289 | 290 | [TYPECHECK] 291 | 292 | # Tells whether missing members accessed in mixin class should be ignored. A 293 | # mixin class is detected if its name ends with "mixin" (case insensitive). 294 | ignore-mixin-members=yes 295 | 296 | # List of module names for which member attributes should not be checked 297 | # (useful for modules/projects where namespaces are manipulated during runtime 298 | # and thus existing member attributes cannot be deduced by static analysis. It 299 | # supports qualified module names, as well as Unix pattern matching. 300 | ignored-modules=matplotlib.cm,numpy.random,retworkx 301 | 302 | # List of class names for which member attributes should not be checked (useful 303 | # for classes with dynamically set attributes). This supports the use of 304 | # qualified names. 305 | ignored-classes=optparse.Values,thread._local,_thread._local,QuantumCircuit 306 | 307 | # List of members which are set dynamically and missed by pylint inference 308 | # system, and so shouldn't trigger E1101 when accessed. Python regular 309 | # expressions are accepted. 310 | generated-members= 311 | 312 | # List of decorators that produce context managers, such as 313 | # contextlib.contextmanager. Add to this list to register other decorators that 314 | # produce valid context managers. 315 | contextmanager-decorators=contextlib.contextmanager 316 | 317 | 318 | [VARIABLES] 319 | 320 | # Tells whether we should check for unused import in __init__ files. 321 | init-import=no 322 | 323 | # A regular expression matching the name of dummy variables (i.e. expectedly 324 | # not used). 325 | dummy-variables-rgx=(_+[a-zA-Z0-9]*?$)|dummy 326 | 327 | # List of additional names supposed to be defined in builtins. Remember that 328 | # you should avoid to define new builtins when possible. 329 | additional-builtins= 330 | 331 | # List of strings which can identify a callback function by name. A callback 332 | # name must start or end with one of those strings. 333 | callbacks=cb_,_cb 334 | 335 | # List of qualified module names which can have objects that can redefine 336 | # builtins. 337 | redefining-builtins-modules=six.moves,future.builtins 338 | 339 | 340 | [CLASSES] 341 | 342 | # List of method names used to declare (i.e. assign) instance attributes. 343 | defining-attr-methods=__init__,__new__,setUp 344 | 345 | # List of valid names for the first argument in a class method. 346 | valid-classmethod-first-arg=cls 347 | 348 | # List of valid names for the first argument in a metaclass class method. 349 | valid-metaclass-classmethod-first-arg=mcs 350 | 351 | # List of member names, which should be excluded from the protected access 352 | # warning. 353 | exclude-protected=_asdict,_fields,_replace,_source,_make 354 | 355 | 356 | [DESIGN] 357 | 358 | # Maximum number of arguments for function / method 359 | max-args=8 360 | 361 | # Argument names that match this expression will be ignored. Default to name 362 | # with leading underscore 363 | ignored-argument-names=_.* 364 | 365 | # Maximum number of locals for function / method body 366 | max-locals=15 367 | 368 | # Maximum number of return / yield for function / method body 369 | max-returns=6 370 | 371 | # Maximum number of branch for function / method body 372 | max-branches=12 373 | 374 | # Maximum number of statements in function / method body 375 | max-statements=50 376 | 377 | # Maximum number of parents for a class (see R0901). 378 | max-parents=7 379 | 380 | # Maximum number of attributes for a class (see R0902). 381 | max-attributes=10 382 | 383 | # Minimum number of public methods for a class (see R0903). 384 | min-public-methods=2 385 | 386 | # Maximum number of public methods for a class (see R0904). 387 | max-public-methods=35 388 | 389 | # Maximum number of boolean expressions in a if statement 390 | max-bool-expr=5 391 | 392 | 393 | [IMPORTS] 394 | 395 | # Deprecated modules which should not be used, separated by a comma 396 | deprecated-modules=optparse 397 | 398 | # Create a graph of every (i.e. internal and external) dependencies in the 399 | # given file (report RP0402 must not be disabled) 400 | import-graph= 401 | 402 | # Create a graph of external dependencies in the given file (report RP0402 must 403 | # not be disabled) 404 | ext-import-graph= 405 | 406 | # Create a graph of internal dependencies in the given file (report RP0402 must 407 | # not be disabled) 408 | int-import-graph= 409 | 410 | # Force import order to recognize a module as part of the standard 411 | # compatibility libraries. 412 | known-standard-library= 413 | 414 | # Force import order to recognize a module as part of a third party library. 415 | known-third-party=enchant 416 | 417 | # Analyse import fallback blocks. This can be used to support both Python 2 and 418 | # 3 compatible code, which means that the block might have code that exists 419 | # only in one or another interpreter, leading to false positives when analysed. 420 | analyse-fallback-blocks=no 421 | 422 | 423 | [EXCEPTIONS] 424 | 425 | # Exceptions that will emit a warning when being caught. Defaults to 426 | # "Exception" 427 | overgeneral-exceptions=Exception 428 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qiskit Runtime (NOW ARCHIVED) 2 | [![License](https://img.shields.io/github/license/Qiskit/qiskit-terra.svg?style=popout-square)](https://opensource.org/licenses/Apache-2.0) 3 | 4 | > **Archived**: This repository has been merged with [qiskit-ibm-runtime](https://github.com/qiskit/qiskit-ibm-runtime) to keep documentation closer to code. This repository is archived and no longer maintained. Please use [qiskit-ibm-runtime](https://github.com/qiskit/qiskit-ibm-runtime) instead. 5 | 6 | 7 | **Qiskit Runtime** is a new architecture offered by IBM Quantum that streamlines quantum computations. 8 | It is designed to use classical compute resources to execute quantum circuits with more efficiency on quantum processors. 9 | 10 | Using Qiskit Runtime, for example, a research team at IBM Quantum was able to achieve 120x speed 11 | up in their lithium hydride simulation. For more information, see the 12 | [IBM Research blog](https://research.ibm.com/blog/120x-quantum-speedup) 13 | 14 | Qiskit Runtime allows authorized users to upload quantum programs. A quantum program, also called a 15 | Qiskit runtime program, is a piece of Python code that takes certain inputs, performs 16 | quantum and classical computation, and returns the processing results. The users can then 17 | invoke these quantum programs by simply passing in the required input parameters. 18 | 19 | --- 20 | :rocket: Qiskit Runtime is now available on all IBM Quantum systems. If `ibm-q/open/main` is the 21 | only hub/group/project in your account, then you can only execute runtime programs on 22 | `ibmq_qasm_simulator`. If you have more than one hub/group/project, you can execute runtime programs 23 | on any systems to which you have access and upload your custom programs. 24 | 25 | --- 26 | 27 | ## Installation 28 | 29 | You need to install the required packages for the tutorials, which are documented in `requirements.txt`. 30 | After that, you can download this repository and use Jupyter Notebook/Lab to explore the 31 | tutorials and learn how Qiskit Runtime works. 32 | 33 | ```bash 34 | git clone https://github.com/Qiskit-Partners/qiskit-runtime.git 35 | cd qiskit-runtime 36 | pip install -r requirements.txt 37 | 38 | cd tutorials 39 | jupyter notebook . 40 | ``` 41 | 42 | ## Executing a Qiskit Runtime program 43 | 44 | ### Configuring your IBM Quantum credentials 45 | 46 | Before you can start using Qiskit Runtime, make sure you have an [IBM Quantum](https://quantum-computing.ibm.com) 47 | account. If this is 48 | your first time using IBM Quantum or Qiskit, please refer to the instruction in the 49 | [`qiskit-ibmq-provider`](https://github.com/Qiskit/qiskit-ibmq-provider#configure-your-ibm-quantum-experience-credentials) 50 | repository to configure your IBM Quantum credentials. 51 | 52 | ### Finding available programs 53 | 54 | To list all available programs: 55 | 56 | ```python 57 | 58 | from qiskit import IBMQ 59 | 60 | IBMQ.load_account() 61 | provider = IBMQ.get_provider(hub='MY_HUB', group='MY_GROUP', project='MY_PROJECT') 62 | provider.runtime.pprint_programs() 63 | ``` 64 | 65 | `pprint_programs()` prints the metadata of all programs visible to you. A program's metadata 66 | consists of its ID, name, description, input parameters, return values, interim results, and 67 | other information that helps you to know more about the program. 68 | 69 | If you know the ID of the program you're looking for, you can also print out the metadata of just 70 | that one program: 71 | 72 | ```python 73 | print(provider.runtime.program('hello-world')) 74 | ``` 75 | 76 | The output of the code above would be: 77 | 78 | ``` 79 | hello-world: 80 | Name: hello-world 81 | Description: A sample runtime program. 82 | Creation date: 2021-07-02T13:45:13Z 83 | Update date: 2021-07-02T13:45:13Z 84 | Max execution time: 300 85 | Input parameters: 86 | Properties: 87 | - iterations: 88 | Description: Number of iterations to run. Each iteration generates a runs a random circuit. 89 | Minimum: 0 90 | Type: integer 91 | Required: True 92 | Interim results: 93 | Properties: 94 | - counts: 95 | Description: Histogram data of the circuit result. 96 | Type: object 97 | Required: False 98 | - iteration: 99 | Description: Iteration number. 100 | Type: integer 101 | Required: False 102 | Returns: 103 | Description: A string that says 'All done!'. 104 | Type: string 105 | ``` 106 | 107 | `hello-world` is a sample program used for demonstration. 108 | It takes only 1 input parameter `iterations`, which indicates how many iterations to run. 109 | For each iteration it generates and runs a random 5-qubit circuit and returns the counts as well 110 | as the iteration number as the interim results. When the program finishes, it returns the sentence 111 | `All done!`. This program has a maximum execution time of 300 seconds, after which the execution will 112 | be forcibly terminated. 113 | 114 | ### Executing the `hello-world` program 115 | 116 | Because `hello-world` provides interim results, which are results available to you while the program is 117 | still running, we want to first define a callback function that would handle these interim results: 118 | 119 | ```python 120 | def interim_result_callback(job_id, interim_result): 121 | print(f"interim result: {interim_result}") 122 | ``` 123 | 124 | When an interim result is available, this callback function will be invoked and the result data passed to it. 125 | Not all programs provide interim results, and you don't have to provide a callback even if the program you're 126 | executing does provide them. 127 | 128 | To run the `hello-world` program: 129 | 130 | ```python 131 | program_inputs = { 132 | 'iterations': 3 133 | } 134 | options = {'backend_name': 'ibmq_montreal'} 135 | job = provider.runtime.run(program_id="hello-world", 136 | options=options, 137 | inputs=program_inputs, 138 | callback=interim_result_callback 139 | ) 140 | print(f"job ID: {job.job_id()}") 141 | result = job.result() 142 | ``` 143 | 144 | ### Deleting your job 145 | 146 | While not strictly necessary, deleting unwanted jobs can help with performance when you want to query 147 | for old jobs. To delete a job: 148 | 149 | ```python 150 | provider.runtime.delete_job('JOB_ID') 151 | ``` 152 | 153 | ## Limitations 154 | 155 | ### API 156 | 157 | Qiskit Runtime is still in beta mode, and heavy modifications to both functionality and API 158 | are likely to occur. Some of the changes might not be backward compatible and would require updating 159 | your Qiskit version. 160 | 161 | ## Next Steps 162 | 163 | This README only provides a quick overview of Qiskit Runtime. Check out the 164 | [tutorials](https://github.com/Qiskit-Partners/qiskit-runtime/tree/main/tutorials). 165 | The Qiskit user interface for accessing Qiskit Runtime is provided by `qiskit-ibmq-provider`, so you 166 | might want to also check out its [runtime API documentation](https://qiskit.org/documentation/apidoc/ibmq_runtime.html). 167 | 168 | ## License 169 | 170 | [Apache License 2.0](LICENSE.txt) 171 | -------------------------------------------------------------------------------- /constraints.txt: -------------------------------------------------------------------------------- 1 | # Jinja2 3.1.0 is incompatible with sphinx and/or jupyter until they are updated 2 | # to work with the new jinja version (the jinja maintainers aren't going to 3 | # fix things) pin to the previous working version. 4 | jinja2==3.0.3 5 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # This code is part of Kaleidoscope 2 | # 3 | # (C) Copyright IBM 2020. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | # You can set these variables from the command line. 14 | SPHINXOPTS = 15 | SPHINXBUILD = sphinx-build 16 | SOURCEDIR = . 17 | BUILDDIR = _build 18 | 19 | # Put it first so that "make" without argument is like "make help". 20 | help: 21 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 22 | 23 | .PHONY: help Makefile 24 | 25 | # Catch-all target: route all unknown targets to Sphinx using the new 26 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 27 | %: Makefile 28 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 29 | -------------------------------------------------------------------------------- /docs/_static/gallery.css: -------------------------------------------------------------------------------- 1 | /* 2 | Sphinx-Gallery has compatible CSS to fix default sphinx themes 3 | Tested for Sphinx 1.3.1 for all themes: default, alabaster, sphinxdoc, 4 | scrolls, agogo, traditional, nature, haiku, pyramid 5 | Tested for Read the Docs theme 0.1.7 */ 6 | .sphx-glr-thumbcontainer { 7 | background: #fff; 8 | border: solid #fff 1px; 9 | -moz-border-radius: 5px; 10 | -webkit-border-radius: 5px; 11 | border-radius: 5px; 12 | box-shadow: none; 13 | float: left; 14 | margin: 5px; 15 | min-height: 230px; 16 | padding-top: 5px; 17 | position: relative; 18 | } 19 | .sphx-glr-thumbcontainer:hover { 20 | border: solid #6200EE 1px; 21 | box-shadow: 0 0 15px rgba(163, 142, 202, 0.5); 22 | } 23 | .sphx-glr-thumbcontainer a.internal { 24 | bottom: 0; 25 | display: block; 26 | left: 0; 27 | padding: 150px 10px 0; 28 | position: absolute; 29 | right: 0; 30 | top: 0; 31 | } 32 | /* Next one is to avoid Sphinx traditional theme to cover all the 33 | thumbnail with its default link Background color */ 34 | .sphx-glr-thumbcontainer a.internal:hover { 35 | background-color: transparent; 36 | } 37 | 38 | .sphx-glr-thumbcontainer p { 39 | margin: 0 0 .1em 0; 40 | } 41 | .sphx-glr-thumbcontainer .figure { 42 | margin: 10px; 43 | width: 160px; 44 | } 45 | .sphx-glr-thumbcontainer img { 46 | display: inline; 47 | max-height: 112px; 48 | max-width: 160px; 49 | } 50 | .sphx-glr-thumbcontainer[tooltip]:hover:after { 51 | background: rgba(0, 0, 0, 0.8); 52 | -webkit-border-radius: 5px; 53 | -moz-border-radius: 5px; 54 | border-radius: 5px; 55 | color: #fff; 56 | content: attr(tooltip); 57 | left: 95%; 58 | padding: 5px 15px; 59 | position: absolute; 60 | z-index: 98; 61 | width: 220px; 62 | bottom: 52%; 63 | } 64 | .sphx-glr-thumbcontainer[tooltip]:hover:before { 65 | border: solid; 66 | border-color: #333 transparent; 67 | border-width: 18px 0 0 20px; 68 | bottom: 58%; 69 | content: ''; 70 | left: 85%; 71 | position: absolute; 72 | z-index: 99; 73 | } 74 | 75 | .sphx-glr-script-out { 76 | color: #888; 77 | margin: 0; 78 | } 79 | p.sphx-glr-script-out { 80 | padding-top: 0.7em; 81 | } 82 | .sphx-glr-script-out .highlight { 83 | background-color: transparent; 84 | margin-left: 2.5em; 85 | margin-top: -2.1em; 86 | } 87 | .sphx-glr-script-out .highlight pre { 88 | background-color: #fafae2; 89 | border: 0; 90 | max-height: 30em; 91 | overflow: auto; 92 | padding-left: 1ex; 93 | margin: 0px; 94 | word-break: break-word; 95 | } 96 | .sphx-glr-script-out + p { 97 | margin-top: 1.8em; 98 | } 99 | blockquote.sphx-glr-script-out { 100 | margin-left: 0pt; 101 | } 102 | .sphx-glr-script-out.highlight-pytb .highlight pre { 103 | color: #000; 104 | background-color: #ffe4e4; 105 | border: 1px solid #f66; 106 | margin-top: 10px; 107 | padding: 7px; 108 | } 109 | 110 | div.sphx-glr-footer { 111 | text-align: center; 112 | } 113 | 114 | div.sphx-glr-download { 115 | margin: 1em auto; 116 | vertical-align: middle; 117 | } 118 | 119 | div.sphx-glr-download a { 120 | background-color: #ffc; 121 | background-image: linear-gradient(to bottom, #FFC, #d5d57e); 122 | border-radius: 4px; 123 | border: 1px solid #c2c22d; 124 | color: #000; 125 | display: inline-block; 126 | font-weight: bold; 127 | padding: 1ex; 128 | text-align: center; 129 | } 130 | 131 | div.sphx-glr-download code.download { 132 | display: inline-block; 133 | white-space: normal; 134 | word-break: normal; 135 | overflow-wrap: break-word; 136 | /* border and background are given by the enclosing 'a' */ 137 | border: none; 138 | background: none; 139 | } 140 | 141 | div.sphx-glr-download a:hover { 142 | box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); 143 | text-decoration: none; 144 | background-image: none; 145 | background-color: #d5d57e; 146 | } 147 | 148 | .sphx-glr-example-title > :target::before { 149 | display: block; 150 | content: ""; 151 | margin-top: -50px; 152 | height: 50px; 153 | visibility: hidden; 154 | } 155 | 156 | ul.sphx-glr-horizontal { 157 | list-style: none; 158 | padding: 0; 159 | } 160 | ul.sphx-glr-horizontal li { 161 | display: inline; 162 | } 163 | ul.sphx-glr-horizontal img { 164 | height: auto !important; 165 | } 166 | 167 | .sphx-glr-single-img { 168 | margin: auto; 169 | display: block; 170 | max-width: 100%; 171 | } 172 | 173 | .sphx-glr-multi-img { 174 | max-width: 42%; 175 | height: auto; 176 | } 177 | 178 | p.sphx-glr-signature a.reference.external { 179 | -moz-border-radius: 5px; 180 | -webkit-border-radius: 5px; 181 | border-radius: 5px; 182 | padding: 3px; 183 | font-size: 75%; 184 | text-align: right; 185 | margin-left: auto; 186 | display: table; 187 | } 188 | 189 | .sphx-glr-clear{ 190 | clear: both; 191 | } 192 | 193 | a.sphx-glr-backref-instance { 194 | text-decoration: none; 195 | } 196 | -------------------------------------------------------------------------------- /docs/_static/no_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit-Partners/qiskit-runtime/15f5712f35e942d50689ad54e352aa89cfde0901/docs/_static/no_image.png -------------------------------------------------------------------------------- /docs/_templates/autosummary/class.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline}} 2 | 3 | .. currentmodule:: {{ module }} 4 | 5 | .. autoclass:: {{ objname }} 6 | :members: 7 | {% block methods %} 8 | .. automethod:: __init__ 9 | 10 | {% if methods %} 11 | .. rubric:: {{ _('Methods') }} 12 | 13 | .. autosummary:: 14 | {% for item in methods %} 15 | {%- if item not in inherited_members %} 16 | {%- if not item.startswith('_') or item in ['__call__', '__mul__', '__getitem__', '__len__'] %} 17 | ~{{ name }}.{{ item }} 18 | {% endif %} 19 | {% endif %} 20 | {%- endfor %} 21 | {% endif %} 22 | {% endblock %} 23 | 24 | {% block attributes %} 25 | {% if attributes %} 26 | .. rubric:: {{ _('Attributes') }} 27 | 28 | .. autosummary:: 29 | {% for item in attributes %} 30 | ~{{ name }}.{{ item }} 31 | {%- endfor %} 32 | {% endif %} 33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /docs/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {# TEMPLATE VAR SETTINGS #} 2 | {%- set url_root = pathto('', 1) %} 3 | {%- if url_root == '#' %}{% set url_root = '' %}{% endif %} 4 | {%- if not embedded and docstitle %} 5 | {%- set titlesuffix = " — "|safe + docstitle|e %} 6 | {%- else %} 7 | {%- set titlesuffix = "" %} 8 | {%- endif %} 9 | {%- set lang_attr = 'en' if language == None else (language | replace('_', '-')) %} 10 | {% import 'theme_variables.jinja' as theme_variables %} 11 | 12 | 13 | 14 | 15 | 16 | 17 | {{ metatags }} 18 | 19 | {% block htmltitle %} 20 | {{ title|striptags|e }}{{ titlesuffix }} 21 | {% endblock %} 22 | 23 | {# FAVICON #} 24 | {% if favicon %} 25 | 26 | {% endif %} 27 | {# CANONICAL URL #} 28 | {% if theme_canonical_url %} 29 | 30 | {% endif %} 31 | 32 | {# CSS #} 33 | 34 | {# OPENSEARCH #} 35 | {% if not embedded %} 36 | {% if use_opensearch %} 37 | 40 | {% endif %} 41 | 42 | {% endif %} 43 | 44 | 45 | 46 | {%- for css in css_files %} 47 | {%- if css|attr("rel") %} 48 | 49 | {%- else %} 50 | 51 | {%- endif %} 52 | {%- endfor %} 53 | {%- for cssfile in extra_css_files %} 54 | 55 | {%- endfor %} 56 | 57 | {%- block linktags %} 58 | {%- if hasdoc('about') %} 59 | 60 | {%- endif %} 61 | {%- if hasdoc('genindex') %} 62 | 63 | {%- endif %} 64 | {%- if hasdoc('search') %} 65 | 66 | {%- endif %} 67 | {%- if hasdoc('copyright') %} 68 | 69 | {%- endif %} 70 | {%- if next %} 71 | 72 | {%- endif %} 73 | {%- if prev %} 74 | 75 | {%- endif %} 76 | {%- endblock %} 77 | {%- block extrahead %} {% endblock %} 78 | 79 | {# Keep modernizr in head - http://modernizr.com/docs/#installing #} 80 | 81 | 82 | 83 | 84 |
85 |
86 |
87 | 88 | 89 | 109 | 110 | 111 |
112 | 113 |
114 |
115 | 116 | 117 | 118 | 119 | {% block extrabody %} {% endblock %} 120 | 121 | {# SIDE NAV, TOGGLES ON MOBILE #} 122 | 123 | {% include "versions.html" %} 124 | 125 | 129 | 130 | 174 | 175 |
176 |
177 |
178 | {% include "breadcrumbs.html" %} 179 |
180 | 181 |
182 | Shortcuts 183 |
184 |
185 | 186 |
187 |
188 | 189 | {%- block content %} 190 | {% if theme_style_external_links|tobool %} 191 | 211 | 212 |
213 |
214 |
215 | {{ toc }} 216 |
217 |
218 |
219 |
220 |
221 | 222 | {% if not embedded %} 223 | 224 | {% if sphinx_version >= "1.8.0" %} 225 | 226 | {%- for scriptfile in script_files %} 227 | {{ js_tag(scriptfile) }} 228 | {%- endfor %} 229 | {% else %} 230 | 241 | {%- for scriptfile in script_files %} 242 | 243 | {%- endfor %} 244 | {% endif %} 245 | 246 | {% endif %} 247 | 248 | 249 | 250 | 251 | 252 | 253 | 258 | 259 | {%- block footer %} {% endblock %} 260 | 261 |
262 |
263 |
264 | 265 | 266 | 267 |
268 |
269 |
270 |
271 | 272 | 273 |
274 |
275 |
276 | 277 | 298 |
299 | 300 | 301 | 302 | 303 | 304 | 321 | 322 | 323 | -------------------------------------------------------------------------------- /docs/_templates/theme_variables.jinja: -------------------------------------------------------------------------------- 1 | {%- set external_urls = { 2 | 'github': 'https://github.com/Qiskit-Partners/qiskit-runtime', 3 | 'github_issues': 'https://github.com/Qiskit-Partners/qiskit-runtime/issues', 4 | 'contributing': 'https://github.com/Qiskit/qiskit/blob/master/CONTRIBUTING.md', 5 | 'docs': 'https://qiskit.org/documentation/', 6 | 'api': 'https://runtime-us-east.quantum-computing.ibm.com/openapi/', 7 | 'ml': 'https://qiskit.org/documentation/machine-learning/', 8 | 'nature': 'https://qiskit.org/documentation/nature/', 9 | 'finance': 'https://qiskit.org/documentation/finance/', 10 | 'optim': 'https://qiskit.org/documentation/optimization/', 11 | 'experiments': 'https://qiskit.org/documentation/experiments/', 12 | 'partners': 'https://qiskit.org/documentation/partners/', 13 | 'twitter': 'https://twitter.com/qiskit', 14 | 'events': 'https://qiskit.org/events', 15 | 'textbook': 'https://qiskit.org/textbook', 16 | 'slack': 'https://qiskit.slack.com', 17 | 'home': 'https://qiskit.org/', 18 | 'blog': 'https://pytorch.org/blog/', 19 | 'resources': 'https://qiskit.org/learn', 20 | 'support': 'https://pytorch.org/support', 21 | 'youtube': 'https://www.youtube.com/qiskit', 22 | 'iqx': 'https://quantum-computing.ibm.com/', 23 | 'iqx_systems': 'https://quantum-computing.ibm.com/docs/manage/backends/', 24 | 'ibm': 'https://www.ibm.com/quantum-computing/', 25 | } 26 | -%} 27 | -------------------------------------------------------------------------------- /docs/_templates/versions.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{ version_label }} 4 | 5 | 6 |
7 | {% if translations %} 8 |
9 |
{{ _('Languages') }}
10 | {% for code, language in translations_list %} 11 |
{{ language }}
12 | {% endfor %} 13 |
14 | {% endif %} 15 |
16 | 24 |
25 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | # pylint: disable=invalid-name 14 | # Configuration file for the Sphinx documentation builder. 15 | # 16 | # This file does only contain a selection of the most common options. For a 17 | # full list see the documentation: 18 | # http://www.sphinx-doc.org/en/master/config 19 | 20 | # -- Path setup -------------------------------------------------------------- 21 | 22 | # If extensions (or modules to document with autodoc) are in another directory, 23 | # add these directories to sys.path here. If the directory is relative to the 24 | # documentation root, use os.path.abspath to make it absolute, like shown here. 25 | # 26 | import os 27 | import sys 28 | sys.path.insert(0, os.path.abspath('.')) 29 | 30 | import re 31 | import warnings 32 | import shutil 33 | import subprocess 34 | import tempfile 35 | from distutils.dir_util import copy_tree 36 | 37 | """ 38 | Sphinx documentation builder 39 | """ 40 | 41 | # The short X.Y version 42 | version = '0.1.0' 43 | # The full version, including alpha/beta/rc tags 44 | release = '0.1.0' 45 | 46 | 47 | rst_prolog = """ 48 | .. |version| replace:: {0} 49 | """.format(version) 50 | 51 | # -- Project information ----------------------------------------------------- 52 | project = 'Qiskit runtime {}'.format(version) 53 | copyright = '2021, Qiskit development team' # pylint: disable=redefined-builtin 54 | author = 'Qiskit development team' 55 | # -- General configuration --------------------------------------------------- 56 | 57 | # If your documentation needs a minimal Sphinx version, state it here. 58 | # 59 | # needs_sphinx = '1.0' 60 | 61 | # Add any Sphinx extension module names here, as strings. They can be 62 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 63 | # ones. 64 | extensions = [ 65 | 'sphinx.ext.napoleon', 66 | 'sphinx.ext.autodoc', 67 | 'sphinx.ext.autosummary', 68 | 'sphinx.ext.mathjax', 69 | 'sphinx.ext.viewcode', 70 | 'sphinx.ext.extlinks', 71 | 'nbsphinx', 72 | 'jupyter_sphinx', 73 | 'sphinx_reredirects', 74 | ] 75 | html_static_path = ['_static'] 76 | templates_path = ['_templates'] 77 | html_css_files = ['gallery.css'] 78 | nbsphinx_timeout = 300 79 | nbsphinx_execute = 'never' 80 | nbsphinx_widgets_path = '' 81 | html_sourcelink_suffix = '' 82 | exclude_patterns = ['_build', '**.ipynb_checkpoints'] 83 | 84 | # ----------------------------------------------------------------------------- 85 | # Autosummary 86 | # ----------------------------------------------------------------------------- 87 | autosummary_generate = True 88 | 89 | # ----------------------------------------------------------------------------- 90 | # Autodoc 91 | # ----------------------------------------------------------------------------- 92 | 93 | autoclass_content = 'init' 94 | 95 | # If true, figures, tables and code-blocks are automatically numbered if they 96 | # have a caption. 97 | numfig = True 98 | 99 | # A dictionary mapping 'figure', 'table', 'code-block' and 'section' to 100 | # strings that are used for format of figure numbers. As a special character, 101 | # %s will be replaced to figure number. 102 | numfig_format = { 103 | 'table': 'Table %s' 104 | } 105 | # The language for content autogenerated by Sphinx. Refer to documentation 106 | # for a list of supported languages. 107 | # 108 | # This is also used if you do content translation via gettext catalogs. 109 | # Usually you set "language" from the command line for these cases. 110 | language = None 111 | 112 | # A boolean that decides whether module names are prepended to all object names 113 | # (for object types where a “module” of some kind is defined), e.g. for 114 | # py:function directives. 115 | add_module_names = False 116 | 117 | # A list of prefixes that are ignored for sorting the Python module index 118 | # (e.g., if this is set to ['foo.'], then foo.bar is shown under B, not F). 119 | # This can be handy if you document a project that consists of a single 120 | # package. Works only for the HTML builder currently. 121 | modindex_common_prefix = ['qiskit_runtime.'] 122 | 123 | # -- Configuration for extlinks extension ------------------------------------ 124 | # Refer to https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html 125 | 126 | 127 | # -- Options for HTML output ------------------------------------------------- 128 | 129 | # The theme to use for HTML and HTML Help pages. See the documentation for 130 | # a list of builtin themes. 131 | # 132 | html_theme = "qiskit_sphinx_theme" 133 | 134 | #html_sidebars = {'**': ['globaltoc.html']} 135 | html_last_updated_fmt = '%Y/%m/%d' 136 | 137 | html_theme_options = { 138 | 'logo_only': True, 139 | 'display_version': True, 140 | 'prev_next_buttons_location': 'bottom', 141 | 'style_external_links': True, 142 | } 143 | 144 | redirects = { 145 | "*": "https://qiskit.org/documentation/partners/qiskit_ibm_runtime/index.html" 146 | 147 | } 148 | 149 | 150 | def load_tutorials(app): 151 | dest_dir = os.path.join(app.srcdir, 'tutorials') 152 | source_dir = os.path.dirname(app.srcdir)+'/tutorials' 153 | 154 | try: 155 | copy_tree(source_dir, dest_dir) 156 | except FileNotFoundError: 157 | warnings.warn('Copy tutorials failed.', RuntimeWarning) 158 | 159 | def clean_tutorials(app, exc): 160 | tutorials_dir = os.path.join(app.srcdir, 'tutorials') 161 | shutil.rmtree(tutorials_dir) 162 | 163 | def setup(app): 164 | load_tutorials(app) 165 | app.connect('build-finished', clean_tutorials) 166 | -------------------------------------------------------------------------------- /docs/example_scripts/circuit_runner.rst: -------------------------------------------------------------------------------- 1 | ############################# 2 | Circuit runner example script 3 | ############################# 4 | 5 | 6 | .. literalinclude:: ../../qiskit_runtime/circuit_runner/circuit_runner.py 7 | :language: python -------------------------------------------------------------------------------- /docs/example_scripts/qka.rst: -------------------------------------------------------------------------------- 1 | ####################################### 2 | Quantum Kernel Alignment example script 3 | ####################################### 4 | 5 | 6 | .. literalinclude:: ../../qiskit_runtime/qka/qka.py 7 | :language: python -------------------------------------------------------------------------------- /docs/getting_started.rst: -------------------------------------------------------------------------------- 1 | 2 | ############### 3 | Getting started 4 | ############### 5 | 6 | Runtime Requirements 7 | ==================== 8 | 9 | The Qiskit Runtime requires the following packages: 10 | 11 | .. code-block:: bash 12 | 13 | qiskit-terra>=0.18.3 14 | qiskit-ibmq-provider>=0.18.0 15 | 16 | that come as part of ``qiskit>=0.32`` or can be installed individually. For usage examples 17 | see the :ref:`tutorials`. Example Runtime programs can also be found in the sidebar navigation. 18 | Additional information can be found in the 19 | `IBM Quantum Runtime documentation `_. 20 | 21 | Tutorial Requirements 22 | ====================== 23 | 24 | The tutorials in this repository require the following dependencies to run: 25 | 26 | .. literalinclude:: ../../qiskit-runtime/requirements.txt 27 | 28 | 29 | 30 | .. Hiding - Indices and tables 31 | :ref:`genindex` 32 | :ref:`modindex` 33 | :ref:`search` 34 | -------------------------------------------------------------------------------- /docs/images/runtime_arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit-Partners/qiskit-runtime/15f5712f35e942d50689ad54e352aa89cfde0901/docs/images/runtime_arch.png -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | ########################## 2 | Qiskit Runtime (|version|) 3 | ########################## 4 | 5 | .. important:: 6 | 7 | The Qiskit Runtime is currently in beta mode and is available on 8 | all IBM Quantum systems and simulators. If ``ibm-q/open/main`` is the 9 | only hub/group/project in your account, then you can only execute runtime programs on 10 | simulators. If you have more than one hub/group/project, you can execute runtime programs 11 | on any systems to which you have access, as well as upload your custom programs. 12 | 13 | The Qiskit Runtime is a new execution model / architecture that markedly reduces 14 | IO overhead when submitting applications and algorithms to quantum processors that 15 | require many iterations of circuit executions and classical processing. Programs of this 16 | category are common, and span a wide variety of application spaces including chemistry, 17 | machine learning, and optimization. 18 | 19 | .. figure:: images/runtime_arch.png 20 | :align: center 21 | 22 | In general, most users of the Qiskit Runtime execute programs that are predefined 23 | and specified using a program name and a small number of input arguments, e.g.: 24 | 25 | .. code-block:: python 26 | 27 | program_inputs = {'circuits': circuit, 28 | 'optimization_level': 3 29 | } 30 | options = {'backend_name': "ibmq_bogota"} 31 | job = provider.runtime.run(program_id="circuit-runner", 32 | options=options, 33 | inputs=program_inputs, 34 | ) 35 | 36 | It is also possible to define custom programs and upload them to the Cloud infrastructure, 37 | although access to this functionality is limited at present. 38 | 39 | For additional information and usage examples see the :ref:`tutorials` page and the 40 | `IBM Quantum Runtime documentation `_. 41 | 42 | 43 | .. toctree:: 44 | :hidden: 45 | 46 | self 47 | Getting starting 48 | Current runtime limitations 49 | 50 | 51 | .. toctree:: 52 | :maxdepth: 1 53 | :caption: Example programs 54 | :hidden: 55 | 56 | Circuit runner 57 | Quantum Kernel Alignment 58 | -------------------------------------------------------------------------------- /docs/limitations.rst: -------------------------------------------------------------------------------- 1 | .. _limitations: 2 | 3 | =================== 4 | Runtime limitations 5 | =================== 6 | 7 | - **Open-access users can only execute runtime programs on simulators.** 8 | 9 | At present, open-access users can only execute runtime programs on 10 | simulators and cannot upload custom programs. 11 | This will be relaxed in upcoming releases. 12 | 13 | 14 | .. Hiding - Indices and tables 15 | :ref:`genindex` 16 | :ref:`modindex` 17 | :ref:`search` 18 | -------------------------------------------------------------------------------- /docs/tutorials.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | .. _tutorials: 4 | 5 | ========= 6 | Tutorials 7 | ========= 8 | 9 | 10 | Basic 11 | ===== 12 | 13 | .. nbgallery:: 14 | :glob: 15 | 16 | tutorials/* 17 | 18 | 19 | 20 | In-depth 21 | ======== 22 | 23 | .. nbgallery:: 24 | :glob: 25 | 26 | tutorials/sample_vqe_program/* 27 | tutorials/sample_expval_program/* 28 | 29 | 30 | .. Hiding - Indices and tables 31 | :ref:`genindex` 32 | :ref:`modindex` 33 | :ref:`search` 34 | -------------------------------------------------------------------------------- /extras/README.md: -------------------------------------------------------------------------------- 1 | Files in this directory provide additional information about Qiskit Runtime but may not be updated 2 | regularly. 3 | -------------------------------------------------------------------------------- /extras/images/api_token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit-Partners/qiskit-runtime/15f5712f35e942d50689ad54e352aa89cfde0901/extras/images/api_token.png -------------------------------------------------------------------------------- /extras/images/ibmq_services.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit-Partners/qiskit-runtime/15f5712f35e942d50689ad54e352aa89cfde0901/extras/images/ibmq_services.png -------------------------------------------------------------------------------- /extras/images/main_function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit-Partners/qiskit-runtime/15f5712f35e942d50689ad54e352aa89cfde0901/extras/images/main_function.png -------------------------------------------------------------------------------- /extras/images/program_jobs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit-Partners/qiskit-runtime/15f5712f35e942d50689ad54e352aa89cfde0901/extras/images/program_jobs.png -------------------------------------------------------------------------------- /extras/images/qva_loop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit-Partners/qiskit-runtime/15f5712f35e942d50689ad54e352aa89cfde0901/extras/images/qva_loop.png -------------------------------------------------------------------------------- /extras/images/runtime_api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit-Partners/qiskit-runtime/15f5712f35e942d50689ad54e352aa89cfde0901/extras/images/runtime_api.png -------------------------------------------------------------------------------- /extras/images/runtime_programs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit-Partners/qiskit-runtime/15f5712f35e942d50689ad54e352aa89cfde0901/extras/images/runtime_programs.png -------------------------------------------------------------------------------- /extras/images/sample_program.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit-Partners/qiskit-runtime/15f5712f35e942d50689ad54e352aa89cfde0901/extras/images/sample_program.png -------------------------------------------------------------------------------- /extras/images/vqa_pre_runtime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit-Partners/qiskit-runtime/15f5712f35e942d50689ad54e352aa89cfde0901/extras/images/vqa_pre_runtime.png -------------------------------------------------------------------------------- /extras/images/vqa_with_runtime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit-Partners/qiskit-runtime/15f5712f35e942d50689ad54e352aa89cfde0901/extras/images/vqa_with_runtime.png -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 100 3 | target-version = ['py36', 'py37', 'py38', 'py39'] 4 | -------------------------------------------------------------------------------- /qiskit_runtime/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Main entry point for the qiskit_runtime""" 14 | 15 | 16 | try: 17 | from .version import version as __version__ 18 | except ImportError: 19 | __version__ = "0.0.0" 20 | -------------------------------------------------------------------------------- /qiskit_runtime/circuit_runner/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | Qiskit circuit runner module 15 | """ 16 | -------------------------------------------------------------------------------- /qiskit_runtime/circuit_runner/circuit_runner.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "circuit-runner", 3 | "description": "A runtime program that takes one or more circuits, compiles them, executes them, and optionally applies measurement error mitigation.", 4 | "max_execution_time": 14400, 5 | "version": "1.0", 6 | "parameters": [ 7 | {"name": "circuits", "description": "A circuit or a list of circuits.", "type": "A QuantumCircuit or a list of QuantumCircuits.", "required": true}, 8 | {"name": "shots", "description": "Number of repetitions of each circuit, for sampling. Default: 1024.", "type": "int", "required": false}, 9 | {"name": "initial_layout", "description": "Initial position of virtual qubits on physical qubits.", "type": "dict or list", "required": false}, 10 | {"name": "layout_method", "description": "Name of layout selection pass ('trivial', 'dense', 'noise_adaptive', 'sabre')", "type": "string", "required": false}, 11 | {"name": "routing_method", "description": "Name of routing pass ('basic', 'lookahead', 'stochastic', 'sabre').", "type": "string", "required": false}, 12 | {"name": "translation_method", "description": "Name of translation pass ('unroller', 'translator', 'synthesis').", "type": "string", "required": false}, 13 | {"name": "seed_transpiler", "description": "Sets random seed for the stochastic parts of the transpiler.", "type": "int", "required": false}, 14 | {"name": "optimization_level", "description": "How much optimization to perform on the circuits (0-3). Higher levels generate more optimized circuits. Default is 1.", "type": "int", "required": false}, 15 | {"name": "init_qubits", "description": "Whether to reset the qubits to the ground state for each shot.", "type": "bool", "required": false}, 16 | {"name": "rep_delay", "description": "Delay between programs in seconds.", "type": "float", "required": false}, 17 | {"name": "transpiler_options", "description": "Additional compilation options.", "type": "dict", "required": false}, 18 | {"name": "measurement_error_mitigation", "description": "Whether to apply measurement error mitigation. Default is False.", "type": "bool", "required": false} 19 | ], 20 | "return_values": [ 21 | {"name": "-", "description": "Circuit execution results.", "type": "RunnerResult object"} 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /qiskit_runtime/circuit_runner/circuit_runner.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Circuit-runner runtime program. 14 | 15 | This is a simplified version of the circuit-runner program. 16 | """ 17 | 18 | from qiskit.compiler import transpile, schedule 19 | 20 | 21 | def main( 22 | backend, 23 | user_messenger, # pylint: disable=unused-argument 24 | circuits, 25 | initial_layout=None, 26 | seed_transpiler=None, 27 | optimization_level=None, 28 | transpiler_options=None, 29 | scheduling_method=None, 30 | schedule_circuit=False, 31 | inst_map=None, 32 | meas_map=None, 33 | measurement_error_mitigation=False, 34 | **kwargs, 35 | ): 36 | """Run the circuits on the backend.""" 37 | 38 | # transpiling the circuits using given transpile options 39 | transpiler_options = transpiler_options or {} 40 | circuits = transpile( 41 | circuits, 42 | initial_layout=initial_layout, 43 | seed_transpiler=seed_transpiler, 44 | optimization_level=optimization_level, 45 | backend=backend, 46 | **transpiler_options, 47 | ) 48 | 49 | if schedule_circuit: 50 | circuits = schedule( 51 | circuits=circuits, 52 | backend=backend, 53 | inst_map=inst_map, 54 | meas_map=meas_map, 55 | method=scheduling_method, 56 | ) 57 | 58 | if not isinstance(circuits, list): 59 | circuits = [circuits] 60 | 61 | # Compute raw results 62 | result = backend.run(circuits, **kwargs).result() 63 | 64 | if measurement_error_mitigation: 65 | # Performs measurement error mitigation. 66 | pass 67 | 68 | return result.to_dict() 69 | -------------------------------------------------------------------------------- /qiskit_runtime/hello_world/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Package containing ``hello-world`` Qiskit quantum program.""" 14 | -------------------------------------------------------------------------------- /qiskit_runtime/hello_world/hello_world.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello-world", 3 | "description": "A sample runtime program.", 4 | "max_execution_time": 300, 5 | "spec": { 6 | "backend_requirements": { 7 | "min_num_qubits": 5 8 | }, 9 | "parameters": { 10 | "$schema": "https://json-schema.org/draft/2019-09/schema", 11 | "properties": { 12 | "iterations": { 13 | "type": "integer", 14 | "minimum": 0, 15 | "description": "Number of iterations to run. Each iteration generates a runs a random circuit." 16 | } 17 | }, 18 | "required": [ 19 | "iterations" 20 | ] 21 | }, 22 | "return_values": { 23 | "$schema": "https://json-schema.org/draft/2019-09/schema", 24 | "description": "A string that says 'All done!'.", 25 | "type": "string" 26 | }, 27 | "interim_results": { 28 | "$schema": "https://json-schema.org/draft/2019-09/schema", 29 | "properties": { 30 | "iteration": { 31 | "type": "integer", 32 | "description": "Iteration number." 33 | }, 34 | "counts": { 35 | "description": "Histogram data of the circuit result.", 36 | "type": "object" 37 | } 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /qiskit_runtime/hello_world/hello_world.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """A sample runtime program called hello-world that submits random circuits 14 | for user-specified iterations. 15 | """ 16 | 17 | import random 18 | from typing import Any 19 | 20 | from qiskit import transpile 21 | from qiskit.circuit.random import random_circuit 22 | 23 | 24 | def prepare_circuits(backend): 25 | """Generate a random circuit. 26 | 27 | Args: 28 | backend (qiskit.providers.Backend): Backend used for transpilation. 29 | 30 | Returns: 31 | qiskit.QuantumCircuit: Generated circuit. 32 | """ 33 | circuit = random_circuit(num_qubits=5, depth=4, measure=True, seed=random.randint(0, 1000)) 34 | return transpile(circuit, backend) 35 | 36 | 37 | def main(backend, user_messenger, **kwargs) -> Any: 38 | """Main entry point of the program. 39 | 40 | Args: 41 | backend (qiskit.providers.Backend): Backend to submit the circuits to. 42 | user_messenger (qiskit.providers.ibmq.runtime.UserMessenger): Used to communicate with the 43 | program consumer. 44 | kwargs: User inputs. 45 | 46 | Returns: 47 | Final result of the program. 48 | """ 49 | iterations = kwargs.pop("iterations", 1) 50 | for it in range(iterations): 51 | qc = prepare_circuits(backend) 52 | result = backend.run(qc).result() 53 | user_messenger.publish({"iteration": it, "counts": result.get_counts()}) 54 | 55 | return "All done!" 56 | -------------------------------------------------------------------------------- /qiskit_runtime/qaoa/qaoa_metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "qaoa", 3 | "description": "Qiskit Runtime QAOA program", 4 | "max_execution_time": 18000, 5 | "spec": { 6 | "parameters": { 7 | "$schema": "https://json-schema.org/draft/2019-09/schema", 8 | "properties": { 9 | "operator": { 10 | "description": "The cost Hamiltonian, consisting of Pauli I and Z operators, whose smallest eigenvalue we're trying to find. The type must be a PauliSumOp.", 11 | "type": "object" 12 | }, 13 | "optimizer": { 14 | "description": "The classical optimizer used to update the parameters in each iteration. Per default, SPSA with automatic calibration of the learning rate is used. The type must be a qiskit.algorithms.optimizers.Optimizer.", 15 | "type": "object" 16 | }, 17 | "initial_point": { 18 | "description": "Initial parameters of the ansatz. Can be an array or the string ``'random'`` to choose random initial parameters. The type must be numpy.ndarray or str.", 19 | "type": [ 20 | "array", 21 | "string" 22 | ] 23 | }, 24 | "aux_operators": { 25 | "description": "A list of operators to be evaluated at the final, optimized state. This must be a List[PauliSumOp].", 26 | "type": "array" 27 | }, 28 | "reps": { 29 | "description": "The number of QAOA repetitions, i.e. the QAOA depth typically labeled p. This value defaults to 1. This is an integer.", 30 | "type": "integer", 31 | "default": 1 32 | }, 33 | "shots": { 34 | "description": "The integer number of shots used for each circuit evaluation. Defaults to 1024.", 35 | "type": "integer", 36 | "default": 1024 37 | }, 38 | "alpha": { 39 | "description": "The fraction of top measurement samples to be used for the expectation value (CVaR expectation). Defaults to 1, i.e. using all samples to construct the expectation value.", 40 | "type": "number" 41 | }, 42 | "measurement_error_mitigation": { 43 | "description": "Whether to apply measurement error mitigation in form of a tensored measurement fitter to the measurements. Defaults to False.", 44 | "type": "boolean", 45 | "default": false 46 | }, 47 | "use_swap_strategies": { 48 | "description": "A boolean on whether or not to use swap strategies when transpiling. This flag is set to True by default. If this is False then the standard transpiler with the given optimization level will run.", 49 | "type": "boolean", 50 | "default": true 51 | }, 52 | "use_pulse_efficient": { 53 | "description": "A boolean on whether or not to use a pulse-efficient transpilation. This flag is set to False by default.", 54 | "type": "boolean", 55 | "default": false 56 | }, 57 | "optimization_level": { 58 | "description": "The optimization level to run if the swap strategies are not used. This value is 1 by default. This is an integer.", 59 | "type": "integer", 60 | "default": 1 61 | }, 62 | "use_initial_mapping": { 63 | "description": "A boolean flag that, if set to True (the default is False), runs a heuristic algorithm to permute the Paulis in the cost operator to better fit the coupling map and the swap strategy. This is only needed when the optimization problem is sparse and when using swap strategies to transpile.", 64 | "type": "boolean", 65 | "default": false 66 | } 67 | }, 68 | "required": [ 69 | "operator" 70 | ] 71 | }, 72 | "return_values": { 73 | "$schema": "https://json-schema.org/draft/2019-09/schema", 74 | "properties": { 75 | "optimizer_time": { 76 | "description": "The total time taken by the optimizer.", 77 | "type": "number" 78 | }, 79 | "optimal_value": { 80 | "description": "The smallest value found during the optimization. Equal to the ``eigenvalue`` attribute.", 81 | "type": "number" 82 | }, 83 | "optimal_point": { 84 | "description": "The optimal parameter values found during the optimization.", 85 | "type": "array" 86 | }, 87 | "optimal_parameters": { 88 | "description": "Not supported at the moment, therefore ``None``.", 89 | "type": "null" 90 | }, 91 | "cost_function_evals": { 92 | "description": "The number of cost function (energy) evaluations. This is an integer.", 93 | "type": "number" 94 | }, 95 | "eigenstate": { 96 | "description": "The square root of sampling probabilities for each computational basis state of the circuit with optimal parameters.", 97 | "type": "object" 98 | }, 99 | "eigenvalue": { 100 | "description": "The estimated smallest eigenvalue.", 101 | "type": "number" 102 | }, 103 | "aux_operator_eigenvalues": { 104 | "description": "The expectation values of the auxiliary operators at the optimal state.", 105 | "type": "array" 106 | }, 107 | "optimizer_history": { 108 | "description": "A dictionary containing information about the optimization process: the value objective function, parameters, and a timestamp. The type is Dict[str, Any].", 109 | "type": "object" 110 | }, 111 | "inputs": { 112 | "description": "A dictionary of the serialized input keyword arguments. The type is Dict[str, Any].", 113 | "type": "object" 114 | } 115 | } 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /qiskit_runtime/qka/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """ 14 | Quantum Kernel Alignment modules 15 | ================================ 16 | 17 | .. currentmodule:: qiskit_runtime.qka 18 | 19 | Aux files 20 | --------- 21 | 22 | The ``aux_file`` directory contains datasets for binary classification. 23 | 24 | KernelMatrix class 25 | ------------------ 26 | 27 | .. autosummary:: 28 | :toctree: ../stubs/ 29 | 30 | KernelMatrix 31 | 32 | FeatureMap class 33 | ------------------ 34 | 35 | .. autosummary:: 36 | :toctree: ../stubs/ 37 | 38 | FeatureMap 39 | 40 | """ 41 | 42 | from .kernel_matrix import KernelMatrix 43 | from .featuremaps import FeatureMap 44 | -------------------------------------------------------------------------------- /qiskit_runtime/qka/featuremaps.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """The FeatureMap class.""" 14 | 15 | import json 16 | 17 | import numpy as np 18 | 19 | from qiskit import QuantumCircuit, QuantumRegister 20 | 21 | 22 | class FeatureMap: 23 | """Mapping data with the feature map.""" 24 | 25 | def __init__(self, feature_dimension, entangler_map=None): 26 | """ 27 | Args: 28 | feature_dimension (int): number of features (twice the number of qubits for this 29 | encoding) 30 | entangler_map (list[list]): connectivity of qubits with a list of [source, target], 31 | or None for full entanglement. Note that the order in the list is the order of 32 | applying the two-qubit gate. 33 | 34 | Raises: 35 | ValueError: If the value of ``feature_dimension`` is odd. 36 | """ 37 | 38 | if isinstance(feature_dimension, int): 39 | if feature_dimension % 2 == 0: 40 | self._feature_dimension = feature_dimension 41 | else: 42 | raise ValueError("Feature dimension must be an even integer.") 43 | else: 44 | raise ValueError("Feature dimension must be an even integer.") 45 | 46 | self._num_qubits = int(feature_dimension / 2) 47 | 48 | if entangler_map is None: 49 | self._entangler_map = [ 50 | [i, j] for i in range(self._num_qubits) for j in range(i + 1, self._num_qubits) 51 | ] 52 | else: 53 | self._entangler_map = entangler_map 54 | 55 | self._num_parameters = self._num_qubits 56 | 57 | def construct_circuit(self, x=None, parameters=None, q=None, inverse=False, name=None): 58 | """Construct the feature map circuit. 59 | 60 | Args: 61 | x (numpy.ndarray): data vector of size feature_dimension 62 | parameters (numpy.ndarray): optional parameters in feature map 63 | q (QauntumRegister): the QuantumRegister object for the circuit 64 | inverse (bool): whether or not to invert the circuit 65 | name (str): The name to use for the constructed ``QuantumCircuit`` object 66 | 67 | Returns: 68 | QuantumCircuit: a quantum circuit transforming data x 69 | 70 | Raises: 71 | ValueError: If the input parameters or vector are invalid 72 | """ 73 | 74 | if parameters is not None: 75 | if isinstance(parameters, (int, float)): 76 | raise ValueError("Parameters must be a list.") 77 | if len(parameters) == 1: 78 | parameters = parameters * np.ones(self._num_qubits) 79 | else: 80 | if len(parameters) != self._num_parameters: 81 | raise ValueError( 82 | "The number of feature map parameters must be {}.".format( 83 | self._num_parameters 84 | ) 85 | ) 86 | 87 | if len(x) != self._feature_dimension: 88 | raise ValueError( 89 | "The input vector must be of length {}.".format(self._feature_dimension) 90 | ) 91 | 92 | if q is None: 93 | q = QuantumRegister(self._num_qubits, name="q") 94 | 95 | circuit = QuantumCircuit(q, name=name) 96 | 97 | for i in range(self._num_qubits): 98 | circuit.ry(-parameters[i], q[i]) 99 | 100 | for source, target in self._entangler_map: 101 | circuit.cz(q[source], q[target]) 102 | 103 | for i in range(self._num_qubits): 104 | circuit.rz(-2 * x[2 * i + 1], q[i]) 105 | circuit.rx(-2 * x[2 * i], q[i]) 106 | 107 | if inverse: 108 | return circuit.inverse() 109 | else: 110 | return circuit 111 | 112 | def to_json(self): 113 | """Return JSON representation of this object. 114 | 115 | Returns: 116 | str: JSON string representing this object. 117 | """ 118 | return json.dumps( 119 | {"feature_dimension": self._feature_dimension, "entangler_map": self._entangler_map} 120 | ) 121 | 122 | @classmethod 123 | def from_json(cls, data): 124 | """Return an instance of this class from the JSON representation. 125 | 126 | Args: 127 | data (str): JSON string representing an object. 128 | 129 | Returns: 130 | FeatureMap: An instance of this class. 131 | """ 132 | return cls(**json.loads(data)) 133 | -------------------------------------------------------------------------------- /qiskit_runtime/qka/kernel_matrix.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """The KernelMatrix class.""" 14 | 15 | import itertools 16 | 17 | import numpy as np 18 | 19 | from qiskit.compiler import transpile 20 | 21 | 22 | class KernelMatrix: 23 | """Build the kernel matrix from a quantum feature map.""" 24 | 25 | def __init__(self, feature_map, backend, initial_layout=None): 26 | """ 27 | Args: 28 | feature_map (int): the feature map object 29 | backend (Backend): the backend instance 30 | initial layout (list or dict): initial position of virtual qubits on the physical 31 | qubits of the quantum device 32 | """ 33 | 34 | self._feature_map = feature_map 35 | self._feature_map_circuit = self._feature_map.construct_circuit # the feature map circuit 36 | self._backend = backend 37 | self._initial_layout = initial_layout 38 | 39 | self.results = {} # store the results object (program_data) 40 | 41 | def construct_kernel_matrix(self, x1_vec, x2_vec, parameters=None): 42 | """Create the kernel matrix for a given feature map and input data. 43 | 44 | With the qasm simulator or real backends, compute order 'n^2' 45 | states Phi^dag(y)Phi(x)|0> for input vectors x and y. 46 | 47 | Args: 48 | x1_vec (numpy.ndarray): NxD array of training data or test data, where N is the 49 | number of samples and D is the feature dimension 50 | x2_vec (numpy.ndarray): MxD array of training data or support vectors, where M 51 | is the number of samples and D is the feature dimension 52 | parameters (numpy.ndarray): optional parameters in feature map 53 | 54 | Returns: 55 | numpy.ndarray: the kernel matrix 56 | """ 57 | 58 | is_identical = False 59 | if np.array_equal(x1_vec, x2_vec): 60 | is_identical = True 61 | 62 | experiments = [] 63 | 64 | measurement_basis = "0" * self._feature_map._num_qubits 65 | 66 | if is_identical: 67 | 68 | my_product_list = list( 69 | itertools.combinations(range(len(x1_vec)), 2) 70 | ) # all pairwise combos of datapoint indices 71 | for index_1, index_2 in my_product_list: 72 | 73 | circuit_1 = self._feature_map_circuit( 74 | x=x1_vec[index_1], parameters=parameters, name="{}_{}".format(index_1, index_2) 75 | ) 76 | circuit_2 = self._feature_map_circuit( 77 | x=x1_vec[index_2], parameters=parameters, inverse=True 78 | ) 79 | circuit = circuit_1.compose(circuit_2) 80 | circuit.measure_all() 81 | 82 | experiments.append(circuit) 83 | 84 | program_data = self._run_circuits(experiments) 85 | self.results["program_data"] = program_data 86 | 87 | mat = np.eye( 88 | len(x1_vec), len(x1_vec) 89 | ) # kernel matrix element on the diagonal is always 1 90 | for experiment, [index_1, index_2] in enumerate(my_product_list): 91 | 92 | counts = program_data.get_counts(experiment=experiment) 93 | shots = sum(counts.values()) 94 | 95 | mat[index_1][index_2] = ( 96 | counts.get(measurement_basis, 0) / shots 97 | ) # kernel matrix element is the probability of measuring all 0s 98 | mat[index_2][index_1] = mat[index_1][index_2] # kernel matrix is symmetric 99 | 100 | return mat 101 | 102 | else: 103 | 104 | for index_1, point_1 in enumerate(x1_vec): 105 | for index_2, point_2 in enumerate(x2_vec): 106 | 107 | circuit_1 = self._feature_map_circuit( 108 | x=point_1, parameters=parameters, name="{}_{}".format(index_1, index_2) 109 | ) 110 | circuit_2 = self._feature_map_circuit( 111 | x=point_2, parameters=parameters, inverse=True 112 | ) 113 | circuit = circuit_1.compose(circuit_2) 114 | circuit.measure_all() 115 | 116 | experiments.append(circuit) 117 | 118 | program_data = self._run_circuits(experiments) 119 | self.results["program_data"] = program_data 120 | 121 | mat = np.zeros((len(x1_vec), len(x2_vec))) 122 | i = 0 123 | for index_1, _ in enumerate(x1_vec): 124 | for index_2, _ in enumerate(x2_vec): 125 | 126 | counts = program_data.get_counts(experiment=i) 127 | shots = sum(counts.values()) 128 | 129 | mat[index_1][index_2] = counts.get(measurement_basis, 0) / shots 130 | i += 1 131 | 132 | return mat 133 | 134 | def _run_circuits(self, circuits): 135 | """Execute the input circuits.""" 136 | 137 | transpiled = transpile(circuits, backend=self._backend, initial_layout=self._initial_layout) 138 | return self._backend.run(transpiled, shots=8192).result() 139 | -------------------------------------------------------------------------------- /qiskit_runtime/qka/qka.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "quantum-kernel-alignment", 3 | "description": "Quantum kernel alignment algorithm that learns, on a given dataset, a quantum kernel maximizing the SVM classification margin.", 4 | "max_execution_time": 28800, 5 | "version": "1.0", 6 | "parameters": [ 7 | {"name": "feature_map", "description": "An instance of FeatureMap in dictionary format used to map classical data into a quantum state space.", "type": "dict", "required": true}, 8 | {"name": "data", "description": "NxD array of training data, where N is the number of samples and D is the feature dimension.", "type": "numpy.ndarray", "required": true}, 9 | {"name": "labels", "description": "Nx1 array of +/-1 labels of the N training samples.", "type": "numpy.ndarray", "required": true}, 10 | {"name": "initial_kernel_parameters", "description": "Initial parameters of the quantum kernel. If not specified, an array of randomly generated numbers is used.", "type": "numpy.ndarray", "required": false}, 11 | {"name": "maxiters", "description": "Number of SPSA optimization steps. Default is 1.", "type": "int", "required": false}, 12 | {"name": "C", "description": "Penalty parameter for the soft-margin support vector machine. Default is 1.", "type": "float", "required": false}, 13 | {"name": "initial_layout", "description": "Initial position of virtual qubits on the physical qubits of the quantum device. Default is None.", "type": "list or dict", "required": false} 14 | ], 15 | "return_values": [ 16 | {"name": "aligned_kernel_parameters", "description": "The optimized kernel parameters found from quantum kernel alignment.", "type": "numpy.ndarray"}, 17 | {"name": "aligned_kernel_matrix", "description": "The aligned quantum kernel matrix evaluated with the optimized kernel parameters on the training data.", "type": "numpy.ndarray"} 18 | ] 19 | } -------------------------------------------------------------------------------- /qiskit_runtime/qka/qka.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Source code for the QKA Qiskit Runtime program.""" 14 | 15 | # pylint: disable=invalid-name 16 | 17 | import itertools 18 | import json 19 | import numpy as np 20 | from numpy.random import RandomState 21 | from qiskit import QuantumCircuit, QuantumRegister 22 | from qiskit.compiler import transpile 23 | from cvxopt import matrix, solvers # pylint: disable=import-error 24 | 25 | 26 | class FeatureMap: 27 | """Mapping data with the feature map.""" 28 | 29 | def __init__(self, feature_dimension, entangler_map=None): 30 | """ 31 | Args: 32 | feature_dimension (int): number of features, twice the number 33 | of qubits for this encoding 34 | entangler_map (list[list]): connectivity of qubits with a list of [source, target], 35 | or None for full entanglement. Note that the order in 36 | the list is the order of applying the two-qubit gate. 37 | Raises: 38 | ValueError: If the value of ``feature_dimension`` is not an even integer. 39 | """ 40 | 41 | if isinstance(feature_dimension, int): 42 | if feature_dimension % 2 == 0: 43 | self._feature_dimension = feature_dimension 44 | else: 45 | raise ValueError("Feature dimension must be an even integer.") 46 | else: 47 | raise ValueError("Feature dimension must be an even integer.") 48 | 49 | self._num_qubits = int(feature_dimension / 2) 50 | 51 | if entangler_map is None: 52 | self._entangler_map = [ 53 | [i, j] 54 | for i in range(self._feature_dimension) 55 | for j in range(i + 1, self._feature_dimension) 56 | ] 57 | else: 58 | self._entangler_map = entangler_map 59 | 60 | self._num_parameters = self._num_qubits 61 | 62 | def construct_circuit(self, x=None, parameters=None, q=None, inverse=False, name=None): 63 | """Construct the feature map circuit. 64 | 65 | Args: 66 | x (numpy.ndarray): data vector of size feature_dimension 67 | parameters (numpy.ndarray): optional parameters in feature map 68 | q (QauntumRegister): the QuantumRegister object for the circuit 69 | inverse (bool): whether or not to invert the circuit 70 | name (str): name of circuit 71 | 72 | Returns: 73 | QuantumCircuit: a quantum circuit transforming data x 74 | Raises: 75 | ValueError: If the input parameters or vector are invalid 76 | """ 77 | 78 | if parameters is not None: 79 | if isinstance(parameters, (int, float)): 80 | raise ValueError("Parameters must be a list.") 81 | if len(parameters) == 1: 82 | parameters = parameters * np.ones(self._num_qubits) 83 | else: 84 | if len(parameters) != self._num_parameters: 85 | raise ValueError( 86 | "The number of feature map parameters must be {}.".format( 87 | self._num_parameters 88 | ) 89 | ) 90 | 91 | if len(x) != self._feature_dimension: 92 | raise ValueError( 93 | "The input vector must be of length {}.".format(self._feature_dimension) 94 | ) 95 | 96 | if q is None: 97 | q = QuantumRegister(self._num_qubits, name="q") 98 | 99 | circuit = QuantumCircuit(q, name=name) 100 | 101 | for i in range(self._num_qubits): 102 | circuit.ry(-parameters[i], q[i]) 103 | 104 | for source, target in self._entangler_map: 105 | circuit.cz(q[source], q[target]) 106 | 107 | for i in range(self._num_qubits): 108 | circuit.rz(-2 * x[2 * i + 1], q[i]) 109 | circuit.rx(-2 * x[2 * i], q[i]) 110 | 111 | if inverse: 112 | return circuit.inverse() 113 | else: 114 | return circuit 115 | 116 | def to_json(self): 117 | """Return JSON representation of this object. 118 | 119 | Returns: 120 | str: JSON string representing this object. 121 | """ 122 | return json.dumps( 123 | {"feature_dimension": self._feature_dimension, "entangler_map": self._entangler_map} 124 | ) 125 | 126 | @classmethod 127 | def from_json(cls, data): 128 | """Return an instance of this class from the JSON representation. 129 | 130 | Args: 131 | data (str): JSON string representing an object. 132 | 133 | Returns: 134 | cls: An instance of this class. 135 | """ 136 | return cls(**json.loads(data)) 137 | 138 | 139 | class KernelMatrix: 140 | """Build the kernel matrix from a quantum feature map.""" 141 | 142 | def __init__(self, feature_map, backend, initial_layout=None): 143 | """ 144 | Args: 145 | feature_map: the feature map object 146 | backend (Backend): the backend instance 147 | initial_layout (list or dict): initial position of virtual 148 | qubits on the physical qubits 149 | of the quantum device 150 | """ 151 | 152 | self._feature_map = feature_map 153 | self._feature_map_circuit = self._feature_map.construct_circuit 154 | self._backend = backend 155 | self._initial_layout = initial_layout 156 | 157 | self.results = {} 158 | 159 | def construct_kernel_matrix(self, x1_vec, x2_vec, parameters=None): 160 | """Create the kernel matrix for a given feature map and input data. 161 | 162 | With the qasm simulator or real backends, compute order 'n^2' 163 | states Phi^dag(y)Phi(x)|0> for input vectors x and y. 164 | 165 | Args: 166 | x1_vec (numpy.ndarray): NxD array of training data or test data, 167 | where N is the number of samples 168 | and D is the feature dimension 169 | x2_vec (numpy.ndarray): MxD array of training data or support 170 | vectors, where M is the number of samples 171 | and D is the feature dimension 172 | parameters (numpy.ndarray): optional parameters in feature map 173 | 174 | Returns: 175 | numpy.ndarray: the kernel matrix 176 | """ 177 | 178 | is_identical = False 179 | if np.array_equal(x1_vec, x2_vec): 180 | is_identical = True 181 | 182 | experiments = [] 183 | 184 | measurement_basis = "0" * self._feature_map._num_qubits 185 | 186 | if is_identical: 187 | 188 | my_product_list = list( 189 | itertools.combinations(range(len(x1_vec)), 2) 190 | ) # all pairwise combos of datapoint indices 191 | 192 | for index_1, index_2 in my_product_list: 193 | 194 | circuit_1 = self._feature_map_circuit( 195 | x=x1_vec[index_1], parameters=parameters, name="{}_{}".format(index_1, index_2) 196 | ) 197 | circuit_2 = self._feature_map_circuit( 198 | x=x1_vec[index_2], parameters=parameters, inverse=True 199 | ) 200 | circuit = circuit_1.compose(circuit_2) 201 | circuit.measure_all() 202 | experiments.append(circuit) 203 | 204 | experiments = transpile( 205 | experiments, backend=self._backend, initial_layout=self._initial_layout 206 | ) 207 | program_data = self._backend.run(experiments, shots=8192).result() 208 | 209 | self.results["program_data"] = program_data 210 | 211 | mat = np.eye( 212 | len(x1_vec), len(x1_vec) 213 | ) # kernel matrix element on the diagonal is always 1 214 | for experiment, [index_1, index_2] in enumerate(my_product_list): 215 | 216 | counts = program_data.get_counts(experiment=experiment) 217 | shots = sum(counts.values()) 218 | 219 | mat[index_1][index_2] = ( 220 | counts.get(measurement_basis, 0) / shots 221 | ) # kernel matrix element is the probability of measuring all 0s 222 | mat[index_2][index_1] = mat[index_1][index_2] # kernel matrix is symmetric 223 | 224 | return mat 225 | 226 | else: 227 | 228 | for index_1, point_1 in enumerate(x1_vec): 229 | for index_2, point_2 in enumerate(x2_vec): 230 | 231 | circuit_1 = self._feature_map_circuit( 232 | x=point_1, parameters=parameters, name="{}_{}".format(index_1, index_2) 233 | ) 234 | circuit_2 = self._feature_map_circuit( 235 | x=point_2, parameters=parameters, inverse=True 236 | ) 237 | circuit = circuit_1.compose(circuit_2) 238 | circuit.measure_all() 239 | experiments.append(circuit) 240 | 241 | experiments = transpile( 242 | experiments, backend=self._backend, initial_layout=self._initial_layout 243 | ) 244 | program_data = self._backend.run(experiments, shots=8192).result() 245 | 246 | self.results["program_data"] = program_data 247 | 248 | mat = np.zeros((len(x1_vec), len(x2_vec))) 249 | i = 0 250 | for index_1, _ in enumerate(x1_vec): 251 | for index_2, _ in enumerate(x2_vec): 252 | 253 | counts = program_data.get_counts(experiment=i) 254 | shots = sum(counts.values()) 255 | 256 | mat[index_1][index_2] = counts.get(measurement_basis, 0) / shots 257 | i += 1 258 | 259 | return mat 260 | 261 | 262 | class QKA: 263 | """The quantum kernel alignment algorithm.""" 264 | 265 | def __init__(self, feature_map, backend, initial_layout=None, user_messenger=None): 266 | """Constructor. 267 | 268 | Args: 269 | feature_map (partial obj): the quantum feature map object 270 | backend (Backend): the backend instance 271 | initial_layout (list or dict): initial position of virtual qubits on 272 | the physical qubits of the quantum device 273 | user_messenger (UserMessenger): used to publish interim results. 274 | """ 275 | 276 | self.feature_map = feature_map 277 | self.feature_map_circuit = self.feature_map.construct_circuit 278 | self.backend = backend 279 | self.initial_layout = initial_layout 280 | self.num_parameters = self.feature_map._num_parameters 281 | 282 | self._user_messenger = user_messenger 283 | self.result = {} 284 | self.kernel_matrix = KernelMatrix( 285 | feature_map=self.feature_map, backend=self.backend, initial_layout=self.initial_layout 286 | ) 287 | 288 | def spsa_parameters(self): 289 | """Return array of precomputed SPSA parameters. 290 | 291 | The i-th optimization step, i>=0, the parameters evolve as 292 | 293 | a_i = a / (i + 1 + A) ** alpha, 294 | c_i = c / (i + 1) ** gamma, 295 | 296 | for fixed coefficents a, c, alpha, gamma, A. 297 | 298 | Returns: 299 | numpy.ndarray: spsa parameters 300 | """ 301 | spsa_params = np.zeros((5)) 302 | spsa_params[0] = 0.05 # a 303 | spsa_params[1] = 0.1 # c 304 | spsa_params[2] = 0.602 # alpha 305 | spsa_params[3] = 0.101 # gamma 306 | spsa_params[4] = 0 # A 307 | 308 | return spsa_params 309 | 310 | def cvxopt_solver(self, K, y, C, max_iters=10000, show_progress=False): 311 | """Convex optimization of SVM objective using cvxopt. 312 | 313 | Args: 314 | K (numpy.ndarray): nxn kernel (Gram) matrix 315 | y (numpy.ndarray): nx1 vector of labels +/-1 316 | C (float): soft-margin penalty 317 | max_iters (int): maximum iterations for the solver 318 | show_progress (bool): print progress of solver 319 | 320 | Returns: 321 | dict: results from the solver 322 | """ 323 | 324 | if y.ndim == 1: 325 | y = y[:, np.newaxis] 326 | H = np.outer(y, y) * K 327 | f = -np.ones(y.shape) 328 | 329 | n = K.shape[1] # number of training points 330 | 331 | y = y.astype("float") 332 | 333 | P = matrix(H) 334 | q = matrix(f) 335 | G = matrix(np.vstack((-np.eye((n)), np.eye((n))))) 336 | h = matrix(np.vstack((np.zeros((n, 1)), np.ones((n, 1)) * C))) 337 | A = matrix(y, y.T.shape) 338 | b = matrix(np.zeros(1), (1, 1)) 339 | 340 | solvers.options["maxiters"] = max_iters 341 | solvers.options["show_progress"] = show_progress 342 | 343 | ret = solvers.qp(P, q, G, h, A, b, kktsolver="ldl") 344 | 345 | return ret 346 | 347 | def spsa_step_one(self, lambdas, spsa_params, count): 348 | """Evaluate +/- perturbations of kernel parameters (lambdas). 349 | 350 | Args: 351 | lambdas (numpy.ndarray): kernel parameters at step 'count' in SPSA optimization loop 352 | spsa_params (numpy.ndarray): SPSA parameters 353 | count (int): the current step in the SPSA optimization loop 354 | 355 | Returns: 356 | numpy.ndarray: kernel parameters in + direction 357 | numpy.ndarray: kernel parameters in - direction 358 | numpy.ndarray: random vector with elements {-1,1} 359 | """ 360 | 361 | prng = RandomState(count) 362 | 363 | c_spsa = float(spsa_params[1]) / np.power(count + 1, spsa_params[3]) 364 | delta = 2 * prng.randint(0, 2, size=np.shape(lambdas)[0]) - 1 365 | 366 | lambda_plus = lambdas + c_spsa * delta 367 | lambda_minus = lambdas - c_spsa * delta 368 | 369 | return lambda_plus, lambda_minus, delta 370 | 371 | def spsa_step_two(self, cost_plus, cost_minus, lambdas, spsa_params, delta, count): 372 | """Evaluate one iteration of SPSA on SVM objective function F and 373 | return updated kernel parameters. 374 | 375 | F(alpha, lambda) = 1^T * alpha - (1/2) * alpha^T * Y * K * Y * alpha 376 | 377 | Args: 378 | cost_plus (float): objective function F(alpha_+, lambda_+) 379 | cost_minus (float): objective function F(alpha_-, lambda_-) 380 | lambdas (numpy.ndarray): kernel parameters at step 'count' in SPSA optimization loop 381 | spsa_params (numpy.ndarray): SPSA parameters 382 | delta (numpy.ndarray): random vector with elements {-1,1} 383 | count(int): the current step in the SPSA optimization loop 384 | 385 | Returns: 386 | float: estimate of updated SVM objective function F using average 387 | of F(alpha_+, lambda_+) and F(alpha_-, lambda_-) 388 | numpy.ndarray: updated values of the kernel parameters 389 | after one SPSA optimization step 390 | """ 391 | 392 | a_spsa = float(spsa_params[0]) / np.power(count + 1 + spsa_params[4], spsa_params[2]) 393 | c_spsa = float(spsa_params[1]) / np.power(count + 1, spsa_params[3]) 394 | 395 | g_spsa = (cost_plus - cost_minus) * delta / (2.0 * c_spsa) 396 | 397 | lambdas_new = lambdas - a_spsa * g_spsa 398 | lambdas_new = lambdas_new.flatten() 399 | 400 | cost_final = (cost_plus + cost_minus) / 2 401 | 402 | return cost_final, lambdas_new 403 | 404 | def align_kernel(self, data, labels, initial_kernel_parameters=None, maxiters=1, C=1): 405 | """Align the quantum kernel. 406 | 407 | Uses SPSA for minimization over kernel parameters (lambdas) and 408 | convex optimization for maximization over lagrange multipliers (alpha): 409 | 410 | min_lambda max_alpha 1^T * alpha - (1/2) * alpha^T * Y * K_lambda * Y * alpha 411 | 412 | Args: 413 | data (numpy.ndarray): NxD array of training data, where N is the 414 | number of samples and D is the feature dimension 415 | labels (numpy.ndarray): Nx1 array of +/-1 labels of the N training samples 416 | initial_kernel_parameters (numpy.ndarray): Initial parameters of the quantum kernel 417 | maxiters (int): number of SPSA optimization steps 418 | C (float): penalty parameter for the soft-margin support vector machine 419 | 420 | Returns: 421 | dict: the results of kernel alignment 422 | """ 423 | 424 | if initial_kernel_parameters is not None: 425 | lambdas = initial_kernel_parameters 426 | else: 427 | lambdas = np.random.uniform(-1.0, 1.0, size=(self.num_parameters)) 428 | 429 | spsa_params = self.spsa_parameters() 430 | 431 | lambda_save = [] 432 | cost_final_save = [] 433 | 434 | for count in range(maxiters): 435 | 436 | lambda_plus, lambda_minus, delta = self.spsa_step_one( 437 | lambdas=lambdas, spsa_params=spsa_params, count=count 438 | ) 439 | 440 | kernel_plus = self.kernel_matrix.construct_kernel_matrix( 441 | x1_vec=data, x2_vec=data, parameters=lambda_plus 442 | ) 443 | kernel_minus = self.kernel_matrix.construct_kernel_matrix( 444 | x1_vec=data, x2_vec=data, parameters=lambda_minus 445 | ) 446 | 447 | ret_plus = self.cvxopt_solver(K=kernel_plus, y=labels, C=C) 448 | cost_plus = -1 * ret_plus["primal objective"] 449 | 450 | ret_minus = self.cvxopt_solver(K=kernel_minus, y=labels, C=C) 451 | cost_minus = -1 * ret_minus["primal objective"] 452 | 453 | cost_final, lambda_best = self.spsa_step_two( 454 | cost_plus=cost_plus, 455 | cost_minus=cost_minus, 456 | lambdas=lambdas, 457 | spsa_params=spsa_params, 458 | delta=delta, 459 | count=count, 460 | ) 461 | 462 | lambdas = lambda_best 463 | 464 | interim_result = {"cost": cost_final, "kernel_parameters": lambdas} 465 | 466 | self._user_messenger.publish(interim_result) 467 | 468 | lambda_save.append(lambdas) 469 | cost_final_save.append(cost_final) 470 | 471 | # Evaluate aligned kernel matrix with optimized set of 472 | # parameters averaged over last 10% of SPSA steps: 473 | num_last_lambdas = int(len(lambda_save) * 0.10) 474 | if num_last_lambdas > 0: 475 | last_lambdas = np.array(lambda_save)[-num_last_lambdas:, :] 476 | lambdas = np.sum(last_lambdas, axis=0) / num_last_lambdas 477 | else: 478 | lambdas = np.array(lambda_save)[-1, :] 479 | 480 | kernel_best = self.kernel_matrix.construct_kernel_matrix( 481 | x1_vec=data, x2_vec=data, parameters=lambdas 482 | ) 483 | 484 | self.result["aligned_kernel_parameters"] = lambdas 485 | self.result["aligned_kernel_matrix"] = kernel_best 486 | 487 | return self.result 488 | 489 | 490 | def main(backend, user_messenger, **kwargs): 491 | """Entry function.""" 492 | 493 | # Reconstruct the feature map object. 494 | feature_map = kwargs.get("feature_map") 495 | fm = FeatureMap.from_json(feature_map) 496 | 497 | data = kwargs.get("data") 498 | labels = kwargs.get("labels") 499 | initial_kernel_parameters = kwargs.get("initial_kernel_parameters", None) 500 | maxiters = kwargs.get("maxiters", 1) 501 | C = kwargs.get("C", 1) 502 | initial_layout = kwargs.get("initial_layout", None) 503 | 504 | qka = QKA( 505 | feature_map=fm, 506 | backend=backend, 507 | initial_layout=initial_layout, 508 | user_messenger=user_messenger, 509 | ) 510 | qka_results = qka.align_kernel( 511 | data=data, 512 | labels=labels, 513 | initial_kernel_parameters=initial_kernel_parameters, 514 | maxiters=maxiters, 515 | C=C, 516 | ) 517 | 518 | return qka_results 519 | -------------------------------------------------------------------------------- /qiskit_runtime/sample_program/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Package containing ``sample-program`` Qiskit quantum program.""" 14 | -------------------------------------------------------------------------------- /qiskit_runtime/sample_program/sample_program.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sample-program", 3 | "description": "(DEPRECATED) A sample runtime program. This runtime program is deprecated, please use hello-world instead.", 4 | "max_execution_time": 300, 5 | "spec": { 6 | "backend_requirements": { 7 | "min_num_qubits": 5 8 | }, 9 | "parameters": { 10 | "$schema": "https://json-schema.org/draft/2019-09/schema", 11 | "properties": { 12 | "iterations": { 13 | "type": "integer", 14 | "minimum": 0, 15 | "description": "Number of iterations to run. Each iteration generates a runs a random circuit." 16 | } 17 | }, 18 | "required": [ 19 | "iterations" 20 | ] 21 | }, 22 | "return_values": { 23 | "$schema": "https://json-schema.org/draft/2019-09/schema", 24 | "description": "A string that says 'All done!'.", 25 | "type": "string" 26 | }, 27 | "interim_results": { 28 | "$schema": "https://json-schema.org/draft/2019-09/schema", 29 | "properties": { 30 | "iteration": { 31 | "type": "integer", 32 | "description": "Iteration number." 33 | }, 34 | "counts": { 35 | "description": "Histogram data of the circuit result.", 36 | "type": "object" 37 | } 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /qiskit_runtime/sample_program/sample_program.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """A sample runtime program that submits random circuits for user-specified iterations.""" 14 | 15 | import random 16 | from typing import Any 17 | 18 | from qiskit import transpile 19 | from qiskit.circuit.random import random_circuit 20 | 21 | 22 | def prepare_circuits(backend): 23 | """Generate a random circuit. 24 | 25 | Args: 26 | backend (qiskit.providers.Backend): Backend used for transpilation. 27 | 28 | Returns: 29 | qiskit.QuantumCircuit: Generated circuit. 30 | """ 31 | circuit = random_circuit(num_qubits=5, depth=4, measure=True, seed=random.randint(0, 1000)) 32 | return transpile(circuit, backend) 33 | 34 | 35 | def main(backend, user_messenger, **kwargs) -> Any: 36 | """Main entry point of the program. 37 | 38 | Args: 39 | backend (qiskit.providers.Backend): Backend to submit the circuits to. 40 | user_messenger (qiskit.providers.ibmq.runtime.UserMessenger): Used to communicate with the 41 | program consumer. 42 | kwargs: User inputs. 43 | 44 | Returns: 45 | Final result of the program. 46 | """ 47 | iterations = kwargs.pop("iterations", 5) 48 | for it in range(iterations): 49 | qc = prepare_circuits(backend) 50 | result = backend.run(qc).result() 51 | user_messenger.publish({"iteration": it, "counts": result.get_counts()}) 52 | 53 | return "All done!" 54 | -------------------------------------------------------------------------------- /qiskit_runtime/version.py: -------------------------------------------------------------------------------- 1 | # THIS FILE IS GENERATED FROM QISKIT_RUNTIME SETUP.PY 2 | # pylint: disable=missing-module-docstring,invalid-name 3 | short_version = "0.1.0" 4 | version = "0.1.0.dev0+bca5fbf" 5 | release = False 6 | -------------------------------------------------------------------------------- /qiskit_runtime/vqe/vqe_metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vqe", 3 | "description": "Variational Quantum Eigensolver (VQE) to find the minimal eigenvalue of a Hamiltonian.", 4 | "max_execution_time": 18000, 5 | "version": "1.1", 6 | "parameters": [ 7 | {"name": "ansatz", "description": "A parameterized quantum circuit preparing the ansatz wavefunction for the VQE. It is assumed that all qubits are initially in the 0 state.", "type": "QuantumCircuit", "required": true}, 8 | {"name": "operator", "description": "The Hamiltonian whose smallest eigenvalue we're trying to find.", "type": "PauliSumOp", "required": true}, 9 | {"name": "optimizer", "description": "The classical optimizer used in to update the parameters in each iteration. Can be either any of Qiskit's optimizer classes. If a dictionary, only SPSA and QN-SPSA are supported and the dictionary must specify the name and options of the optimizer, e.g. ``{'name': 'SPSA', 'maxiter': 100}``.", "type": "Union[Optimizer, dict]", "required": true}, 10 | {"name": "initial_parameters", "description": "Initial parameters of the ansatz. Can be an array or the string ``'random'`` to choose random initial parameters.", "type": "Union[numpy.ndarray, str]", "required": true}, 11 | {"name": "aux_operators", "description": "A list of operators to be evaluated at the final, optimized state.", "type": "List[PauliSumOp]", "required": false}, 12 | {"name": "shots", "description": "The number of shots used for each circuit evaluation. Defaults to 1024.", "type": "int", "required": false}, 13 | {"name": "measurement_error_mitigation", "description": "Whether to apply measurement error mitigation in form of a complete measurement fitter to the measurements. Defaults to False.", "type": "bool", "required": false}, 14 | {"name": "initial_layout", "description": "Initial position of virtual qubits on the physical qubits of the quantum device. Default is None.", "type": "list or dict", "required": false} 15 | ], 16 | "return_values": [ 17 | {"name": "optimizer_evals", "description": "The number of steps of the optimizer.", "type": "int"}, 18 | {"name": "optimizer_time", "description": "The total time taken by the optimizer.", "type": "float"}, 19 | {"name": "optimal_value", "description": "The smallest value found during the optimization. Equal to the ``eigenvalue`` attribute.", "type": "float"}, 20 | {"name": "optimal_point", "description": "The optimal parameter values found during the optimization.", "type": "np.ndarray"}, 21 | {"name": "optimal_parameters", "description": "Not supported at the moment, therefore ``None``.", "type": "NoneType"}, 22 | {"name": "cost_function_evals", "description": "The number of cost function (energy) evaluations", "type": "int"}, 23 | {"name": "eigenstate", "description": "The square root of sampling probabilities for each computational basis state of the circuit with optimal parameters.", "type": "dict"}, 24 | {"name": "eigenvalue", "description": "The estimated eigenvalue.", "type": "complex"}, 25 | {"name": "aux_operator_eigenvalues", "description": "The expectation values of the auxiliary operators at the optimal state.", "type": "np.ndarray"}, 26 | {"name": "optimizer_history", "description": "A dictionary containing information about the optimization process: the value objective function, parameters, and a timestamp.", "type": "dict"} 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | qiskit-aer 2 | pytest 3 | black==21.5b0 4 | astroid==2.5.6 5 | pylint==2.8.2 6 | -------------------------------------------------------------------------------- /requirements-docs.txt: -------------------------------------------------------------------------------- 1 | Sphinx>=3.3 2 | sphinx-autodoc-typehints 3 | jupyter-sphinx 4 | qiskit-sphinx-theme>=1.8.0 5 | sphinx-panels 6 | nbsphinx 7 | sphinx-reredirects 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | qiskit-terra>=0.18.2 2 | qiskit-nature>=0.1.2 3 | qiskit-ibmq-provider>=0.16 4 | qiskit-ignis>=0.6 5 | qiskit-aer>=0.8.2 6 | jupyter 7 | numpy 8 | matplotlib 9 | pylatexenc 10 | pandas 11 | scikit-learn -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """qiskit-runtime 3 | 4 | Package of tools for using the Qiskit-runtime. 5 | """ 6 | 7 | import os 8 | import sys 9 | import subprocess 10 | import setuptools 11 | 12 | 13 | MAJOR = 0 14 | MINOR = 1 15 | MICRO = 0 16 | 17 | ISRELEASED = False 18 | VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO) 19 | 20 | REQUIREMENTS = [ 21 | 'qiskit-terra>=0.17', 22 | 'qiskit-ibmq-provider>=0.12' 23 | ] 24 | PACKAGES = setuptools.find_packages() 25 | PACKAGE_DATA = {} 26 | DOCLINES = __doc__.split('\n') 27 | DESCRIPTION = DOCLINES[0] 28 | LONG_DESCRIPTION = "\n".join(DOCLINES[2:]) 29 | 30 | def git_short_hash(): 31 | try: 32 | git_str = "+" + os.popen('git log -1 --format="%h"').read().strip() 33 | except: # pylint: disable=bare-except 34 | git_str = "" 35 | else: 36 | if git_str == '+': #fixes setuptools PEP issues with versioning 37 | git_str = '' 38 | return git_str 39 | 40 | FULLVERSION = VERSION 41 | if not ISRELEASED: 42 | FULLVERSION += '.dev'+str(MICRO)+git_short_hash() 43 | 44 | local_path = os.path.dirname(os.path.abspath(sys.argv[0])) 45 | os.chdir(local_path) 46 | sys.path.insert(0, local_path) 47 | sys.path.insert(0, os.path.join(local_path, 'qiskit_runtime')) # to retrive _version 48 | 49 | def write_version_py(filename='qiskit_runtime/version.py'): 50 | cnt = """\ 51 | # THIS FILE IS GENERATED FROM QISKIT_RUNTIME SETUP.PY 52 | # pylint: disable=missing-module-docstring,invalid-name 53 | short_version = "%(version)s" 54 | version = "%(fullversion)s" 55 | release = %(isrelease)s 56 | """ 57 | a = open(filename, 'w') 58 | try: 59 | a.write(cnt % {'version': VERSION, 'fullversion': 60 | FULLVERSION, 'isrelease': str(ISRELEASED)}) 61 | finally: 62 | a.close() 63 | 64 | # always rewrite _version 65 | if os.path.exists('qiskit_runtime/version.py'): 66 | os.remove('qiskit_runtime/version.py') 67 | # write the version info 68 | write_version_py() 69 | 70 | setuptools.setup( 71 | name='qiskit-runtime', 72 | version=VERSION, 73 | description=DESCRIPTION, 74 | long_description=LONG_DESCRIPTION, 75 | packages=PACKAGES, 76 | url="", 77 | author="Qiskit Development Team", 78 | author_email="hello@qiskit.org", 79 | license="Apache 2.0", 80 | classifiers=[ 81 | "Environment :: Web Environment", 82 | "License :: OSI Approved :: Apache Software License", 83 | "Intended Audience :: Developers", 84 | "Intended Audience :: Science/Research", 85 | "Operating System :: Microsoft :: Windows", 86 | "Operating System :: MacOS", 87 | "Operating System :: POSIX :: Linux", 88 | "Programming Language :: Python :: 3.6", 89 | "Programming Language :: Python :: 3.7", 90 | "Programming Language :: Python :: 3.8", 91 | "Topic :: Scientific/Engineering", 92 | ], 93 | package_data=PACKAGE_DATA, 94 | install_requires=REQUIREMENTS, 95 | zip_safe=False 96 | ) 97 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2018, 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Qiskit runtime tests""" 14 | -------------------------------------------------------------------------------- /test/circuit_runner/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Runtime test packages.""" 14 | -------------------------------------------------------------------------------- /test/circuit_runner/test_circuit_runner.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Test the circuit runner program.""" 14 | 15 | import json 16 | from test.fake_user_messenger import FakeUserMessenger 17 | from unittest import TestCase 18 | 19 | from qiskit.providers.aer import AerSimulator 20 | from qiskit.providers.ibmq.runtime.utils import RuntimeEncoder, RuntimeDecoder 21 | from qiskit.result.result import Result 22 | from qiskit import QuantumCircuit 23 | from qiskit_runtime.circuit_runner import circuit_runner 24 | 25 | 26 | class TestCircuitRunner(TestCase): 27 | """Test circuit_runner.""" 28 | 29 | def setUp(self) -> None: 30 | """Test case setup.""" 31 | n = 6 32 | qc = QuantumCircuit(n) 33 | qc.x(range(0, n)) 34 | qc.h(range(0, n)) 35 | self.qc = qc 36 | self.backend = AerSimulator() 37 | self.user_messenger = FakeUserMessenger() 38 | 39 | def test_circuit_runner(self): 40 | """Test circuit_runner program.""" 41 | inputs = { 42 | "circuits": self.qc, 43 | "optimization_level": 0, 44 | "initial_layout": [0, 1, 4, 7, 10, 12], 45 | "measurement_error_mitigation": False, 46 | } 47 | serialized_inputs = json.dumps(inputs, cls=RuntimeEncoder) 48 | unserialized_inputs = json.loads(serialized_inputs, cls=RuntimeDecoder) 49 | result = circuit_runner.main( 50 | backend=self.backend, user_messenger=self.user_messenger, **unserialized_inputs 51 | ) 52 | self.assertEqual(self.user_messenger.call_count, 0) 53 | self.assertTrue(isinstance(Result.from_dict(result), Result)) 54 | -------------------------------------------------------------------------------- /test/fake_user_messenger.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Fake UserMessenger. 14 | 15 | This class is a fake UserMessenger. 16 | """ 17 | 18 | from typing import Any, Type 19 | import json 20 | from qiskit.providers.ibmq.runtime.utils import RuntimeEncoder 21 | 22 | 23 | class FakeUserMessenger: 24 | """Fake UserMessenger.""" 25 | 26 | def __init__(self): 27 | self.call_count = 0 28 | self.message = None 29 | 30 | def publish( 31 | self, 32 | message: Any, 33 | encoder: Type[json.JSONEncoder] = RuntimeEncoder, # pylint: disable=unused-argument 34 | final: bool = False, # pylint: disable=unused-argument 35 | ): 36 | """Fake publish for UserMessenger. 37 | 38 | Increments the number of times this method is called and stores the message arg. 39 | """ 40 | self.message = message 41 | self.call_count += 1 42 | -------------------------------------------------------------------------------- /test/hello_world/__init__.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Runtime test packages.""" 14 | -------------------------------------------------------------------------------- /test/hello_world/test_sample_program.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | """Test the hello_world.""" 14 | 15 | import json 16 | from test.fake_user_messenger import FakeUserMessenger 17 | from unittest import TestCase 18 | from qiskit.providers.aer import AerSimulator 19 | from qiskit.providers.ibmq.runtime.utils import RuntimeEncoder, RuntimeDecoder 20 | from qiskit_runtime.hello_world import hello_world 21 | 22 | 23 | class TestHelloWorld(TestCase): 24 | """Test hello_world.""" 25 | 26 | def setUp(self) -> None: 27 | """Test case setup.""" 28 | self.backend = AerSimulator() 29 | user_messenger = FakeUserMessenger() 30 | self.user_messenger = user_messenger 31 | 32 | def test_hello_world(self): 33 | """Test hello_world.""" 34 | inputs = {"iterations": 2} 35 | serialized_inputs = json.dumps(inputs, cls=RuntimeEncoder) 36 | unserialized_inputs = json.loads(serialized_inputs, cls=RuntimeDecoder) 37 | hello_world.main(self.backend, self.user_messenger, **unserialized_inputs) 38 | self.assertEqual(self.user_messenger.call_count, inputs["iterations"]) 39 | -------------------------------------------------------------------------------- /tools/deploy_documentation.sh: -------------------------------------------------------------------------------- 1 | 2 | #!/bin/bash 3 | 4 | # This code is part of Qiskit. 5 | # 6 | # (C) Copyright IBM 2017, 2021. 7 | # 8 | # This code is licensed under the Apache License, Version 2.0. You may 9 | # obtain a copy of this license in the LICENSE.txt file in the root directory 10 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 11 | # 12 | # Any modifications or derivative works of this code must retain this 13 | # copyright notice, and modified files need to carry a notice indicating 14 | # that they have been altered from the originals. 15 | 16 | # Script for pushing the documentation to the qiskit.org repository. 17 | set -e 18 | 19 | curl https://downloads.rclone.org/rclone-current-linux-amd64.deb -o rclone.deb 20 | sudo apt-get install -y ./rclone.deb 21 | 22 | RCLONE_CONFIG_PATH=$(rclone config file | tail -1) 23 | 24 | # Build the documentation. 25 | tox -edocs 26 | 27 | echo "show current dir: " 28 | pwd 29 | 30 | # Push to qiskit.org website 31 | openssl aes-256-cbc -K $encrypted_rclone_key -iv $encrypted_rclone_iv -in tools/rclone.conf.enc -out $RCLONE_CONFIG_PATH -d 32 | echo "Pushing built docs to website" 33 | rclone sync --progress ./docs/_build/html IBMCOS:qiskit-org-web-resources/documentation/partners/qiskit_runtime 34 | -------------------------------------------------------------------------------- /tools/rclone.conf.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit-Partners/qiskit-runtime/15f5712f35e942d50689ad54e352aa89cfde0901/tools/rclone.conf.enc -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | minversion = 2.1 3 | envlist = py36, py37, py38, py39, lint, docs 4 | 5 | [testenv] 6 | deps = 7 | -r requirements.txt 8 | -r requirements-dev.txt 9 | install_command = pip install -c{toxinidir}/constraints.txt -U {opts} {packages} 10 | usedevelop = true 11 | setenv = 12 | VIRTUAL_ENV={envdir} 13 | LANGUAGE=en_US 14 | LC_ALL=en_US.utf-8 15 | commands = 16 | pytest 17 | 18 | [testenv:lint] 19 | envdir = .tox/lint 20 | basepython = python3 21 | commands = 22 | black --check --diff {posargs} qiskit_runtime test 23 | pylint -rn qiskit_runtime test 24 | 25 | [testenv:black] 26 | envdir = .tox/lint 27 | commands = black {posargs} qiskit_runtime test 28 | 29 | [testenv:docs] 30 | allowlist_externals = make 31 | envdir = .tox/docs 32 | deps = 33 | -r requirements-docs.txt 34 | commands = 35 | sphinx-build -b html {posargs} docs/ docs/_build/html 36 | -------------------------------------------------------------------------------- /tutorials/00_introduction.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "2b3fb1b1", 6 | "metadata": {}, 7 | "source": [ 8 | "# Qiskit Runtime" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "8fb23fc2", 14 | "metadata": {}, 15 | "source": [ 16 | "Qiskit Runtime is a new architecture offered by IBM Quantum that streamlines computations requiring many iterations. These experiments will execute significantly faster within this improved hybrid quantum/classical process.\n", 17 | "\n", 18 | "Using Qiskit Runtime, for example, a research team at IBM Quantum was able to achieve \n", 19 | "[120x speed up](https://research.ibm.com/blog/120x-quantum-speedup) in their lithium hydride simulation. \n", 20 | "\n", 21 | "Qiskit Runtime allows authorized users to upload their Qiskit quantum programs for themselves or \n", 22 | "others to use. A Qiskit quantum program, also called a Qiskit runtime program, is a piece of Python code that takes certain inputs, performs\n", 23 | "quantum and maybe classical computation, and returns the processing results. The same or other\n", 24 | "authorized users can then invoke these quantum programs by simply passing in the required input parameters." 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 1, 30 | "id": "233c286a", 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "from qiskit import IBMQ\n", 35 | "\n", 36 | "IBMQ.load_account()\n", 37 | "provider = IBMQ.get_provider(project='qiskit-runtime') # Change this to your provider." 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "id": "1612dac1", 43 | "metadata": {}, 44 | "source": [ 45 | "\n", 46 | "If you don't have an IBM Quantum account, you can sign up for one on the [IBM Quantum](https://quantum-computing.ibm.com/) page." 47 | ] 48 | }, 49 | { 50 | "cell_type": "markdown", 51 | "id": "61d9f293", 52 | "metadata": {}, 53 | "source": [ 54 | "## Listing programs " 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "id": "2ed6ce38", 60 | "metadata": {}, 61 | "source": [ 62 | "The `provider.runtime` object is an instance of the [`IBMRuntimeService`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.IBMRuntimeService.html#qiskit.providers.ibmq.runtime.IBMRuntimeService) class and serves as the main entry point to using the runtime service. It has three methods that can be used to find metadata of available programs:\n", 63 | "- `pprint_programs()`: pretty prints summary metadata of available programs\n", 64 | "- `programs()`: returns a list of `RuntimeProgram` instances\n", 65 | "- `program()`: returns a single `RuntimeProgram` instance\n", 66 | "\n", 67 | "The metadata of a runtime program includes its ID, name, description, maximum execution time, backend requirements, input parameters, return values, and interim results. Maximum execution time is the maximum amount of time, in seconds, a program can run before being forcibly terminated." 68 | ] 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "id": "2abfb988", 73 | "metadata": {}, 74 | "source": [ 75 | "To print the summary metadata of the programs (by default first 20 programs are displayed):" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": 2, 81 | "id": "a420f91c", 82 | "metadata": {}, 83 | "outputs": [ 84 | { 85 | "output_type": "stream", 86 | "name": "stdout", 87 | "text": "==================================================\nqasm3-runner:\n Name: qasm3-runner\n Description: A runtime program that takes one or more circuits, converts them to OpenQASM3, compiles them, executes them, and optionally applies measurement error mitigation. This program can also take and execute one or more OpenQASM3 strings. Note that this program can only run on a backend that supports OpenQASM3.\n==================================================\nsampler:\n Name: sampler\n Description: Sample distributions generated by given circuits executed on the target backend.\n==================================================\nestimator:\n Name: estimator\n Description: Expectation value estimator. A runtime program that estimates the value of an observable for an input quantum circuit. This program is in beta mode and is only available to select accounts.\n==================================================\nsample-expval:\n Name: sample-expval\n Description: A sample expectation value program.\n==================================================\nvqe:\n Name: vqe\n Description: Variational Quantum Eigensolver (VQE) to find the minimal eigenvalue of a Hamiltonian.\n==================================================\ncircuit-runner:\n Name: circuit-runner\n Description: A runtime program that takes one or more circuits, compiles them, executes them, and optionally applies measurement error mitigation.\n==================================================\nhello-world:\n Name: hello-world\n Description: A sample runtime program.\n==================================================\nquantum-kernel-alignment:\n Name: quantum-kernel-alignment\n Description: Quantum kernel alignment algorithm that learns, on a given dataset, a quantum kernel maximizing the SVM classification margin.\n" 88 | } 89 | ], 90 | "source": [ 91 | "provider.runtime.pprint_programs()" 92 | ] 93 | }, 94 | { 95 | "cell_type": "markdown", 96 | "id": "0a5ca5f5", 97 | "metadata": {}, 98 | "source": [ 99 | "You can use the `limit` and `skip` parameters in `pprint_programs()` and `programs()` to page through the remaining programs. You can pass `detailed = True` parameter to `pprint_programs()` to view all the metadata for the programs. The program metadata once fetched, is cached for performance reasons, so you can pass `refresh = True` parameter to `pprint_programs()` or `programs()` methods in order to get the latest programs from the server. To print the metadata of the program `hello-world`:" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 3, 105 | "id": "f8302b63", 106 | "metadata": {}, 107 | "outputs": [ 108 | { 109 | "output_type": "stream", 110 | "name": "stdout", 111 | "text": "hello-world:\n Name: hello-world\n Description: A sample runtime program.\n Creation date: 2021-07-02T13:45:13Z\n Update date: 2021-07-02T13:45:13Z\n Max execution time: 300\n Input parameters:\n Properties:\n - iterations:\n Description: Number of iterations to run. Each iteration generates a runs a random circuit.\n Minimum: 0\n Type: integer\n Required: True\n Interim results:\n Properties:\n - counts:\n Description: Histogram data of the circuit result.\n Type: object\n Required: False\n - iteration:\n Description: Iteration number.\n Type: integer\n Required: False\n Returns:\n Description: A string that says 'All done!'.\n Type: string\n" 112 | } 113 | ], 114 | "source": [ 115 | "program = provider.runtime.program('hello-world')\n", 116 | "print(program)" 117 | ] 118 | }, 119 | { 120 | "cell_type": "markdown", 121 | "id": "ec37a66c", 122 | "metadata": {}, 123 | "source": [ 124 | "As you can see from above, the program `hello-world` is a simple program that has only 1 input parameter `iterations`, which indicates how many iterations to run. For each iteration it generates and runs a random 5-qubit circuit and returns the counts as well as the iteration number as the interim results. When the program finishes, it returns the sentence `All done!`. This program can only run for 300 seconds (5 minutes), and requires a backend that has at least 5 qubits." 125 | ] 126 | }, 127 | { 128 | "cell_type": "markdown", 129 | "id": "8097db3a", 130 | "metadata": {}, 131 | "source": [ 132 | "## Invoking a runtime program " 133 | ] 134 | }, 135 | { 136 | "cell_type": "markdown", 137 | "id": "b6d680a3", 138 | "metadata": {}, 139 | "source": [ 140 | "You can use the [`IBMRuntimeService.run()`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.IBMRuntimeService.html#qiskit.providers.ibmq.runtime.IBMRuntimeService.run) method to invoke a runtime program. This method takes the following parameters:\n", 141 | "\n", 142 | "- `program_id`: ID of the program to run\n", 143 | "- `inputs`: Program input parameters. These input values are passed to the runtime program.\n", 144 | "- `options`: Runtime options. These options control the execution environment. Currently the only available option is `backend_name`, which is required.\n", 145 | "- `callback`: Callback function to be invoked for any interim results. The callback function will receive 2 positional parameters: job ID and interim result.\n", 146 | "- `result_decoder`: Optional class used to decode job result." 147 | ] 148 | }, 149 | { 150 | "cell_type": "markdown", 151 | "id": "abe247c4", 152 | "metadata": {}, 153 | "source": [ 154 | "Before we run a quantum program, we may want to define a callback function that would process interim results, which are intermediate data provided by a program while its still running. \n", 155 | "\n", 156 | "As we saw earlier, the metadata of `hello-world` says that its interim results are the iteration number and the counts of the randomly generated circuit. Here we define a simple callback function that just prints these interim results:" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": 4, 162 | "id": "92f46214", 163 | "metadata": {}, 164 | "outputs": [], 165 | "source": [ 166 | "def interim_result_callback(job_id, interim_result):\n", 167 | " print(f\"interim result: {interim_result}\")" 168 | ] 169 | }, 170 | { 171 | "cell_type": "markdown", 172 | "id": "3f9e793f", 173 | "metadata": {}, 174 | "source": [ 175 | "The following example runs the `hello-world` program with 3 iterations on `ibmq_montreal` and waits for its result. You can also use a different backend that supports Qiskit Runtime:" 176 | ] 177 | }, 178 | { 179 | "cell_type": "code", 180 | "execution_count": 5, 181 | "id": "d622e53c", 182 | "metadata": {}, 183 | "outputs": [ 184 | { 185 | "output_type": "stream", 186 | "name": "stdout", 187 | "text": "job id: c618jdik2ih5ha3l6mog\ninterim result: {'iteration': 0, 'counts': {'00000': 31, '00001': 11, '10000': 10, '10001': 10, '10010': 19, '10011': 11, '10100': 4, '10101': 6, '10110': 11, '10111': 8, '11000': 16, '11001': 4, '11010': 45, '11011': 16, '11100': 8, '11101': 9, '11110': 18, '11111': 8, '00010': 104, '00011': 47, '00100': 5, '00101': 10, '00110': 25, '00111': 10, '01000': 60, '01001': 35, '01010': 260, '01011': 119, '01100': 13, '01101': 12, '01110': 39, '01111': 40}}\ninterim result: {'iteration': 1, 'counts': {'00000': 99, '00001': 64, '10000': 13, '10001': 12, '10010': 9, '10011': 4, '10100': 21, '10101': 89, '10110': 6, '10111': 19, '11000': 19, '11001': 9, '11010': 5, '11011': 5, '11100': 26, '11101': 61, '11110': 11, '11111': 17, '00010': 37, '00011': 23, '00100': 73, '00101': 13, '00110': 20, '00111': 3, '01000': 105, '01001': 83, '01010': 30, '01011': 26, '01100': 79, '01101': 11, '01110': 22, '01111': 10}}\ninterim result: {'iteration': 2, 'counts': {'00000': 30, '00001': 5, '10000': 8, '10001': 3, '10010': 1, '10011': 3, '10100': 7, '10101': 5, '10110': 3, '11000': 22, '11001': 6, '11010': 1, '11011': 3, '11100': 66, '11101': 8, '11110': 11, '11111': 7, '00010': 2, '00011': 2, '00100': 51, '00101': 5, '00110': 5, '00111': 2, '01000': 136, '01001': 16, '01010': 11, '01011': 2, '01100': 534, '01101': 31, '01110': 31, '01111': 7}}\nAll done!\n" 188 | } 189 | ], 190 | "source": [ 191 | "backend = provider.get_backend('ibmq_montreal')\n", 192 | "program_inputs = {\n", 193 | " 'iterations': 3\n", 194 | "}\n", 195 | "options = {'backend_name': backend.name()}\n", 196 | "job = provider.runtime.run(program_id=\"hello-world\",\n", 197 | " options=options,\n", 198 | " inputs=program_inputs,\n", 199 | " callback=interim_result_callback\n", 200 | " )\n", 201 | "print(f\"job id: {job.job_id()}\")\n", 202 | "result = job.result()\n", 203 | "print(result)" 204 | ] 205 | }, 206 | { 207 | "cell_type": "markdown", 208 | "id": "1cb7b160", 209 | "metadata": {}, 210 | "source": [ 211 | "The `run()` method returns a [`RuntimeJob`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.RuntimeJob.html#qiskit.providers.ibmq.runtime.RuntimeJob) instance, which is similar to the `Job` instance returned by regular `backend.run()`. Some of the `RuntimeJob` methods:\n", 212 | "\n", 213 | "- `status()`: Return job status.\n", 214 | "- `result()`: Wait for the job to finish and return the final result.\n", 215 | "- `cancel()`: Cancel the job.\n", 216 | "- `wait_for_final_state()`: Wait for the job to finish.\n", 217 | "- `stream_results()`: Stream interim results. This can be used to start streaming the interim results if a `callback` function was not passed to the `run()` method. This method can also be used to reconnect a lost websocket connection.\n", 218 | "- `job_id()`: Return the job ID.\n", 219 | "- `backend()`: Return the backend where the job is run.\n", 220 | "- `logs()`: Return job logs.\n", 221 | "- `error_message()`: Returns the reason if the job failed and `None` otherwise.\n", 222 | "\n", 223 | "Refer to the [`RuntimeJob` API documentation](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.RuntimeJob.html#qiskit.providers.ibmq.runtime.RuntimeJob) for a full list of methods and usage. " 224 | ] 225 | }, 226 | { 227 | "cell_type": "markdown", 228 | "id": "present-creature", 229 | "metadata": {}, 230 | "source": [ 231 | "
\n", 232 | "Note: To ensure fairness, there is a maximum execution time for each Qiskit Runtime job. If a job exceeds this time limit, it is forcibly terminated. The maximum execution time is calculated based on 1) a maximum system limit, 2) the `max_execution_time` defined by the program, and 3) the fair-share value in your hub/group/project. \n", 233 | "
" 234 | ] 235 | }, 236 | { 237 | "cell_type": "markdown", 238 | "id": "821630b0", 239 | "metadata": {}, 240 | "source": [ 241 | "## Retrieving old jobs" 242 | ] 243 | }, 244 | { 245 | "cell_type": "markdown", 246 | "id": "ed6efcd4", 247 | "metadata": {}, 248 | "source": [ 249 | "You can use the [`IBMRuntimeService.job()`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.IBMRuntimeService.html#qiskit.providers.ibmq.runtime.IBMRuntimeService.job) method to retrieve a previously executed runtime job. Attributes of this [`RuntimeJob`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.RuntimeJob.html#qiskit.providers.ibmq.runtime.RuntimeJob) instance can tell you about the execution:" 250 | ] 251 | }, 252 | { 253 | "cell_type": "code", 254 | "execution_count": 6, 255 | "id": "4336b881", 256 | "metadata": {}, 257 | "outputs": [ 258 | { 259 | "output_type": "stream", 260 | "name": "stdout", 261 | "text": "Job c618jdik2ih5ha3l6mog is an execution instance of runtime program hello-world.\nThis job ran on backend ibmq_montreal and had input parameters {'iterations': 3}\n" 262 | } 263 | ], 264 | "source": [ 265 | "retrieved_job = provider.runtime.job(job.job_id())\n", 266 | "print(f\"Job {retrieved_job.job_id()} is an execution instance of runtime program {retrieved_job.program_id}.\")\n", 267 | "print(f\"This job ran on backend {retrieved_job.backend()} and had input parameters {retrieved_job.inputs}\")" 268 | ] 269 | }, 270 | { 271 | "cell_type": "markdown", 272 | "id": "5c00514e", 273 | "metadata": {}, 274 | "source": [ 275 | "Similarly, you can use [`IBMRuntimeService.jobs()`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.IBMRuntimeService.html#qiskit.providers.ibmq.runtime.IBMRuntimeService.jobs) to get a list of jobs. You can specify a limit on how many jobs to return. The default limit is 10:" 276 | ] 277 | }, 278 | { 279 | "cell_type": "code", 280 | "execution_count": 7, 281 | "id": "919862b8", 282 | "metadata": {}, 283 | "outputs": [ 284 | { 285 | "output_type": "stream", 286 | "name": "stdout", 287 | "text": "c618jdik2ih5ha3l6mog\n" 288 | } 289 | ], 290 | "source": [ 291 | "retrieved_jobs = provider.runtime.jobs(limit=1)\n", 292 | "for rjob in retrieved_jobs:\n", 293 | " print(rjob.job_id())" 294 | ] 295 | }, 296 | { 297 | "cell_type": "markdown", 298 | "id": "d6f8f1d2", 299 | "metadata": {}, 300 | "source": [ 301 | "## Deleting a job" 302 | ] 303 | }, 304 | { 305 | "cell_type": "markdown", 306 | "id": "81234913", 307 | "metadata": {}, 308 | "source": [ 309 | "You can use the [`IBMRuntimeService.delete_job()`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.IBMRuntimeService.html#qiskit.providers.ibmq.runtime.IBMRuntimeService.delete_job) method to delete a job. You can only delete your own jobs, and this action cannot be reversed. " 310 | ] 311 | }, 312 | { 313 | "cell_type": "code", 314 | "execution_count": 8, 315 | "id": "b1095852", 316 | "metadata": {}, 317 | "outputs": [], 318 | "source": [ 319 | "provider.runtime.delete_job(job.job_id())" 320 | ] 321 | } 322 | ], 323 | "metadata": { 324 | "kernelspec": { 325 | "display_name": "Python 3", 326 | "language": "python", 327 | "name": "python3" 328 | }, 329 | "language_info": { 330 | "codemirror_mode": { 331 | "name": "ipython", 332 | "version": 3 333 | }, 334 | "file_extension": ".py", 335 | "mimetype": "text/x-python", 336 | "name": "python", 337 | "nbconvert_exporter": "python", 338 | "pygments_lexer": "ipython3", 339 | "version": "3.9.1" 340 | } 341 | }, 342 | "nbformat": 4, 343 | "nbformat_minor": 5 344 | } 345 | -------------------------------------------------------------------------------- /tutorials/02_uploading_program.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "55f13cc7", 6 | "metadata": {}, 7 | "source": [ 8 | "# Uploading a Qiskit runtime program" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "4ff8d2da", 14 | "metadata": {}, 15 | "source": [ 16 | "
\n", 17 | "Note: Qiskit Runtime allows authorized users to upload runtime programs. Access to the Qiskit Runtime service may not mean you have access to upload a runtime program.\n", 18 | "
" 19 | ] 20 | }, 21 | { 22 | "cell_type": "markdown", 23 | "id": "2077b996", 24 | "metadata": {}, 25 | "source": [ 26 | "Here we provide an overview on how to construct and upload a runtime program. A runtime program is a piece of Python code that lives in the cloud and can be invoked by passing in just its parameters. Runtime programs are private by default, which means only you can see and access your programs. Some authorized users can also mark their programs as public, making them visible and accessible by everyone." 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "id": "cf42076e", 32 | "metadata": {}, 33 | "source": [ 34 | "## Constructing a runtime program" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "id": "e282eccc", 40 | "metadata": {}, 41 | "source": [ 42 | "Below is a template of a runtime program. You can find the template file in the \n", 43 | "[`qiskit-ibmq-provider`](https://github.com/Qiskit/qiskit-ibmq-provider/blob/master/qiskit/providers/ibmq/runtime/program/program_template.py) repository." 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 1, 49 | "id": "1206f612", 50 | "metadata": {}, 51 | "outputs": [], 52 | "source": [ 53 | "import sys\n", 54 | "import json\n", 55 | "\n", 56 | "from qiskit.providers.ibmq.runtime import UserMessenger, ProgramBackend\n", 57 | "\n", 58 | "\n", 59 | "def program(backend: ProgramBackend, user_messenger: UserMessenger, **kwargs):\n", 60 | " \"\"\"Function that does classical-quantum calculation.\"\"\"\n", 61 | " # UserMessenger can be used to publish interim results.\n", 62 | " user_messenger.publish(\"This is an interim result.\")\n", 63 | " return \"final result\"\n", 64 | "\n", 65 | "\n", 66 | "def main(backend: ProgramBackend, user_messenger: UserMessenger, **kwargs):\n", 67 | " \"\"\"This is the main entry point of a runtime program.\n", 68 | "\n", 69 | " The name of this method must not change. It also must have ``backend``\n", 70 | " and ``user_messenger`` as the first two positional arguments.\n", 71 | "\n", 72 | " Args:\n", 73 | " backend: Backend for the circuits to run on.\n", 74 | " user_messenger: Used to communicate with the program user.\n", 75 | " kwargs: User inputs.\n", 76 | " \"\"\"\n", 77 | " # Massage the input if necessary.\n", 78 | " result = program(backend, user_messenger, **kwargs)\n", 79 | " # Final result can be directly returned\n", 80 | " return result\n" 81 | ] 82 | }, 83 | { 84 | "cell_type": "markdown", 85 | "id": "bb4cfa8b", 86 | "metadata": {}, 87 | "source": [ 88 | "Each runtime program must have a `main()` function, which serves as the entry point to the program. This function must have `backend` and `user_messenger` as the first two positional arguments:\n", 89 | "\n", 90 | "- `backend` is an instance of [`ProgramBackend`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.ProgramBackend.html#qiskit.providers.ibmq.runtime.ProgramBackend) and has a [`run()`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.ProgramBackend.run.html#qiskit.providers.ibmq.runtime.ProgramBackend.run) method that can be used to submit circuits.\n", 91 | "- `user_messenger` is an instance of [`UserMessenger`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.UserMessenger.html#qiskit.providers.ibmq.runtime.UserMessenger) and has a [`publish()`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.UserMessenger.publish.html#qiskit.providers.ibmq.runtime.UserMessenger.publish) method that can be used to send interim and final results to the program user. This method takes a parameter `final` that indicates whether it's a final result. However, it is recommended to return the final result directly from the `main()` function. Currently only final results are stored after a program execution finishes." 92 | ] 93 | }, 94 | { 95 | "cell_type": "markdown", 96 | "id": "705ccef3", 97 | "metadata": {}, 98 | "source": [ 99 | "There are several runtime programs in the `qiskit_runtime` directory in this repository. `qiskit_runtime/hello_world/hello_world.py` is one of them. It is a sample runtime program that submits random circuits for user-specified iterations:" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 2, 105 | "id": "181916df", 106 | "metadata": {}, 107 | "outputs": [], 108 | "source": [ 109 | "\"\"\"A sample runtime program that submits random circuits for user-specified iterations.\"\"\"\n", 110 | "\n", 111 | "import random\n", 112 | "\n", 113 | "from qiskit import transpile\n", 114 | "from qiskit.circuit.random import random_circuit\n", 115 | "\n", 116 | "\n", 117 | "def prepare_circuits(backend):\n", 118 | " \"\"\"Generate a random circuit.\n", 119 | "\n", 120 | " Args:\n", 121 | " backend: Backend used for transpilation.\n", 122 | "\n", 123 | " Returns:\n", 124 | " Generated circuit.\n", 125 | " \"\"\"\n", 126 | " circuit = random_circuit(num_qubits=5, depth=4, measure=True,\n", 127 | " seed=random.randint(0, 1000))\n", 128 | " return transpile(circuit, backend)\n", 129 | "\n", 130 | "\n", 131 | "def main(backend, user_messenger, **kwargs):\n", 132 | " \"\"\"Main entry point of the program.\n", 133 | "\n", 134 | " Args:\n", 135 | " backend: Backend to submit the circuits to.\n", 136 | " user_messenger: Used to communicate with the program consumer.\n", 137 | " kwargs: User inputs.\n", 138 | " \"\"\"\n", 139 | " iterations = kwargs.pop('iterations', 5)\n", 140 | " for it in range(iterations):\n", 141 | " qc = prepare_circuits(backend)\n", 142 | " result = backend.run(qc).result()\n", 143 | " user_messenger.publish({\"iteration\": it, \"counts\": result.get_counts()})\n", 144 | "\n", 145 | " return \"All done!\"\n" 146 | ] 147 | }, 148 | { 149 | "cell_type": "markdown", 150 | "id": "1281b655", 151 | "metadata": {}, 152 | "source": [ 153 | "## Data serialization" 154 | ] 155 | }, 156 | { 157 | "cell_type": "markdown", 158 | "id": "9edb1023", 159 | "metadata": {}, 160 | "source": [ 161 | "Runtime programs live in the cloud, and JSON is the standard way of passing data to and from cloud services. Therefore, when a user invokes a runtime program, the input parameters must first be serialized into the JSON format and then deserialized once received by the server. By default, this serialization and deserialization is done automatically using the [`RuntimeEncoder`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.RuntimeEncoder.html#qiskit.providers.ibmq.runtime.RuntimeEncoder) and [`RuntimeDecoder`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.RuntimeDecoder.html#qiskit.providers.ibmq.runtime.RuntimeDecoder) classes.\n" 162 | ] 163 | }, 164 | { 165 | "cell_type": "markdown", 166 | "id": "8b4aeb2b", 167 | "metadata": {}, 168 | "source": [ 169 | "### Custom classes" 170 | ] 171 | }, 172 | { 173 | "cell_type": "markdown", 174 | "id": "1d7fbdf5", 175 | "metadata": {}, 176 | "source": [ 177 | "`RuntimeEncoder` and `RuntimeDecoder` only support types commonly used in Qiskit, such as complex numbers and numpy arrays. If your program uses custom Python classes for input or output, these two methods only have partial support for that. \n", 178 | "\n", 179 | "Your custom class should have the following methods:\n", 180 | "\n", 181 | "- a `to_json()` method that returns a JSON string representation of the object\n", 182 | "- a `from_json()` class method that accepts a JSON string and returns the corresponding object. \n", 183 | "\n", 184 | "When `RuntimeEncoder` serializes a Python object, it checks whether the object has a `to_json()` method. If so, it calls the method to serialize the object. `RuntimeDecoder`, however, does _not_ invoke `from_json()` to convert the data back because it doesn't know how to import your custom class. Therefore the deserialization needs to be done explicitly. " 185 | ] 186 | }, 187 | { 188 | "cell_type": "markdown", 189 | "id": "c3e2d6e2", 190 | "metadata": {}, 191 | "source": [ 192 | "Here is an example of serializing and deserializing a custom class. First we define the class `MyCustomClass`:" 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": 3, 198 | "id": "ca9047fc", 199 | "metadata": {}, 200 | "outputs": [], 201 | "source": [ 202 | "import json\n", 203 | "\n", 204 | "class MyCustomClass:\n", 205 | " \n", 206 | " def __init__(self, foo, bar):\n", 207 | " self._foo = foo\n", 208 | " self._bar = bar\n", 209 | " \n", 210 | " def to_json(self):\n", 211 | " \"\"\"Convert this instance to a JSON string.\"\"\"\n", 212 | " return json.dumps({\"foo\": self._foo, \"bar\": self._bar})\n", 213 | " \n", 214 | " @classmethod\n", 215 | " def from_json(cls, json_str):\n", 216 | " \"\"\"Return a MyCustomClass instance based on the input JSON string.\"\"\"\n", 217 | " return cls(**json.loads(json_str))" 218 | ] 219 | }, 220 | { 221 | "cell_type": "markdown", 222 | "id": "31f967a4", 223 | "metadata": {}, 224 | "source": [ 225 | "Note that it has the `to_json()` method that converts a `MyCustomClass` instance to a JSON string, and a `from_json()` class method that converts a JSON string back to a `MyCustomClass` instance." 226 | ] 227 | }, 228 | { 229 | "cell_type": "markdown", 230 | "id": "2fdf8941", 231 | "metadata": {}, 232 | "source": [ 233 | "Here is how one would use `MyCustomClass` as an **input** to your program:" 234 | ] 235 | }, 236 | { 237 | "cell_type": "markdown", 238 | "id": "258fcd02", 239 | "metadata": {}, 240 | "source": [ 241 | "```\n", 242 | "program_inputs = {\n", 243 | " 'my_obj': MyCustomClass(\"my foo\", \"my bar\")\n", 244 | "}\n", 245 | "\n", 246 | "options = {\"backend_name\": \"ibmq_qasm_simulator\"}\n", 247 | "job = provider.runtime.run(program_id=\"some-program\",\n", 248 | " options=options,\n", 249 | " inputs=program_inputs\n", 250 | " )\n", 251 | "```" 252 | ] 253 | }, 254 | { 255 | "cell_type": "markdown", 256 | "id": "dc86356b", 257 | "metadata": {}, 258 | "source": [ 259 | "Since `MyCustomClass` has a `to_json()` method, the method is automatically called to convert the instance to a JSON string when `provider.runtime.run()` is invoked. \n", 260 | "\n", 261 | "Your program can then use the `from_json()` method to restore the JSON string back to a `MyCustomClass` instance:" 262 | ] 263 | }, 264 | { 265 | "cell_type": "code", 266 | "execution_count": 4, 267 | "id": "681a1798", 268 | "metadata": {}, 269 | "outputs": [], 270 | "source": [ 271 | "def main(backend, user_messenger, **kwargs):\n", 272 | " \"\"\"Main entry point of the program.\"\"\"\n", 273 | " my_obj_str = kwargs.pop('my_obj')\n", 274 | " my_obj = MyCustomClass.from_json(my_obj_str)" 275 | ] 276 | }, 277 | { 278 | "cell_type": "markdown", 279 | "id": "b71c40bc", 280 | "metadata": {}, 281 | "source": [ 282 | "Similarly, if you pass a `MyCustomClass` instance as an **output** of your program, it is automatically converted to a JSON string (via the `to_json()` method):" 283 | ] 284 | }, 285 | { 286 | "cell_type": "code", 287 | "execution_count": 5, 288 | "id": "f4cf18b4", 289 | "metadata": {}, 290 | "outputs": [], 291 | "source": [ 292 | "def main(backend, user_messenger, **kwargs):\n", 293 | " \"\"\"Main entry point of the program.\"\"\"\n", 294 | " return MyCustomClass(\"this foo\", \"that bar\")" 295 | ] 296 | }, 297 | { 298 | "cell_type": "markdown", 299 | "id": "8e0fdb4a", 300 | "metadata": {}, 301 | "source": [ 302 | "Now when the user of this program calls `job.result()`, they will receive a JSON string rather than a `MyCustomClass` instance. The user can convert the string back to `MyCustomClass` themselves:" 303 | ] 304 | }, 305 | { 306 | "cell_type": "markdown", 307 | "id": "abf149cc", 308 | "metadata": {}, 309 | "source": [ 310 | "```\n", 311 | "output_str = job.result()\n", 312 | "output = MyCustomClass.from_json(output_str)\n", 313 | "```" 314 | ] 315 | }, 316 | { 317 | "cell_type": "markdown", 318 | "id": "32cd0c7e", 319 | "metadata": {}, 320 | "source": [ 321 | "Alternatively, you can provide a decoder for the users. Your decoder class should inherit [`ResultDecoder`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.ResultDecoder.html#qiskit.providers.ibmq.runtime.ResultDecoder) and overwrites the `decode()` method:" 322 | ] 323 | }, 324 | { 325 | "cell_type": "code", 326 | "execution_count": 6, 327 | "id": "a2f8564d", 328 | "metadata": {}, 329 | "outputs": [], 330 | "source": [ 331 | "from qiskit.providers.ibmq.runtime import ResultDecoder\n", 332 | "\n", 333 | "class MyResultDecoder(ResultDecoder):\n", 334 | "\n", 335 | " @classmethod\n", 336 | " def decode(cls, data):\n", 337 | " data = super().decoded(data) # Perform any preprocessing.\n", 338 | " return MyCustomClass.from_json(data)" 339 | ] 340 | }, 341 | { 342 | "cell_type": "markdown", 343 | "id": "3d0de7d0", 344 | "metadata": {}, 345 | "source": [ 346 | "Your user can then use this `MyResultDecoder` to decode the result of your program:\n", 347 | "\n", 348 | "```\n", 349 | "output = job.result(decoder=MyResultDecoder)\n", 350 | "```" 351 | ] 352 | }, 353 | { 354 | "cell_type": "markdown", 355 | "id": "ecdda3bf", 356 | "metadata": {}, 357 | "source": [ 358 | "## Testing your runtime program" 359 | ] 360 | }, 361 | { 362 | "cell_type": "markdown", 363 | "id": "2a18f49e", 364 | "metadata": {}, 365 | "source": [ 366 | "You can test your runtime program using a local simulator or a real backend before uploading it. Simply import and invoke the `main()` function of your program and pass the following parameters:\n", 367 | "\n", 368 | "- the `backend` instance you want to use\n", 369 | "- a new `UserMessenger` instance.\n", 370 | "- program input parameters that are serialized and then deserialized using the correct encoder and decoder. While this may seem redundant, it is to ensure input parameters can be passed to your program properly once it's uploaded to the cloud.\n" 371 | ] 372 | }, 373 | { 374 | "cell_type": "markdown", 375 | "id": "f197d48e", 376 | "metadata": {}, 377 | "source": [ 378 | "The following example tests the `hello-world` program we saw earlier. It uses the `qasm_simulator` from Qiskit Aer as the test backend. It serializes and deserializes input data using `RuntimeEncoder` and `RuntimeDecoder`, which are the default en/decoders used by runtime." 379 | ] 380 | }, 381 | { 382 | "cell_type": "code", 383 | "execution_count": 7, 384 | "id": "12c32ba7", 385 | "metadata": {}, 386 | "outputs": [ 387 | { 388 | "name": "stdout", 389 | "output_type": "stream", 390 | "text": [ 391 | "{\"iteration\": 0, \"counts\": {\"01000\": 4, \"00000\": 12, \"00011\": 872, \"01011\": 136}}\n", 392 | "{\"iteration\": 1, \"counts\": {\"01000\": 6, \"00000\": 19, \"00011\": 871, \"01011\": 128}}\n", 393 | "{\"iteration\": 2, \"counts\": {\"00001\": 1024}}\n" 394 | ] 395 | }, 396 | { 397 | "data": { 398 | "text/plain": [ 399 | "'All done!'" 400 | ] 401 | }, 402 | "execution_count": 7, 403 | "metadata": {}, 404 | "output_type": "execute_result" 405 | } 406 | ], 407 | "source": [ 408 | "import sys\n", 409 | "sys.path.insert(0, '..') # Add qiskit_runtime directory to the path\n", 410 | "\n", 411 | "from qiskit_runtime.hello_world import hello_world\n", 412 | "from qiskit import Aer\n", 413 | "from qiskit.providers.ibmq.runtime.utils import RuntimeEncoder, RuntimeDecoder\n", 414 | "from qiskit.providers.ibmq.runtime import UserMessenger\n", 415 | "\n", 416 | "inputs = {\"iterations\": 3}\n", 417 | "\n", 418 | "backend = Aer.get_backend('qasm_simulator')\n", 419 | "user_messenger = UserMessenger()\n", 420 | "serialized_inputs = json.dumps(inputs, cls=RuntimeEncoder)\n", 421 | "deserialized_inputs = json.loads(serialized_inputs, cls=RuntimeDecoder)\n", 422 | "\n", 423 | "hello_world.main(backend, user_messenger, **deserialized_inputs)" 424 | ] 425 | }, 426 | { 427 | "cell_type": "markdown", 428 | "id": "501a66f3", 429 | "metadata": {}, 430 | "source": [ 431 | "## Defining program metadata" 432 | ] 433 | }, 434 | { 435 | "cell_type": "markdown", 436 | "id": "f98640c1", 437 | "metadata": {}, 438 | "source": [ 439 | "Program metadata helps users to understand how to use your program. It includes:\n", 440 | "\n", 441 | "- `name`: Name of the program.\n", 442 | "- `max_execution_time`: Maximum amount of time, in seconds, a program can run before being forcibly terminated.\n", 443 | "- `description`: Describes the program.\n", 444 | "- `spec`: Detailed information about the program, which includes the following attributes:\n", 445 | " - `backend_requirements`: Describes the backend attributes needed to run the program.\n", 446 | " - `parameters`: Describes the program input parameters as a JSON schema\n", 447 | " - `return_values`: Describes the return values as a JSON schema\n", 448 | " - `interim_results`: Describes the interim results as a JSON schema\n", 449 | "\n", 450 | "When uploading a program, you must specify at least `name`, `max_execution_time`, and `description`. It is strongly encouraged to also specify `parameters`, `return_values`, and `interim_results` within `spec` if the program has them.\n", 451 | "Note that the maximum job timeout within the API module acts as an upper bound for the `max_execution_time`, set as shown in the following table. A *premium user* here means a user who has access to more than one hub/group/project.\n", 452 | "\n", 453 | "\n", 454 | "\n", 455 | " \n", 456 | " \n", 457 | " \n", 458 | " \n", 459 | " \n", 460 | "\n", 461 | "\n", 462 | " \n", 463 | " \n", 464 | " \n", 465 | " \n", 466 | " \n", 467 | " \n", 468 | " \n", 469 | " \n", 470 | " \n", 471 | " \n", 472 | " \n", 473 | " \n", 474 | " \n", 475 | " \n", 476 | " \n", 477 | " \n", 478 | " \n", 479 | " \n", 480 | " \n", 481 | " \n", 482 | " \n", 483 | "\n", 484 | "
Public Program (IBM Only)Private Program
Premium UserOpen UserPremium UserOpen User
Simulated Device3h1h3h1h
Real Device8h4h8h2h
" 485 | ] 486 | }, 487 | { 488 | "cell_type": "markdown", 489 | "id": "55db2a39", 490 | "metadata": {}, 491 | "source": [ 492 | "Below shows the metadata JSON file of the `hello-world` program as an example:" 493 | ] 494 | }, 495 | { 496 | "cell_type": "code", 497 | "execution_count": 8, 498 | "id": "3cdce276", 499 | "metadata": {}, 500 | "outputs": [ 501 | { 502 | "name": "stdout", 503 | "output_type": "stream", 504 | "text": [ 505 | "{\n", 506 | " \"name\": \"hello-world\",\n", 507 | " \"description\": \"A sample runtime program.\",\n", 508 | " \"max_execution_time\": 300,\n", 509 | " \"spec\": {\n", 510 | " \"backend_requirements\": {\n", 511 | " \"min_num_qubits\": 5\n", 512 | " },\n", 513 | " \"parameters\": {\n", 514 | " \"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\n", 515 | " \"properties\": {\n", 516 | " \"iterations\": {\n", 517 | " \"type\": \"integer\",\n", 518 | " \"minimum\": 0,\n", 519 | " \"description\": \"Number of iterations to run. Each iteration generates a runs a random circuit.\"\n", 520 | " }\n", 521 | " },\n", 522 | " \"required\": [\n", 523 | " \"iterations\"\n", 524 | " ]\n", 525 | " },\n", 526 | " \"return_values\": {\n", 527 | " \"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\n", 528 | " \"description\": \"A string that says 'All done!'.\",\n", 529 | " \"type\": \"string\"\n", 530 | " },\n", 531 | " \"interim_results\": {\n", 532 | " \"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\n", 533 | " \"properties\": {\n", 534 | " \"iteration\": {\n", 535 | " \"type\": \"integer\",\n", 536 | " \"description\": \"Iteration number.\"\n", 537 | " },\n", 538 | " \"counts\": {\n", 539 | " \"description\": \"Histogram data of the circuit result.\",\n", 540 | " \"type\": \"object\"\n", 541 | " }\n", 542 | " }\n", 543 | " }\n", 544 | " }\n", 545 | "}\n", 546 | "\n" 547 | ] 548 | } 549 | ], 550 | "source": [ 551 | "import os\n", 552 | "\n", 553 | "hello_world_json = os.path.join(os.getcwd(), \"../qiskit_runtime/hello_world/hello_world.json\")\n", 554 | "\n", 555 | "with open(hello_world_json, 'r') as file:\n", 556 | " data = file.read()\n", 557 | "\n", 558 | "print(data)" 559 | ] 560 | }, 561 | { 562 | "cell_type": "markdown", 563 | "id": "43dd6a77", 564 | "metadata": {}, 565 | "source": [ 566 | "## Uploading a program" 567 | ] 568 | }, 569 | { 570 | "cell_type": "markdown", 571 | "id": "d1865c58", 572 | "metadata": {}, 573 | "source": [ 574 | "You can use the [`IBMRuntimeService.upload_program()`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.IBMRuntimeService.html#qiskit.providers.ibmq.runtime.IBMRuntimeService.upload_program) method to upload your program. In the example below, the program data lives in the file `hello_world.py`, and its metadata, as described above, is in `hello_world.json`. " 575 | ] 576 | }, 577 | { 578 | "cell_type": "code", 579 | "execution_count": 9, 580 | "id": "864ab085", 581 | "metadata": {}, 582 | "outputs": [ 583 | { 584 | "name": "stdout", 585 | "output_type": "stream", 586 | "text": [ 587 | "hello-world-nQ9dgRjGEe\n" 588 | ] 589 | } 590 | ], 591 | "source": [ 592 | "import os\n", 593 | "from qiskit import IBMQ\n", 594 | "\n", 595 | "IBMQ.load_account()\n", 596 | "provider = IBMQ.get_provider(project='qiskit-runtime') # Substitute with your provider.\n", 597 | "\n", 598 | "hello_world_data = os.path.join(os.getcwd(), \"../qiskit_runtime/hello_world/hello_world.py\")\n", 599 | "hello_world_json = os.path.join(os.getcwd(), \"../qiskit_runtime/hello_world/hello_world.json\")\n", 600 | "\n", 601 | "program_id = provider.runtime.upload_program(\n", 602 | " data=hello_world_data,\n", 603 | " metadata=hello_world_json\n", 604 | ")\n", 605 | "print(program_id)" 606 | ] 607 | }, 608 | { 609 | "cell_type": "markdown", 610 | "id": "45ffd6c8", 611 | "metadata": {}, 612 | "source": [ 613 | "`upload_program()` returns a program ID, which uniquely identifies the program. It is derived from the program name, usually with a randomly-generated suffix. Program ID is needed for users to invoke the program" 614 | ] 615 | }, 616 | { 617 | "cell_type": "markdown", 618 | "id": "chubby-infection", 619 | "metadata": {}, 620 | "source": [ 621 | "## Updating a program" 622 | ] 623 | }, 624 | { 625 | "cell_type": "markdown", 626 | "id": "measured-catalyst", 627 | "metadata": {}, 628 | "source": [ 629 | "You can use the [`IBMRuntimeService.update_program()`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.IBMRuntimeService.update_program.html#qiskit.providers.ibmq.runtime.IBMRuntimeService.update_program) method to update the source code and/or metadata of a program:" 630 | ] 631 | }, 632 | { 633 | "cell_type": "code", 634 | "execution_count": null, 635 | "id": "southern-farmer", 636 | "metadata": {}, 637 | "outputs": [], 638 | "source": [ 639 | "provider.runtime.update_program(program_id=program_id, description=\"A new description.\")" 640 | ] 641 | }, 642 | { 643 | "cell_type": "markdown", 644 | "id": "becoming-badge", 645 | "metadata": {}, 646 | "source": [ 647 | "This method allows you to make changes to your program while retaining the same program ID." 648 | ] 649 | }, 650 | { 651 | "cell_type": "markdown", 652 | "id": "f841041c", 653 | "metadata": {}, 654 | "source": [ 655 | "## Deleting a program" 656 | ] 657 | }, 658 | { 659 | "cell_type": "markdown", 660 | "id": "a20cd296", 661 | "metadata": {}, 662 | "source": [ 663 | "You can use the [`IBMRuntimeService.delete_program()`](https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.runtime.IBMRuntimeService.html#qiskit.providers.ibmq.runtime.IBMRuntimeService.delete_program) method to delete a program. Only the person who uploaded the program can delete it. \n" 664 | ] 665 | } 666 | ], 667 | "metadata": { 668 | "kernelspec": { 669 | "display_name": "Python 3", 670 | "language": "python", 671 | "name": "python3" 672 | }, 673 | "language_info": { 674 | "codemirror_mode": { 675 | "name": "ipython", 676 | "version": 3 677 | }, 678 | "file_extension": ".py", 679 | "mimetype": "text/x-python", 680 | "name": "python", 681 | "nbconvert_exporter": "python", 682 | "pygments_lexer": "ipython3", 683 | "version": "3.9.1" 684 | } 685 | }, 686 | "nbformat": 4, 687 | "nbformat_minor": 5 688 | } 689 | -------------------------------------------------------------------------------- /tutorials/API_direct.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "b4263208", 6 | "metadata": {}, 7 | "source": [ 8 | "# Qiskit Runtime API" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "fa65772b", 14 | "metadata": {}, 15 | "source": [ 16 | "Qiskit Runtime is a cloud service that allow you upload and run Qiskit programs in a Qiskit Runtimes near to the QPUs. \n", 17 | "\n", 18 | "In this example we are going to explore how to integrate this Qiskit Runtime in any application using only basic HTTP requests and interact with a the program running in the service.\n", 19 | "\n" 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "id": "b756372c", 25 | "metadata": {}, 26 | "source": [ 27 | "
\n", 28 | "Note: You need to have an IBM Quantum API token. You can get one by signing up at https://quantum-computing.ibm.com/\n", 29 | "
" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "id": "3ee2485c", 35 | "metadata": {}, 36 | "source": [ 37 | "For this tutorial we are going to use the Python HTTP library `requests` to facilitate the API calls.\n", 38 | "\n", 39 | "You can access the online interactive runtime API documentation here: https://runtime-us-east.quantum-computing.ibm.com/openapi/" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": 70, 45 | "id": "ddb6c73b", 46 | "metadata": {}, 47 | "outputs": [], 48 | "source": [ 49 | "import requests\n", 50 | "import json\n", 51 | "import time" 52 | ] 53 | }, 54 | { 55 | "cell_type": "markdown", 56 | "id": "11a669e0", 57 | "metadata": {}, 58 | "source": [ 59 | "## Authenticate with the service " 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 51, 65 | "id": "90b25676", 66 | "metadata": {}, 67 | "outputs": [], 68 | "source": [ 69 | "# you need to pass your API token in the header of every call\n", 70 | "\n", 71 | "headers = {\n", 72 | " 'Authorization': f'Bearer {Your_API_TOKEN}',\n", 73 | " 'Content-Type': 'application/json'\n", 74 | "}\n", 75 | "\n", 76 | "Runtime_API_URL = \"https://runtime-us-east.quantum-computing.ibm.com/\"" 77 | ] 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "id": "92c99e95", 82 | "metadata": {}, 83 | "source": [ 84 | "## Get a list of program that you can invoke " 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": 52, 90 | "id": "e30e589d", 91 | "metadata": {}, 92 | "outputs": [ 93 | { 94 | "output_type": "stream", 95 | "name": "stdout", 96 | "text": "Qiskit Runtime Programs:\n- qasm3-runner: A runtime program that takes one or more circuits, converts them to OpenQASM3, compiles them, executes them, and optionally applies measurement error mitigation. This program can also take and execute one or more OpenQASM3 strings. Note that this program can only run on a backend that supports OpenQASM3. \n- sampler: Sample distributions generated by given circuits executed on the target backend. \n- estimator: Expectation value estimator. A runtime program that estimates the value of an observable for an input quantum circuit. This program is in beta mode and is only available to select accounts. \n- sample-expval: A sample expectation value program. \n- vqe: Variational Quantum Eigensolver (VQE) to find the minimal eigenvalue of a Hamiltonian. \n- circuit-runner: A runtime program that takes one or more circuits, compiles them, executes them, and optionally applies measurement error mitigation. \n- hello-world: A sample runtime program. \n- quantum-kernel-alignment: Quantum kernel alignment algorithm that learns, on a given dataset, a quantum kernel maximizing the SVM classification margin. \n" 97 | } 98 | ], 99 | "source": [ 100 | "\n", 101 | "# Call the API passing the API Token and get the programs\n", 102 | "\n", 103 | "response = requests.get(Runtime_API_URL + 'programs' , headers = headers)\n", 104 | "\n", 105 | "list_of_programs = {}\n", 106 | "if response.status_code == 200:\n", 107 | " list_of_programs = response.json()\n", 108 | "else:\n", 109 | " print(f'Error:{response.status_code}')\n", 110 | " exit()\n", 111 | " \n", 112 | "print(f'Qiskit Runtime Programs:')\n", 113 | "\n", 114 | "for program in list_of_programs[\"programs\"]:\n", 115 | " print(f'- {program[\"name\"]}: {program[\"description\"]} ')\n", 116 | "" 117 | ] 118 | }, 119 | { 120 | "cell_type": "markdown", 121 | "id": "048da401", 122 | "metadata": {}, 123 | "source": [ 124 | "## Display information about a specific program" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 53, 130 | "id": "94493809", 131 | "metadata": {}, 132 | "outputs": [ 133 | { 134 | "output_type": "stream", 135 | "name": "stdout", 136 | "text": "Qiskit Program details:\n\n{\n \"id\": \"qasm3-runner\",\n \"name\": \"qasm3-runner\",\n \"cost\": 14400,\n \"description\": \"A runtime program that takes one or more circuits, converts them to OpenQASM3, compiles them, executes them, and optionally applies measurement error mitigation. This program can also take and execute one or more OpenQASM3 strings. Note that this program can only run on a backend that supports OpenQASM3.\",\n \"creation_date\": \"2021-11-08T18:28:28Z\",\n \"update_date\": \"2021-11-10T17:10:19.353876Z\",\n \"is_public\": true,\n \"spec\": {\n \"backend_requirements\": {\n \"input_allowed\": \"qasm3\"\n },\n \"parameters\": {\n \"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\n \"properties\": {\n \"circuits\": {\n \"description\": \"A circuit/OpenQASM3 string or a list of circuits/OpenQASM3 strings (real backend only).\",\n \"type\": [\n \"object\",\n \"array\",\n \"string\"\n ]\n },\n \"exporter_config\": {\n \"description\": \"Options to use when converting circuits to QASM3 strings, if applicable.\",\n \"type\": \"object\"\n },\n \"qasm3_args\": {\n \"description\": \"Input arguments to the OpenQASM3 program. Only supported when running on a simulator.\",\n \"type\": [\n \"object\",\n \"array\"\n ]\n },\n \"run_config\": {\n \"description\": \"Execution time options. QSAM3 simulator supports 'shots', and real backends support both 'shots' and 'rep_delay'.\",\n \"type\": \"object\"\n },\n \"skip_transpilation\": {\n \"default\": false,\n \"description\": \"Skip circuit transpilation.\",\n \"type\": \"boolean\"\n },\n \"transpiler_config\": {\n \"description\": \"Compilation options.\",\n \"type\": \"object\"\n },\n \"use_measurement_mitigation\": {\n \"default\": false,\n \"description\": \"Whether to apply measurement error mitigation. Currently, error mitigation only applies to QuantumCircuit.\",\n \"type\": \"boolean\"\n }\n },\n \"required\": [\n \"circuits\"\n ]\n },\n \"return_values\": {\n \"$schema\": \"https://json-schema.org/draft/2019-09/schema\",\n \"description\": \"Execution results. A RunnerResult object is returned if a real backend is used. Otherwise a list of per-shot result is returned for each circuit.\",\n \"type\": [\n \"object\",\n \"array\"\n ]\n }\n }\n}\n" 137 | } 138 | ], 139 | "source": [ 140 | "print('Qiskit Program details:\\n')\n", 141 | "\n", 142 | "qiskit_runtime_program = json.dumps(list_of_programs[\"programs\"][0], indent=2) \n", 143 | " \n", 144 | "print(qiskit_runtime_program)" 145 | ] 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "id": "a1d812fd", 150 | "metadata": {}, 151 | "source": [ 152 | "## Run a Qiskit Runtime program on the Cloud" 153 | ] 154 | }, 155 | { 156 | "cell_type": "code", 157 | "execution_count": 83, 158 | "id": "61922aeb", 159 | "metadata": {}, 160 | "outputs": [ 161 | { 162 | "name": "stdout", 163 | "output_type": "stream", 164 | "text": [ 165 | " status: 200, Job: c2b04fot418h0qp0peh0\n" 166 | ] 167 | } 168 | ], 169 | "source": [ 170 | "Runtime_program = \"hello-world\"\n", 171 | "\n", 172 | "program_input = {\"iterations\":2} \n", 173 | "\n", 174 | "def run_runtime_program(program_name, program_input):\n", 175 | " # configuing your IBM Provider data\n", 176 | " params = json.dumps({\n", 177 | " \"program_id\": Runtime_program,\n", 178 | " \"hub\": \"ibm-q-internal\",\n", 179 | " \"group\": \"near-time\",\n", 180 | " \"project\": \"qiskit-runtime\",\n", 181 | " \"backend\": \"ibmq_montreal\",\n", 182 | " \"params\": program_input\n", 183 | " })\n", 184 | "\n", 185 | " job_ID = ''\n", 186 | "\n", 187 | " response = requests.post(Runtime_API_URL + 'jobs', data=params, headers=headers)\n", 188 | "\n", 189 | " if response.status_code == 200:\n", 190 | " job_ID = response.json()['id']\n", 191 | " return 200, job_ID\n", 192 | " else:\n", 193 | " return response.status_code, None\n", 194 | "\n", 195 | " \n", 196 | "status, job_ID = run_runtime_program(Runtime_program, program_input)\n", 197 | "\n", 198 | "print(f' status: {status}, Job: {job_ID}')\n", 199 | "\n", 200 | " " 201 | ] 202 | }, 203 | { 204 | "cell_type": "markdown", 205 | "id": "ad5fa5f6", 206 | "metadata": {}, 207 | "source": [ 208 | "## Get the result" 209 | ] 210 | }, 211 | { 212 | "cell_type": "code", 213 | "execution_count": 81, 214 | "id": "dc385e66", 215 | "metadata": {}, 216 | "outputs": [ 217 | { 218 | "name": "stdout", 219 | "output_type": "stream", 220 | "text": [ 221 | "Waiting for the final result\n", 222 | "Waiting for the final result\n", 223 | "Waiting for the final result\n", 224 | "Waiting for the final result\n", 225 | "Waiting for the final result\n", 226 | "Waiting for the final result\n", 227 | "Waiting for the final result\n", 228 | "Waiting for the final result\n", 229 | "Waiting for the final result\n", 230 | "Waiting for the final result\n", 231 | "Waiting for the final result\n", 232 | "Waiting for the final result\n", 233 | "Waiting for the final result\n", 234 | "Waiting for the final result\n", 235 | "Waiting for the final result\n", 236 | "Waiting for the final result\n", 237 | "Waiting for the final result\n", 238 | "Waiting for the final result\n", 239 | "Waiting for the final result\n", 240 | "Waiting for the final result\n", 241 | "Waiting for the final result\n", 242 | "Waiting for the final result\n", 243 | "Waiting for the final result\n", 244 | "Final Result: All done!\n" 245 | ] 246 | } 247 | ], 248 | "source": [ 249 | "# You are going to get a 204 status code while the Qiskit program is still running.\n", 250 | "\n", 251 | "final_result = False\n", 252 | "\n", 253 | "while not final_result:\n", 254 | " \n", 255 | " response = requests.get(Runtime_API_URL + 'jobs/'+ job_ID +'/results', headers=headers)\n", 256 | "\n", 257 | " if response.status_code == 200:\n", 258 | " print(f'Final Result: {response.text}')\n", 259 | " final_result = True\n", 260 | " \n", 261 | " elif response.status_code == 204:\n", 262 | " print(f'Waiting for the final result')\n", 263 | " time.sleep(2)\n", 264 | " \n", 265 | " else:\n", 266 | " print(f'Error:{response.status_code}')\n", 267 | " break" 268 | ] 269 | } 270 | ], 271 | "metadata": { 272 | "kernelspec": { 273 | "display_name": "Python 3", 274 | "language": "python", 275 | "name": "python3" 276 | }, 277 | "language_info": { 278 | "codemirror_mode": { 279 | "name": "ipython", 280 | "version": 3 281 | }, 282 | "file_extension": ".py", 283 | "mimetype": "text/x-python", 284 | "name": "python", 285 | "nbconvert_exporter": "python", 286 | "pygments_lexer": "ipython3", 287 | "version": "3.9.1" 288 | } 289 | }, 290 | "nbformat": 4, 291 | "nbformat_minor": 5 292 | } 293 | -------------------------------------------------------------------------------- /tutorials/images/chip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit-Partners/qiskit-runtime/15f5712f35e942d50689ad54e352aa89cfde0901/tutorials/images/chip.png -------------------------------------------------------------------------------- /tutorials/images/subgraphs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit-Partners/qiskit-runtime/15f5712f35e942d50689ad54e352aa89cfde0901/tutorials/images/subgraphs.png -------------------------------------------------------------------------------- /tutorials/sample_expval_program/sample_expval.py: -------------------------------------------------------------------------------- 1 | import mthree 2 | from qiskit import transpile 3 | 4 | # The entrypoint for our Runtime Program 5 | def main(backend, user_messenger, 6 | circuits, 7 | expectation_operators='', 8 | shots = 8192, 9 | transpiler_config={}, 10 | run_config={}, 11 | skip_transpilation=False, 12 | return_stddev=False, 13 | use_measurement_mitigation=False, 14 | ): 15 | 16 | """Compute expectation values for a list of operators after 17 | executing a list of circuits on the target backend. 18 | 19 | Parameters: 20 | backend (ProgramBackend): Qiskit backend instance. 21 | user_messenger (UserMessenger): Used to communicate with the program user. 22 | circuits: (QuantumCircuit or list): A single list of QuantumCircuits. 23 | expectation_operators (str or dict or list): Expectation values to evaluate. 24 | shots (int): Number of shots to take per circuit. 25 | transpiler_config (dict): A collection of kwargs passed to transpile(). 26 | run_config (dict): A collection of kwargs passed to backend.run(). 27 | skip_transpilation (bool): Skip transpiling of circuits, default=False. 28 | return_stddev (bool): Return upper bound on standard devitation, 29 | default=False. 30 | use_measurement_mitigation (bool): Improve resulting using measurement 31 | error mitigation, default=False. 32 | 33 | Returns: 34 | array_like: Returns array of expectation values or a list of (expval, stddev) 35 | tuples if return_stddev=True. 36 | """ 37 | 38 | # transpiling the circuits using given transpile options 39 | if not skip_transpilation: 40 | trans_circuits = transpile(circuits, backend=backend, 41 | **transpiler_config) 42 | 43 | if not isinstance(trans_circuits, list): 44 | trans_circuits = [trans_circuits] 45 | # If skipping set circuits -> trans_circuits 46 | else: 47 | if not isinstance(circuits, list): 48 | trans_circuits = [circuits] 49 | else: 50 | trans_circuits = circuits 51 | 52 | # If we are given a single circuit but requesting multiple expectation values 53 | # Then set flag to make multiple pointers to same result. 54 | duplicate_results = False 55 | if isinstance(expectation_operators, list): 56 | if len(expectation_operators) and len(trans_circuits) == 1: 57 | duplicate_results = True 58 | 59 | if use_measurement_mitigation: 60 | # Get an the measurement mappings at end of circuits 61 | meas_maps = mthree.utils.final_measurement_mapping(trans_circuits) 62 | # Get an M3 mitigator 63 | mit = mthree.M3Mitigation(backend) 64 | # Calibrate over the set of qubits measured in the transpiled circuits. 65 | mit.cals_from_system(meas_maps) 66 | 67 | # Compute raw results 68 | result = backend.run(trans_circuits, shots=shots, **run_config).result() 69 | raw_counts = result.get_counts() 70 | 71 | # When using measurement mitigation we need to apply the correction and then 72 | # compute the expectation values from the computed quasi-probabilities. 73 | if use_measurement_mitigation: 74 | quasi_dists = mit.apply_correction(raw_counts, meas_maps, 75 | return_mitigation_overhead=return_stddev) 76 | 77 | if duplicate_results: 78 | quasi_dists = mthree.classes.QuasiCollection([quasi_dists]*len(expectation_operators)) 79 | # There are two different calls depending on what we want returned. 80 | if return_stddev: 81 | return quasi_dists.expval_and_stddev(expectation_operators) 82 | return quasi_dists.expval(expectation_operators) 83 | 84 | # If the program didn't return in the mitigation loop above it means 85 | # we are processing the raw_counts data. We do so here using the 86 | # mthree utilities 87 | if duplicate_results: 88 | raw_counts = [raw_counts]*len(expectation_operators) 89 | if return_stddev: 90 | return mthree.utils.expval_and_stddev(raw_counts, expectation_operators) 91 | return mthree.utils.expval(raw_counts, expectation_operators) 92 | -------------------------------------------------------------------------------- /tutorials/sample_vqe_program/sample_vqe.py: -------------------------------------------------------------------------------- 1 | # This code is part of qiskit-runtime. 2 | # 3 | # (C) Copyright IBM 2021. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | # Grab functions and modules from dependencies 14 | import numpy as np 15 | import scipy.optimize as opt 16 | from scipy.optimize import OptimizeResult 17 | import mthree 18 | 19 | # Grab functions and modules from Qiskit needed 20 | from qiskit import QuantumCircuit, transpile 21 | import qiskit.circuit.library.n_local as lib_local 22 | 23 | 24 | # The entrypoint for our Runtime Program 25 | def main(backend, user_messenger, 26 | hamiltonian, 27 | ansatz='EfficientSU2', 28 | ansatz_config={}, 29 | x0=None, 30 | optimizer='SPSA', 31 | optimizer_config={'maxiter': 100}, 32 | shots = 8192, 33 | use_measurement_mitigation=False 34 | ): 35 | 36 | """ 37 | The main sample VQE program. 38 | 39 | Parameters: 40 | backend (ProgramBackend): Qiskit backend instance. 41 | user_messenger (UserMessenger): Used to communicate with the program user. 42 | hamiltonian (list): Hamiltonian whose ground state we want to find. 43 | ansatz (str): Optional, name of ansatz quantum circuit to use, default='EfficientSU2' 44 | ansatz_config (dict): Optional, configuration parameters for the ansatz circuit. 45 | x0 (array_like): Optional, initial vector of parameters. 46 | optimizer (str): Optional, string specifying classical optimizer, default='SPSA'. 47 | optimizer_config (dict): Optional, configuration parameters for the optimizer. 48 | shots (int): Optional, number of shots to take per circuit. 49 | use_measurement_mitigation (bool): Optional, use measurement mitigation, default=False. 50 | 51 | Returns: 52 | OptimizeResult: The result in SciPy optimization format. 53 | """ 54 | 55 | # Split the Hamiltonian into two arrays, one for coefficients, the other for 56 | # operator strings 57 | coeffs = np.array([item[0] for item in hamiltonian], dtype=complex) 58 | op_strings = [item[1] for item in hamiltonian] 59 | # The number of qubits needed is given by the number of elements in the strings 60 | # the defiune the Hamiltonian. Here we grab this data from the first element. 61 | num_qubits = len(op_strings[0]) 62 | 63 | # We grab the requested ansatz circuit class from the Qiskit circuit library 64 | # n_local module and configure it using the number of qubits and options 65 | # passed in the ansatz_config. 66 | ansatz_instance = getattr(lib_local, ansatz) 67 | ansatz_circuit = ansatz_instance(num_qubits, **ansatz_config) 68 | 69 | # Here we use our convenence function from Appendix B to get measurement circuits 70 | # with the correct single-qubit rotation gates. 71 | meas_circs = opstr_to_meas_circ(op_strings) 72 | 73 | # When computing the expectation value for the energy, we need to know if we 74 | # evaluate a Z measurement or and identity measurement. Here we take and X and Y 75 | # operator in the strings and convert it to a Z since we added the rotations 76 | # with the meas_circs. 77 | meas_strings = [string.replace('X', 'Z').replace('Y', 'Z') for string in op_strings] 78 | 79 | # Take the ansatz circuits, add the single-qubit measurement basis rotations from 80 | # meas_circs, and finally append the measurements themselves. 81 | full_circs = [ansatz_circuit.compose(mcirc).measure_all(inplace=False) for mcirc in meas_circs] 82 | 83 | # Get the number of parameters in the ansatz circuit. 84 | num_params = ansatz_circuit.num_parameters 85 | 86 | # Use a given initial state, if any, or do random initial state. 87 | if x0: 88 | x0 = np.asarray(x0, dtype=float) 89 | if x0.shape[0] != num_params: 90 | raise ValueError('Number of params in x0 ({}) does not match number of ansatz parameters ({})'. format( 91 | x0.shape[0], num_params)) 92 | else: 93 | x0 = 2*np.pi*np.random.rand(num_params) 94 | 95 | # Because we are in general targeting a real quantum system, our circuits must be transpiled 96 | # to match the system topology and, hopefully, optimize them. 97 | # Here we will set the transpiler to the most optimal settings where 'sabre' layout and 98 | # routing are used, along with full O3 optimization. 99 | 100 | # This works around a bug in Qiskit where Sabre routing fails for simulators (Issue #7098) 101 | trans_dict = {} 102 | if not backend.configuration().simulator: 103 | trans_dict = {'layout_method': 'sabre', 'routing_method': 'sabre'} 104 | trans_circs = transpile(full_circs, backend, optimization_level=3, **trans_dict) 105 | 106 | # If using measurement mitigation we need to find out which physical qubits our transpiled 107 | # circuits actually measure, construct a mitigation object targeting our backend, and 108 | # finally calibrate our mitgation by running calibration circuits on the backend. 109 | if use_measurement_mitigation: 110 | maps = mthree.utils.final_measurement_mapping(trans_circs) 111 | mit = mthree.M3Mitigation(backend) 112 | mit.cals_from_system(maps) 113 | 114 | # Here we define a callback function that will stream the optimizer parameter vector 115 | # back to the user after each iteration. This uses the `user_messenger` object. 116 | # Here we convert to a list so that the return is user readable locally, but 117 | # this is not required. 118 | def callback(xk): 119 | user_messenger.publish(list(xk)) 120 | 121 | # This is the primary VQE function executed by the optimizer. This function takes the 122 | # parameter vector as input and returns the energy evaluated using an ansatz circuit 123 | # bound with those parameters. 124 | def vqe_func(params): 125 | # Attach (bind) parameters in params vector to the transpiled circuits. 126 | bound_circs = [circ.bind_parameters(params) for circ in trans_circs] 127 | 128 | # Submit the job and get the resultant counts back 129 | counts = backend.run(bound_circs, shots=shots).result().get_counts() 130 | 131 | # If using measurement mitigation apply the correction and 132 | # compute expectation values from the resultant quasiprobabilities 133 | # using the measurement strings. 134 | if use_measurement_mitigation: 135 | quasi_collection = mit.apply_correction(counts, maps) 136 | expvals = quasi_collection.expval(meas_strings) 137 | # If not doing any mitigation just compute expectation values 138 | # from the raw counts using the measurement strings. 139 | # Since Qiskit does not have such functionality we use the convenence 140 | # function from the mthree mitigation module. 141 | else: 142 | expvals = mthree.utils.expval(counts, meas_strings) 143 | 144 | # The energy is computed by simply taking the product of the coefficients 145 | # and the computed expectation values and summing them. Here we also 146 | # take just the real part as the coefficients can possibly be complex, 147 | # but the energy (eigenvalue) of a Hamiltonian is always real. 148 | energy = np.sum(coeffs*expvals).real 149 | return energy 150 | 151 | # Here is where we actually perform the computation. We begin by seeing what 152 | # optimization routine the user has requested, eg. SPSA verses SciPy ones, 153 | # and dispatch to the correct optimizer. The selected optimizer starts at 154 | # x0 and calls 'vqe_func' everytime the optimizer needs to evaluate the cost 155 | # function. The result is returned as a SciPy OptimizerResult object. 156 | # Additionally, after every iteration, we use the 'callback' function to 157 | # publish the interm results back to the user. This is important to do 158 | # so that if the Program terminates unexpectedly, the user can start where they 159 | # left off. 160 | 161 | # Since SPSA is not in SciPy need if statement 162 | if optimizer == 'SPSA': 163 | res = fmin_spsa(vqe_func, x0, args=(), **optimizer_config, callback=callback) 164 | # All other SciPy optimizers here 165 | else: 166 | res = opt.minimize(vqe_func, x0, method=optimizer, options=optimizer_config, callback=callback) 167 | # Return result. OptimizeResult is a subclass of dict. 168 | return res 169 | 170 | 171 | def opstr_to_meas_circ(op_str): 172 | """Takes a list of operator strings and makes circuit with the correct post-rotations for measurements. 173 | 174 | Parameters: 175 | op_str (list): List of strings representing the operators needed for measurements. 176 | 177 | Returns: 178 | list: List of circuits for measurement post-rotations 179 | """ 180 | num_qubits = len(op_str[0]) 181 | circs = [] 182 | for op in op_str: 183 | qc = QuantumCircuit(num_qubits) 184 | for idx, item in enumerate(op): 185 | if item == 'X': 186 | qc.h(num_qubits-idx-1) 187 | elif item == 'Y': 188 | qc.sdg(num_qubits-idx-1) 189 | qc.h(num_qubits-idx-1) 190 | circs.append(qc) 191 | return circs 192 | 193 | 194 | def fmin_spsa(func, x0, args=(), maxiter=100, 195 | a=1.0, alpha=0.602, c=1.0, gamma=0.101, 196 | callback=None): 197 | """ 198 | Minimization of scalar function of one or more variables using simultaneous 199 | perturbation stochastic approximation (SPSA). 200 | 201 | Parameters: 202 | func (callable): The objective function to be minimized. 203 | 204 | ``fun(x, *args) -> float`` 205 | 206 | where x is an 1-D array with shape (n,) and args is a 207 | tuple of the fixed parameters needed to completely 208 | specify the function. 209 | 210 | x0 (ndarray): Initial guess. Array of real elements of size (n,), 211 | where ‘n’ is the number of independent variables. 212 | 213 | maxiter (int): Maximum number of iterations. The number of function 214 | evaluations is twice as many. Optional. 215 | 216 | a (float): SPSA gradient scaling parameter. Optional. 217 | 218 | alpha (float): SPSA gradient scaling exponent. Optional. 219 | 220 | c (float): SPSA step size scaling parameter. Optional. 221 | 222 | gamma (float): SPSA step size scaling exponent. Optional. 223 | 224 | callback (callable): Function that accepts the current parameter vector 225 | as input. 226 | 227 | Returns: 228 | OptimizeResult: Solution in SciPy Optimization format. 229 | 230 | Notes: 231 | See the `SPSA homepage `_ for usage and 232 | additional extentions to the basic version implimented here. 233 | """ 234 | A = 0.01 * maxiter 235 | x0 = np.asarray(x0) 236 | x = x0 237 | 238 | for kk in range(maxiter): 239 | ak = a * (kk+1.0+A)**-alpha 240 | ck = c * (kk+1.0)**-gamma 241 | # Bernoulli distribution for randoms 242 | deltak = 2*np.random.randint(2, size=x.shape[0])-1 243 | grad = (func(x + ck*deltak, *args) - func(x - ck*deltak, *args))/(2*ck*deltak) 244 | x -= ak*grad 245 | 246 | if callback is not None: 247 | callback(x) 248 | 249 | return OptimizeResult(fun=func(x, *args), x=x, nit=maxiter, nfev=2*maxiter, 250 | message='Optimization terminated successfully.', 251 | success=True) 252 | --------------------------------------------------------------------------------