From 5acb568822d3e5fd0adc1afad4c42d1100d23a70 Mon Sep 17 00:00:00 2001 From: Hiroshi Horii Date: Mon, 20 Feb 2023 20:05:34 +0900 Subject: [PATCH 1/8] add black and clang-format --- .clang-format | 3 +++ .github/workflows/tests.yml | 7 +++++- .pylintrc | 45 ++++++++++++++++++------------------- CONTRIBUTING.md | 21 +++++++++++++++++ requirements-dev.txt | 3 ++- tools/clang-format.sh | 25 +++++++++++++++++++++ tox.ini | 26 ++++++++++++++++----- 7 files changed, 100 insertions(+), 30 deletions(-) create mode 100644 .clang-format create mode 100644 tools/clang-format.sh diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..cc3f2683f8 --- /dev/null +++ b/.clang-format @@ -0,0 +1,3 @@ +BasedOnStyle: LLVM +AlwaysBreakTemplateDeclarations: Yes +RemoveBracesLLVM: No diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d540b0978e..b7e2aeaf62 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -34,10 +34,15 @@ jobs: pip install -U pip wheel pip install -U -c constraints.txt -r requirements-dev.txt qiskit-terra numpy scipy shell: bash + - name: Run clang-format + run: | + set -e + sh tools/clang-format.sh --Werror -n + shell: bash - name: Run Lint run: | set -e - pycodestyle --ignore=E402,W503,W504 --max-line-length=100 qiskit_aer + black --check qiskit_aer test tools pylint -j 2 -rn qiskit_aer sdist: runs-on: ${{ matrix.platform.os }} diff --git a/.pylintrc b/.pylintrc index c8443f43e8..5ae93e220b 100644 --- a/.pylintrc +++ b/.pylintrc @@ -21,7 +21,7 @@ persistent=yes # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins=pylint.extensions.docparams, # enable checking of docstring args - pylint.extensions.docstyle # basic docstring stle checks + pylint.extensions.docstyle, # basic docstring style checks # Use multiple processes to speed up Pylint. jobs=1 @@ -33,8 +33,7 @@ unsafe-load-any-extension=no # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code -extension-pkg-whitelist= - +extension-pkg-allow-list= [MESSAGES CONTROL] @@ -43,10 +42,10 @@ extension-pkg-whitelist= confidence= # Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifiers separated by comma (,) or put this option +# either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). See also the "--disable" option for examples. -#enable= +enable=use-symbolic-message-instead # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this @@ -57,7 +56,8 @@ confidence= # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" -disable=no-self-use, # disabled as it is too verbose +disable=spelling, # way too noisy + no-self-use, # disabled as it is too verbose fixme, # disabled as TODOs would show up as warnings protected-access, # disabled as we don't follow the public vs private # convention strictly @@ -70,8 +70,13 @@ disable=no-self-use, # disabled as it is too verbose unnecessary-pass, # allow for methods with just "pass", for clarity no-else-return, # relax "elif" after a clause with a return docstring-first-line-empty, # relax docstring style - unsubscriptable-object, # pylint can't determine this for numpy types - bad-continuation, bad-whitespace # differences of opinion with black + import-outside-toplevel, + bad-continuation, bad-whitespace, # differences of opinion with black + import-error, # overzealous with our optionals/dynamic packages + consider-using-f-string, # pass re-lint old commits + broad-exception-raised, # pass re-lint old commits + unsubscriptable-object # pass re-lint old commits + @@ -83,12 +88,6 @@ disable=no-self-use, # disabled as it is too verbose # mypackage.mymodule.MyReporterClass. output-format=text -# Put messages in a separate file for each module / package specified on the -# command line instead of printing them on stdout. Reports (if any) will be -# written in a file name "pylint_global.[txt|html]". This option is deprecated -# and it will be removed in Pylint 2.0. -files-output=no - # Tells whether to display a full report or only the messages reports=yes @@ -117,8 +116,8 @@ evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / stateme # pi = the PI constant # op = operation iterator # b = basis iterator -good-names=i,j,k,n,m,ex,v,w,x,y,z,Run,_,logger,q,c,r,qr,cr,qc,nd,pi,op,b,ar,br,dt, - __unittest +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, + __unittest,iSwapGate,mu # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,toto,tutu,tata @@ -171,16 +170,16 @@ attr-rgx=[a-z_][a-z0-9_]{2,30}$ attr-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct argument names -argument-rgx=[a-z_][a-z0-9_]{2,30}$ +argument-rgx=[a-z_][a-z0-9_]{2,30}|ax|dt$ # Naming hint for argument names argument-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct variable names -variable-rgx=[a-z_][a-z0-9_]{2,30}$ +variable-rgx=[a-z_][a-z0-9_]{1,30}$ # Naming hint for variable names -variable-name-hint=[a-z_][a-z0-9_]{2,30}$ +variable-name-hint=[a-z_][a-z0-9_]{1,30}$ # Regular expression matching correct class attribute names class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ @@ -212,7 +211,7 @@ max-nested-blocks=5 [FORMAT] # Maximum number of characters on a single line. -max-line-length=100 +max-line-length=105 # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ @@ -279,7 +278,7 @@ spelling-dict= spelling-ignore-words= # A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= +spelling-private-dict-file=.local-spellings # Tells whether to store unknown words to indicated private dictionary in # --spelling-private-dict-file option instead of raising a message. @@ -296,7 +295,7 @@ ignore-mixin-members=yes # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis. It # supports qualified module names, as well as Unix pattern matching. -ignored-modules=matplotlib.cm,numpy.random,qiskit.providers +ignored-modules=numpy # List of class names for which member attributes should not be checked (useful # for classes with dynamically set attributes). This supports the use of @@ -333,7 +332,7 @@ callbacks=cb_,_cb # List of qualified module names which can have objects that can redefine # builtins. -redefining-builtins-modules=six.moves,future.builtins,tools.compiler +redefining-builtins-modules=six.moves,future.builtins [CLASSES] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 307136e3c5..90a7ad8b21 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,6 +18,11 @@ please ensure that: 1. The code follows the code style of the project and successfully passes the tests. For convenience, you can execute `tox` locally, which will run these checks and report any issues. + + If your code fails the local style checks, you can use `tox -eblack` + and `tox -eclang` to automatically fix update the code formatting + in python and C++ respectively. + 2. The documentation has been updated accordingly. In particular, if a function or class has been modified during the PR, please update the *docstring* accordingly. @@ -185,6 +190,22 @@ like for the current state of the repo, you can run: `tox -edocs` which will build all the documentation into `docs/_build/html` and the release notes in particular will be located at `docs/_build/html/release_notes.html` +## Style and lint + +Qiskit Aer uses 3 tools for verify code formatting and lint checking. The +first tool is [black](https://github.com/psf/black) which is a Python code formatting +tool that will automatically update the code formatting to a consistent style. +The second tool is [pylint](https://www.pylint.org/) which is a code linter +which does a deeper analysis of the Python code to find both style issues and +potential bugs and other common issues in Python. + +You can check that your local modifications conform to the style rules +by running `tox -elint` which will run `black`, `pylint` and `clang-format` +to check the local code formatting and lint. If black returns a code +formatting error you can run `tox -eblack` to automatically update the +code formatting to conform to the style. However, if `pylint` returns +any error you will have to fix these issues by manually updating your code. + ### Development Cycle The development cycle for qiskit-aer is all handled in the open using diff --git a/requirements-dev.txt b/requirements-dev.txt index 87dfcda37d..20e0860e91 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -5,7 +5,8 @@ scikit-build>=0.11.0 asv cvxpy>=1.0.0,<1.1.15;platform_system != 'Windows' and python_version < '3.11' pylint -pycodestyle +black[jupyter]~=22.0 +clang-format~=15.0.7 Sphinx>=1.8.3 jupyter-sphinx reno>=3.4.0 diff --git a/tools/clang-format.sh b/tools/clang-format.sh new file mode 100644 index 0000000000..1607e91d79 --- /dev/null +++ b/tools/clang-format.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +cd `dirname $0`/.. +IGNORE_FILES="src/misc/warnings.hpp" + +ERROR=0 +for FILE in `find src -iname "*.hpp" -or -iname "*.cpp"`; do + + IGNORE=false + for IGNORE_FILE in $IGNORE_FILES; do + if [ "$IGNORE_FILE" = "$FILE" ]; then + IGNORE=true + break + fi + done + + if $IGNORE; then continue; fi + + clang-format -style=file $* $FILE + if [ "$?" != "0" ]; then + ERROR=1 + fi +done + +exit $ERROR diff --git a/tox.ini b/tox.ini index 699976c607..d7f5bbcf0f 100644 --- a/tox.ini +++ b/tox.ini @@ -10,6 +10,7 @@ setenv = LANGUAGE=en_US LC_ALL=en_US.utf-8 SETUPTOOLS_ENABLE_FEATURES=legacy-editable +whitelist_externals = sh deps = -r requirements-dev.txt build @@ -22,20 +23,35 @@ commands = basepython = python3 setenv = {[testenv]setenv} - PYTHON=coverage3 run --source qiskit --parallel-mode + PYTHON=coverage3 run --source qiskit_aer --parallel-mode commands = stestr run {posargs} coverage3 combine coverage3 report [testenv:lint] -deps = - pycodestyle - pylint +envdir = .tox/lint +basepython = python3 commands = - pycodestyle --ignore=E402,W503,W504 --max-line-length=100 qiskit_aer + sh tools/clang-format.sh --Werror -n + black --line-length 100 --check {posargs} qiskit_aer test tools setup.py pylint -j 2 -rn qiskit_aer +[testenv:clang-format] +envdir = .tox/lint +commands = sh tools/clang-format.sh -i + +[testenv:black] +envdir = .tox/lint +commands = black qiskit_aer test tools setup.py + +[pycodestyle] +max-line-length = 105 +# default ignores + E741 because of opflow global variable I +# + E203 because of a difference of opinion with black +# codebase does currently comply with: E133, E242, E704, W505 +ignore = E121, E123, E126, E133, E226, E241, E242, E704, W503, W504, W505, E741, E203 + [testenv:docs] deps = -r requirements-dev.txt From 1dafc1bccd7367230b1f459bc8e0024bddf82945 Mon Sep 17 00:00:00 2001 From: Hiroshi Horii Date: Fri, 10 Mar 2023 12:04:40 +0900 Subject: [PATCH 2/8] apply black and clang-format --- qiskit_aer/__init__.py | 1 + qiskit_aer/aererror.py | 2 +- qiskit_aer/aerprovider.py | 34 +- qiskit_aer/backends/aer_compiler.py | 333 ++- qiskit_aer/backends/aer_simulator.py | 398 ++- qiskit_aer/backends/aerbackend.py | 212 +- qiskit_aer/backends/backend_utils.py | 470 +++- qiskit_aer/backends/compatibility.py | 34 +- qiskit_aer/backends/pulse_simulator.py | 169 +- qiskit_aer/backends/qasm_simulator.py | 590 ++-- qiskit_aer/backends/statevector_simulator.py | 218 +- qiskit_aer/backends/unitary_simulator.py | 215 +- qiskit_aer/jobs/aerjob.py | 40 +- qiskit_aer/jobs/aerjobset.py | 87 +- qiskit_aer/jobs/utils.py | 28 +- qiskit_aer/library/__init__.py | 42 +- qiskit_aer/library/default_qubits.py | 2 +- .../library/save_instructions/__init__.py | 48 +- .../save_instructions/save_amplitudes.py | 91 +- .../save_instructions/save_clifford.py | 3 +- .../library/save_instructions/save_data.py | 67 +- .../save_instructions/save_density_matrix.py | 53 +- .../save_expectation_value.py | 114 +- .../save_matrix_product_state.py | 31 +- .../save_instructions/save_probabilities.py | 110 +- .../save_instructions/save_stabilizer.py | 23 +- .../library/save_instructions/save_state.py | 21 +- .../save_instructions/save_statevector.py | 50 +- .../library/save_instructions/save_superop.py | 1 + .../library/save_instructions/save_unitary.py | 3 +- .../set_instructions/set_density_matrix.py | 7 +- .../set_matrix_product_state.py | 14 +- .../set_instructions/set_stabilizer.py | 5 +- .../set_instructions/set_statevector.py | 5 +- .../library/set_instructions/set_superop.py | 6 +- .../library/set_instructions/set_unitary.py | 6 +- qiskit_aer/noise/device/models.py | 86 +- qiskit_aer/noise/device/parameters.py | 52 +- qiskit_aer/noise/errors/quantum_error.py | 59 +- qiskit_aer/noise/errors/readout_error.py | 66 +- qiskit_aer/noise/errors/standard_errors.py | 103 +- qiskit_aer/noise/noise_model.py | 474 ++-- qiskit_aer/noise/noiseerror.py | 2 +- qiskit_aer/noise/passes/local_noise_pass.py | 28 +- .../noise/passes/relaxation_noise_pass.py | 34 +- qiskit_aer/primitives/estimator.py | 94 +- qiskit_aer/primitives/sampler.py | 12 +- .../pulse/controllers/digest_pulse_qobj.py | 321 ++- qiskit_aer/pulse/controllers/mc_controller.py | 78 +- .../pulse/controllers/pulse_controller.py | 209 +- .../pulse/controllers/pulse_de_solver.py | 2 +- .../pulse/controllers/pulse_sim_options.py | 96 +- .../pulse/controllers/unitary_controller.py | 43 +- qiskit_aer/pulse/de/DE_Methods.py | 123 +- qiskit_aer/pulse/de/DE_Options.py | 42 +- qiskit_aer/pulse/de/type_utils.py | 29 +- .../system_models/duffing_model_generators.py | 155 +- .../pulse/system_models/hamiltonian_model.py | 78 +- .../pulse/system_models/pulse_system_model.py | 66 +- .../apply_str_func_to_qobj.py | 8 +- .../string_model_parser/gen_operator.py | 6 +- .../operator_from_string.py | 21 +- .../operator_generators.py | 72 +- .../string_model_parser.py | 211 +- .../quantum_info/states/aer_densitymatrix.py | 66 +- qiskit_aer/quantum_info/states/aer_state.py | 79 +- .../quantum_info/states/aer_statevector.py | 135 +- qiskit_aer/utils/noise_model_inserter.py | 13 +- qiskit_aer/utils/noise_transformation.py | 84 +- qiskit_aer/version.py | 33 +- src/controllers/aer_controller.hpp | 724 ++--- src/controllers/controller_execute.hpp | 47 +- src/controllers/state_controller.hpp | 481 ++-- src/framework/avx2_detect.hpp | 38 +- src/framework/blas_protos.hpp | 46 +- src/framework/circuit.hpp | 368 +-- src/framework/config.hpp | 242 +- src/framework/creg.hpp | 146 +- src/framework/json.hpp | 64 +- src/framework/json_parser.hpp | 83 +- src/framework/linalg/almost_equal.hpp | 23 +- src/framework/linalg/eigensystem.hpp | 77 +- .../linalg/linops/linops_aer_vector.hpp | 32 +- src/framework/linalg/linops/linops_array.hpp | 28 +- .../linalg/linops/linops_generic.hpp | 28 +- src/framework/linalg/linops/linops_json.hpp | 28 +- src/framework/linalg/linops/linops_map.hpp | 56 +- src/framework/linalg/linops/linops_matrix.hpp | 28 +- .../linalg/linops/linops_unordered_map.hpp | 60 +- src/framework/linalg/linops/linops_vector.hpp | 28 +- src/framework/linalg/matrix_utils.hpp | 2 +- .../linalg/matrix_utils/matrix_defs.hpp | 72 +- .../linalg/matrix_utils/smatrix_defs.hpp | 62 +- .../linalg/matrix_utils/vmatrix_defs.hpp | 73 +- src/framework/linalg/square.hpp | 74 +- src/framework/linalg/vector.hpp | 64 +- src/framework/linalg/vector_json.hpp | 12 +- src/framework/matrix.hpp | 171 +- src/framework/noise_utils.hpp | 40 +- src/framework/operations.hpp | 689 +++-- src/framework/opset.hpp | 9 +- src/framework/pybind_basics.hpp | 80 +- src/framework/pybind_casts.hpp | 84 +- src/framework/pybind_json.hpp | 322 +-- src/framework/python_parser.hpp | 251 +- src/framework/qobj.hpp | 51 +- src/framework/results/data/data.hpp | 61 +- src/framework/results/data/metadata.hpp | 24 +- .../results/data/mixins/data_cdict.hpp | 21 +- .../results/data/mixins/data_cmatrix.hpp | 35 +- .../results/data/mixins/data_creg.hpp | 4 +- .../results/data/mixins/data_mps.hpp | 2 +- .../results/data/mixins/data_rdict.hpp | 37 +- .../results/data/mixins/data_rvalue.hpp | 15 +- .../results/data/mixins/data_rvector.hpp | 4 +- .../results/data/mixins/pybind_data_cdict.hpp | 27 +- .../data/mixins/pybind_data_cmatrix.hpp | 83 +- .../results/data/mixins/pybind_data_creg.hpp | 11 +- .../data/mixins/pybind_data_cvector.hpp | 43 +- .../results/data/mixins/pybind_data_json.hpp | 15 +- .../results/data/mixins/pybind_data_mps.hpp | 33 +- .../results/data/mixins/pybind_data_rdict.hpp | 35 +- .../data/mixins/pybind_data_rvalue.hpp | 21 +- .../data/mixins/pybind_data_rvector.hpp | 33 +- src/framework/results/data/pybind_data.hpp | 34 +- .../results/data/pybind_metadata.hpp | 18 +- .../results/data/subtypes/accum_data.hpp | 17 +- .../results/data/subtypes/average_data.hpp | 21 +- .../results/data/subtypes/data_map.hpp | 39 +- .../results/data/subtypes/list_data.hpp | 18 +- .../results/data/subtypes/pybind_data_map.hpp | 19 +- .../results/data/subtypes/pybind_subtypes.hpp | 5 +- .../results/data/subtypes/single_data.hpp | 16 +- src/framework/results/experiment_result.hpp | 238 +- src/framework/results/pybind_result.hpp | 55 +- src/framework/results/result.hpp | 43 +- src/framework/rng.hpp | 23 +- src/framework/stl_ostream.hpp | 83 +- src/framework/types.hpp | 44 +- src/framework/utils.hpp | 577 ++-- src/misc/clang_omp_symbols.hpp | 569 ++-- src/misc/common_macros.hpp | 4 +- src/misc/gcc_omp_symbols.hpp | 161 +- src/misc/hacks.hpp | 75 +- src/misc/wrap_thrust.hpp | 16 +- src/noise/noise_model.hpp | 641 +++-- src/noise/quantum_error.hpp | 146 +- src/noise/readout_error.hpp | 25 +- src/open_pulse/eval_hamiltonian.hpp | 147 +- src/open_pulse/iterators.hpp | 90 +- src/open_pulse/log.hpp | 124 +- src/open_pulse/numeric_integrator.cpp | 393 +-- src/open_pulse/numeric_integrator.hpp | 27 +- src/open_pulse/ordered_map.hpp | 40 +- src/open_pulse/pulse_utils.cpp | 265 +- src/open_pulse/pulse_utils.hpp | 20 +- src/open_pulse/pulse_utils_bindings.cpp | 57 +- src/open_pulse/python_to_cpp.hpp | 609 ++-- src/open_pulse/test_python_to_cpp.cpp | 113 +- src/open_pulse/test_python_to_cpp.hpp | 77 +- src/open_pulse/types.hpp | 4 +- src/open_pulse/zspmv.cpp | 258 +- src/open_pulse/zspmv.hpp | 54 +- .../density_matrix/densitymatrix.hpp | 209 +- .../density_matrix/densitymatrix_state.hpp | 1577 ++++++----- .../density_matrix/densitymatrix_thrust.hpp | 1043 +++---- .../extended_stabilizer/ch_runner.hpp | 675 ++--- .../chlib/chstabilizer.hpp | 1453 +++++----- .../extended_stabilizer/chlib/core.hpp | 479 ++-- .../extended_stabilizer_state.hpp | 995 +++---- src/simulators/extended_stabilizer/gates.hpp | 268 +- .../matrix_product_state.hpp | 779 +++-- .../matrix_product_state_internal.cpp | 1386 ++++----- .../matrix_product_state_internal.hpp | 356 +-- .../matrix_product_state_tensor.hpp | 509 ++-- src/simulators/matrix_product_state/svd.cpp | 837 +++--- src/simulators/matrix_product_state/svd.hpp | 18 +- src/simulators/stabilizer/binary_vector.hpp | 75 +- src/simulators/stabilizer/clifford.hpp | 524 ++-- src/simulators/stabilizer/pauli.hpp | 62 +- .../stabilizer/stabilizer_state.hpp | 470 ++-- src/simulators/state.hpp | 166 +- src/simulators/state_chunk.hpp | 1870 ++++++------ src/simulators/statevector/chunk/chunk.hpp | 478 ++-- .../statevector/chunk/chunk_container.hpp | 990 ++++--- .../statevector/chunk/chunk_manager.hpp | 307 +- .../chunk/cuStateVec_chunk_container.hpp | 727 ++--- .../statevector/chunk/cuda_kernels.hpp | 312 +- .../chunk/device_chunk_container.hpp | 1021 +++---- .../chunk/host_chunk_container.hpp | 270 +- .../statevector/chunk/thrust_kernels.hpp | 1862 +++++------- src/simulators/statevector/indexes.hpp | 291 +- src/simulators/statevector/qubitvector.hpp | 1771 ++++++------ .../statevector/qubitvector_thrust.hpp | 2504 ++++++++--------- src/simulators/statevector/qv_avx2.cpp | 763 +++-- src/simulators/statevector/qv_avx2.hpp | 19 +- .../statevector/statevector_state.hpp | 1727 ++++++------ src/simulators/statevector/transformer.hpp | 142 +- .../statevector/transformer_avx2.hpp | 23 +- .../superoperator/superoperator.hpp | 56 +- .../superoperator/superoperator_state.hpp | 445 +-- .../superoperator/superoperator_thrust.hpp | 56 +- src/simulators/tensor_network/tensor.hpp | 207 +- src/simulators/tensor_network/tensor_net.hpp | 1060 ++++--- .../tensor_network/tensor_net_contractor.hpp | 70 +- .../tensor_net_contractor_cuTensorNet.hpp | 989 ++++--- .../tensor_network/tensor_net_state.hpp | 831 +++--- src/simulators/unitary/unitary_state.hpp | 803 +++--- src/simulators/unitary/unitarymatrix.hpp | 167 +- .../unitary/unitarymatrix_thrust.hpp | 130 +- src/transpile/basic_opts.hpp | 13 +- src/transpile/cacheblocking.hpp | 717 +++-- src/transpile/circuitopt.hpp | 13 +- src/transpile/fusion.hpp | 515 ++-- test/__init__.py | 4 +- test/benchmark/__init__.py | 2 +- test/benchmark/basic.py | 52 +- test/benchmark/basic_05q.py | 182 +- test/benchmark/basic_15q.py | 182 +- test/benchmark/basic_25q.py | 184 +- test/benchmark/circuit_library_circuits.py | 52 +- test/benchmark/noise.py | 64 +- test/benchmark/noise_12q.py | 103 +- test/benchmark/noise_16q.py | 105 +- test/benchmark/noise_20q.py | 105 +- test/benchmark/output.py | 44 +- test/benchmark/output_05q.py | 98 +- test/benchmark/output_15q.py | 98 +- test/benchmark/output_25q.py | 98 +- test/benchmark/simulator_benchmark.py | 366 ++- test/benchmark/vqe_application.py | 77 +- test/terra/__init__.py | 13 +- test/terra/backends/__init__.py | 12 +- test/terra/backends/aer_simulator/__init__.py | 12 +- .../backends/aer_simulator/test_algorithms.py | 56 +- .../aer_simulator/test_auto_method.py | 119 +- .../backends/aer_simulator/test_chunk.py | 102 +- .../backends/aer_simulator/test_circuit.py | 106 +- .../backends/aer_simulator/test_cliffords.py | 120 +- .../aer_simulator/test_conditional.py | 148 +- .../aer_simulator/test_control_flow.py | 191 +- .../backends/aer_simulator/test_executors.py | 80 +- .../aer_simulator/test_from_backend.py | 19 +- .../backends/aer_simulator/test_fusion.py | 429 +-- .../backends/aer_simulator/test_initialize.py | 68 +- .../aer_simulator/test_job_splitting.py | 40 +- .../backends/aer_simulator/test_measure.py | 154 +- .../backends/aer_simulator/test_metadata.py | 67 +- .../aer_simulator/test_multiplexer.py | 34 +- .../backends/aer_simulator/test_noise.py | 120 +- .../aer_simulator/test_non_cliffords.py | 45 +- .../backends/aer_simulator/test_options.py | 173 +- .../backends/aer_simulator/test_pauli_gate.py | 38 +- .../backends/aer_simulator/test_reset.py | 22 +- .../aer_simulator/test_save_amplitudes.py | 72 +- .../aer_simulator/test_save_density_matrix.py | 94 +- .../aer_simulator/test_save_expval.py | 263 +- .../test_save_matrix_product_state.py | 22 +- .../aer_simulator/test_save_probabilities.py | 85 +- .../backends/aer_simulator/test_save_state.py | 82 +- .../aer_simulator/test_save_statevector.py | 101 +- .../test_save_statevector_dict.py | 59 +- .../aer_simulator/test_save_superop.py | 10 +- .../aer_simulator/test_save_unitary.py | 10 +- .../backends/aer_simulator/test_set_state.py | 93 +- .../aer_simulator/test_standard_gates.py | 159 +- .../aer_simulator/test_thread_management.py | 423 +-- .../backends/aer_simulator/test_truncate.py | 73 +- .../aer_simulator/test_unitary_gate.py | 33 +- .../test_wrapper_qasm_simulator.py | 4 +- .../test_wrapper_statevector_simulator.py | 55 +- .../test_wrapper_unitary_simulator.py | 15 +- test/terra/backends/pulse_sim_independent.py | 60 +- test/terra/backends/simulator_test_case.py | 61 +- test/terra/backends/test_compatibility.py | 8 +- .../backends/test_config_pulse_simulator.py | 146 +- .../terra/backends/test_parameterized_qobj.py | 253 +- test/terra/backends/test_pulse_simulator.py | 870 +++--- test/terra/common.py | 151 +- test/terra/decorators.py | 8 +- test/terra/extensions/__init__.py | 12 +- test/terra/extensions/test_save_amplitudes.py | 28 +- test/terra/extensions/test_save_expval.py | 116 +- test/terra/extensions/test_wrappers.py | 12 +- test/terra/noise/__init__.py | 12 +- test/terra/noise/passes/__init__.py | 12 +- .../passes/test_relaxation_noise_pass.py | 19 +- test/terra/noise/test_device_models.py | 8 +- test/terra/noise/test_noise_inserter.py | 48 +- test/terra/noise/test_noise_model.py | 142 +- test/terra/noise/test_noise_transformation.py | 181 +- test/terra/noise/test_quantum_error.py | 125 +- test/terra/noise/test_readout_error.py | 47 +- test/terra/noise/test_standard_errors.py | 227 +- test/terra/primitives/__init__.py | 12 +- test/terra/primitives/test_estimator.py | 26 +- test/terra/primitives/test_sampler.py | 20 +- test/terra/pulse/__init__.py | 12 +- test/terra/pulse/controllers/__init__.py | 12 +- .../controllers/test_pulse_controller.py | 45 +- test/terra/pulse/de/__init__.py | 12 +- test/terra/pulse/de/test_de_methods.py | 70 +- test/terra/pulse/de/test_type_utils.py | 64 +- .../pulse/test_duffing_model_generators.py | 770 +++-- test/terra/pulse/test_system_models.py | 230 +- test/terra/reference/ref_1q_clifford.py | 160 +- test/terra/reference/ref_2q_clifford.py | 274 +- test/terra/reference/ref_algorithms.py | 29 +- test/terra/reference/ref_conditionals.py | 148 +- test/terra/reference/ref_diagonal_gate.py | 78 +- test/terra/reference/ref_initialize.py | 465 ++- test/terra/reference/ref_kraus_noise.py | 10 +- test/terra/reference/ref_measure.py | 97 +- test/terra/reference/ref_multiplexer.py | 67 +- test/terra/reference/ref_non_clifford.py | 910 +++--- test/terra/reference/ref_pauli_noise.py | 56 +- test/terra/reference/ref_readout_noise.py | 46 +- test/terra/reference/ref_reset.py | 72 +- test/terra/reference/ref_reset_noise.py | 33 +- test/terra/reference/ref_save_expval.py | 130 +- test/terra/reference/ref_unitary_gate.py | 83 +- test/terra/states/test_aer_densitymatrix.py | 100 +- test/terra/states/test_aer_state.py | 189 +- test/terra/states/test_aer_statevector.py | 102 +- test/terra/test_python_to_cpp.py | 43 +- test/terra/utils/multiplexer.py | 22 +- test/terra/utils/utils.py | 2 +- tools/generate_qobj.py | 13 +- tools/verify_standalone_results.py | 47 +- tools/verify_wheels.py | 173 +- 330 files changed, 33135 insertions(+), 29565 deletions(-) mode change 100755 => 100644 src/controllers/controller_execute.hpp mode change 100755 => 100644 src/framework/blas_protos.hpp mode change 100755 => 100644 src/framework/circuit.hpp mode change 100755 => 100644 src/framework/creg.hpp mode change 100755 => 100644 src/framework/json.hpp mode change 100755 => 100644 src/framework/linalg/almost_equal.hpp mode change 100755 => 100644 src/framework/linalg/linops/linops_aer_vector.hpp mode change 100755 => 100644 src/framework/linalg/linops/linops_array.hpp mode change 100755 => 100644 src/framework/linalg/linops/linops_generic.hpp mode change 100755 => 100644 src/framework/linalg/linops/linops_json.hpp mode change 100755 => 100644 src/framework/linalg/linops/linops_map.hpp mode change 100755 => 100644 src/framework/linalg/linops/linops_matrix.hpp mode change 100755 => 100644 src/framework/linalg/linops/linops_unordered_map.hpp mode change 100755 => 100644 src/framework/linalg/linops/linops_vector.hpp mode change 100755 => 100644 src/framework/linalg/matrix_utils.hpp mode change 100755 => 100644 src/framework/linalg/matrix_utils/matrix_defs.hpp mode change 100755 => 100644 src/framework/linalg/matrix_utils/smatrix_defs.hpp mode change 100755 => 100644 src/framework/linalg/matrix_utils/vmatrix_defs.hpp mode change 100755 => 100644 src/framework/linalg/square.hpp mode change 100755 => 100644 src/framework/linalg/vector.hpp mode change 100755 => 100644 src/framework/linalg/vector_json.hpp mode change 100755 => 100644 src/framework/matrix.hpp mode change 100755 => 100644 src/framework/operations.hpp mode change 100755 => 100644 src/framework/opset.hpp mode change 100755 => 100644 src/framework/pybind_basics.hpp mode change 100755 => 100644 src/framework/pybind_json.hpp mode change 100755 => 100644 src/framework/qobj.hpp mode change 100755 => 100644 src/framework/results/data/mixins/pybind_data_cdict.hpp mode change 100755 => 100644 src/framework/results/data/mixins/pybind_data_cmatrix.hpp mode change 100755 => 100644 src/framework/results/data/mixins/pybind_data_creg.hpp mode change 100755 => 100644 src/framework/results/data/mixins/pybind_data_cvector.hpp mode change 100755 => 100644 src/framework/results/data/mixins/pybind_data_json.hpp mode change 100755 => 100644 src/framework/results/data/mixins/pybind_data_mps.hpp mode change 100755 => 100644 src/framework/results/data/mixins/pybind_data_rdict.hpp mode change 100755 => 100644 src/framework/results/data/mixins/pybind_data_rvalue.hpp mode change 100755 => 100644 src/framework/results/data/mixins/pybind_data_rvector.hpp mode change 100755 => 100644 src/framework/results/data/pybind_data.hpp mode change 100755 => 100644 src/framework/results/data/pybind_metadata.hpp mode change 100755 => 100644 src/framework/results/data/subtypes/accum_data.hpp mode change 100755 => 100644 src/framework/results/data/subtypes/average_data.hpp mode change 100755 => 100644 src/framework/results/data/subtypes/data_map.hpp mode change 100755 => 100644 src/framework/results/data/subtypes/list_data.hpp mode change 100755 => 100644 src/framework/results/data/subtypes/pybind_data_map.hpp mode change 100755 => 100644 src/framework/results/data/subtypes/pybind_subtypes.hpp mode change 100755 => 100644 src/framework/results/data/subtypes/single_data.hpp mode change 100755 => 100644 src/framework/results/pybind_result.hpp mode change 100755 => 100644 src/framework/results/result.hpp mode change 100755 => 100644 src/framework/rng.hpp mode change 100755 => 100644 src/framework/stl_ostream.hpp mode change 100755 => 100644 src/framework/types.hpp mode change 100755 => 100644 src/framework/utils.hpp mode change 100755 => 100644 src/simulators/density_matrix/densitymatrix.hpp mode change 100755 => 100644 src/simulators/density_matrix/densitymatrix_thrust.hpp mode change 100755 => 100644 src/simulators/statevector/qubitvector.hpp mode change 100755 => 100644 src/simulators/statevector/statevector_state.hpp mode change 100755 => 100644 src/simulators/statevector/transformer.hpp mode change 100755 => 100644 src/simulators/statevector/transformer_avx2.hpp mode change 100755 => 100644 src/simulators/superoperator/superoperator.hpp mode change 100755 => 100644 src/simulators/superoperator/superoperator_state.hpp mode change 100755 => 100644 src/simulators/superoperator/superoperator_thrust.hpp mode change 100755 => 100644 src/simulators/unitary/unitary_state.hpp mode change 100755 => 100644 src/simulators/unitary/unitarymatrix.hpp mode change 100755 => 100644 src/simulators/unitary/unitarymatrix_thrust.hpp diff --git a/qiskit_aer/__init__.py b/qiskit_aer/__init__.py index 730eed4e52..8a76e0305f 100644 --- a/qiskit_aer/__init__.py +++ b/qiskit_aer/__init__.py @@ -62,6 +62,7 @@ # before loading our simulators, so we force it using this ugly trick if platform.system() == "Darwin": import numpy as np + np.dot(np.zeros(100), np.zeros(100)) # ... ¯\_(ツ)_/¯ diff --git a/qiskit_aer/aererror.py b/qiskit_aer/aererror.py index 4e3311c0ff..d1ffa74eab 100644 --- a/qiskit_aer/aererror.py +++ b/qiskit_aer/aererror.py @@ -23,7 +23,7 @@ class AerError(QiskitError): def __init__(self, *message): """Set the error message.""" super().__init__(*message) - self.message = ' '.join(message) + self.message = " ".join(message) def __str__(self): """Return the message.""" diff --git a/qiskit_aer/aerprovider.py b/qiskit_aer/aerprovider.py index 82bf38ca62..4a7b50c27c 100644 --- a/qiskit_aer/aerprovider.py +++ b/qiskit_aer/aerprovider.py @@ -37,26 +37,28 @@ def __init__(self): devices = AerSimulator().available_devices() backends = [] for method in methods: - name = 'aer_simulator' - if method not in [None, 'automatic']: - name += f'_{method}' - device_name = 'CPU' + name = "aer_simulator" + if method not in [None, "automatic"]: + name += f"_{method}" + device_name = "CPU" backends.append((name, AerSimulator, method, device_name)) # Add GPU device backends - if method in ['statevector', 'density_matrix', 'unitary']: + if method in ["statevector", "density_matrix", "unitary"]: for device in devices: - if device != 'CPU': - new_name = f'{name}_{device}'.lower() + if device != "CPU": + new_name = f"{name}_{device}".lower() device_name = device - backends.append((new_name, AerSimulator, method, device_name)) + backends.append( + (new_name, AerSimulator, method, device_name) + ) # Add legacy backend names backends += [ - ('qasm_simulator', QasmSimulator, None, None), - ('statevector_simulator', StatevectorSimulator, None, None), - ('unitary_simulator', UnitarySimulator, None, None), - ('pulse_simulator', PulseSimulator, None, None) + ("qasm_simulator", QasmSimulator, None, None), + ("statevector_simulator", StatevectorSimulator, None, None), + ("unitary_simulator", UnitarySimulator, None, None), + ("pulse_simulator", PulseSimulator, None, None), ] AerProvider._BACKENDS = backends @@ -77,14 +79,14 @@ def backends(self, name=None, filters=None, **kwargs): # are set they will only last as long as that backend object exists backends = [] for backend_name, backend_cls, method, device in self._BACKENDS: - opts = {'provider': self} + opts = {"provider": self} if method is not None: - opts['method'] = method + opts["method"] = method if device is not None: - opts['device'] = device + opts["device"] = device if name is None or backend_name == name: backends.append(backend_cls(**opts)) return filter_backends(backends, filters=filters) def __str__(self): - return 'AerProvider' + return "AerProvider" diff --git a/qiskit_aer/backends/aer_compiler.py b/qiskit_aer/backends/aer_compiler.py index 9f5e714b16..88d468e767 100644 --- a/qiskit_aer/backends/aer_compiler.py +++ b/qiskit_aer/backends/aer_compiler.py @@ -26,10 +26,12 @@ ForLoopOp, IfElseOp, BreakLoopOp, - ContinueLoopOp) + ContinueLoopOp, +) from qiskit.compiler import transpile from qiskit.qobj import QobjExperimentHeader from qiskit_aer.aererror import AerError + # pylint: disable=import-error, no-name-in-module from qiskit_aer.backends.controller_wrappers import AerCircuit, AerConfig from .backend_utils import circuit_optypes @@ -37,7 +39,7 @@ class AerCompiler: - """ Aer Compiler to convert instructions of control-flow to mark and jump instructions""" + """Aer Compiler to convert instructions of control-flow to mark and jump instructions""" def __init__(self): self._last_flow_id = -1 @@ -67,7 +69,7 @@ def compile(self, circuits, basis_gates=None, optypes=None): # Make a shallow copy incase we modify it compiled_optypes = list(optypes) if isinstance(circuits, list): - basis_gates = basis_gates + ['mark', 'jump'] + basis_gates = basis_gates + ["mark", "jump"] compiled_circuits = [] for idx, circuit in enumerate(circuits): # Resolve initialize @@ -75,7 +77,7 @@ def compile(self, circuits, basis_gates=None, optypes=None): if self._is_dynamic(circuit, compiled_optypes[idx]): compiled_circ = transpile( self._inline_circuit(circuit, None, None), - basis_gates=basis_gates + basis_gates=basis_gates, ) compiled_circuits.append(compiled_circ) # Recompute optype for compiled circuit @@ -106,7 +108,9 @@ def _inline_initialize(self, circ, optype): for inst, qargs, cargs in circ.data: if isinstance(inst, Initialize) and not isinstance(inst.params[0], complex): # Assume that the decomposed circuit of inst.definition consists of basis gates - new_circ.compose(inst.definition.decompose(), qargs, cargs, inplace=True) + new_circ.compose( + inst.definition.decompose(), qargs, cargs, inplace=True + ) else: new_circ._append(inst, qargs, cargs) @@ -119,7 +123,11 @@ def _is_dynamic(circuit, optype=None): return False controlflow_types = ( - WhileLoopOp, ForLoopOp, IfElseOp, BreakLoopOp, ContinueLoopOp + WhileLoopOp, + ForLoopOp, + IfElseOp, + BreakLoopOp, + ContinueLoopOp, ) # Check via optypes @@ -163,15 +171,21 @@ def _inline_circuit(self, circ, continue_label, break_label, bit_map=None): ret.barrier() elif isinstance(instruction.operation, IfElseOp): ret.barrier() - self._inline_if_else_op(instruction, continue_label, break_label, ret, bit_map) + self._inline_if_else_op( + instruction, continue_label, break_label, ret, bit_map + ) ret.barrier() elif isinstance(instruction.operation, BreakLoopOp): ret._append( - AerJump(break_label, ret.num_qubits, ret.num_clbits), ret.qubits, ret.clbits + AerJump(break_label, ret.num_qubits, ret.num_clbits), + ret.qubits, + ret.clbits, ) elif isinstance(instruction.operation, ContinueLoopOp): ret._append( - AerJump(continue_label, ret.num_qubits, ret.num_clbits), ret.qubits, ret.clbits + AerJump(continue_label, ret.num_qubits, ret.num_clbits), + ret.qubits, + ret.clbits, ) else: ret._append(instruction) @@ -200,13 +214,15 @@ def _inline_for_loop_op(self, instruction, parent, bit_map): self._last_flow_id += 1 loop_id = self._last_flow_id - loop_name = f'loop_{loop_id}' + loop_name = f"loop_{loop_id}" inlined_body = None - break_label = f'{loop_name}_end' + break_label = f"{loop_name}_end" for index in indexset: - continue_label = f'{loop_name}_{index}' - inlined_body = self._inline_circuit(body, continue_label, break_label, inner_bit_map) + continue_label = f"{loop_name}_{index}" + inlined_body = self._inline_circuit( + body, continue_label, break_label, inner_bit_map + ) if loop_parameter is not None: inlined_body = inlined_body.bind_parameters({loop_parameter: index}) parent.append(inlined_body, qargs, cargs) @@ -217,16 +233,18 @@ def _inline_for_loop_op(self, instruction, parent, bit_map): def _inline_while_loop_op(self, instruction, parent, bit_map): """inline while_loop body with jump and mark instructions""" - condition_tuple = self._convert_c_if_args(instruction.operation.condition, bit_map) - body, = instruction.operation.params + condition_tuple = self._convert_c_if_args( + instruction.operation.condition, bit_map + ) + (body,) = instruction.operation.params self._last_flow_id += 1 loop_id = self._last_flow_id - loop_name = f'while_{loop_id}' + loop_name = f"while_{loop_id}" - continue_label = f'{loop_name}_continue' - loop_start_label = f'{loop_name}_start' - break_label = f'{loop_name}_end' + continue_label = f"{loop_name}_continue" + loop_start_label = f"{loop_name}_start" + break_label = f"{loop_name}_end" inlined_body = self._inline_circuit( body, continue_label, @@ -243,37 +261,55 @@ def _inline_while_loop_op(self, instruction, parent, bit_map): cargs = [bit_map[c] for c in instruction.clbits] mark_cargs = cargs.copy() mark_cargs.extend( - bit_map[c] for c in ( + bit_map[c] + for c in ( ( - {condition_tuple[0]} if isinstance(condition_tuple[0], Clbit) + {condition_tuple[0]} + if isinstance(condition_tuple[0], Clbit) else set(condition_tuple[0]) - ) - set(instruction.clbits) + ) + - set(instruction.clbits) ) ) c_if_args = self._convert_c_if_args(condition_tuple, bit_map) - parent.append(AerMark(continue_label, len(qargs), len(mark_cargs)), qargs, mark_cargs) - parent.append(AerJump(loop_start_label, len(qargs), len(mark_cargs)).c_if(*c_if_args), - qargs, mark_cargs) - parent.append(AerJump(break_label, len(qargs), len(mark_cargs)), qargs, mark_cargs) - parent.append(AerMark(loop_start_label, len(qargs), len(mark_cargs)), qargs, mark_cargs) + parent.append( + AerMark(continue_label, len(qargs), len(mark_cargs)), qargs, mark_cargs + ) + parent.append( + AerJump(loop_start_label, len(qargs), len(mark_cargs)).c_if(*c_if_args), + qargs, + mark_cargs, + ) + parent.append( + AerJump(break_label, len(qargs), len(mark_cargs)), qargs, mark_cargs + ) + parent.append( + AerMark(loop_start_label, len(qargs), len(mark_cargs)), qargs, mark_cargs + ) parent.append(inlined_body, qargs, cargs) - parent.append(AerJump(continue_label, len(qargs), len(mark_cargs)), qargs, mark_cargs) - parent.append(AerMark(break_label, len(qargs), len(mark_cargs)), qargs, mark_cargs) + parent.append( + AerJump(continue_label, len(qargs), len(mark_cargs)), qargs, mark_cargs + ) + parent.append( + AerMark(break_label, len(qargs), len(mark_cargs)), qargs, mark_cargs + ) - def _inline_if_else_op(self, instruction, continue_label, break_label, parent, bit_map): + def _inline_if_else_op( + self, instruction, continue_label, break_label, parent, bit_map + ): """inline true and false bodies of if_else with jump and mark instructions""" condition_tuple = instruction.operation.condition true_body, false_body = instruction.operation.params self._last_flow_id += 1 if_id = self._last_flow_id - if_name = f'if_{if_id}' + if_name = f"if_{if_id}" - if_true_label = f'{if_name}_true' - if_end_label = f'{if_name}_end' + if_true_label = f"{if_name}_true" + if_end_label = f"{if_name}_end" if false_body: - if_else_label = f'{if_name}_else' + if_else_label = f"{if_name}_else" else: if_else_label = if_end_label @@ -283,11 +319,14 @@ def _inline_if_else_op(self, instruction, continue_label, break_label, parent, b cargs = [bit_map[c] for c in instruction.clbits] mark_cargs = cargs.copy() mark_cargs.extend( - bit_map[c] for c in ( + bit_map[c] + for c in ( ( - {condition_tuple[0]} if isinstance(condition_tuple[0], Clbit) + {condition_tuple[0]} + if isinstance(condition_tuple[0], Clbit) else set(condition_tuple[0]) - ) - set(instruction.clbits) + ) + - set(instruction.clbits) ) ) @@ -300,12 +339,20 @@ def _inline_if_else_op(self, instruction, continue_label, break_label, parent, b } parent.append( - AerJump(if_true_label, len(qargs), len(mark_cargs)).c_if(*c_if_args), qargs, mark_cargs + AerJump(if_true_label, len(qargs), len(mark_cargs)).c_if(*c_if_args), + qargs, + mark_cargs, + ) + parent.append( + AerJump(if_else_label, len(qargs), len(mark_cargs)), qargs, mark_cargs + ) + parent.append( + AerMark(if_true_label, len(qargs), len(mark_cargs)), qargs, mark_cargs ) - parent.append(AerJump(if_else_label, len(qargs), len(mark_cargs)), qargs, mark_cargs) - parent.append(AerMark(if_true_label, len(qargs), len(mark_cargs)), qargs, mark_cargs) parent.append( - self._inline_circuit(true_body, continue_label, break_label, true_bit_map), qargs, cargs + self._inline_circuit(true_body, continue_label, break_label, true_bit_map), + qargs, + cargs, ) if false_body: @@ -316,15 +363,23 @@ def _inline_if_else_op(self, instruction, continue_label, break_label, parent, b zip(false_body.clbits, instruction.clbits), ) } - parent.append(AerJump(if_end_label, len(qargs), len(mark_cargs)), qargs, mark_cargs) - parent.append(AerMark(if_else_label, len(qargs), len(mark_cargs)), qargs, mark_cargs) parent.append( - self._inline_circuit(false_body, continue_label, break_label, false_bit_map), + AerJump(if_end_label, len(qargs), len(mark_cargs)), qargs, mark_cargs + ) + parent.append( + AerMark(if_else_label, len(qargs), len(mark_cargs)), qargs, mark_cargs + ) + parent.append( + self._inline_circuit( + false_body, continue_label, break_label, false_bit_map + ), qargs, cargs, ) - parent.append(AerMark(if_end_label, len(qargs), len(mark_cargs)), qargs, mark_cargs) + parent.append( + AerMark(if_end_label, len(qargs), len(mark_cargs)), qargs, mark_cargs + ) def compile_circuit(circuits, basis_gates=None, optypes=None): @@ -335,9 +390,7 @@ def compile_circuit(circuits, basis_gates=None, optypes=None): def generate_aer_config( - circuits: List[QuantumCircuit], - backend_options: Options, - **run_options + circuits: List[QuantumCircuit], backend_options: Options, **run_options ) -> AerConfig: """generates a configuration to run simulation. @@ -426,13 +479,21 @@ def assemble_circuit(circuit: QuantumCircuit): aer_circ.bfunc(f"0x{mask:X}", f"0x{val:X}", "==", conditional_reg) max_conditional_idx += 1 - _assemble_op(aer_circ, inst, qubit_indices, clbit_indices, - is_conditional, conditional_reg) + _assemble_op( + aer_circ, + inst, + qubit_indices, + clbit_indices, + is_conditional, + conditional_reg, + ) return aer_circ -def _assemble_op(aer_circ, inst, qubit_indices, clbit_indices, is_conditional, conditional_reg): +def _assemble_op( + aer_circ, inst, qubit_indices, clbit_indices, is_conditional, conditional_reg +): operation = inst.operation qubits = [qubit_indices[qubit] for qubit in inst.qubits] clbits = [clbit_indices[clbit] for clbit in inst.clbits] @@ -442,49 +503,116 @@ def _assemble_op(aer_circ, inst, qubit_indices, clbit_indices, is_conditional, c copied = False for i, param in enumerate(params): - if (isinstance(param, ParameterExpression) and len(param.parameters) > 0): + if isinstance(param, ParameterExpression) and len(param.parameters) > 0: if not copied: params = copy(params) copied = True params[i] = 0.0 - if name in {'ccx', 'ccz', 'cp', 'cswap', 'csx', 'cx', 'cy', 'cz', 'delay', 'ecr', - 'h', 'id', 'mcp', 'mcphase', 'mcr', 'mcrx', 'mcry', 'mcrz', 'mcswap', - 'mcsx', 'mcu', 'mcu1', 'mcu2', 'mcu3', 'mcx', 'mcx_gray', 'mcy', 'mcz', - 'p', 'r', 'rx', 'rxx', 'ry', 'ryy', 'rz', 'rzx', 'rzz', 's', 'sdg', 'swap', - 'sx', 'sxdg', 't', 'tdg', 'u', 'x', 'y', 'z', 'u1', 'u2', 'u3', - 'cu', 'cu1', 'cu2', 'cu3'}: - aer_circ.gate(name, qubits, params, [], conditional_reg, label if label else name) - elif name == 'measure': + if name in { + "ccx", + "ccz", + "cp", + "cswap", + "csx", + "cx", + "cy", + "cz", + "delay", + "ecr", + "h", + "id", + "mcp", + "mcphase", + "mcr", + "mcrx", + "mcry", + "mcrz", + "mcswap", + "mcsx", + "mcu", + "mcu1", + "mcu2", + "mcu3", + "mcx", + "mcx_gray", + "mcy", + "mcz", + "p", + "r", + "rx", + "rxx", + "ry", + "ryy", + "rz", + "rzx", + "rzz", + "s", + "sdg", + "swap", + "sx", + "sxdg", + "t", + "tdg", + "u", + "x", + "y", + "z", + "u1", + "u2", + "u3", + "cu", + "cu1", + "cu2", + "cu3", + }: + aer_circ.gate( + name, qubits, params, [], conditional_reg, label if label else name + ) + elif name == "measure": if is_conditional: aer_circ.measure(qubits, clbits, clbits) else: aer_circ.measure(qubits, clbits, []) - elif name == 'reset': + elif name == "reset": aer_circ.reset(qubits) - elif name == 'diagonal': - aer_circ.diagonal(qubits, params, label if label else 'diagonal') - elif name == 'unitary': - aer_circ.unitary(qubits, params[0], conditional_reg, label if label else 'unitary') - elif name == 'pauli': - aer_circ.gate(name, qubits, [], params, conditional_reg, label if label else name) - elif name == 'initialize': + elif name == "diagonal": + aer_circ.diagonal(qubits, params, label if label else "diagonal") + elif name == "unitary": + aer_circ.unitary( + qubits, params[0], conditional_reg, label if label else "unitary" + ) + elif name == "pauli": + aer_circ.gate( + name, qubits, [], params, conditional_reg, label if label else name + ) + elif name == "initialize": aer_circ.initialize(qubits, params) - elif name == 'roerror': + elif name == "roerror": aer_circ.roerror(qubits, params) - elif name == 'multiplexer': + elif name == "multiplexer": aer_circ.multiplexer(qubits, params, conditional_reg, label if label else name) - elif name == 'kraus': + elif name == "kraus": aer_circ.kraus(qubits, params, conditional_reg) - elif name in {'save_statevector', 'save_statevector_dict', 'save_clifford', - 'save_probabilities', 'save_probabilities_dict', 'save_matrix_product_state', - 'save_unitary', 'save_superop', 'save_density_matrix', 'save_state', - 'save_stabilizer'}: + elif name in { + "save_statevector", + "save_statevector_dict", + "save_clifford", + "save_probabilities", + "save_probabilities_dict", + "save_matrix_product_state", + "save_unitary", + "save_superop", + "save_density_matrix", + "save_state", + "save_stabilizer", + }: aer_circ.save_state(qubits, name, operation._subtype, label if label else name) - elif name in {'save_amplitudes', 'save_amplitudes_sq'}: - aer_circ.save_amplitudes(qubits, name, params, operation._subtype, - label if label else name) - elif name in ('save_expval', 'save_expval_var'): + elif name in {"save_amplitudes", "save_amplitudes_sq"}: + aer_circ.save_amplitudes( + qubits, name, params, operation._subtype, label if label else name + ) + elif name in ("save_expval", "save_expval_var"): paulis = [] coeff_reals = [] coeff_imags = [] @@ -492,41 +620,48 @@ def _assemble_op(aer_circ, inst, qubit_indices, clbit_indices, is_conditional, c paulis.append(pauli) coeff_reals.append(coeff[0]) coeff_imags.append(coeff[1]) - aer_circ.save_expval(qubits, name, paulis, coeff_reals, coeff_imags, operation._subtype, - label if label else name) - elif name == 'set_statevector': + aer_circ.save_expval( + qubits, + name, + paulis, + coeff_reals, + coeff_imags, + operation._subtype, + label if label else name, + ) + elif name == "set_statevector": aer_circ.set_statevector(qubits, params) - elif name == 'set_unitary': + elif name == "set_unitary": aer_circ.set_unitary(qubits, params) - elif name == 'set_density_matrix': + elif name == "set_density_matrix": aer_circ.set_density_matrix(qubits, params) - elif name == 'set_stabilizer': + elif name == "set_stabilizer": aer_circ.set_clifford(qubits, params) - elif name == 'set_superop': + elif name == "set_superop": aer_circ.set_superop(qubits, params) - elif name == 'set_matrix_product_state': + elif name == "set_matrix_product_state": aer_circ.set_matrix_product_state(qubits, params) - elif name == 'superop': + elif name == "superop": aer_circ.superop(qubits, params[0], conditional_reg) - elif name == 'barrier': + elif name == "barrier": pass - elif name == 'jump': + elif name == "jump": aer_circ.jump(qubits, params, conditional_reg) - elif name == 'mark': + elif name == "mark": aer_circ.mark(qubits, params) - elif name == 'qerror_loc': + elif name == "qerror_loc": aer_circ.set_qerror_loc(qubits, label if label else name, conditional_reg) - elif name in ('for_loop', 'while_loop', 'if_else'): - raise AerError('control-flow instructions must be converted ' - f'to jump and mark instructions: {name}') + elif name in ("for_loop", "while_loop", "if_else"): + raise AerError( + "control-flow instructions must be converted " + f"to jump and mark instructions: {name}" + ) else: - raise AerError(f'unknown instruction: {name}') + raise AerError(f"unknown instruction: {name}") -def assemble_circuits( - circuits: List[QuantumCircuit] -) -> List[AerCircuit]: +def assemble_circuits(circuits: List[QuantumCircuit]) -> List[AerCircuit]: """converts a list of Qiskit circuits into circuits mapped AER::Circuit Args: diff --git a/qiskit_aer/backends/aer_simulator.py b/qiskit_aer/backends/aer_simulator.py index 6a4911dbd7..6971fb401a 100644 --- a/qiskit_aer/backends/aer_simulator.py +++ b/qiskit_aer/backends/aer_simulator.py @@ -22,10 +22,15 @@ from ..version import __version__ from .aerbackend import AerBackend, AerError -from .backend_utils import (cpp_execute_circuits, cpp_execute_qobj, - available_methods, available_devices, - MAX_QUBITS_STATEVECTOR, - BASIS_GATES) +from .backend_utils import ( + cpp_execute_circuits, + cpp_execute_qobj, + available_methods, + available_devices, + MAX_QUBITS_STATEVECTOR, + BASIS_GATES, +) + # pylint: disable=import-error, no-name-in-module from .controller_wrappers import aer_controller_execute @@ -448,137 +453,236 @@ class AerSimulator(AerBackend): _BASIS_GATES = BASIS_GATES _CUSTOM_INSTR = { - 'statevector': sorted([ - 'quantum_channel', 'qerror_loc', 'roerror', 'kraus', - 'save_expval', 'save_expval_var', - 'save_probabilities', 'save_probabilities_dict', - 'save_amplitudes', 'save_amplitudes_sq', - 'save_density_matrix', 'save_state', 'save_statevector', - 'save_statevector_dict', 'set_statevector', - 'if_else', 'for_loop', 'while_loop', 'break_loop', 'continue_loop', - ]), - 'density_matrix': sorted([ - 'quantum_channel', 'qerror_loc', 'roerror', 'kraus', 'superop', - 'save_state', 'save_expval', 'save_expval_var', - 'save_probabilities', 'save_probabilities_dict', - 'save_density_matrix', 'save_amplitudes_sq', 'set_density_matrix', - 'if_else', 'for_loop', 'while_loop', 'break_loop', 'continue_loop', - ]), - 'matrix_product_state': sorted([ - 'quantum_channel', 'qerror_loc', 'roerror', 'kraus', - 'save_expval', 'save_expval_var', - 'save_probabilities', 'save_probabilities_dict', - 'save_state', 'save_matrix_product_state', 'save_statevector', - 'save_density_matrix', 'save_amplitudes', 'save_amplitudes_sq', - 'set_matrix_product_state', - 'if_else', 'for_loop', 'while_loop', 'break_loop', 'continue_loop', - ]), - 'stabilizer': sorted([ - 'quantum_channel', 'qerror_loc', 'roerror', - 'save_expval', 'save_expval_var', - 'save_probabilities', 'save_probabilities_dict', - 'save_amplitudes_sq', 'save_state', 'save_clifford', - 'save_stabilizer', 'set_stabilizer', - 'if_else', 'for_loop', 'while_loop', 'break_loop', 'continue_loop', - ]), - 'extended_stabilizer': sorted([ - 'quantum_channel', 'qerror_loc', 'roerror', 'save_statevector', - ]), - 'unitary': sorted([ - 'save_state', 'save_unitary', 'set_unitary', - ]), - 'superop': sorted([ - 'quantum_channel', 'qerror_loc', 'kraus', 'superop', 'save_state', - 'save_superop', 'set_superop', - ]), - 'tensor_network': sorted([ - 'quantum_channel', 'qerror_loc', 'roerror', 'kraus', 'superop', - 'save_state', 'save_expval', 'save_expval_var', - 'save_probabilities', 'save_probabilities_dict', - 'save_density_matrix', 'save_amplitudes', 'save_amplitudes_sq', - 'save_statevector', 'save_statevector_dict', - 'set_statevector', 'set_density_matrix' - ]) + "statevector": sorted( + [ + "quantum_channel", + "qerror_loc", + "roerror", + "kraus", + "save_expval", + "save_expval_var", + "save_probabilities", + "save_probabilities_dict", + "save_amplitudes", + "save_amplitudes_sq", + "save_density_matrix", + "save_state", + "save_statevector", + "save_statevector_dict", + "set_statevector", + "if_else", + "for_loop", + "while_loop", + "break_loop", + "continue_loop", + ] + ), + "density_matrix": sorted( + [ + "quantum_channel", + "qerror_loc", + "roerror", + "kraus", + "superop", + "save_state", + "save_expval", + "save_expval_var", + "save_probabilities", + "save_probabilities_dict", + "save_density_matrix", + "save_amplitudes_sq", + "set_density_matrix", + "if_else", + "for_loop", + "while_loop", + "break_loop", + "continue_loop", + ] + ), + "matrix_product_state": sorted( + [ + "quantum_channel", + "qerror_loc", + "roerror", + "kraus", + "save_expval", + "save_expval_var", + "save_probabilities", + "save_probabilities_dict", + "save_state", + "save_matrix_product_state", + "save_statevector", + "save_density_matrix", + "save_amplitudes", + "save_amplitudes_sq", + "set_matrix_product_state", + "if_else", + "for_loop", + "while_loop", + "break_loop", + "continue_loop", + ] + ), + "stabilizer": sorted( + [ + "quantum_channel", + "qerror_loc", + "roerror", + "save_expval", + "save_expval_var", + "save_probabilities", + "save_probabilities_dict", + "save_amplitudes_sq", + "save_state", + "save_clifford", + "save_stabilizer", + "set_stabilizer", + "if_else", + "for_loop", + "while_loop", + "break_loop", + "continue_loop", + ] + ), + "extended_stabilizer": sorted( + [ + "quantum_channel", + "qerror_loc", + "roerror", + "save_statevector", + ] + ), + "unitary": sorted( + [ + "save_state", + "save_unitary", + "set_unitary", + ] + ), + "superop": sorted( + [ + "quantum_channel", + "qerror_loc", + "kraus", + "superop", + "save_state", + "save_superop", + "set_superop", + ] + ), + "tensor_network": sorted( + [ + "quantum_channel", + "qerror_loc", + "roerror", + "kraus", + "superop", + "save_state", + "save_expval", + "save_expval_var", + "save_probabilities", + "save_probabilities_dict", + "save_density_matrix", + "save_amplitudes", + "save_amplitudes_sq", + "save_statevector", + "save_statevector_dict", + "set_statevector", + "set_density_matrix", + ] + ), } # Automatic method custom instructions are the union of statevector, # density matrix, and stabilizer methods - _CUSTOM_INSTR[None] = _CUSTOM_INSTR['automatic'] = sorted( - set(_CUSTOM_INSTR['statevector']).union( - _CUSTOM_INSTR['stabilizer']).union( - _CUSTOM_INSTR['density_matrix']).union( - _CUSTOM_INSTR['matrix_product_state']).union( - _CUSTOM_INSTR['unitary']).union( - _CUSTOM_INSTR['superop']).union( - _CUSTOM_INSTR['tensor_network'])) + _CUSTOM_INSTR[None] = _CUSTOM_INSTR["automatic"] = sorted( + set(_CUSTOM_INSTR["statevector"]) + .union(_CUSTOM_INSTR["stabilizer"]) + .union(_CUSTOM_INSTR["density_matrix"]) + .union(_CUSTOM_INSTR["matrix_product_state"]) + .union(_CUSTOM_INSTR["unitary"]) + .union(_CUSTOM_INSTR["superop"]) + .union(_CUSTOM_INSTR["tensor_network"]) + ) _DEFAULT_CONFIGURATION = { - 'backend_name': 'aer_simulator', - 'backend_version': __version__, - 'n_qubits': MAX_QUBITS_STATEVECTOR, - 'url': 'https://github.com/Qiskit/qiskit-aer', - 'simulator': True, - 'local': True, - 'conditional': True, - 'open_pulse': False, - 'memory': True, - 'max_shots': int(1e6), - 'description': 'A C++ QasmQobj simulator with noise', - 'coupling_map': None, - 'basis_gates': BASIS_GATES['automatic'], - 'custom_instructions': _CUSTOM_INSTR['automatic'], - 'gates': [] + "backend_name": "aer_simulator", + "backend_version": __version__, + "n_qubits": MAX_QUBITS_STATEVECTOR, + "url": "https://github.com/Qiskit/qiskit-aer", + "simulator": True, + "local": True, + "conditional": True, + "open_pulse": False, + "memory": True, + "max_shots": int(1e6), + "description": "A C++ QasmQobj simulator with noise", + "coupling_map": None, + "basis_gates": BASIS_GATES["automatic"], + "custom_instructions": _CUSTOM_INSTR["automatic"], + "gates": [], } _SIMULATION_METHODS = [ - 'automatic', 'statevector', 'density_matrix', - 'stabilizer', 'matrix_product_state', 'extended_stabilizer', - 'unitary', 'superop', 'tensor_network' + "automatic", + "statevector", + "density_matrix", + "stabilizer", + "matrix_product_state", + "extended_stabilizer", + "unitary", + "superop", + "tensor_network", ] _AVAILABLE_METHODS = None - _SIMULATION_DEVICES = ('CPU', 'GPU', 'Thrust') + _SIMULATION_DEVICES = ("CPU", "GPU", "Thrust") _AVAILABLE_DEVICES = None - def __init__(self, - configuration=None, - properties=None, - provider=None, - **backend_options): + def __init__( + self, configuration=None, properties=None, provider=None, **backend_options + ): self._controller = aer_controller_execute() # Update available methods and devices for class if AerSimulator._AVAILABLE_DEVICES is None: AerSimulator._AVAILABLE_DEVICES = available_devices( - self._controller, AerSimulator._SIMULATION_DEVICES) + self._controller, AerSimulator._SIMULATION_DEVICES + ) if AerSimulator._AVAILABLE_METHODS is None: AerSimulator._AVAILABLE_METHODS = available_methods( - self._controller, AerSimulator._SIMULATION_METHODS, AerSimulator._AVAILABLE_DEVICES) + self._controller, + AerSimulator._SIMULATION_METHODS, + AerSimulator._AVAILABLE_DEVICES, + ) # Default configuration if configuration is None: configuration = QasmBackendConfiguration.from_dict( - AerSimulator._DEFAULT_CONFIGURATION) + AerSimulator._DEFAULT_CONFIGURATION + ) # Cache basis gates since computing the intersection # of noise model, method, and config gates is expensive. - self._cached_basis_gates = self._BASIS_GATES['automatic'] + self._cached_basis_gates = self._BASIS_GATES["automatic"] - super().__init__(configuration, - properties=properties, - provider=provider, - backend_options=backend_options) + super().__init__( + configuration, + properties=properties, + provider=provider, + backend_options=backend_options, + ) @classmethod def _default_options(cls): return Options( # Global options shots=1024, - method='automatic', - device='CPU', + method="automatic", + device="CPU", precision="double", executor=None, max_job_size=None, @@ -614,7 +718,7 @@ def _default_options(cls): # stabilizer options stabilizer_max_snapshot_probabilities=32, # extended stabilizer options - extended_stabilizer_sampling_method='resampled_metropolis', + extended_stabilizer_sampling_method="resampled_metropolis", extended_stabilizer_metropolis_mixing_time=5000, extended_stabilizer_approximation_error=0.05, extended_stabilizer_norm_estimation_samples=100, @@ -624,35 +728,35 @@ def _default_options(cls): # MPS options matrix_product_state_truncation_threshold=1e-16, matrix_product_state_max_bond_dimension=None, - mps_sample_measure_algorithm='mps_heuristic', + mps_sample_measure_algorithm="mps_heuristic", mps_log_data=False, - mps_swap_direction='mps_swap_left', + mps_swap_direction="mps_swap_left", chop_threshold=1e-8, mps_parallel_threshold=14, mps_omp_threads=1, # tensor network options tensor_network_num_sampling_qubits=10, - use_cuTensorNet_autotuning=False + use_cuTensorNet_autotuning=False, ) def __repr__(self): """String representation of an AerSimulator.""" display = super().__repr__() - noise_model = getattr(self.options, 'noise_model', None) + noise_model = getattr(self.options, "noise_model", None) if noise_model is None or noise_model.is_ideal(): return display - pad = ' ' * (len(self.__class__.__name__) + 1) - return f'{display[:-1]}\n{pad}noise_model={repr(noise_model)})' + pad = " " * (len(self.__class__.__name__) + 1) + return f"{display[:-1]}\n{pad}noise_model={repr(noise_model)})" def name(self): """Format backend name string for simulator""" name = self._configuration.backend_name - method = getattr(self.options, 'method', None) - if method not in [None, 'automatic']: - name += f'_{method}' - device = getattr(self.options, 'device', None) - if device not in [None, 'CPU']: - name += f'_{device}'.lower() + method = getattr(self.options, "method", None) + if method not in [None, "automatic"]: + name += f"_{method}" + device = getattr(self.options, "device", None) + if device not in [None, "CPU"]: + name += f"_{device}".lower() return name @classmethod @@ -682,26 +786,24 @@ def from_backend(cls, backend, **options): # Customize configuration name name = configuration.backend_name - configuration.backend_name = f'aer_simulator({name})' + configuration.backend_name = f"aer_simulator({name})" else: raise TypeError( "The backend argument requires a BackendV2 or BackendV1 object, " f"not a {type(backend)} object" ) # Use automatic noise model if none is provided - if 'noise_model' not in options: + if "noise_model" not in options: # pylint: disable=import-outside-toplevel # Avoid cyclic import from ..noise.noise_model import NoiseModel noise_model = NoiseModel.from_backend(backend) if not noise_model.is_ideal(): - options['noise_model'] = noise_model + options["noise_model"] = noise_model # Initialize simulator - sim = cls(configuration=configuration, - properties=properties, - **options) + sim = cls(configuration=configuration, properties=properties, **options) return sim def available_methods(self): @@ -724,15 +826,15 @@ def configuration(self): # Update basis gates based on custom options, config, method, # and noise model config.custom_instructions = self._CUSTOM_INSTR[ - getattr(self.options, 'method', 'automatic')] + getattr(self.options, "method", "automatic") + ] config.basis_gates = self._cached_basis_gates + config.custom_instructions # Update simulator name config.backend_name = self.name() return config def _execute_circuits(self, aer_circuits, noise_model, config): - """Execute circuits on the backend. - """ + """Execute circuits on the backend.""" ret = cpp_execute_circuits(self._controller, aer_circuits, noise_model, config) return ret @@ -752,10 +854,11 @@ def set_option(self, key, value): self._set_configuration_option(key, value) return if key == "method": - if (value is not None and value not in self.available_methods()): + if value is not None and value not in self.available_methods(): raise AerError( f"Invalid simulation method {value}. Available methods" - f" are: {self.available_methods()}") + f" are: {self.available_methods()}" + ) self._set_method_config(value) super().set_option(key, value) if key in ["method", "noise_model", "basis_gates"]: @@ -777,8 +880,9 @@ def _validate(self, qobj): if no_data: logger.warning( 'No measure or save instruction in circuit "%s": ' - 'results will be empty.', - experiment.header.name) + "results will be empty.", + experiment.header.name, + ) def _basis_gates(self): """Return simualtor basis gates. @@ -788,21 +892,20 @@ def _basis_gates(self): and method supported basis gates. """ # Use option value for basis gates if set - if 'basis_gates' in self._options_configuration: - return self._options_configuration['basis_gates'] + if "basis_gates" in self._options_configuration: + return self._options_configuration["basis_gates"] # Compute intersection with method basis gates - method = getattr(self._options, 'method', 'automatic') + method = getattr(self._options, "method", "automatic") method_gates = self._BASIS_GATES[method] config_gates = self._configuration.basis_gates if config_gates: - basis_gates = set(config_gates).intersection( - method_gates) + basis_gates = set(config_gates).intersection(method_gates) else: basis_gates = method_gates # Compute intersection with noise model basis gates - noise_model = getattr(self.options, 'noise_model', None) + noise_model = getattr(self.options, "noise_model", None) if noise_model: noise_gates = noise_model.basis_gates basis_gates = basis_gates.intersection(noise_gates) @@ -814,36 +917,39 @@ def _basis_gates(self): "The intersection of configuration basis gates (%s), " "simulation method basis gates (%s), and " "noise model basis gates (%s) is empty", - config_gates, method_gates, noise_gates) + config_gates, + method_gates, + noise_gates, + ) return sorted(basis_gates) def _set_method_config(self, method=None): """Set non-basis gate options when setting method""" # Update configuration description and number of qubits - if method == 'statevector': - description = 'A C++ statevector simulator with noise' + if method == "statevector": + description = "A C++ statevector simulator with noise" n_qubits = MAX_QUBITS_STATEVECTOR - elif method == 'density_matrix': - description = 'A C++ density matrix simulator with noise' + elif method == "density_matrix": + description = "A C++ density matrix simulator with noise" n_qubits = MAX_QUBITS_STATEVECTOR // 2 - elif method == 'unitary': - description = 'A C++ unitary matrix simulator' + elif method == "unitary": + description = "A C++ unitary matrix simulator" n_qubits = MAX_QUBITS_STATEVECTOR // 2 - elif method == 'superop': - description = 'A C++ superop matrix simulator with noise' + elif method == "superop": + description = "A C++ superop matrix simulator with noise" n_qubits = MAX_QUBITS_STATEVECTOR // 4 - elif method == 'matrix_product_state': - description = 'A C++ matrix product state simulator with noise' + elif method == "matrix_product_state": + description = "A C++ matrix product state simulator with noise" n_qubits = 63 # TODO: not sure what to put here? - elif method == 'stabilizer': - description = 'A C++ Clifford stabilizer simulator with noise' + elif method == "stabilizer": + description = "A C++ Clifford stabilizer simulator with noise" n_qubits = 10000 # TODO: estimate from memory - elif method == 'extended_stabilizer': - description = 'A C++ Clifford+T extended stabilizer simulator with noise' + elif method == "extended_stabilizer": + description = "A C++ Clifford+T extended stabilizer simulator with noise" n_qubits = 63 # TODO: estimate from memory else: # Clear options to default description = None n_qubits = None - self._set_configuration_option('description', description) - self._set_configuration_option('n_qubits', n_qubits) + self._set_configuration_option("description", description) + self._set_configuration_option("n_qubits", n_qubits) diff --git a/qiskit_aer/backends/aerbackend.py b/qiskit_aer/backends/aerbackend.py index 501ff50756..2e2126c6f6 100644 --- a/qiskit_aer/backends/aerbackend.py +++ b/qiskit_aer/backends/aerbackend.py @@ -42,12 +42,14 @@ class AerBackend(Backend, ABC): """Qiskit Aer Backend class.""" - def __init__(self, - configuration, - properties=None, - defaults=None, - backend_options=None, - provider=None): + def __init__( + self, + configuration, + properties=None, + defaults=None, + backend_options=None, + provider=None, + ): """Aer class for backends. This method should initialize the module and its configuration, and @@ -111,7 +113,9 @@ def _convert_circuit_binds(self, circuit, binds): def _convert_binds(self, circuits, parameter_binds): if isinstance(circuits, QuantumCircuit): if len(parameter_binds) > 1: - raise AerError("More than 1 parameter table provided for a single circuit") + raise AerError( + "More than 1 parameter table provided for a single circuit" + ) return [self._convert_circuit_binds(circuits, parameter_binds[0])] elif len(parameter_binds) != len(circuits): @@ -120,17 +124,13 @@ def _convert_binds(self, circuits, parameter_binds): "parameter bind dictionaries" ) parameterizations = [ - self._convert_circuit_binds( - circuit, parameter_binds[idx]) for idx, circuit in enumerate(circuits) + self._convert_circuit_binds(circuit, parameter_binds[idx]) + for idx, circuit in enumerate(circuits) ] return parameterizations # pylint: disable=arguments-differ - def run(self, - circuits, - validate=False, - parameter_binds=None, - **run_options): + def run(self, circuits, validate=False, parameter_binds=None, **run_options): """Run a qobj on the backend. Args: @@ -172,11 +172,13 @@ def run(self, if isinstance(circuits, (QasmQobj, PulseQobj)): warnings.warn( - 'Using a qobj for run() is deprecated as of qiskit-aer 0.9.0' - ' and will be removed no sooner than 3 months from that release' - ' date. Transpiled circuits should now be passed directly using' - ' `backend.run(circuits, **run_options).', - DeprecationWarning, stacklevel=2) + "Using a qobj for run() is deprecated as of qiskit-aer 0.9.0" + " and will be removed no sooner than 3 months from that release" + " date. Transpiled circuits should now be passed directly using" + " `backend.run(circuits, **run_options).", + DeprecationWarning, + stacklevel=2, + ) if parameter_binds: raise TypeError("Parameter binds can't be used with an input qobj") # A work around to support both qobj options and run options until @@ -191,8 +193,8 @@ def run(self, for key, value in circuits.config.__dict__.items(): if key not in run_options and value is not None: run_options[key] = value - if 'parameter_binds' in run_options: - parameter_binds = run_options.pop('parameter_binds') + if "parameter_binds" in run_options: + parameter_binds = run_options.pop("parameter_binds") return self._run_qobj(circuits, validate, parameter_binds, **run_options) only_circuits = True @@ -203,55 +205,62 @@ def run(self, if only_circuits and not only_pulse: if validate: - raise TypeError("bad input to run() function;" - "`validation` argument is only effective for input qobj") - - executor = run_options.get('executor', None) - if executor is None and 'executor' in self.options.__dict__: - executor = self.options.__dict__.get('executor', None) + raise TypeError( + "bad input to run() function;" + "`validation` argument is only effective for input qobj" + ) + + executor = run_options.get("executor", None) + if executor is None and "executor" in self.options.__dict__: + executor = self.options.__dict__.get("executor", None) if executor: # This path remains for DASK execution to split a qobj insttance # into sub-qobj instances. This will be replaced with _run_circuits path # in the near releases - return self._run_qobj(circuits, validate, parameter_binds, **run_options) + return self._run_qobj( + circuits, validate, parameter_binds, **run_options + ) else: return self._run_circuits(circuits, parameter_binds, **run_options) elif not only_circuits and only_pulse: return self._run_qobj(circuits, validate, parameter_binds, **run_options) elif not only_circuits and not only_pulse: - raise TypeError("bad input to run() function;" - "circuits and schedules cannot be mixed in a single run") + raise TypeError( + "bad input to run() function;" + "circuits and schedules cannot be mixed in a single run" + ) else: - raise TypeError("bad input to run() function;" - "circuits must be either circuits or schedules") - - def _run_circuits(self, - circuits, - parameter_binds, - **run_options): - """Run circuits by generating native circuits. - """ + raise TypeError( + "bad input to run() function;" + "circuits must be either circuits or schedules" + ) + + def _run_circuits(self, circuits, parameter_binds, **run_options): + """Run circuits by generating native circuits.""" circuits, noise_model = self._compile(circuits, **run_options) if parameter_binds: - run_options['parameterizations'] = self._convert_binds(circuits, parameter_binds) + run_options["parameterizations"] = self._convert_binds( + circuits, parameter_binds + ) config = generate_aer_config(circuits, self.options, **run_options) # Submit job job_id = str(uuid.uuid4()) - aer_job = AerJob(self, job_id, self._execute_circuits_job, - circuits=circuits, noise_model=noise_model, config=config) + aer_job = AerJob( + self, + job_id, + self._execute_circuits_job, + circuits=circuits, + noise_model=noise_model, + config=config, + ) aer_job.submit() return aer_job # pylint: disable=arguments-differ - def _run_qobj(self, - circuits, - validate=False, - parameter_binds=None, - **run_options): - """Run circuits by assembling qobj. - """ + def _run_qobj(self, circuits, validate=False, parameter_binds=None, **run_options): + """Run circuits by assembling qobj.""" qobj = self._assemble(circuits, parameter_binds=parameter_binds, **run_options) # Optional validation @@ -259,32 +268,41 @@ def _run_qobj(self, self._validate(qobj) # Get executor from qobj config and delete attribute so qobj can still be serialized - executor = getattr(qobj.config, 'executor', None) - if hasattr(qobj.config, 'executor'): - delattr(qobj.config, 'executor') + executor = getattr(qobj.config, "executor", None) + if hasattr(qobj.config, "executor"): + delattr(qobj.config, "executor") # Optionally split the job experiments = split_qobj( - qobj, max_size=getattr(qobj.config, 'max_job_size', None), - max_shot_size=getattr(qobj.config, 'max_shot_size', None)) + qobj, + max_size=getattr(qobj.config, "max_job_size", None), + max_shot_size=getattr(qobj.config, "max_shot_size", None), + ) # Temporarily remove any executor from options so that job submission # can work with Dask client executors which can't be pickled - opts_executor = getattr(self._options, 'executor', None) - if hasattr(self._options, 'executor'): + opts_executor = getattr(self._options, "executor", None) + if hasattr(self._options, "executor"): self._options.executor = None # Submit job job_id = str(uuid.uuid4()) if isinstance(experiments, list): - aer_job = AerJobSet(self, job_id, self._execute_qobj_job, experiments, executor) + aer_job = AerJobSet( + self, job_id, self._execute_qobj_job, experiments, executor + ) else: - aer_job = AerJob(self, job_id, self._execute_qobj_job, qobj=experiments, - executor=executor) + aer_job = AerJob( + self, + job_id, + self._execute_qobj_job, + qobj=experiments, + executor=executor, + ) aer_job.submit() # Restore removed executor after submission - if hasattr(self._options, 'executor'): + if hasattr(self._options, "executor"): self._options.executor = opts_executor return aer_job @@ -300,7 +318,7 @@ def configuration(self): setattr(config, key, val) # If config has custom instructions add them to # basis gates to include them for the terra transpiler - if hasattr(config, 'custom_instructions'): + if hasattr(config, "custom_instructions"): config.basis_gates = config.basis_gates + config.custom_instructions return config @@ -350,9 +368,10 @@ def status(self): backend_version=self.configuration().backend_version, operational=True, pending_jobs=0, - status_msg='') + status_msg="", + ) - def _execute_qobj_job(self, qobj, job_id='', format_result=True): + def _execute_qobj_job(self, qobj, job_id="", format_result=True): """Run a qobj job""" # Start timer start = time.time() @@ -385,9 +404,8 @@ def _execute_qobj_job(self, qobj, job_id='', format_result=True): if not isinstance(output, dict): logger.error("%s: simulation failed.", self.name()) if output: - logger.error('Output: %s', output) - raise AerError( - "simulation terminated without returning valid output.") + logger.error("Output: %s", output) + raise AerError("simulation terminated without returning valid output.") # Format results output["job_id"] = job_id @@ -397,9 +415,11 @@ def _execute_qobj_job(self, qobj, job_id='', format_result=True): # Push metadata to experiment headers for result in output["results"]: - if ("header" in result and - "metadata" in result["header"] and - "metadata_index" in result["header"]["metadata"]): + if ( + "header" in result + and "metadata" in result["header"] + and "metadata_index" in result["header"]["metadata"] + ): metadata_index = result["header"]["metadata"]["metadata_index"] result["header"]["metadata"] = metadata_list[metadata_index] @@ -416,8 +436,9 @@ def _execute_qobj_job(self, qobj, job_id='', format_result=True): return self._format_results(output) return output - def _execute_circuits_job(self, circuits, noise_model, config, job_id='', - format_result=True): + def _execute_circuits_job( + self, circuits, noise_model, config, job_id="", format_result=True + ): """Run a job""" # Start timer start = time.time() @@ -441,9 +462,8 @@ def _execute_circuits_job(self, circuits, noise_model, config, job_id='', if not isinstance(output, dict): logger.error("%s: simulation failed.", self.name()) if output: - logger.error('Output: %s', output) - raise AerError( - "simulation terminated without returning valid output.") + logger.error("Output: %s", output) + raise AerError("simulation terminated without returning valid output.") # Format results output["job_id"] = job_id @@ -453,9 +473,12 @@ def _execute_circuits_job(self, circuits, noise_model, config, job_id='', # Push metadata to experiment headers for result in output["results"]: - if ("header" in result and - "metadata" in result["header"] and result["header"]["metadata"] and - "metadata_index" in result["header"]["metadata"]): + if ( + "header" in result + and "metadata" in result["header"] + and result["header"]["metadata"] + and "metadata_index" in result["header"]["metadata"] + ): metadata_index = result["header"]["metadata"]["metadata_index"] result["header"]["metadata"] = metadata_list[metadata_index] @@ -485,7 +508,9 @@ def _format_results(output): save_subtypes = metadata.get("result_subtypes", {}) for key, val in data.items(): if key in save_types: - data[key] = format_save_type(val, save_types[key], save_subtypes[key]) + data[key] = format_save_type( + val, save_types[key], save_subtypes[key] + ) return Result.from_dict(output) def _compile(self, circuits, **run_options): @@ -496,13 +521,13 @@ def _compile(self, circuits, **run_options): # Compile Qasm3 instructions circuits, optypes = compile_circuit( - circuits, - basis_gates=self.configuration().basis_gates, - optypes=optypes) + circuits, basis_gates=self.configuration().basis_gates, optypes=optypes + ) # run option noise model circuits, noise_model, run_options = self._assemble_noise_model( - circuits, optypes, **run_options) + circuits, optypes, **run_options + ) return circuits, noise_model @@ -517,7 +542,7 @@ def _assemble(self, circuits, parameter_binds=None, **run_options): # If noise model exists, add it to the run options if noise_model: - run_options['noise_model'] = noise_model + run_options["noise_model"] = noise_model if parameter_binds: # Handle parameter binding @@ -529,7 +554,8 @@ def _assemble(self, circuits, parameter_binds=None, **run_options): [circuit], backend=self, parameter_binds=[assemble_bind], - parameterizations=parameterizations) + parameterizations=parameterizations, + ) if qobj: qobj.experiments.append(qobj_tmp.experiments[0]) else: @@ -558,12 +584,15 @@ def _assemble_noise_model(self, circuits, optypes, **run_options): # that do not contain a quantum error updated_noise = False noise_model = run_options.get( - 'noise_model', getattr(self.options, 'noise_model', None)) + "noise_model", getattr(self.options, "noise_model", None) + ) # Add custom pass noise only to QuantumCircuit objects that contain delay # instructions since this is the only instruction handled by the noise pass # at present - if noise_model and all(isinstance(circ, QuantumCircuit) for circ in run_circuits): + if noise_model and all( + isinstance(circ, QuantumCircuit) for circ in run_circuits + ): npm = noise_model._pass_manager() if npm is not None: # Get indicies of circuits that need noise transpiling @@ -584,7 +613,8 @@ def _assemble_noise_model(self, circuits, optypes, **run_options): # Check if circuits contain quantum error instructions for idx, circ in enumerate(run_circuits): if QuantumChannelInstruction in optypes[idx] and not isinstance( - circ, (Schedule, ScheduleBlock)): + circ, (Schedule, ScheduleBlock) + ): updated_circ = False new_data = [] for inst, qargs, cargs in circ.data: @@ -618,10 +648,10 @@ def _assemble_noise_model(self, circuits, optypes, **run_options): def _get_executor(self, **run_options): """Get the executor""" - if 'executor' in run_options: - return run_options['executor'] + if "executor" in run_options: + return run_options["executor"] else: - return getattr(self._options, 'executor', None) + return getattr(self._options, "executor", None) @abstractmethod def _execute_qobj(self, qobj): @@ -718,4 +748,4 @@ def __repr__(self): """String representation of an AerBackend.""" name = self.__class__.__name__ display = f"'{self.name()}'" - return f'{name}({display})' + return f"{name}({display})" diff --git a/qiskit_aer/backends/backend_utils.py b/qiskit_aer/backends/backend_utils.py index c85049e6f2..72b3fbe5fc 100644 --- a/qiskit_aer/backends/backend_utils.py +++ b/qiskit_aer/backends/backend_utils.py @@ -23,10 +23,15 @@ from qiskit.result import ProbDistribution from qiskit.quantum_info import Clifford from .compatibility import ( - Statevector, DensityMatrix, StabilizerState, Operator, SuperOp) + Statevector, + DensityMatrix, + StabilizerState, + Operator, + SuperOp, +) # Available system memory -SYSTEM_MEMORY_GB = local_hardware_info()['memory'] +SYSTEM_MEMORY_GB = local_hardware_info()["memory"] # Max number of qubits for complex double statevector # given available system memory @@ -49,71 +54,370 @@ } BASIS_GATES = { - 'statevector': sorted([ - 'u1', 'u2', 'u3', 'u', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', - 'y', 'z', 'h', 's', 'sdg', 'sx', 'sxdg', 't', 'tdg', 'swap', 'cx', - 'cy', 'cz', 'csx', 'cp', 'cu', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', - 'rzz', 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', - 'mcp', 'mcphase', 'mcu', 'mcu1', 'mcu2', 'mcu3', 'mcrx', 'mcry', 'mcrz', - 'mcr', 'mcswap', 'unitary', 'diagonal', 'multiplexer', - 'initialize', 'delay', 'pauli', 'mcx_gray', 'ecr' - ]), - 'density_matrix': sorted([ - 'u1', 'u2', 'u3', 'u', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', - 'y', 'z', 'h', 's', 'sdg', 'sx', 'sxdg', 't', 'tdg', 'swap', 'cx', - 'cy', 'cz', 'cp', 'cu1', 'rxx', 'ryy', 'rzz', 'rzx', 'ccx', - 'unitary', 'diagonal', 'delay', 'pauli', 'ecr', - ]), - 'matrix_product_state': sorted([ - 'u1', 'u2', 'u3', 'u', 'p', 'cp', 'cx', 'cy', 'cz', 'id', 'x', 'y', 'z', 'h', 's', - 'sdg', 'sx', 'sxdg', 't', 'tdg', 'swap', 'ccx', 'unitary', 'roerror', 'delay', 'pauli', - 'r', 'rx', 'ry', 'rz', 'rxx', 'ryy', 'rzz', 'rzx', 'csx', 'cswap', 'diagonal', - 'initialize' - ]), - 'stabilizer': sorted([ - 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'sx', 'sxdg', 'cx', 'cy', 'cz', - 'swap', 'delay', 'pauli' - ]), - 'extended_stabilizer': sorted([ - 'cx', 'cz', 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'sx', 'sxdg', - 'swap', 'u0', 't', 'tdg', 'u1', 'p', 'ccx', 'ccz', 'delay', 'pauli' - ]), - 'unitary': sorted([ - 'u1', 'u2', 'u3', 'u', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', - 'y', 'z', 'h', 's', 'sdg', 'sx', 'sxdg', 't', 'tdg', 'swap', 'cx', - 'cy', 'cz', 'csx', 'cp', 'cu', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', - 'rzz', 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', - 'mcp', 'mcphase', 'mcu', 'mcu1', 'mcu2', 'mcu3', 'mcrx', 'mcry', 'mcrz', - 'mcr', 'mcswap', 'unitary', 'diagonal', 'multiplexer', 'delay', 'pauli', - 'ecr', - ]), - 'superop': sorted([ - 'u1', 'u2', 'u3', 'u', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', - 'y', 'z', 'h', 's', 'sdg', 'sx', 'sxdg', 't', 'tdg', 'swap', 'cx', - 'cy', 'cz', 'cp', 'cu1', 'rxx', 'ryy', - 'rzz', 'rzx', 'ccx', 'unitary', 'diagonal', 'delay', 'pauli' - ]), - 'tensor_network': sorted([ - 'u1', 'u2', 'u3', 'u', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', - 'y', 'z', 'h', 's', 'sdg', 'sx', 'sxdg', 't', 'tdg', 'swap', 'cx', - 'cy', 'cz', 'csx', 'cp', 'cu', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', - 'rzz', 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', - 'mcp', 'mcphase', 'mcu', 'mcu1', 'mcu2', 'mcu3', 'mcrx', 'mcry', 'mcrz', - 'mcr', 'mcswap', 'unitary', 'diagonal', 'multiplexer', - 'initialize', 'delay', 'pauli', 'mcx_gray' - ]) + "statevector": sorted( + [ + "u1", + "u2", + "u3", + "u", + "p", + "r", + "rx", + "ry", + "rz", + "id", + "x", + "y", + "z", + "h", + "s", + "sdg", + "sx", + "sxdg", + "t", + "tdg", + "swap", + "cx", + "cy", + "cz", + "csx", + "cp", + "cu", + "cu1", + "cu2", + "cu3", + "rxx", + "ryy", + "rzz", + "rzx", + "ccx", + "cswap", + "mcx", + "mcy", + "mcz", + "mcsx", + "mcp", + "mcphase", + "mcu", + "mcu1", + "mcu2", + "mcu3", + "mcrx", + "mcry", + "mcrz", + "mcr", + "mcswap", + "unitary", + "diagonal", + "multiplexer", + "initialize", + "delay", + "pauli", + "mcx_gray", + "ecr", + ] + ), + "density_matrix": sorted( + [ + "u1", + "u2", + "u3", + "u", + "p", + "r", + "rx", + "ry", + "rz", + "id", + "x", + "y", + "z", + "h", + "s", + "sdg", + "sx", + "sxdg", + "t", + "tdg", + "swap", + "cx", + "cy", + "cz", + "cp", + "cu1", + "rxx", + "ryy", + "rzz", + "rzx", + "ccx", + "unitary", + "diagonal", + "delay", + "pauli", + "ecr", + ] + ), + "matrix_product_state": sorted( + [ + "u1", + "u2", + "u3", + "u", + "p", + "cp", + "cx", + "cy", + "cz", + "id", + "x", + "y", + "z", + "h", + "s", + "sdg", + "sx", + "sxdg", + "t", + "tdg", + "swap", + "ccx", + "unitary", + "roerror", + "delay", + "pauli", + "r", + "rx", + "ry", + "rz", + "rxx", + "ryy", + "rzz", + "rzx", + "csx", + "cswap", + "diagonal", + "initialize", + ] + ), + "stabilizer": sorted( + [ + "id", + "x", + "y", + "z", + "h", + "s", + "sdg", + "sx", + "sxdg", + "cx", + "cy", + "cz", + "swap", + "delay", + "pauli", + ] + ), + "extended_stabilizer": sorted( + [ + "cx", + "cz", + "id", + "x", + "y", + "z", + "h", + "s", + "sdg", + "sx", + "sxdg", + "swap", + "u0", + "t", + "tdg", + "u1", + "p", + "ccx", + "ccz", + "delay", + "pauli", + ] + ), + "unitary": sorted( + [ + "u1", + "u2", + "u3", + "u", + "p", + "r", + "rx", + "ry", + "rz", + "id", + "x", + "y", + "z", + "h", + "s", + "sdg", + "sx", + "sxdg", + "t", + "tdg", + "swap", + "cx", + "cy", + "cz", + "csx", + "cp", + "cu", + "cu1", + "cu2", + "cu3", + "rxx", + "ryy", + "rzz", + "rzx", + "ccx", + "cswap", + "mcx", + "mcy", + "mcz", + "mcsx", + "mcp", + "mcphase", + "mcu", + "mcu1", + "mcu2", + "mcu3", + "mcrx", + "mcry", + "mcrz", + "mcr", + "mcswap", + "unitary", + "diagonal", + "multiplexer", + "delay", + "pauli", + "ecr", + ] + ), + "superop": sorted( + [ + "u1", + "u2", + "u3", + "u", + "p", + "r", + "rx", + "ry", + "rz", + "id", + "x", + "y", + "z", + "h", + "s", + "sdg", + "sx", + "sxdg", + "t", + "tdg", + "swap", + "cx", + "cy", + "cz", + "cp", + "cu1", + "rxx", + "ryy", + "rzz", + "rzx", + "ccx", + "unitary", + "diagonal", + "delay", + "pauli", + ] + ), + "tensor_network": sorted( + [ + "u1", + "u2", + "u3", + "u", + "p", + "r", + "rx", + "ry", + "rz", + "id", + "x", + "y", + "z", + "h", + "s", + "sdg", + "sx", + "sxdg", + "t", + "tdg", + "swap", + "cx", + "cy", + "cz", + "csx", + "cp", + "cu", + "cu1", + "cu2", + "cu3", + "rxx", + "ryy", + "rzz", + "rzx", + "ccx", + "cswap", + "mcx", + "mcy", + "mcz", + "mcsx", + "mcp", + "mcphase", + "mcu", + "mcu1", + "mcu2", + "mcu3", + "mcrx", + "mcry", + "mcrz", + "mcr", + "mcswap", + "unitary", + "diagonal", + "multiplexer", + "initialize", + "delay", + "pauli", + "mcx_gray", + ] + ), } # Automatic method basis gates are the union of statevector, # density matrix, and stabilizer methods -BASIS_GATES[None] = BASIS_GATES['automatic'] = sorted( - set(BASIS_GATES['statevector']).union( - BASIS_GATES['stabilizer']).union( - BASIS_GATES['density_matrix']).union( - BASIS_GATES['matrix_product_state']).union( - BASIS_GATES['unitary']).union( - BASIS_GATES['superop']).union( - BASIS_GATES['tensor_network'])) +BASIS_GATES[None] = BASIS_GATES["automatic"] = sorted( + set(BASIS_GATES["statevector"]) + .union(BASIS_GATES["stabilizer"]) + .union(BASIS_GATES["density_matrix"]) + .union(BASIS_GATES["matrix_product_state"]) + .union(BASIS_GATES["unitary"]) + .union(BASIS_GATES["superop"]) + .union(BASIS_GATES["tensor_network"]) +) def cpp_execute_qobj(controller, qobj): @@ -147,13 +451,15 @@ def available_methods(controller, methods, devices): for device in devices: for method in methods: if method not in valid_methods: - qobj = assemble(dummy_circ, - optimization_level=0, - shots=1, - method=method, - device=device) + qobj = assemble( + dummy_circ, + optimization_level=0, + shots=1, + method=method, + device=device, + ) result = cpp_execute_qobj(controller, qobj) - if result.get('success', False): + if result.get("success", False): valid_methods.append(method) return tuple(valid_methods) @@ -166,13 +472,15 @@ def available_devices(controller, devices): valid_devices = [] for device in devices: - qobj = assemble(dummy_circ, - optimization_level=0, - shots=1, - method="statevector", - device=device) + qobj = assemble( + dummy_circ, + optimization_level=0, + shots=1, + method="statevector", + device=device, + ) result = cpp_execute_qobj(controller, qobj) - if result.get('success', False): + if result.get("success", False): valid_devices.append(device) return tuple(valid_devices) @@ -186,7 +494,8 @@ def save_inst(num_qubits): name=f"save_{state}", qubits=list(range(num_qubits)), label=f"{state}", - snapshot_type="single") + snapshot_type="single", + ) for exp in qobj.experiments: num_qubits = exp.config.n_qubits @@ -200,10 +509,9 @@ def add_final_save_op(aer_circuits, state): for aer_circuit in aer_circuits: num_qubits = aer_circuit.num_qubits - aer_circuit.save_state(list(range(num_qubits)), - f"save_{state}", - "single", - state) + aer_circuit.save_state( + list(range(num_qubits)), f"save_{state}", "single", state + ) return aer_circuits @@ -241,9 +549,11 @@ def format_save_type(data, save_type, save_subtype): return data if save_subtype in ["list", "c_list"]: + def func(data): init_fn = init_fns[save_type] return [init_fn(i) for i in data] + else: func = init_fns[save_type] diff --git a/qiskit_aer/backends/compatibility.py b/qiskit_aer/backends/compatibility.py index faaccda273..2f3c874631 100644 --- a/qiskit_aer/backends/compatibility.py +++ b/qiskit_aer/backends/compatibility.py @@ -30,7 +30,7 @@ def _forward_attr(attr): # Pass Iterable magic methods on to the Numpy array. We can't pass # `__getitem__` (and consequently `__setitem__`, `__delitem__`) on because # `Statevector` implements them itself. - if attr[:2] == '__' or attr in ['_data', '_op_shape']: + if attr[:2] == "__" or attr in ["_data", "_op_shape"]: return False return True @@ -60,9 +60,9 @@ def __getattr__(self, attr): def __eq__(self, other): return ( - isinstance(self, type(other)) and - self._op_shape == other._op_shape and - np.allclose(self.data, other.data, rtol=self.rtol, atol=self.atol) + isinstance(self, type(other)) + and self._op_shape == other._op_shape + and np.allclose(self.data, other.data, rtol=self.rtol, atol=self.atol) ) def __bool__(self): @@ -103,9 +103,9 @@ def __getattr__(self, attr): def __eq__(self, other): return ( - isinstance(self, type(other)) and - self._op_shape == other._op_shape and - np.allclose(self.data, other.data, rtol=self.rtol, atol=self.atol) + isinstance(self, type(other)) + and self._op_shape == other._op_shape + and np.allclose(self.data, other.data, rtol=self.rtol, atol=self.atol) ) def __len__(self): @@ -144,9 +144,9 @@ def __getattr__(self, attr): def __eq__(self, other): return ( - isinstance(self, type(other)) and - self._op_shape == other._op_shape and - np.allclose(self.data, other.data, rtol=self.rtol, atol=self.atol) + isinstance(self, type(other)) + and self._op_shape == other._op_shape + and np.allclose(self.data, other.data, rtol=self.rtol, atol=self.atol) ) def __bool__(self): @@ -190,9 +190,9 @@ def __getattr__(self, attr): def __eq__(self, other): return ( - isinstance(self, type(other)) and - self._op_shape == other._op_shape and - np.allclose(self.data, other.data, rtol=self.rtol, atol=self.atol) + isinstance(self, type(other)) + and self._op_shape == other._op_shape + and np.allclose(self.data, other.data, rtol=self.rtol, atol=self.atol) ) def __bool__(self): @@ -253,7 +253,9 @@ def __getitem__(self, item): " Accessing dict items is deprecated and will result in an" " error in a future release. Use the `.clifford.to_dict()` methods to access " " the stored Clifford operator and convert to a dictionary.", - DeprecationWarning, stacklevel=2) + DeprecationWarning, + stacklevel=2, + ) return self._data.to_dict()[item] raise TypeError("'StabilizerState object is not subscriptable'") @@ -282,4 +284,6 @@ def _add(self, other): raise NotImplementedError(f"{type(self)} does not support addition") def _multiply(self, other): - raise NotImplementedError(f"{type(self)} does not support scalar multiplication") + raise NotImplementedError( + f"{type(self)} does not support scalar multiplication" + ) diff --git a/qiskit_aer/backends/pulse_simulator.py b/qiskit_aer/backends/pulse_simulator.py index b3be282793..b817e2de32 100644 --- a/qiskit_aer/backends/pulse_simulator.py +++ b/qiskit_aer/backends/pulse_simulator.py @@ -34,22 +34,22 @@ logger = logging.getLogger(__name__) DEFAULT_CONFIGURATION = { - 'backend_name': 'pulse_simulator', - 'backend_version': __version__, - 'n_qubits': 20, - 'coupling_map': None, - 'url': 'https://github.com/Qiskit/qiskit-aer', - 'simulator': True, - 'meas_levels': [1, 2], - 'local': True, - 'conditional': True, - 'open_pulse': True, - 'memory': False, - 'max_shots': int(1e6), - 'description': 'A Pulse-based Hamiltonian simulator for Pulse Qobj files', - 'gates': [], - 'basis_gates': [], - 'parametric_pulses': [] + "backend_name": "pulse_simulator", + "backend_version": __version__, + "n_qubits": 20, + "coupling_map": None, + "url": "https://github.com/Qiskit/qiskit-aer", + "simulator": True, + "meas_levels": [1, 2], + "local": True, + "conditional": True, + "open_pulse": True, + "memory": False, + "max_shots": int(1e6), + "description": "A Pulse-based Hamiltonian simulator for Pulse Qobj files", + "gates": [], + "basis_gates": [], + "parametric_pulses": [], } @@ -155,12 +155,15 @@ class PulseSimulator(AerBackend): are ``'atol'``, ``'rtol'``, ``'nsteps'``, ``'max_step'``, ``'num_cpus'``, ``'norm_tol'``, and ``'norm_steps'``. """ - def __init__(self, - configuration=None, - properties=None, - defaults=None, - provider=None, - **backend_options): + + def __init__( + self, + configuration=None, + properties=None, + defaults=None, + provider=None, + **backend_options + ): warn( "The Pulse simulator backend in Qiskit Aer is deprecated and will " "be removed in a future release. Instead the qiskit-dynamics " @@ -170,8 +173,7 @@ def __init__(self, ) if configuration is None: - configuration = BackendConfiguration.from_dict( - DEFAULT_CONFIGURATION) + configuration = BackendConfiguration.from_dict(DEFAULT_CONFIGURATION) else: configuration = copy.copy(configuration) configuration.meas_levels = self._meas_levels(configuration.meas_levels) @@ -179,24 +181,29 @@ def __init__(self, configuration.parametric_pulses = [] if defaults is None: - defaults = PulseDefaults(qubit_freq_est=[inf], - meas_freq_est=[inf], - buffer=0, - cmd_def=[], - pulse_library=[]) - - super().__init__(configuration, - properties=properties, - defaults=defaults, - provider=provider, - backend_options=backend_options) + defaults = PulseDefaults( + qubit_freq_est=[inf], + meas_freq_est=[inf], + buffer=0, + cmd_def=[], + pulse_library=[], + ) + + super().__init__( + configuration, + properties=properties, + defaults=defaults, + provider=provider, + backend_options=backend_options, + ) # Set up default system model - subsystem_list = backend_options.get('subsystem_list', None) - if backend_options.get('system_model') is None: - if hasattr(configuration, 'hamiltonian'): + subsystem_list = backend_options.get("subsystem_list", None) + if backend_options.get("system_model") is None: + if hasattr(configuration, "hamiltonian"): system_model = PulseSystemModel.from_config( - configuration, subsystem_list) + configuration, subsystem_list + ) self._set_system_model(system_model) @classmethod @@ -218,13 +225,11 @@ def _default_options(cls): executor=None, memory_slots=1, max_job_size=None, - max_shot_size=None) + max_shot_size=None, + ) # pylint: disable=arguments-differ, missing-param-doc - def run(self, - schedules, - validate=True, - **run_options): + def run(self, schedules, validate=True, **run_options): """Run a qobj on the backend. Args: @@ -255,7 +260,7 @@ def run(self, @property def _system_model(self): - return getattr(self._options, 'system_model') + return getattr(self._options, "system_model") @classmethod def from_backend(cls, backend, **options): @@ -268,16 +273,18 @@ def from_backend(cls, backend, **options): defaults = copy.copy(backend.defaults()) properties = copy.copy(backend.properties()) - backend_name = 'pulse_simulator({})'.format(configuration.backend_name) - description = 'A Pulse-based simulator configured from the backend: ' + backend_name = "pulse_simulator({})".format(configuration.backend_name) + description = "A Pulse-based simulator configured from the backend: " description += configuration.backend_name - sim = cls(configuration=configuration, - properties=properties, - defaults=defaults, - backend_name=backend_name, - description=description, - **options) + sim = cls( + configuration=configuration, + properties=properties, + defaults=defaults, + backend_name=backend_name, + description=description, + **options + ) return sim def _execute_qobj(self, qobj): @@ -293,42 +300,44 @@ def _execute_qobj(self, qobj): return pulse_controller(qobj) def _execute_circuits(self, aer_circuits, noise_model, config): - """Execute circuits on the backend. - """ + """Execute circuits on the backend.""" raise TypeError("pulse simulator does not support circuit execution") def set_option(self, key, value): """Set pulse simulation options and update backend.""" - if key == 'meas_levels': + if key == "meas_levels": self._set_configuration_option(key, self._meas_levels(value)) return # Handle cases that require updating two places - if key in ['dt', 'u_channel_lo']: + if key in ["dt", "u_channel_lo"]: self._set_configuration_option(key, value) if self._system_model is not None: setattr(self._system_model, key, value) return - if key == 'hamiltonian': + if key == "hamiltonian": # if option is hamiltonian, set in configuration and reconstruct pulse system model - subsystem_list = getattr(self._options.get, 'subsystem_list', None) - system_model = PulseSystemModel.from_config(self.configuration(), - subsystem_list) - super().set_option('system_model', system_model) + subsystem_list = getattr(self._options.get, "subsystem_list", None) + system_model = PulseSystemModel.from_config( + self.configuration(), subsystem_list + ) + super().set_option("system_model", system_model) self._set_configuration_option(key, value) return # if system model is specified directly - if key == 'system_model': - if hasattr(self.configuration(), 'hamiltonian'): - warn('Specifying both a configuration with a Hamiltonian and a ' - 'system model may result in inconsistencies.') + if key == "system_model": + if hasattr(self.configuration(), "hamiltonian"): + warn( + "Specifying both a configuration with a Hamiltonian and a " + "system model may result in inconsistencies." + ) # Set config dt and u_channel_lo to system model values self._set_system_model(value) return - if key == 'qubit_lo_freq': + if key == "qubit_lo_freq": value = [freq * 1e-9 for freq in value] # Set all other options from AerBackend @@ -336,11 +345,11 @@ def set_option(self, key, value): def _set_system_model(self, system_model): """Set system model option""" + self._set_configuration_option("dt", getattr(system_model, "dt", [])) self._set_configuration_option( - 'dt', getattr(system_model, 'dt', [])) - self._set_configuration_option( - 'u_channel_lo', getattr(system_model, 'u_channel_lo', [])) - super().set_option('system_model', system_model) + "u_channel_lo", getattr(system_model, "u_channel_lo", []) + ) + super().set_option("system_model", system_model) def _validate(self, qobj): """Validation of qobj. @@ -348,28 +357,32 @@ def _validate(self, qobj): Ensures that exactly one Acquire instruction is present in each schedule. Checks SystemModel is in qobj config """ - if getattr(qobj.config, 'system_model', None) is None: + if getattr(qobj.config, "system_model", None) is None: raise AerError("PulseSimulator requires a system model to run.") for exp in qobj.experiments: num_acquires = 0 for instruction in exp.instructions: - if instruction.name == 'acquire': + if instruction.name == "acquire": num_acquires += 1 if num_acquires > 1: - raise AerError("PulseSimulator does not support multiple Acquire " - "instructions in a single schedule.") + raise AerError( + "PulseSimulator does not support multiple Acquire " + "instructions in a single schedule." + ) if num_acquires == 0: - raise AerError("PulseSimulator requires at least one Acquire " - "instruction per schedule.") + raise AerError( + "PulseSimulator requires at least one Acquire " + "instruction per schedule." + ) @staticmethod def _meas_levels(meas_levels): """Function for setting meas_levels in a pulse simulator configuration.""" if 0 in meas_levels: - warn('Measurement level 0 not supported in pulse simulator.') + warn("Measurement level 0 not supported in pulse simulator.") tmp = copy.copy(meas_levels) tmp.remove(0) return tmp diff --git a/qiskit_aer/backends/qasm_simulator.py b/qiskit_aer/backends/qasm_simulator.py index 4a17dd8f37..02edf71ac9 100644 --- a/qiskit_aer/backends/qasm_simulator.py +++ b/qiskit_aer/backends/qasm_simulator.py @@ -23,13 +23,16 @@ from ..version import __version__ from ..aererror import AerError from .aerbackend import AerBackend -from .backend_utils import (cpp_execute_qobj, - cpp_execute_circuits, - available_methods, - MAX_QUBITS_STATEVECTOR, - LEGACY_METHOD_MAP, - map_legacy_method_options, - map_legacy_method_config) +from .backend_utils import ( + cpp_execute_qobj, + cpp_execute_circuits, + available_methods, + MAX_QUBITS_STATEVECTOR, + LEGACY_METHOD_MAP, + map_legacy_method_options, + map_legacy_method_config, +) + # pylint: disable=import-error, no-name-in-module from .controller_wrappers import aer_controller_execute @@ -303,79 +306,158 @@ class QasmSimulator(AerBackend): than or equal to enable fusion optimization [Default: 14] """ - _DEFAULT_BASIS_GATES = sorted([ - 'u1', 'u2', 'u3', 'u', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', - 'y', 'z', 'h', 's', 'sdg', 'sx', 'sxdg', 't', 'tdg', 'swap', 'cx', - 'cy', 'cz', 'csx', 'cp', 'cu', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', - 'rzz', 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', - 'mcp', 'mcphase', 'mcu', 'mcu1', 'mcu2', 'mcu3', 'mcrx', 'mcry', 'mcrz', - 'mcr', 'mcswap', 'unitary', 'diagonal', 'multiplexer', - 'initialize', 'delay', 'pauli', 'mcx_gray', 'ecr' - ]) - - _DEFAULT_CUSTOM_INSTR = sorted([ - 'quantum_channel', 'qerror_loc', 'roerror', 'kraus', - 'save_expval', 'save_expval_var', - 'save_probabilities', 'save_probabilities_dict', - 'save_amplitudes', 'save_amplitudes_sq', 'save_state', - 'save_density_matrix', 'save_statevector', 'save_statevector_dict', - 'save_stabilizer', 'set_statevector', 'set_density_matrix', - 'set_stabilizer', - ]) + _DEFAULT_BASIS_GATES = sorted( + [ + "u1", + "u2", + "u3", + "u", + "p", + "r", + "rx", + "ry", + "rz", + "id", + "x", + "y", + "z", + "h", + "s", + "sdg", + "sx", + "sxdg", + "t", + "tdg", + "swap", + "cx", + "cy", + "cz", + "csx", + "cp", + "cu", + "cu1", + "cu2", + "cu3", + "rxx", + "ryy", + "rzz", + "rzx", + "ccx", + "cswap", + "mcx", + "mcy", + "mcz", + "mcsx", + "mcp", + "mcphase", + "mcu", + "mcu1", + "mcu2", + "mcu3", + "mcrx", + "mcry", + "mcrz", + "mcr", + "mcswap", + "unitary", + "diagonal", + "multiplexer", + "initialize", + "delay", + "pauli", + "mcx_gray", + "ecr", + ] + ) + + _DEFAULT_CUSTOM_INSTR = sorted( + [ + "quantum_channel", + "qerror_loc", + "roerror", + "kraus", + "save_expval", + "save_expval_var", + "save_probabilities", + "save_probabilities_dict", + "save_amplitudes", + "save_amplitudes_sq", + "save_state", + "save_density_matrix", + "save_statevector", + "save_statevector_dict", + "save_stabilizer", + "set_statevector", + "set_density_matrix", + "set_stabilizer", + ] + ) _DEFAULT_CONFIGURATION = { - 'backend_name': 'qasm_simulator', - 'backend_version': __version__, - 'n_qubits': MAX_QUBITS_STATEVECTOR, - 'url': 'https://github.com/Qiskit/qiskit-aer', - 'simulator': True, - 'local': True, - 'conditional': True, - 'open_pulse': False, - 'memory': True, - 'max_shots': int(1e6), - 'description': 'A C++ QasmQobj simulator with noise', - 'coupling_map': None, - 'basis_gates': _DEFAULT_BASIS_GATES, - 'custom_instructions': _DEFAULT_CUSTOM_INSTR, - 'gates': [] + "backend_name": "qasm_simulator", + "backend_version": __version__, + "n_qubits": MAX_QUBITS_STATEVECTOR, + "url": "https://github.com/Qiskit/qiskit-aer", + "simulator": True, + "local": True, + "conditional": True, + "open_pulse": False, + "memory": True, + "max_shots": int(1e6), + "description": "A C++ QasmQobj simulator with noise", + "coupling_map": None, + "basis_gates": _DEFAULT_BASIS_GATES, + "custom_instructions": _DEFAULT_CUSTOM_INSTR, + "gates": [], } _SIMULATION_METHODS = [ - 'automatic', 'statevector', 'statevector_gpu', 'statevector_custatevec', - 'statevector_thrust', 'density_matrix', - 'density_matrix_gpu', 'density_matrix_custatevec', 'density_matrix_thrust', - 'stabilizer', 'matrix_product_state', 'extended_stabilizer' + "automatic", + "statevector", + "statevector_gpu", + "statevector_custatevec", + "statevector_thrust", + "density_matrix", + "density_matrix_gpu", + "density_matrix_custatevec", + "density_matrix_thrust", + "stabilizer", + "matrix_product_state", + "extended_stabilizer", ] _AVAILABLE_METHODS = None - _SIMULATION_DEVICES = ('CPU', 'GPU', 'Thrust') + _SIMULATION_DEVICES = ("CPU", "GPU", "Thrust") _AVAILABLE_DEVICES = None - def __init__(self, - configuration=None, - properties=None, - provider=None, - **backend_options): + def __init__( + self, configuration=None, properties=None, provider=None, **backend_options + ): - warn('The `QasmSimulator` backend will be deprecated in the' - ' future. It has been superseded by the `AerSimulator`' - ' backend.', PendingDeprecationWarning) + warn( + "The `QasmSimulator` backend will be deprecated in the" + " future. It has been superseded by the `AerSimulator`" + " backend.", + PendingDeprecationWarning, + ) self._controller = aer_controller_execute() # Update available methods for class if QasmSimulator._AVAILABLE_METHODS is None: QasmSimulator._AVAILABLE_METHODS = available_methods( - self._controller, QasmSimulator._SIMULATION_METHODS, - QasmSimulator._SIMULATION_DEVICES) + self._controller, + QasmSimulator._SIMULATION_METHODS, + QasmSimulator._SIMULATION_DEVICES, + ) # Default configuration if configuration is None: configuration = QasmBackendConfiguration.from_dict( - QasmSimulator._DEFAULT_CONFIGURATION) + QasmSimulator._DEFAULT_CONFIGURATION + ) else: configuration.open_pulse = False @@ -383,23 +465,25 @@ def __init__(self, # of noise model, method, and config gates is expensive. self._cached_basis_gates = self._DEFAULT_BASIS_GATES - super().__init__(configuration, - properties=properties, - provider=provider, - backend_options=backend_options) + super().__init__( + configuration, + properties=properties, + provider=provider, + backend_options=backend_options, + ) def __repr__(self): """String representation of an AerBackend.""" display = super().__repr__()[:-1] - pad = ' ' * (len(self.__class__.__name__) + 1) + pad = " " * (len(self.__class__.__name__) + 1) - method = getattr(self.options, 'method', None) - if method not in [None, 'automatic']: + method = getattr(self.options, "method", None) + if method not in [None, "automatic"]: display += f",\n{pad}method='{method}'" - noise_model = getattr(self.options, 'noise_model', None) + noise_model = getattr(self.options, "noise_model", None) if noise_model is not None and not noise_model.is_ideal(): - display += f',\n{pad}noise_model={repr(noise_model)})' + display += f",\n{pad}noise_model={repr(noise_model)})" display += ")" return display @@ -438,7 +522,7 @@ def _default_options(cls): # stabilizer options stabilizer_max_snapshot_probabilities=32, # extended stabilizer options - extended_stabilizer_sampling_method='resampled_metropolis', + extended_stabilizer_sampling_method="resampled_metropolis", extended_stabilizer_metropolis_mixing_time=5000, extended_stabilizer_approximation_error=0.05, extended_stabilizer_norm_estimation_samples=100, @@ -448,11 +532,12 @@ def _default_options(cls): # MPS options matrix_product_state_truncation_threshold=1e-16, matrix_product_state_max_bond_dimension=None, - mps_sample_measure_algorithm='mps_heuristic', + mps_sample_measure_algorithm="mps_heuristic", mps_log_data=False, chop_threshold=1e-8, mps_parallel_threshold=14, - mps_omp_threads=1) + mps_omp_threads=1, + ) @classmethod def from_backend(cls, backend, **options): @@ -471,18 +556,16 @@ def from_backend(cls, backend, **options): # Customize configuration name name = configuration.backend_name - configuration.backend_name = f'qasm_simulator({name})' + configuration.backend_name = f"qasm_simulator({name})" # Use automatic noise model if none is provided - if 'noise_model' not in options: + if "noise_model" not in options: noise_model = NoiseModel.from_backend(backend) if not noise_model.is_ideal(): - options['noise_model'] = noise_model + options["noise_model"] = noise_model # Initialize simulator - sim = cls(configuration=configuration, - properties=properties, - **options) + sim = cls(configuration=configuration, properties=properties, **options) return sim def configuration(self): @@ -521,8 +604,7 @@ def _execute_qobj(self, qobj): return cpp_execute_qobj(self._controller, qobj) def _execute_circuits(self, aer_circuits, noise_model, config): - """Execute circuits on the backend. - """ + """Execute circuits on the backend.""" config = map_legacy_method_config(config) return cpp_execute_circuits(self._controller, aer_circuits, noise_model, config) @@ -534,10 +616,11 @@ def set_option(self, key, value): if value in LEGACY_METHOD_MAP: value, device = LEGACY_METHOD_MAP[value] self.set_option("device", device) - if (value is not None and value not in self.available_methods()): + if value is not None and value not in self.available_methods(): raise AerError( f"Invalid simulation method {value}. Available methods" - f" are: {self.available_methods()}") + f" are: {self.available_methods()}" + ) self._set_method_config(value) super().set_option(key, value) if key in ["method", "noise_model", "basis_gates"]: @@ -563,8 +646,9 @@ def _validate(self, qobj): if no_measure: logger.warning( 'No measurements in circuit "%s": ' - 'count data will return all zeros.', - experiment.header.name) + "count data will return all zeros.", + experiment.header.name, + ) def _basis_gates(self): """Return simualtor basis gates. @@ -574,20 +658,19 @@ def _basis_gates(self): and method supported basis gates. """ # Use option value for basis gates if set - if 'basis_gates' in self._options_configuration: - return self._options_configuration['basis_gates'] + if "basis_gates" in self._options_configuration: + return self._options_configuration["basis_gates"] # Compute intersection with method basis gates method_gates = self._method_basis_gates() config_gates = self._configuration.basis_gates if config_gates: - basis_gates = set(config_gates).intersection( - method_gates) + basis_gates = set(config_gates).intersection(method_gates) else: basis_gates = method_gates # Compute intersection with noise model basis gates - noise_model = getattr(self.options, 'noise_model', None) + noise_model = getattr(self.options, "noise_model", None) if noise_model: noise_gates = noise_model.basis_gates basis_gates = basis_gates.intersection(noise_gates) @@ -599,106 +682,281 @@ def _basis_gates(self): "The intersection of configuration basis gates (%s), " "simulation method basis gates (%s), and " "noise model basis gates (%s) is empty", - config_gates, method_gates, noise_gates) + config_gates, + method_gates, + noise_gates, + ) return sorted(basis_gates) def _method_basis_gates(self): """Return method basis gates and custom instructions""" - method = self._options.get('method', None) - if method in ['density_matrix', 'density_matrix_gpu', - 'density_matrix_custatevec', 'density_matrix_thrust']: - return sorted([ - 'u1', 'u2', 'u3', 'u', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', - 'y', 'z', 'h', 's', 'sdg', 'sx', 'sxdg', 't', 'tdg', 'swap', 'cx', - 'cy', 'cz', 'cp', 'cu1', 'rxx', 'ryy', 'rzz', 'rzx', 'ccx', - 'unitary', 'diagonal', 'delay', 'pauli', 'ecr' - ]) - if method == 'matrix_product_state': - return sorted([ - 'u1', 'u2', 'u3', 'u', 'p', 'cp', 'cx', 'cy', 'cz', 'id', 'x', - 'y', 'z', 'h', 's', 'sdg', 'sx', 'sxdg', 't', 'tdg', 'swap', 'ccx', - 'unitary', 'roerror', 'delay', 'pauli', 'r', 'rx', 'ry', 'rz', 'rxx', - 'ryy', 'rzz', 'rzx', 'csx', 'cswap', 'diagonal', 'initialize' - ]) - if method == 'stabilizer': - return sorted([ - 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'sx', 'sxdg', 'cx', 'cy', 'cz', - 'swap', 'delay', 'pauli' - ]) - if method == 'extended_stabilizer': - return sorted([ - 'cx', 'cz', 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'sx', 'sxdg', - 'swap', 'u0', 't', 'tdg', 'u1', 'p', 'ccx', 'ccz', 'delay', 'pauli' - ]) + method = self._options.get("method", None) + if method in [ + "density_matrix", + "density_matrix_gpu", + "density_matrix_custatevec", + "density_matrix_thrust", + ]: + return sorted( + [ + "u1", + "u2", + "u3", + "u", + "p", + "r", + "rx", + "ry", + "rz", + "id", + "x", + "y", + "z", + "h", + "s", + "sdg", + "sx", + "sxdg", + "t", + "tdg", + "swap", + "cx", + "cy", + "cz", + "cp", + "cu1", + "rxx", + "ryy", + "rzz", + "rzx", + "ccx", + "unitary", + "diagonal", + "delay", + "pauli", + "ecr", + ] + ) + if method == "matrix_product_state": + return sorted( + [ + "u1", + "u2", + "u3", + "u", + "p", + "cp", + "cx", + "cy", + "cz", + "id", + "x", + "y", + "z", + "h", + "s", + "sdg", + "sx", + "sxdg", + "t", + "tdg", + "swap", + "ccx", + "unitary", + "roerror", + "delay", + "pauli", + "r", + "rx", + "ry", + "rz", + "rxx", + "ryy", + "rzz", + "rzx", + "csx", + "cswap", + "diagonal", + "initialize", + ] + ) + if method == "stabilizer": + return sorted( + [ + "id", + "x", + "y", + "z", + "h", + "s", + "sdg", + "sx", + "sxdg", + "cx", + "cy", + "cz", + "swap", + "delay", + "pauli", + ] + ) + if method == "extended_stabilizer": + return sorted( + [ + "cx", + "cz", + "id", + "x", + "y", + "z", + "h", + "s", + "sdg", + "sx", + "sxdg", + "swap", + "u0", + "t", + "tdg", + "u1", + "p", + "ccx", + "ccz", + "delay", + "pauli", + ] + ) return QasmSimulator._DEFAULT_BASIS_GATES def _custom_instructions(self): """Return method basis gates and custom instructions""" # pylint: disable = too-many-return-statements - if 'custom_instructions' in self._options_configuration: - return self._options_configuration['custom_instructions'] - - method = self._options.get('method', None) - if method in ['statevector', 'statevector_gpu', - 'statevector_custatevec', 'statevector_thrust']: - return sorted([ - 'quantum_channel', 'qerror_loc', 'roerror', 'kraus', 'save_expval', - 'save_expval_var', 'save_probabilities', 'save_probabilities_dict', - 'save_amplitudes', 'save_amplitudes_sq', 'save_state', - 'save_density_matrix', 'save_statevector', 'save_statevector_dict', - 'set_statevector' - ]) - if method in ['density_matrix', 'density_matrix_gpu', - 'density_matrix_custatevec', 'density_matrix_thrust']: - return sorted([ - 'quantum_channel', 'qerror_loc', 'roerror', 'kraus', 'superop', - 'save_expval', 'save_expval_var', 'save_probabilities', 'save_probabilities_dict', - 'save_state', 'save_density_matrix', 'save_amplitudes_sq', - 'set_statevector', 'set_density_matrix' - ]) - if method == 'matrix_product_state': - return sorted([ - 'quantum_channel', 'qerror_loc', 'roerror', 'kraus', 'save_expval', - 'save_expval_var', 'save_probabilities', 'save_probabilities_dict', - 'save_density_matrix', 'save_state', 'save_statevector', - 'save_amplitudes', 'save_amplitudes_sq', 'save_matrix_product_state', - 'set_matrix_product_state']) - if method == 'stabilizer': - return sorted([ - 'quantum_channel', 'qerror_loc', 'roerror', 'save_expval', - 'save_expval_var', 'save_probabilities', 'save_probabilities_dict', - 'save_amplitudes_sq', 'save_state', 'save_stabilizer', - 'set_stabilizer' - ]) - if method == 'extended_stabilizer': - return sorted([ - 'quantum_channel', 'qerror_loc', 'roerror', - 'save_statevector']) + if "custom_instructions" in self._options_configuration: + return self._options_configuration["custom_instructions"] + + method = self._options.get("method", None) + if method in [ + "statevector", + "statevector_gpu", + "statevector_custatevec", + "statevector_thrust", + ]: + return sorted( + [ + "quantum_channel", + "qerror_loc", + "roerror", + "kraus", + "save_expval", + "save_expval_var", + "save_probabilities", + "save_probabilities_dict", + "save_amplitudes", + "save_amplitudes_sq", + "save_state", + "save_density_matrix", + "save_statevector", + "save_statevector_dict", + "set_statevector", + ] + ) + if method in [ + "density_matrix", + "density_matrix_gpu", + "density_matrix_custatevec", + "density_matrix_thrust", + ]: + return sorted( + [ + "quantum_channel", + "qerror_loc", + "roerror", + "kraus", + "superop", + "save_expval", + "save_expval_var", + "save_probabilities", + "save_probabilities_dict", + "save_state", + "save_density_matrix", + "save_amplitudes_sq", + "set_statevector", + "set_density_matrix", + ] + ) + if method == "matrix_product_state": + return sorted( + [ + "quantum_channel", + "qerror_loc", + "roerror", + "kraus", + "save_expval", + "save_expval_var", + "save_probabilities", + "save_probabilities_dict", + "save_density_matrix", + "save_state", + "save_statevector", + "save_amplitudes", + "save_amplitudes_sq", + "save_matrix_product_state", + "set_matrix_product_state", + ] + ) + if method == "stabilizer": + return sorted( + [ + "quantum_channel", + "qerror_loc", + "roerror", + "save_expval", + "save_expval_var", + "save_probabilities", + "save_probabilities_dict", + "save_amplitudes_sq", + "save_state", + "save_stabilizer", + "set_stabilizer", + ] + ) + if method == "extended_stabilizer": + return sorted( + ["quantum_channel", "qerror_loc", "roerror", "save_statevector"] + ) return QasmSimulator._DEFAULT_CUSTOM_INSTR def _set_method_config(self, method=None): """Set non-basis gate options when setting method""" # Update configuration description and number of qubits - if method in ['statevector', 'statevector_gpu', - 'statevector_custatevec', 'statevector_thrust']: - description = 'A C++ statevector simulator with noise' + if method in [ + "statevector", + "statevector_gpu", + "statevector_custatevec", + "statevector_thrust", + ]: + description = "A C++ statevector simulator with noise" n_qubits = MAX_QUBITS_STATEVECTOR - elif method in ['density_matrix', 'density_matrix_gpu', - 'density_matrix_custatevec', 'density_matrix_thrust']: - description = 'A C++ density matrix simulator with noise' + elif method in [ + "density_matrix", + "density_matrix_gpu", + "density_matrix_custatevec", + "density_matrix_thrust", + ]: + description = "A C++ density matrix simulator with noise" n_qubits = MAX_QUBITS_STATEVECTOR // 2 - elif method == 'matrix_product_state': - description = 'A C++ matrix product state simulator with noise' + elif method == "matrix_product_state": + description = "A C++ matrix product state simulator with noise" n_qubits = 63 # TODO: not sure what to put here? - elif method == 'stabilizer': - description = 'A C++ Clifford stabilizer simulator with noise' + elif method == "stabilizer": + description = "A C++ Clifford stabilizer simulator with noise" n_qubits = 10000 # TODO: estimate from memory - elif method == 'extended_stabilizer': - description = 'A C++ Clifford+T extended stabilizer simulator with noise' + elif method == "extended_stabilizer": + description = "A C++ Clifford+T extended stabilizer simulator with noise" n_qubits = 63 # TODO: estimate from memory else: # Clear options to default description = None n_qubits = None - self._set_configuration_option('description', description) - self._set_configuration_option('n_qubits', n_qubits) + self._set_configuration_option("description", description) + self._set_configuration_option("n_qubits", n_qubits) diff --git a/qiskit_aer/backends/statevector_simulator.py b/qiskit_aer/backends/statevector_simulator.py index 93564bb723..0c3c524100 100644 --- a/qiskit_aer/backends/statevector_simulator.py +++ b/qiskit_aer/backends/statevector_simulator.py @@ -23,15 +23,18 @@ from ..aererror import AerError from ..version import __version__ from .aerbackend import AerBackend -from .backend_utils import (cpp_execute_qobj, available_devices, - MAX_QUBITS_STATEVECTOR, - LEGACY_METHOD_MAP, - add_final_save_instruction, - cpp_execute_circuits, - map_legacy_method_options, - map_legacy_method_config, - add_final_save_op, - ) +from .backend_utils import ( + cpp_execute_qobj, + available_devices, + MAX_QUBITS_STATEVECTOR, + LEGACY_METHOD_MAP, + add_final_save_instruction, + cpp_execute_circuits, + map_legacy_method_options, + map_legacy_method_config, + add_final_save_op, +) + # pylint: disable=import-error, no-name-in-module from .controller_wrappers import aer_controller_execute @@ -135,65 +138,131 @@ class StatevectorSimulator(AerBackend): """ _DEFAULT_CONFIGURATION = { - 'backend_name': 'statevector_simulator', - 'backend_version': __version__, - 'n_qubits': MAX_QUBITS_STATEVECTOR, - 'url': 'https://github.com/Qiskit/qiskit-aer', - 'simulator': True, - 'local': True, - 'conditional': True, - 'open_pulse': False, - 'memory': True, - 'max_shots': int(1e6), # Note that this backend will only ever + "backend_name": "statevector_simulator", + "backend_version": __version__, + "n_qubits": MAX_QUBITS_STATEVECTOR, + "url": "https://github.com/Qiskit/qiskit-aer", + "simulator": True, + "local": True, + "conditional": True, + "open_pulse": False, + "memory": True, + "max_shots": int(1e6), # Note that this backend will only ever # perform a single shot. This value is just # so that the default shot value for execute # will not raise an error when trying to run # a simulation - 'description': 'A C++ statevector circuit simulator', - 'coupling_map': None, - 'basis_gates': sorted([ - 'u1', 'u2', 'u3', 'u', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', - 'y', 'z', 'h', 's', 'sdg', 'sx', 'sxdg', 't', 'tdg', 'swap', 'cx', - 'cy', 'cz', 'csx', 'cu', 'cp', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', - 'rzz', 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', - 'mcu', 'mcp', 'mcphase', 'mcu1', 'mcu2', 'mcu3', 'mcrx', 'mcry', 'mcrz', - 'mcr', 'mcswap', 'unitary', 'diagonal', 'multiplexer', - 'initialize', 'delay', 'pauli' - ]), - 'custom_instructions': sorted([ - 'kraus', 'roerror', 'quantum_channel', 'qerror_loc', - 'save_expval', 'save_density_matrix', 'save_statevector', - 'save_probs', 'save_probs_ket', 'save_amplitudes', - 'save_amplitudes_sq', 'save_state', 'set_statevector' - ]), - 'gates': [] + "description": "A C++ statevector circuit simulator", + "coupling_map": None, + "basis_gates": sorted( + [ + "u1", + "u2", + "u3", + "u", + "p", + "r", + "rx", + "ry", + "rz", + "id", + "x", + "y", + "z", + "h", + "s", + "sdg", + "sx", + "sxdg", + "t", + "tdg", + "swap", + "cx", + "cy", + "cz", + "csx", + "cu", + "cp", + "cu1", + "cu2", + "cu3", + "rxx", + "ryy", + "rzz", + "rzx", + "ccx", + "cswap", + "mcx", + "mcy", + "mcz", + "mcsx", + "mcu", + "mcp", + "mcphase", + "mcu1", + "mcu2", + "mcu3", + "mcrx", + "mcry", + "mcrz", + "mcr", + "mcswap", + "unitary", + "diagonal", + "multiplexer", + "initialize", + "delay", + "pauli", + ] + ), + "custom_instructions": sorted( + [ + "kraus", + "roerror", + "quantum_channel", + "qerror_loc", + "save_expval", + "save_density_matrix", + "save_statevector", + "save_probs", + "save_probs_ket", + "save_amplitudes", + "save_amplitudes_sq", + "save_state", + "set_statevector", + ] + ), + "gates": [], } - _SIMULATION_DEVICES = ('CPU', 'GPU', 'Thrust') + _SIMULATION_DEVICES = ("CPU", "GPU", "Thrust") _AVAILABLE_DEVICES = None - def __init__(self, - configuration=None, - properties=None, - provider=None, - **backend_options): + def __init__( + self, configuration=None, properties=None, provider=None, **backend_options + ): - warn('The `StatevectorSimulator` backend will be deprecated in the' - ' future. It has been superseded by the `AerSimulator`' - ' backend. To obtain legacy functionality initialize with' - ' `AerSimulator(method="statevector")` and append run circuits' - ' with the `save_state` instruction.', PendingDeprecationWarning) + warn( + "The `StatevectorSimulator` backend will be deprecated in the" + " future. It has been superseded by the `AerSimulator`" + " backend. To obtain legacy functionality initialize with" + ' `AerSimulator(method="statevector")` and append run circuits' + " with the `save_state` instruction.", + PendingDeprecationWarning, + ) self._controller = aer_controller_execute() if StatevectorSimulator._AVAILABLE_DEVICES is None: StatevectorSimulator._AVAILABLE_DEVICES = available_devices( - self._controller, StatevectorSimulator._SIMULATION_DEVICES) + self._controller, StatevectorSimulator._SIMULATION_DEVICES + ) if configuration is None: configuration = QasmBackendConfiguration.from_dict( - StatevectorSimulator._DEFAULT_CONFIGURATION) + StatevectorSimulator._DEFAULT_CONFIGURATION + ) else: configuration.open_pulse = False @@ -201,7 +270,8 @@ def __init__(self, configuration, properties=properties, provider=provider, - backend_options=backend_options) + backend_options=backend_options, + ) @classmethod def _default_options(cls): @@ -225,31 +295,37 @@ def _default_options(cls): fusion_max_qubit=5, fusion_threshold=14, # statevector options - statevector_parallel_threshold=14) + statevector_parallel_threshold=14, + ) def set_option(self, key, value): if key == "method": # Handle deprecation of method option for device option - warn("The method option of the `StatevectorSimulator` has been" - " deprecated as of qiskit-aer 0.9.0. To run a GPU statevector" - " simulation use the option `device='GPU'` instead", - DeprecationWarning) + warn( + "The method option of the `StatevectorSimulator` has been" + " deprecated as of qiskit-aer 0.9.0. To run a GPU statevector" + " simulation use the option `device='GPU'` instead", + DeprecationWarning, + ) if value in LEGACY_METHOD_MAP: value, device = LEGACY_METHOD_MAP[value] self.set_option("device", device) if value != "statevector": raise AerError( - "only the 'statevector' method is supported for the StatevectorSimulator") + "only the 'statevector' method is supported for the StatevectorSimulator" + ) return super().set_option(key, value) def available_methods(self): """Return the available simulation methods.""" - warn("The `available_methods` method of the StatevectorSimulator" - " is deprecated as of qiskit-aer 0.9.0 as this simulator only" - " supports a single method. To check if GPU simulation is available" - " use the `available_devices` method instead.", - DeprecationWarning) + warn( + "The `available_methods` method of the StatevectorSimulator" + " is deprecated as of qiskit-aer 0.9.0 as this simulator only" + " supports a single method. To check if GPU simulation is available" + " use the `available_devices` method instead.", + DeprecationWarning, + ) return ("statevector",) def available_devices(self): @@ -272,8 +348,7 @@ def _execute_qobj(self, qobj): return cpp_execute_qobj(self._controller, qobj) def _execute_circuits(self, aer_circuits, noise_model, config): - """Execute circuits on the backend. - """ + """Execute circuits on the backend.""" config = map_legacy_method_config(config) aer_circuits = add_final_save_op(aer_circuits, "statevector") return cpp_execute_circuits(self._controller, aer_circuits, noise_model, config) @@ -286,15 +361,16 @@ def _validate(self, qobj): 2. Check number of qubits will fit in local memory. """ name = self.name() - if getattr(qobj.config, 'noise_model', None) is not None: + if getattr(qobj.config, "noise_model", None) is not None: raise AerError(f"{name} does not support noise.") n_qubits = qobj.config.n_qubits max_qubits = self.configuration().n_qubits if n_qubits > max_qubits: raise AerError( - f'Number of qubits ({n_qubits}) is greater than max ({max_qubits}) ' - f'for "{name}" with {int(local_hardware_info()["memory"])} GB system memory.') + f"Number of qubits ({n_qubits}) is greater than max ({max_qubits}) " + f'for "{name}" with {int(local_hardware_info()["memory"])} GB system memory.' + ) if qobj.config.shots != 1: logger.info('"%s" only supports 1 shot. Setting shots=1.', name) @@ -302,8 +378,10 @@ def _validate(self, qobj): for experiment in qobj.experiments: exp_name = experiment.header.name - if getattr(experiment.config, 'shots', 1) != 1: + if getattr(experiment.config, "shots", 1) != 1: logger.info( - '"%s" only supports 1 shot. ' - 'Setting shots=1 for circuit "%s".', name, exp_name) + '"%s" only supports 1 shot. ' 'Setting shots=1 for circuit "%s".', + name, + exp_name, + ) experiment.config.shots = 1 diff --git a/qiskit_aer/backends/unitary_simulator.py b/qiskit_aer/backends/unitary_simulator.py index 7971391f3d..77a2bba0ef 100644 --- a/qiskit_aer/backends/unitary_simulator.py +++ b/qiskit_aer/backends/unitary_simulator.py @@ -24,15 +24,18 @@ from ..aererror import AerError from ..version import __version__ from .aerbackend import AerBackend -from .backend_utils import (cpp_execute_qobj, - cpp_execute_circuits, - available_devices, - MAX_QUBITS_STATEVECTOR, - LEGACY_METHOD_MAP, - add_final_save_instruction, - map_legacy_method_options, - add_final_save_op, - map_legacy_method_config) +from .backend_utils import ( + cpp_execute_qobj, + cpp_execute_circuits, + available_devices, + MAX_QUBITS_STATEVECTOR, + LEGACY_METHOD_MAP, + add_final_save_instruction, + map_legacy_method_options, + add_final_save_op, + map_legacy_method_config, +) + # pylint: disable=import-error, no-name-in-module from .controller_wrappers import aer_controller_execute @@ -139,66 +142,123 @@ class UnitarySimulator(AerBackend): """ _DEFAULT_CONFIGURATION = { - 'backend_name': 'unitary_simulator', - 'backend_version': __version__, - 'n_qubits': MAX_QUBITS_STATEVECTOR // 2, - 'url': 'https://github.com/Qiskit/qiskit-aer', - 'simulator': True, - 'local': True, - 'conditional': False, - 'open_pulse': False, - 'memory': False, - 'max_shots': int(1e6), # Note that this backend will only ever - # perform a single shot. This value is just - # so that the default shot value for execute - # will not raise an error when trying to run - # a simulation - 'description': 'A C++ unitary circuit simulator', - 'coupling_map': None, - 'basis_gates': sorted([ - 'u1', 'u2', 'u3', 'u', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', - 'y', 'z', 'h', 's', 'sdg', 'sx', 'sxdg', 't', 'tdg', 'swap', 'cx', - 'cy', 'cz', 'csx', 'cu', 'cp', 'cu1', 'cu2', 'cu3', 'rxx', 'ryy', - 'rzz', 'rzx', 'ccx', 'cswap', 'mcx', 'mcy', 'mcz', 'mcsx', - 'mcu', 'mcp', 'mcphase', 'mcu1', 'mcu2', 'mcu3', 'mcrx', 'mcry', 'mcrz', - 'mcr', 'mcswap', 'unitary', 'diagonal', 'multiplexer', 'delay', 'pauli', - ]), - 'custom_instructions': sorted(['save_unitary', 'save_state', 'set_unitary']), - 'gates': [] + "backend_name": "unitary_simulator", + "backend_version": __version__, + "n_qubits": MAX_QUBITS_STATEVECTOR // 2, + "url": "https://github.com/Qiskit/qiskit-aer", + "simulator": True, + "local": True, + "conditional": False, + "open_pulse": False, + "memory": False, + "max_shots": int(1e6), # Note that this backend will only ever + # perform a single shot. This value is just + # so that the default shot value for execute + # will not raise an error when trying to run + # a simulation + "description": "A C++ unitary circuit simulator", + "coupling_map": None, + "basis_gates": sorted( + [ + "u1", + "u2", + "u3", + "u", + "p", + "r", + "rx", + "ry", + "rz", + "id", + "x", + "y", + "z", + "h", + "s", + "sdg", + "sx", + "sxdg", + "t", + "tdg", + "swap", + "cx", + "cy", + "cz", + "csx", + "cu", + "cp", + "cu1", + "cu2", + "cu3", + "rxx", + "ryy", + "rzz", + "rzx", + "ccx", + "cswap", + "mcx", + "mcy", + "mcz", + "mcsx", + "mcu", + "mcp", + "mcphase", + "mcu1", + "mcu2", + "mcu3", + "mcrx", + "mcry", + "mcrz", + "mcr", + "mcswap", + "unitary", + "diagonal", + "multiplexer", + "delay", + "pauli", + ] + ), + "custom_instructions": sorted(["save_unitary", "save_state", "set_unitary"]), + "gates": [], } - _SIMULATION_DEVICES = ('CPU', 'GPU', 'Thrust') + _SIMULATION_DEVICES = ("CPU", "GPU", "Thrust") _AVAILABLE_DEVICES = None - def __init__(self, - configuration=None, - properties=None, - provider=None, - **backend_options): + def __init__( + self, configuration=None, properties=None, provider=None, **backend_options + ): - warn('The `UnitarySimulator` backend will be deprecated in the' - ' future. It has been superseded by the `AerSimulator`' - ' backend. To obtain legacy functionality initialize with' - ' `AerSimulator(method="unitary")` and append run circuits' - ' with the `save_state` instruction.', PendingDeprecationWarning) + warn( + "The `UnitarySimulator` backend will be deprecated in the" + " future. It has been superseded by the `AerSimulator`" + " backend. To obtain legacy functionality initialize with" + ' `AerSimulator(method="unitary")` and append run circuits' + " with the `save_state` instruction.", + PendingDeprecationWarning, + ) self._controller = aer_controller_execute() if UnitarySimulator._AVAILABLE_DEVICES is None: UnitarySimulator._AVAILABLE_DEVICES = available_devices( - self._controller, UnitarySimulator._SIMULATION_DEVICES) + self._controller, UnitarySimulator._SIMULATION_DEVICES + ) if configuration is None: configuration = QasmBackendConfiguration.from_dict( - UnitarySimulator._DEFAULT_CONFIGURATION) + UnitarySimulator._DEFAULT_CONFIGURATION + ) else: configuration.open_pulse = False - super().__init__(configuration, - properties=properties, - provider=provider, - backend_options=backend_options) + super().__init__( + configuration, + properties=properties, + provider=provider, + backend_options=backend_options, + ) @classmethod def _default_options(cls): @@ -224,31 +284,37 @@ def _default_options(cls): blocking_qubits=None, blocking_enable=False, # statevector options - statevector_parallel_threshold=14) + statevector_parallel_threshold=14, + ) def set_option(self, key, value): if key == "method": # Handle deprecation of method option for device option - warn("The method option of the `UnitarySimulator` has been" - " deprecated as of qiskit-aer 0.9.0. To run a GPU statevector" - " simulation use the option `device='GPU'` instead", - DeprecationWarning) + warn( + "The method option of the `UnitarySimulator` has been" + " deprecated as of qiskit-aer 0.9.0. To run a GPU statevector" + " simulation use the option `device='GPU'` instead", + DeprecationWarning, + ) if value in LEGACY_METHOD_MAP: value, device = LEGACY_METHOD_MAP[value] self.set_option("device", device) if value != "unitary": raise AerError( - "only the 'unitary' method is supported for the UnitarySimulator") + "only the 'unitary' method is supported for the UnitarySimulator" + ) return super().set_option(key, value) def available_methods(self): """Return the available simulation methods.""" - warn("The `available_methods` method of the UnitarySimulator" - " is deprecated as of qiskit-aer 0.9.0 as this simulator only" - " supports a single method. To check if GPU simulation is available" - " use the `available_devices` method instead.", - DeprecationWarning) + warn( + "The `available_methods` method of the UnitarySimulator" + " is deprecated as of qiskit-aer 0.9.0 as this simulator only" + " supports a single method. To check if GPU simulation is available" + " use the `available_devices` method instead.", + DeprecationWarning, + ) return ("unitary",) def available_devices(self): @@ -271,8 +337,7 @@ def _execute_qobj(self, qobj): return cpp_execute_qobj(self._controller, qobj) def _execute_circuits(self, aer_circuits, noise_model, config): - """Execute circuits on the backend. - """ + """Execute circuits on the backend.""" config = map_legacy_method_config(config) aer_circuits = add_final_save_op(aer_circuits, "unitary") return cpp_execute_circuits(self._controller, aer_circuits, noise_model, config) @@ -285,27 +350,31 @@ def _validate(self, qobj): 3. Check number of qubits will fit in local memory. """ name = self.name() - if getattr(qobj.config, 'noise_model', None) is not None: + if getattr(qobj.config, "noise_model", None) is not None: raise AerError(f"{name} does not support noise.") n_qubits = qobj.config.n_qubits max_qubits = self.configuration().n_qubits if n_qubits > max_qubits: raise AerError( - f'Number of qubits ({n_qubits}) is greater than ' + f"Number of qubits ({n_qubits}) is greater than " f'max ({max_qubits}) for "{name}" with ' - f"{int(local_hardware_info()['memory'])} GB system memory.") + f"{int(local_hardware_info()['memory'])} GB system memory." + ) if qobj.config.shots != 1: logger.info('"%s" only supports 1 shot. Setting shots=1.', name) qobj.config.shots = 1 for experiment in qobj.experiments: exp_name = experiment.header.name - if getattr(experiment.config, 'shots', 1) != 1: + if getattr(experiment.config, "shots", 1) != 1: logger.info( - '"%s" only supports 1 shot. ' - 'Setting shots=1 for circuit "%s".', name, exp_name) + '"%s" only supports 1 shot. ' 'Setting shots=1 for circuit "%s".', + name, + exp_name, + ) experiment.config.shots = 1 for operation in experiment.instructions: - if operation.name in ['measure', 'reset']: + if operation.name in ["measure", "reset"]: raise AerError( - f'Unsupported {name} instruction {operation.name} in circuit {exp_name}') + f"Unsupported {name} instruction {operation.name} in circuit {exp_name}" + ) diff --git a/qiskit_aer/jobs/aerjob.py b/qiskit_aer/jobs/aerjob.py index 0bd0124264..da1de6d60c 100644 --- a/qiskit_aer/jobs/aerjob.py +++ b/qiskit_aer/jobs/aerjob.py @@ -27,11 +27,18 @@ class AerJob(Job): """AerJob class for Qiskit Aer Simulators.""" - def __init__(self, backend, job_id, fn, - qobj=None, - circuits=None, noise_model=None, config=None, - executor=None): - """ Initializes the asynchronous job. + def __init__( + self, + backend, + job_id, + fn, + qobj=None, + circuits=None, + noise_model=None, + config=None, + executor=None, + ): + """Initializes the asynchronous job. Args: backend(AerBackend): the backend used to run the job. @@ -65,7 +72,7 @@ def __init__(self, backend, job_id, fn, self._noise_model = noise_model self._config = config else: - raise JobError('AerJob needs a qobj or circuits') + raise JobError("AerJob needs a qobj or circuits") self._executor = executor or DEFAULT_EXECUTOR self._future = None @@ -82,8 +89,9 @@ def submit(self): if self._qobj: self._future = self._executor.submit(self._fn, self._qobj, self._job_id) else: - self._future = self._executor.submit(self._fn, self._circuits, self._noise_model, - self._config, self._job_id) + self._future = self._executor.submit( + self._fn, self._circuits, self._noise_model, self._config, self._job_id + ) @requires_submit def result(self, timeout=None): @@ -127,7 +135,9 @@ def status(self): elif self._future.cancelled(): _status = JobStatus.CANCELLED elif self._future.done(): - _status = JobStatus.DONE if self._future.exception() is None else JobStatus.ERROR + _status = ( + JobStatus.DONE if self._future.exception() is None else JobStatus.ERROR + ) else: # Note: There is an undocumented Future state: PENDING, that seems to show up when # the job is enqueued, waiting for someone to pick it up. We need to deal with this @@ -147,11 +157,13 @@ def qobj(self): Qobj: the Qobj submitted for this job. """ warnings.warn( - '`AerJob.qobj() is deprecated as of qiskit-aer 0.12.0`. ' - 'Using a qobj for `backend.run()` is deprecated as of qiskit-aer 0.9.0' - ' and will be removed no sooner than 3 months from that release' - ' date. Once it is removed, this `qobj()` returns always `None`.', - DeprecationWarning, stacklevel=2) + "`AerJob.qobj() is deprecated as of qiskit-aer 0.12.0`. " + "Using a qobj for `backend.run()` is deprecated as of qiskit-aer 0.9.0" + " and will be removed no sooner than 3 months from that release" + " date. Once it is removed, this `qobj()` returns always `None`.", + DeprecationWarning, + stacklevel=2, + ) return self._qobj def circuits(self): diff --git a/qiskit_aer/jobs/aerjobset.py b/qiskit_aer/jobs/aerjobset.py index 5b32625371..93493993b1 100644 --- a/qiskit_aer/jobs/aerjobset.py +++ b/qiskit_aer/jobs/aerjobset.py @@ -80,7 +80,8 @@ def submit(self): """ if self._futures: raise RuntimeError( - 'The jobs for this managed job set have already been submitted.') + "The jobs for this managed job set have already been submitted." + ) self._future = True worker_id = 0 @@ -99,8 +100,9 @@ def submit(self): self._combined_result.append(_worker_id_list) @requires_submit - def status(self, worker: Union[None, int, Iterable[int]] - ) -> Union[JobStatus, List[JobStatus]]: + def status( + self, worker: Union[None, int, Iterable[int]] + ) -> Union[JobStatus, List[JobStatus]]: """Return the status of each job in this set. Args @@ -122,9 +124,10 @@ def status(self, worker: Union[None, int, Iterable[int]] return [aer.status() for aer in self._futures] @requires_submit - def result(self, - timeout: Optional[float] = None, - ) -> Result: + def result( + self, + timeout: Optional[float] = None, + ) -> Result: """Return the results of the jobs as a single Result object. This call will block until all job results become available or @@ -145,10 +148,11 @@ def result(self, return res @requires_submit - def worker_results(self, - worker: Union[None, int, Iterable[int]], - timeout: Optional[float] = None, - ) -> Union[Result, List[Result]]: + def worker_results( + self, + worker: Union[None, int, Iterable[int]], + timeout: Optional[float] = None, + ) -> Union[Result, List[Result]]: """Return the result of the jobs specified with worker_id. When the worker is None, this call return all worker's result. @@ -216,19 +220,24 @@ def _get_worker_result(self, worker: int, timeout: Optional[float] = None): result = aer_job.result(timeout=timeout) if result is None or not result.success: if result: - logger.warning('AerJobSet %s Error: %s', aer_job.name(), result.header) + logger.warning( + "AerJobSet %s Error: %s", aer_job.name(), result.header + ) else: - logger.warning('AerJobSet %s did not return a result', aer_job.name()) + logger.warning( + "AerJobSet %s did not return a result", aer_job.name() + ) except JobError: raise JobError( - 'Timeout while waiting for the results of experiment {}'.format( - aer_job.name())) + "Timeout while waiting for the results of experiment {}".format( + aer_job.name() + ) + ) if timeout: timeout = original_timeout - (time.time() - start_time) if timeout <= 0: - raise JobError( - "Timeout while waiting for JobSet results") + raise JobError("Timeout while waiting for JobSet results") return result def _combine_job_results(self, result_list: List[Result]): @@ -239,7 +248,9 @@ def _combine_job_results(self, result_list: List[Result]): _merge_result_list = [] for _result in result_list[1:]: - for (_master_result, _sub_result) in zip(master_result.results, _result.results): + for (_master_result, _sub_result) in zip( + master_result.results, _result.results + ): _merge_result_list.append(self._merge_exp(_master_result, _sub_result)) master_result.results = _merge_result_list return master_result @@ -267,9 +278,10 @@ def _accumulate_experiment_results(self, results: List[Result]): master_result = None for _result in each_result.results: - if not hasattr(_result.data, "counts") and not hasattr(_result.data, "memory"): - raise JobError( - "Results do not include counts or memory data") + if not hasattr(_result.data, "counts") and not hasattr( + _result.data, "memory" + ): + raise JobError("Results do not include counts or memory data") meta_data = getattr(_result.header, "metadata", None) if meta_data and "id" in meta_data: _id = meta_data["id"] @@ -295,9 +307,7 @@ def _merge_exp(self, master: Result, sub: Result): return master - def _combine_results(self, - results: List[Union[Result, None]] = None - ) -> Result: + def _combine_results(self, results: List[Union[Result, None]] = None) -> Result: """Combine results from all jobs into a single `Result`. Note: @@ -313,8 +323,7 @@ def _combine_results(self, JobError: If results cannot be combined because some jobs failed. """ if not results: - raise JobError( - "Results cannot be combined - no results.") + raise JobError("Results cannot be combined - no results.") # find first non-null result and copy it's config _result = next((r for r in results if r is not None), None) @@ -334,12 +343,13 @@ def _combine_results(self, combined_result["header"] = _result.header.to_dict() combined_result.update(_result._metadata) else: - raise JobError( - "Results cannot be combined - no results.") + raise JobError("Results cannot be combined - no results.") for each_result in results: if each_result is not None: - combined_result["results"].extend(x.to_dict() for x in each_result.results) + combined_result["results"].extend( + x.to_dict() for x in each_result.results + ) if self._end_time is None: self._end_time = datetime.datetime.now() @@ -360,7 +370,9 @@ def cancel(self) -> None: aer_job.cancel() @requires_submit - def job(self, experiment: Union[str, QuantumCircuit, Schedule]) -> Tuple[AerJob, int]: + def job( + self, experiment: Union[str, QuantumCircuit, Schedule] + ) -> Tuple[AerJob, int]: """Retrieve the job used to submit the specified experiment and its index. Args: @@ -381,9 +393,9 @@ def job(self, experiment: Union[str, QuantumCircuit, Schedule]) -> Tuple[AerJob, return self.worker_job(worker_index) @requires_submit - def worker(self, - experiment: Union[str, QuantumCircuit, Schedule] - ) -> Union[int, List[int]]: + def worker( + self, experiment: Union[str, QuantumCircuit, Schedule] + ) -> Union[int, List[int]]: """Retrieve the index of job. Args: @@ -406,7 +418,7 @@ def worker(self, job_list = [] for job in self._futures: for i, exp in enumerate(job.qobj().experiments): - if hasattr(exp.header, 'name') and exp.header.name == experiment: + if hasattr(exp.header, "name") and exp.header.name == experiment: job_list.append(i) if len(job_list) == 1: @@ -414,13 +426,12 @@ def worker(self, elif len(job_list) > 1: return job_list - raise JobError( - 'Unable to find the job for experiment {}.'.format(experiment)) + raise JobError("Unable to find the job for experiment {}.".format(experiment)) @requires_submit - def worker_job(self, - worker: Union[None, int, Iterable[int]] - ) -> Union[AerJob, List[AerJob]]: + def worker_job( + self, worker: Union[None, int, Iterable[int]] + ) -> Union[AerJob, List[AerJob]]: """Retrieve the job specified with job's id Args: diff --git a/qiskit_aer/jobs/utils.py b/qiskit_aer/jobs/utils.py index b778496a54..3c9fd0915a 100644 --- a/qiskit_aer/jobs/utils.py +++ b/qiskit_aer/jobs/utils.py @@ -34,11 +34,13 @@ def requires_submit(func): Returns: callable: the decorated function. """ + @wraps(func) def _wrapper(self, *args, **kwargs): if self._future is None: raise JobError("Job not submitted yet!. You have to .submit() first!") return func(self, *args, **kwargs) + return _wrapper @@ -51,6 +53,7 @@ def methdispatch(func): def wrapper(*args, **kw): return dispatcher.dispatch(args[2].__class__)(*args, **kw) + wrapper.register = dispatcher.register update_wrapper(wrapper, func) return wrapper @@ -99,7 +102,7 @@ def _split_qobj(qobj, max_size, qobj_id, seed): qobjs = [] # Check for parameterizations - params = getattr(qobj.config, 'parameterizations', None) + params = getattr(qobj.config, "parameterizations", None) for i in range(num_jobs): sub_id = qobj_id or str(uuid.uuid4()) @@ -125,16 +128,10 @@ def _check_custom_instruction(experiments, optypes=None): # Check via optype list if available if optypes is not None: # Optypes store class names as strings - return any( - {"SaveData"}.intersection(optype) - for optype in optypes - ) + return any({"SaveData"}.intersection(optype) for optype in optypes) # Otherwise iterate over instruction names - return any( - "save_" in inst.name - for exp in experiments for inst in exp.instructions - ) + return any("save_" in inst.name for exp in experiments for inst in exp.instructions) def _set_seed(qobj_list, seed): @@ -169,19 +166,22 @@ def split_qobj(qobj, max_size=None, max_shot_size=None, qobj_id=None): Returns: List: A list of qobjs. """ - optypes = getattr(qobj.config, 'optypes', None) + optypes = getattr(qobj.config, "optypes", None) split_qobj_list = [] - if (max_shot_size is not None and max_shot_size > 0): + if max_shot_size is not None and max_shot_size > 0: if _check_custom_instruction(qobj.experiments, optypes): raise JobError( "`max_shot_size` option cannot be used with circuits" - " containing save instructions.") + " containing save instructions." + ) _seed = getattr(qobj.config, "seed_simulator", 0) if hasattr(qobj.config, "noise_model"): if _seed and max_size is not None and max_size > 1: - raise JobError("cannot support max_job_size > 1 for noise simulation, " - "when seed_simulator is set.") + raise JobError( + "cannot support max_job_size > 1 for noise simulation, " + "when seed_simulator is set." + ) if max_shot_size is not None and max_shot_size > 0: _qobj = _copy_qobj_for_noise(qobj, max_shot_size, qobj_id) diff --git a/qiskit_aer/library/__init__.py b/qiskit_aer/library/__init__.py index da05a836aa..965099e41c 100644 --- a/qiskit_aer/library/__init__.py +++ b/qiskit_aer/library/__init__.py @@ -177,27 +177,27 @@ """ __all__ = [ - 'SaveAmplitudes', - 'SaveAmplitudesSquared', - 'SaveClifford', - 'SaveDensityMatrix', - 'SaveExpectationValue', - 'SaveExpectationValueVariance', - 'SaveMatrixProductState', - 'SaveProbabilities', - 'SaveProbabilitiesDict', - 'SaveStabilizer', - 'SaveState', - 'SaveStatevector', - 'SaveStatevectorDict', - 'SaveSuperOp', - 'SaveUnitary', - 'SetDensityMatrix', - 'SetStabilizer', - 'SetStatevector', - 'SetSuperOp', - 'SetUnitary', - 'SetMatrixProductState' + "SaveAmplitudes", + "SaveAmplitudesSquared", + "SaveClifford", + "SaveDensityMatrix", + "SaveExpectationValue", + "SaveExpectationValueVariance", + "SaveMatrixProductState", + "SaveProbabilities", + "SaveProbabilitiesDict", + "SaveStabilizer", + "SaveState", + "SaveStatevector", + "SaveStatevectorDict", + "SaveSuperOp", + "SaveUnitary", + "SetDensityMatrix", + "SetStabilizer", + "SetStatevector", + "SetSuperOp", + "SetUnitary", + "SetMatrixProductState", ] from .save_instructions import * diff --git a/qiskit_aer/library/default_qubits.py b/qiskit_aer/library/default_qubits.py index 2e81fdc5a3..df251d158d 100644 --- a/qiskit_aer/library/default_qubits.py +++ b/qiskit_aer/library/default_qubits.py @@ -43,7 +43,7 @@ def default_qubits(circuit, qubits=None): for register in circuit.qregs: tuples.append(register) if not tuples: - raise ExtensionError('no qubits for snapshot') + raise ExtensionError("no qubits for snapshot") qubits = [] for tuple_element in tuples: if isinstance(tuple_element, QuantumRegister): diff --git a/qiskit_aer/library/save_instructions/__init__.py b/qiskit_aer/library/save_instructions/__init__.py index 1c5b990676..cb18acd870 100644 --- a/qiskit_aer/library/save_instructions/__init__.py +++ b/qiskit_aer/library/save_instructions/__init__.py @@ -11,22 +11,34 @@ # that they have been altered from the originals. """Save directive instructions for the Aer simulator""" -from .save_state import (SaveState, save_state) -from .save_expectation_value import (SaveExpectationValue, - save_expectation_value, - SaveExpectationValueVariance, - save_expectation_value_variance) -from .save_probabilities import (SaveProbabilities, save_probabilities, - SaveProbabilitiesDict, - save_probabilities_dict) -from .save_statevector import (SaveStatevector, save_statevector, - SaveStatevectorDict, save_statevector_dict) +from .save_state import SaveState, save_state +from .save_expectation_value import ( + SaveExpectationValue, + save_expectation_value, + SaveExpectationValueVariance, + save_expectation_value_variance, +) +from .save_probabilities import ( + SaveProbabilities, + save_probabilities, + SaveProbabilitiesDict, + save_probabilities_dict, +) +from .save_statevector import ( + SaveStatevector, + save_statevector, + SaveStatevectorDict, + save_statevector_dict, +) from .save_density_matrix import SaveDensityMatrix, save_density_matrix -from .save_amplitudes import (SaveAmplitudes, save_amplitudes, - SaveAmplitudesSquared, save_amplitudes_squared) -from .save_stabilizer import (SaveStabilizer, save_stabilizer) -from .save_clifford import (SaveClifford, save_clifford) -from .save_unitary import (SaveUnitary, save_unitary) -from .save_matrix_product_state import ( - SaveMatrixProductState, save_matrix_product_state) -from .save_superop import (SaveSuperOp, save_superop) +from .save_amplitudes import ( + SaveAmplitudes, + save_amplitudes, + SaveAmplitudesSquared, + save_amplitudes_squared, +) +from .save_stabilizer import SaveStabilizer, save_stabilizer +from .save_clifford import SaveClifford, save_clifford +from .save_unitary import SaveUnitary, save_unitary +from .save_matrix_product_state import SaveMatrixProductState, save_matrix_product_state +from .save_superop import SaveSuperOp, save_superop diff --git a/qiskit_aer/library/save_instructions/save_amplitudes.py b/qiskit_aer/library/save_instructions/save_amplitudes.py index 4daa0d3488..392a6ec277 100644 --- a/qiskit_aer/library/save_instructions/save_amplitudes.py +++ b/qiskit_aer/library/save_instructions/save_amplitudes.py @@ -21,12 +21,10 @@ class SaveAmplitudes(SaveSingleData): """Save complex statevector amplitudes.""" - def __init__(self, - num_qubits, - params, - label="amplitudes", - pershot=False, - conditional=False): + + def __init__( + self, num_qubits, params, label="amplitudes", pershot=False, conditional=False + ): """Instruction to save complex statevector amplitudes. Args: @@ -44,21 +42,28 @@ def __init__(self, ExtensionError: if params is invalid for the specified number of qubits. """ params = _format_amplitude_params(params, num_qubits) - super().__init__("save_amplitudes", num_qubits, label, - pershot=pershot, - conditional=conditional, - params=params) + super().__init__( + "save_amplitudes", + num_qubits, + label, + pershot=pershot, + conditional=conditional, + params=params, + ) class SaveAmplitudesSquared(SaveAverageData): """Save squared statevector amplitudes (probabilities).""" - def __init__(self, - num_qubits, - params, - label="amplitudes_squared", - unnormalized=False, - pershot=False, - conditional=False): + + def __init__( + self, + num_qubits, + params, + label="amplitudes_squared", + unnormalized=False, + pershot=False, + conditional=False, + ): """Instruction to save squared statevector amplitudes (probabilities). Args: @@ -78,13 +83,15 @@ def __init__(self, ExtensionError: if params is invalid for the specified number of qubits. """ params = _format_amplitude_params(params, num_qubits) - super().__init__("save_amplitudes_sq", - num_qubits, - label, - unnormalized=unnormalized, - pershot=pershot, - conditional=conditional, - params=params) + super().__init__( + "save_amplitudes_sq", + num_qubits, + label, + unnormalized=unnormalized, + pershot=pershot, + conditional=conditional, + params=params, + ) def save_amplitudes(self, params, label="amplitudes", pershot=False, conditional=False): @@ -107,15 +114,20 @@ def save_amplitudes(self, params, label="amplitudes", pershot=False, conditional ExtensionError: if params is invalid for the specified number of qubits. """ qubits = default_qubits(self) - instr = SaveAmplitudes(len(qubits), params, label=label, - pershot=pershot, conditional=conditional) + instr = SaveAmplitudes( + len(qubits), params, label=label, pershot=pershot, conditional=conditional + ) return self.append(instr, qubits) -def save_amplitudes_squared(self, params, label="amplitudes_squared", - unnormalized=False, - pershot=False, - conditional=False): +def save_amplitudes_squared( + self, + params, + label="amplitudes_squared", + unnormalized=False, + pershot=False, + conditional=False, +): """Save squared statevector amplitudes (probabilities). Args: @@ -137,23 +149,28 @@ def save_amplitudes_squared(self, params, label="amplitudes_squared", ExtensionError: if params is invalid for the specified number of qubits. """ qubits = default_qubits(self) - instr = SaveAmplitudesSquared(len(qubits), params, label=label, - unnormalized=unnormalized, - pershot=pershot, - conditional=conditional) + instr = SaveAmplitudesSquared( + len(qubits), + params, + label=label, + unnormalized=unnormalized, + pershot=pershot, + conditional=conditional, + ) return self.append(instr, qubits) def _format_amplitude_params(params, num_qubits=None): """Format amplitude params as a interger list.""" if isinstance(params[0], str): - if params[0].find('0x') == 0: + if params[0].find("0x") == 0: params = [int(i, 16) for i in params] else: params = [int(i, 2) for i in params] - if num_qubits and max(params) >= 2 ** num_qubits: + if num_qubits and max(params) >= 2**num_qubits: raise ExtensionError( - "Param values contain a state larger than the number of qubits") + "Param values contain a state larger than the number of qubits" + ) return params diff --git a/qiskit_aer/library/save_instructions/save_clifford.py b/qiskit_aer/library/save_instructions/save_clifford.py index 866d1954d5..9088d1e9c2 100644 --- a/qiskit_aer/library/save_instructions/save_clifford.py +++ b/qiskit_aer/library/save_instructions/save_clifford.py @@ -20,6 +20,7 @@ class SaveClifford(SaveSingleData): """Save Clifford instruction""" + def __init__(self, num_qubits, label="clifford", pershot=False): """Create new instruction to save the stabilizer simulator state as a Clifford. @@ -36,7 +37,7 @@ def __init__(self, num_qubits, label="clifford", pershot=False): qubits in a circuit, otherwise an exception will be raised during simulation. """ - super().__init__('save_clifford', num_qubits, label, pershot=pershot) + super().__init__("save_clifford", num_qubits, label, pershot=pershot) def save_clifford(self, label="clifford", pershot=False): diff --git a/qiskit_aer/library/save_instructions/save_data.py b/qiskit_aer/library/save_instructions/save_data.py index c3803ff152..fc3e839e81 100644 --- a/qiskit_aer/library/save_instructions/save_data.py +++ b/qiskit_aer/library/save_instructions/save_data.py @@ -23,12 +23,20 @@ class SaveData(Instruction): """Pragma Instruction to save simulator data.""" _directive = True - _allowed_subtypes = set([ - 'single', 'c_single', 'list', 'c_list', - 'average', 'c_average', 'accum', 'c_accum' - ]) - - def __init__(self, name, num_qubits, label, subtype='single', params=None): + _allowed_subtypes = set( + [ + "single", + "c_single", + "list", + "c_list", + "average", + "c_average", + "accum", + "c_accum", + ] + ) + + def __init__(self, name, num_qubits, label, subtype="single", params=None): """Create new save data instruction. Args: @@ -47,12 +55,12 @@ def __init__(self, name, num_qubits, label, subtype='single', params=None): 'c_average', 'accum', 'c_accum'. """ if subtype not in self._allowed_subtypes: - raise ExtensionError( - "Invalid data subtype for SaveData instruction.") + raise ExtensionError("Invalid data subtype for SaveData instruction.") if not isinstance(label, str): raise ExtensionError( - f"Invalid label for save data instruction, {label} must be a string.") + f"Invalid label for save data instruction, {label} must be a string." + ) if params is None: params = {} @@ -78,14 +86,17 @@ def inverse(self): class SaveAverageData(SaveData): """Save averageble data""" - def __init__(self, - name, - num_qubits, - label, - unnormalized=False, - pershot=False, - conditional=False, - params=None): + + def __init__( + self, + name, + num_qubits, + label, + unnormalized=False, + pershot=False, + conditional=False, + params=None, + ): """Create new save data instruction. Args: @@ -105,26 +116,22 @@ def __init__(self, [Default: None]. """ if pershot: - subtype = 'list' + subtype = "list" elif unnormalized: - subtype = 'accum' + subtype = "accum" else: - subtype = 'average' + subtype = "average" if conditional: - subtype = 'c_' + subtype + subtype = "c_" + subtype super().__init__(name, num_qubits, label, subtype=subtype, params=params) class SaveSingleData(SaveData): """Save non-averagable single data type.""" - def __init__(self, - name, - num_qubits, - label, - pershot=False, - conditional=False, - params=None): + def __init__( + self, name, num_qubits, label, pershot=False, conditional=False, params=None + ): """Create new save data instruction. Args: @@ -139,7 +146,7 @@ def __init__(self, params (list or None): Optional, the parameters for instruction [Default: None]. """ - subtype = 'list' if pershot else 'single' + subtype = "list" if pershot else "single" if conditional: - subtype = 'c_' + subtype + subtype = "c_" + subtype super().__init__(name, num_qubits, label, subtype=subtype, params=params) diff --git a/qiskit_aer/library/save_instructions/save_density_matrix.py b/qiskit_aer/library/save_instructions/save_density_matrix.py index 289c050788..219562d355 100644 --- a/qiskit_aer/library/save_instructions/save_density_matrix.py +++ b/qiskit_aer/library/save_instructions/save_density_matrix.py @@ -20,12 +20,15 @@ class SaveDensityMatrix(SaveAverageData): """Save a reduced density matrix.""" - def __init__(self, - num_qubits, - label="density_matrix", - unnormalized=False, - pershot=False, - conditional=False): + + def __init__( + self, + num_qubits, + label="density_matrix", + unnormalized=False, + pershot=False, + conditional=False, + ): """Create new instruction to save the simulator reduced density matrix. Args: @@ -41,18 +44,24 @@ def __init__(self, conditional on the current classical register values [Default: False]. """ - super().__init__("save_density_matrix", num_qubits, label, - unnormalized=unnormalized, - pershot=pershot, - conditional=conditional) + super().__init__( + "save_density_matrix", + num_qubits, + label, + unnormalized=unnormalized, + pershot=pershot, + conditional=conditional, + ) -def save_density_matrix(self, - qubits=None, - label="density_matrix", - unnormalized=False, - pershot=False, - conditional=False): +def save_density_matrix( + self, + qubits=None, + label="density_matrix", + unnormalized=False, + pershot=False, + conditional=False, +): """Save the current simulator quantum state as a density matrix. Args: @@ -74,11 +83,13 @@ def save_density_matrix(self, QuantumCircuit: with attached instruction. """ qubits = default_qubits(self, qubits=qubits) - instr = SaveDensityMatrix(len(qubits), - label=label, - unnormalized=unnormalized, - pershot=pershot, - conditional=conditional) + instr = SaveDensityMatrix( + len(qubits), + label=label, + unnormalized=unnormalized, + pershot=pershot, + conditional=conditional, + ) return self.append(instr, qubits) diff --git a/qiskit_aer/library/save_instructions/save_expectation_value.py b/qiskit_aer/library/save_instructions/save_expectation_value.py index 71fd85bd8a..bb583e1cdd 100644 --- a/qiskit_aer/library/save_instructions/save_expectation_value.py +++ b/qiskit_aer/library/save_instructions/save_expectation_value.py @@ -22,12 +22,15 @@ class SaveExpectationValue(SaveAverageData): """Save expectation value of an operator.""" - def __init__(self, - operator, - label="expectation_value", - unnormalized=False, - pershot=False, - conditional=False): + + def __init__( + self, + operator, + label="expectation_value", + unnormalized=False, + pershot=False, + conditional=False, + ): r"""Instruction to save the expectation value of a Hermitian operator. The expectation value of a Hermitian operator :math:`H` for a simulator @@ -63,21 +66,28 @@ def __init__(self, if not allclose(operator.coeffs.imag, 0): raise ExtensionError("Input operator is not Hermitian.") params = _expval_params(operator, variance=False) - super().__init__('save_expval', operator.num_qubits, label, - unnormalized=unnormalized, - pershot=pershot, - conditional=conditional, - params=params) + super().__init__( + "save_expval", + operator.num_qubits, + label, + unnormalized=unnormalized, + pershot=pershot, + conditional=conditional, + params=params, + ) class SaveExpectationValueVariance(SaveAverageData): """Save expectation value and variance of an operator.""" - def __init__(self, - operator, - label="expectation_value_variance", - unnormalized=False, - pershot=False, - conditional=False): + + def __init__( + self, + operator, + label="expectation_value_variance", + unnormalized=False, + pershot=False, + conditional=False, + ): r"""Instruction to save the expectation value and variance of a Hermitian operator. The expectation value of a Hermitian operator :math:`H` for a @@ -114,11 +124,15 @@ def __init__(self, if not allclose(operator.coeffs.imag, 0): raise ExtensionError("Input operator is not Hermitian.") params = _expval_params(operator, variance=True) - super().__init__('save_expval_var', operator.num_qubits, label, - unnormalized=unnormalized, - pershot=pershot, - conditional=conditional, - params=params) + super().__init__( + "save_expval_var", + operator.num_qubits, + label, + unnormalized=unnormalized, + pershot=pershot, + conditional=conditional, + params=params, + ) def _expval_params(operator, variance=False): @@ -154,13 +168,15 @@ def _expval_params(operator, variance=False): return list(params.items()) -def save_expectation_value(self, - operator, - qubits, - label="expectation_value", - unnormalized=False, - pershot=False, - conditional=False): +def save_expectation_value( + self, + operator, + qubits, + label="expectation_value", + unnormalized=False, + pershot=False, + conditional=False, +): r"""Save the expectation value of a Hermitian operator. Args: @@ -188,21 +204,25 @@ def save_expectation_value(self, This method appends a :class:`SaveExpectationValue` instruction to the quantum circuit. """ - instr = SaveExpectationValue(operator, - label=label, - unnormalized=unnormalized, - pershot=pershot, - conditional=conditional) + instr = SaveExpectationValue( + operator, + label=label, + unnormalized=unnormalized, + pershot=pershot, + conditional=conditional, + ) return self.append(instr, qubits) -def save_expectation_value_variance(self, - operator, - qubits, - label="expectation_value_variance", - unnormalized=False, - pershot=False, - conditional=False): +def save_expectation_value_variance( + self, + operator, + qubits, + label="expectation_value_variance", + unnormalized=False, + pershot=False, + conditional=False, +): r"""Save the expectation value of a Hermitian operator. Args: @@ -229,11 +249,13 @@ def save_expectation_value_variance(self, This method appends a :class:`SaveExpectationValueVariance` instruction to the quantum circuit. """ - instr = SaveExpectationValueVariance(operator, - label=label, - unnormalized=unnormalized, - pershot=pershot, - conditional=conditional) + instr = SaveExpectationValueVariance( + operator, + label=label, + unnormalized=unnormalized, + pershot=pershot, + conditional=conditional, + ) return self.append(instr, qubits) diff --git a/qiskit_aer/library/save_instructions/save_matrix_product_state.py b/qiskit_aer/library/save_instructions/save_matrix_product_state.py index 12f6ed51ee..9358befe5a 100644 --- a/qiskit_aer/library/save_instructions/save_matrix_product_state.py +++ b/qiskit_aer/library/save_instructions/save_matrix_product_state.py @@ -20,10 +20,10 @@ class SaveMatrixProductState(SaveSingleData): """Save matrix product state instruction""" - def __init__(self, num_qubits, - label="matrix_product_state", - pershot=False, - conditional=False): + + def __init__( + self, num_qubits, label="matrix_product_state", pershot=False, conditional=False + ): """Create new instruction to save the matrix product state. Args: @@ -40,14 +40,18 @@ def __init__(self, num_qubits, qubits in a circuit, otherwise an exception will be raised during simulation. """ - super().__init__('save_matrix_product_state', - num_qubits, - label, - pershot=pershot, - conditional=conditional) + super().__init__( + "save_matrix_product_state", + num_qubits, + label, + pershot=pershot, + conditional=conditional, + ) -def save_matrix_product_state(self, label="matrix_product_state", pershot=False, conditional=False): +def save_matrix_product_state( + self, label="matrix_product_state", pershot=False, conditional=False +): """Save the current simulator quantum state as a matrix product state. Args: @@ -66,10 +70,9 @@ def save_matrix_product_state(self, label="matrix_product_state", pershot=False, This instruction is always defined across all qubits in a circuit. """ qubits = default_qubits(self) - instr = SaveMatrixProductState(len(qubits), - label=label, - pershot=pershot, - conditional=conditional) + instr = SaveMatrixProductState( + len(qubits), label=label, pershot=pershot, conditional=conditional + ) return self.append(instr, qubits) diff --git a/qiskit_aer/library/save_instructions/save_probabilities.py b/qiskit_aer/library/save_instructions/save_probabilities.py index caabbe53c6..164802e4e0 100644 --- a/qiskit_aer/library/save_instructions/save_probabilities.py +++ b/qiskit_aer/library/save_instructions/save_probabilities.py @@ -20,12 +20,15 @@ class SaveProbabilities(SaveAverageData): """Save measurement outcome probabilities vector.""" - def __init__(self, - num_qubits, - label="probabilities", - unnormalized=False, - pershot=False, - conditional=False): + + def __init__( + self, + num_qubits, + label="probabilities", + unnormalized=False, + pershot=False, + conditional=False, + ): """Instruction to save measurement probabilities vector. Args: @@ -40,20 +43,27 @@ def __init__(self, on the current classical register values [Default: False]. """ - super().__init__("save_probabilities", num_qubits, label, - conditional=conditional, - pershot=pershot, - unnormalized=unnormalized) + super().__init__( + "save_probabilities", + num_qubits, + label, + conditional=conditional, + pershot=pershot, + unnormalized=unnormalized, + ) class SaveProbabilitiesDict(SaveAverageData): """Save measurement outcome probabilities dict.""" - def __init__(self, - num_qubits, - label="probabilities_dict", - unnormalized=False, - pershot=False, - conditional=False): + + def __init__( + self, + num_qubits, + label="probabilities_dict", + unnormalized=False, + pershot=False, + conditional=False, + ): """Instruction to save measurement probabilities dict. Args: @@ -68,18 +78,24 @@ def __init__(self, on the current classical register values [Default: False]. """ - super().__init__("save_probabilities_dict", num_qubits, label, - unnormalized=unnormalized, - pershot=pershot, - conditional=conditional) - - -def save_probabilities(self, - qubits=None, - label="probabilities", - unnormalized=False, - pershot=False, - conditional=False): + super().__init__( + "save_probabilities_dict", + num_qubits, + label, + unnormalized=unnormalized, + pershot=pershot, + conditional=conditional, + ) + + +def save_probabilities( + self, + qubits=None, + label="probabilities", + unnormalized=False, + pershot=False, + conditional=False, +): """Save measurement outcome probabilities vector. Args: @@ -99,20 +115,24 @@ def save_probabilities(self, QuantumCircuit: with attached instruction. """ qubits = default_qubits(self, qubits=qubits) - instr = SaveProbabilities(len(qubits), - label=label, - unnormalized=unnormalized, - pershot=pershot, - conditional=conditional) + instr = SaveProbabilities( + len(qubits), + label=label, + unnormalized=unnormalized, + pershot=pershot, + conditional=conditional, + ) return self.append(instr, qubits) -def save_probabilities_dict(self, - qubits=None, - label="probabilities", - unnormalized=False, - pershot=False, - conditional=False): +def save_probabilities_dict( + self, + qubits=None, + label="probabilities", + unnormalized=False, + pershot=False, + conditional=False, +): """Save measurement outcome probabilities vector. Args: @@ -132,11 +152,13 @@ def save_probabilities_dict(self, QuantumCircuit: with attached instruction. """ qubits = default_qubits(self, qubits=qubits) - instr = SaveProbabilitiesDict(len(qubits), - label=label, - unnormalized=unnormalized, - pershot=pershot, - conditional=conditional) + instr = SaveProbabilitiesDict( + len(qubits), + label=label, + unnormalized=unnormalized, + pershot=pershot, + conditional=conditional, + ) return self.append(instr, qubits) diff --git a/qiskit_aer/library/save_instructions/save_stabilizer.py b/qiskit_aer/library/save_instructions/save_stabilizer.py index 4a1ca163f1..d21b2e61f0 100644 --- a/qiskit_aer/library/save_instructions/save_stabilizer.py +++ b/qiskit_aer/library/save_instructions/save_stabilizer.py @@ -20,8 +20,10 @@ class SaveStabilizer(SaveSingleData): """Save Stabilizer instruction""" - def __init__(self, num_qubits, label="stabilizer", - pershot=False, conditional=False): + + def __init__( + self, num_qubits, label="stabilizer", pershot=False, conditional=False + ): """Create new instruction to save the stabilizer simulator state as a StabilizerState. Args: @@ -39,9 +41,13 @@ def __init__(self, num_qubits, label="stabilizer", qubits in a circuit, otherwise an exception will be raised during simulation. """ - super().__init__('save_stabilizer', num_qubits, label, - pershot=pershot, - conditional=conditional) + super().__init__( + "save_stabilizer", + num_qubits, + label, + pershot=pershot, + conditional=conditional, + ) def save_stabilizer(self, label="stabilizer", pershot=False, conditional=False): @@ -63,10 +69,9 @@ def save_stabilizer(self, label="stabilizer", pershot=False, conditional=False): This instruction is always defined across all qubits in a circuit. """ qubits = default_qubits(self) - instr = SaveStabilizer(len(qubits), - label=label, - pershot=pershot, - conditional=conditional) + instr = SaveStabilizer( + len(qubits), label=label, pershot=pershot, conditional=conditional + ) return self.append(instr, qubits) diff --git a/qiskit_aer/library/save_instructions/save_state.py b/qiskit_aer/library/save_instructions/save_state.py index 3e320d86ea..d969c3d252 100644 --- a/qiskit_aer/library/save_instructions/save_state.py +++ b/qiskit_aer/library/save_instructions/save_state.py @@ -23,10 +23,8 @@ class SaveState(SaveSingleData): The format of the saved state depends on the simulation method used. """ - def __init__(self, num_qubits, - label=None, - pershot=False, - conditional=False): + + def __init__(self, num_qubits, label=None, pershot=False, conditional=False): """Create new instruction to save the simualtor state. The format of the saved state depends on the simulation method used. @@ -49,10 +47,10 @@ def __init__(self, num_qubits, simulation. """ if label is None: - label = '_method_' - super().__init__('save_state', num_qubits, label, - pershot=pershot, - conditional=conditional) + label = "_method_" + super().__init__( + "save_state", num_qubits, label, pershot=pershot, conditional=conditional + ) def save_state(self, label=None, pershot=False, conditional=False): @@ -76,10 +74,9 @@ def save_state(self, label=None, pershot=False, conditional=False): This instruction is always defined across all qubits in a circuit. """ qubits = default_qubits(self) - instr = SaveState(len(qubits), - label=label, - pershot=pershot, - conditional=conditional) + instr = SaveState( + len(qubits), label=label, pershot=pershot, conditional=conditional + ) return self.append(instr, qubits) diff --git a/qiskit_aer/library/save_instructions/save_statevector.py b/qiskit_aer/library/save_instructions/save_statevector.py index 2358f86642..4f5eca07db 100644 --- a/qiskit_aer/library/save_instructions/save_statevector.py +++ b/qiskit_aer/library/save_instructions/save_statevector.py @@ -20,10 +20,10 @@ class SaveStatevector(SaveSingleData): """Save statevector""" - def __init__(self, num_qubits, - label="statevector", - pershot=False, - conditional=False): + + def __init__( + self, num_qubits, label="statevector", pershot=False, conditional=False + ): """Create new instruction to save the simulator statevector. Args: @@ -41,17 +41,21 @@ def __init__(self, num_qubits, qubits in a circuit, otherwise an exception will be raised during simulation. """ - super().__init__('save_statevector', num_qubits, label, - pershot=pershot, - conditional=conditional) + super().__init__( + "save_statevector", + num_qubits, + label, + pershot=pershot, + conditional=conditional, + ) class SaveStatevectorDict(SaveSingleData): """Save statevector as ket-form dictionary.""" - def __init__(self, num_qubits, - label="statevector_dict", - pershot=False, - conditional=False): + + def __init__( + self, num_qubits, label="statevector_dict", pershot=False, conditional=False + ): """Create new instruction to save the simulator statevector as a dict. Args: @@ -69,9 +73,13 @@ def __init__(self, num_qubits, qubits in a circuit, otherwise an exception will be raised during simulation. """ - super().__init__('save_statevector_dict', num_qubits, label, - pershot=pershot, - conditional=conditional) + super().__init__( + "save_statevector_dict", + num_qubits, + label, + pershot=pershot, + conditional=conditional, + ) def save_statevector(self, label="statevector", pershot=False, conditional=False): @@ -93,10 +101,9 @@ def save_statevector(self, label="statevector", pershot=False, conditional=False This instruction is always defined across all qubits in a circuit. """ qubits = default_qubits(self) - instr = SaveStatevector(len(qubits), - label=label, - pershot=pershot, - conditional=conditional) + instr = SaveStatevector( + len(qubits), label=label, pershot=pershot, conditional=conditional + ) return self.append(instr, qubits) @@ -119,10 +126,9 @@ def save_statevector_dict(self, label="statevector", pershot=False, conditional= This instruction is always defined across all qubits in a circuit. """ qubits = default_qubits(self) - instr = SaveStatevectorDict(len(qubits), - label=label, - pershot=pershot, - conditional=conditional) + instr = SaveStatevectorDict( + len(qubits), label=label, pershot=pershot, conditional=conditional + ) return self.append(instr, qubits) diff --git a/qiskit_aer/library/save_instructions/save_superop.py b/qiskit_aer/library/save_instructions/save_superop.py index d8ebca6103..d2ea183481 100644 --- a/qiskit_aer/library/save_instructions/save_superop.py +++ b/qiskit_aer/library/save_instructions/save_superop.py @@ -20,6 +20,7 @@ class SaveSuperOp(SaveSingleData): """Save a SuperOp matrix.""" + def __init__(self, num_qubits, label="superop", pershot=False): """Create new instruction to save the superop simulator state. diff --git a/qiskit_aer/library/save_instructions/save_unitary.py b/qiskit_aer/library/save_instructions/save_unitary.py index 8766852cbc..542992ca57 100644 --- a/qiskit_aer/library/save_instructions/save_unitary.py +++ b/qiskit_aer/library/save_instructions/save_unitary.py @@ -20,6 +20,7 @@ class SaveUnitary(SaveSingleData): """Save Unitary""" + def __init__(self, num_qubits, label="unitary", pershot=False): """Create new instruction to save the unitary simulator state. @@ -36,7 +37,7 @@ def __init__(self, num_qubits, label="unitary", pershot=False): qubits in a circuit, otherwise an exception will be raised during simulation. """ - super().__init__('save_unitary', num_qubits, label, pershot=pershot) + super().__init__("save_unitary", num_qubits, label, pershot=pershot) def save_unitary(self, label="unitary", pershot=False): diff --git a/qiskit_aer/library/set_instructions/set_density_matrix.py b/qiskit_aer/library/set_instructions/set_density_matrix.py index e228288440..08b013e1aa 100644 --- a/qiskit_aer/library/set_instructions/set_density_matrix.py +++ b/qiskit_aer/library/set_instructions/set_density_matrix.py @@ -43,9 +43,7 @@ def __init__(self, state): state = DensityMatrix(state) if not state.num_qubits or not state.is_valid(): raise ExtensionError("The input state is not valid") - super().__init__('set_density_matrix', - state.num_qubits, 0, - [state.data]) + super().__init__("set_density_matrix", state.num_qubits, 0, [state.data]) def set_density_matrix(self, state): @@ -73,7 +71,8 @@ def set_density_matrix(self, state): "The size of the density matrix for the set state" " instruction must be equal to the number of qubits" f" in the circuit (state.num_qubits ({state.num_qubits})" - f" != QuantumCircuit.num_qubits ({self.num_qubits})).") + f" != QuantumCircuit.num_qubits ({self.num_qubits}))." + ) return self.append(SetDensityMatrix(state), qubits) diff --git a/qiskit_aer/library/set_instructions/set_matrix_product_state.py b/qiskit_aer/library/set_instructions/set_matrix_product_state.py index 302057bc70..1546c842f1 100644 --- a/qiskit_aer/library/set_instructions/set_matrix_product_state.py +++ b/qiskit_aer/library/set_instructions/set_matrix_product_state.py @@ -38,7 +38,7 @@ def __init__(self, state): vector of pairs of matrices of complex numbers. The second is a vector of vectors of double. """ - super().__init__('set_matrix_product_state', len(state[0]), 0, [state]) + super().__init__("set_matrix_product_state", len(state[0]), 0, [state]) def set_matrix_product_state(self, state): @@ -61,19 +61,23 @@ def set_matrix_product_state(self, state): qubits = default_qubits(self) if not isinstance(state, tuple) or len(state) != 2: raise ExtensionError( - "The input matrix product state is not valid. Should be a list of 2 elements") + "The input matrix product state is not valid. Should be a list of 2 elements" + ) if not isinstance(state[0], list) or not isinstance(state[1], list): raise ExtensionError( - "The first element of the input matrix product state is not valid. Should be a list.") + "The first element of the input matrix product state is not valid. Should be a list." + ) if len(state[0]) != len(state[1]) + 1: raise ExtensionError( "The input matrix product state is not valid. " - "Length of q_reg vector should be 1 more than length of lambda_reg") + "Length of q_reg vector should be 1 more than length of lambda_reg" + ) for elem in state[0]: if not isinstance(elem, tuple) or len(elem) != 2: raise ExtensionError( "The input matrix product state is not valid." - "The first element should be a list of length 2") + "The first element should be a list of length 2" + ) return self.append(SetMatrixProductState(state), qubits) diff --git a/qiskit_aer/library/set_instructions/set_stabilizer.py b/qiskit_aer/library/set_instructions/set_stabilizer.py index bbafbc8703..7767560f41 100644 --- a/qiskit_aer/library/set_instructions/set_stabilizer.py +++ b/qiskit_aer/library/set_instructions/set_stabilizer.py @@ -40,7 +40,7 @@ def __init__(self, state): state = state.clifford elif not isinstance(state, Clifford): state = Clifford(state) - super().__init__('set_stabilizer', state.num_qubits, 0, [state.to_dict()]) + super().__init__("set_stabilizer", state.num_qubits, 0, [state.to_dict()]) def set_stabilizer(self, state): @@ -70,7 +70,8 @@ def set_stabilizer(self, state): "The size of the Clifford for the set_stabilizer" " instruction must be equal to the number of qubits" f" in the circuit (state.num_qubits ({state.num_qubits})" - f" != QuantumCircuit.num_qubits ({self.num_qubits})).") + f" != QuantumCircuit.num_qubits ({self.num_qubits}))." + ) return self.append(SetStabilizer(state), qubits) diff --git a/qiskit_aer/library/set_instructions/set_statevector.py b/qiskit_aer/library/set_instructions/set_statevector.py index a2fb6ab8d9..25603cecc5 100644 --- a/qiskit_aer/library/set_instructions/set_statevector.py +++ b/qiskit_aer/library/set_instructions/set_statevector.py @@ -43,7 +43,7 @@ def __init__(self, state): state = Statevector(state) if not state.num_qubits or not state.is_valid(): raise ExtensionError("The input statevector is not valid") - super().__init__('set_statevector', state.num_qubits, 0, [state.data]) + super().__init__("set_statevector", state.num_qubits, 0, [state.data]) def set_statevector(self, state): @@ -71,7 +71,8 @@ def set_statevector(self, state): "The size of the statevector for the set_statevector" " instruction must be equal to the number of qubits" f" in the circuit (state.num_qubits ({state.num_qubits})" - f" != QuantumCircuit.num_qubits ({self.num_qubits})).") + f" != QuantumCircuit.num_qubits ({self.num_qubits}))." + ) return self.append(SetStatevector(state), qubits) diff --git a/qiskit_aer/library/set_instructions/set_superop.py b/qiskit_aer/library/set_instructions/set_superop.py index e176834c99..0538e5f2dd 100644 --- a/qiskit_aer/library/set_instructions/set_superop.py +++ b/qiskit_aer/library/set_instructions/set_superop.py @@ -43,8 +43,7 @@ def __init__(self, state): state = SuperOp(state) if not state.num_qubits or not state.is_cptp(): raise ExtensionError("The input quantum channel is not CPTP") - super().__init__('set_superop', state.num_qubits, 0, - [state.data]) + super().__init__("set_superop", state.num_qubits, 0, [state.data]) def set_superop(self, state): @@ -73,7 +72,8 @@ def set_superop(self, state): "The size of the quantum channel for the set_superop" " instruction must be equal to the number of qubits" f" in the circuit (state.num_qubits ({state.num_qubits})" - f" != QuantumCircuit.num_qubits ({self.num_qubits})).") + f" != QuantumCircuit.num_qubits ({self.num_qubits}))." + ) return self.append(SetSuperOp(state), qubits) diff --git a/qiskit_aer/library/set_instructions/set_unitary.py b/qiskit_aer/library/set_instructions/set_unitary.py index 744923d5ac..ab8e261cdc 100644 --- a/qiskit_aer/library/set_instructions/set_unitary.py +++ b/qiskit_aer/library/set_instructions/set_unitary.py @@ -43,8 +43,7 @@ def __init__(self, state): state = Operator(state) if not state.num_qubits or not state.is_unitary(): raise ExtensionError("The input matrix is not unitary") - super().__init__('set_unitary', state.num_qubits, 0, - [state.data]) + super().__init__("set_unitary", state.num_qubits, 0, [state.data]) def set_unitary(self, state): @@ -73,7 +72,8 @@ def set_unitary(self, state): "The size of the unitary matrix for the set_unitary" " instruction must be equal to the number of qubits" f" in the circuit (state.num_qubits ({state.num_qubits})" - f" != QuantumCircuit.num_qubits ({self.num_qubits})).") + f" != QuantumCircuit.num_qubits ({self.num_qubits}))." + ) return self.append(SetUnitary(state), qubits) diff --git a/qiskit_aer/noise/device/models.py b/qiskit_aer/noise/device/models.py index 657e74c8ec..b18aeb4668 100644 --- a/qiskit_aer/noise/device/models.py +++ b/qiskit_aer/noise/device/models.py @@ -79,14 +79,16 @@ def basic_device_readout_errors(properties=None, target=None): return errors -def basic_device_gate_errors(properties=None, - gate_error=True, - thermal_relaxation=True, - gate_lengths=None, - gate_length_units='ns', - temperature=0, - warnings=None, - target=None): +def basic_device_gate_errors( + properties=None, + gate_error=True, + thermal_relaxation=True, + gate_lengths=None, + gate_length_units="ns", + temperature=0, + warnings=None, + target=None, +): """ Return QuantumErrors derived from either of a devices BackendProperties or Target. @@ -134,26 +136,33 @@ def basic_device_gate_errors(properties=None, if warnings is not None: warn( '"warnings" argument has been deprecated as of qiskit-aer 0.12.0 ' - 'and will be removed no earlier than 3 months from that release date. ' - 'Use the warnings filter in Python standard library instead.', - DeprecationWarning, stacklevel=2) + "and will be removed no earlier than 3 months from that release date. " + "Use the warnings filter in Python standard library instead.", + DeprecationWarning, + stacklevel=2, + ) else: warnings = True if target is not None: if not warnings: - warn("When `target` is supplied, `warnings` are ignored," - " and they are always set to true.", UserWarning) + warn( + "When `target` is supplied, `warnings` are ignored," + " and they are always set to true.", + UserWarning, + ) if gate_lengths: - raise NoiseError("When `target` is supplied, `gate_lengths` option is not allowed." - "Use `duration` property in target's InstructionProperties instead.") + raise NoiseError( + "When `target` is supplied, `gate_lengths` option is not allowed." + "Use `duration` property in target's InstructionProperties instead." + ) return _basic_device_target_gate_errors( target=target, gate_error=gate_error, thermal_relaxation=thermal_relaxation, - temperature=temperature + temperature=temperature, ) # Generate custom gate time dict @@ -187,8 +196,7 @@ def basic_device_gate_errors(properties=None, # Override with custom value if name in custom_times: filtered = [ - val for q, val in custom_times[name] - if q is None or q == qubits + val for q, val in custom_times[name] if q is None or q == qubits ] if filtered: # get first value @@ -196,13 +204,12 @@ def basic_device_gate_errors(properties=None, # Get relaxation error if thermal_relaxation: relax_error = _device_thermal_relaxation_error( - qubits, relax_time, relax_params, temperature, - thermal_relaxation) + qubits, relax_time, relax_params, temperature, thermal_relaxation + ) # Get depolarizing error channel if gate_error: - depol_error = _device_depolarizing_error( - qubits, error_param, relax_error) + depol_error = _device_depolarizing_error(qubits, error_param, relax_error) # Combine errors combined_error = _combine_depol_and_relax_error(depol_error, relax_error) @@ -222,10 +229,9 @@ def _combine_depol_and_relax_error(depol_error, relax_error): return None -def _basic_device_target_gate_errors(target, - gate_error=True, - thermal_relaxation=True, - temperature=0): +def _basic_device_target_gate_errors( + target, gate_error=True, thermal_relaxation=True, temperature=0 +): """Return QuantumErrors derived from a devices Target. Note that, in the resulting error list, non-Gate instructions (e.g. Reset) will have no gate errors while they may have thermal relaxation errors. Exceptionally, @@ -245,10 +251,14 @@ def _basic_device_target_gate_errors(target, relax_error = None # Get relaxation error if thermal_relaxation and inst_prop.duration: - relax_params = {q: (target.qubit_properties[q].t1, - target.qubit_properties[q].t2, - target.qubit_properties[q].frequency) - for q in qubits} + relax_params = { + q: ( + target.qubit_properties[q].t1, + target.qubit_properties[q].t2, + target.qubit_properties[q].frequency, + ) + for q in qubits + } relax_error = _device_thermal_relaxation_error( qubits=qubits, gate_time=inst_prop.duration, @@ -270,9 +280,7 @@ def _basic_device_target_gate_errors(target, return errors -def _device_depolarizing_error(qubits, - error_param, - relax_error=None): +def _device_depolarizing_error(qubits, error_param, relax_error=None): """Construct a depolarizing_error for device. If un-physical parameters are supplied, they are truncated to the theoretical bound values.""" @@ -301,7 +309,7 @@ def _device_depolarizing_error(qubits, relax_infid = 0 if error_param is not None and error_param > relax_infid: num_qubits = len(qubits) - dim = 2 ** num_qubits + dim = 2**num_qubits error_max = dim / (dim + 1) # Check if reported error param is un-physical # The minimum average gate fidelity is F_min = 1 / (dim + 1) @@ -309,7 +317,7 @@ def _device_depolarizing_error(qubits, error_param = min(error_param, error_max) # Model gate error entirely as depolarizing error num_qubits = len(qubits) - dim = 2 ** num_qubits + dim = 2**num_qubits depol_param = dim * (error_param - relax_infid) / (dim * relax_fid - 1) max_param = 4**num_qubits / (4**num_qubits - 1) if depol_param > max_param: @@ -318,11 +326,9 @@ def _device_depolarizing_error(qubits, return None -def _device_thermal_relaxation_error(qubits, - gate_time, - relax_params, - temperature, - thermal_relaxation=True): +def _device_thermal_relaxation_error( + qubits, gate_time, relax_params, temperature, thermal_relaxation=True +): """Construct a thermal_relaxation_error for device""" # Check trivial case if not thermal_relaxation or gate_time is None or gate_time == 0: diff --git a/qiskit_aer/noise/device/parameters.py b/qiskit_aer/noise/device/parameters.py index 88e8fcb473..04cf0df41a 100644 --- a/qiskit_aer/noise/device/parameters.py +++ b/qiskit_aer/noise/device/parameters.py @@ -17,8 +17,8 @@ from numpy import inf # Time and frequency unit conversions -_NANOSECOND_UNITS = {'s': 1e9, 'ms': 1e6, 'µs': 1e3, 'us': 1e3, 'ns': 1} -_GHZ_UNITS = {'Hz': 1e-9, 'KHz': 1e-6, 'MHz': 1e-3, 'GHz': 1, 'THz': 1e3} +_NANOSECOND_UNITS = {"s": 1e9, "ms": 1e6, "µs": 1e3, "us": 1e3, "ns": 1} +_GHZ_UNITS = {"Hz": 1e-9, "KHz": 1e-6, "MHz": 1e-3, "GHz": 1, "THz": 1e3} def gate_param_values(properties): @@ -39,16 +39,16 @@ def gate_param_values(properties): qubits = gate.qubits # Check for gate time information gate_length = None # default value - time_param = _check_for_item(gate.parameters, 'gate_length') - if hasattr(time_param, 'value'): + time_param = _check_for_item(gate.parameters, "gate_length") + if hasattr(time_param, "value"): gate_length = time_param.value - if hasattr(time_param, 'unit'): + if hasattr(time_param, "unit"): # Convert gate time to ns gate_length *= _NANOSECOND_UNITS.get(time_param.unit, 1) # Check for gate error information gate_error = None # default value - error_param = _check_for_item(gate.parameters, 'gate_error') - if hasattr(error_param, 'value'): + error_param = _check_for_item(gate.parameters, "gate_error") + if hasattr(error_param, "value"): gate_error = error_param.value values.append((name, qubits, gate_length, gate_error)) @@ -72,8 +72,8 @@ def gate_error_values(properties): name = gate.gate qubits = gate.qubits value = None # default value - params = _check_for_item(gate.parameters, 'gate_error') - if hasattr(params, 'value'): + params = _check_for_item(gate.parameters, "gate_error") + if hasattr(params, "value"): value = params.value values.append((name, qubits, value)) return values @@ -98,10 +98,10 @@ def gate_length_values(properties): name = gate.gate qubits = gate.qubits value = None # default value - params = _check_for_item(gate.parameters, 'gate_length') - if hasattr(params, 'value'): + params = _check_for_item(gate.parameters, "gate_length") + if hasattr(params, "value"): value = params.value - if hasattr(params, 'unit'): + if hasattr(params, "unit"): # Convert gate time to ns value *= _NANOSECOND_UNITS.get(params.unit, 1) values.append((name, qubits, value)) @@ -124,13 +124,13 @@ def readout_error_values(properties): for qubit_props in properties.qubits: value = None # default value - params_roerror = _check_for_item(qubit_props, 'readout_error') - params_m1p0 = _check_for_item(qubit_props, 'prob_meas1_prep0') - params_m0p1 = _check_for_item(qubit_props, 'prob_meas0_prep1') + params_roerror = _check_for_item(qubit_props, "readout_error") + params_m1p0 = _check_for_item(qubit_props, "prob_meas1_prep0") + params_m0p1 = _check_for_item(qubit_props, "prob_meas0_prep1") - if hasattr(params_m1p0, 'value') and hasattr(params_m0p1, 'value'): + if hasattr(params_m1p0, "value") and hasattr(params_m0p1, "value"): value = [params_m1p0.value, params_m0p1.value] - elif hasattr(params_roerror, 'value'): + elif hasattr(params_roerror, "value"): value = [params_roerror.value, params_roerror.value] values.append(value) return values @@ -161,24 +161,24 @@ def thermal_relaxation_values(properties): t1, t2, freq = inf, inf, inf # Get the readout error value - t1_params = _check_for_item(qubit_props, 'T1') - t2_params = _check_for_item(qubit_props, 'T2') - freq_params = _check_for_item(qubit_props, 'frequency') + t1_params = _check_for_item(qubit_props, "T1") + t2_params = _check_for_item(qubit_props, "T2") + freq_params = _check_for_item(qubit_props, "frequency") # Load values from parameters - if hasattr(t1_params, 'value'): + if hasattr(t1_params, "value"): t1 = t1_params.value - if hasattr(t1_params, 'unit'): + if hasattr(t1_params, "unit"): # Convert to nanoseconds t1 *= _NANOSECOND_UNITS.get(t1_params.unit, 1) - if hasattr(t2_params, 'value'): + if hasattr(t2_params, "value"): t2 = t2_params.value - if hasattr(t2_params, 'unit'): + if hasattr(t2_params, "unit"): # Convert to nanoseconds t2 *= _NANOSECOND_UNITS.get(t2_params.unit, 1) - if hasattr(freq_params, 'value'): + if hasattr(freq_params, "value"): freq = freq_params.value - if hasattr(freq_params, 'unit'): + if hasattr(freq_params, "unit"): # Convert to Gigahertz freq *= _GHZ_UNITS.get(freq_params.unit, 1) diff --git a/qiskit_aer/noise/errors/quantum_error.py b/qiskit_aer/noise/errors/quantum_error.py index 5d8efd335c..a2d66f8a74 100644 --- a/qiskit_aer/noise/errors/quantum_error.py +++ b/qiskit_aer/noise/errors/quantum_error.py @@ -44,8 +44,7 @@ class QuantumError(BaseOperator, TolerancesMixin): module. """ - def __init__(self, - noise_ops): + def __init__(self, noise_ops): """ Create a quantum error for a noise model. @@ -102,8 +101,9 @@ def __init__(self, return # Single circuit case - if not isinstance(noise_ops, Iterable) or \ - (isinstance(noise_ops, tuple) and isinstance(noise_ops[0], Instruction)): + if not isinstance(noise_ops, Iterable) or ( + isinstance(noise_ops, tuple) and isinstance(noise_ops[0], Instruction) + ): noise_ops = [(noise_ops, 1.0)] # Convert zipped object to list (to enable multiple iteration over it) @@ -180,7 +180,7 @@ def _to_circuit(cls, op): f"Fail to convert {op.__class__.__name__} to Instruction." ) from err if isinstance(op, BaseOperator): - if hasattr(op, 'to_instruction'): + if hasattr(op, "to_instruction"): try: return cls._to_circuit(op.to_instruction()) except QiskitError as err: @@ -231,7 +231,7 @@ def __hash__(self): return hash(self._id) @property - def id(self): # pylint: disable=invalid-name + def id(self): # pylint: disable=invalid-name """Return unique ID string for error""" return self._id @@ -273,15 +273,16 @@ def ideal(self): if isinstance(op, IGate): continue if isinstance(op, PauliGate): - if op.params[0].replace('I', ''): + if op.params[0].replace("I", ""): return False else: # Convert to Kraus and check if identity kmats = Kraus(op).data if len(kmats) > 1: return False - if not is_identity_matrix(kmats[0], ignore_phase=True, - atol=self.atol, rtol=self.rtol): + if not is_identity_matrix( + kmats[0], ignore_phase=True, atol=self.atol, rtol=self.rtol + ): return False return True @@ -289,7 +290,7 @@ def to_quantumchannel(self): """Convert the QuantumError to a SuperOp quantum channel. Required to enable SuperOp(QuantumError).""" # Initialize as an empty superoperator of the correct size - dim = 2 ** self.num_qubits + dim = 2**self.num_qubits ret = SuperOp(np.zeros([dim * dim, dim * dim])) for circ, prob in zip(self.circuits, self.probabilities): component = prob * SuperOp(circ) @@ -340,7 +341,7 @@ def to_dict(self): "id": self.id, "operations": [], "instructions": instructions, - "probabilities": list(self.probabilities) + "probabilities": list(self.probabilities), } return error @@ -349,22 +350,26 @@ def compose(self, other, qargs=None, front=False): other = QuantumError(other) if qargs is not None: if self.num_qubits < other.num_qubits: - raise QiskitError("Number of qubits of this error must be less than" - " that of the error to be composed if using 'qargs' argument.") + raise QiskitError( + "Number of qubits of this error must be less than" + " that of the error to be composed if using 'qargs' argument." + ) if len(qargs) != other.num_qubits: - raise QiskitError("Number of items in 'qargs' argument must be the same as" - " number of qubits of the error to be composed.") + raise QiskitError( + "Number of items in 'qargs' argument must be the same as" + " number of qubits of the error to be composed." + ) if front: raise QiskitError( "QuantumError.compose does not support 'qargs' when 'front=True'." ) - circs = [self._compose_circ(lqc, rqc, qubits=qargs, front=front) - for lqc in self.circuits - for rqc in other.circuits] - probs = [lpr * rpr - for lpr in self.probabilities - for rpr in other.probabilities] + circs = [ + self._compose_circ(lqc, rqc, qubits=qargs, front=front) + for lqc in self.circuits + for rqc in other.circuits + ] + probs = [lpr * rpr for lpr in self.probabilities for rpr in other.probabilities] return QuantumError(zip(circs, probs)) @staticmethod @@ -389,12 +394,8 @@ def tensor(self, other): if not isinstance(other, QuantumError): other = QuantumError(other) - circs = [lqc.tensor(rqc) - for lqc in self.circuits - for rqc in other.circuits] - probs = [lpr * rpr - for lpr in self.probabilities - for rpr in other.probabilities] + circs = [lqc.tensor(rqc) for lqc in self.circuits for rqc in other.circuits] + probs = [lpr * rpr for lpr in self.probabilities for rpr in other.probabilities] return QuantumError(zip(circs, probs)) def expand(self, other): @@ -402,7 +403,9 @@ def expand(self, other): # Overloads def __rmul__(self, other): - raise NotImplementedError("'QuantumError' does not support scalar multiplication.") + raise NotImplementedError( + "'QuantumError' does not support scalar multiplication." + ) def __truediv__(self, other): raise NotImplementedError("'QuantumError' does not support division.") diff --git a/qiskit_aer/noise/errors/readout_error.py b/qiskit_aer/noise/errors/readout_error.py index f84661d494..abcee0e480 100644 --- a/qiskit_aer/noise/errors/readout_error.py +++ b/qiskit_aer/noise/errors/readout_error.py @@ -27,6 +27,7 @@ class ReadoutError: """ Readout error class for Qiskit Aer noise model. """ + # pylint: disable=invalid-name _ATOL_DEFAULT = ATOL_DEFAULT _RTOL_DEFAULT = RTOL_DEFAULT @@ -73,8 +74,13 @@ def __init__(self, probabilities, atol=ATOL_DEFAULT): self._check_probabilities(probabilities, atol) self._probabilities = np.array(probabilities, dtype=float) self._number_of_qubits = int(np.log2(self._probabilities.shape[0])) - if self._probabilities.shape != (2**self._number_of_qubits, 2**self._number_of_qubits): - raise NoiseError("Input readout error probabilities is not a 2^N by 2^N matrix.") + if self._probabilities.shape != ( + 2**self._number_of_qubits, + 2**self._number_of_qubits, + ): + raise NoiseError( + "Input readout error probabilities is not a 2^N by 2^N matrix." + ) def __repr__(self): """Display ReadoutError.""" @@ -82,8 +88,10 @@ def __repr__(self): def __str__(self): """Print error information.""" - output = "ReadoutError on {} qubits.".format(self._number_of_qubits) + \ - " Assignment probabilities:" + output = ( + "ReadoutError on {} qubits.".format(self._number_of_qubits) + + " Assignment probabilities:" + ) for j, vec in enumerate(self._probabilities): output += "\n P(j|{0}) = {1}".format(j, vec) return output @@ -94,8 +102,9 @@ def __eq__(self, other): return False if self.number_of_qubits != other.number_of_qubits: return False - return np.allclose(self._probabilities, other._probabilities, - atol=self.atol, rtol=self.rtol) + return np.allclose( + self._probabilities, other._probabilities, atol=self.atol, rtol=self.rtol + ) def copy(self): """Make a copy of current ReadoutError.""" @@ -127,24 +136,22 @@ def rtol(self): def set_atol(cls, value): """Set the class default absolute tolerance parameter for float comparisons.""" if value < 0: - raise NoiseError( - "Invalid atol ({}) must be non-negative.".format(value)) + raise NoiseError("Invalid atol ({}) must be non-negative.".format(value)) if value > cls._MAX_TOL: raise NoiseError( - "Invalid atol ({}) must be less than {}.".format( - value, cls._MAX_TOL)) + "Invalid atol ({}) must be less than {}.".format(value, cls._MAX_TOL) + ) cls._ATOL_DEFAULT = value @classmethod def set_rtol(cls, value): """Set the class default relative tolerance parameter for float comparisons.""" if value < 0: - raise NoiseError( - "Invalid rtol ({}) must be non-negative.".format(value)) + raise NoiseError("Invalid rtol ({}) must be non-negative.".format(value)) if value > cls._MAX_TOL: raise NoiseError( - "Invalid rtol ({}) must be less than {}.".format( - value, cls._MAX_TOL)) + "Invalid rtol ({}) must be less than {}.".format(value, cls._MAX_TOL) + ) cls._RTOL_DEFAULT = value def ideal(self): @@ -164,7 +171,7 @@ def to_dict(self): error = { "type": "roerror", "operations": ["measure"], - "probabilities": self._probabilities.tolist() + "probabilities": self._probabilities.tolist(), } return error @@ -256,28 +263,35 @@ def expand(self, other): def _check_probabilities(probabilities, threshold): """Check probabilities are valid.""" # probabilities parameter can be a list or a numpy.ndarray - if (isinstance(probabilities, list) and not probabilities) or \ - (isinstance(probabilities, np.ndarray) and probabilities.size == 0): + if (isinstance(probabilities, list) and not probabilities) or ( + isinstance(probabilities, np.ndarray) and probabilities.size == 0 + ): raise NoiseError("Input probabilities: empty.") num_outcomes = len(probabilities[0]) num_qubits = int(np.log2(num_outcomes)) if 2**num_qubits != num_outcomes: - raise NoiseError("Invalid probabilities: length " - "{} != 2**{}".format(num_outcomes, num_qubits)) + raise NoiseError( + "Invalid probabilities: length " + "{} != 2**{}".format(num_outcomes, num_qubits) + ) if len(probabilities) != num_outcomes: raise NoiseError("Invalid probabilities.") for vec in probabilities: arr = np.array(vec) if len(arr) != num_outcomes: raise NoiseError( - "Invalid probabilities: vectors are different lengths.") + "Invalid probabilities: vectors are different lengths." + ) if abs(sum(arr) - 1) > threshold: - raise NoiseError("Invalid probabilities: sum({})= {} " - "is not 1.".format(vec, sum(arr))) + raise NoiseError( + "Invalid probabilities: sum({})= {} " + "is not 1.".format(vec, sum(arr)) + ) if arr[arr < 0].size > 0: raise NoiseError( "Invalid probabilities: {} " - "contains a negative probability.".format(vec)) + "contains a negative probability.".format(vec) + ) def _matmul(self, other, left_multiply=False): """Return the composition readout error. @@ -336,7 +350,8 @@ def __xor__(self, other): def __rmul__(self, other): raise NotImplementedError( - "'ReadoutError' does not support scalar multiplication.") + "'ReadoutError' does not support scalar multiplication." + ) def __truediv__(self, other): raise NotImplementedError("'ReadoutError' does not support division.") @@ -345,8 +360,7 @@ def __add__(self, other): raise NotImplementedError("'ReadoutError' does not support addition.") def __sub__(self, other): - raise NotImplementedError( - "'ReadoutError' does not support subtraction.") + raise NotImplementedError("'ReadoutError' does not support subtraction.") def __neg__(self): raise NotImplementedError("'ReadoutError' does not support negation.") diff --git a/qiskit_aer/noise/errors/standard_errors.py b/qiskit_aer/noise/errors/standard_errors.py index cbb01e8667..9c64c97a95 100644 --- a/qiskit_aer/noise/errors/standard_errors.py +++ b/qiskit_aer/noise/errors/standard_errors.py @@ -83,12 +83,14 @@ def mixed_unitary_error(noise_ops): raise NoiseError("Input noise list is empty.") # Check for identity unitaries - prob_identity = 0. + prob_identity = 0.0 instructions = [] instructions_probs = [] num_qubits = int(np.log2(noise_ops[0][0].shape[0])) if noise_ops[0][0].shape != (2**num_qubits, 2**num_qubits): - raise NoiseError("A unitary matrix in input noise_ops is not a multi-qubit matrix.") + raise NoiseError( + "A unitary matrix in input noise_ops is not a multi-qubit matrix." + ) for unitary, prob in noise_ops: # Check unitary if unitary.shape != noise_ops[0][0].shape: @@ -202,11 +204,12 @@ def depolarizing_error(param, num_qubits): if not isinstance(num_qubits, int) or num_qubits < 1: raise NoiseError("num_qubits must be a positive integer.") # Check that the depolarizing parameter gives a valid CPTP - num_terms = 4 ** num_qubits + num_terms = 4**num_qubits max_param = num_terms / (num_terms - 1) if param < 0 or param > max_param: - raise NoiseError("Depolarizing parameter must be in between 0 " - "and {}.".format(max_param)) + raise NoiseError( + "Depolarizing parameter must be in between 0 " "and {}.".format(max_param) + ) # Rescale completely depolarizing channel error probs # with the identity component removed @@ -216,7 +219,10 @@ def depolarizing_error(param, num_qubits): # Generate pauli strings. The order doesn't matter as long # as the all identity string is first. - paulis = [Pauli("".join(tup)) for tup in it.product(['I', 'X', 'Y', 'Z'], repeat=num_qubits)] + paulis = [ + Pauli("".join(tup)) + for tup in it.product(["I", "X", "Y", "Z"], repeat=num_qubits) + ] return QuantumError(zip(paulis, probs)) @@ -249,7 +255,7 @@ def reset_error(prob0, prob1=0): noise_ops = [ ([(IGate(), [0])], 1 - prob0 - prob1), ([(Reset(), [0])], prob0), - ([(Reset(), [0]), (XGate(), [0])], prob1) + ([(Reset(), [0]), (XGate(), [0])], prob1), ] return QuantumError(noise_ops) @@ -283,11 +289,15 @@ def thermal_relaxation_error(t1, t2, time, excited_state_population=0): general non-unitary Kraus error channel. """ if excited_state_population < 0: - raise NoiseError("Invalid excited state population " - "({} < 0).".format(excited_state_population)) + raise NoiseError( + "Invalid excited state population " + "({} < 0).".format(excited_state_population) + ) if excited_state_population > 1: - raise NoiseError("Invalid excited state population " - "({} > 1).".format(excited_state_population)) + raise NoiseError( + "Invalid excited state population " + "({} > 1).".format(excited_state_population) + ) if time < 0: raise NoiseError("Invalid gate_time ({} < 0)".format(time)) if t1 <= 0: @@ -296,7 +306,8 @@ def thermal_relaxation_error(t1, t2, time, excited_state_population=0): raise NoiseError("Invalid T_2 relaxation time parameter: T_2 <= 0.") if t2 - 2 * t1 > 0: raise NoiseError( - "Invalid T_2 relaxation time parameter: T_2 greater than 2 * T_1.") + "Invalid T_2 relaxation time parameter: T_2 greater than 2 * T_1." + ) # T1 relaxation rate if t1 == np.inf: @@ -320,9 +331,15 @@ def thermal_relaxation_error(t1, t2, time, excited_state_population=0): # If T_2 > T_1 we must express this as a Kraus channel # We start with the Choi-matrix representation: chan = Choi( - np.array([[1 - p1 * p_reset, 0, 0, exp_t2], - [0, p1 * p_reset, 0, 0], [0, 0, p0 * p_reset, 0], - [exp_t2, 0, 0, 1 - p0 * p_reset]])) + np.array( + [ + [1 - p1 * p_reset, 0, 0, exp_t2], + [0, p1 * p_reset, 0, 0], + [0, 0, p0 * p_reset, 0], + [exp_t2, 0, 0, 1 - p0 * p_reset], + ] + ) + ) return QuantumError(Kraus(chan)) else: # If T_2 < T_1 we can express this channel as a probabilistic @@ -331,7 +348,7 @@ def thermal_relaxation_error(t1, t2, time, excited_state_population=0): [(IGate(), [0])], [(ZGate(), [0])], [(Reset(), [0])], - [(Reset(), [0]), (XGate(), [0])] + [(Reset(), [0]), (XGate(), [0])], ] # Probability p_reset0 = p_reset * p0 @@ -342,10 +359,9 @@ def thermal_relaxation_error(t1, t2, time, excited_state_population=0): return QuantumError(zip(circuits, probabilities)) -def phase_amplitude_damping_error(param_amp, - param_phase, - excited_state_population=0, - canonical_kraus=True): +def phase_amplitude_damping_error( + param_amp, param_phase, excited_state_population=0, canonical_kraus=True +): r""" Return a single-qubit combined phase and amplitude damping quantum error channel. @@ -385,20 +401,28 @@ def phase_amplitude_damping_error(param_amp, """ if param_amp < 0: - raise NoiseError("Invalid amplitude damping to |0> parameter " - "({} < 0)".format(param_amp)) + raise NoiseError( + "Invalid amplitude damping to |0> parameter " "({} < 0)".format(param_amp) + ) if param_phase < 0: - raise NoiseError("Invalid phase damping parameter " - "({} < 0)".format(param_phase)) + raise NoiseError( + "Invalid phase damping parameter " "({} < 0)".format(param_phase) + ) if param_phase + param_amp > 1: - raise NoiseError("Invalid amplitude and phase damping parameters " - "({} + {} > 1)".format(param_phase, param_amp)) + raise NoiseError( + "Invalid amplitude and phase damping parameters " + "({} + {} > 1)".format(param_phase, param_amp) + ) if excited_state_population < 0: - raise NoiseError("Invalid excited state population " - "({} < 0).".format(excited_state_population)) + raise NoiseError( + "Invalid excited state population " + "({} < 0).".format(excited_state_population) + ) if excited_state_population > 1: - raise NoiseError("Invalid excited state population " - "({} > 1).".format(excited_state_population)) + raise NoiseError( + "Invalid excited state population " + "({} > 1).".format(excited_state_population) + ) c0 = np.sqrt(1 - excited_state_population) c1 = np.sqrt(excited_state_population) param = 1 - param_amp - param_phase @@ -411,15 +435,13 @@ def phase_amplitude_damping_error(param_amp, B1 = c1 * np.array([[0, 0], [np.sqrt(param_amp), 0]], dtype=complex) B2 = c1 * np.array([[np.sqrt(param_phase), 0], [0, 0]], dtype=complex) # Select non-zero ops - noise_ops = [ - a for a in [A0, A1, A2, B0, B1, B2] if np.linalg.norm(a) > 1e-10 - ] + noise_ops = [a for a in [A0, A1, A2, B0, B1, B2] if np.linalg.norm(a) > 1e-10] return kraus_error(noise_ops, canonical_kraus=canonical_kraus) -def amplitude_damping_error(param_amp, - excited_state_population=0, - canonical_kraus=True): +def amplitude_damping_error( + param_amp, excited_state_population=0, canonical_kraus=True +): r""" Return a single-qubit generalized amplitude damping quantum error channel. @@ -455,7 +477,8 @@ def amplitude_damping_error(param_amp, param_amp, 0, excited_state_population=excited_state_population, - canonical_kraus=canonical_kraus) + canonical_kraus=canonical_kraus, + ) def phase_damping_error(param_phase, canonical_kraus=True): @@ -490,7 +513,5 @@ def phase_damping_error(param_phase, canonical_kraus=True): """ return phase_amplitude_damping_error( - 0, - param_phase, - excited_state_population=0, - canonical_kraus=canonical_kraus) + 0, param_phase, excited_state_population=0, canonical_kraus=canonical_kraus + ) diff --git a/qiskit_aer/noise/noise_model.py b/qiskit_aer/noise/noise_model.py index fa2aa6f11d..914f923821 100644 --- a/qiskit_aer/noise/noise_model.py +++ b/qiskit_aer/noise/noise_model.py @@ -129,14 +129,52 @@ class NoiseModel: print(noise_model) """ + # Checks for standard 1-3 qubit instructions - _1qubit_instructions = set([ - 'u1', 'u2', 'u3', 'u', 'p', 'r', 'rx', 'ry', 'rz', 'id', 'x', - 'y', 'z', 'h', 's', 'sdg', 'sx', 'sxdg', 't', 'tdg']) - _2qubit_instructions = set([ - 'swap', 'cx', 'cy', 'cz', 'csx', 'cp', 'cu', 'cu1', 'cu2', 'cu3', 'rxx', - 'ryy', 'rzz', 'rzx', 'ecr']) - _3qubit_instructions = set(['ccx', 'cswap']) + _1qubit_instructions = set( + [ + "u1", + "u2", + "u3", + "u", + "p", + "r", + "rx", + "ry", + "rz", + "id", + "x", + "y", + "z", + "h", + "s", + "sdg", + "sx", + "sxdg", + "t", + "tdg", + ] + ) + _2qubit_instructions = set( + [ + "swap", + "cx", + "cy", + "cz", + "csx", + "cp", + "cu", + "cu1", + "cu2", + "cu3", + "rxx", + "ryy", + "rzz", + "rzx", + "ecr", + ] + ) + _3qubit_instructions = set(["ccx", "cswap"]) def __init__(self, basis_gates=None): """Initialize an empty noise model. @@ -160,10 +198,11 @@ def __init__(self, basis_gates=None): # Default basis gates is id, rz, sx, cx so that all standard # non-identity instructions can be unrolled to rz, sx, cx, # and identities won't be unrolled - self._basis_gates = set(['id', 'rz', 'sx', 'cx']) + self._basis_gates = set(["id", "rz", "sx", "cx"]) else: self._basis_gates = set( - name for name, _ in self._instruction_names_labels(basis_gates)) + name for name, _ in self._instruction_names_labels(basis_gates) + ) # Store gates with a noise model defined self._noise_instructions = set() # Store qubits referenced in noise model. @@ -205,14 +244,17 @@ def noise_qubits(self): return sorted(self._noise_qubits) @classmethod - def from_backend(cls, backend, - gate_error=True, - readout_error=True, - thermal_relaxation=True, - temperature=0, - gate_lengths=None, - gate_length_units='ns', - warnings=None): + def from_backend( + cls, + backend, + gate_error=True, + readout_error=True, + thermal_relaxation=True, + temperature=0, + gate_lengths=None, + gate_length_units="ns", + warnings=None, + ): """Return a noise model derived from a devices backend properties. This function generates a noise model based on: @@ -305,9 +347,11 @@ def from_backend(cls, backend, if warnings is not None: warn( '"warnings" argument has been deprecated as of qiskit-aer 0.12.0 ' - 'and will be removed no earlier than 3 months from that release date. ' - 'Use the warnings filter in Python standard library instead.', - DeprecationWarning, stacklevel=2) + "and will be removed no earlier than 3 months from that release date. " + "Use the warnings filter in Python standard library instead.", + DeprecationWarning, + stacklevel=2, + ) else: warnings = True @@ -318,8 +362,11 @@ def from_backend(cls, backend, target = None if backend_interface_version == 2: if not warnings: - warn("When a BackendV2 is supplied, `warnings`" - " are ignored, and their default values are used.", UserWarning) + warn( + "When a BackendV2 is supplied, `warnings`" + " are ignored, and their default values are used.", + UserWarning, + ) properties = None basis_gates = backend.operation_names target = backend.target @@ -328,26 +375,37 @@ def from_backend(cls, backend, target = copy.deepcopy(target) for op_name, qubits, value in gate_lengths: prop = target[op_name][qubits] - prop.duration = apply_prefix(value, gate_length_units) # convert to seconds + prop.duration = apply_prefix( + value, gate_length_units + ) # convert to seconds target.update_instruction_properties(op_name, qubits, prop) all_qubit_properties = backend.target.qubit_properties if not all_qubit_properties: - warn(f"Qiskit backend {backend} has no QubitProperties, so the resulting" - " noise model will not include any thermal relaxation errors.", UserWarning) + warn( + f"Qiskit backend {backend} has no QubitProperties, so the resulting" + " noise model will not include any thermal relaxation errors.", + UserWarning, + ) dt = backend.dt elif backend_interface_version <= 1: properties = backend.properties() configuration = backend.configuration() basis_gates = configuration.basis_gates - all_qubit_properties = [QubitProperties(t1=properties.t1(q), - t2=properties.t2(q), - frequency=properties.frequency(q)) - for q in range(configuration.num_qubits)] + all_qubit_properties = [ + QubitProperties( + t1=properties.t1(q), + t2=properties.t2(q), + frequency=properties.frequency(q), + ) + for q in range(configuration.num_qubits) + ] dt = getattr(configuration, "dt", 0) if not properties: - raise NoiseError(f'Qiskit backend {backend} does not have a BackendProperties') + raise NoiseError( + f"Qiskit backend {backend} does not have a BackendProperties" + ) else: - raise NoiseError(f'{backend} is not a Qiskit backend') + raise NoiseError(f"{backend} is not a Qiskit backend") noise_model = NoiseModel(basis_gates=basis_gates) @@ -359,9 +417,7 @@ def from_backend(cls, backend, # Add gate errors with catch_warnings(): filterwarnings( - "ignore", - category=DeprecationWarning, - module="qiskit_aer.noise" + "ignore", category=DeprecationWarning, module="qiskit_aer.noise" ) gate_errors = basic_device_gate_errors( properties, @@ -380,20 +436,23 @@ def from_backend(cls, backend, # Add delay errors via RelaxationNiose pass try: excited_state_populations = [ - _excited_population( - freq=q.frequency, temperature=temperature - ) for q in all_qubit_properties] + _excited_population(freq=q.frequency, temperature=temperature) + for q in all_qubit_properties + ] except BackendPropertyError: excited_state_populations = None try: t1s = [prop.t1 for prop in all_qubit_properties] - t2s = [_truncate_t2_value(prop.t1, prop.t2) for prop in all_qubit_properties] + t2s = [ + _truncate_t2_value(prop.t1, prop.t2) + for prop in all_qubit_properties + ] delay_pass = RelaxationNoisePass( t1s=t1s, t2s=t2s, dt=dt, op_types=Delay, - excited_state_populations=excited_state_populations + excited_state_populations=excited_state_populations, ) noise_model._custom_noise_passes.append(delay_pass) except BackendPropertyError: @@ -492,8 +551,12 @@ def from_backend_properties( try: delay_pass = RelaxationNoisePass( t1s=[backend_properties.t1(q) for q in range(num_qubits)], - t2s=[_truncate_t2_value(backend_properties.t1( - q), backend_properties.t2(q)) for q in range(num_qubits)], + t2s=[ + _truncate_t2_value( + backend_properties.t1(q), backend_properties.t2(q) + ) + for q in range(num_qubits) + ], dt=dt, op_types=Delay, excited_state_populations=excited_state_populations, @@ -535,10 +598,10 @@ def __str__(self): # Get default errors default_error_ops = [] for inst in self._default_quantum_errors: - default_error_ops.append('{}'.format(inst)) + default_error_ops.append("{}".format(inst)) if self._default_readout_error is not None: - if 'measure' not in default_error_ops: - default_error_ops.append('measure') + if "measure" not in default_error_ops: + default_error_ops.append("measure") # Get local errors local_error_ops = [] @@ -546,7 +609,7 @@ def __str__(self): for qubits in dic.keys(): local_error_ops.append((inst, qubits)) for qubits in self._local_readout_errors: - tmp = ('measure', qubits) + tmp = ("measure", qubits) if tmp not in local_error_ops: local_error_ops.append(tmp) @@ -554,15 +617,14 @@ def __str__(self): output += "\n Basis gates: {}".format(self.basis_gates) if self._noise_instructions: output += "\n Instructions with noise: {}".format( - list(self._noise_instructions)) + list(self._noise_instructions) + ) if self._noise_qubits: - output += "\n Qubits with noise: {}".format( - list(self._noise_qubits)) + output += "\n Qubits with noise: {}".format(list(self._noise_qubits)) if default_error_ops: output += "\n All-qubits errors: {}".format(default_error_ops) if local_error_ops: - output += "\n Specific qubit errors: {}".format( - local_error_ops) + output += "\n Specific qubit errors: {}".format(local_error_ops) return output def __eq__(self, other): @@ -571,10 +633,12 @@ def __eq__(self, other): # the same basis_gates # the same noise_qubits # the same noise_instructions - if (not isinstance(other, NoiseModel) or - self.basis_gates != other.basis_gates or - self.noise_qubits != other.noise_qubits or - self.noise_instructions != other.noise_instructions): + if ( + not isinstance(other, NoiseModel) + or self.basis_gates != other.basis_gates + or self.noise_qubits != other.noise_qubits + or self.noise_instructions != other.noise_instructions + ): return False # Check default readout errors is equal if not self._readout_errors_equal(other): @@ -604,9 +668,15 @@ def add_basis_gates(self, instructions): for name, _ in self._instruction_names_labels(instructions): # If the instruction is in the default basis gates for the # AerSimulator we add it to the basis gates. - if name in BASIS_GATES['automatic']: - if name not in ['measure', 'reset', 'initialize', - 'kraus', 'superop', 'roerror']: + if name in BASIS_GATES["automatic"]: + if name not in [ + "measure", + "reset", + "initialize", + "kraus", + "superop", + "roerror", + ]: self._basis_gates.add(name) def add_all_qubit_quantum_error(self, error, instructions, warnings=True): @@ -646,20 +716,23 @@ def add_all_qubit_quantum_error(self, error, instructions, warnings=True): if warnings: logger.warning( "WARNING: all-qubit error already exists for " - "instruction \"%s\", " - "composing with additional error.", label) + 'instruction "%s", ' + "composing with additional error.", + label, + ) else: self._default_quantum_errors[label] = error # Check if a specific qubit error has been applied for this instruction if label in self._local_quantum_errors: - local_qubits = self._keys2str( - self._local_quantum_errors[label].keys()) + local_qubits = self._keys2str(self._local_quantum_errors[label].keys()) if warnings: logger.warning( "WARNING: all-qubit error for instruction " - "\"%s\" will not apply to qubits: " - "%s as specific error already exists.", label, - local_qubits) + '"%s" will not apply to qubits: ' + "%s as specific error already exists.", + label, + local_qubits, + ) self._noise_instructions.add(label) self.add_basis_gates(name) @@ -691,7 +764,9 @@ def add_quantum_error(self, error, instructions, qubits, warnings=True): try: qubits = tuple(qubits) except TypeError as ex: - raise NoiseError("Qubits must be convertible to a tuple of integers") from ex + raise NoiseError( + "Qubits must be convertible to a tuple of integers" + ) from ex # Check if error is ideal and if so don't add to the noise model if error.ideal(): return @@ -712,17 +787,21 @@ def add_quantum_error(self, error, instructions, qubits, warnings=True): # Convert qubits list to hashable string if error.num_qubits != len(qubits): - raise NoiseError("Number of qubits ({}) does not match " - " the error size ({})".format( - len(qubits), error.num_qubits)) + raise NoiseError( + "Number of qubits ({}) does not match " + " the error size ({})".format(len(qubits), error.num_qubits) + ) if qubits in qubit_dict: new_error = qubit_dict[qubits].compose(error) qubit_dict[qubits] = new_error if warnings: logger.warning( "WARNING: quantum error already exists for " - "instruction \"%s\" on qubits %s " - ", appending additional error.", label, qubits) + 'instruction "%s" on qubits %s ' + ", appending additional error.", + label, + qubits, + ) else: qubit_dict[qubits] = error # Add updated dictionary @@ -732,9 +811,12 @@ def add_quantum_error(self, error, instructions, qubits, warnings=True): if label in self._default_quantum_errors: if warnings: logger.warning( - "WARNING: Specific error for instruction \"%s\" " + 'WARNING: Specific error for instruction "%s" ' "on qubits %s overrides previously defined " - "all-qubit error for these qubits.", label, qubits) + "all-qubit error for these qubits.", + label, + qubits, + ) self._noise_instructions.add(label) self.add_basis_gates(name) @@ -774,7 +856,8 @@ def add_all_qubit_readout_error(self, error, warnings=True): if warnings: logger.warning( "WARNING: all-qubit readout error already exists, " - "overriding with new readout error.") + "overriding with new readout error." + ) self._default_readout_error = error # Check if a specific qubit error has been applied for this instruction @@ -784,7 +867,9 @@ def add_all_qubit_readout_error(self, error, warnings=True): logger.warning( "WARNING: The all-qubit readout error will not " "apply to measure of qubits qubits: %s " - "as specific readout errors already exist.", local_qubits) + "as specific readout errors already exist.", + local_qubits, + ) self._noise_instructions.add("measure") def add_readout_error(self, error, qubits, warnings=True): @@ -813,7 +898,9 @@ def add_readout_error(self, error, qubits, warnings=True): try: qubits = tuple(qubits) except TypeError as ex: - raise NoiseError("Qubits must be convertible to a tuple of integers") from ex + raise NoiseError( + "Qubits must be convertible to a tuple of integers" + ) from ex # Check if error is ideal and if so don't add to the noise model if error.ideal(): @@ -827,13 +914,16 @@ def add_readout_error(self, error, qubits, warnings=True): if error.number_of_qubits != len(qubits): raise NoiseError( "Number of qubits ({}) does not match the readout " - "error size ({})".format(len(qubits), error.number_of_qubits)) + "error size ({})".format(len(qubits), error.number_of_qubits) + ) # Check if we are overriding a previous error if qubits in self._local_readout_errors: if warnings: logger.warning( "WARNING: readout error already exists for qubits " - "%s, overriding with new readout error.", qubits) + "%s, overriding with new readout error.", + qubits, + ) self._local_readout_errors[qubits] = error # Check if all-qubit readout error is already defined @@ -842,7 +932,9 @@ def add_readout_error(self, error, qubits, warnings=True): logger.warning( "WARNING: Specific readout error on qubits " "%s overrides previously defined " - "all-qubit readout error for these qubits.", qubits) + "all-qubit readout error for these qubits.", + qubits, + ) self._noise_instructions.add("measure") def to_dict(self, serializable=False): @@ -903,84 +995,94 @@ def from_dict(noise_dict): Raises: NoiseError: if dict cannot be converted to NoiseModel. """ - warn('from_dict has been deprecated as of qiskit-aer 0.10.0' - ' and will be removed no earlier than 3 months from that release date.', - DeprecationWarning, stacklevel=2) + warn( + "from_dict has been deprecated as of qiskit-aer 0.10.0" + " and will be removed no earlier than 3 months from that release date.", + DeprecationWarning, + stacklevel=2, + ) def inst_dic_list_to_circuit(dic_list): - num_qubits = max([max(dic['qubits']) for dic in dic_list]) + 1 + num_qubits = max([max(dic["qubits"]) for dic in dic_list]) + 1 circ = QuantumCircuit(num_qubits) for dic in dic_list: - if dic['name'] == 'reset': - circ.append(Reset(), qargs=dic['qubits']) - elif dic['name'] == 'kraus': - circ.append(Instruction(name='kraus', - num_qubits=len(dic['qubits']), - num_clbits=0, - params=dic['params']), - qargs=dic['qubits']) - elif dic['name'] == 'unitary': - circ.append(UnitaryGate(data=dic['params'][0]), - qargs=dic['qubits']) - elif dic['name'] == 'pauli': - circ.append(PauliGate(dic['params'][0]), - qargs=dic['qubits']) + if dic["name"] == "reset": + circ.append(Reset(), qargs=dic["qubits"]) + elif dic["name"] == "kraus": + circ.append( + Instruction( + name="kraus", + num_qubits=len(dic["qubits"]), + num_clbits=0, + params=dic["params"], + ), + qargs=dic["qubits"], + ) + elif dic["name"] == "unitary": + circ.append(UnitaryGate(data=dic["params"][0]), qargs=dic["qubits"]) + elif dic["name"] == "pauli": + circ.append(PauliGate(dic["params"][0]), qargs=dic["qubits"]) else: with catch_warnings(): filterwarnings( "ignore", category=DeprecationWarning, - module="qiskit_aer.noise.errors.errorutils" + module="qiskit_aer.noise.errors.errorutils", + ) + circ.append( + UnitaryGate( + label=dic["name"], + data=_standard_gate_unitary(dic["name"]), + ), + qargs=dic["qubits"], ) - circ.append(UnitaryGate(label=dic['name'], - data=_standard_gate_unitary(dic['name'])), - qargs=dic['qubits']) return circ # Return noise model noise_model = NoiseModel() # Get error terms - errors = noise_dict.get('errors', []) + errors = noise_dict.get("errors", []) for error in errors: - error_type = error['type'] + error_type = error["type"] # Add QuantumError - if error_type == 'qerror': - circuits = [inst_dic_list_to_circuit(dics) for dics in error['instructions']] - noise_ops = tuple(zip(circuits, error['probabilities'])) + if error_type == "qerror": + circuits = [ + inst_dic_list_to_circuit(dics) for dics in error["instructions"] + ] + noise_ops = tuple(zip(circuits, error["probabilities"])) qerror = QuantumError(noise_ops) - qerror._id = error.get('id', None) or qerror.id - instruction_names = error['operations'] - all_gate_qubits = error.get('gate_qubits', None) + qerror._id = error.get("id", None) or qerror.id + instruction_names = error["operations"] + all_gate_qubits = error.get("gate_qubits", None) if all_gate_qubits is not None: for gate_qubits in all_gate_qubits: # Add local quantum error noise_model.add_quantum_error( - qerror, - instruction_names, - gate_qubits, - warnings=False) + qerror, instruction_names, gate_qubits, warnings=False + ) else: # Add all-qubit quantum error noise_model.add_all_qubit_quantum_error( - qerror, instruction_names, warnings=False) + qerror, instruction_names, warnings=False + ) # Add ReadoutError - elif error_type == 'roerror': - probabilities = error['probabilities'] - all_gate_qubits = error.get('gate_qubits', None) + elif error_type == "roerror": + probabilities = error["probabilities"] + all_gate_qubits = error.get("gate_qubits", None) roerror = ReadoutError(probabilities) # Add local readout error if all_gate_qubits is not None: for gate_qubits in all_gate_qubits: noise_model.add_readout_error( - roerror, gate_qubits, warnings=False) + roerror, gate_qubits, warnings=False + ) # Add all-qubit readout error else: - noise_model.add_all_qubit_readout_error( - roerror, warnings=False) + noise_model.add_all_qubit_readout_error(roerror, warnings=False) # Invalid error type else: raise NoiseError("Invalid error type: {}".format(error_type)) @@ -996,12 +1098,12 @@ def _instruction_names_labels(self, instructions): # as the label if isinstance(inst, Instruction): name = inst.name - label = getattr(inst, 'label', inst.name) + label = getattr(inst, "label", inst.name) names_labels.append((name, label)) elif isinstance(inst, str): names_labels.append((inst, inst)) else: - raise NoiseError('Invalid instruction type {}'.format(inst)) + raise NoiseError("Invalid instruction type {}".format(inst)) return names_labels def _check_number_of_qubits(self, error, name): @@ -1017,9 +1119,11 @@ def _check_number_of_qubits(self, error, name): """ def error_message(gate_qubits): - msg = "{} qubit QuantumError".format(error.num_qubits) + \ - " cannot be applied to {} qubit".format(gate_qubits) + \ - " instruction \"{}\".".format(name) + msg = ( + "{} qubit QuantumError".format(error.num_qubits) + + " cannot be applied to {} qubit".format(gate_qubits) + + ' instruction "{}".'.format(name) + ) return msg if name in self._1qubit_instructions and error.num_qubits != 1: @@ -1041,29 +1145,30 @@ def _readout_errors_equal(self, other): return False # Check local readout errors are equal if sorted(self._local_readout_errors.keys()) != sorted( - other._local_readout_errors.keys()): + other._local_readout_errors.keys() + ): return False for key in self._local_readout_errors: - if self._local_readout_errors[key] != other._local_readout_errors[ - key]: + if self._local_readout_errors[key] != other._local_readout_errors[key]: return False return True def _all_qubit_quantum_errors_equal(self, other): """Check two noise models have equal local quantum errors""" if sorted(self._default_quantum_errors.keys()) != sorted( - other._default_quantum_errors.keys()): + other._default_quantum_errors.keys() + ): return False for key in self._default_quantum_errors: - if self._default_quantum_errors[ - key] != other._default_quantum_errors[key]: + if self._default_quantum_errors[key] != other._default_quantum_errors[key]: return False return True def _local_quantum_errors_equal(self, other): """Check two noise models have equal local quantum errors""" if sorted(self._local_quantum_errors.keys()) != sorted( - other._local_quantum_errors.keys()): + other._local_quantum_errors.keys() + ): return False for key in self._local_quantum_errors: inner_dict1 = self._local_quantum_errors[key] @@ -1073,8 +1178,7 @@ def _local_quantum_errors_equal(self, other): for inner_key in inner_dict1: if inner_dict1[inner_key] != inner_dict2[inner_key]: return False - if self._local_quantum_errors[key] != other._local_quantum_errors[ - key]: + if self._local_quantum_errors[key] != other._local_quantum_errors[key]: return False return True @@ -1094,50 +1198,66 @@ def _pass_manager(self) -> Optional[PassManager]: def _standard_gate_unitary(name): # To be removed with from_dict unitary_matrices = { - ("id", "I"): - np.eye(2, dtype=complex), - ("x", "X"): - np.array([[0, 1], [1, 0]], dtype=complex), - ("y", "Y"): - np.array([[0, -1j], [1j, 0]], dtype=complex), - ("z", "Z"): - np.array([[1, 0], [0, -1]], dtype=complex), - ("h", "H"): - np.array([[1, 1], [1, -1]], dtype=complex) / np.sqrt(2), - ("s", "S"): - np.array([[1, 0], [0, 1j]], dtype=complex), - ("sdg", "Sdg"): - np.array([[1, 0], [0, -1j]], dtype=complex), - ("t", "T"): - np.array([[1, 0], [0, np.exp(1j * np.pi / 4)]], dtype=complex), - ("tdg", "Tdg"): - np.array([[1, 0], [0, np.exp(-1j * np.pi / 4)]], dtype=complex), - ("cx", "CX", "cx_01"): - np.array([[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]], dtype=complex), - ("cx_10",): - np.array([[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]], dtype=complex), - ("cz", "CZ"): - np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]], dtype=complex), - ("swap", "SWAP"): - np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]], dtype=complex), - ("ccx", "CCX", "ccx_012", "ccx_102"): - np.array([[1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 0, 0]], - dtype=complex), - ("ccx_021", "ccx_201"): - np.array([[1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1, 0, 0]], - dtype=complex), - ("ccx_120", "ccx_210"): - np.array([[1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0]], - dtype=complex) + ("id", "I"): np.eye(2, dtype=complex), + ("x", "X"): np.array([[0, 1], [1, 0]], dtype=complex), + ("y", "Y"): np.array([[0, -1j], [1j, 0]], dtype=complex), + ("z", "Z"): np.array([[1, 0], [0, -1]], dtype=complex), + ("h", "H"): np.array([[1, 1], [1, -1]], dtype=complex) / np.sqrt(2), + ("s", "S"): np.array([[1, 0], [0, 1j]], dtype=complex), + ("sdg", "Sdg"): np.array([[1, 0], [0, -1j]], dtype=complex), + ("t", "T"): np.array([[1, 0], [0, np.exp(1j * np.pi / 4)]], dtype=complex), + ("tdg", "Tdg"): np.array([[1, 0], [0, np.exp(-1j * np.pi / 4)]], dtype=complex), + ("cx", "CX", "cx_01"): np.array( + [[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]], dtype=complex + ), + ("cx_10",): np.array( + [[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]], dtype=complex + ), + ("cz", "CZ"): np.array( + [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]], dtype=complex + ), + ("swap", "SWAP"): np.array( + [[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]], dtype=complex + ), + ("ccx", "CCX", "ccx_012", "ccx_102"): np.array( + [ + [1, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0], + [0, 0, 0, 1, 0, 0, 0, 0], + ], + dtype=complex, + ), + ("ccx_021", "ccx_201"): np.array( + [ + [1, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 0, 1, 0], + [0, 0, 0, 0, 0, 1, 0, 0], + ], + dtype=complex, + ), + ("ccx_120", "ccx_210"): np.array( + [ + [1, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 0, 1, 0], + ], + dtype=complex, + ), } return next((value for key, value in unitary_matrices.items() if name in key), None) diff --git a/qiskit_aer/noise/noiseerror.py b/qiskit_aer/noise/noiseerror.py index 32edb0febf..cc3e5244c6 100644 --- a/qiskit_aer/noise/noiseerror.py +++ b/qiskit_aer/noise/noiseerror.py @@ -23,7 +23,7 @@ class NoiseError(QiskitError): def __init__(self, *message): """Set the error message.""" super().__init__(*message) - self.message = ' '.join(message) + self.message = " ".join(message) def __str__(self): """Return the message.""" diff --git a/qiskit_aer/noise/passes/local_noise_pass.py b/qiskit_aer/noise/passes/local_noise_pass.py index e141d6f685..23a59d6d81 100644 --- a/qiskit_aer/noise/passes/local_noise_pass.py +++ b/qiskit_aer/noise/passes/local_noise_pass.py @@ -53,10 +53,10 @@ def func( """ def __init__( - self, - func: Callable[[Instruction, Sequence[int]], Optional[InstructionLike]], - op_types: Optional[Union[type, Iterable[type]]] = None, - method: str = 'append' + self, + func: Callable[[Instruction, Sequence[int]], Optional[InstructionLike]], + op_types: Optional[Union[type, Iterable[type]]] = None, + method: str = "append", ): """Initialize noise pass. @@ -109,7 +109,9 @@ def run(self, dag: DAGCircuit) -> DAGCircuit: continue if isinstance(new_op, ReadoutError): - raise TranspilerError("Insertions of ReadoutError is not yet supported.") + raise TranspilerError( + "Insertions of ReadoutError is not yet supported." + ) # Initialize new node dag new_dag = DAGCircuit() @@ -118,7 +120,9 @@ def run(self, dag: DAGCircuit) -> DAGCircuit: # If appending re-apply original op node first if self._method == "append": - new_dag.apply_operation_back(node.op, qargs=node.qargs, cargs=node.cargs) + new_dag.apply_operation_back( + node.op, qargs=node.qargs, cargs=node.cargs + ) # If the new op is not a QuantumCircuit or Instruction, attempt # to conver to an Instruction @@ -144,14 +148,20 @@ def run(self, dag: DAGCircuit) -> DAGCircuit: if isinstance(new_op, QuantumCircuit): # If the new op is a quantum circuit, compose its DAG with the new dag # so that it is unrolled rather than added as an opaque instruction - new_dag.compose(circuit_to_dag(new_op), qubits=node.qargs) # never touch clbits + new_dag.compose( + circuit_to_dag(new_op), qubits=node.qargs + ) # never touch clbits else: # Otherwise append the instruction returned by the function - new_dag.apply_operation_back(new_op, qargs=node.qargs) # never touch cargs + new_dag.apply_operation_back( + new_op, qargs=node.qargs + ) # never touch cargs # If prepending reapply original op node last if self._method == "prepend": - new_dag.apply_operation_back(node.op, qargs=node.qargs, cargs=node.cargs) + new_dag.apply_operation_back( + node.op, qargs=node.qargs, cargs=node.cargs + ) dag.substitute_node_with_dag(node, new_dag) diff --git a/qiskit_aer/noise/passes/relaxation_noise_pass.py b/qiskit_aer/noise/passes/relaxation_noise_pass.py index b441ce6a3b..32e5accbaf 100644 --- a/qiskit_aer/noise/passes/relaxation_noise_pass.py +++ b/qiskit_aer/noise/passes/relaxation_noise_pass.py @@ -28,12 +28,12 @@ class RelaxationNoisePass(LocalNoisePass): """Add duration dependent thermal relaxation noise after instructions.""" def __init__( - self, - t1s: List[float], - t2s: List[float], - dt: Optional[float] = None, - op_types: Optional[Union[type, Sequence[type]]] = None, - excited_state_populations: Optional[List[float]] = None, + self, + t1s: List[float], + t2s: List[float], + dt: Optional[float] = None, + op_types: Optional[Union[type, Sequence[type]]] = None, + excited_state_populations: Optional[List[float]] = None, ): """Initialize RelaxationNoisePass. @@ -55,26 +55,28 @@ def __init__( else: self._p1s = np.zeros(len(t1s)) self._dt = dt - super().__init__(self._thermal_relaxation_error, op_types=op_types, method="append") + super().__init__( + self._thermal_relaxation_error, op_types=op_types, method="append" + ) - def _thermal_relaxation_error( - self, - op: Instruction, - qubits: Sequence[int] - ): + def _thermal_relaxation_error(self, op: Instruction, qubits: Sequence[int]): """Return thermal relaxation error on each operand qubit""" if not op.duration: if op.duration is None: - warnings.warn("RelaxationNoisePass ignores instructions without duration," - " you may need to schedule circuit in advance.", UserWarning) + warnings.warn( + "RelaxationNoisePass ignores instructions without duration," + " you may need to schedule circuit in advance.", + UserWarning, + ) return None # Convert op duration to seconds - if op.unit == 'dt': + if op.unit == "dt": if self._dt is None: raise NoiseError( "RelaxationNoisePass cannot apply noise to a 'dt' unit duration" - " without a dt time set.") + " without a dt time set." + ) duration = op.duration * self._dt else: duration = apply_prefix(op.duration, op.unit) diff --git a/qiskit_aer/primitives/estimator.py b/qiskit_aer/primitives/estimator.py index 1917d145e9..0e97cdc2f4 100644 --- a/qiskit_aer/primitives/estimator.py +++ b/qiskit_aer/primitives/estimator.py @@ -83,7 +83,9 @@ def __init__( backend_options = {} if backend_options is None else backend_options method = ( - "density_matrix" if approximation and "noise_model" in backend_options else "automatic" + "density_matrix" + if approximation and "noise_model" in backend_options + else "automatic" ) self._backend = AerSimulator(method=method) self._backend.set_options(**backend_options) @@ -144,10 +146,16 @@ def _run( observable_indices.append(index) else: observable_indices.append(len(self._observables)) - self._observable_ids[_observable_key(observable)] = len(self._observables) + self._observable_ids[_observable_key(observable)] = len( + self._observables + ) self._observables.append(observable) job = PrimitiveJob( - self._call, circuit_indices, observable_indices, parameter_values, **run_options + self._call, + circuit_indices, + observable_indices, + parameter_values, + **run_options, ) job.submit() return job @@ -159,7 +167,9 @@ def _compute(self, circuits, observables, parameter_values, run_options): # Create expectation value experiments. if key in self._cache: # Use a cache experiments_dict, obs_maps = self._cache[key] - exp_map = self._pre_process_params(circuits, observables, parameter_values, obs_maps) + exp_map = self._pre_process_params( + circuits, observables, parameter_values, obs_maps + ) experiments, parameter_binds = self._flatten(experiments_dict, exp_map) post_processings = self._create_post_processing( circuits, observables, parameter_values, obs_maps, exp_map @@ -171,7 +181,9 @@ def _compute(self, circuits, observables, parameter_values, run_options): for circ_ind, obs_ind in zip(circuits, observables): circ_obs_map[circ_ind].append(obs_ind) experiments_dict = {} - obs_maps = {} # circ_ind => obs_ind => term_ind (Original Pauli) => basis_ind + obs_maps = ( + {} + ) # circ_ind => obs_ind => term_ind (Original Pauli) => basis_ind # Group and create measurement circuit for circ_ind, obs_indices in circ_obs_map.items(): pauli_list = sum( @@ -190,9 +202,13 @@ def _compute(self, circuits, observables, parameter_values, run_options): break obs_maps[circ_ind] = obs_map bases = [_paulis2basis(pauli_list) for pauli_list in pauli_lists] - if len(bases) == 1 and not bases[0].x.any() and not bases[0].z.any(): # identity + if ( + len(bases) == 1 and not bases[0].x.any() and not bases[0].z.any() + ): # identity break - meas_circuits = [self._create_meas_circuit(basis, circ_ind) for basis in bases] + meas_circuits = [ + self._create_meas_circuit(basis, circ_ind) for basis in bases + ] circuit = ( self._circuits[circ_ind] if self._skip_transpilation @@ -201,7 +217,9 @@ def _compute(self, circuits, observables, parameter_values, run_options): experiments_dict[circ_ind] = self._combine_circs(circuit, meas_circuits) self._cache[key] = experiments_dict, obs_maps - exp_map = self._pre_process_params(circuits, observables, parameter_values, obs_maps) + exp_map = self._pre_process_params( + circuits, observables, parameter_values, obs_maps + ) # Flatten experiments, parameter_binds = self._flatten(experiments_dict, exp_map) @@ -232,8 +250,12 @@ def _compute(self, circuits, observables, parameter_values, run_options): return EstimatorResult(np.real_if_close(expectation_values), list(metadata)) def _pre_process_params(self, circuits, observables, parameter_values, obs_maps): - exp_map = defaultdict(dict) # circ_ind => basis_ind => (parameter, parameter_values) - for circ_ind, obs_ind, param_val in zip(circuits, observables, parameter_values): + exp_map = defaultdict( + dict + ) # circ_ind => basis_ind => (parameter, parameter_values) + for circ_ind, obs_ind, param_val in zip( + circuits, observables, parameter_values + ): self._validate_parameter_length(param_val, circ_ind) parameter = self._parameters[circ_ind] for basis_ind in obs_maps[circ_ind][obs_ind]: @@ -296,7 +318,9 @@ def _combine_circs(circuit: QuantumCircuit, meas_circuits: list[QuantumCircuit]) return circs @staticmethod - def _calculate_result_index(circ_ind, obs_ind, term_ind, param_val, obs_maps, exp_map) -> int: + def _calculate_result_index( + circ_ind, obs_ind, term_ind, param_val, obs_maps, exp_map + ) -> int: basis_ind = obs_maps[circ_ind][obs_ind][term_ind] result_index = 0 @@ -314,12 +338,16 @@ def _create_post_processing( self, circuits, observables, parameter_values, obs_maps, exp_map ) -> list[_PostProcessing]: post_processings = [] - for circ_ind, obs_ind, param_val in zip(circuits, observables, parameter_values): + for circ_ind, obs_ind, param_val in zip( + circuits, observables, parameter_values + ): result_indices: list[int | None] = [] paulis = [] coeffs = [] observable = self._observables[obs_ind] - for term_ind, (pauli, coeff) in enumerate(zip(observable.paulis, observable.coeffs)): + for term_ind, (pauli, coeff) in enumerate( + zip(observable.paulis, observable.coeffs) + ): # Identity if not pauli.x.any() and not pauli.z.any(): result_indices.append(None) @@ -353,7 +381,9 @@ def _compute_with_approximation( experiments, experiment_data = self._cache[key] for i, j, value in zip(circuits, observables, parameter_values): self._validate_parameter_length(value, i) - parameter_binds.append({k: [v] for k, v in zip(self._parameters[i], value)}) + parameter_binds.append( + {k: [v] for k, v in zip(self._parameters[i], value)} + ) else: self._transpile_circuits(circuits) experiments = [] @@ -371,9 +401,13 @@ def _compute_with_approximation( circuit.save_expectation_value(observable, self._layouts[i]) else: for term_ind, pauli in enumerate(observable.paulis): - circuit.save_expectation_value(pauli, self._layouts[i], label=str(term_ind)) + circuit.save_expectation_value( + pauli, self._layouts[i], label=str(term_ind) + ) experiments.append(circuit) - parameter_binds.append({k: [v] for k, v in zip(self._parameters[i], value)}) + parameter_binds.append( + {k: [v] for k, v in zip(self._parameters[i], value)} + ) self._cache[key] = (experiments, experiment_data) parameter_binds = parameter_binds if any(parameter_binds) else None result = self._backend.run( @@ -382,9 +416,12 @@ def _compute_with_approximation( # Post processing (calculate expectation values) if shots is None: - expectation_values = [result.data(i)["expectation_value"] for i in range(len(circuits))] + expectation_values = [ + result.data(i)["expectation_value"] for i in range(len(circuits)) + ] metadata = [ - {"simulator_metadata": result.results[i].metadata} for i in range(len(experiments)) + {"simulator_metadata": result.results[i].metadata} + for i in range(len(experiments)) ] else: expectation_values = [] @@ -459,7 +496,10 @@ def _expval_with_variance(counts) -> tuple[float, float]: class _PostProcessing: def __init__( - self, result_indices: list[int], paulis: list[PauliList], coeffs: list[list[float]] + self, + result_indices: list[int], + paulis: list[PauliList], + coeffs: list[list[float]], ): self._result_indices = result_indices self._paulis = paulis @@ -477,10 +517,14 @@ def run(self, results: list[ExperimentResult]) -> tuple[float, dict]: combined_expval = 0.0 combined_var = 0.0 simulator_metadata = [] - for c_i, paulis, coeffs in zip(self._result_indices, self._paulis, self._coeffs): + for c_i, paulis, coeffs in zip( + self._result_indices, self._paulis, self._coeffs + ): if c_i is None: # Observable is identity - expvals, variances = np.array([1], dtype=complex), np.array([0], dtype=complex) + expvals, variances = np.array([1], dtype=complex), np.array( + [0], dtype=complex + ) shots = 0 else: result = results[c_i] @@ -511,7 +555,9 @@ def _update_metadata(circuit: QuantumCircuit, metadata: dict) -> QuantumCircuit: return circuit -def _pauli_expval_with_variance(counts: dict, paulis: PauliList) -> tuple[np.ndarray, np.ndarray]: +def _pauli_expval_with_variance( + counts: dict, paulis: PauliList +) -> tuple[np.ndarray, np.ndarray]: # Diag indices size = len(paulis) diag_inds = _paulis2inds(paulis) @@ -534,7 +580,9 @@ def _pauli_expval_with_variance(counts: dict, paulis: PauliList) -> tuple[np.nda def _paulis2inds(paulis: PauliList) -> list[int]: nonid = paulis.z | paulis.x - packed_vals = np.packbits(nonid, axis=1, bitorder="little").astype( # pylint:disable=no-member + packed_vals = np.packbits( + nonid, axis=1, bitorder="little" + ).astype( # pylint:disable=no-member object ) power_uint8 = 1 << (8 * np.arange(packed_vals.shape[1], dtype=object)) diff --git a/qiskit_aer/primitives/sampler.py b/qiskit_aer/primitives/sampler.py index e1b75cef39..d87a93b3d6 100644 --- a/qiskit_aer/primitives/sampler.py +++ b/qiskit_aer/primitives/sampler.py @@ -118,7 +118,9 @@ def _call( {f"{k:0{num_qubits}b}": v for k, v in probabilities.items()} ) quasis.append(quasi_dist) - metadata.append({"shots": None, "simulator_metadata": result.results[i].metadata}) + metadata.append( + {"shots": None, "simulator_metadata": result.results[i].metadata} + ) else: counts = result.get_counts(i) shots = sum(counts.values()) @@ -128,7 +130,9 @@ def _call( shots=shots, ) ) - metadata.append({"shots": shots, "simulator_metadata": result.results[i].metadata}) + metadata.append( + {"shots": shots, "simulator_metadata": result.results[i].metadata} + ) return SamplerResult(quasis, metadata) @@ -179,7 +183,9 @@ def _preprocess_circuit(circuit: QuantumCircuit): def _transpile(self, circuit_indices: Sequence[int], is_shots_none: bool): to_handle = [ - i for i in set(circuit_indices) if (i, is_shots_none) not in self._transpiled_circuits + i + for i in set(circuit_indices) + if (i, is_shots_none) not in self._transpiled_circuits ] if to_handle: circuits = (self._circuits[i] for i in to_handle) diff --git a/qiskit_aer/pulse/controllers/digest_pulse_qobj.py b/qiskit_aer/pulse/controllers/digest_pulse_qobj.py index a64d032423..d7d7317f5e 100644 --- a/qiskit_aer/pulse/controllers/digest_pulse_qobj.py +++ b/qiskit_aer/pulse/controllers/digest_pulse_qobj.py @@ -21,6 +21,7 @@ from qiskit.pulse import DriveChannel from ...aererror import AerError + # pylint: disable=no-name-in-module from .pulse_utils import oplist_to_array @@ -66,7 +67,7 @@ def __init__(self): def digest_pulse_qobj(qobj, channels, dt, qubit_list): - """ Given a PulseQobj (and other parameters), returns a DigestedPulseQobj + """Given a PulseQobj (and other parameters), returns a DigestedPulseQobj containing relevant extracted information Parameters: @@ -86,47 +87,54 @@ def digest_pulse_qobj(qobj, channels, dt, qubit_list): digested_qobj = DigestedPulseQobj() qobj_dict = qobj.to_dict() - qobj_config = qobj_dict['config'] + qobj_config = qobj_dict["config"] # extract schedule_los - if qobj_config.get('schedule_los') is not None: - for exp, schedule_lo in zip(qobj_dict['experiments'], qobj_config['schedule_los']): - if exp.get('config') is None: - exp['config'] = {} + if qobj_config.get("schedule_los") is not None: + for exp, schedule_lo in zip( + qobj_dict["experiments"], qobj_config["schedule_los"] + ): + if exp.get("config") is None: + exp["config"] = {} schedule_lo_list = [] for idx in qubit_list: freq = schedule_lo.get(DriveChannel(idx), None) if freq is None: - raise ValueError('''A qubit in the simulation is missing an entry in - schedule_los.''') + raise ValueError( + """A qubit in the simulation is missing an entry in + schedule_los.""" + ) schedule_lo_list.append(freq * 1e-9) - exp['config']['qubit_lo_freq'] = schedule_lo_list + exp["config"]["qubit_lo_freq"] = schedule_lo_list # raises errors for unsupported features _unsupported_errors(qobj_dict) - if 'memory_slots' not in qobj_config: - raise ValueError('Number of memory_slots must be specific in Qobj config') + if "memory_slots" not in qobj_config: + raise ValueError("Number of memory_slots must be specific in Qobj config") # set memory and measurement details - digested_qobj.shots = int(qobj_config.get('shots', 1024)) - digested_qobj.meas_level = int(qobj_config.get('meas_level', 2)) - digested_qobj.meas_return = qobj_config.get('meas_return', 'avg') - digested_qobj.memory_slots = qobj_config.get('memory_slots', 0) - digested_qobj.memory = qobj_config.get('memory', False) - digested_qobj.n_registers = qobj_config.get('n_registers', 0) + digested_qobj.shots = int(qobj_config.get("shots", 1024)) + digested_qobj.meas_level = int(qobj_config.get("meas_level", 2)) + digested_qobj.meas_return = qobj_config.get("meas_return", "avg") + digested_qobj.memory_slots = qobj_config.get("memory_slots", 0) + digested_qobj.memory = qobj_config.get("memory", False) + digested_qobj.n_registers = qobj_config.get("n_registers", 0) # set qubit_lo_freq as given in qobj - if 'qubit_lo_freq' in qobj_config and qobj_config['qubit_lo_freq'] != [np.inf]: + if "qubit_lo_freq" in qobj_config and qobj_config["qubit_lo_freq"] != [np.inf]: # qobj frequencies are divided by 1e9, so multiply back - digested_qobj.qubit_lo_freq = [freq * 1e9 for freq in qobj_config['qubit_lo_freq']] + digested_qobj.qubit_lo_freq = [ + freq * 1e9 for freq in qobj_config["qubit_lo_freq"] + ] # build pulse arrays from qobj - pulses, pulses_idx, pulse_dict = build_pulse_arrays(qobj_dict['experiments'], - qobj_config['pulse_library']) + pulses, pulses_idx, pulse_dict = build_pulse_arrays( + qobj_dict["experiments"], qobj_config["pulse_library"] + ) digested_qobj.pulse_array = pulses digested_qobj.pulse_indices = pulses_idx @@ -134,13 +142,10 @@ def digest_pulse_qobj(qobj, channels, dt, qubit_list): experiments = [] - for exp in qobj_dict['experiments']: - exp_struct = experiment_to_structs(exp, - channels, - pulses_idx, - pulse_dict, - dt, - qubit_list) + for exp in qobj_dict["experiments"]: + exp_struct = experiment_to_structs( + exp, channels, pulses_idx, pulse_dict, dt, qubit_list + ) experiments.append(exp_struct) digested_qobj.experiments = experiments @@ -149,7 +154,7 @@ def digest_pulse_qobj(qobj, channels, dt, qubit_list): def _unsupported_errors(qobj_dict): - """ Raises errors for untested/unsupported features. + """Raises errors for untested/unsupported features. Parameters: qobj_dict (dict): qobj in dictionary form @@ -159,26 +164,30 @@ def _unsupported_errors(qobj_dict): """ # Warnings that don't stop execution - warning_str = '{} are an untested feature, and therefore may not behave as expected.' - if _contains_pv_instruction(qobj_dict['experiments']): - raise AerError(warning_str.format('PersistentValue instructions')) + warning_str = ( + "{} are an untested feature, and therefore may not behave as expected." + ) + if _contains_pv_instruction(qobj_dict["experiments"]): + raise AerError(warning_str.format("PersistentValue instructions")) - error_str = '''{} are not directly supported by PulseSimulator. Convert to - explicit WaveForms to simulate.''' - if _contains_parametric_pulse(qobj_dict['experiments']): - raise AerError(error_str.format('Parametric Pulses')) + error_str = """{} are not directly supported by PulseSimulator. Convert to + explicit WaveForms to simulate.""" + if _contains_parametric_pulse(qobj_dict["experiments"]): + raise AerError(error_str.format("Parametric Pulses")) - error_str = '''Schedules contain {}, are not supported by PulseSimulator.''' - if _contains_frequency_instruction(qobj_dict['experiments']): - raise AerError(error_str.format('shift frequency and/or set frequency instructions')) + error_str = """Schedules contain {}, are not supported by PulseSimulator.""" + if _contains_frequency_instruction(qobj_dict["experiments"]): + raise AerError( + error_str.format("shift frequency and/or set frequency instructions") + ) - required_str = '{} are required for simulation, and none were specified.' - if not _contains_acquire_instruction(qobj_dict['experiments']): - raise AerError(required_str.format('Acquire instructions')) + required_str = "{} are required for simulation, and none were specified." + if not _contains_acquire_instruction(qobj_dict["experiments"]): + raise AerError(required_str.format("Acquire instructions")) def _contains_acquire_instruction(experiments): - """ Return True if the list of experiments contains an Acquire instruction + """Return True if the list of experiments contains an Acquire instruction Parameters: experiments (list): list of schedules Returns: @@ -187,14 +196,14 @@ def _contains_acquire_instruction(experiments): """ for exp in experiments: - for inst in exp['instructions']: - if inst['name'] == 'acquire': + for inst in exp["instructions"]: + if inst["name"] == "acquire": return True return False def _contains_pv_instruction(experiments): - """ Return True if the list of experiments contains a PersistentValue instruction. + """Return True if the list of experiments contains a PersistentValue instruction. Parameters: experiments (list): list of schedules @@ -203,14 +212,14 @@ def _contains_pv_instruction(experiments): Raises: """ for exp in experiments: - for inst in exp['instructions']: - if inst['name'] == 'pv': + for inst in exp["instructions"]: + if inst["name"] == "pv": return True return False def _contains_frequency_instruction(experiments): - """ Return True if the list of experiments contains either a set fruquency or shift + """Return True if the list of experiments contains either a set fruquency or shift frequency instruction. Parameters: @@ -220,8 +229,8 @@ def _contains_frequency_instruction(experiments): Raises: """ for exp in experiments: - for inst in exp['instructions']: - if inst['name'] == 'setf' or inst['name'] == 'shiftf': + for inst in exp["instructions"]: + if inst["name"] == "setf" or inst["name"] == "shiftf": return True return False @@ -236,14 +245,14 @@ def _contains_parametric_pulse(experiments): Raises: """ for exp in experiments: - for inst in exp['instructions']: - if inst['name'] == 'parametric_pulse': + for inst in exp["instructions"]: + if inst["name"] == "parametric_pulse": return True return False def build_pulse_arrays(experiments, pulse_library): - """ Build pulses and pulse_idx arrays, and a pulse_dict + """Build pulses and pulse_idx arrays, and a pulse_dict used in simulations and mapping of experimental pulse sequencies to pulse_idx sequencies and timings. @@ -261,22 +270,25 @@ def build_pulse_arrays(experiments, pulse_library): num_pulse = 0 for pulse in pulse_library: - pulse_dict[pulse['name']] = num_pulse - total_pulse_length += len(pulse['samples']) + pulse_dict[pulse["name"]] = num_pulse + total_pulse_length += len(pulse["samples"]) num_pulse += 1 idx = num_pulse + 1 # now go through experiments looking for PV gates pv_pulses = [] for exp in experiments: - for pulse in exp['instructions']: - if pulse['name'] == 'pv': - if pulse['val'] not in [pval[1] for pval in pv_pulses] and pulse['val'] != 0: - pv_pulses.append((pulse['val'], idx)) + for pulse in exp["instructions"]: + if pulse["name"] == "pv": + if ( + pulse["val"] not in [pval[1] for pval in pv_pulses] + and pulse["val"] != 0 + ): + pv_pulses.append((pulse["val"], idx)) idx += 1 total_pulse_length += 1 - pulse_dict['pv'] = pv_pulses + pulse_dict["pv"] = pv_pulses pulses = np.empty(total_pulse_length, dtype=complex) pulses_idx = np.zeros(idx + 1, dtype=np.uint32) @@ -284,9 +296,11 @@ def build_pulse_arrays(experiments, pulse_library): stop = 0 ind = 1 for _, pulse in enumerate(pulse_library): - stop = pulses_idx[ind - 1] + len(pulse['samples']) + stop = pulses_idx[ind - 1] + len(pulse["samples"]) pulses_idx[ind] = stop - oplist_to_array(format_pulse_samples(pulse['samples']), pulses, pulses_idx[ind - 1]) + oplist_to_array( + format_pulse_samples(pulse["samples"]), pulses, pulses_idx[ind - 1] + ) ind += 1 for pv in pv_pulses: @@ -320,7 +334,9 @@ def format_pulse_samples(pulse_samples): return [[samp.real, samp.imag] for samp in new_samples] -def experiment_to_structs(experiment, ham_chans, pulse_inds, pulse_to_int, dt, qubit_list=None): +def experiment_to_structs( + experiment, ham_chans, pulse_inds, pulse_to_int, dt, qubit_list=None +): """Converts an experiment to a better formatted structure Args: @@ -341,171 +357,184 @@ def experiment_to_structs(experiment, ham_chans, pulse_inds, pulse_to_int, dt, q # TO DO: Error check that operations are restricted to qubit list max_time = 0 structs = {} - structs['header'] = experiment['header'] - structs['channels'] = OrderedDict() + structs["header"] = experiment["header"] + structs["channels"] = OrderedDict() for chan_name in ham_chans: - structs['channels'][chan_name] = [[], []] - structs['acquire'] = [] - structs['cond'] = [] - structs['snapshot'] = [] - structs['tlist'] = [] - structs['can_sample'] = True + structs["channels"][chan_name] = [[], []] + structs["acquire"] = [] + structs["cond"] = [] + structs["snapshot"] = [] + structs["tlist"] = [] + structs["can_sample"] = True # set an experiment qubit_lo_freq if present in experiment - structs['qubit_lo_freq'] = None - if 'config' in experiment: - if ('qubit_lo_freq' in experiment['config'] and - experiment['config']['qubit_lo_freq'] is not None): - freq_list = experiment['config']['qubit_lo_freq'] + structs["qubit_lo_freq"] = None + if "config" in experiment: + if ( + "qubit_lo_freq" in experiment["config"] + and experiment["config"]["qubit_lo_freq"] is not None + ): + freq_list = experiment["config"]["qubit_lo_freq"] freq_list = [freq * 1e9 for freq in freq_list] - structs['qubit_lo_freq'] = freq_list + structs["qubit_lo_freq"] = freq_list # This is a list that tells us whether # the last PV pulse on a channel needs to # be assigned a final time based on the next pulse on that channel pv_needs_tf = [0] * len(ham_chans) # The instructions are time-ordered so just loop through them. - for inst in experiment['instructions']: + for inst in experiment["instructions"]: # Do D and U channels - if 'ch' in inst.keys() and inst['ch'][0] in ['d', 'u']: - chan_name = inst['ch'].upper() + if "ch" in inst.keys() and inst["ch"][0] in ["d", "u"]: + chan_name = inst["ch"].upper() if chan_name not in ham_chans.keys(): - raise ValueError('Channel {} is not in Hamiltonian model'.format(inst['ch'])) + raise ValueError( + "Channel {} is not in Hamiltonian model".format(inst["ch"]) + ) # If last pulse on channel was a PV then need to set # its final time to be start time of current pulse if pv_needs_tf[ham_chans[chan_name]]: - structs['channels'][chan_name][0][-3] = inst['t0'] * dt + structs["channels"][chan_name][0][-3] = inst["t0"] * dt pv_needs_tf[ham_chans[chan_name]] = 0 # Get condtional info - if 'conditional' in inst.keys(): - cond = inst['conditional'] + if "conditional" in inst.keys(): + cond = inst["conditional"] else: cond = -1 # PV's - if inst['name'] == 'pv': + if inst["name"] == "pv": # Get PV index - for pv in pulse_to_int['pv']: - if pv[0] == inst['val']: + for pv in pulse_to_int["pv"]: + if pv[0] == inst["val"]: index = pv[1] break - structs['channels'][chan_name][0].extend([inst['t0'] * dt, None, index, cond]) + structs["channels"][chan_name][0].extend( + [inst["t0"] * dt, None, index, cond] + ) pv_needs_tf[ham_chans[chan_name]] = 1 # ShiftPhase instructions - elif inst['name'] == 'fc': + elif inst["name"] == "fc": # get current phase value current_phase = 0 - if len(structs['channels'][chan_name][1]) > 0: - current_phase = structs['channels'][chan_name][1][-2] + if len(structs["channels"][chan_name][1]) > 0: + current_phase = structs["channels"][chan_name][1][-2] - structs['channels'][chan_name][1].extend([inst['t0'] * dt, - current_phase + inst['phase'], - cond]) + structs["channels"][chan_name][1].extend( + [inst["t0"] * dt, current_phase + inst["phase"], cond] + ) # SetPhase instruction - elif inst['name'] == 'setp': - structs['channels'][chan_name][1].extend([inst['t0'] * dt, - inst['phase'], - cond]) + elif inst["name"] == "setp": + structs["channels"][chan_name][1].extend( + [inst["t0"] * dt, inst["phase"], cond] + ) # Delay instruction - elif inst['name'] == 'delay': + elif inst["name"] == "delay": pass # nothing to be done in this case # A standard pulse else: - start = inst['t0'] * dt - pulse_int = pulse_to_int[inst['name']] + start = inst["t0"] * dt + pulse_int = pulse_to_int[inst["name"]] pulse_width = (pulse_inds[pulse_int + 1] - pulse_inds[pulse_int]) * dt stop = start + pulse_width - structs['channels'][chan_name][0].extend([start, stop, pulse_int, cond]) + structs["channels"][chan_name][0].extend([start, stop, pulse_int, cond]) max_time = max(max_time, stop) # Take care of acquires and snapshots (bfuncs added ) else: # measurements - if inst['name'] == 'acquire': + if inst["name"] == "acquire": # Better way?? qlist2 = [] mlist2 = [] if qubit_list is None: - qlist2 = inst['qubits'] - mlist2 = inst['memory_slot'] + qlist2 = inst["qubits"] + mlist2 = inst["memory_slot"] else: - for qind, qb in enumerate(inst['qubits']): + for qind, qb in enumerate(inst["qubits"]): if qb in qubit_list: qlist2.append(qb) - mlist2.append(inst['memory_slot'][qind]) - - acq_vals = [inst['t0'] * dt, - np.asarray(qlist2, dtype=np.uint32), - np.asarray(mlist2, dtype=np.uint32) - ] - if 'register_slot' in inst.keys(): - acq_vals.append(np.asarray(inst['register_slot'], - dtype=np.uint32)) + mlist2.append(inst["memory_slot"][qind]) + + acq_vals = [ + inst["t0"] * dt, + np.asarray(qlist2, dtype=np.uint32), + np.asarray(mlist2, dtype=np.uint32), + ] + if "register_slot" in inst.keys(): + acq_vals.append(np.asarray(inst["register_slot"], dtype=np.uint32)) else: acq_vals.append(None) - structs['acquire'].append(acq_vals) + structs["acquire"].append(acq_vals) # update max_time - max_time = max(max_time, (inst['t0'] + inst['duration']) * dt) + max_time = max(max_time, (inst["t0"] + inst["duration"]) * dt) # Add time to tlist - if inst['t0'] * dt not in structs['tlist']: - structs['tlist'].append(inst['t0'] * dt) + if inst["t0"] * dt not in structs["tlist"]: + structs["tlist"].append(inst["t0"] * dt) # conditionals - elif inst['name'] == 'bfunc': - bfun_vals = [inst['t0'] * dt, inst['mask'], inst['relation'], - inst['val'], inst['register']] - if 'memory' in inst.keys(): - bfun_vals.append(inst['memory']) + elif inst["name"] == "bfunc": + bfun_vals = [ + inst["t0"] * dt, + inst["mask"], + inst["relation"], + inst["val"], + inst["register"], + ] + if "memory" in inst.keys(): + bfun_vals.append(inst["memory"]) else: bfun_vals.append(None) - structs['cond'].append(acq_vals) + structs["cond"].append(acq_vals) # update max_time - max_time = max(max_time, inst['t0'] * dt) + max_time = max(max_time, inst["t0"] * dt) # Add time to tlist - if inst['t0'] * dt not in structs['tlist']: - structs['tlist'].append(inst['t0'] * dt) + if inst["t0"] * dt not in structs["tlist"]: + structs["tlist"].append(inst["t0"] * dt) # snapshots - elif inst['name'] == 'snapshot': - if inst['type'] != 'state': + elif inst["name"] == "snapshot": + if inst["type"] != "state": raise TypeError("Snapshots must be of type 'state'") - structs['snapshot'].append([inst['t0'] * dt, inst['label']]) + structs["snapshot"].append([inst["t0"] * dt, inst["label"]]) # Add time to tlist - if inst['t0'] * dt not in structs['tlist']: - structs['tlist'].append(inst['t0'] * dt) + if inst["t0"] * dt not in structs["tlist"]: + structs["tlist"].append(inst["t0"] * dt) # update max_time - max_time = max(max_time, inst['t0'] * dt) + max_time = max(max_time, inst["t0"] * dt) # If any PVs still need time then they are at the end # and should just go til final time ham_keys = list(ham_chans.keys()) for idx, pp in enumerate(pv_needs_tf): if pp: - structs['channels'][ham_keys[idx]][0][-3] = max_time + structs["channels"][ham_keys[idx]][0][-3] = max_time pv_needs_tf[idx] = 0 # Convert lists to numpy arrays - for key in structs['channels'].keys(): - structs['channels'][key][0] = np.asarray(structs['channels'][key][0], - dtype=float) - structs['channels'][key][1] = np.asarray(structs['channels'][key][1], - dtype=float) - - structs['tlist'] = np.asarray([0] + structs['tlist'], dtype=float) - - if structs['tlist'][-1] > structs['acquire'][-1][0]: - structs['can_sample'] = False + for key in structs["channels"].keys(): + structs["channels"][key][0] = np.asarray( + structs["channels"][key][0], dtype=float + ) + structs["channels"][key][1] = np.asarray( + structs["channels"][key][1], dtype=float + ) + + structs["tlist"] = np.asarray([0] + structs["tlist"], dtype=float) + + if structs["tlist"][-1] > structs["acquire"][-1][0]: + structs["can_sample"] = False return structs diff --git a/qiskit_aer/pulse/controllers/mc_controller.py b/qiskit_aer/pulse/controllers/mc_controller.py index 03e93faf1d..e53bdc1ca4 100644 --- a/qiskit_aer/pulse/controllers/mc_controller.py +++ b/qiskit_aer/pulse/controllers/mc_controller.py @@ -29,13 +29,13 @@ from qiskit.tools.parallel import parallel_map, CPU_COUNT from .pulse_sim_options import PulseSimOptions from .pulse_de_solver import setup_de_solver -from .pulse_utils import (occ_probabilities, write_shots_memory, spmv, cy_expect_psi) +from .pulse_utils import occ_probabilities, write_shots_memory, spmv, cy_expect_psi dznrm2 = get_blas_funcs("znrm2", dtype=np.float64) def run_monte_carlo_experiments(pulse_sim_desc, pulse_de_model, solver_options=None): - """ Runs monte carlo experiments for a given op_system + """Runs monte carlo experiments for a given op_system Parameters: pulse_sim_desc (PulseSimDescription): description of pulse simulation @@ -64,9 +64,9 @@ def run_monte_carlo_experiments(pulse_sim_desc, pulse_de_model, solver_options=N seed = pulse_sim_desc.seed or np.random.randint(np.iinfo(np.int32).max - 1) prng = np.random.RandomState(seed) for exp in pulse_sim_desc.experiments: - exp['seed'] = prng.randint(np.iinfo(np.int32).max - 1) + exp["seed"] = prng.randint(np.iinfo(np.int32).max - 1) - map_kwargs = {'num_processes': solver_options.num_cpus} + map_kwargs = {"num_processes": solver_options.num_cpus} exp_results = [] exp_times = [] @@ -76,16 +76,20 @@ def run_monte_carlo_experiments(pulse_sim_desc, pulse_de_model, solver_options=N for exp in pulse_sim_desc.experiments: start = time.time() - rng = np.random.RandomState(exp['seed']) + rng = np.random.RandomState(exp["seed"]) seeds = rng.randint(np.iinfo(np.int32).max - 1, size=pulse_sim_desc.shots) - exp_res = parallel_map(monte_carlo_evolution, - seeds, - task_args=(exp, - y0, - pulse_sim_desc, - pulse_de_model, - solver_options, ), - **map_kwargs) + exp_res = parallel_map( + monte_carlo_evolution, + seeds, + task_args=( + exp, + y0, + pulse_sim_desc, + pulse_de_model, + solver_options, + ), + **map_kwargs + ) # exp_results is a list for each shot # so transform back to an array of shots @@ -100,13 +104,10 @@ def run_monte_carlo_experiments(pulse_sim_desc, pulse_de_model, solver_options=N return exp_results, exp_times -def monte_carlo_evolution(seed, - exp, - y0, - pulse_sim_desc, - pulse_de_model, - solver_options=None): - """ Performs a single monte carlo run for the given op_system, experiment, and seed +def monte_carlo_evolution( + seed, exp, y0, pulse_sim_desc, pulse_de_model, solver_options=None +): + """Performs a single monte carlo run for the given op_system, experiment, and seed Parameters: seed (int): seed for random number generation @@ -126,12 +127,12 @@ def monte_carlo_evolution(seed, solver_options = PulseSimOptions() if solver_options is None else solver_options rng = np.random.RandomState(seed) - tlist = exp['tlist'] + tlist = exp["tlist"] # Init memory memory = np.zeros((1, pulse_sim_desc.memory_slots), dtype=np.uint8) # Get number of acquire - num_acq = len(exp['acquire']) + num_acq = len(exp["acquire"]) acq_idx = 0 collapse_times = [] @@ -167,18 +168,19 @@ def monte_carlo_evolution(seed, t_final = ODE.t while ii < solver_options.norm_steps: ii += 1 - t_guess = t_prev + \ - log(norm2_prev / rand_vals[0]) / \ - log(norm2_prev / norm2_psi) * (t_final - t_prev) + t_guess = t_prev + log(norm2_prev / rand_vals[0]) / log( + norm2_prev / norm2_psi + ) * (t_final - t_prev) ODE.y = y_prev ODE.t = t_prev ODE.integrate(t_guess, step=0) if not ODE.successful(): - raise Exception( - "Integration failed after adjusting step size!") - norm2_guess = dznrm2(ODE.y)**2 - if (abs(rand_vals[0] - norm2_guess) < - solver_options.norm_tol * rand_vals[0]): + raise Exception("Integration failed after adjusting step size!") + norm2_guess = dznrm2(ODE.y) ** 2 + if ( + abs(rand_vals[0] - norm2_guess) + < solver_options.norm_tol * rand_vals[0] + ): break if norm2_guess < rand_vals[0]: @@ -191,9 +193,11 @@ def monte_carlo_evolution(seed, y_prev = ODE.y norm2_prev = norm2_guess if ii > solver_options.norm_steps: - raise Exception("Norm tolerance not reached. " + - "Increase accuracy of ODE solver or " + - "Options.norm_steps.") + raise Exception( + "Norm tolerance not reached. " + + "Increase accuracy of ODE solver or " + + "Options.norm_steps." + ) collapse_times.append(ODE.t) # all constant collapse operators. @@ -214,11 +218,13 @@ def monte_carlo_evolution(seed, out_psi = ODE.y / dznrm2(ODE.y) for aind in range(acq_idx, num_acq): - if exp['acquire'][aind][0] == stop_time: - current_acq = exp['acquire'][aind] + if exp["acquire"][aind][0] == stop_time: + current_acq = exp["acquire"][aind] qubits = current_acq[1] memory_slots = current_acq[2] - probs = occ_probabilities(qubits, out_psi, pulse_sim_desc.measurement_ops) + probs = occ_probabilities( + qubits, out_psi, pulse_sim_desc.measurement_ops + ) rand_vals = rng.rand(memory_slots.shape[0]) write_shots_memory(memory, memory_slots, probs, rand_vals) acq_idx += 1 diff --git a/qiskit_aer/pulse/controllers/pulse_controller.py b/qiskit_aer/pulse/controllers/pulse_controller.py index 0e06c48adc..ee5f7189b4 100644 --- a/qiskit_aer/pulse/controllers/pulse_controller.py +++ b/qiskit_aer/pulse/controllers/pulse_controller.py @@ -32,7 +32,7 @@ def pulse_controller(qobj): - """ Interprets PulseQobj input, runs simulations, and returns results + """Interprets PulseQobj input, runs simulations, and returns results Parameters: qobj (PulseQobj): pulse qobj containing a list of pulse schedules @@ -59,12 +59,12 @@ def pulse_controller(qobj): # Get qubit list and number qubit_list = system_model.subsystem_list if qubit_list is None: - raise ValueError('Model must have a qubit list to simulate.') + raise ValueError("Model must have a qubit list to simulate.") n_qubits = len(qubit_list) # get Hamiltonian if system_model.hamiltonian is None: - raise ValueError('Model must have a Hamiltonian to simulate.') + raise ValueError("Model must have a Hamiltonian to simulate.") ham_model = system_model.hamiltonian # Extract DE model information @@ -80,19 +80,19 @@ def pulse_controller(qobj): estates = [op_gen.state(state) for state in ham_model._estates.T[:]] # initial state set here - if getattr(config, 'initial_state', None) is not None: + if getattr(config, "initial_state", None) is not None: pulse_sim_desc.initial_state = op_gen.state(config.initial_state) else: pulse_sim_desc.initial_state = estates[0] # Get dt if system_model.dt is None: - raise ValueError('System model must have a dt value to simulate.') + raise ValueError("System model must have a dt value to simulate.") pulse_de_model.dt = system_model.dt # Parse noise - noise_model = getattr(config, 'noise_model', None) + noise_model = getattr(config, "noise_model", None) # post warnings for unsupported features _unsupported_warnings(noise_model) @@ -108,10 +108,9 @@ def pulse_controller(qobj): # ############################### # ### Parse qobj_config settings # ############################### - digested_qobj = digest_pulse_qobj(qobj, - pulse_de_model.channels, - system_model.dt, - qubit_list) + digested_qobj = digest_pulse_qobj( + qobj, pulse_de_model.channels, system_model.dt, qubit_list + ) # extract simulation-description level qobj content pulse_sim_desc.shots = digested_qobj.shots @@ -133,43 +132,56 @@ def pulse_controller(qobj): # if it wasn't specified in the PulseQobj, draw from system_model if qubit_lo_freq is None: - default_freq = getattr(config, 'qubit_freq_est', [np.inf]) + default_freq = getattr(config, "qubit_freq_est", [np.inf]) if default_freq != [np.inf]: qubit_lo_freq = default_freq # if still None, or is the placeholder value draw from the Hamiltonian if qubit_lo_freq is None: qubit_lo_freq = system_model.hamiltonian.get_qubit_lo_from_drift() - if getattr(qobj.config, 'schedule_los', None) is None: - warn('Warning: qubit_lo_freq was not specified in PulseQobj and there is no default, ' - 'so it is being automatically determined from the drift Hamiltonian.') - - pulse_de_model.freqs = system_model.calculate_channel_frequencies(qubit_lo_freq=qubit_lo_freq) - pulse_de_model.calculate_channel_frequencies = system_model.calculate_channel_frequencies + if getattr(qobj.config, "schedule_los", None) is None: + warn( + "Warning: qubit_lo_freq was not specified in PulseQobj and there is no default, " + "so it is being automatically determined from the drift Hamiltonian." + ) + + pulse_de_model.freqs = system_model.calculate_channel_frequencies( + qubit_lo_freq=qubit_lo_freq + ) + pulse_de_model.calculate_channel_frequencies = ( + system_model.calculate_channel_frequencies + ) # ############################### # ### Parse backend_options # # solver-specific information should be extracted in the solver # ############################### - pulse_sim_desc.seed = int(config.seed) if hasattr(config, 'seed') else None - pulse_sim_desc.q_level_meas = int(getattr(config, 'q_level_meas', 1)) + pulse_sim_desc.seed = int(config.seed) if hasattr(config, "seed") else None + pulse_sim_desc.q_level_meas = int(getattr(config, "q_level_meas", 1)) # solver options - allowed_solver_options = ['atol', 'rtol', 'nsteps', 'max_step', - 'num_cpus', 'norm_tol', 'norm_steps', - 'method'] - solver_options = getattr(config, 'solver_options', {}) + allowed_solver_options = [ + "atol", + "rtol", + "nsteps", + "max_step", + "num_cpus", + "norm_tol", + "norm_steps", + "method", + ] + solver_options = getattr(config, "solver_options", {}) for key in solver_options: if key not in allowed_solver_options: - raise Exception('Invalid solver_option: {}'.format(key)) + raise Exception("Invalid solver_option: {}".format(key)) solver_options = PulseSimOptions(**solver_options) # Set the ODE solver max step to be the half the # width of the smallest pulse min_width = np.iinfo(np.int32).max for key, val in pulse_de_model.pulse_to_int.items(): - if key != 'pv': + if key != "pv": stop = pulse_de_model.pulse_indices[val + 1] start = pulse_de_model.pulse_indices[val] min_width = min(min_width, stop - start) @@ -186,22 +198,24 @@ def pulse_controller(qobj): # Not sure if this will work for multiple measurements # Note: the extraction of multiple measurements works, but the simulation routines # themselves implicitly assume there is only one measurement at the end - if any(exp['acquire']): - for acq in exp['acquire']: + if any(exp["acquire"]): + for acq in exp["acquire"]: for jj in acq[1]: if jj > qubit_list[-1]: continue if not pulse_sim_desc.measurement_ops[qubit_list.index(jj)]: q_level_meas = pulse_sim_desc.q_level_meas - pulse_sim_desc.measurement_ops[qubit_list.index(jj)] = \ - op_gen.qubit_occ_oper_dressed(jj, - estates, - h_osc=dim_osc, - h_qub=dim_qub, - level=q_level_meas - ) - - if not exp['can_sample']: + pulse_sim_desc.measurement_ops[ + qubit_list.index(jj) + ] = op_gen.qubit_occ_oper_dressed( + jj, + estates, + h_osc=dim_osc, + h_qub=dim_qub, + level=q_level_meas, + ) + + if not exp["can_sample"]: pulse_sim_desc.can_sample = False # trim measurement operators to relevant qubits once constructed @@ -211,20 +225,25 @@ def pulse_controller(qobj): meas_ops_reduced.append(op) pulse_sim_desc.measurement_ops = meas_ops_reduced - run_experiments = (run_unitary_experiments if pulse_sim_desc.can_sample - else run_monte_carlo_experiments) - exp_results, exp_times = run_experiments(pulse_sim_desc, pulse_de_model, solver_options) + run_experiments = ( + run_unitary_experiments + if pulse_sim_desc.can_sample + else run_monte_carlo_experiments + ) + exp_results, exp_times = run_experiments( + pulse_sim_desc, pulse_de_model, solver_options + ) output = { - 'results': format_exp_results(exp_results, exp_times, pulse_sim_desc), - 'success': True, - 'qobj_id': qobj.qobj_id + "results": format_exp_results(exp_results, exp_times, pulse_sim_desc), + "success": True, + "qobj_id": qobj.qobj_id, } return output def format_exp_results(exp_results, exp_times, pulse_sim_desc): - """ format simulation results + """format simulation results Parameters: exp_results (list): simulation results @@ -243,23 +262,24 @@ def format_exp_results(exp_results, exp_times, pulse_sim_desc): m_ret = pulse_sim_desc.meas_return # populate the results dictionary - results = {'seed_simulator': exp['seed'], - 'shots': pulse_sim_desc.shots, - 'status': 'DONE', - 'success': True, - 'time_taken': exp_times[idx_exp], - 'header': exp['header'], - 'meas_level': m_lev, - 'meas_return': m_ret, - 'data': {}} + results = { + "seed_simulator": exp["seed"], + "shots": pulse_sim_desc.shots, + "status": "DONE", + "success": True, + "time_taken": exp_times[idx_exp], + "header": exp["header"], + "meas_level": m_lev, + "meas_return": m_ret, + "data": {}, + } if pulse_sim_desc.can_sample: memory = exp_results[idx_exp][0] - results['data']['statevector'] = [] + results["data"]["statevector"] = [] for coef in exp_results[idx_exp][1]: - results['data']['statevector'].append([np.real(coef), - np.imag(coef)]) - results['header']['ode_t'] = exp_results[idx_exp][2] + results["data"]["statevector"].append([np.real(coef), np.imag(coef)]) + results["header"]["ode_t"] = exp_results[idx_exp][2] else: memory = exp_results[idx_exp] @@ -268,13 +288,12 @@ def format_exp_results(exp_results, exp_times, pulse_sim_desc): # convert the memory **array** into a n # integer # e.g. [1,0] -> 2 - int_mem = memory.dot(np.power(2.0, - np.arange(memory.shape[1]))).astype(int) + int_mem = memory.dot(np.power(2.0, np.arange(memory.shape[1]))).astype(int) # if the memory flag is set return each shot if pulse_sim_desc.memory: hex_mem = [hex(val) for val in int_mem] - results['data']['memory'] = hex_mem + results["data"]["memory"] = hex_mem # Get hex counts dict unique = np.unique(int_mem, return_counts=True) @@ -282,32 +301,33 @@ def format_exp_results(exp_results, exp_times, pulse_sim_desc): for kk in range(unique[0].shape[0]): key = hex(unique[0][kk]) hex_dict[key] = unique[1][kk] - results['data']['counts'] = hex_dict + results["data"]["counts"] = hex_dict # meas_level 1 returns the elif m_lev == 1: - if m_ret == 'avg': + if m_ret == "avg": memory = [np.mean(memory, 0)] # convert into the right [real, complex] pair form for json - results['data']['memory'] = [] + results["data"]["memory"] = [] for mem_shot in memory: - results['data']['memory'].append([]) + results["data"]["memory"].append([]) for mem_slot in mem_shot: - results['data']['memory'][-1].append( - [np.real(mem_slot), np.imag(mem_slot)]) + results["data"]["memory"][-1].append( + [np.real(mem_slot), np.imag(mem_slot)] + ) - if m_ret == 'avg': - results['data']['memory'] = results['data']['memory'][0] + if m_ret == "avg": + results["data"]["memory"] = results["data"]["memory"][0] all_results.append(results) return all_results def _unsupported_warnings(noise_model): - """ Warns the user about untested/unsupported features. + """Warns the user about untested/unsupported features. Parameters: noise_model (dict): backend_options for simulation @@ -317,14 +337,15 @@ def _unsupported_warnings(noise_model): """ # Warnings that don't stop execution - warning_str = '{} are an untested feature, and therefore may not behave as expected.' + warning_str = ( + "{} are an untested feature, and therefore may not behave as expected." + ) if noise_model is not None: - warn(warning_str.format('Noise models')) + warn(warning_str.format("Noise models")) class PulseInternalDEModel: - """Container of information required for de RHS construction - """ + """Container of information required for de RHS construction""" def __init__(self): # The system Hamiltonian in numerical format @@ -372,8 +393,7 @@ def __init__(self): self._rhs_dict = None def _config_internal_data(self): - """Preps internal data into format required by RHS function. - """ + """Preps internal data into format required by RHS function.""" self.vars = list(self.variables.values()) # Need this info for evaluating the hamiltonian vars in the c++ solver @@ -411,14 +431,16 @@ def _config_internal_data(self): # construct data sets self.h_ops_data = [-1.0j * hpart.data for hpart in H] - self._rhs_dict = {'freqs': list(self.freqs.values()), - 'pulse_array': self.pulse_array, - 'pulse_indices': self.pulse_indices, - 'vars': self.vars, - 'vars_names': self.vars_names, - 'num_h_terms': self.num_h_terms, - 'h_ops_data': self.h_ops_data, - 'h_diag_elems': self.h_diag_elems} + self._rhs_dict = { + "freqs": list(self.freqs.values()), + "pulse_array": self.pulse_array, + "pulse_indices": self.pulse_indices, + "vars": self.vars, + "vars_names": self.vars_names, + "num_h_terms": self.num_h_terms, + "h_ops_data": self.h_ops_data, + "h_diag_elems": self.h_diag_elems, + } def init_rhs(self, exp): """Set up and return rhs function corresponding to this model for a given @@ -434,8 +456,12 @@ def init_rhs(self, exp): # Init register register = np.ones(self.n_registers, dtype=np.uint8) - rhs_dict = setup_rhs_dict_freqs(self._rhs_dict, exp, self.calculate_channel_frequencies) - ode_rhs_obj = get_ode_rhs_functor(rhs_dict, exp, self.system, channels, register) + rhs_dict = setup_rhs_dict_freqs( + self._rhs_dict, exp, self.calculate_channel_frequencies + ) + ode_rhs_obj = get_ode_rhs_functor( + rhs_dict, exp, self.system, channels, register + ) def rhs(t, y): return ode_rhs_obj(t, y) @@ -443,9 +469,9 @@ def rhs(t, y): return rhs -def setup_rhs_dict_freqs(default_rhs_dict: dict, - exp: dict, - calculate_channel_frequencies: Callable): +def setup_rhs_dict_freqs( + default_rhs_dict: dict, exp: dict, calculate_channel_frequencies: Callable +): """Standalone function for overriding channel frequencies in a given experiment. Args: @@ -458,19 +484,20 @@ def setup_rhs_dict_freqs(default_rhs_dict: dict, dict: Dictionary with frequencies potentially overriden by those in exp. """ - if 'qubit_lo_freq' in exp and exp['qubit_lo_freq'] is not None: + if "qubit_lo_freq" in exp and exp["qubit_lo_freq"] is not None: # copy to not overwrite defaults default_rhs_dict = copy(default_rhs_dict) - freqs_dict = calculate_channel_frequencies(exp['qubit_lo_freq']) - default_rhs_dict['freqs'] = list(freqs_dict.values()) + freqs_dict = calculate_channel_frequencies(exp["qubit_lo_freq"]) + default_rhs_dict["freqs"] = list(freqs_dict.values()) return default_rhs_dict class PulseSimDescription: - """ Object for holding any/all information required for simulation. + """Object for holding any/all information required for simulation. Needs to be refactored into different pieces. """ + def __init__(self): self.initial_state = None # Channels in the Hamiltonian string diff --git a/qiskit_aer/pulse/controllers/pulse_de_solver.py b/qiskit_aer/pulse/controllers/pulse_de_solver.py index 16c93b790b..ab6081f06b 100644 --- a/qiskit_aer/pulse/controllers/pulse_de_solver.py +++ b/qiskit_aer/pulse/controllers/pulse_de_solver.py @@ -24,7 +24,7 @@ def setup_de_solver(exp, y0, pulse_de_model, de_options): - """ Constructs a scipy ODE solver for a given exp and op_system + """Constructs a scipy ODE solver for a given exp and op_system Parameters: exp (dict): dict containing experiment description diff --git a/qiskit_aer/pulse/controllers/pulse_sim_options.py b/qiskit_aer/pulse/controllers/pulse_sim_options.py index 9357078803..94109d44ce 100644 --- a/qiskit_aer/pulse/controllers/pulse_sim_options.py +++ b/qiskit_aer/pulse/controllers/pulse_sim_options.py @@ -17,7 +17,7 @@ from ..de.DE_Options import DE_Options -class PulseSimOptions(): +class PulseSimOptions: """ Class of options for pulse solver routines. Options can be specified either as arguments to the constructor:: @@ -54,35 +54,39 @@ class PulseSimOptions(): of the evolution. """ - def __init__(self, - method='zvode-adams', - atol=1e-8, - rtol=1e-6, - order=12, - nsteps=10**6, - first_step=None, - max_step=None, - min_step=None, - max_dt=10**-3, - num_cpus=0, - norm_tol=1e-3, - norm_steps=5, - progress_bar=True, - shots=1024, - store_final_state=False, - seeds=None, - reuse_seeds=False): + def __init__( + self, + method="zvode-adams", + atol=1e-8, + rtol=1e-6, + order=12, + nsteps=10**6, + first_step=None, + max_step=None, + min_step=None, + max_dt=10**-3, + num_cpus=0, + norm_tol=1e-3, + norm_steps=5, + progress_bar=True, + shots=1024, + store_final_state=False, + seeds=None, + reuse_seeds=False, + ): # set DE specific options - self.de_options = DE_Options(method=method, - atol=atol, - rtol=rtol, - order=order, - nsteps=nsteps, - first_step=first_step, - max_step=max_step, - min_step=min_step, - max_dt=max_dt) + self.de_options = DE_Options( + method=method, + atol=atol, + rtol=rtol, + order=order, + nsteps=nsteps, + first_step=first_step, + max_step=max_step, + min_step=min_step, + max_dt=max_dt, + ) self.shots = shots self.seeds = seeds @@ -95,23 +99,25 @@ def __init__(self, def copy(self): """Create a copy.""" - return PulseSimOptions(method=self.de_options.method, - atol=self.de_options.atol, - rtol=self.de_options.rtol, - order=self.de_options.order, - nsteps=self.de_options.nsteps, - first_step=self.de_options.first_step, - max_step=self.de_options.max_step, - min_step=self.de_options.min_step, - max_dt=self.de_options.max_dt, - num_cpus=self.num_cpus, - norm_tol=self.norm_tol, - norm_steps=self.norm_steps, - progress_bar=self.progress_bar, - shots=self.shots, - store_final_state=self.store_final_state, - seeds=self.seeds, - reuse_seeds=self.reuse_seeds) + return PulseSimOptions( + method=self.de_options.method, + atol=self.de_options.atol, + rtol=self.de_options.rtol, + order=self.de_options.order, + nsteps=self.de_options.nsteps, + first_step=self.de_options.first_step, + max_step=self.de_options.max_step, + min_step=self.de_options.min_step, + max_dt=self.de_options.max_dt, + num_cpus=self.num_cpus, + norm_tol=self.norm_tol, + norm_steps=self.norm_steps, + progress_bar=self.progress_bar, + shots=self.shots, + store_final_state=self.store_final_state, + seeds=self.seeds, + reuse_seeds=self.reuse_seeds, + ) def __str__(self): return str(vars(self)) diff --git a/qiskit_aer/pulse/controllers/unitary_controller.py b/qiskit_aer/pulse/controllers/unitary_controller.py index 0397e12f25..002a7218e2 100644 --- a/qiskit_aer/pulse/controllers/unitary_controller.py +++ b/qiskit_aer/pulse/controllers/unitary_controller.py @@ -42,7 +42,7 @@ def _full_simulation(exp, y0, pulse_sim_desc, pulse_de_model, solver_options=Non # ############### # do measurement # ############### - rng = np.random.RandomState(exp['seed']) + rng = np.random.RandomState(exp["seed"]) shots = pulse_sim_desc.shots # Init memory @@ -50,13 +50,13 @@ def _full_simulation(exp, y0, pulse_sim_desc, pulse_de_model, solver_options=Non qubits = [] memory_slots = [] - tlist = exp['tlist'] - for acq in exp['acquire']: + tlist = exp["tlist"] + for acq in exp["acquire"]: if acq[0] == tlist[-1]: qubits += list(acq[1]) memory_slots += list(acq[2]) - qubits = np.array(qubits, dtype='uint32') - memory_slots = np.array(memory_slots, dtype='uint32') + qubits = np.array(qubits, dtype="uint32") + memory_slots = np.array(memory_slots, dtype="uint32") probs = occ_probabilities(qubits, psi, pulse_sim_desc.measurement_ops) rand_vals = rng.rand(memory_slots.shape[0] * shots) @@ -66,7 +66,7 @@ def _full_simulation(exp, y0, pulse_sim_desc, pulse_de_model, solver_options=Non def run_unitary_experiments(pulse_sim_desc, pulse_de_model, solver_options=None): - """ Runs unitary experiments for a given op_system + """Runs unitary experiments for a given op_system Parameters: pulse_sim_desc (PulseSimDescription): description of pulse simulation @@ -95,20 +95,29 @@ def run_unitary_experiments(pulse_sim_desc, pulse_de_model, solver_options=None) seed = pulse_sim_desc.seed or np.random.randint(np.iinfo(np.int32).max - 1) prng = np.random.RandomState(seed) for exp in pulse_sim_desc.experiments: - exp['seed'] = prng.randint(np.iinfo(np.int32).max - 1) + exp["seed"] = prng.randint(np.iinfo(np.int32).max - 1) - map_kwargs = {'num_processes': solver_options.num_cpus} + map_kwargs = {"num_processes": solver_options.num_cpus} # run simulation on each experiment in parallel start = time.time() - exp_results = parallel_map(_full_simulation, - pulse_sim_desc.experiments, - task_args=(y0, pulse_sim_desc, pulse_de_model, solver_options, ), - **map_kwargs - ) + exp_results = parallel_map( + _full_simulation, + pulse_sim_desc.experiments, + task_args=( + y0, + pulse_sim_desc, + pulse_de_model, + solver_options, + ), + **map_kwargs + ) end = time.time() - exp_times = (np.ones(len(pulse_sim_desc.experiments)) * - (end - start) / len(pulse_sim_desc.experiments)) + exp_times = ( + np.ones(len(pulse_sim_desc.experiments)) + * (end - start) + / len(pulse_sim_desc.experiments) + ) return exp_results, exp_times @@ -135,14 +144,14 @@ def unitary_evolution(exp, y0, pulse_de_model, solver_options=None): ODE = setup_de_solver(exp, y0, pulse_de_model, solver_options.de_options) - tlist = exp['tlist'] + tlist = exp["tlist"] for t in tlist[1:]: ODE.integrate(t) if ODE.successful(): psi = ODE.y / dznrm2(ODE.y) else: - err_msg = 'ODE method exited with status: %s' % ODE.return_code() + err_msg = "ODE method exited with status: %s" % ODE.return_code() raise Exception(err_msg) # apply final rotation to come out of rotating frame diff --git a/qiskit_aer/pulse/de/DE_Methods.py b/qiskit_aer/pulse/de/DE_Methods.py index f0994c4aaa..c746be5ede 100644 --- a/qiskit_aer/pulse/de/DE_Methods.py +++ b/qiskit_aer/pulse/de/DE_Methods.py @@ -45,7 +45,7 @@ class ODE_Method(ABC): rhs (dict): rhs-related functions as values Currently supports key 'rhs'. """ - method_spec = {'inner_state_spec': {'type': 'array'}} + method_spec = {"inner_state_spec": {"type": "array"}} def __init__(self, t0=None, y0=None, rhs=None, options=None): @@ -110,14 +110,14 @@ def y(self, new_y): self.set_y(new_y) def set_y(self, new_y, reset=True): - """Method for logic of setting internal state of solver with more control - """ + """Method for logic of setting internal state of solver with more control""" # instantiate internal StateTypeConverter based on the provided new_y and the # general type required internally by the solver - type_spec = self.method_spec.get('inner_state_spec') - self._state_type_converter = \ + type_spec = self.method_spec.get("inner_state_spec") + self._state_type_converter = ( StateTypeConverter.from_outer_instance_inner_type_spec(new_y, type_spec) + ) # set internal state self._y = self._state_type_converter.outer_to_inner(new_y) @@ -138,13 +138,15 @@ def set_rhs(self, rhs=None, reset=True): """ if rhs is None: - rhs = {'rhs': None} + rhs = {"rhs": None} if callable(rhs): - rhs = {'rhs': rhs} + rhs = {"rhs": rhs} - if 'rhs' not in rhs: - raise Exception('ODE_Method requires at minimum a specification of an rhs function.') + if "rhs" not in rhs: + raise Exception( + "ODE_Method requires at minimum a specification of an rhs function." + ) # transform rhs function into a function that accepts/returns inner state type self.rhs = self._state_type_converter.transform_rhs_funcs(rhs) @@ -198,26 +200,29 @@ class ScipyODE(ODE_Method): do not handle complex types """ - method_spec = {'inner_state_spec': {'type': 'array', 'ndim': 1}} + method_spec = {"inner_state_spec": {"type": "array", "ndim": 1}} def integrate(self, tf, **kwargs): - """Integrate up to a time tf. - """ + """Integrate up to a time tf.""" t0 = self.t y0 = self._y - rhs = self.rhs.get('rhs') + rhs = self.rhs.get("rhs") # solve problem and silence warnings for options that don't apply to a given method kept_warnings = [] with warnings.catch_warnings(record=True) as ws: - results = solve_ivp(rhs, (t0, tf), y0, - method=self.options.method, - atol=self.options.atol, - rtol=self.options.rtol, - max_step=self.options.max_step, - min_step=self.options.min_step, - first_step=self.options.first_step, - **kwargs) + results = solve_ivp( + rhs, + (t0, tf), + y0, + method=self.options.method, + atol=self.options.atol, + rtol=self.options.rtol, + max_step=self.options.max_step, + min_step=self.options.min_step, + first_step=self.options.first_step, + **kwargs + ) # update the internal state self._y = results.y[:, -1] @@ -225,7 +230,7 @@ def integrate(self, tf, **kwargs): # discard warnings for arguments with no effect for w in ws: - if 'The following arguments have no effect' not in str(w.message): + if "The following arguments have no effect" not in str(w.message): kept_warnings.append(w) # display warnings we don't want to silence @@ -236,10 +241,10 @@ def set_options(self, options): # establish method if options is None: options = DE_Options() - options.method = 'RK45' + options.method = "RK45" else: options = options.copy() - if 'scipy-' in options.method: + if "scipy-" in options.method: options.method = options.method[6:] self.options = options @@ -256,13 +261,15 @@ class QiskitZVODE(ODE_Method): - Internally this """ - method_spec = {'inner_state_spec': {'type': 'array', 'ndim': 1}} + method_spec = {"inner_state_spec": {"type": "array", "ndim": 1}} def __init__(self, t0=None, y0=None, rhs=None, options=None): # all de specification arguments are necessary to instantiate scipy ode object if (t0 is None) or (y0 is None) or (rhs is None): - raise Exception('QiskitZVODE solver requires t0, y0, and rhs at instantiation.') + raise Exception( + "QiskitZVODE solver requires t0, y0, and rhs at instantiation." + ) # initialize internal attribute for storing scipy ode object self._ODE = None @@ -280,11 +287,11 @@ def t(self, new_t): self._reset_method() def set_y(self, new_y, reset=True): - """Method for logic of setting internal state of solver with more control - """ - type_spec = self.method_spec.get('inner_state_spec') - self._state_type_converter = \ + """Method for logic of setting internal state of solver with more control""" + type_spec = self.method_spec.get("inner_state_spec") + self._state_type_converter = ( StateTypeConverter.from_outer_instance_inner_type_spec(new_y, type_spec) + ) self._y = self._state_type_converter.outer_to_inner(new_y) @@ -297,27 +304,30 @@ def set_rhs(self, rhs=None, reset=True): """This set_rhs function fully instantiates the scipy ode object behind the scenes.""" if rhs is None: - rhs = {'rhs': None} + rhs = {"rhs": None} if callable(rhs): - rhs = {'rhs': rhs} + rhs = {"rhs": rhs} - if 'rhs' not in rhs: - raise Exception('ODE_Method requires at minimum a specification of an rhs function.') + if "rhs" not in rhs: + raise Exception( + "ODE_Method requires at minimum a specification of an rhs function." + ) self.rhs = self._state_type_converter.transform_rhs_funcs(rhs) - self._ODE = ode(self.rhs['rhs']) + self._ODE = ode(self.rhs["rhs"]) - self._ODE._integrator = qiskit_zvode(method=self.options.method, - order=self.options.order, - atol=self.options.atol, - rtol=self.options.rtol, - nsteps=self.options.nsteps, - first_step=self.options.first_step, - min_step=self.options.min_step, - max_step=self.options.max_step - ) + self._ODE._integrator = qiskit_zvode( + method=self.options.method, + order=self.options.order, + atol=self.options.atol, + rtol=self.options.rtol, + nsteps=self.options.nsteps, + first_step=self.options.first_step, + min_step=self.options.min_step, + max_step=self.options.max_step, + ) # Forces complex ODE solving if not self._ODE._y: @@ -339,7 +349,7 @@ def integrate(self, tf, **kwargs): single step of the solver """ - step = kwargs.get('step', False) + step = kwargs.get("step", False) self._ODE.integrate(tf, step=step) @@ -359,10 +369,10 @@ def _reset_method(self, reset=True): def set_options(self, options): # establish method if options is None: - options = DE_Options(method='adams') + options = DE_Options(method="adams") else: options = options.copy() - if 'zvode-' in options.method: + if "zvode-" in options.method: options.method = options.method[6:] # handle None-type defaults @@ -383,6 +393,7 @@ class qiskit_zvode(zvode): it always stops at a given time in tlist; by default, it over shoots the time. """ + def step(self, *args): itask = self.call_args[2] self.rwork[0] = args[4] @@ -399,8 +410,7 @@ class RK4(ODE_Method): """ def integrate(self, tf, **kwargs): - """Integrate up to a time tf. - """ + """Integrate up to a time tf.""" delta_t = tf - self.t steps = int((delta_t // self._max_dt) + 1) @@ -409,11 +419,10 @@ def integrate(self, tf, **kwargs): self._integration_step(h) def _integration_step(self, h): - """Integration step for RK4 - """ + """Integration step for RK4""" y0 = self._y t0 = self._t - rhs = self.rhs.get('rhs') + rhs = self.rhs.get("rhs") k1 = rhs(t0, y0) t_mid = t0 + (h / 2) @@ -421,7 +430,7 @@ def _integration_step(self, h): k3 = rhs(t_mid, y0 + (h * k2 / 2)) t_end = t0 + h k4 = rhs(t_end, y0 + h * k3) - self._y = y0 + (1. / 6) * h * (k1 + (2 * k2) + (2 * k3) + k4) + self._y = y0 + (1.0 / 6) * h * (k1 + (2 * k2) + (2 * k3) + k4) self._t = t_end def set_options(self, options): @@ -438,14 +447,12 @@ def method_from_string(method_str): method: instance of an ODE_Method object """ - if 'scipy-' in method_str: + if "scipy-" in method_str: return ScipyODE - if 'zvode-' in method_str: + if "zvode-" in method_str: return QiskitZVODE - method_dict = {'RK4': RK4, - 'scipy': ScipyODE, - 'zvode': QiskitZVODE} + method_dict = {"RK4": RK4, "scipy": ScipyODE, "zvode": QiskitZVODE} return method_dict.get(method_str) diff --git a/qiskit_aer/pulse/de/DE_Options.py b/qiskit_aer/pulse/de/DE_Options.py index 2825000d99..b75c13e781 100644 --- a/qiskit_aer/pulse/de/DE_Options.py +++ b/qiskit_aer/pulse/de/DE_Options.py @@ -45,16 +45,18 @@ class DE_Options: max_dt (float, 1e-3): Max step size for fixed step solver. """ - def __init__(self, - method='zvode-adams', - atol=1e-8, - rtol=1e-6, - order=12, - nsteps=10**6, - first_step=None, - max_step=None, - min_step=None, - max_dt=10**-3): + def __init__( + self, + method="zvode-adams", + atol=1e-8, + rtol=1e-6, + order=12, + nsteps=10**6, + first_step=None, + max_step=None, + min_step=None, + max_dt=10**-3, + ): self.method = method self.atol = atol @@ -68,15 +70,17 @@ def __init__(self, def copy(self): """Create a copy of the object.""" - return DE_Options(method=self.method, - atol=self.atol, - rtol=self.rtol, - order=self.order, - nsteps=self.nsteps, - first_step=self.first_step, - max_step=self.max_step, - min_step=self.min_step, - max_dt=self.max_dt) + return DE_Options( + method=self.method, + atol=self.atol, + rtol=self.rtol, + order=self.order, + nsteps=self.nsteps, + first_step=self.first_step, + max_step=self.max_step, + min_step=self.min_step, + max_dt=self.max_dt, + ) def __str__(self): return str(vars(self)) diff --git a/qiskit_aer/pulse/de/type_utils.py b/qiskit_aer/pulse/de/type_utils.py index 5d671c0637..568b36794b 100644 --- a/qiskit_aer/pulse/de/type_utils.py +++ b/qiskit_aer/pulse/de/type_utils.py @@ -43,7 +43,9 @@ def __init__(self, inner_type_spec, outer_type_spec=None): self.inner_type_spec = inner_type_spec - self.outer_type_spec = self.inner_type_spec if outer_type_spec is None else outer_type_spec + self.outer_type_spec = ( + self.inner_type_spec if outer_type_spec is None else outer_type_spec + ) @classmethod def from_instances(cls, inner_y, outer_y=None): @@ -90,27 +92,27 @@ def from_outer_instance_inner_type_spec(cls, outer_y, inner_type_spec=None): if inner_type_spec is None: return cls.from_instances(outer_y) - inner_type = inner_type_spec.get('type') + inner_type = inner_type_spec.get("type") if inner_type is None: raise Exception("inner_type_spec needs a 'type' key.") - if inner_type == 'array': + if inner_type == "array": outer_y_as_array = np.array(outer_y) # if a specific shape is given attempt to instantiate from a reshaped outer_y - shape = inner_type_spec.get('shape') + shape = inner_type_spec.get("shape") if shape is not None: return cls.from_instances(outer_y_as_array.reshape(shape), outer_y) # handle the case that ndim == 1 is given - ndim = inner_type_spec.get('ndim') + ndim = inner_type_spec.get("ndim") if ndim == 1: return cls.from_instances(outer_y_as_array.flatten(), outer_y) # if neither shape nor ndim is given, assume it can be an array of any shape return cls.from_instances(outer_y_as_array, outer_y) - raise Exception('inner_type_spec not a handled type.') + raise Exception("inner_type_spec not a handled type.") def inner_to_outer(self, y): """Convert a state of inner type to one of outer type.""" @@ -137,15 +139,16 @@ def transform_rhs_funcs(self, rhs_funcs): new_rhs_funcs = {} # transform standard rhs function - rhs = rhs_funcs.get('rhs') + rhs = rhs_funcs.get("rhs") if rhs is not None: + def new_rhs(t, y): outer_y = self.inner_to_outer(y) rhs_val = rhs(t, outer_y) return self.outer_to_inner(rhs_val) - new_rhs_funcs['rhs'] = new_rhs + new_rhs_funcs["rhs"] = new_rhs return new_rhs_funcs @@ -156,11 +159,11 @@ def convert_state(y, type_spec): new_y = None - if type_spec['type'] == 'array': + if type_spec["type"] == "array": # default array data type to complex - new_y = np.array(y, dtype=type_spec.get('dtype', 'complex')) + new_y = np.array(y, dtype=type_spec.get("dtype", "complex")) - shape = type_spec.get('shape') + shape = type_spec.get("shape") if shape is not None: new_y = new_y.reshape(shape) @@ -171,7 +174,7 @@ def type_spec_from_instance(y): """Determine type spec from an instance.""" type_spec = {} if isinstance(y, np.ndarray): - type_spec['type'] = 'array' - type_spec['shape'] = y.shape + type_spec["type"] = "array" + type_spec["shape"] = y.shape return type_spec diff --git a/qiskit_aer/pulse/system_models/duffing_model_generators.py b/qiskit_aer/pulse/system_models/duffing_model_generators.py index 4fc5431971..94fa372519 100644 --- a/qiskit_aer/pulse/system_models/duffing_model_generators.py +++ b/qiskit_aer/pulse/system_models/duffing_model_generators.py @@ -22,12 +22,9 @@ from .pulse_system_model import PulseSystemModel -def duffing_system_model(dim_oscillators, - oscillator_freqs, - anharm_freqs, - drive_strengths, - coupling_dict, - dt): +def duffing_system_model( + dim_oscillators, oscillator_freqs, anharm_freqs, drive_strengths, coupling_dict, dt +): r"""Returns a :class:`PulseSystemModel` representing a physical model for a collection of Duffing oscillators. @@ -120,25 +117,27 @@ def duffing_system_model(dim_oscillators, """ # set symbols for string generation - freq_symbol = 'v' - anharm_symbol = 'alpha' - drive_symbol = 'r' - coupling_symbol = 'j' + freq_symbol = "v" + anharm_symbol = "alpha" + drive_symbol = "r" + coupling_symbol = "j" coupling_edges = coupling_dict.keys() # construct coupling graph, and raise warning if coupling_edges contains duplicate edges coupling_graph = CouplingGraph(coupling_edges) if len(coupling_graph.graph) < len(coupling_edges): - warn('Warning: The coupling_dict contains diplicate edges, and the second appearance of \ - the same edge will be ignored.') + warn( + "Warning: The coupling_dict contains diplicate edges, and the second appearance of \ + the same edge will be ignored." + ) # construct the HamiltonianModel num_oscillators = len(oscillator_freqs) oscillators = list(range(num_oscillators)) oscillator_dims = [dim_oscillators] * num_oscillators - freq_symbols = _str_list_generator(freq_symbol + '{0}', oscillators) - anharm_symbols = _str_list_generator(anharm_symbol + '{0}', oscillators) - drive_symbols = _str_list_generator(drive_symbol + '{0}', oscillators) + freq_symbols = _str_list_generator(freq_symbol + "{0}", oscillators) + anharm_symbols = _str_list_generator(anharm_symbol + "{0}", oscillators) + drive_symbols = _str_list_generator(drive_symbol + "{0}", oscillators) sorted_coupling_edges = coupling_graph.sorted_graph # populate coupling strengths in sorted order (vertex indices are now also sorted within edges, # so this needs to be accounted for when retrieving weights from coupling_dict) @@ -149,21 +148,25 @@ def duffing_system_model(dim_oscillators, edge_strength = coupling_dict.get((edge[1], edge[0])) coupling_strengths.append(edge_strength) - coupling_symbols = _str_list_generator(coupling_symbol + '{0}{1}', *zip(*sorted_coupling_edges)) + coupling_symbols = _str_list_generator( + coupling_symbol + "{0}{1}", *zip(*sorted_coupling_edges) + ) cr_idx_dict = coupling_graph.two_way_graph_dict - hamiltonian_dict = _duffing_hamiltonian_dict(oscillators=oscillators, - oscillator_dims=oscillator_dims, - oscillator_freqs=oscillator_freqs, - freq_symbols=freq_symbols, - anharm_freqs=anharm_freqs, - anharm_symbols=anharm_symbols, - drive_strengths=drive_strengths, - drive_symbols=drive_symbols, - ordered_coupling_edges=sorted_coupling_edges, - coupling_strengths=coupling_strengths, - coupling_symbols=coupling_symbols, - cr_idx_dict=cr_idx_dict) + hamiltonian_dict = _duffing_hamiltonian_dict( + oscillators=oscillators, + oscillator_dims=oscillator_dims, + oscillator_freqs=oscillator_freqs, + freq_symbols=freq_symbols, + anharm_freqs=anharm_freqs, + anharm_symbols=anharm_symbols, + drive_strengths=drive_strengths, + drive_symbols=drive_symbols, + ordered_coupling_edges=sorted_coupling_edges, + coupling_strengths=coupling_strengths, + coupling_symbols=coupling_symbols, + cr_idx_dict=cr_idx_dict, + ) hamiltonian_model = HamiltonianModel.from_dict(hamiltonian_dict) @@ -171,28 +174,32 @@ def duffing_system_model(dim_oscillators, u_channel_lo = _cr_lo_list(cr_idx_dict) # construct and return the PulseSystemModel - return PulseSystemModel(hamiltonian=hamiltonian_model, - u_channel_lo=u_channel_lo, - control_channel_labels=coupling_graph.sorted_two_way_graph, - subsystem_list=oscillators, - dt=dt) + return PulseSystemModel( + hamiltonian=hamiltonian_model, + u_channel_lo=u_channel_lo, + control_channel_labels=coupling_graph.sorted_two_way_graph, + subsystem_list=oscillators, + dt=dt, + ) # Helper functions for creating pieces necessary to construct oscillator system models -def _duffing_hamiltonian_dict(oscillators, - oscillator_dims, - oscillator_freqs, - freq_symbols, - anharm_freqs, - anharm_symbols, - drive_strengths, - drive_symbols, - ordered_coupling_edges, - coupling_strengths, - coupling_symbols, - cr_idx_dict): +def _duffing_hamiltonian_dict( + oscillators, + oscillator_dims, + oscillator_freqs, + freq_symbols, + anharm_freqs, + anharm_symbols, + drive_strengths, + drive_symbols, + ordered_coupling_edges, + coupling_strengths, + coupling_symbols, + cr_idx_dict, +): """Creates a hamiltonian string dict for a duffing oscillator model Note, this function makes the following assumptions: @@ -227,19 +234,25 @@ def _duffing_hamiltonian_dict(oscillators, """ # single oscillator terms - hamiltonian_str = _single_duffing_drift_terms(freq_symbols, anharm_symbols, oscillators) + hamiltonian_str = _single_duffing_drift_terms( + freq_symbols, anharm_symbols, oscillators + ) hamiltonian_str += _drive_terms(drive_symbols, oscillators) # exchange terms if len(ordered_coupling_edges) > 0: - hamiltonian_str += _exchange_coupling_terms(coupling_symbols, ordered_coupling_edges) + hamiltonian_str += _exchange_coupling_terms( + coupling_symbols, ordered_coupling_edges + ) # cr terms if len(cr_idx_dict) > 0: driven_system_indices = [key[0] for key in cr_idx_dict.keys()] cr_drive_symbols = [drive_symbols[idx] for idx in driven_system_indices] cr_channel_idx = cr_idx_dict.values() - hamiltonian_str += _cr_terms(cr_drive_symbols, driven_system_indices, cr_channel_idx) + hamiltonian_str += _cr_terms( + cr_drive_symbols, driven_system_indices, cr_channel_idx + ) # construct vars dictionary var_dict = {} @@ -252,9 +265,11 @@ def _duffing_hamiltonian_dict(oscillators, for symbol, strength in zip(coupling_symbols, coupling_strengths): var_dict[symbol] = strength - dim_dict = {str(oscillator): dim for oscillator, dim in zip(oscillators, oscillator_dims)} + dim_dict = { + str(oscillator): dim for oscillator, dim in zip(oscillators, oscillator_dims) + } - return {'h_str': hamiltonian_str, 'vars': var_dict, 'qub': dim_dict} + return {"h_str": hamiltonian_str, "vars": var_dict, "qub": dim_dict} def _cr_lo_list(cr_idx_dict): @@ -293,13 +308,12 @@ def _single_duffing_drift_terms(freq_symbols, anharm_symbols, system_list): list: drift term strings """ - harm_terms = _str_list_generator('np.pi*(2*{0}-{1})*O{2}', - freq_symbols, - anharm_symbols, - system_list) - anharm_terms = _str_list_generator('np.pi*{0}*O{1}*O{1}', - anharm_symbols, - system_list) + harm_terms = _str_list_generator( + "np.pi*(2*{0}-{1})*O{2}", freq_symbols, anharm_symbols, system_list + ) + anharm_terms = _str_list_generator( + "np.pi*{0}*O{1}*O{1}", anharm_symbols, system_list + ) return harm_terms + anharm_terms @@ -314,9 +328,7 @@ def _drive_terms(drive_symbols, system_list): list: drive term strings """ - return _str_list_generator('2*np.pi*{0}*X{1}||D{1}', - drive_symbols, - system_list) + return _str_list_generator("2*np.pi*{0}*X{1}||D{1}", drive_symbols, system_list) def _exchange_coupling_terms(coupling_symbols, ordered_edges): @@ -331,10 +343,9 @@ def _exchange_coupling_terms(coupling_symbols, ordered_edges): idx1_list, idx2_list = zip(*list(ordered_edges)) - return _str_list_generator('2*np.pi*{0}*(Sp{1}*Sm{2}+Sm{1}*Sp{2})', - coupling_symbols, - idx1_list, - idx2_list) + return _str_list_generator( + "2*np.pi*{0}*(Sp{1}*Sm{2}+Sm{1}*Sp{2})", coupling_symbols, idx1_list, idx2_list + ) def _cr_terms(drive_symbols, driven_system_indices, u_channel_indices): @@ -348,10 +359,12 @@ def _cr_terms(drive_symbols, driven_system_indices, u_channel_indices): list: cr term strings """ - return _str_list_generator('2*np.pi*{0}*X{1}||U{2}', - drive_symbols, - driven_system_indices, - u_channel_indices) + return _str_list_generator( + "2*np.pi*{0}*X{1}||U{2}", + drive_symbols, + driven_system_indices, + u_channel_indices, + ) def _str_list_generator(str_template, *args): @@ -451,8 +464,10 @@ def __init__(self, edges): self.sorted_two_way_graph = two_way_graph_list # create the dictionary version - self.two_way_graph_dict = {self.sorted_two_way_graph[k]: k - for k in range(len(self.sorted_two_way_graph))} + self.two_way_graph_dict = { + self.sorted_two_way_graph[k]: k + for k in range(len(self.sorted_two_way_graph)) + } def sorted_edge_index(self, edge): """Given an edge, returns the index in self.sorted_graph. Order in edge does not matter. diff --git a/qiskit_aer/pulse/system_models/hamiltonian_model.py b/qiskit_aer/pulse/system_models/hamiltonian_model.py index a4b6c90f1d..2da28b8b34 100644 --- a/qiskit_aer/pulse/system_models/hamiltonian_model.py +++ b/qiskit_aer/pulse/system_models/hamiltonian_model.py @@ -22,13 +22,10 @@ from .string_model_parser.string_model_parser import HamiltonianParser -class HamiltonianModel(): +class HamiltonianModel: """Hamiltonian model for pulse simulator.""" - def __init__(self, - system=None, - variables=None, - subsystem_dims=None): + def __init__(self, system=None, variables=None, subsystem_dims=None): """Initialize a Hamiltonian model. Args: @@ -65,7 +62,7 @@ def __init__(self, self._calculate_hamiltonian_channels() if len(self._channels) == 0: - raise AerError('HamiltonianModel must contain channels to simulate.') + raise AerError("HamiltonianModel must contain channels to simulate.") # populate self._h_diag, self._evals, self._estates self._compute_drift_data() @@ -89,51 +86,44 @@ def from_dict(cls, hamiltonian, subsystem_list=None): # get variables variables = OrderedDict() - if 'vars' in hamiltonian: - variables = OrderedDict(hamiltonian['vars']) + if "vars" in hamiltonian: + variables = OrderedDict(hamiltonian["vars"]) # Get qubit subspace dimensions - if 'qub' in hamiltonian: + if "qub" in hamiltonian: if subsystem_list is None: - subsystem_list = [int(qubit) for qubit in hamiltonian['qub']] + subsystem_list = [int(qubit) for qubit in hamiltonian["qub"]] else: # if user supplied, make a copy and sort it subsystem_list = subsystem_list.copy() subsystem_list.sort() # force keys in hamiltonian['qub'] to be ints - qub_dict = { - int(key): val - for key, val in hamiltonian['qub'].items() - } + qub_dict = {int(key): val for key, val in hamiltonian["qub"].items()} subsystem_dims = { - int(qubit): qub_dict[int(qubit)] - for qubit in subsystem_list + int(qubit): qub_dict[int(qubit)] for qubit in subsystem_list } else: subsystem_dims = {} # Get oscillator subspace dimensions - if 'osc' in hamiltonian: - oscillator_dims = { - int(key): val - for key, val in hamiltonian['osc'].items() - } + if "osc" in hamiltonian: + oscillator_dims = {int(key): val for key, val in hamiltonian["osc"].items()} else: oscillator_dims = {} # Parse the Hamiltonian - system = HamiltonianParser(h_str=hamiltonian['h_str'], - dim_osc=oscillator_dims, - dim_qub=subsystem_dims) + system = HamiltonianParser( + h_str=hamiltonian["h_str"], dim_osc=oscillator_dims, dim_qub=subsystem_dims + ) system.parse(subsystem_list) system = system.compiled return cls(system, variables, subsystem_dims) def get_qubit_lo_from_drift(self): - """ Computes a list of qubit frequencies corresponding to the exact energy + """Computes a list of qubit frequencies corresponding to the exact energy gap between the ground and first excited states of each qubit. If the keys in self._subsystem_dims skips over a qubit, it will default to outputting @@ -151,13 +141,14 @@ def get_qubit_lo_from_drift(self): for q_idx in self._subsystem_dims.keys(): single_excite = _first_excited_state(q_idx, self._subsystem_dims) dressed_eval = _eval_for_max_espace_overlap( - single_excite, self._evals, self._estates) + single_excite, self._evals, self._estates + ) qubit_lo_freq[q_idx] = (dressed_eval - min_eval) / (2 * np.pi) return qubit_lo_freq def _calculate_hamiltonian_channels(self): - """ Get all the qubit channels D_i and U_i in the string + """Get all the qubit channels D_i and U_i in the string representation of a system Hamiltonian. Raises: @@ -165,13 +156,12 @@ def _calculate_hamiltonian_channels(self): """ channels = [] for _, ham_str in self._system: - chan_idx = [ - i for i, letter in enumerate(ham_str) if letter in ['D', 'U'] - ] + chan_idx = [i for i, letter in enumerate(ham_str) if letter in ["D", "U"]] for ch in chan_idx: if (ch + 1) == len(ham_str) or not ham_str[ch + 1].isdigit(): - raise Exception('Channel name must include' + - 'an integer labeling the qubit.') + raise Exception( + "Channel name must include" + "an integer labeling the qubit." + ) for kk in chan_idx: done = False offset = 0 @@ -183,7 +173,7 @@ def _calculate_hamiltonian_channels(self): elif (kk + offset + 1) == len(ham_str): done = True offset += 1 - temp_chan = ham_str[kk:kk + offset] + temp_chan = ham_str[kk : kk + offset] if temp_chan not in channels: channels.append(temp_chan) channels.sort(key=lambda x: (int(x[1:]), x[0])) @@ -206,12 +196,12 @@ def _compute_drift_data(self): # Get the diagonal elements of the hamiltonian with all the # drive terms set to zero for chan in self._channels: - exec('%s=0' % chan) + exec("%s=0" % chan) # might be a better solution to replace the 'var' in the hamiltonian # string with 'op_system.vars[var]' for var in self._variables: - exec('%s=%f' % (var, self._variables[var])) + exec("%s=%f" % (var, self._variables[var])) full_dim = np.prod(list(self._subsystem_dims.values())) @@ -234,7 +224,7 @@ def _compute_drift_data(self): pos = np.argmax(np.abs(estate_copy)) pos_list.append(pos) - min_overlap = min(np.abs(estate_copy)[pos]**2, min_overlap) + min_overlap = min(np.abs(estate_copy)[pos] ** 2, min_overlap) evals_mapped[pos] = evals[i] estates_mapped[:, pos] = estate @@ -254,15 +244,17 @@ def _hamiltonian_pre_parse_exceptions(hamiltonian): AerError: if some part of the hamiltonian dictionary is unsupported """ - ham_str = hamiltonian.get('h_str', []) - if ham_str in ([], ['']): + ham_str = hamiltonian.get("h_str", []) + if ham_str in ([], [""]): raise AerError("Hamiltonian dict requires a non-empty 'h_str' entry.") - if hamiltonian.get('qub', {}) == {}: - raise AerError("Hamiltonian dict requires non-empty 'qub' entry with subsystem dimensions.") + if hamiltonian.get("qub", {}) == {}: + raise AerError( + "Hamiltonian dict requires non-empty 'qub' entry with subsystem dimensions." + ) - if hamiltonian.get('osc', {}) != {}: - raise AerError('Oscillator-type systems are not supported.') + if hamiltonian.get("osc", {}) != {}: + raise AerError("Oscillator-type systems are not supported.") def _first_excited_state(qubit_idx, subsystem_dims): @@ -279,7 +271,7 @@ def _first_excited_state(qubit_idx, subsystem_dims): Returns: vector: the state with qubit_idx in state 1, and the rest in state 0 """ - vector = np.array([1.]) + vector = np.array([1.0]) # iterate through qubits, tensoring on the state qubit_indices = [int(qubit) for qubit in subsystem_dims] qubit_indices.sort() diff --git a/qiskit_aer/pulse/system_models/pulse_system_model.py b/qiskit_aer/pulse/system_models/pulse_system_model.py index 74e8dde177..45cdac74cd 100644 --- a/qiskit_aer/pulse/system_models/pulse_system_model.py +++ b/qiskit_aer/pulse/system_models/pulse_system_model.py @@ -22,7 +22,7 @@ from .hamiltonian_model import HamiltonianModel -class PulseSystemModel(): +class PulseSystemModel: r"""Physical model object for pulse simulator. This class contains model information required by the @@ -51,12 +51,15 @@ class PulseSystemModel(): system_model = PulseSystemModel.from_backend(armonk_backend) """ - def __init__(self, - hamiltonian=None, - u_channel_lo=None, - control_channel_labels=None, - subsystem_list=None, - dt=None): + + def __init__( + self, + hamiltonian=None, + u_channel_lo=None, + control_channel_labels=None, + subsystem_list=None, + dt=None, + ): """Initialize a PulseSystemModel. Args: @@ -101,7 +104,7 @@ def from_backend(cls, backend, subsystem_list=None): config = backend.configuration() if not config.open_pulse: - raise AerError('{} is not an open pulse backend'.format(backend)) + raise AerError("{} is not an open pulse backend".format(backend)) return cls.from_config(config, subsystem_list) @@ -114,8 +117,8 @@ def from_config(cls, configuration, subsystem_list=None): subsystem_list = subsystem_list or list(range(configuration.n_qubits)) ham_string = configuration.hamiltonian hamiltonian = HamiltonianModel.from_dict(ham_string, subsystem_list) - u_channel_lo = getattr(configuration, 'u_channel_lo', None) - dt = getattr(configuration, 'dt', None) + u_channel_lo = getattr(configuration, "u_channel_lo", None) + dt = getattr(configuration, "dt", None) control_channel_labels = [None] * len(u_channel_lo) # populate control_channel_dict @@ -126,12 +129,12 @@ def from_config(cls, configuration, subsystem_list=None): # find drive index drive_idx = None while drive_idx is None: - u_str_label = 'U{0}'.format(str(u_idx)) - for h_term_str in ham_string['h_str']: + u_str_label = "U{0}".format(str(u_idx)) + for h_term_str in ham_string["h_str"]: # check if this string corresponds to this u channel if u_str_label in h_term_str: # get index of X operator drive term - x_idx = h_term_str.find('X') + x_idx = h_term_str.find("X") # if 'X' is found, and is not at the end of the string, drive_idx # is the subsequent character if x_idx != -1 and x_idx + 1 < len(h_term_str): @@ -139,23 +142,28 @@ def from_config(cls, configuration, subsystem_list=None): if drive_idx is not None: # construct string for u channel - u_string = '' + u_string = "" for u_term_dict in u_lo: - scale = getattr(u_term_dict, 'scale', [1.0, 0]) - q_idx = getattr(u_term_dict, 'q') + scale = getattr(u_term_dict, "scale", [1.0, 0]) + q_idx = getattr(u_term_dict, "q") if len(u_string) > 0: - u_string += ' + ' + u_string += " + " if isinstance(scale, complex): - u_string += str(scale) + 'q' + str(q_idx) + u_string += str(scale) + "q" + str(q_idx) else: - u_string += str(scale[0] + scale[1] * 1j) + 'q' + str(q_idx) - control_channel_labels[u_idx] = {'driven_q': drive_idx, 'freq': u_string} - - return cls(hamiltonian=hamiltonian, - u_channel_lo=u_channel_lo, - control_channel_labels=control_channel_labels, - subsystem_list=subsystem_list, - dt=dt) + u_string += str(scale[0] + scale[1] * 1j) + "q" + str(q_idx) + control_channel_labels[u_idx] = { + "driven_q": drive_idx, + "freq": u_string, + } + + return cls( + hamiltonian=hamiltonian, + u_channel_lo=u_channel_lo, + control_channel_labels=control_channel_labels, + subsystem_list=subsystem_list, + dt=dt, + ) def control_channel_index(self, label): """Return the index of the control channel with identifying label. @@ -167,7 +175,7 @@ def control_channel_index(self, label): int or None: index of the ControlChannel """ if label not in self.control_channel_labels: - warn('There is no listed ControlChannel matching the provided label.') + warn("There is no listed ControlChannel matching the provided label.") return None else: return self.control_channel_labels.index(label) @@ -195,9 +203,9 @@ def calculate_channel_frequencies(self, qubit_lo_freq=None): freqs = OrderedDict() for key in self.hamiltonian._channels: chidx = int(key[1:]) - if key[0] == 'D': + if key[0] == "D": freqs[key] = qubit_lo_freq[chidx] - elif key[0] == 'U': + elif key[0] == "U": freqs[key] = 0 for u_lo_idx in self.u_channel_lo[chidx]: if u_lo_idx.q < len(qubit_lo_freq): diff --git a/qiskit_aer/pulse/system_models/string_model_parser/apply_str_func_to_qobj.py b/qiskit_aer/pulse/system_models/string_model_parser/apply_str_func_to_qobj.py index 43cf12757a..4e4646fc26 100644 --- a/qiskit_aer/pulse/system_models/string_model_parser/apply_str_func_to_qobj.py +++ b/qiskit_aer/pulse/system_models/string_model_parser/apply_str_func_to_qobj.py @@ -19,16 +19,14 @@ def dag(qobj): - """ Qiskit wrapper of adjoint - """ + """Qiskit wrapper of adjoint""" return qobj.dag() def apply_func(name, qobj): - """ Apply function of given name, or do nothing if func not found - """ + """Apply function of given name, or do nothing if func not found""" return __funcdict.get(name, lambda x: x)(qobj) # pylint: disable=invalid-name -__funcdict = {'dag': dag} +__funcdict = {"dag": dag} diff --git a/qiskit_aer/pulse/system_models/string_model_parser/gen_operator.py b/qiskit_aer/pulse/system_models/string_model_parser/gen_operator.py index 0c04087e68..9c957ec486 100644 --- a/qiskit_aer/pulse/system_models/string_model_parser/gen_operator.py +++ b/qiskit_aer/pulse/system_models/string_model_parser/gen_operator.py @@ -64,7 +64,7 @@ def sigmax(): Returns: Operator: Operator representation for sigma x. """ - return Operator.from_label('X') + return Operator.from_label("X") def sigmay(): @@ -72,7 +72,7 @@ def sigmay(): Returns: Operator: Operator representation for sigma y. """ - return Operator.from_label('Y') + return Operator.from_label("Y") def sigmaz(): @@ -80,7 +80,7 @@ def sigmaz(): Returns: Operator: Operator representation for sigma z. """ - return Operator.from_label('Z') + return Operator.from_label("Z") def identity(dim): diff --git a/qiskit_aer/pulse/system_models/string_model_parser/operator_from_string.py b/qiskit_aer/pulse/system_models/string_model_parser/operator_from_string.py index dc485f9d22..e20dd810dd 100644 --- a/qiskit_aer/pulse/system_models/string_model_parser/operator_from_string.py +++ b/qiskit_aer/pulse/system_models/string_model_parser/operator_from_string.py @@ -35,26 +35,25 @@ def gen_oper(opname, index, h_osc, h_qub, states=None): opr_tmp = None # get number of levels in Hilbert space - if opname in ['X', 'Y', 'Z', 'Sp', 'Sm', 'I', 'O', 'P']: + if opname in ["X", "Y", "Z", "Sp", "Sm", "I", "O", "P"]: is_qubit = True dim = h_qub.get(index, 2) - if opname in ['X', 'Y', 'Z'] and dim > 2: - if opname == 'X': - opr_tmp = (op_gen.get_oper('A', dim) + - op_gen.get_oper('C', dim)) - elif opname == 'Y': - opr_tmp = (-1j * op_gen.get_oper('A', dim) + - 1j * op_gen.get_oper('C', dim)) + if opname in ["X", "Y", "Z"] and dim > 2: + if opname == "X": + opr_tmp = op_gen.get_oper("A", dim) + op_gen.get_oper("C", dim) + elif opname == "Y": + opr_tmp = -1j * op_gen.get_oper("A", dim) + 1j * op_gen.get_oper( + "C", dim + ) else: - opr_tmp = (op_gen.get_oper('I', dim) - - 2 * op_gen.get_oper('N', dim)) + opr_tmp = op_gen.get_oper("I", dim) - 2 * op_gen.get_oper("N", dim) else: is_qubit = False dim = h_osc.get(index, 5) - if opname == 'P': + if opname == "P": opr_tmp = op_gen.get_oper(opname, dim, states) else: if opr_tmp is None: diff --git a/qiskit_aer/pulse/system_models/string_model_parser/operator_generators.py b/qiskit_aer/pulse/system_models/string_model_parser/operator_generators.py index 3fbcd770fb..33c3edf7f9 100644 --- a/qiskit_aer/pulse/system_models/string_model_parser/operator_generators.py +++ b/qiskit_aer/pulse/system_models/string_model_parser/operator_generators.py @@ -21,99 +21,87 @@ def sigmax(dim=2): - """Qiskit wrapper of sigma-X operator. - """ + """Qiskit wrapper of sigma-X operator.""" if dim == 2: return gen_operator.sigmax() else: - raise Exception('Invalid level specification of the qubit subspace') + raise Exception("Invalid level specification of the qubit subspace") def sigmay(dim=2): - """Qiskit wrapper of sigma-Y operator. - """ + """Qiskit wrapper of sigma-Y operator.""" if dim == 2: return gen_operator.sigmay() else: - raise Exception('Invalid level specification of the qubit subspace') + raise Exception("Invalid level specification of the qubit subspace") def sigmaz(dim=2): - """Qiskit wrapper of sigma-Z operator. - """ + """Qiskit wrapper of sigma-Z operator.""" if dim == 2: return gen_operator.sigmaz() else: - raise Exception('Invalid level specification of the qubit subspace') + raise Exception("Invalid level specification of the qubit subspace") def sigmap(dim=2): - """Qiskit wrapper of sigma-plus operator. - """ + """Qiskit wrapper of sigma-plus operator.""" return gen_operator.create(dim) def sigmam(dim=2): - """Qiskit wrapper of sigma-minus operator. - """ + """Qiskit wrapper of sigma-minus operator.""" return gen_operator.destroy(dim) def create(dim): - """Qiskit wrapper of creation operator. - """ + """Qiskit wrapper of creation operator.""" return gen_operator.create(dim) def destroy(dim): - """Qiskit wrapper of annihilation operator. - """ + """Qiskit wrapper of annihilation operator.""" return gen_operator.destroy(dim) def num(dim): - """Qiskit wrapper of number operator. - """ + """Qiskit wrapper of number operator.""" return gen_operator.num(dim) def qeye(dim): - """Qiskit wrapper of identity operator. - """ + """Qiskit wrapper of identity operator.""" return gen_operator.identity(dim) def project(dim, states): - """Qiskit wrapper of projection operator. - """ + """Qiskit wrapper of projection operator.""" ket, bra = states if ket in range(dim) and bra in range(dim): return gen_operator.basis(dim, ket) * gen_operator.basis(dim, bra).adjoint() else: - raise Exception('States are specified on the outside of Hilbert space %s' % states) + raise Exception( + "States are specified on the outside of Hilbert space %s" % states + ) def tensor(list_qobj): - """ Qiskit wrapper of tensor product - """ + """Qiskit wrapper of tensor product""" return gen_operator.tensor(list_qobj) def basis(level, pos): - """ Qiskit wrapper of basis - """ + """Qiskit wrapper of basis""" return gen_operator.basis(level, pos) def state(state_vec): - """ Qiskit wrapper of qobj - """ + """Qiskit wrapper of qobj""" return gen_operator.state(state_vec) def fock_dm(level, eigv): - """ Qiskit wrapper of fock_dm - """ + """Qiskit wrapper of fock_dm""" return gen_operator.fock_dm(level, eigv) @@ -158,12 +146,20 @@ def qubit_occ_oper_dressed(target_qubit, estates, h_osc, h_qub, level=0): def get_oper(name, *args): - """ Return quantum operator of given name - """ + """Return quantum operator of given name""" return __operdict.get(name, qeye)(*args) -__operdict = {'X': sigmax, 'Y': sigmay, 'Z': sigmaz, - 'Sp': create, 'Sm': destroy, 'I': qeye, - 'O': num, 'P': project, 'A': destroy, - 'C': create, 'N': num} +__operdict = { + "X": sigmax, + "Y": sigmay, + "Z": sigmaz, + "Sp": create, + "Sm": destroy, + "I": qeye, + "O": num, + "P": project, + "A": destroy, + "C": create, + "N": num, +} diff --git a/qiskit_aer/pulse/system_models/string_model_parser/string_model_parser.py b/qiskit_aer/pulse/system_models/string_model_parser/string_model_parser.py index 312f4338f1..6396b8ee08 100644 --- a/qiskit_aer/pulse/system_models/string_model_parser/string_model_parser.py +++ b/qiskit_aer/pulse/system_models/string_model_parser/string_model_parser.py @@ -24,7 +24,7 @@ from .operator_from_string import gen_oper -Token = namedtuple('Token', ('type', 'name')) +Token = namedtuple("Token", ("type", "name")) ham_elements = OrderedDict( QubOpr=re.compile(r"(?PO|Sp|Sm|X|Y|Z|I)(?P[0-9]+)"), @@ -37,15 +37,15 @@ MathOrd0=re.compile(r"[*/]"), MathOrd1=re.compile(r"[+-]"), BrkL=re.compile(r"\("), - BrkR=re.compile(r"\)") + BrkR=re.compile(r"\)"), ) class HamiltonianParser: - """ Generate QuTip hamiltonian object from string - """ + """Generate QuTip hamiltonian object from string""" + def __init__(self, h_str, dim_osc, dim_qub): - """ Create new quantum operator generator + """Create new quantum operator generator Parameters: h_str (list): list of Hamiltonian string @@ -61,13 +61,11 @@ def __init__(self, h_str, dim_osc, dim_qub): @property def compiled(self): - """ Return Hamiltonian in OpenPulse handler format - """ + """Return Hamiltonian in OpenPulse handler format""" return self.__tc_hams + self.__td_hams def parse(self, qubit_list=None): - """ Parse and generate quantum class object - """ + """Parse and generate quantum class object""" self.__td_hams = [] self.__tc_hams = [] @@ -82,14 +80,14 @@ def parse(self, qubit_list=None): # find time-dependent term if p_td: - coef, token = self._tokenizer(p_td.group('opr'), qubit_list) + coef, token = self._tokenizer(p_td.group("opr"), qubit_list) if token is None: continue # combine coefficient to time-dependent term if coef: - td = '*'.join([coef, p_td.group('ch')]) + td = "*".join([coef, p_td.group("ch")]) else: - td = p_td.group('ch') + td = p_td.group("ch") token = self._shunting_yard(token) _td = self._token2qobj(token), td @@ -100,17 +98,18 @@ def parse(self, qubit_list=None): continue token = self._shunting_yard(token) - if (coef == '') or (coef is None): - coef = '1.' + if (coef == "") or (coef is None): + coef = "1." _tc = self._token2qobj(token), coef self.__tc_hams.append(_tc) def _expand_sum(self): - """ Takes a string-based Hamiltonian list and expands the _SUM action items out. - """ - sum_str = re.compile(r"_SUM\[(?P[a-z]),(?P[a-z\d{}+-]+),(?P[a-z\d{}+-]+),") + """Takes a string-based Hamiltonian list and expands the _SUM action items out.""" + sum_str = re.compile( + r"_SUM\[(?P[a-z]),(?P[a-z\d{}+-]+),(?P[a-z\d{}+-]+)," + ) brk_str = re.compile(r"]") ham_list = copy.copy(self.h_str) @@ -121,15 +120,15 @@ def _expand_sum(self): p_sums = list(sum_str.finditer(ham)) p_brks = list(brk_str.finditer(ham)) if len(p_sums) != len(p_brks): - raise Exception('Missing correct number of brackets in %s' % ham) + raise Exception("Missing correct number of brackets in %s" % ham) # find correct sum-bracket correspondence if any(p_sums) == 0: ham_out.append(ham) else: - itr = p_sums[0].group('itr') - _l = int(p_sums[0].group('l')) - _u = int(p_sums[0].group('u')) + itr = p_sums[0].group("itr") + _l = int(p_sums[0].group("l")) + _u = int(p_sums[0].group("u")) for ii in range(len(p_sums) - 1): if p_sums[ii + 1].end() > p_brks[ii].start(): break @@ -139,20 +138,25 @@ def _expand_sum(self): # substitute iterator value _temp = [] for kk in range(_l, _u + 1): - trg_s = ham[p_sums[0].end():p_brks[ii].start()] + trg_s = ham[p_sums[0].end() : p_brks[ii].start()] # generate replacement pattern pattern = {} for p in re.finditer(r"\{(?P[a-z0-9*/+-]+)\}", trg_s): if p.group() not in pattern: - sub = parse_binop(p.group('op_str'), operands={itr: str(kk)}) + sub = parse_binop( + p.group("op_str"), operands={itr: str(kk)} + ) if sub.isdecimal(): pattern[p.group()] = sub else: pattern[p.group()] = "{%s}" % sub for key, val in pattern.items(): trg_s = trg_s.replace(key, val) - _temp.append(''.join([ham[:p_sums[0].start()], - trg_s, ham[p_brks[ii].end():]])) + _temp.append( + "".join( + [ham[: p_sums[0].start()], trg_s, ham[p_brks[ii].end() :]] + ) + ) ham_list.extend(_temp) self.h_str = ham_out @@ -160,98 +164,99 @@ def _expand_sum(self): return ham_out def _tokenizer(self, op_str, qubit_list=None): - """ Convert string to token and coefficient + """Convert string to token and coefficient Check if the index is in qubit_list """ # generate token _op_str = copy.copy(op_str) token_list = [] - prev = 'none' + prev = "none" while any(_op_str): for key, parser in ham_elements.items(): p = parser.match(_op_str) if p: # find quantum operators - if key in ['QubOpr', 'CavOpr']: + if key in ["QubOpr", "CavOpr"]: _key = key _name = p.group() if p.group() not in self.__str2qopr.keys(): - idx = int(p.group('idx')) + idx = int(p.group("idx")) if qubit_list is not None and idx not in qubit_list: return 0, None - name = p.group('opr') + name = p.group("opr") opr = gen_oper(name, idx, self.dim_osc, self.dim_qub) self.__str2qopr[p.group()] = opr - elif key == 'PrjOpr': + elif key == "PrjOpr": _key = key _name = p.group() if p.group() not in self.__str2qopr.keys(): - idx = int(p.group('idx')) - name = 'P' - lvs = int(p.group('ket')), int(p.group('bra')) + idx = int(p.group("idx")) + name = "P" + lvs = int(p.group("ket")), int(p.group("bra")) opr = gen_oper(name, idx, self.dim_osc, self.dim_qub, lvs) self.__str2qopr[p.group()] = opr - elif key in ['Func', 'Ext']: - _name = p.group('name') + elif key in ["Func", "Ext"]: + _name = p.group("name") _key = key - elif key == 'MathOrd1': + elif key == "MathOrd1": _name = p.group() - if prev not in ['QubOpr', 'PrjOpr', 'CavOpr', 'Var', 'Num']: - _key = 'MathUnitary' + if prev not in ["QubOpr", "PrjOpr", "CavOpr", "Var", "Num"]: + _key = "MathUnitary" else: _key = key else: _name = p.group() _key = key token_list.append(Token(_key, _name)) - _op_str = _op_str[p.end():] + _op_str = _op_str[p.end() :] prev = _key break else: - raise Exception('Invalid input string %s is found' % op_str) + raise Exception("Invalid input string %s is found" % op_str) # split coefficient - coef = '' - if any([k.type == 'Var' for k in token_list]): + coef = "" + if any([k.type == "Var" for k in token_list]): for ii, _ in enumerate(token_list): - if token_list[ii].name == '*': - if all([k.type != 'Var' for k in token_list[ii + 1:]]): - coef = ''.join([k.name for k in token_list[:ii]]) - token_list = token_list[ii + 1:] + if token_list[ii].name == "*": + if all([k.type != "Var" for k in token_list[ii + 1 :]]): + coef = "".join([k.name for k in token_list[:ii]]) + token_list = token_list[ii + 1 :] break else: - raise Exception('Invalid order of operators and coefficients in %s' % op_str) + raise Exception( + "Invalid order of operators and coefficients in %s" % op_str + ) return coef, token_list def _shunting_yard(self, token_list): - """ Reformat token to reverse Polish notation - """ + """Reformat token to reverse Polish notation""" stack = [] queue = [] while any(token_list): token = token_list.pop(0) - if token.type in ['QubOpr', 'PrjOpr', 'CavOpr', 'Num']: + if token.type in ["QubOpr", "PrjOpr", "CavOpr", "Num"]: queue.append(token) - elif token.type in ['Func', 'Ext']: + elif token.type in ["Func", "Ext"]: stack.append(token) - elif token.type in ['MathUnitary', 'MathOrd0', 'MathOrd1']: + elif token.type in ["MathUnitary", "MathOrd0", "MathOrd1"]: while stack and math_priority(token, stack[-1]): queue.append(stack.pop(-1)) stack.append(token) - elif token.type in ['BrkL']: + elif token.type in ["BrkL"]: stack.append(token) - elif token.type in ['BrkR']: - while stack[-1].type not in ['BrkL', 'Func']: + elif token.type in ["BrkR"]: + while stack[-1].type not in ["BrkL", "Func"]: queue.append(stack.pop(-1)) if not any(stack): - raise Exception('Missing correct number of brackets') + raise Exception("Missing correct number of brackets") pop = stack.pop(-1) - if pop.type == 'Func': + if pop.type == "Func": queue.append(pop) else: - raise Exception('Invalid token %s is found' % token.name) + raise Exception("Invalid token %s is found" % token.name) while any(stack): queue.append(stack.pop(-1)) @@ -259,44 +264,43 @@ def _shunting_yard(self, token_list): return queue def _token2qobj(self, tokens): - """ Generate quantum class object from tokens - """ + """Generate quantum class object from tokens""" stack = [] for token in tokens: - if token.type in ['QubOpr', 'PrjOpr', 'CavOpr']: + if token.type in ["QubOpr", "PrjOpr", "CavOpr"]: stack.append(self.__str2qopr[token.name]) - elif token.type == 'Num': + elif token.type == "Num": stack.append(float(token.name)) - elif token.type in ['MathUnitary']: - if token.name == '-': + elif token.type in ["MathUnitary"]: + if token.name == "-": stack.append(-stack.pop(-1)) - elif token.type in ['MathOrd0', 'MathOrd1']: + elif token.type in ["MathOrd0", "MathOrd1"]: op2 = stack.pop(-1) op1 = stack.pop(-1) - if token.name == '+': + if token.name == "+": stack.append(op1 + op2) - elif token.name == '-': + elif token.name == "-": stack.append(op1 - op2) - elif token.name == '*': + elif token.name == "*": if isinstance(op1, Operator) and isinstance(op2, Operator): stack.append(op1 & op2) else: stack.append(op1 * op2) - elif token.name == '/': + elif token.name == "/": stack.append(op1 / op2) - elif token.type in ['Func', 'Ext']: + elif token.type in ["Func", "Ext"]: stack.append(apply_func(token.name, stack.pop(-1))) else: - raise Exception('Invalid token %s is found' % token.name) + raise Exception("Invalid token %s is found" % token.name) if len(stack) > 1: - raise Exception('Invalid mathematical operation in ' % tokens) + raise Exception("Invalid mathematical operation in " % tokens) return stack[0] class NoiseParser: - """ Generate QuTip noise object from dictionary + """Generate QuTip noise object from dictionary Qubit noise is given in the format of nested dictionary: "qubit": { "0": { @@ -314,59 +318,57 @@ class NoiseParser: } these configurations are combined in the same dictionary """ + def __init__(self, noise_dict, dim_osc, dim_qub): - """ Create new quantum operator generator + """Create new quantum operator generator Parameters: noise_dict (dict): dictionary of noise configuration dim_osc (dict): dimension of oscillator subspace dim_qub (dict): dimension of qubit subspace """ - self.noise_osc = noise_dict.get('oscillator', {'n_th': {}, 'coupling': {}}) - self.noise_qub = noise_dict.get('qubit', {}) + self.noise_osc = noise_dict.get("oscillator", {"n_th": {}, "coupling": {}}) + self.noise_qub = noise_dict.get("qubit", {}) self.dim_osc = dim_osc self.dim_qub = dim_qub self.__c_list = [] @property def compiled(self): - """ Return noise configuration in OpenPulse handler format - """ + """Return noise configuration in OpenPulse handler format""" return self.__c_list def parse(self): - """ Parse and generate quantum class object - """ + """Parse and generate quantum class object""" # Qubit noise for index, config in self.noise_qub.items(): for opname, coef in config.items(): # TODO: support noise in multi-dimensional system # TODO: support noise with math operation - if opname in ['X', 'Y', 'Z', 'Sp', 'Sm']: + if opname in ["X", "Y", "Z", "Sp", "Sm"]: opr = gen_oper(opname, int(index), self.dim_osc, self.dim_qub) else: - raise Exception('Unsupported noise operator %s is given' % opname) + raise Exception("Unsupported noise operator %s is given" % opname) self.__c_list.append(np.sqrt(coef) * opr) # Oscillator noise - ndic = self.noise_osc['n_th'] - cdic = self.noise_osc['coupling'] + ndic = self.noise_osc["n_th"] + cdic = self.noise_osc["coupling"] for (n_ii, n_coef), (c_ii, c_coef) in zip(ndic.items(), cdic.items()): if n_ii == c_ii: if c_coef > 0: - opr = gen_oper('A', int(n_ii), self.dim_osc, self.dim_qub) + opr = gen_oper("A", int(n_ii), self.dim_osc, self.dim_qub) if n_coef: self.__c_list.append(np.sqrt(c_coef * (1 + n_coef)) * opr) self.__c_list.append(np.sqrt(c_coef * n_coef) * opr.dag()) else: self.__c_list.append(np.sqrt(c_coef) * opr) else: - raise Exception('Invalid oscillator index in noise dictionary.') + raise Exception("Invalid oscillator index in noise dictionary.") def math_priority(o1, o2): - """ Check priority of given math operation - """ - rank = {'MathUnitary': 2, 'MathOrd0': 1, 'MathOrd1': 0} + """Check priority of given math operation""" + rank = {"MathUnitary": 2, "MathOrd0": 1, "MathOrd1": 0} diff_ops = rank.get(o1.type, -1) - rank.get(o2.type, -1) if diff_ops > 0: @@ -377,51 +379,50 @@ def math_priority(o1, o2): # pylint: disable=dangerous-default-value def parse_binop(op_str, operands={}, cast_str=True): - """ Calculate binary operation in string format - """ + """Calculate binary operation in string format""" oprs = OrderedDict( sum=r"(?P[a-zA-Z0-9]+)\+(?P[a-zA-Z0-9]+)", sub=r"(?P[a-zA-Z0-9]+)\-(?P[a-zA-Z0-9]+)", mul=r"(?P[a-zA-Z0-9]+)\*(?P[a-zA-Z0-9]+)", div=r"(?P[a-zA-Z0-9]+)\/(?P[a-zA-Z0-9]+)", - non=r"(?P[a-zA-Z0-9]+)" + non=r"(?P[a-zA-Z0-9]+)", ) for key, regr in oprs.items(): p = re.match(regr, op_str) if p: - val0 = operands.get(p.group('v0'), p.group('v0')) - if key == 'non': + val0 = operands.get(p.group("v0"), p.group("v0")) + if key == "non": # substitution retv = val0 else: - val1 = operands.get(p.group('v1'), p.group('v1')) + val1 = operands.get(p.group("v1"), p.group("v1")) # binary operation - if key == 'sum': + if key == "sum": if val0.isdecimal() and val1.isdecimal(): retv = int(val0) + int(val1) else: - retv = '+'.join([str(val0), str(val1)]) - elif key == 'sub': + retv = "+".join([str(val0), str(val1)]) + elif key == "sub": if val0.isdecimal() and val1.isdecimal(): retv = int(val0) - int(val1) else: - retv = '-'.join([str(val0), str(val1)]) - elif key == 'mul': + retv = "-".join([str(val0), str(val1)]) + elif key == "mul": if val0.isdecimal() and val1.isdecimal(): retv = int(val0) * int(val1) else: - retv = '*'.join([str(val0), str(val1)]) - elif key == 'div': + retv = "*".join([str(val0), str(val1)]) + elif key == "div": if val0.isdecimal() and val1.isdecimal(): retv = int(val0) / int(val1) else: - retv = '/'.join([str(val0), str(val1)]) + retv = "/".join([str(val0), str(val1)]) else: retv = 0 break else: - raise Exception('Invalid string %s' % op_str) + raise Exception("Invalid string %s" % op_str) if cast_str: return str(retv) diff --git a/qiskit_aer/quantum_info/states/aer_densitymatrix.py b/qiskit_aer/quantum_info/states/aer_densitymatrix.py index a7b4c1c77c..5a87667b62 100644 --- a/qiskit_aer/quantum_info/states/aer_densitymatrix.py +++ b/qiskit_aer/quantum_info/states/aer_densitymatrix.py @@ -53,16 +53,18 @@ def __init__(self, data, dims=None, **configs): Additional Information: The ``dims`` kwarg is used to ``AerDensityMatrix`` constructor. """ - if '_aer_state' in configs: - self._aer_state = configs.pop('_aer_state') + if "_aer_state" in configs: + self._aer_state = configs.pop("_aer_state") else: - if 'method' not in configs: - configs['method'] = 'density_matrix' - elif configs['method'] != 'density_matrix': - method = configs['method'] - raise AerError(f'Method {method} is not supported') + if "method" not in configs: + configs["method"] = "density_matrix" + elif configs["method"] != "density_matrix": + method = configs["method"] + raise AerError(f"Method {method} is not supported") if isinstance(data, (QuantumCircuit, Instruction)): - data, aer_state = AerDensityMatrix._from_instruction(data, None, configs) + data, aer_state = AerDensityMatrix._from_instruction( + data, None, configs + ) elif isinstance(data, list): data = self._from_1d_array(np.array(data, dtype=complex)) data, aer_state = AerDensityMatrix._from_ndarray(data, configs) @@ -75,9 +77,10 @@ def __init__(self, data, dims=None, **configs): dims = data._op_shape._dims_l data = data._data.copy() elif isinstance(data, DensityMatrix): - data, aer_state = AerDensityMatrix._from_ndarray(np.array(data.data, - dtype=complex), configs) - elif hasattr(data, 'to_operator'): + data, aer_state = AerDensityMatrix._from_ndarray( + np.array(data.data, dtype=complex), configs + ) + elif hasattr(data, "to_operator"): # If the data object has a 'to_operator' attribute this is given # higher preference than the 'to_matrix' method for initializing # an Operator object. @@ -85,14 +88,17 @@ def __init__(self, data, dims=None, **configs): data, aer_state = AerDensityMatrix._from_ndarray(op.data, configs) if dims is None: dims = op.output_dims() - elif hasattr(data, 'to_matrix'): + elif hasattr(data, "to_matrix"): # If no 'to_operator' attribute exists we next look for a # 'to_matrix' attribute to a matrix that will be cast into # a complex numpy matrix. data, aer_state = AerDensityMatrix._from_ndarray( - np.asarray(data.to_matrix(), dtype=complex), configs) + np.asarray(data.to_matrix(), dtype=complex), configs + ) else: - raise AerError(f'Input data is not supported: type={data.__class__}, data={data}') + raise AerError( + f"Input data is not supported: type={data.__class__}, data={data}" + ) self._aer_state = aer_state @@ -106,7 +112,9 @@ def seed(self, value=None): if value is None or isinstance(value, int): self._aer_state.set_seed(value) else: - raise AerError(f'This seed is not supported: type={value.__class__}, value={value}') + raise AerError( + f"This seed is not supported: type={value.__class__}, value={value}" + ) def _last_result(self): if self._result is None: @@ -116,8 +124,8 @@ def _last_result(self): def metadata(self): """Return result metadata of an operation that executed lastly.""" if self._last_result() is None: - raise AerError('AerState was not used and metdata does not exist.') - return self._last_result()['metadata'] + raise AerError("AerState was not used and metdata does not exist.") + return self._last_result()["metadata"] def __copy__(self): return copy.deepcopy(self) @@ -210,7 +218,7 @@ def _from_1d_array(data): @staticmethod def _from_ndarray(init_data, configs): - aer_state = AerState(method='density_matrix') + aer_state = AerState(method="density_matrix") options = AerSimulator._default_options() for config_key, config_value in configs.items(): @@ -218,7 +226,7 @@ def _from_ndarray(init_data, configs): aer_state.configure(config_key, config_value) if len(init_data) == 0: - raise AerError('initial data must be larger than 0') + raise AerError("initial data must be larger than 0") num_qubits = int(np.log2(len(init_data))) @@ -233,12 +241,12 @@ def from_instruction(cls, instruction): @staticmethod def _from_instruction(inst, init_data, configs): - aer_state = AerState(method='density_matrix') + aer_state = AerState(method="density_matrix") for config_key, config_value in configs.items(): aer_state.configure(config_key, config_value) - basis_gates = BASIS_GATES['density_matrix'] + basis_gates = BASIS_GATES["density_matrix"] aer_state.allocate_qubits(inst.num_qubits) num_qubits = inst.num_qubits @@ -252,9 +260,13 @@ def _from_instruction(inst, init_data, configs): aer_state.apply_global_phase(inst.global_phase) if isinstance(inst, QuantumCircuit): - AerStatevector._aer_evolve_circuit(aer_state, inst, range(num_qubits), basis_gates) + AerStatevector._aer_evolve_circuit( + aer_state, inst, range(num_qubits), basis_gates + ) else: - AerStatevector._aer_evolve_instruction(aer_state, inst, range(num_qubits), basis_gates) + AerStatevector._aer_evolve_instruction( + aer_state, inst, range(num_qubits), basis_gates + ) return aer_state.move_to_ndarray(), aer_state @@ -294,13 +306,15 @@ def to_statevector(self, atol=None, rtol=None): rtol = self.rtol if not is_hermitian_matrix(self.data, atol=atol, rtol=rtol): - raise QiskitError('Not a valid density matrix (non-hermitian).') + raise QiskitError("Not a valid density matrix (non-hermitian).") evals, evecs = np.linalg.eig(self.data) nonzero_evals = evals[abs(evals) > atol] - if len(nonzero_evals) != 1 or not np.isclose(nonzero_evals[0], 1, atol=atol, rtol=rtol): - raise QiskitError('Density matrix is not a pure state') + if len(nonzero_evals) != 1 or not np.isclose( + nonzero_evals[0], 1, atol=atol, rtol=rtol + ): + raise QiskitError("Density matrix is not a pure state") psi = evecs[:, np.argmax(evals)] # eigenvectors returned in columns. return AerStatevector(psi) diff --git a/qiskit_aer/quantum_info/states/aer_state.py b/qiskit_aer/quantum_info/states/aer_state.py index 0f21602751..ee993df844 100644 --- a/qiskit_aer/quantum_info/states/aer_state.py +++ b/qiskit_aer/quantum_info/states/aer_state.py @@ -14,6 +14,7 @@ """ from enum import Enum import numpy as np + # pylint: disable=import-error, no-name-in-module from qiskit_aer.backends.controller_wrappers import AerStateWrapper from ...backends.aerbackend import AerError @@ -69,57 +70,65 @@ def renew(self): def _assert_initializing(self): if self._state != _STATE.INITIALIZING: - raise AerError('AerState was already initialized.') + raise AerError("AerState was already initialized.") def _assert_allocated_or_mapped_or_moved(self): if self._state == _STATE.INITIALIZING: - raise AerError('AerState has not been initialized yet.') + raise AerError("AerState has not been initialized yet.") if self._state == _STATE.CLOSED: - raise AerError('AerState has already been closed.') + raise AerError("AerState has already been closed.") def _assert_allocated_or_mapped(self): if self._state == _STATE.INITIALIZING: - raise AerError('AerState has not been initialized yet.') + raise AerError("AerState has not been initialized yet.") if self._state == _STATE.MOVED: - raise AerError('AerState has already been moved.') + raise AerError("AerState has already been moved.") if self._state == _STATE.CLOSED: - raise AerError('AerState has already been closed.') + raise AerError("AerState has already been closed.") def _assert_mapped_or_moved(self): if self._state == _STATE.INITIALIZING: - raise AerError('AerState has not been initialized yet.') + raise AerError("AerState has not been initialized yet.") if self._state == _STATE.ALLOCATED: - raise AerError('AerState has not been moved yet.') + raise AerError("AerState has not been moved yet.") if self._state == _STATE.CLOSED: - raise AerError('AerState has already been closed.') + raise AerError("AerState has already been closed.") def _assert_closed(self): if self._state != _STATE.CLOSED: - raise AerError('AerState is not closed.') + raise AerError("AerState is not closed.") def _allocated(self): if self._state != _STATE.INITIALIZING: - raise AerError('unexpected state transition: {self._state}->{_STATE.ALLOCATED}') + raise AerError( + "unexpected state transition: {self._state}->{_STATE.ALLOCATED}" + ) self._state = _STATE.ALLOCATED def _mapped(self): if self._state != _STATE.INITIALIZING: - raise AerError('unexpected state transition: {self._state}->{_STATE.MAPPED}') + raise AerError( + "unexpected state transition: {self._state}->{_STATE.MAPPED}" + ) self._state = _STATE.MAPPED def _released(self): if self._state != _STATE.MAPPED: - raise AerError('unexpected state transition: {self._state}->{_STATE.RELEASED}') + raise AerError( + "unexpected state transition: {self._state}->{_STATE.RELEASED}" + ) self._state = _STATE.RELEASED def _moved(self): if self._state != _STATE.ALLOCATED: - raise AerError('unexpected state transition: {self._state}->{_STATE.MOVED}') + raise AerError("unexpected state transition: {self._state}->{_STATE.MOVED}") self._state = _STATE.MOVED def _closed(self): if self._state not in (_STATE.MOVED, _STATE.MAPPED, _STATE.RELEASED): - raise AerError('unexpected state transition: {self._state}->{_STATE.CLOSED}') + raise AerError( + "unexpected state transition: {self._state}->{_STATE.CLOSED}" + ) self._state = _STATE.CLOSED def configure(self, key, value): @@ -127,7 +136,7 @@ def configure(self, key, value): self._assert_initializing() if not isinstance(key, str): - raise AerError('AerState is configured with a str key') + raise AerError("AerState is configured with a str key") if not isinstance(value, str): value = str(value) @@ -146,7 +155,7 @@ def initialize(self, data=None, copy=True): self._assert_initializing() if not self._method: - raise AerError('method is not configured yet.') + raise AerError("method is not configured yet.") if data is None: self._native_state.initialize() @@ -155,23 +164,25 @@ def initialize(self, data=None, copy=True): elif isinstance(data, np.ndarray): return self._initialize_with_ndarray(data, copy) else: - raise AerError(f'unsupported init data: {data.__class__}') + raise AerError(f"unsupported init data: {data.__class__}") def _initialize_with_ndarray(self, data, copy): if AerState._is_in_use(data) and not copy: - raise AerError('another AerState owns this data') + raise AerError("another AerState owns this data") num_of_qubits = int(np.log2(len(data))) if len(data) != np.power(2, num_of_qubits): - raise AerError('length of init data must be power of two') + raise AerError("length of init data must be power of two") init = False - if self._method == 'statevector': + if self._method == "statevector": init = self._native_state.initialize_statevector(num_of_qubits, data, copy) - elif self._method == 'density_matrix': + elif self._method == "density_matrix": if data.shape != (len(data), len(data)): - raise AerError('shape of init data must be a pair of power of two') - init = self._native_state.initialize_density_matrix(num_of_qubits, data, copy) + raise AerError("shape of init data must be a pair of power of two") + init = self._native_state.initialize_density_matrix( + num_of_qubits, data, copy + ) if init: if not copy: @@ -186,9 +197,9 @@ def _initialize_with_ndarray(self, data, copy): self._native_state.initialize() if not data.flags.c_contiguous and not data.flags.f_contiguous: data = np.ascontiguousarray(data) - if self._method == 'statevector': + if self._method == "statevector": self._native_state.apply_initialize(range(num_of_qubits), data) - elif self._method == 'density_matrix': + elif self._method == "density_matrix": self._native_state.set_density_matrix(range(num_of_qubits), data) else: self._native_state.apply_initialize(range(num_of_qubits), data) @@ -241,7 +252,7 @@ def move_to_ndarray(self): elif self._state == _STATE.MOVED: ret = self._moved_data else: - if self._method == 'density_matrix': + if self._method == "density_matrix": self._moved_data = self._native_state.move_to_matrix() else: self._moved_data = self._native_state.move_to_ndarray() @@ -253,16 +264,16 @@ def allocate_qubits(self, num_of_qubits): """allocate qubits.""" self._assert_initializing() if num_of_qubits <= 0: - raise AerError(f'invalid number of qubits: {num_of_qubits}') + raise AerError(f"invalid number of qubits: {num_of_qubits}") allocated = self._native_state.allocate_qubits(num_of_qubits) self._last_qubit = allocated[len(allocated) - 1] def _assert_in_allocated_qubits(self, qubit): - if hasattr(qubit, '__iter__'): + if hasattr(qubit, "__iter__"): for q in qubit: self._assert_in_allocated_qubits(q) elif qubit < 0 or qubit > self._last_qubit: - raise AerError(f'invalid qubit: index={qubit}') + raise AerError(f"invalid qubit: index={qubit}") @property def num_qubits(self): @@ -441,7 +452,9 @@ def apply_cu(self, control_qubit, target_qubit, theta, phi, lamb, gamma): self._assert_in_allocated_qubits(control_qubit) self._assert_in_allocated_qubits(target_qubit) # update state - self._native_state.apply_cu([control_qubit, target_qubit], theta, phi, lamb, gamma) + self._native_state.apply_cu( + [control_qubit, target_qubit], theta, phi, lamb, gamma + ) def apply_mcu(self, control_qubits, target_qubit, theta, phi, lamb, gamma): """apply a mcu operation.""" @@ -449,7 +462,9 @@ def apply_mcu(self, control_qubits, target_qubit, theta, phi, lamb, gamma): self._assert_in_allocated_qubits(control_qubits) self._assert_in_allocated_qubits(target_qubit) # update state - self._native_state.apply_mcu(control_qubits + [target_qubit], theta, phi, lamb, gamma) + self._native_state.apply_mcu( + control_qubits + [target_qubit], theta, phi, lamb, gamma + ) def apply_mcswap(self, control_qubits, qubit0, qubit1): """apply a mcswap operation.""" diff --git a/qiskit_aer/quantum_info/states/aer_statevector.py b/qiskit_aer/quantum_info/states/aer_statevector.py index d27a6a53ac..4a27f433fe 100644 --- a/qiskit_aer/quantum_info/states/aer_statevector.py +++ b/qiskit_aer/quantum_info/states/aer_statevector.py @@ -55,19 +55,20 @@ def __init__(self, data, dims=None, **configs): The ``dims`` kwarg is used to ``Statevector`` constructor. """ - if '_aer_state' in configs: - self._aer_state = configs.pop('_aer_state') + if "_aer_state" in configs: + self._aer_state = configs.pop("_aer_state") else: - if 'method' not in configs: - configs['method'] = 'statevector' - elif configs['method'] not in ('statevector', 'matrix_product_state'): - method = configs['method'] - raise AerError(f'Method {method} is not supported') + if "method" not in configs: + configs["method"] = "statevector" + elif configs["method"] not in ("statevector", "matrix_product_state"): + method = configs["method"] + raise AerError(f"Method {method} is not supported") if isinstance(data, (QuantumCircuit, Instruction)): data, aer_state = AerStatevector._from_instruction(data, None, configs) elif isinstance(data, list): - data, aer_state = AerStatevector._from_ndarray(np.array(data, dtype=complex), - configs) + data, aer_state = AerStatevector._from_ndarray( + np.array(data, dtype=complex), configs + ) elif isinstance(data, np.ndarray): data, aer_state = AerStatevector._from_ndarray(data, configs) elif isinstance(data, AerStatevector): @@ -76,10 +77,13 @@ def __init__(self, data, dims=None, **configs): dims = data._op_shape._dims_l data = data._data.copy() elif isinstance(data, Statevector): - data, aer_state = AerStatevector._from_ndarray(np.array(data.data, dtype=complex), - configs) + data, aer_state = AerStatevector._from_ndarray( + np.array(data.data, dtype=complex), configs + ) else: - raise AerError(f'Input data is not supported: type={data.__class__}, data={data}') + raise AerError( + f"Input data is not supported: type={data.__class__}, data={data}" + ) self._aer_state = aer_state @@ -93,7 +97,9 @@ def seed(self, value=None): if value is None or isinstance(value, int): self._aer_state.set_seed(value) else: - raise AerError(f'This seed is not supported: type={value.__class__}, value={value}') + raise AerError( + f"This seed is not supported: type={value.__class__}, value={value}" + ) def _last_result(self): if self._result is None: @@ -103,8 +109,8 @@ def _last_result(self): def metadata(self): """Return result metadata of an operation that executed lastly.""" if self._last_result() is None: - raise AerError('AerState was not used and metdata does not exist.') - return self._last_result()['metadata'] + raise AerError("AerState was not used and metdata does not exist.") + return self._last_result()["metadata"] def __copy__(self): return copy.deepcopy(self) @@ -134,7 +140,7 @@ def sample_memory(self, shots, qargs=None): @staticmethod def _from_ndarray(init_data, configs): do_copy = True - if not init_data.flags['C_CONTIGUOUS']: + if not init_data.flags["C_CONTIGUOUS"]: init_data = np.ascontiguousarray(init_data) do_copy = False @@ -146,7 +152,7 @@ def _from_ndarray(init_data, configs): aer_state.configure(config_key, config_value) if len(init_data) == 0: - raise AerError('initial data must be larger than 0') + raise AerError("initial data must be larger than 0") num_qubits = int(np.log2(len(init_data))) @@ -166,11 +172,11 @@ def _from_instruction(inst, init_data, configs): for config_key, config_value in configs.items(): aer_state.configure(config_key, config_value) - if 'method' in configs: - method = configs['method'] + if "method" in configs: + method = configs["method"] else: - method = 'statevector' - aer_state.configure('method', method) + method = "statevector" + aer_state.configure("method", method) basis_gates = BASIS_GATES[method] @@ -186,9 +192,13 @@ def _from_instruction(inst, init_data, configs): aer_state.apply_global_phase(inst.global_phase) if isinstance(inst, QuantumCircuit): - AerStatevector._aer_evolve_circuit(aer_state, inst, range(num_qubits), basis_gates) + AerStatevector._aer_evolve_circuit( + aer_state, inst, range(num_qubits), basis_gates + ) else: - AerStatevector._aer_evolve_instruction(aer_state, inst, range(num_qubits), basis_gates) + AerStatevector._aer_evolve_instruction( + aer_state, inst, range(num_qubits), basis_gates + ) return aer_state.move_to_ndarray(), aer_state @@ -202,9 +212,12 @@ def _aer_evolve_circuit(aer_state, circuit, qubits, basis_gates=None): ) inst = instruction.operation qargs = instruction.qubits - AerStatevector._aer_evolve_instruction(aer_state, inst, - [qubits[circuit.find_bit(qarg).index] - for qarg in qargs], basis_gates) + AerStatevector._aer_evolve_instruction( + aer_state, + inst, + [qubits[circuit.find_bit(qarg).index] for qarg in qargs], + basis_gates, + ) @staticmethod def _aer_evolve_instruction(aer_state, inst, qubits, basis_gates=None): @@ -214,46 +227,60 @@ def _aer_evolve_instruction(aer_state, inst, qubits, basis_gates=None): applied = True if basis_gates and inst.name in basis_gates: - if inst.name in ['u3', 'u']: + if inst.name in ["u3", "u"]: aer_state.apply_u(qubits[0], params[0], params[1], params[2]) - elif inst.name == 'h': + elif inst.name == "h": aer_state.apply_h(qubits[0]) - elif inst.name == 'x': + elif inst.name == "x": aer_state.apply_x(qubits[0]) - elif inst.name == 'cx': + elif inst.name == "cx": aer_state.apply_cx(qubits[0], qubits[1]) - elif inst.name == 'y': + elif inst.name == "y": aer_state.apply_y(qubits[0]) - elif inst.name == 'cy': + elif inst.name == "cy": aer_state.apply_cy(qubits[0], qubits[1]) - elif inst.name == 'z': + elif inst.name == "z": aer_state.apply_z(qubits[0]) - elif inst.name == 'cz': + elif inst.name == "cz": aer_state.apply_cz(qubits[0], qubits[1]) - elif inst.name == 'unitary': + elif inst.name == "unitary": aer_state.apply_unitary(qubits, inst.params[0]) - elif inst.name == 'diagonal': + elif inst.name == "diagonal": aer_state.apply_diagonal(qubits, inst.params) - elif inst.name == 'cu': - aer_state.apply_cu(qubits[0], qubits[1], params[0], params[1], params[2], params[3]) - elif inst.name == 'mcu': - aer_state.apply_mcu(qubits[0:len(qubits) - 1], qubits[len(qubits) - 1], - params[0], params[1], params[2], params[3]) - elif inst.name in 'mcx': - aer_state.apply_mcx(qubits[0:len(qubits) - 1], qubits[len(qubits) - 1]) - elif inst.name in 'mcy': - aer_state.apply_mcy(qubits[0:len(qubits) - 1], qubits[len(qubits) - 1]) - elif inst.name in 'mcz': - aer_state.apply_mcz(qubits[0:len(qubits) - 1], qubits[len(qubits) - 1]) - elif inst.name == 'id': + elif inst.name == "cu": + aer_state.apply_cu( + qubits[0], qubits[1], params[0], params[1], params[2], params[3] + ) + elif inst.name == "mcu": + aer_state.apply_mcu( + qubits[0 : len(qubits) - 1], + qubits[len(qubits) - 1], + params[0], + params[1], + params[2], + params[3], + ) + elif inst.name in "mcx": + aer_state.apply_mcx( + qubits[0 : len(qubits) - 1], qubits[len(qubits) - 1] + ) + elif inst.name in "mcy": + aer_state.apply_mcy( + qubits[0 : len(qubits) - 1], qubits[len(qubits) - 1] + ) + elif inst.name in "mcz": + aer_state.apply_mcz( + qubits[0 : len(qubits) - 1], qubits[len(qubits) - 1] + ) + elif inst.name == "id": pass else: applied = False - elif inst.name == 'kraus': + elif inst.name == "kraus": aer_state.apply_kraus(qubits, inst.params) - elif inst.name == 'reset': + elif inst.name == "reset": aer_state.apply_reset(qubits) - elif inst.name == 'barrier': + elif inst.name == "barrier": pass else: applied = False @@ -261,8 +288,10 @@ def _aer_evolve_instruction(aer_state, inst, qubits, basis_gates=None): if not applied: definition = inst.definition if definition is inst or definition is None: - raise AerError('cannot decompose ' + inst.name) - AerStatevector._aer_evolve_circuit(aer_state, definition, qubits, basis_gates) + raise AerError("cannot decompose " + inst.name) + AerStatevector._aer_evolve_circuit( + aer_state, definition, qubits, basis_gates + ) @classmethod def from_label(cls, label): diff --git a/qiskit_aer/utils/noise_model_inserter.py b/qiskit_aer/utils/noise_model_inserter.py index 3ab5ea266e..c889990d2b 100644 --- a/qiskit_aer/utils/noise_model_inserter.py +++ b/qiskit_aer/utils/noise_model_inserter.py @@ -42,12 +42,17 @@ def insert_noise(circuits, noise_model, transpile=False): default_errors = noise_model._default_quantum_errors for circuit in circuits: if transpile: - transpiled_circuit = qiskit.compiler.transpile(circuit, - basis_gates=noise_model.basis_gates) + transpiled_circuit = qiskit.compiler.transpile( + circuit, basis_gates=noise_model.basis_gates + ) else: transpiled_circuit = circuit - qubit_indices = {bit: index for index, bit in enumerate(transpiled_circuit.qubits)} - result_circuit = transpiled_circuit.copy(name=transpiled_circuit.name + '_with_noise') + qubit_indices = { + bit: index for index, bit in enumerate(transpiled_circuit.qubits) + } + result_circuit = transpiled_circuit.copy( + name=transpiled_circuit.name + "_with_noise" + ) result_circuit.data = [] for inst, qargs, cargs in transpiled_circuit.data: result_circuit.data.append((inst, qargs, cargs)) diff --git a/qiskit_aer/utils/noise_transformation.py b/qiskit_aer/utils/noise_transformation.py index dd00df0947..2b29a31ad1 100644 --- a/qiskit_aer/utils/noise_transformation.py +++ b/qiskit_aer/utils/noise_transformation.py @@ -35,8 +35,13 @@ from qiskit.circuit import Reset from qiskit.circuit.library.standard_gates import ( - IGate, XGate, YGate, ZGate, - HGate, SGate, SdgGate, + IGate, + XGate, + YGate, + ZGate, + HGate, + SGate, + SdgGate, ) from qiskit.compiler import transpile from qiskit.exceptions import MissingOptionalLibraryError @@ -126,16 +131,16 @@ def transpile_noise_model(noise_model: NoiseModel, **transpile_kwargs) -> NoiseM Raises: NoiseError: if the transformation failed. """ + def func(error): return transpile_quantum_error(error, **transpile_kwargs) return transform_noise_model(noise_model, func) -def approximate_quantum_error(error, *, - operator_string=None, - operator_dict=None, - operator_list=None): +def approximate_quantum_error( + error, *, operator_string=None, operator_dict=None, operator_list=None +): r""" Return a ``QuantumError`` object that approximates an error as a mixture of specified operators (channels). @@ -182,30 +187,40 @@ def approximate_quantum_error(error, *, raise NoiseError(f"Invalid input error type: {error.__class__.__name__}") if error.num_qubits > 2: - raise NoiseError("Only 1-qubit and 2-qubit noises can be converted, " - f"{error.num_qubits}-qubit noise found in model") + raise NoiseError( + "Only 1-qubit and 2-qubit noises can be converted, " + f"{error.num_qubits}-qubit noise found in model" + ) if operator_string is not None: valid_operator_strings = _PRESET_OPERATOR_TABLE.keys() operator_string = operator_string.lower() if operator_string not in valid_operator_strings: - raise NoiseError(f"{operator_string} is not a valid operator_string. " - f"It must be one of {valid_operator_strings}") + raise NoiseError( + f"{operator_string} is not a valid operator_string. " + f"It must be one of {valid_operator_strings}" + ) try: operator_list = _PRESET_OPERATOR_TABLE[operator_string][error.num_qubits] except KeyError as err: - raise NoiseError(f"Preset '{operator_string}' operators do not support the " - f"approximation of errors with {error.num_qubits} qubits") from err + raise NoiseError( + f"Preset '{operator_string}' operators do not support the " + f"approximation of errors with {error.num_qubits} qubits" + ) from err if operator_dict is not None: _, operator_list = zip(*operator_dict.items()) if operator_list is not None: if not isinstance(operator_list, Sequence): raise NoiseError(f"operator_list is not a sequence: {operator_list}") try: - channel_list = [op if isinstance(op, QuantumChannel) else QuantumError([(op, 1)]) - for op in operator_list] # preserve operator_list + channel_list = [ + op if isinstance(op, QuantumChannel) else QuantumError([(op, 1)]) + for op in operator_list + ] # preserve operator_list except NoiseError as err: - raise NoiseError(f"Invalid type found in operator list: {operator_list}") from err + raise NoiseError( + f"Invalid type found in operator list: {operator_list}" + ) from err probabilities = _transform_by_operator_list(channel_list, error)[1:] identity_prob = np.round(1 - sum(probabilities), 9) @@ -221,10 +236,9 @@ def approximate_quantum_error(error, *, ) -def approximate_noise_model(model, *, - operator_string=None, - operator_dict=None, - operator_list=None): +def approximate_noise_model( + model, *, operator_string=None, operator_dict=None, operator_list=None +): """ Replace all noises in a noise model with ones approximated by a mixture of operators (channels). @@ -257,13 +271,15 @@ def approximate_noise_model(model, *, its possible values are ``'pauli'``, ``'reset'``, ``'clifford'``. The ``'clifford'`` does not support 2-qubit errors. """ + def approximate(noise): return approximate_quantum_error( noise, operator_string=operator_string, operator_dict=operator_dict, - operator_list=operator_list + operator_list=operator_list, ) + return transform_noise_model(model, approximate) @@ -281,12 +297,12 @@ def approximate(noise): _RESET_Q0Q1 = [op_q0 + op_q1 for op_q0 in _RESET_Q0 for op_q1 in _RESET_Q1] # clifford operators _CLIFFORD_GATES = [ - (IGate(), ), - (SGate(), ), - (SdgGate(), ), - (ZGate(), ), + (IGate(),), + (SGate(),), + (SdgGate(),), + (ZGate(),), # u2 gates - (HGate(), ), + (HGate(),), (HGate(), ZGate()), (ZGate(), HGate()), (HGate(), SGate()), @@ -303,10 +319,10 @@ def approximate(noise): (SdgGate(), HGate(), ZGate()), (ZGate(), HGate(), ZGate()), # u3 gates - (XGate(), ), - (YGate(), ), + (XGate(),), + (YGate(),), (SGate(), XGate()), - (SdgGate(), XGate()) + (SdgGate(), XGate()), ] # preset operator table _PRESET_OPERATOR_TABLE = { @@ -320,12 +336,14 @@ def approximate(noise): }, "clifford": { 1: [[(gate, [0]) for gate in _CLIFFORD_GATES[j]] for j in range(1, 24)], - } + }, } -def _transform_by_operator_list(basis_ops: Sequence[Union[QuantumChannel, QuantumError]], - target: Union[QuantumChannel, QuantumError]) -> List[float]: +def _transform_by_operator_list( + basis_ops: Sequence[Union[QuantumChannel, QuantumError]], + target: Union[QuantumChannel, QuantumError], +) -> List[float]: r""" Transform (or approximate) the target quantum channel into a mixture of basis operators (channels) and return the mixing probabilities. @@ -395,13 +413,13 @@ def fidelity(channel): # fidelity w.r.t. identity omitting the N^-2 factor name="Transformation/Approximation of noise", pip_install="pip install cvxpy", msg="CVXPY is required to solve an optimization problem of" - " approximating a noise channel." + " approximating a noise channel.", ) from err # create quadratic program x = cvxpy.Variable(n) prob = cvxpy.Problem( cvxpy.Minimize(cvxpy.quad_form(x, A) + b.T @ x), - constraints=[cvxpy.sum(x) <= 1, x >= 0, source_fids.T @ x <= target_fid] + constraints=[cvxpy.sum(x) <= 1, x >= 0, source_fids.T @ x <= target_fid], ) # solve quadratic program prob.solve() diff --git a/qiskit_aer/version.py b/qiskit_aer/version.py index 237d02af7e..a723c4b76b 100644 --- a/qiskit_aer/version.py +++ b/qiskit_aer/version.py @@ -23,17 +23,21 @@ def _minimal_ext_cmd(cmd): # construct minimal environment env = {} - for k in ['SYSTEMROOT', 'PATH']: + for k in ["SYSTEMROOT", "PATH"]: v = os.environ.get(k) if v is not None: env[k] = v # LANGUAGE is used on win32 - env['LANGUAGE'] = 'C' - env['LANG'] = 'C' - env['LC_ALL'] = 'C' - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, env=env, - cwd=os.path.join(os.path.dirname(ROOT_DIR))) + env["LANGUAGE"] = "C" + env["LANG"] = "C" + env["LC_ALL"] = "C" + proc = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=env, + cwd=os.path.join(os.path.dirname(ROOT_DIR)), + ) out = proc.communicate()[0] if proc.returncode > 0: raise OSError @@ -44,8 +48,8 @@ def git_version(): """Get the current git head sha1.""" # Determine if we're at main try: - out = _minimal_ext_cmd(['git', 'rev-parse', 'HEAD']) - git_revision = out.strip().decode('ascii') + out = _minimal_ext_cmd(["git", "rev-parse", "HEAD"]) + git_revision = out.strip().decode("ascii") except OSError: git_revision = "Unknown" @@ -63,16 +67,19 @@ def get_version_info(): # up the build under Python 3. full_version = VERSION - if not os.path.exists(os.path.join(os.path.dirname(os.path.dirname( - os.path.dirname(ROOT_DIR))), '.git')): + if not os.path.exists( + os.path.join( + os.path.dirname(os.path.dirname(os.path.dirname(ROOT_DIR))), ".git" + ) + ): return full_version try: - release = _minimal_ext_cmd(['git', 'tag', '-l', '--points-at', 'HEAD']) + release = _minimal_ext_cmd(["git", "tag", "-l", "--points-at", "HEAD"]) except Exception: # pylint: disable=broad-except return full_version if not release: git_revision = git_version() - full_version += '.dev0+' + git_revision[:7] + full_version += ".dev0+" + git_revision[:7] return full_version diff --git a/src/controllers/aer_controller.hpp b/src/controllers/aer_controller.hpp index 405e827392..bf144fc298 100644 --- a/src/controllers/aer_controller.hpp +++ b/src/controllers/aer_controller.hpp @@ -41,12 +41,12 @@ #include #endif +#include "framework/config.hpp" #include "framework/creg.hpp" #include "framework/qobj.hpp" #include "framework/results/experiment_result.hpp" #include "framework/results/result.hpp" #include "framework/rng.hpp" -#include "framework/config.hpp" #include "noise/noise_model.hpp" #include "transpile/cacheblocking.hpp" @@ -59,8 +59,8 @@ #include "simulators/statevector/qubitvector.hpp" #include "simulators/statevector/statevector_state.hpp" #include "simulators/superoperator/superoperator_state.hpp" -#include "simulators/unitary/unitary_state.hpp" #include "simulators/tensor_network/tensor_net_state.hpp" +#include "simulators/unitary/unitary_state.hpp" namespace AER { @@ -85,8 +85,7 @@ class Controller { template Result execute(const inputdata_t &qobj); - Result execute(std::vector &circuits, - Noise::NoiseModel &noise_model, + Result execute(std::vector &circuits, Noise::NoiseModel &noise_model, const Config &config); //----------------------------------------------------------------------- @@ -124,16 +123,15 @@ class Controller { enum class Precision { Double, Single }; const std::unordered_map method_names_ = { - {Method::automatic, "automatic"}, - {Method::statevector, "statevector"}, - {Method::density_matrix, "density_matrix"}, - {Method::matrix_product_state, "matrix_product_state"}, - {Method::stabilizer, "stabilizer"}, - {Method::extended_stabilizer, "extended_stabilizer"}, - {Method::unitary, "unitary"}, - {Method::superop, "superop"}, - {Method::tensor_network, "tensor_network"} - }; + {Method::automatic, "automatic"}, + {Method::statevector, "statevector"}, + {Method::density_matrix, "density_matrix"}, + {Method::matrix_product_state, "matrix_product_state"}, + {Method::stabilizer, "stabilizer"}, + {Method::extended_stabilizer, "extended_stabilizer"}, + {Method::unitary, "unitary"}, + {Method::superop, "superop"}, + {Method::tensor_network, "tensor_network"}}; //----------------------------------------------------------------------- // Config @@ -169,7 +167,8 @@ class Controller { // This method must initialize a state and return output data for // the required number of shots. void run_circuit(const Circuit &circ, const Noise::NoiseModel &noise, - const Method method, const Config &config, ExperimentResult &result) const; + const Method method, const Config &config, + ExperimentResult &result) const; //---------------------------------------------------------------- // Run circuit helpers @@ -178,7 +177,7 @@ class Controller { // Execute n-shots of a circuit on the input state template void run_circuit_helper(const Circuit &circ, const Noise::NoiseModel &noise, - const Config &config, const Method method, + const Config &config, const Method method, ExperimentResult &result) const; // Execute a single shot a of circuit by initializing the state vector, @@ -192,12 +191,9 @@ class Controller { // running all ops in circ, and updating data with // simulation output. template - void run_with_sampling(const Circuit &circ, - State_t &state, - ExperimentResult &result, - RngEngine &rng, - const uint_t block_bits, - const uint_t shots) const; + void run_with_sampling(const Circuit &circ, State_t &state, + ExperimentResult &result, RngEngine &rng, + const uint_t block_bits, const uint_t shots) const; // Execute multiple shots a of circuit by initializing the state vector, // running all ops in circ, and updating data with @@ -212,8 +208,7 @@ class Controller { template void run_circuit_with_sampled_noise(const Circuit &circ, const Noise::NoiseModel &noise, - const Config &config, - const Method method, + const Config &config, const Method method, ExperimentResult &result) const; //---------------------------------------------------------------- @@ -225,7 +220,7 @@ class Controller { template void measure_sampler(InputIterator first_meas, InputIterator last_meas, uint_t shots, State_t &state, ExperimentResult &result, - RngEngine &rng , int_t shot_index = -1) const; + RngEngine &rng, int_t shot_index = -1) const; // Check if measure sampling optimization is valid for the input circuit // for the given method. This checks if operation types before @@ -243,11 +238,10 @@ class Controller { // If `throw_except` is true an exception will be thrown on the return false // case listing the invalid instructions in the circuit or noise model, or // the required memory. - bool validate_method(Method method, - const Circuit &circ, + bool validate_method(Method method, const Circuit &circ, const Noise::NoiseModel &noise, bool throw_except = false) const; - + template bool validate_state(const state_t &state, const Circuit &circ, const Noise::NoiseModel &noise, @@ -261,7 +255,7 @@ class Controller { //---------------------------------------------------------------- // Utility functions //---------------------------------------------------------------- - + // Return a vector of simulation methods for each circuit. // If the default method is automatic this will be computed based on the // circuit and noise model. @@ -285,14 +279,13 @@ class Controller { // Return cache blocking transpiler pass Transpile::CacheBlocking - transpile_cache_blocking(Controller::Method method, - const Circuit &circ, + transpile_cache_blocking(Controller::Method method, const Circuit &circ, const Noise::NoiseModel &noise, const Config &config) const; - //return maximum number of qubits for matrix + // return maximum number of qubits for matrix int_t get_max_matrix_qubits(const Circuit &circ) const; - int_t get_matrix_bits(const Operations::Op& op) const; + int_t get_matrix_bits(const Operations::Op &op) const; bool has_statevector_ops(const Circuit &circuit) const; @@ -304,10 +297,9 @@ class Controller { void clear_parallelization(); // Set parallelization for experiments - void - set_parallelization_experiments(const std::vector &circuits, - const Noise::NoiseModel &noise, - const std::vector &methods); + void set_parallelization_experiments(const std::vector &circuits, + const Noise::NoiseModel &noise, + const std::vector &methods); // Set circuit parallelization void set_parallelization_circuit(const Circuit &circ, @@ -355,7 +347,8 @@ class Controller { bool parallel_nested_ = false; - //max number of states can be stored on memory for batched multi-shots/experiments optimization + // max number of states can be stored on memory for batched + // multi-shots/experiments optimization int max_batched_states_; // max number of qubits in given circuits @@ -371,15 +364,18 @@ class Controller { uint_t cache_block_qubit_ = 0; - //multi-chunks are required to simulate circuits + // multi-chunks are required to simulate circuits bool multi_chunk_required_ = false; - //config setting for multi-shot parallelization + // config setting for multi-shot parallelization bool batched_shots_gpu_ = true; - int_t batched_shots_gpu_max_qubits_ = 16; //multi-shot parallelization is applied if qubits is less than max qubits - bool enable_batch_multi_shots_ = false; //multi-shot parallelization can be applied + int_t batched_shots_gpu_max_qubits_ = + 16; // multi-shot parallelization is applied if qubits is less than max + // qubits + bool enable_batch_multi_shots_ = + false; // multi-shot parallelization can be applied - //settings for cuStateVec + // settings for cuStateVec bool cuStateVec_enable_ = false; }; @@ -455,13 +451,13 @@ void Controller::set_config(const Config &config) { // enable multiple qregs if cache blocking is enabled if (config.blocking_qubits.has_value()) - cache_block_qubit_ = config.blocking_qubits.value(); + cache_block_qubit_ = config.blocking_qubits.value(); - //enable batched multi-shots/experiments optimization + // enable batched multi-shots/experiments optimization batched_shots_gpu_ = config.batched_shots_gpu; batched_shots_gpu_max_qubits_ = config.batched_shots_gpu_max_qubits; - //cuStateVec configs + // cuStateVec configs cuStateVec_enable_ = false; if (config.cuStateVec_enable.has_value()) cuStateVec_enable_ = config.cuStateVec_enable.value(); @@ -486,10 +482,10 @@ void Controller::set_config(const Config &config) { method_ = Method::tensor_network; } else if (config.method != "automatic") { throw std::runtime_error(std::string("Invalid simulation method (") + - method + std::string(").")); + method + std::string(").")); } - if(method_ == Method::density_matrix || method_ == Method::unitary) + if (method_ == Method::density_matrix || method_ == Method::unitary) batched_shots_gpu_max_qubits_ /= 2; // Override automatic simulation method with a fixed method @@ -510,30 +506,31 @@ void Controller::set_config(const Config &config) { #else #ifndef AER_CUSTATEVEC - if(cuStateVec_enable_){ - //Aer is not built for cuStateVec - throw std::runtime_error( - "Simulation device \"GPU\" does not support cuStateVec on this system"); + if (cuStateVec_enable_) { + // Aer is not built for cuStateVec + throw std::runtime_error("Simulation device \"GPU\" does not support " + "cuStateVec on this system"); } #endif int nDev; if (cudaGetDeviceCount(&nDev) != cudaSuccess) { - cudaGetLastError(); - throw std::runtime_error("No CUDA device available!"); + cudaGetLastError(); + throw std::runtime_error("No CUDA device available!"); } sim_device_ = Device::GPU; #endif - } - else { + } else { throw std::runtime_error(std::string("Invalid simulation device (\"") + - sim_device_name_ + std::string("\").")); + sim_device_name_ + std::string("\").")); } - if(method_ == Method::tensor_network){ + if (method_ == Method::tensor_network) { #if defined(AER_THRUST_CUDA) && defined(AER_CUTENSORNET) - if(sim_device_ != Device::GPU) + if (sim_device_ != Device::GPU) #endif - throw std::runtime_error("Invalid combination of simulation method and device, \"tensor_network\" only supports \"device=GPU\""); + throw std::runtime_error( + "Invalid combination of simulation method and device, " + "\"tensor_network\" only supports \"device=GPU\""); } std::string precision = config.precision; @@ -543,7 +540,7 @@ void Controller::set_config(const Config &config) { sim_precision_ = Precision::Single; } else { throw std::runtime_error(std::string("Invalid simulation precision (") + - precision + std::string(").")); + precision + std::string(").")); } } @@ -576,40 +573,41 @@ void Controller::clear_parallelization() { } void Controller::set_parallelization_experiments( - const std::vector &circuits, - const Noise::NoiseModel &noise, - const std::vector &methods) -{ + const std::vector &circuits, const Noise::NoiseModel &noise, + const std::vector &methods) { std::vector required_memory_mb_list(circuits.size()); max_qubits_ = 0; for (size_t j = 0; j < circuits.size(); j++) { - if(circuits[j].num_qubits > max_qubits_) + if (circuits[j].num_qubits > max_qubits_) max_qubits_ = circuits[j].num_qubits; - required_memory_mb_list[j] = required_memory_mb(circuits[j], noise, methods[j]); + required_memory_mb_list[j] = + required_memory_mb(circuits[j], noise, methods[j]); } std::sort(required_memory_mb_list.begin(), required_memory_mb_list.end(), std::greater<>()); - //set max batchable number of circuits - if(batched_shots_gpu_){ - if(required_memory_mb_list[0] == 0 || max_qubits_ == 0) + // set max batchable number of circuits + if (batched_shots_gpu_) { + if (required_memory_mb_list[0] == 0 || max_qubits_ == 0) max_batched_states_ = 1; - else{ - if(sim_device_ == Device::GPU){ - max_batched_states_ = ((max_gpu_memory_mb_/num_gpus_*8/10) / required_memory_mb_list[0])*num_gpus_; - } - else{ - max_batched_states_ = (max_memory_mb_*8/10) / required_memory_mb_list[0]; + else { + if (sim_device_ == Device::GPU) { + max_batched_states_ = ((max_gpu_memory_mb_ / num_gpus_ * 8 / 10) / + required_memory_mb_list[0]) * + num_gpus_; + } else { + max_batched_states_ = + (max_memory_mb_ * 8 / 10) / required_memory_mb_list[0]; } } } - if(max_qubits_ == 0) + if (max_qubits_ == 0) max_qubits_ = 1; - if(explicit_parallelization_ ) + if (explicit_parallelization_) return; - if(circuits.size() == 1){ + if (circuits.size() == 1) { parallel_experiments_ = 1; return; } @@ -647,55 +645,56 @@ void Controller::set_parallelization_experiments( void Controller::set_parallelization_circuit(const Circuit &circ, const Noise::NoiseModel &noise, - const Method method) -{ + const Method method) { enable_batch_multi_shots_ = false; - if(batched_shots_gpu_ && sim_device_ == Device::GPU && - circ.shots > 1 && max_batched_states_ >= num_gpus_ && - batched_shots_gpu_max_qubits_ >= circ.num_qubits ){ - enable_batch_multi_shots_ = true; + if (batched_shots_gpu_ && sim_device_ == Device::GPU && circ.shots > 1 && + max_batched_states_ >= num_gpus_ && + batched_shots_gpu_max_qubits_ >= circ.num_qubits) { + enable_batch_multi_shots_ = true; } - if(sim_device_ == Device::GPU && cuStateVec_enable_){ - enable_batch_multi_shots_ = false; //cuStateVec does not support batch execution of multi-shots + if (sim_device_ == Device::GPU && cuStateVec_enable_) { + enable_batch_multi_shots_ = + false; // cuStateVec does not support batch execution of multi-shots return; } - if(explicit_parallelization_) + if (explicit_parallelization_) return; // Check for trivial parallelization conditions switch (method) { - case Method::statevector: - case Method::stabilizer: - case Method::unitary: - case Method::matrix_product_state: { - if (circ.shots == 1 || num_process_per_experiment_ > 1 || - (!noise.has_quantum_errors() && - check_measure_sampling_opt(circ, method))) { - parallel_shots_ = 1; - parallel_state_update_ = - std::max({1, max_parallel_threads_ / parallel_experiments_}); - return; - } - break; + case Method::statevector: + case Method::stabilizer: + case Method::unitary: + case Method::matrix_product_state: { + if (circ.shots == 1 || num_process_per_experiment_ > 1 || + (!noise.has_quantum_errors() && + check_measure_sampling_opt(circ, method))) { + parallel_shots_ = 1; + parallel_state_update_ = + std::max({1, max_parallel_threads_ / parallel_experiments_}); + return; } - case Method::density_matrix: - case Method::superop: - case Method::tensor_network: { - if (circ.shots == 1 || num_process_per_experiment_ > 1 || - check_measure_sampling_opt(circ, method)) { - parallel_shots_ = 1; - parallel_state_update_ = - std::max({1, max_parallel_threads_ / parallel_experiments_}); - return; - } - break; + break; + } + case Method::density_matrix: + case Method::superop: + case Method::tensor_network: { + if (circ.shots == 1 || num_process_per_experiment_ > 1 || + check_measure_sampling_opt(circ, method)) { + parallel_shots_ = 1; + parallel_state_update_ = + std::max({1, max_parallel_threads_ / parallel_experiments_}); + return; } - case Method::extended_stabilizer: - break; - default: - throw std::invalid_argument("Cannot set parallelization for unresolved method."); + break; + } + case Method::extended_stabilizer: + break; + default: + throw std::invalid_argument( + "Cannot set parallelization for unresolved method."); } // Use a local variable to not override stored maximum based @@ -715,7 +714,8 @@ void Controller::set_parallelization_circuit(const Circuit &circ, // And assign the remaining threads to state update int circ_memory_mb = required_memory_mb(circ, noise, method) / num_process_per_experiment_; - size_t mem_size = (sim_device_ == Device::GPU) ? max_gpu_memory_mb_ : max_memory_mb_; + size_t mem_size = + (sim_device_ == Device::GPU) ? max_gpu_memory_mb_ : max_memory_mb_; if (mem_size < circ_memory_mb) throw std::runtime_error( "a circuit requires more memory than max_memory_mb."); @@ -724,7 +724,7 @@ void Controller::set_parallelization_circuit(const Circuit &circ, int shots = circ.shots; parallel_shots_ = std::min( - {static_cast(mem_size/(circ_memory_mb*2)), max_shots, shots}); + {static_cast(mem_size / (circ_memory_mb * 2)), max_shots, shots}); } parallel_state_update_ = (parallel_shots_ > 1) @@ -734,21 +734,23 @@ void Controller::set_parallelization_circuit(const Circuit &circ, bool Controller::multiple_chunk_required(const Circuit &circ, const Noise::NoiseModel &noise, - const Method method) const -{ + const Method method) const { if (circ.num_qubits < 3) return false; if (cache_block_qubit_ >= 2 && cache_block_qubit_ < circ.num_qubits) return true; - if(num_process_per_experiment_ == 1 && sim_device_ == Device::GPU && num_gpus_ > 0){ - return (max_gpu_memory_mb_ / num_gpus_ < required_memory_mb(circ, noise, method)); + if (num_process_per_experiment_ == 1 && sim_device_ == Device::GPU && + num_gpus_ > 0) { + return (max_gpu_memory_mb_ / num_gpus_ < + required_memory_mb(circ, noise, method)); } - if(num_process_per_experiment_ > 1){ + if (num_process_per_experiment_ > 1) { size_t total_mem = max_memory_mb_; - if(sim_device_ == Device::GPU) + if (sim_device_ == Device::GPU) total_mem += max_gpu_memory_mb_; - if(total_mem*num_process_per_experiment_ > required_memory_mb(circ, noise, method)) + if (total_mem * num_process_per_experiment_ > + required_memory_mb(circ, noise, method)) return true; } @@ -757,27 +759,24 @@ bool Controller::multiple_chunk_required(const Circuit &circ, bool Controller::multiple_shots_required(const Circuit &circ, const Noise::NoiseModel &noise, - const Method method) const -{ + const Method method) const { if (circ.shots < 2) return false; - if (method == Method::density_matrix || - method == Method::superop || + if (method == Method::density_matrix || method == Method::superop || method == Method::unitary) { return false; } bool can_sample = check_measure_sampling_opt(circ, method); - if (noise.is_ideal()){ - return !can_sample; + if (noise.is_ideal()) { + return !can_sample; } return true; } -size_t Controller::get_system_memory_mb() -{ +size_t Controller::get_system_memory_mb() { size_t total_physical_memory = Utils::get_system_memory_mb(); #ifdef AER_MPI // get minimum memory size per process @@ -821,19 +820,16 @@ size_t Controller::get_gpu_memory_mb() { return total_physical_memory >> 20; } - -Transpile::CacheBlocking -Controller::transpile_cache_blocking(Controller::Method method, const Circuit &circ, - const Noise::NoiseModel &noise, - const Config &config) const -{ +Transpile::CacheBlocking Controller::transpile_cache_blocking( + Controller::Method method, const Circuit &circ, + const Noise::NoiseModel &noise, const Config &config) const { Transpile::CacheBlocking cache_block_pass; - const bool is_matrix = (method == Method::density_matrix - || method == Method::unitary); + const bool is_matrix = + (method == Method::density_matrix || method == Method::unitary); const auto complex_size = (sim_precision_ == Precision::Single) - ? sizeof(std::complex) - : sizeof(std::complex); + ? sizeof(std::complex) + : sizeof(std::complex); cache_block_pass.set_num_processes(num_process_per_experiment_); cache_block_pass.set_config(config); @@ -842,7 +838,7 @@ Controller::transpile_cache_blocking(Controller::Method method, const Circuit &c // if blocking is not set by config, automatically set if required if (multiple_chunk_required(circ, noise, method)) { int nplace = num_process_per_experiment_; - if(sim_device_ == Device::GPU && num_gpus_ > 0) + if (sim_device_ == Device::GPU && num_gpus_ > 0) nplace *= num_gpus_; cache_block_pass.set_blocking(circ.num_qubits, get_min_memory_mb() << 20, nplace, complex_size, is_matrix); @@ -908,8 +904,7 @@ Result Controller::execute(const inputdata_t &input_qobj) { Result Controller::execute(std::vector &circuits, Noise::NoiseModel &noise_model, - const Config &config) -{ + const Config &config) { // Start QOBJ timer auto timer_start = myclock_t::now(); @@ -922,15 +917,15 @@ Result Controller::execute(std::vector &circuits, // Execute each circuit in a try block try { - //check if multi-chunk distribution is required + // check if multi-chunk distribution is required bool multi_chunk_required_ = false; - for (size_t j = 0; j < circuits.size(); j++){ - if(circuits[j].num_qubits > 0){ - if(multiple_chunk_required(circuits[j], noise_model, methods[j])) + for (size_t j = 0; j < circuits.size(); j++) { + if (circuits[j].num_qubits > 0) { + if (multiple_chunk_required(circuits[j], noise_model, methods[j])) multi_chunk_required_ = true; } } - if(multi_chunk_required_) + if (multi_chunk_required_) num_process_per_experiment_ = num_processes_; else num_process_per_experiment_ = 1; @@ -955,7 +950,8 @@ Result Controller::execute(std::vector &circuits, // store rank and number of processes, if no distribution rank=0 procs=1 is // set - result.metadata.add(num_process_per_experiment_, "num_processes_per_experiments"); + result.metadata.add(num_process_per_experiment_, + "num_processes_per_experiments"); result.metadata.add(num_processes_, "num_mpi_processes"); result.metadata.add(myrank_, "mpi_rank"); @@ -966,7 +962,7 @@ Result Controller::execute(std::vector &circuits, // Nested parallel experiments parallel_nested_ = true; - //nested should be set to zero if num_threads clause will be used + // nested should be set to zero if num_threads clause will be used omp_set_nested(0); result.metadata.add(parallel_nested_, "omp_nested"); @@ -976,33 +972,35 @@ Result Controller::execute(std::vector &circuits, #endif #ifdef AER_MPI - //average random seed to set the same seed to each process (when seed_simulator is not set) - if(num_processes_ > 1){ + // average random seed to set the same seed to each process (when + // seed_simulator is not set) + if (num_processes_ > 1) { reg_t seeds(circuits.size()); reg_t avg_seeds(circuits.size()); - for(int_t i=0;i &circuits, //------------------------------------------------------------------------- // Base class override //------------------------------------------------------------------------- -void Controller::run_circuit(const Circuit &circ, const Noise::NoiseModel &noise, - const Method method,const Config &config, ExperimentResult &result) const -{ +void Controller::run_circuit(const Circuit &circ, + const Noise::NoiseModel &noise, + const Method method, const Config &config, + ExperimentResult &result) const { // Run the circuit switch (method) { case Method::statevector: { @@ -1052,13 +1051,11 @@ void Controller::run_circuit(const Circuit &circ, const Noise::NoiseModel &noise // Chunk based simualtion if (sim_precision_ == Precision::Double) { // Double-precision Statevector simulation - return run_circuit_helper< - Statevector::State>>( + return run_circuit_helper>>( circ, noise, config, Method::statevector, result); } else { // Single-precision Statevector simulation - return run_circuit_helper< - Statevector::State>>( + return run_circuit_helper>>( circ, noise, config, Method::statevector, result); } } else { @@ -1150,8 +1147,8 @@ void Controller::run_circuit(const Circuit &circ, const Noise::NoiseModel &noise case Method::stabilizer: // Stabilizer simulation // TODO: Stabilizer doesn't yet support custom state initialization - return run_circuit_helper( - circ, noise, config, Method::stabilizer, result); + return run_circuit_helper(circ, noise, config, + Method::stabilizer, result); case Method::extended_stabilizer: return run_circuit_helper( circ, noise, config, Method::extended_stabilizer, result); @@ -1267,7 +1264,7 @@ Transpile::Fusion Controller::transpile_fusion(Method method, } case Method::matrix_product_state: { fusion_pass.active = false; - return fusion_pass; // Do not allow the config to set active for MPS + return fusion_pass; // Do not allow the config to set active for MPS } case Method::statevector: { if (fusion_pass.allow_kraus) { @@ -1282,13 +1279,13 @@ Transpile::Fusion Controller::transpile_fusion(Method method, break; } case Method::tensor_network: { - if(opset.contains(Operations::OpType::save_statevec) || opset.contains(Operations::OpType::save_statevec_dict)){ + if (opset.contains(Operations::OpType::save_statevec) || + opset.contains(Operations::OpType::save_statevec_dict)) { if (fusion_pass.allow_kraus) { // Halve default max fused qubits for Kraus noise fusion fusion_pass.max_qubit /= 2; } - } - else{ + } else { // Halve the default threshold and max fused qubits for density matrix fusion_pass.threshold /= 2; fusion_pass.max_qubit /= 2; @@ -1312,10 +1309,8 @@ Transpile::Fusion Controller::transpile_fusion(Method method, template void Controller::run_circuit_helper(const Circuit &circ, const Noise::NoiseModel &noise, - const Config &config, - const Method method, - ExperimentResult &result) const -{ + const Config &config, const Method method, + ExperimentResult &result) const { // Start individual circuit timer auto timer_start = myclock_t::now(); // state circuit timer @@ -1348,7 +1343,7 @@ void Controller::run_circuit_helper(const Circuit &circ, result.metadata.add(false, "measure_sampling"); result.metadata.add(false, "batched_shots_optimization"); - if(circ.num_qubits > 0){ //do nothing for query steps + if (circ.num_qubits > 0) { // do nothing for query steps // Choose execution method based on noise and method Circuit opt_circ; bool noise_sampling = false; @@ -1364,35 +1359,40 @@ void Controller::run_circuit_helper(const Circuit &circ, result.metadata.add("readout", "noise"); } // Superop noise sampling - else if (method == Method::density_matrix || method == Method::superop || (method == Method::tensor_network && !has_statevector_ops(circ))) { + else if (method == Method::density_matrix || method == Method::superop || + (method == Method::tensor_network && + !has_statevector_ops(circ))) { // Sample noise using SuperOp method - opt_circ = noise.sample_noise(circ, rng, Noise::NoiseModel::Method::superop); + opt_circ = + noise.sample_noise(circ, rng, Noise::NoiseModel::Method::superop); result.metadata.add("superop", "noise"); } // Kraus noise sampling else if (noise.opset().contains(Operations::OpType::kraus) || noise.opset().contains(Operations::OpType::superop)) { - opt_circ = noise.sample_noise(circ, rng, Noise::NoiseModel::Method::kraus); + opt_circ = + noise.sample_noise(circ, rng, Noise::NoiseModel::Method::kraus); result.metadata.add("kraus", "noise"); } // General circuit noise sampling else { - if(enable_batch_multi_shots_ && !multi_chunk_required_){ - //batched optimization samples noise at runtime - opt_circ = noise.sample_noise(circ, rng, Noise::NoiseModel::Method::circuit, true); - } - else{ + if (enable_batch_multi_shots_ && !multi_chunk_required_) { + // batched optimization samples noise at runtime + opt_circ = noise.sample_noise( + circ, rng, Noise::NoiseModel::Method::circuit, true); + } else { noise_sampling = true; } result.metadata.add("circuit", "noise"); } - if(noise_sampling){ - run_circuit_with_sampled_noise(circ, noise, config, method, result); - } - else{ + if (noise_sampling) { + run_circuit_with_sampled_noise(circ, noise, config, method, + result); + } else { // Run multishot simulation without noise sampling - run_circuit_without_sampled_noise(opt_circ, noise, config, method, result); + run_circuit_without_sampled_noise(opt_circ, noise, config, + method, result); } } @@ -1430,13 +1430,11 @@ void Controller::run_single_shot(const Circuit &circ, State_t &state, } template -void Controller::run_with_sampling(const Circuit &circ, - State_t &state, - ExperimentResult &result, - RngEngine &rng, +void Controller::run_with_sampling(const Circuit &circ, State_t &state, + ExperimentResult &result, RngEngine &rng, const uint_t block_bits, const uint_t shots) const { - auto& ops = circ.ops; + auto &ops = circ.ops; auto first_meas = circ.first_measure_pos; // Position of first measurement op bool final_ops = (first_meas == ops.size()); @@ -1447,22 +1445,22 @@ void Controller::run_with_sampling(const Circuit &circ, state.initialize_qreg(circ.num_qubits); state.initialize_creg(circ.num_memory, circ.num_registers); - state.apply_ops(ops.cbegin(), ops.cbegin() + first_meas, result, rng, final_ops); + state.apply_ops(ops.cbegin(), ops.cbegin() + first_meas, result, rng, + final_ops); // Get measurement operations and set of measured qubits - measure_sampler(circ.ops.begin() + first_meas, circ.ops.end(), shots, state, result, rng); + measure_sampler(circ.ops.begin() + first_meas, circ.ops.end(), shots, state, + result, rng); } template -void Controller::run_circuit_without_sampled_noise(Circuit &circ, - const Noise::NoiseModel &noise, - const Config &config, - const Method method, - ExperimentResult &result) const -{ +void Controller::run_circuit_without_sampled_noise( + Circuit &circ, const Noise::NoiseModel &noise, const Config &config, + const Method method, ExperimentResult &result) const { State_t state; - // Validate gateset and memory requirements, raise exception if they're exceeded + // Validate gateset and memory requirements, raise exception if they're + // exceeded validate_state(state, circ, noise, true); // Set state config @@ -1481,8 +1479,9 @@ void Controller::run_circuit_without_sampled_noise(Circuit &circ, // Cache blocking pass uint_t block_bits = circ.num_qubits; - if(state.multi_chunk_distribution_supported()){ - auto cache_block_pass = transpile_cache_blocking(method, circ, dummy_noise, config); + if (state.multi_chunk_distribution_supported()) { + auto cache_block_pass = + transpile_cache_blocking(method, circ, dummy_noise, config); cache_block_pass.set_sample_measure(can_sample); cache_block_pass.optimize_circuit(circ, dummy_noise, state.opset(), result); if (cache_block_pass.enabled()) { @@ -1508,8 +1507,8 @@ void Controller::run_circuit_without_sampled_noise(Circuit &circ, #pragma omp parallel for num_threads(parallel_shots_) for (int i = 0; i < parallel_shots_; i++) { - uint_t i_shot = circ.shots*i/parallel_shots_; - uint_t shot_end = circ.shots*(i+1)/parallel_shots_; + uint_t i_shot = circ.shots * i / parallel_shots_; + uint_t shot_end = circ.shots * (i + 1) / parallel_shots_; uint_t this_shot = shot_end - i_shot; State_t shot_state; @@ -1524,7 +1523,8 @@ void Controller::run_circuit_without_sampled_noise(Circuit &circ, RngEngine rng; rng.set_seed(circ.seed + i); - run_with_sampling(circ, shot_state, par_results[i], rng, block_bits, this_shot); + run_with_sampling(circ, shot_state, par_results[i], rng, block_bits, + this_shot); shot_state.add_metadata(par_results[i]); } @@ -1532,8 +1532,8 @@ void Controller::run_circuit_without_sampled_noise(Circuit &circ, result.combine(std::move(res)); } - if (sim_device_name_ == "GPU"){ - if(parallel_shots_ >= num_gpus_) + if (sim_device_name_ == "GPU") { + if (parallel_shots_ >= num_gpus_) result.metadata.add(num_gpus_, "gpu_parallel_shots_"); else result.metadata.add(parallel_shots_, "gpu_parallel_shots_"); @@ -1542,67 +1542,71 @@ void Controller::run_circuit_without_sampled_noise(Circuit &circ, // Add measure sampling metadata result.metadata.add(true, "measure_sampling"); - } - else{ + } else { // Perform standard execution if we cannot apply the // measurement sampling optimization - if(block_bits == circ.num_qubits && enable_batch_multi_shots_ && state.multi_shot_parallelization_supported()){ - //apply batched multi-shots optimization (currenly only on GPU) + if (block_bits == circ.num_qubits && enable_batch_multi_shots_ && + state.multi_shot_parallelization_supported()) { + // apply batched multi-shots optimization (currenly only on GPU) state.set_max_bached_shots(max_batched_states_); state.set_distribution(num_processes_); state.set_max_matrix_qubits(max_bits); state.set_num_creg_bits(circ.num_memory, circ.num_registers); - state.allocate(circ.num_qubits, circ.num_qubits, circ.shots); //allocate multiple-shots + state.allocate(circ.num_qubits, circ.num_qubits, + circ.shots); // allocate multiple-shots - //qreg is initialized inside state class + // qreg is initialized inside state class state.initialize_creg(circ.num_memory, circ.num_registers); - state.apply_ops_multi_shots(circ.ops.cbegin(), circ.ops.cend(), noise, result, circ.seed, true); + state.apply_ops_multi_shots(circ.ops.cbegin(), circ.ops.cend(), noise, + result, circ.seed, true); result.save_count_data(state.cregs(), save_creg_memory_); // Add batched multi-shots optimizaiton metadata result.metadata.add(true, "batched_shots_optimization"); - } - else{ + } else { std::vector par_results(parallel_shots_); int_t par_shots = parallel_shots_; - if(block_bits != circ.num_qubits) + if (block_bits != circ.num_qubits) par_shots = 1; - auto run_circuit_without_sampled_noise_lambda = [this,&par_results,circ,noise,config,method,block_bits,max_bits,par_shots](int_t i){ - uint_t i_shot,shot_end; - i_shot = circ.shots*i/par_shots; - shot_end = circ.shots*(i+1)/par_shots; - - State_t par_state; - // Set state config - par_state.set_config(config); - par_state.set_parallelization(parallel_state_update_); - par_state.set_global_phase(circ.global_phase_angle); - par_state.enable_density_matrix(!has_statevector_ops(circ)); - - par_state.set_distribution(num_process_per_experiment_); - par_state.set_max_matrix_qubits(max_bits ); - - // allocate qubit register - par_state.allocate(circ.num_qubits, block_bits); - - for(;i_shot 1),0,par_shots,run_circuit_without_sampled_noise_lambda); + auto run_circuit_without_sampled_noise_lambda = + [this, &par_results, circ, noise, config, method, block_bits, + max_bits, par_shots](int_t i) { + uint_t i_shot, shot_end; + i_shot = circ.shots * i / par_shots; + shot_end = circ.shots * (i + 1) / par_shots; + + State_t par_state; + // Set state config + par_state.set_config(config); + par_state.set_parallelization(parallel_state_update_); + par_state.set_global_phase(circ.global_phase_angle); + par_state.enable_density_matrix(!has_statevector_ops(circ)); + + par_state.set_distribution(num_process_per_experiment_); + par_state.set_max_matrix_qubits(max_bits); + + // allocate qubit register + par_state.allocate(circ.num_qubits, block_bits); + + for (; i_shot < shot_end; i_shot++) { + RngEngine rng; + rng.set_seed(circ.seed + i_shot); + run_single_shot(circ, par_state, par_results[i], rng); + } + par_state.add_metadata(par_results[i]); + }; + Utils::apply_omp_parallel_for((par_shots > 1), 0, par_shots, + run_circuit_without_sampled_noise_lambda); for (auto &res : par_results) { result.combine(std::move(res)); } - if (sim_device_name_ == "GPU"){ - if(par_shots >= num_gpus_) + if (sim_device_name_ == "GPU") { + if (par_shots >= num_gpus_) result.metadata.add(num_gpus_, "gpu_parallel_shots_"); else result.metadata.add(par_shots, "gpu_parallel_shots_"); @@ -1615,16 +1619,17 @@ void Controller::run_circuit_without_sampled_noise(Circuit &circ, template void Controller::run_circuit_with_sampled_noise( const Circuit &circ, const Noise::NoiseModel &noise, const Config &config, - const Method method, ExperimentResult &result) const -{ + const Method method, ExperimentResult &result) const { std::vector par_results(parallel_shots_); - auto run_circuit_with_sampled_noise_lambda = [this,&par_results,circ,noise,config,method](int_t i){ + auto run_circuit_with_sampled_noise_lambda = [this, &par_results, circ, noise, + config, method](int_t i) { State_t state; - uint_t i_shot,shot_end; + uint_t i_shot, shot_end; Noise::NoiseModel dummy_noise; - // Validate gateset and memory requirements, raise exception if they're exceeded + // Validate gateset and memory requirements, raise exception if they're + // exceeded validate_state(state, circ, noise, true); // Set state config @@ -1635,12 +1640,13 @@ void Controller::run_circuit_with_sampled_noise( // Transpilation for circuit noise method auto fusion_pass = transpile_fusion(method, circ.opset(), config); - auto cache_block_pass = transpile_cache_blocking(method, circ, noise, config); + auto cache_block_pass = + transpile_cache_blocking(method, circ, noise, config); - i_shot = circ.shots*i/parallel_shots_; - shot_end = circ.shots*(i+1)/parallel_shots_; + i_shot = circ.shots * i / parallel_shots_; + shot_end = circ.shots * (i + 1) / parallel_shots_; - for(;i_shot 1),0,parallel_shots_,run_circuit_with_sampled_noise_lambda); + Utils::apply_omp_parallel_for((parallel_shots_ > 1), 0, parallel_shots_, + run_circuit_with_sampled_noise_lambda); for (auto &res : par_results) { result.combine(std::move(res)); } - if (sim_device_name_ == "GPU"){ - if(parallel_shots_ >= num_gpus_) + if (sim_device_name_ == "GPU") { + if (parallel_shots_ >= num_gpus_) result.metadata.add(num_gpus_, "gpu_parallel_shots_"); else result.metadata.add(parallel_shots_, "gpu_parallel_shots_"); @@ -1695,20 +1702,19 @@ bool Controller::check_measure_sampling_opt(const Circuit &circ, // If density matrix, unitary, superop method all supported instructions // allow sampling - if (method == Method::density_matrix || - method == Method::superop || + if (method == Method::density_matrix || method == Method::superop || method == Method::unitary) { return true; } - if(method == Method::tensor_network){ - //if there are no save statevec ops, tensor network simulator runs as density matrix simulator - if((!circ.opset().contains(Operations::OpType::save_statevec)) && - (!circ.opset().contains(Operations::OpType::save_statevec_dict)) ){ - return true; + if (method == Method::tensor_network) { + // if there are no save statevec ops, tensor network simulator runs as + // density matrix simulator + if ((!circ.opset().contains(Operations::OpType::save_statevec)) && + (!circ.opset().contains(Operations::OpType::save_statevec_dict))) { + return true; } } - // If circuit contains a non-initial initialize that is not a full width // instruction we can't sample if (circ.can_sample_initialize == false) { @@ -1724,7 +1730,7 @@ bool Controller::check_measure_sampling_opt(const Circuit &circ, circ.opset().contains(Operations::OpType::kraus) || circ.opset().contains(Operations::OpType::superop) || circ.opset().contains(Operations::OpType::jump) || - circ.opset().contains(Operations::OpType::mark )) { + circ.opset().contains(Operations::OpType::mark)) { return false; } // Otherwise true @@ -1732,10 +1738,10 @@ bool Controller::check_measure_sampling_opt(const Circuit &circ, } template -void Controller::measure_sampler( - InputIterator first_meas, InputIterator last_meas, uint_t shots, - State_t &state, ExperimentResult &result, RngEngine &rng, int_t shot_index) const -{ +void Controller::measure_sampler(InputIterator first_meas, + InputIterator last_meas, uint_t shots, + State_t &state, ExperimentResult &result, + RngEngine &rng, int_t shot_index) const { // Check if meas_circ is empty, and if so return initial creg if (first_meas == last_meas) { while (shots-- > 0) { @@ -1766,7 +1772,7 @@ void Controller::measure_sampler( // Generate the samples uint_t shots_or_index; - if(shot_index < 0) + if (shot_index < 0) shots_or_index = shots; else shots_or_index = shot_index; @@ -1797,8 +1803,10 @@ void Controller::measure_sampler( } // Process samples - uint_t num_memory = (memory_map.empty()) ? 0ULL : 1 + memory_map.rbegin()->first; - uint_t num_registers = (register_map.empty()) ? 0ULL : 1 + register_map.rbegin()->first; + uint_t num_memory = + (memory_map.empty()) ? 0ULL : 1 + memory_map.rbegin()->first; + uint_t num_registers = + (register_map.empty()) ? 0ULL : 1 + register_map.rbegin()->first; ClassicalRegister creg; while (!all_samples.empty()) { auto sample = all_samples.back(); @@ -1821,14 +1829,13 @@ void Controller::measure_sampler( } // Save count data - result.save_count_data(creg, save_creg_memory_); + result.save_count_data(creg, save_creg_memory_); // pop off processed sample all_samples.pop_back(); } } - //------------------------------------------------------------------------- // Validation //------------------------------------------------------------------------- @@ -1837,22 +1844,28 @@ std::vector Controller::simulation_methods(std::vector &circuits, Noise::NoiseModel &noise_model) const { // Does noise model contain kraus noise - bool kraus_noise = (noise_model.opset().contains(Operations::OpType::kraus) || - noise_model.opset().contains(Operations::OpType::superop)); + bool kraus_noise = + (noise_model.opset().contains(Operations::OpType::kraus) || + noise_model.opset().contains(Operations::OpType::superop)); if (method_ == Method::automatic) { // Determine simulation methods for each circuit and noise model std::vector sim_methods; bool superop_enabled = false; bool kraus_enabled = false; - for (const auto& circ: circuits) { + for (const auto &circ : circuits) { auto method = automatic_simulation_method(circ, noise_model); sim_methods.push_back(method); - if (!superop_enabled && (method == Method::density_matrix || method == Method::superop || (method == Method::tensor_network && !has_statevector_ops(circ)) )) { + if (!superop_enabled && + (method == Method::density_matrix || method == Method::superop || + (method == Method::tensor_network && !has_statevector_ops(circ)))) { noise_model.enable_superop_method(max_parallel_threads_); superop_enabled = true; } else if (kraus_noise && !kraus_enabled && - (method == Method::statevector || method == Method::matrix_product_state || (method == Method::tensor_network && has_statevector_ops(circ))) ) { + (method == Method::statevector || + method == Method::matrix_product_state || + (method == Method::tensor_network && + has_statevector_ops(circ)))) { noise_model.enable_kraus_method(max_parallel_threads_); kraus_enabled = true; } @@ -1864,29 +1877,26 @@ Controller::simulation_methods(std::vector &circuits, std::vector sim_methods(circuits.size(), method_); if (method_ == Method::density_matrix || method_ == Method::superop) { noise_model.enable_superop_method(max_parallel_threads_); - } else if (kraus_noise && ( - method_ == Method::statevector - || method_ == Method::matrix_product_state)) { + } else if (kraus_noise && (method_ == Method::statevector || + method_ == Method::matrix_product_state)) { noise_model.enable_kraus_method(max_parallel_threads_); - } - else if(method_ == Method::tensor_network){ + } else if (method_ == Method::tensor_network) { bool has_save_statevec = false; - for (const auto& circ: circuits) { + for (const auto &circ : circuits) { has_save_statevec |= has_statevector_ops(circ); - if(has_save_statevec) + if (has_save_statevec) break; } - if(!has_save_statevec) + if (!has_save_statevec) noise_model.enable_superop_method(max_parallel_threads_); - else if(kraus_noise) + else if (kraus_noise) noise_model.enable_kraus_method(max_parallel_threads_); } return sim_methods; } -Controller::Method -Controller::automatic_simulation_method(const Circuit &circ, - const Noise::NoiseModel &noise_model) const { +Controller::Method Controller::automatic_simulation_method( + const Circuit &circ, const Noise::NoiseModel &noise_model) const { // If circuit and noise model are Clifford run on Stabilizer simulator if (validate_method(Method::stabilizer, circ, noise_model, false)) { return Method::stabilizer; @@ -1908,12 +1918,10 @@ Controller::automatic_simulation_method(const Circuit &circ, // operations only with preference given by memory requirements // statevector > density matrix > matrix product state > unitary > superop // typically any save state instructions will decide the method. - const std::vector methods({Method::statevector, - Method::density_matrix, - Method::matrix_product_state, - Method::unitary, - Method::superop}); - for (const auto& method : methods) { + const std::vector methods( + {Method::statevector, Method::density_matrix, + Method::matrix_product_state, Method::unitary, Method::superop}); + for (const auto &method : methods) { if (validate_method(method, circ, noise_model, false)) return method; } @@ -1925,34 +1933,40 @@ Controller::automatic_simulation_method(const Circuit &circ, return Method::statevector; } -bool Controller::validate_method(Method method, - const Circuit &circ, +bool Controller::validate_method(Method method, const Circuit &circ, const Noise::NoiseModel &noise_model, bool throw_except) const { // Switch wrapper for templated function validate_state switch (method) { - case Method::stabilizer: - return validate_state(Stabilizer::State(), circ, noise_model, throw_except); - case Method::extended_stabilizer: - return validate_state(ExtendedStabilizer::State(), circ, noise_model, throw_except); - case Method::matrix_product_state: - return validate_state(MatrixProductState::State(), circ, noise_model, throw_except); - case Method::statevector: - return validate_state(Statevector::State<>(), circ, noise_model, throw_except); - case Method::density_matrix: - return validate_state(DensityMatrix::State<>(), circ, noise_model, throw_except); - case Method::unitary: - return validate_state(QubitUnitary::State<>(), circ, noise_model, throw_except); - case Method::superop: - return validate_state(QubitSuperoperator::State<>(), circ, noise_model, throw_except); - case Method::tensor_network: - return validate_state(TensorNetwork::State<>(), circ, noise_model, throw_except); - case Method::automatic: - throw std::runtime_error("Cannot validate circuit for unresolved simulation method."); + case Method::stabilizer: + return validate_state(Stabilizer::State(), circ, noise_model, throw_except); + case Method::extended_stabilizer: + return validate_state(ExtendedStabilizer::State(), circ, noise_model, + throw_except); + case Method::matrix_product_state: + return validate_state(MatrixProductState::State(), circ, noise_model, + throw_except); + case Method::statevector: + return validate_state(Statevector::State<>(), circ, noise_model, + throw_except); + case Method::density_matrix: + return validate_state(DensityMatrix::State<>(), circ, noise_model, + throw_except); + case Method::unitary: + return validate_state(QubitUnitary::State<>(), circ, noise_model, + throw_except); + case Method::superop: + return validate_state(QubitSuperoperator::State<>(), circ, noise_model, + throw_except); + case Method::tensor_network: + return validate_state(TensorNetwork::State<>(), circ, noise_model, + throw_except); + case Method::automatic: + throw std::runtime_error( + "Cannot validate circuit for unresolved simulation method."); } } - template bool Controller::validate_state(const state_t &state, const Circuit &circ, const Noise::NoiseModel &noise, @@ -1980,13 +1994,17 @@ bool Controller::validate_state(const state_t &state, const Circuit &circ, // Validate memory requirements bool memory_valid = true; if (max_memory_mb_ > 0) { - size_t required_mb = state.required_memory_mb(circ.num_qubits, circ.ops) / num_process_per_experiment_; - size_t mem_size = (sim_device_ == Device::GPU) ? max_memory_mb_ + max_gpu_memory_mb_ : max_memory_mb_; + size_t required_mb = state.required_memory_mb(circ.num_qubits, circ.ops) / + num_process_per_experiment_; + size_t mem_size = (sim_device_ == Device::GPU) + ? max_memory_mb_ + max_gpu_memory_mb_ + : max_memory_mb_; memory_valid = (required_mb <= mem_size); if (throw_except && !memory_valid) { error_msg << "Insufficient memory to run circuit " << circ_name; error_msg << " using the " << state.name() << " simulator."; - error_msg << " Required memory: " << required_mb << "M, max memory: " << max_memory_mb_ << "M"; + error_msg << " Required memory: " << required_mb + << "M, max memory: " << max_memory_mb_ << "M"; if (sim_device_ == Device::GPU) { error_msg << " (Host) + " << max_gpu_memory_mb_ << "M (GPU)"; } @@ -2014,13 +2032,15 @@ void Controller::save_exception_to_results(Result &result, } } -int_t Controller::get_matrix_bits(const Operations::Op& op) const -{ +int_t Controller::get_matrix_bits(const Operations::Op &op) const { int_t bit = 1; - if(op.type == Operations::OpType::matrix || op.type == Operations::OpType::diagonal_matrix || op.type == Operations::OpType::initialize) + if (op.type == Operations::OpType::matrix || + op.type == Operations::OpType::diagonal_matrix || + op.type == Operations::OpType::initialize) bit = op.qubits.size(); - else if(op.type == Operations::OpType::kraus || op.type == Operations::OpType::superop){ - if(method_ == Method::density_matrix) + else if (op.type == Operations::OpType::kraus || + op.type == Operations::OpType::superop) { + if (method_ == Method::density_matrix) bit = op.qubits.size() * 2; else bit = op.qubits.size(); @@ -2028,22 +2048,22 @@ int_t Controller::get_matrix_bits(const Operations::Op& op) const return bit; } -int_t Controller::get_max_matrix_qubits(const Circuit &circ) const -{ +int_t Controller::get_max_matrix_qubits(const Circuit &circ) const { int_t max_bits = 0; int_t i; - for(i=0;i #include "misc/hacks.hpp" +#include -#include "framework/results/result.hpp" -#include "framework/python_parser.hpp" -#include "framework/matrix.hpp" #include "framework/config.hpp" +#include "framework/matrix.hpp" +#include "framework/python_parser.hpp" +#include "framework/results/result.hpp" //========================================================================= // Controller Execute interface @@ -30,22 +30,24 @@ namespace AER { template -Result controller_execute(const inputdata_t& qobj) { +Result controller_execute(const inputdata_t &qobj) { controller_t controller; // Fix for MacOS and OpenMP library double initialization crash. // Issue: https://github.com/Qiskit/qiskit-aer/issues/1 if (Parser::check_key("config", qobj)) { - std::string path; - const auto& config = Parser::get_value("config", qobj); - Parser::get_value(path, "library_dir", config); - Hacks::maybe_load_openmp(path); + std::string path; + const auto &config = Parser::get_value("config", qobj); + Parser::get_value(path, "library_dir", config); + Hacks::maybe_load_openmp(path); } return controller.execute(qobj); } template -Result controller_execute(std::vector& input_circs, AER::Noise::NoiseModel &noise_model, AER::Config &config) { +Result controller_execute(std::vector &input_circs, + AER::Noise::NoiseModel &noise_model, + AER::Config &config) { controller_t controller; bool truncate = config.enable_truncation; @@ -77,8 +79,8 @@ Result controller_execute(std::vector& input_circs, AER::Noise::NoiseMo try { // Load circuits - for (size_t i=0; i& input_circs, AER::Noise::NoiseMo const auto circ_params = param_table[i]; const size_t num_params = circ_params[0].second.size(); const size_t num_instr = circ.ops.size(); - for (size_t j=0; j& input_circs, AER::Noise::NoiseMo const auto param_pos = params.first.second; // Validation if (instr_pos >= num_instr) { - throw std::invalid_argument(R"(Invalid parameterized qobj: instruction position out of range)"); + throw std::invalid_argument( + R"(Invalid parameterized qobj: instruction position out of range)"); } auto &op = param_circ.ops[instr_pos]; if (param_pos >= op.params.size()) { - throw std::invalid_argument(R"(Invalid parameterized qobj: instruction param position out of range)"); + throw std::invalid_argument( + R"(Invalid parameterized qobj: instruction param position out of range)"); } if (j >= params.second.size()) { - throw std::invalid_argument(R"(Invalid parameterized qobj: parameterization value out of range)"); + throw std::invalid_argument( + R"(Invalid parameterized qobj: parameterization value out of range)"); } // Update the param op.params[param_pos] = params.second[j]; } // Run truncation. - // TODO: Truncation should be performed and parameters should be resolved after it. - // However, parameters are associated with indices of instructions, which can be changed in truncation. - // Therefore, current implementation performs truncation for each parameter set. + // TODO: Truncation should be performed and parameters should be + // resolved after it. However, parameters are associated with indices + // of instructions, which can be changed in truncation. Therefore, + // current implementation performs truncation for each parameter set. if (truncate) { param_circ.set_params(true); param_circ.set_metadata(config, true); @@ -140,7 +146,7 @@ Result controller_execute(std::vector& input_circs, AER::Noise::NoiseMo else seed = circs[0].seed; - for (auto& circ: circs) { + for (auto &circ : circs) { circ.seed = seed + seed_shift; seed_shift += 2113; } @@ -152,6 +158,5 @@ Result controller_execute(std::vector& input_circs, AER::Noise::NoiseMo return controller.execute(circs, noise_model, config); } - } // end namespace AER #endif diff --git a/src/controllers/state_controller.hpp b/src/controllers/state_controller.hpp index fd54a581d0..bb7ac166e7 100644 --- a/src/controllers/state_controller.hpp +++ b/src/controllers/state_controller.hpp @@ -15,11 +15,11 @@ #ifndef _aer_state_hpp_ #define _aer_state_hpp_ -#include +#include #include +#include #include #include -#include #include "framework/rng.hpp" #include "misc/warnings.hpp" @@ -37,11 +37,11 @@ DISABLE_WARNING_PUSH DISABLE_WARNING_POP #include "framework/creg.hpp" +#include "framework/linalg/vector.hpp" #include "framework/qobj.hpp" #include "framework/results/experiment_result.hpp" #include "framework/results/result.hpp" #include "framework/rng.hpp" -#include "framework/linalg/vector.hpp" #include "noise/noise_model.hpp" @@ -56,8 +56,8 @@ DISABLE_WARNING_POP #include "simulators/statevector/qubitvector.hpp" #include "simulators/statevector/statevector_state.hpp" #include "simulators/superoperator/superoperator_state.hpp" -#include "simulators/unitary/unitarymatrix.hpp" #include "simulators/unitary/unitary_state.hpp" +#include "simulators/unitary/unitarymatrix.hpp" #ifdef AER_THRUST_SUPPORTED #include "simulators/density_matrix/densitymatrix_thrust.hpp" @@ -103,7 +103,7 @@ class AerState { //----------------------------------------------------------------------- AerState() { set_random_seed(); }; - virtual ~AerState() { }; + virtual ~AerState(){}; //----------------------------------------------------------------------- // Configuration @@ -111,28 +111,28 @@ class AerState { // set configuration. // All of the configuration must be done before calling any gate operations. - virtual void configure(const std::string& key, const std::string& value); + virtual void configure(const std::string &key, const std::string &value); // configure a method. - virtual bool set_method(const std::string& name); + virtual bool set_method(const std::string &name); // configure a device. - virtual bool set_device(const std::string& name); + virtual bool set_device(const std::string &name); // configure a precision. - virtual bool set_precision(const std::string& name); + virtual bool set_precision(const std::string &name); // configure custatevec enabled or not - virtual bool set_custatevec(const bool& enabled); + virtual bool set_custatevec(const bool &enabled); // configure number of threads to update state - virtual bool set_parallel_state_update(const uint_t& parallel_state_update); + virtual bool set_parallel_state_update(const uint_t ¶llel_state_update); // configure max number of qubits for a gate - virtual bool set_max_gate_qubits(const uint_t& max_gate_qubits); + virtual bool set_max_gate_qubits(const uint_t &max_gate_qubits); // configure cache blocking qubits - virtual bool set_blocking_qubits(const uint_t& blocking_qubits); + virtual bool set_blocking_qubits(const uint_t &blocking_qubits); // Return true if gate operations have been performed and no configuration // is permitted. @@ -154,7 +154,7 @@ class AerState { // Clear state and buffered ops virtual void clear(); - virtual ExperimentResult& last_result() { return last_result_; }; + virtual ExperimentResult &last_result() { return last_result_; }; //----------------------------------------------------------------------- // Initialization @@ -170,14 +170,16 @@ class AerState { void set_seed(int_t seed); // Allocate qubits with inputted complex array - // method must be statevector and the length of the array must be 2^{num_qubits} - // given data will not be freed in this class - virtual reg_t initialize_statevector(uint_t num_qubits, complex_t* data, bool copy); + // method must be statevector and the length of the array must be + // 2^{num_qubits} given data will not be freed in this class + virtual reg_t initialize_statevector(uint_t num_qubits, complex_t *data, + bool copy); // Allocate qubits with inputted complex array - // method must be densitymatrix and the length of the array must be 4^{num_qubits} - // given data will not be freed in this class - virtual reg_t initialize_density_matrix(uint_t num_qubits, complex_t* data, bool f_order, bool copy); + // method must be densitymatrix and the length of the array must be + // 4^{num_qubits} given data will not be freed in this class + virtual reg_t initialize_density_matrix(uint_t num_qubits, complex_t *data, + bool f_order, bool copy); // Release internal statevector as a vector virtual AER::Vector move_to_vector(); @@ -208,8 +210,11 @@ class AerState { // Apply a N-qubit matrix to the state vector. virtual void apply_unitary(const reg_t &qubits, const cmatrix_t &mat); - // Apply a stacked set of 2^control_count target_count--qubit matrix to the state vector. - virtual void apply_multiplexer(const reg_t &control_qubits, const reg_t &target_qubits, const std::vector &mats); + // Apply a stacked set of 2^control_count target_count--qubit matrix to the + // state vector. + virtual void apply_multiplexer(const reg_t &control_qubits, + const reg_t &target_qubits, + const std::vector &mats); // Apply a N-qubit diagonal matrix to the state vector. virtual void apply_diagonal_matrix(const reg_t &qubits, const cvector_t &mat); @@ -259,22 +264,28 @@ class AerState { // If N=1 this implements an optimized single-qubit phase gate // If N=2 this implements an optimized CPhase gate // If N=3 this implements an optimized CCPhase gate - virtual void apply_mcphase(const reg_t &qubits, const std::complex phase); + virtual void apply_mcphase(const reg_t &qubits, + const std::complex phase); // Apply an optimized H gate virtual void apply_h(const uint_t qubit); // Apply an optimized single-qubit U gate - virtual void apply_u(const uint_t qubit, const double theta, const double phi, const double lambda); + virtual void apply_u(const uint_t qubit, const double theta, const double phi, + const double lambda); // Apply an optimized CU gate - virtual void apply_cu(const reg_t &qubits, const double theta, const double phi, const double lambda, const double gammma); + virtual void apply_cu(const reg_t &qubits, const double theta, + const double phi, const double lambda, + const double gammma); // Apply a general multi-controlled single-qubit unitary gate // If N=1 this implements an optimized single-qubit U gate // If N=2 this implements an optimized CU gate // If N=3 this implements an optimized CCU gate - virtual void apply_mcu(const reg_t &qubits, const double theta, const double phi, const double lambda, const double gammma); + virtual void apply_mcu(const reg_t &qubits, const double theta, + const double phi, const double lambda, + const double gammma); // Apply a general multi-controlled SWAP gate // If N=2 this implements an optimized SWAP gate @@ -341,19 +352,21 @@ class AerState { // The input is a length M list of random reals between [0, 1) used for // generating samples. // The returned value is unordered sampled outcomes - virtual std::vector sample_memory(const reg_t &qubits, uint_t shots); + virtual std::vector sample_memory(const reg_t &qubits, + uint_t shots); // Return M sampled outcomes for Z-basis measurement of specified qubits // The input is a length M list of random reals between [0, 1) used for // generating samples. // The returned value is a map from outcome to its number of samples. - virtual std::unordered_map sample_counts(const reg_t &qubits, uint_t shots); + virtual std::unordered_map sample_counts(const reg_t &qubits, + uint_t shots); //----------------------------------------------------------------------- // Operation management //----------------------------------------------------------------------- // Buffer Operations::Op - virtual void buffer_op(const Operations::Op&& op); + virtual void buffer_op(const Operations::Op &&op); // Flush buffered Operations::Op virtual void flush_ops(); @@ -384,22 +397,20 @@ class AerState { Method method_ = Method::statevector; const std::unordered_map method_names_ = { - {Method::statevector, "statevector"}, - {Method::density_matrix, "density_matrix"}, - {Method::matrix_product_state, "matrix_product_state"}, - {Method::stabilizer, "stabilizer"}, - {Method::extended_stabilizer, "extended_stabilizer"}, - {Method::unitary, "unitary"}, - {Method::superop, "superop"} - }; + {Method::statevector, "statevector"}, + {Method::density_matrix, "density_matrix"}, + {Method::matrix_product_state, "matrix_product_state"}, + {Method::stabilizer, "stabilizer"}, + {Method::extended_stabilizer, "extended_stabilizer"}, + {Method::unitary, "unitary"}, + {Method::superop, "superop"}}; Device device_ = Device::CPU; const std::unordered_map device_names_ = { - {Device::CPU, "CPU"}, - {Device::GPU, "GPU"}, - {Device::ThrustCPU, "ThrustCPU"} - }; + {Device::CPU, "CPU"}, + {Device::GPU, "GPU"}, + {Device::ThrustCPU, "ThrustCPU"}}; Precision precision_ = Precision::Double; @@ -430,22 +441,24 @@ class AerState { bool AerState::is_gpu(bool raise_error) const { #ifndef AER_THRUST_CUDA if (raise_error) - throw std::runtime_error("Simulation device \"GPU\" is not supported on this system"); + throw std::runtime_error( + "Simulation device \"GPU\" is not supported on this system"); else return false; #else int nDev; if (cudaGetDeviceCount(&nDev) != cudaSuccess) { - if (raise_error) { - cudaGetLastError(); - throw std::runtime_error("No CUDA device available!"); - } else return false; + if (raise_error) { + cudaGetLastError(); + throw std::runtime_error("No CUDA device available!"); + } else + return false; } #endif return true; } -void AerState::configure(const std::string& _key, const std::string& _value) { +void AerState::configure(const std::string &_key, const std::string &_value) { std::string key = _key; std::transform(key.begin(), key.end(), key.begin(), ::tolower); @@ -477,44 +490,67 @@ void AerState::configure(const std::string& _key, const std::string& _value) { throw std::runtime_error(msg.str()); } - static std::unordered_set str_config = { "method", "device", "precision", "extended_stabilizer_sampling_method", - "mps_sample_measure_algorithm", "mps_log_data", "mps_swap_direction"}; - static std::unordered_set int_config = { "seed_simulator", "max_parallel_threads", "max_memory_mb", "parallel_state_update", - "blocking_qubits", "batched_shots_gpu_max_qubits", "statevector_parallel_threshold", - "statevector_sample_measure_opt", "stabilizer_max_snapshot_probabilities", - "extended_stabilizer_metropolis_mixing_time", "extended_stabilizer_norm_estimation_samples", - "extended_stabilizer_norm_estimation_repetitions", "extended_stabilizer_parallel_threshold", - "extended_stabilizer_probabilities_snapshot_samples", "matrix_product_state_max_bond_dimension", - "fusion_max_qubit", "fusion_threshold"}; - static std::unordered_set double_config = { "extended_stabilizer_approximation_error", "matrix_product_state_truncation_threshold", - }; - static std::unordered_set bool_config = { "custatevec_enable", "blocking_enable", "batched_shots_gpu", "fusion_enable", "fusion_verbose"}; - - if (str_config.find(key) != str_config.end() ) { + static std::unordered_set str_config = { + "method", + "device", + "precision", + "extended_stabilizer_sampling_method", + "mps_sample_measure_algorithm", + "mps_log_data", + "mps_swap_direction"}; + static std::unordered_set int_config = { + "seed_simulator", + "max_parallel_threads", + "max_memory_mb", + "parallel_state_update", + "blocking_qubits", + "batched_shots_gpu_max_qubits", + "statevector_parallel_threshold", + "statevector_sample_measure_opt", + "stabilizer_max_snapshot_probabilities", + "extended_stabilizer_metropolis_mixing_time", + "extended_stabilizer_norm_estimation_samples", + "extended_stabilizer_norm_estimation_repetitions", + "extended_stabilizer_parallel_threshold", + "extended_stabilizer_probabilities_snapshot_samples", + "matrix_product_state_max_bond_dimension", + "fusion_max_qubit", + "fusion_threshold"}; + static std::unordered_set double_config = { + "extended_stabilizer_approximation_error", + "matrix_product_state_truncation_threshold", + }; + static std::unordered_set bool_config = { + "custatevec_enable", "blocking_enable", "batched_shots_gpu", + "fusion_enable", "fusion_verbose"}; + + if (str_config.find(key) != str_config.end()) { configs_[_key] = _value; - } else if (int_config.find(key) != int_config.end() ) { + } else if (int_config.find(key) != int_config.end()) { configs_[_key] = std::stoi(value); - } else if (bool_config.find(key) != bool_config.end() ) { + } else if (bool_config.find(key) != bool_config.end()) { configs_[_key] = "true" == value; - } else if (double_config.find(key) != double_config.end() ) { + } else if (double_config.find(key) != double_config.end()) { configs_[_key] = std::stod(value); } else { std::stringstream msg; msg << "not supported configuration: " << key << "=" << value << std::endl; throw std::runtime_error(msg.str()); } - }; -bool AerState::set_method(const std::string& method_name) { +bool AerState::set_method(const std::string &method_name) { assert_not_initialized(); - auto it = find_if(method_names_.begin(), method_names_.end(), [method_name](const auto& vt) { return vt.second == method_name; }); - if (it == method_names_.end()) return false; + auto it = find_if( + method_names_.begin(), method_names_.end(), + [method_name](const auto &vt) { return vt.second == method_name; }); + if (it == method_names_.end()) + return false; method_ = it->first; return true; }; -bool AerState::set_device(const std::string& device_name) { +bool AerState::set_device(const std::string &device_name) { assert_not_initialized(); if (device_name == "cpu") device_ = Device::CPU; @@ -527,7 +563,7 @@ bool AerState::set_device(const std::string& device_name) { return true; }; -bool AerState::set_precision(const std::string& precision_name) { +bool AerState::set_precision(const std::string &precision_name) { assert_not_initialized(); if (precision_name == "single") precision_ = Precision::Single; @@ -538,26 +574,25 @@ bool AerState::set_precision(const std::string& precision_name) { return true; }; -bool AerState::set_custatevec(const bool& enabled) { +bool AerState::set_custatevec(const bool &enabled) { assert_not_initialized(); cuStateVec_enable_ = enabled; return true; }; -bool AerState::set_parallel_state_update(const uint_t& parallel_state_update) { +bool AerState::set_parallel_state_update(const uint_t ¶llel_state_update) { assert_not_initialized(); parallel_state_update_ = parallel_state_update; return true; }; -bool AerState::set_max_gate_qubits(const uint_t& max_gate_qubits) { +bool AerState::set_max_gate_qubits(const uint_t &max_gate_qubits) { assert_not_initialized(); max_gate_qubits_ = max_gate_qubits; return true; }; -bool AerState::set_blocking_qubits(const uint_t& blocking_qubits) -{ +bool AerState::set_blocking_qubits(const uint_t &blocking_qubits) { assert_not_initialized(); cache_block_qubits_ = blocking_qubits; return true; @@ -579,9 +614,7 @@ void AerState::assert_not_initialized() const { } }; -void AerState::set_random_seed() { - set_seed(std::random_device()()); -}; +void AerState::set_random_seed() { set_seed(std::random_device()()); }; void AerState::set_seed(int_t seed) { seed_ = seed; @@ -592,7 +625,7 @@ reg_t AerState::allocate_qubits(uint_t num_qubits) { assert_not_initialized(); reg_t ret; for (auto i = 0; i < num_qubits; ++i) - ret.push_back(num_of_qubits_++); + ret.push_back(num_of_qubits_++); return ret; }; @@ -618,85 +651,108 @@ void AerState::initialize_state_controller() { cache_block_pass_.set_config(configs_); }; -void AerState::initialize_qreg_state(std::shared_ptr state) { +void AerState::initialize_qreg_state( + std::shared_ptr state) { if (!state) { if (method_ == Method::statevector) { if (device_ == Device::CPU) if (precision_ == Precision::Double) - state_ = std::make_shared>>(); + state_ = + std::make_shared>>(); else - state_ = std::make_shared>>(); + state_ = + std::make_shared>>(); else // if (device_ == Device::GPU) - #ifdef AER_THRUST_SUPPORTED - if (precision_ == Precision::Double) - state_ = std::make_shared>>(); - else - state_ = std::make_shared>>(); - #else - throw std::runtime_error("specified method does not support non-CPU device: method=statevector"); - #endif +#ifdef AER_THRUST_SUPPORTED + if (precision_ == Precision::Double) + state_ = std::make_shared< + Statevector::State>>(); + else + state_ = std::make_shared< + Statevector::State>>(); +#else + throw std::runtime_error("specified method does not support non-CPU " + "device: method=statevector"); +#endif } else if (method_ == Method::density_matrix) { if (device_ == Device::CPU) if (precision_ == Precision::Double) - state_ = std::make_shared>>(); + state_ = std::make_shared< + DensityMatrix::State>>(); else - state_ = std::make_shared>>(); + state_ = std::make_shared< + DensityMatrix::State>>(); else // if (device_ == Device::GPU) - #ifdef AER_THRUST_SUPPORTED - if (precision_ == Precision::Double) - state_ = std::make_shared>>(); - else - state_ = std::make_shared>>(); - #else - throw std::runtime_error("specified method does not support non-CPU device: method=density_matrix"); - #endif +#ifdef AER_THRUST_SUPPORTED + if (precision_ == Precision::Double) + state_ = std::make_shared< + DensityMatrix::State>>(); + else + state_ = std::make_shared< + DensityMatrix::State>>(); +#else + throw std::runtime_error("specified method does not support non-CPU " + "device: method=density_matrix"); +#endif } else if (method_ == Method::unitary) { if (device_ == Device::CPU) if (precision_ == Precision::Double) - state_ = std::make_shared>>(); + state_ = std::make_shared< + QubitUnitary::State>>(); else - state_ = std::make_shared>>(); + state_ = + std::make_shared>>(); else // if (device_ == Device::GPU) - #ifdef AER_THRUST_SUPPORTED - if (precision_ == Precision::Double) - state_ = std::make_shared>>(); - else - state_ = std::make_shared>>(); - #else - throw std::runtime_error("specified method does not support non-CPU device: method=unitary"); - #endif +#ifdef AER_THRUST_SUPPORTED + if (precision_ == Precision::Double) + state_ = std::make_shared< + QubitUnitary::State>>(); + else + state_ = std::make_shared< + QubitUnitary::State>>(); +#else + throw std::runtime_error( + "specified method does not support non-CPU device: method=unitary"); +#endif } else if (method_ == Method::matrix_product_state) { if (device_ == Device::CPU) state_ = std::make_shared(); else // if (device_ == Device::GPU) - throw std::runtime_error("specified method does not support non-CPU device: method=matrix_product_state"); + throw std::runtime_error("specified method does not support non-CPU " + "device: method=matrix_product_state"); } else if (method_ == Method::stabilizer) { if (device_ == Device::CPU) state_ = std::make_shared(); else // if (device_ == Device::GPU) - throw std::runtime_error("specified method does not support non-CPU device: method=stabilizer"); + throw std::runtime_error("specified method does not support non-CPU " + "device: method=stabilizer"); } else if (method_ == Method::extended_stabilizer) { if (device_ == Device::CPU) state_ = std::make_shared(); else // if (device_ == Device::GPU) - throw std::runtime_error("specified method does not support non-CPU device: method=extended_stabilizer"); + throw std::runtime_error("specified method does not support non-CPU " + "device: method=extended_stabilizer"); } else if (method_ == Method::superop) { if (device_ == Device::CPU) if (precision_ == Precision::Double) - state_ = std::make_shared>>(); + state_ = std::make_shared< + QubitSuperoperator::State>>(); else - state_ = std::make_shared>>(); + state_ = std::make_shared< + QubitSuperoperator::State>>(); else // if (device_ == Device::GPU) - throw std::runtime_error("specified method does not support non-CPU device: method=superop"); + throw std::runtime_error( + "specified method does not support non-CPU device: method=superop"); } else { - throw std::runtime_error("not supported method."); + throw std::runtime_error("not supported method."); } } else { state_ = state; } uint_t block_qubits = cache_block_qubits_; - if(!cache_block_pass_.enabled() || !state_->multi_chunk_distribution_supported()) + if (!cache_block_pass_.enabled() || + !state_->multi_chunk_distribution_supported()) block_qubits = num_of_qubits_; state_->set_config(configs_); state_->set_distribution(num_process_per_experiment_); @@ -719,7 +775,8 @@ void AerState::initialize() { initialized_ = true; }; -reg_t AerState::initialize_statevector(uint_t num_of_qubits, complex_t* data, bool copy) { +reg_t AerState::initialize_statevector(uint_t num_of_qubits, complex_t *data, + bool copy) { assert_not_initialized(); num_of_qubits_ = num_of_qubits; @@ -728,9 +785,11 @@ reg_t AerState::initialize_statevector(uint_t num_of_qubits, complex_t* data, bo initialize_state_controller(); if (device_ != Device::CPU) - throw std::runtime_error("only CPU device supports initialize_statevector()"); + throw std::runtime_error( + "only CPU device supports initialize_statevector()"); if (precision_ != Precision::Double) - throw std::runtime_error("only Double precision supports initialize_statevector()"); + throw std::runtime_error( + "only Double precision supports initialize_statevector()"); auto state = std::make_shared>>(); @@ -739,8 +798,8 @@ reg_t AerState::initialize_statevector(uint_t num_of_qubits, complex_t* data, bo if (cache_block_qubits_ > 0) copy = true; - auto vec = copy? AER::Vector::copy_from_buffer(data_size, data) - : AER::Vector::move_from_buffer(data_size, data); + auto vec = copy ? AER::Vector::copy_from_buffer(data_size, data) + : AER::Vector::move_from_buffer(data_size, data); auto qv = QV::QubitVector(); qv.move_from_vector(std::move(vec)); @@ -756,7 +815,8 @@ reg_t AerState::initialize_statevector(uint_t num_of_qubits, complex_t* data, bo return ret; }; -reg_t AerState::initialize_density_matrix(uint_t num_of_qubits, complex_t* data, bool f_order, bool copy) { +reg_t AerState::initialize_density_matrix(uint_t num_of_qubits, complex_t *data, + bool f_order, bool copy) { assert_not_initialized(); num_of_qubits_ = num_of_qubits; @@ -765,19 +825,22 @@ reg_t AerState::initialize_density_matrix(uint_t num_of_qubits, complex_t* data, initialize_state_controller(); if (device_ != Device::CPU) - throw std::runtime_error("only CPU device supports initialize_density_matrix()"); + throw std::runtime_error( + "only CPU device supports initialize_density_matrix()"); if (precision_ != Precision::Double) - throw std::runtime_error("only Double precision supports initialize_density_matrix()"); + throw std::runtime_error( + "only Double precision supports initialize_density_matrix()"); - auto state = std::make_shared>>(); + auto state = + std::make_shared>>(); initialize_qreg_state(state); if (cache_block_qubits_ > 0) copy = true; - auto vec = copy? AER::Vector::copy_from_buffer(data_size, data) - : AER::Vector::move_from_buffer(data_size, data); + auto vec = copy ? AER::Vector::copy_from_buffer(data_size, data) + : AER::Vector::move_from_buffer(data_size, data); auto dm = QV::DensityMatrix(); dm.move_from_vector(std::move(vec)); @@ -812,14 +875,16 @@ AER::Vector AerState::move_to_vector() { flush_ops(); Operations::Op op; - if (method_ == Method::statevector || method_ == Method::matrix_product_state) { + if (method_ == Method::statevector || + method_ == Method::matrix_product_state) { op.type = Operations::OpType::save_statevec; op.name = "save_statevec"; } else if (method_ == Method::density_matrix) { op.type = Operations::OpType::save_state; op.name = "save_density_matrix"; } else { - throw std::runtime_error("move_to_vector() supports only statevector or matrix_product_state or density_matrix methods"); + throw std::runtime_error("move_to_vector() supports only statevector or " + "matrix_product_state or density_matrix methods"); } for (auto i = 0; i < num_of_qubits_; ++i) op.qubits.push_back(i); @@ -829,17 +894,27 @@ AER::Vector AerState::move_to_vector() { ExperimentResult ret; state_->apply_op(op, ret, rng_, true); - if (method_ == Method::statevector || method_ == Method::matrix_product_state) { - auto vec = std::move(static_cast>>(std::move(ret).data).value()["s"].value()); + if (method_ == Method::statevector || + method_ == Method::matrix_product_state) { + auto vec = std::move( + static_cast>>(std::move(ret).data) + .value()["s"] + .value()); clear(); return std::move(vec); } else if (method_ == Method::density_matrix) { - auto mat = std::move(static_cast, 1>>(std::move(ret).data).value()["s"].value()); - auto vec = Vector::move_from_buffer(mat.GetColumns() * mat.GetRows(), mat.move_to_buffer()); + auto mat = + std::move(static_cast, 1>>( + std::move(ret).data) + .value()["s"] + .value()); + auto vec = Vector::move_from_buffer( + mat.GetColumns() * mat.GetRows(), mat.move_to_buffer()); clear(); return std::move(vec); } else { - throw std::runtime_error("move_to_vector() supports only statevector or matrix_product_state or density_matrix methods"); + throw std::runtime_error("move_to_vector() supports only statevector or " + "matrix_product_state or density_matrix methods"); } }; @@ -849,14 +924,16 @@ matrix AerState::move_to_matrix() { flush_ops(); Operations::Op op; - if (method_ == Method::statevector || method_ == Method::matrix_product_state) { + if (method_ == Method::statevector || + method_ == Method::matrix_product_state) { op.type = Operations::OpType::save_statevec; op.name = "save_statevec"; } else if (method_ == Method::density_matrix) { op.type = Operations::OpType::save_state; op.name = "save_density_matrix"; } else { - throw std::runtime_error("move_to_matrix() supports only statevector or matrix_product_state or density_matrix methods"); + throw std::runtime_error("move_to_matrix() supports only statevector or " + "matrix_product_state or density_matrix methods"); } for (auto i = 0; i < num_of_qubits_; ++i) op.qubits.push_back(i); @@ -866,41 +943,35 @@ matrix AerState::move_to_matrix() { ExperimentResult ret; state_->apply_op(op, ret, rng_, true); - if (method_ == Method::statevector || method_ == Method::matrix_product_state) { + if (method_ == Method::statevector || + method_ == Method::matrix_product_state) { auto vec = std::move( - std::move( - std::move( - static_cast>>( - std::move(ret).data - ) - ).value() - )["s"].value() - ); + std::move(std::move(static_cast>>( + std::move(ret).data)) + .value())["s"] + .value()); clear(); return matrix((1ULL << num_of_qubits_), 1, vec.move_to_buffer()); } else if (method_ == Method::density_matrix) { auto mat = std::move( - std::move( - std::move( - static_cast, 1>>( - std::move(ret).data - ) - ).value() - )["s"].value() - ); + std::move( + std::move(static_cast, 1>>( + std::move(ret).data)) + .value())["s"] + .value()); clear(); return std::move(mat); } else { - throw std::runtime_error("move_to_matrix() supports only statevector or matrix_product_state or density_matrix methods"); + throw std::runtime_error("move_to_matrix() supports only statevector or " + "matrix_product_state or density_matrix methods"); } }; - //----------------------------------------------------------------------- // Apply Initialization //----------------------------------------------------------------------- -void AerState::apply_initialize(const reg_t &qubits, cvector_t && vec) { +void AerState::apply_initialize(const reg_t &qubits, cvector_t &&vec) { assert_initialized(); Operations::Op op; op.type = Operations::OpType::initialize; @@ -912,7 +983,7 @@ void AerState::apply_initialize(const reg_t &qubits, cvector_t && vec) { state_->apply_op(op, last_result_, rng_); }; -void AerState::set_statevector(const reg_t &qubits, cvector_t && vec) { +void AerState::set_statevector(const reg_t &qubits, cvector_t &&vec) { assert_initialized(); Operations::Op op; op.type = Operations::OpType::set_statevec; @@ -956,7 +1027,8 @@ void AerState::apply_unitary(const reg_t &qubits, const cmatrix_t &mat) { buffer_op(std::move(op)); } -void AerState::apply_diagonal_matrix(const reg_t &qubits, const cvector_t &mat) { +void AerState::apply_diagonal_matrix(const reg_t &qubits, + const cvector_t &mat) { assert_initialized(); Operations::Op op; op.type = Operations::OpType::diagonal_matrix; @@ -967,7 +1039,9 @@ void AerState::apply_diagonal_matrix(const reg_t &qubits, const cvector_t &mat) buffer_op(std::move(op)); } -void AerState::apply_multiplexer(const reg_t &control_qubits, const reg_t &target_qubits, const std::vector &mats) { +void AerState::apply_multiplexer(const reg_t &control_qubits, + const reg_t &target_qubits, + const std::vector &mats) { assert_initialized(); if (mats.empty()) @@ -1105,7 +1179,8 @@ void AerState::apply_mcz(const reg_t &qubits) { buffer_op(std::move(op)); } -void AerState::apply_mcphase(const reg_t &qubits, const std::complex phase) { +void AerState::apply_mcphase(const reg_t &qubits, + const std::complex phase) { assert_initialized(); Operations::Op op; @@ -1129,7 +1204,8 @@ void AerState::apply_h(const uint_t qubit) { buffer_op(std::move(op)); } -void AerState::apply_u(const uint_t qubit, const double theta, const double phi, const double lambda) { +void AerState::apply_u(const uint_t qubit, const double theta, const double phi, + const double lambda) { assert_initialized(); Operations::Op op; @@ -1141,7 +1217,9 @@ void AerState::apply_u(const uint_t qubit, const double theta, const double phi, buffer_op(std::move(op)); } -void AerState::apply_cu(const reg_t &qubits, const double theta, const double phi, const double lambda, const double gamma) { +void AerState::apply_cu(const reg_t &qubits, const double theta, + const double phi, const double lambda, + const double gamma) { assert_initialized(); Operations::Op op; @@ -1153,7 +1231,9 @@ void AerState::apply_cu(const reg_t &qubits, const double theta, const double ph buffer_op(std::move(op)); } -void AerState::apply_mcu(const reg_t &qubits, const double theta, const double phi, const double lambda, const double gamma) { +void AerState::apply_mcu(const reg_t &qubits, const double theta, + const double phi, const double lambda, + const double gamma) { assert_initialized(); Operations::Op op; @@ -1233,7 +1313,7 @@ uint_t AerState::apply_measure(const reg_t &qubits) { uint_t bitstring = 0; uint_t bit = 1; - for (const auto& qubit: qubits) { + for (const auto &qubit : qubits) { if (state_->creg().creg_memory()[qubit] == '1') bitstring |= bit; bit <<= 1; @@ -1255,7 +1335,8 @@ void AerState::apply_reset(const reg_t &qubits) { state_->apply_op(op, last_result_, rng_); } -void AerState::apply_kraus(const reg_t &qubits, const std::vector &krausops) { +void AerState::apply_kraus(const reg_t &qubits, + const std::vector &krausops) { assert_initialized(); Operations::Op op; @@ -1286,7 +1367,9 @@ double AerState::probability(const uint_t outcome) { last_result_ = ExperimentResult(); state_->apply_op(op, last_result_, rng_); - return ((DataMap)last_result_.data).value()["s"].value()[0][0]; + return ((DataMap)last_result_.data) + .value()["s"] + .value()[0][0]; } // Return the probability amplitude for outcome in [0, 2^num_qubits - 1] @@ -1305,7 +1388,9 @@ complex_t AerState::amplitude(const uint_t outcome) { last_result_ = ExperimentResult(); state_->apply_op(op, last_result_, rng_); - return ((DataMap>)last_result_.data).value()["s"].value()[0][0]; + return ((DataMap>)last_result_.data) + .value()["s"] + .value()[0][0]; }; std::vector AerState::probabilities() { @@ -1322,7 +1407,9 @@ std::vector AerState::probabilities() { last_result_ = ExperimentResult(); state_->apply_op(op, last_result_, rng_); - return ((DataMap)last_result_.data).value()["s"].value()[0]; + return ((DataMap)last_result_.data) + .value()["s"] + .value()[0]; } std::vector AerState::probabilities(const reg_t &qubits) { @@ -1340,10 +1427,13 @@ std::vector AerState::probabilities(const reg_t &qubits) { last_result_ = ExperimentResult(); state_->apply_op(op, last_result_, rng_); - return ((DataMap)last_result_.data).value()["s"].value()[0]; + return ((DataMap)last_result_.data) + .value()["s"] + .value()[0]; } -std::vector AerState::sample_memory(const reg_t &qubits, uint_t shots) { +std::vector AerState::sample_memory(const reg_t &qubits, + uint_t shots) { assert_initialized(); flush_ops(); @@ -1351,24 +1441,27 @@ std::vector AerState::sample_memory(const reg_t &qubits, uint_t sho std::vector ret; ret.reserve(shots); std::vector samples = state_->sample_measure(qubits, shots, rng_); - for (auto& sample : samples) { - ret.push_back(Utils::int2string(Utils::reg2int(sample, 2), 2, qubits.size())); + for (auto &sample : samples) { + ret.push_back( + Utils::int2string(Utils::reg2int(sample, 2), 2, qubits.size())); } return ret; } -std::unordered_map AerState::sample_counts(const reg_t &qubits, uint_t shots) { +std::unordered_map AerState::sample_counts(const reg_t &qubits, + uint_t shots) { assert_initialized(); flush_ops(); std::vector samples = state_->sample_measure(qubits, shots, rng_); std::unordered_map ret; - for(const auto & sample: samples) { + for (const auto &sample : samples) { uint_t sample_u = 0ULL; uint_t mask = 1ULL; - for (const auto b: sample) { - if (b) sample_u |= mask; + for (const auto b : sample) { + if (b) + sample_u |= mask; mask <<= 1; } if (ret.find(sample_u) == ret.end()) @@ -1382,7 +1475,7 @@ std::unordered_map AerState::sample_counts(const reg_t &qubits, //----------------------------------------------------------------------- // Operation management //----------------------------------------------------------------------- -void AerState::buffer_op(const Operations::Op&& op) { +void AerState::buffer_op(const Operations::Op &&op) { assert_initialized(); buffer_.ops.push_back(std::move(op)); }; @@ -1391,7 +1484,8 @@ void AerState::initialize_experiment_result() { last_result_ = ExperimentResult(); last_result_.set_config(configs_); last_result_.metadata.add(method_names_.at(method_), "method"); - if (method_ == Method::statevector || method_ == Method::density_matrix || method_ == Method::unitary) + if (method_ == Method::statevector || method_ == Method::density_matrix || + method_ == Method::unitary) last_result_.metadata.add(device_names_.at(device_), "device"); else last_result_.metadata.add("CPU", "device"); @@ -1404,14 +1498,16 @@ void AerState::initialize_experiment_result() { }; void AerState::finalize_experiment_result(bool success, double time_taken) { - last_result_.status = success? ExperimentResult::Status::completed : ExperimentResult::Status::error; + last_result_.status = success ? ExperimentResult::Status::completed + : ExperimentResult::Status::error; last_result_.time_taken = time_taken; }; void AerState::flush_ops() { assert_initialized(); - if (buffer_.ops.empty()) return; + if (buffer_.ops.empty()) + return; auto timer_start = myclock_t::now(); @@ -1421,7 +1517,9 @@ void AerState::flush_ops() { transpile_ops(); state_->apply_ops(buffer_.ops.begin(), buffer_.ops.end(), last_result_, rng_); - finalize_experiment_result(true, std::chrono::duration(myclock_t::now() - timer_start).count()); + finalize_experiment_result( + true, + std::chrono::duration(myclock_t::now() - timer_start).count()); clear_ops(); }; @@ -1469,12 +1567,17 @@ void AerState::transpile_ops() { } // Override default fusion settings with custom config fusion_pass_.set_config(configs_); - fusion_pass_.optimize_circuit(buffer_, noise_model_, state_->opset(), last_result_); - - //cache blocking - if(cache_block_pass_.enabled() && state_->multi_chunk_distribution_supported()){ - cache_block_pass_.set_restore_qubit_map(true); //restore swapped qubits because buffer_ does not include output qubits - cache_block_pass_.optimize_circuit(buffer_, noise_model_, state_->opset(), last_result_); + fusion_pass_.optimize_circuit(buffer_, noise_model_, state_->opset(), + last_result_); + + // cache blocking + if (cache_block_pass_.enabled() && + state_->multi_chunk_distribution_supported()) { + cache_block_pass_.set_restore_qubit_map( + true); // restore swapped qubits because buffer_ does not include output + // qubits + cache_block_pass_.optimize_circuit(buffer_, noise_model_, state_->opset(), + last_result_); } } diff --git a/src/framework/avx2_detect.hpp b/src/framework/avx2_detect.hpp index 49f5d73955..2287782f38 100644 --- a/src/framework/avx2_detect.hpp +++ b/src/framework/avx2_detect.hpp @@ -16,63 +16,59 @@ #define _aer_controller_avx2_detect_hpp_ #include -#include #include +#include #include "misc/common_macros.hpp" #if defined(_MSC_VER) - #include +#include #elif defined(GNUC_AVX2) - #include +#include #endif - namespace { -inline void ccpuid(int cpu_info[4], int function_id){ +inline void ccpuid(int cpu_info[4], int function_id) { #if defined(_MSC_VER) __cpuid(cpu_info, function_id); #elif defined(GNUC_AVX2) - __cpuid(function_id, - cpu_info[0], - cpu_info[1], - cpu_info[2], - cpu_info[3]); + __cpuid(function_id, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]); #else // We don't support this platform intrinsics cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; #endif } -inline void cpuidex(int cpu_info[4], int function_id, int subfunction_id){ +inline void cpuidex(int cpu_info[4], int function_id, int subfunction_id) { #if defined(_MSC_VER) __cpuidex(cpu_info, function_id, subfunction_id); #elif defined(GNUC_AVX2) - __cpuid_count(function_id, subfunction_id, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]); + __cpuid_count(function_id, subfunction_id, cpu_info[0], cpu_info[1], + cpu_info[2], cpu_info[3]); #else // We don't support this platform intrinsics - cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; + cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; #endif } -} +} // namespace namespace AER { -inline bool is_avx2_supported(){ +inline bool is_avx2_supported() { #if defined(GNUC_AVX2) || defined(_MSC_VER) static bool cached = false; static bool is_supported = false; - if(cached) + if (cached) return is_supported; std::array cpui; ccpuid(cpui.data(), 0); auto num_ids = cpui[0]; - if(num_ids < 7){ + if (num_ids < 7) { cached = true; is_supported = false; return false; } std::vector> data; - for (int i = 0; i <= num_ids; ++i){ + for (int i = 0; i <= num_ids; ++i) { cpuidex(cpui.data(), i, 0); data.push_back(cpui); } @@ -87,11 +83,9 @@ inline bool is_avx2_supported(){ is_supported = is_fma_supported && is_avx2_supported; return is_supported; #else - return false; + return false; #endif } // end namespace AER -} +} // namespace AER #endif - - diff --git a/src/framework/blas_protos.hpp b/src/framework/blas_protos.hpp old mode 100755 new mode 100644 index d2803c66eb..dc17a25ac8 --- a/src/framework/blas_protos.hpp +++ b/src/framework/blas_protos.hpp @@ -19,10 +19,10 @@ #ifndef _aer_framework_blas_protos_hpp #define _aer_framework_blas_protos_hpp +#include #include #include #include -#include #ifdef __cplusplus extern "C" { @@ -79,45 +79,43 @@ void zgemm_(const char *TransA, const char *TransB, const size_t *M, const std::complex *beta, std::complex *C, size_t *ldc); -// Reduces a Single-Precison Complex Hermitian matrix A to real symmetric tridiagonal form -void chetrd_(char *TRANS, int *N, std::complex *A, - int *LDA, float *d, float *e, std::complex *tau, - std::complex *work, int *lwork, int *info); +// Reduces a Single-Precison Complex Hermitian matrix A to real symmetric +// tridiagonal form +void chetrd_(char *TRANS, int *N, std::complex *A, int *LDA, float *d, + float *e, std::complex *tau, std::complex *work, + int *lwork, int *info); -// Reduces a Double-Precison Complex Hermitian matrix A to real symmetric tridiagonal form T -void zhetrd_(char *TRANS, int *N, std::complex *A, - int *LDA, double *d, double *e, std::complex *tau, - std::complex *work, int *lwork, int *info); +// Reduces a Double-Precison Complex Hermitian matrix A to real symmetric +// tridiagonal form T +void zhetrd_(char *TRANS, int *N, std::complex *A, int *LDA, double *d, + double *e, std::complex *tau, std::complex *work, + int *lwork, int *info); // Computes all eigenvalues and, optionally, eigenvectors of a // Single-Precison Complex symmetric positive definite tridiagonal matrix -void cpteqr_(char* compz, int *n, float *d, float *e, - std::complex *z, int* ldz, - std::complex *work, int *info); +void cpteqr_(char *compz, int *n, float *d, float *e, std::complex *z, + int *ldz, std::complex *work, int *info); // Computes all eigenvalues and, optionally, eigenvectors of a // Double-Precison Complex symmetric positive definite tridiagonal matrix -void zpteqr_(char* compz, int *n, double *d, double *e, - std::complex *z, int* ldz, - std::complex *work, int *info); +void zpteqr_(char *compz, int *n, double *d, double *e, std::complex *z, + int *ldz, std::complex *work, int *info); // Computes selected eigenvalues and, optionally, eigenvectors // of a Single-Precison Complex Hermitian matrix A void cheevx_(char *jobz, char *range, char *uplo, int *n, - std::complex *a, int *lda, float *vl, - float *vu, int *il, int *iu, float *abstol, - int *m, float *w, std::complex *z, int *ldz, - std::complex *work, int *lwork, float *rwork, + std::complex *a, int *lda, float *vl, float *vu, int *il, + int *iu, float *abstol, int *m, float *w, std::complex *z, + int *ldz, std::complex *work, int *lwork, float *rwork, int *iwork, int *ifail, int *info); // Computes selected eigenvalues and, optionally, eigenvectors // of a Double-Precison Complex Hermitian matrix A void zheevx_(char *jobz, char *range, char *uplo, int *n, - std::complex *a, int *lda, double *vl, - double *vu, int *il, int *iu, double *abstol, - int *m, double *w, std::complex *z, int *ldz, - std::complex *work, int *lwork, double *rwork, - int *iwork, int *ifail, int *info); + std::complex *a, int *lda, double *vl, double *vu, int *il, + int *iu, double *abstol, int *m, double *w, + std::complex *z, int *ldz, std::complex *work, + int *lwork, double *rwork, int *iwork, int *ifail, int *info); // Determines Single-Precision machine parameters. float slamch_(char *cmach); diff --git a/src/framework/circuit.hpp b/src/framework/circuit.hpp old mode 100755 new mode 100644 index b5471e4e43..58154a81e9 --- a/src/framework/circuit.hpp +++ b/src/framework/circuit.hpp @@ -17,9 +17,9 @@ #include +#include "framework/config.hpp" #include "framework/operations.hpp" #include "framework/opset.hpp" -#include "framework/config.hpp" using complex_t = std::complex; @@ -40,59 +40,62 @@ class Circuit { std::vector ops; // Circuit parameters updated by from ops by set_params - uint_t num_qubits = 0; // maximum number of qubits needed for ops - uint_t num_memory = 0; // maximum number of memory clbits needed for ops - uint_t num_registers = 0; // maximum number of registers clbits needed for ops - + uint_t num_qubits = 0; // maximum number of qubits needed for ops + uint_t num_memory = 0; // maximum number of memory clbits needed for ops + uint_t num_registers = 0; // maximum number of registers clbits needed for ops + // Measurement params - bool has_conditional = false; // True if any ops are conditional - bool can_sample = true; // True if circuit tail contains measure, roerror, barrier. - size_t first_measure_pos = 0; // Position of first measure instruction - bool can_sample_initialize = true; // True if circuit contains at most 1 initialize - // and it is the first instruction in the circuit + bool has_conditional = false; // True if any ops are conditional + bool can_sample = + true; // True if circuit tail contains measure, roerror, barrier. + size_t first_measure_pos = 0; // Position of first measure instruction + bool can_sample_initialize = + true; // True if circuit contains at most 1 initialize + // and it is the first instruction in the circuit // Circuit metadata constructed from json QobjExperiment uint_t shots = 1; uint_t seed; json_t header; double global_phase_angle = 0; - bool remapped_qubits = false; // True if qubits have been remapped + bool remapped_qubits = false; // True if qubits have been remapped // Constructor - // The constructor automatically calculates the num_qubits, num_memory, num_registers - // parameters by scanning the input list of ops. - Circuit() {set_random_seed();} + // The constructor automatically calculates the num_qubits, num_memory, + // num_registers parameters by scanning the input list of ops. + Circuit() { set_random_seed(); } Circuit(const std::vector &_ops, bool truncation = false); Circuit(std::vector &&_ops, bool truncation = false); // Construct a circuit from JSON - template - Circuit(const inputdata_t& circ, bool truncation = false); + template + Circuit(const inputdata_t &circ, bool truncation = false); - template - Circuit(const inputdata_t& circ, const json_t& qobj_config, bool truncation = false); + template + Circuit(const inputdata_t &circ, const json_t &qobj_config, + bool truncation = false); //----------------------------------------------------------------------- // Set containers //----------------------------------------------------------------------- // Return the opset for the circuit - inline const auto& opset() const {return opset_;} + inline const auto &opset() const { return opset_; } // Return the used qubits for the circuit - inline const auto& qubits() const {return qubitset_;} + inline const auto &qubits() const { return qubitset_; } // Return the used memory for the circuit - inline const auto& memory() const {return memoryset_;} + inline const auto &memory() const { return memoryset_; } // Return the used registers for the circuit - inline const auto& registers() const {return registerset_;} + inline const auto ®isters() const { return registerset_; } // Return the mapping of input op qubits to circuit qubits - inline const auto& qubit_map() const {return qubitmap_;} + inline const auto &qubit_map() const { return qubitmap_; } //----------------------------------------------------------------------- - // Utility methods + // Utility methods //----------------------------------------------------------------------- // Automatically set the number of qubits, memory, registers, and check @@ -110,35 +113,32 @@ class Circuit { void set_metadata(const AER::Config &config, bool truncation); // Set the circuit rng seed to random value - inline void set_random_seed() {seed = std::random_device()();} + inline void set_random_seed() { seed = std::random_device()(); } //----------------------------------------------------------------------- // Op insert helpers //----------------------------------------------------------------------- - void bfunc(const std::string &mask, const std::string &val, const std::string &relation, const uint_t regidx) { + void bfunc(const std::string &mask, const std::string &val, + const std::string &relation, const uint_t regidx) { ops.push_back(Operations::make_bfunc(mask, val, relation, regidx)); } - void gate(const std::string &name, - const reg_t &qubits, + void gate(const std::string &name, const reg_t &qubits, const std::vector ¶ms, const std::vector &string_params, - const int_t cond_regidx=-1, - const std::string label="") { - ops.push_back(Operations::make_gate(name, qubits, params, string_params, cond_regidx, label)); + const int_t cond_regidx = -1, const std::string label = "") { + ops.push_back(Operations::make_gate(name, qubits, params, string_params, + cond_regidx, label)); } - void diagonal(const reg_t &qubits, - const cvector_t &vec, + void diagonal(const reg_t &qubits, const cvector_t &vec, const std::string &label) { ops.push_back(Operations::make_diagonal(qubits, vec, label)); } - void unitary(const reg_t &qubits, - const cmatrix_t &mat, - const int_t cond_regidx=-1, - const std::string label="") { + void unitary(const reg_t &qubits, const cmatrix_t &mat, + const int_t cond_regidx = -1, const std::string label = "") { ops.push_back(Operations::make_unitary(qubits, mat, cond_regidx, label)); } @@ -152,87 +152,88 @@ class Circuit { ops.push_back(Operations::make_roerror(memory, probabilities)); } - void multiplexer(const reg_t &qubits, - const std::vector &mats, - const int_t cond_regidx = -1, - std::string label="") { - ops.push_back(Operations::make_multiplexer(qubits, mats, cond_regidx, label)); + void multiplexer(const reg_t &qubits, const std::vector &mats, + const int_t cond_regidx = -1, std::string label = "") { + ops.push_back( + Operations::make_multiplexer(qubits, mats, cond_regidx, label)); } - void kraus(const reg_t &qubits, - const std::vector &mats, + void kraus(const reg_t &qubits, const std::vector &mats, const int_t cond_regidx = -1) { ops.push_back(Operations::make_kraus(qubits, mats, cond_regidx)); } - void superop(const reg_t &qubits, - const cmatrix_t &mat, + void superop(const reg_t &qubits, const cmatrix_t &mat, const int_t cond_regidx = -1) { ops.push_back(Operations::make_superop(qubits, mat, cond_regidx)); } - void save_state(const reg_t &qubits, - const std::string &name, + void save_state(const reg_t &qubits, const std::string &name, const std::string &snapshot_type, - const std::string &label="") { - ops.push_back(Operations::make_save_state(qubits, name, snapshot_type, label)); + const std::string &label = "") { + ops.push_back( + Operations::make_save_state(qubits, name, snapshot_type, label)); } - void save_amplitudes(const reg_t &qubits, - const std::string &name, + void save_amplitudes(const reg_t &qubits, const std::string &name, const std::vector &basis_state, const std::string &snapshot_type, - const std::string &label="") { - ops.push_back(Operations::make_save_amplitudes(qubits, name, basis_state, snapshot_type, label)); + const std::string &label = "") { + ops.push_back(Operations::make_save_amplitudes(qubits, name, basis_state, + snapshot_type, label)); } - void save_expval(const reg_t &qubits, - const std::string &name, + void save_expval(const reg_t &qubits, const std::string &name, const std::vector pauli_strings, const std::vector coeff_reals, const std::vector coeff_imags, const std::string &snapshot_type, - const std::string label="") { - ops.push_back(Operations::make_save_expval(qubits, name, pauli_strings, coeff_reals, coeff_imags, snapshot_type, label)); + const std::string label = "") { + ops.push_back(Operations::make_save_expval(qubits, name, pauli_strings, + coeff_reals, coeff_imags, + snapshot_type, label)); } - void set_qerror_loc(const reg_t &qubits, - const std::string &label, + void set_qerror_loc(const reg_t &qubits, const std::string &label, const int_t conditional = -1) { ops.push_back(Operations::make_qerror_loc(qubits, label, conditional)); } - template + template void set_statevector(const reg_t &qubits, const inputdata_t ¶m) { - ops.push_back(Operations::make_set_vector(qubits, "set_statevector", param)); + ops.push_back( + Operations::make_set_vector(qubits, "set_statevector", param)); } - template + template void set_density_matrix(const reg_t &qubits, const inputdata_t ¶m) { - ops.push_back(Operations::make_set_matrix(qubits, "set_density_matrix", param)); + ops.push_back( + Operations::make_set_matrix(qubits, "set_density_matrix", param)); } - template + template void set_unitary(const reg_t &qubits, const inputdata_t ¶m) { ops.push_back(Operations::make_set_matrix(qubits, "set_unitary", param)); } - template + template void set_superop(const reg_t &qubits, const inputdata_t ¶m) { ops.push_back(Operations::make_set_matrix(qubits, "set_superop", param)); } - template + template void set_matrix_product_state(const reg_t &qubits, const inputdata_t ¶m) { - ops.push_back(Operations::make_set_mps(qubits, "set_matrix_product_state", param)); + ops.push_back( + Operations::make_set_mps(qubits, "set_matrix_product_state", param)); } - template + template void set_clifford(const reg_t &qubits, const inputdata_t ¶m) { ops.push_back(Operations::make_set_clifford(qubits, "set_clifford", param)); } - void jump(const reg_t &qubits, const std::vector ¶ms, const int_t cond_regidx = -1) { + void jump(const reg_t &qubits, const std::vector ¶ms, + const int_t cond_regidx = -1) { ops.push_back(Operations::make_jump(qubits, params, cond_regidx)); } @@ -240,7 +241,8 @@ class Circuit { ops.push_back(Operations::make_mark(qubits, params)); } - void measure(const reg_t &qubits, const reg_t &memory, const reg_t ®isters) { + void measure(const reg_t &qubits, const reg_t &memory, + const reg_t ®isters) { ops.push_back(Operations::make_measure(qubits, memory, registers)); } @@ -259,23 +261,21 @@ class Circuit { std::unordered_map qubitmap_; // Add type, qubit, memory, conditional metadata information from op - void add_op_metadata(const Op& op); + void add_op_metadata(const Op &op); // Reset circuit metadata void reset_metadata(); // Helper function for optimized set params - bool check_result_ancestor(const Op& op, - std::unordered_set& ancestor_qubits) const; - + bool check_result_ancestor(const Op &op, + std::unordered_set &ancestor_qubits) const; + // Helper function for optimized set params - void remap_qubits(Op& op) const; + void remap_qubits(Op &op) const; }; - // Json conversion function -inline void from_json(const json_t& js, Circuit &circ) {circ = Circuit(js);} - +inline void from_json(const json_t &js, Circuit &circ) { circ = Circuit(js); } //============================================================================ // Implementation: Circuit methods @@ -291,11 +291,14 @@ Circuit::Circuit(std::vector &&_ops, bool truncation) : Circuit() { set_params(truncation); } -template -Circuit::Circuit(const inputdata_t &circ, bool truncation) : Circuit(circ, json_t(), truncation) {} +template +Circuit::Circuit(const inputdata_t &circ, bool truncation) + : Circuit(circ, json_t(), truncation) {} -template -Circuit::Circuit(const inputdata_t &circ, const json_t &qobj_config, bool truncation) : Circuit() { +template +Circuit::Circuit(const inputdata_t &circ, const json_t &qobj_config, + bool truncation) + : Circuit() { // Get config auto config = qobj_config; if (Parser::check_key("config", circ)) { @@ -305,23 +308,24 @@ Circuit::Circuit(const inputdata_t &circ, const json_t &qobj_config, bool trunca config[it.key()] = it.value(); // overwrite circuit level config values } } - + // Set header Parser::get_value(header, "header", circ); Parser::get_value(global_phase_angle, "global_phase", header); - + // Load instructions if (Parser::check_key("instructions", circ) == false) { - throw std::invalid_argument("Invalid Qobj experiment: no \"instructions\" field."); + throw std::invalid_argument( + "Invalid Qobj experiment: no \"instructions\" field."); } const auto input_ops = Parser::get_list("instructions", circ); - + // Convert to Ops - // TODO: If parser could support reverse iteration through the list of ops without - // conversion we could call `get_reversed_ops` on the inputdata without first - // converting. + // TODO: If parser could support reverse iteration through the list of ops + // without conversion we could call `get_reversed_ops` on the inputdata + // without first converting. std::vector converted_ops; - for(auto the_op: input_ops){ + for (auto the_op : input_ops) { converted_ops.emplace_back(Operations::input_to_op(the_op)); } ops = std::move(converted_ops); @@ -337,7 +341,8 @@ void Circuit::set_metadata(const AER::Config &config, bool truncation) { // Check for specified memory slots uint_t memory_slots = config.memory_slots; if (memory_slots < num_memory) { - throw std::invalid_argument("Invalid Qobj experiment: not enough memory slots."); + throw std::invalid_argument( + "Invalid Qobj experiment: not enough memory slots."); } // override memory slot number num_memory = memory_slots; @@ -346,7 +351,8 @@ void Circuit::set_metadata(const AER::Config &config, bool truncation) { if (config.n_qubits.has_value()) { uint_t n_qubits = config.n_qubits.value(); if (n_qubits < num_qubits) { - throw std::invalid_argument("Invalid Qobj experiment: n_qubits < instruction qubits."); + throw std::invalid_argument( + "Invalid Qobj experiment: n_qubits < instruction qubits."); } if (!truncation) { // Override minimal circuit qubit number with qobj number if truncation @@ -372,14 +378,14 @@ void Circuit::reset_metadata() { num_qubits = 0; num_memory = 0; num_registers = 0; - + has_conditional = false; can_sample = true; first_measure_pos = 0; can_sample_initialize = true; } -void Circuit::add_op_metadata(const Op& op) { +void Circuit::add_op_metadata(const Op &op) { has_conditional |= op.conditional; opset_.insert(op); qubitset_.insert(op.qubits.begin(), op.qubits.end()); @@ -396,11 +402,11 @@ void Circuit::add_op_metadata(const Op& op) { } } - void Circuit::set_params(bool truncation) { - // Clear current circuit metadata + // Clear current circuit metadata reset_metadata(); - if (ops.empty()) return; + if (ops.empty()) + return; // Analyze input ops from tail to head to get locations of ancestor, // first measurement position and last initialize position @@ -414,11 +420,11 @@ void Circuit::set_params(bool truncation) { bool ops_to_remove = false; std::unordered_set ancestor_qubits; - for (size_t i = 0; i < size; ++ i) { + for (size_t i = 0; i < size; ++i) { const size_t rpos = size - i - 1; - const auto& op = ops[rpos]; + const auto &op = ops[rpos]; if (op.type == OpType::mark && last_ancestor_pos == 0) - last_ancestor_pos = rpos; + last_ancestor_pos = rpos; if (!truncation || check_result_ancestor(op, ancestor_qubits)) { add_op_metadata(op); ancestor[rpos] = true; @@ -432,7 +438,7 @@ void Circuit::set_params(bool truncation) { if (last_ancestor_pos == 0) { last_ancestor_pos = rpos; } - } else if (truncation && !ops_to_remove){ + } else if (truncation && !ops_to_remove) { ops_to_remove = true; } } @@ -442,7 +448,7 @@ void Circuit::set_params(bool truncation) { if (truncation) { // Generate mapping of original qubits to ancestor set uint_t idx = 0; - for (const auto& qubit: qubitset_) { + for (const auto &qubit : qubitset_) { if (!remapped_qubits && idx != qubit) { // qubits will be remapped remapped_qubits = true; @@ -481,47 +487,46 @@ void Circuit::set_params(bool truncation) { continue; } - const auto& op = ops[pos]; + const auto &op = ops[pos]; if (op.conditional) { can_sample = false; break; } switch (op.type) { - case OpType::measure: - case OpType::roerror: { - meas_qubits.insert(op.qubits.begin(), op.qubits.end()); - tail_meas_ops.push_back(op); - break; - } - case OpType::save_state: - case OpType::save_expval: - case OpType::save_expval_var: - case OpType::save_statevec: - case OpType::save_statevec_dict: - case OpType::save_densmat: - case OpType::save_probs: - case OpType::save_probs_ket: - case OpType::save_amps: - case OpType::save_amps_sq: - case OpType::save_stabilizer: - case OpType::save_clifford: - case OpType::save_unitary: - case OpType::save_mps: - case OpType::save_superop: - { - can_sample = false; - break; - } - default: { - for (const auto &qubit : op.qubits) { - if (meas_qubits.find(qubit) != meas_qubits.end()) { - can_sample = false; - break; - } + case OpType::measure: + case OpType::roerror: { + meas_qubits.insert(op.qubits.begin(), op.qubits.end()); + tail_meas_ops.push_back(op); + break; + } + case OpType::save_state: + case OpType::save_expval: + case OpType::save_expval_var: + case OpType::save_statevec: + case OpType::save_statevec_dict: + case OpType::save_densmat: + case OpType::save_probs: + case OpType::save_probs_ket: + case OpType::save_amps: + case OpType::save_amps_sq: + case OpType::save_stabilizer: + case OpType::save_clifford: + case OpType::save_unitary: + case OpType::save_mps: + case OpType::save_superop: { + can_sample = false; + break; + } + default: { + for (const auto &qubit : op.qubits) { + if (meas_qubits.find(qubit) != meas_qubits.end()) { + can_sample = false; + break; } - tail_pos.push_back(pos); } + tail_pos.push_back(pos); + } } if (!can_sample) { break; @@ -540,7 +545,8 @@ void Circuit::set_params(bool truncation) { head_end = last_ancestor_pos + 1; } for (size_t pos = 0; pos < head_end; ++pos) { - if (ops_to_remove && !ancestor[pos] && ops[pos].type != OpType::mark && ops[pos].type != OpType::jump) { + if (ops_to_remove && !ancestor[pos] && ops[pos].type != OpType::mark && + ops[pos].type != OpType::jump) { // Skip if not ancestor continue; } @@ -553,10 +559,11 @@ void Circuit::set_params(bool truncation) { if (ops[op_idx].type == OpType::jump) { dests.insert(ops[op_idx].string_params[0]); } else if (ops[op_idx].type == OpType::mark) { - auto& mark_name = ops[op_idx].string_params[0]; + auto &mark_name = ops[op_idx].string_params[0]; if (marks.find(mark_name) != marks.end()) { std::stringstream msg; - msg << "Duplicated mark destination:\"" << mark_name << "\"." << std::endl; + msg << "Duplicated mark destination:\"" << mark_name << "\"." + << std::endl; throw std::runtime_error(msg.str()); } marks.insert(mark_name); @@ -582,7 +589,7 @@ void Circuit::set_params(bool truncation) { if (!ops_to_remove && !ancestor[tpos]) { continue; } - auto& op = ops[tpos]; + auto &op = ops[tpos]; if (remapped_qubits) { remap_qubits(ops[tpos]); } @@ -593,7 +600,7 @@ void Circuit::set_params(bool truncation) { } // Now add remaining delayed measure ops first_measure_pos = op_idx; - for (auto & op : tail_meas_ops) { + for (auto &op : tail_meas_ops) { if (remapped_qubits) { remap_qubits(op); } @@ -608,55 +615,54 @@ void Circuit::set_params(bool truncation) { ops.resize(op_idx); } - -void Circuit::remap_qubits(Op& op) const { +void Circuit::remap_qubits(Op &op) const { reg_t new_qubits; - for (auto& qubit : op.qubits) { + for (auto &qubit : op.qubits) { new_qubits.push_back(qubitmap_.at(qubit)); } op.qubits = std::move(new_qubits); } - -bool Circuit::check_result_ancestor(const Op& op, std::unordered_set& ancestor_qubits) const { +bool Circuit::check_result_ancestor( + const Op &op, std::unordered_set &ancestor_qubits) const { switch (op.type) { - case OpType::barrier: - case OpType::nop: { - return false; - } - case OpType::bfunc: { - return true; - } - // Result generating types - case OpType::measure: - case OpType::roerror: - case OpType::save_state: - case OpType::save_expval: - case OpType::save_expval_var: - case OpType::save_statevec: - case OpType::save_statevec_dict: - case OpType::save_densmat: - case OpType::save_probs: - case OpType::save_probs_ket: - case OpType::save_amps: - case OpType::save_amps_sq: - case OpType::save_stabilizer: - case OpType::save_clifford: - case OpType::save_unitary: - case OpType::save_mps: - case OpType::save_superop: { - ancestor_qubits.insert(op.qubits.begin(), op.qubits.end()); - return true; - } - default: { - for (const auto& qubit : op.qubits) { - if (ancestor_qubits.find(qubit) != ancestor_qubits.end()) { - ancestor_qubits.insert(op.qubits.begin(), op.qubits.end()); - return true; - } + case OpType::barrier: + case OpType::nop: { + return false; + } + case OpType::bfunc: { + return true; + } + // Result generating types + case OpType::measure: + case OpType::roerror: + case OpType::save_state: + case OpType::save_expval: + case OpType::save_expval_var: + case OpType::save_statevec: + case OpType::save_statevec_dict: + case OpType::save_densmat: + case OpType::save_probs: + case OpType::save_probs_ket: + case OpType::save_amps: + case OpType::save_amps_sq: + case OpType::save_stabilizer: + case OpType::save_clifford: + case OpType::save_unitary: + case OpType::save_mps: + case OpType::save_superop: { + ancestor_qubits.insert(op.qubits.begin(), op.qubits.end()); + return true; + } + default: { + for (const auto &qubit : op.qubits) { + if (ancestor_qubits.find(qubit) != ancestor_qubits.end()) { + ancestor_qubits.insert(op.qubits.begin(), op.qubits.end()); + return true; } - return false; } + return false; + } } } diff --git a/src/framework/config.hpp b/src/framework/config.hpp index 59b0c76004..6ebe786559 100644 --- a/src/framework/config.hpp +++ b/src/framework/config.hpp @@ -15,9 +15,9 @@ #ifndef _aer_framework_config_hpp_ #define _aer_framework_config_hpp_ -#include -#include #include "types.hpp" +#include +#include namespace AER { @@ -33,26 +33,22 @@ struct optional { return val; } - void value(const T& input) { + void value(const T &input) { exist = true; val = input; } - void clear() { - exist = false; - } + void clear() { exist = false; } - // operator bool() const { + // operator bool() const { // return exist; // } - bool has_value() const { - return exist; - } + bool has_value() const { return exist; } }; template -bool get_value(optional &var, const std::string& key, const json_t &js) { +bool get_value(optional &var, const std::string &key, const json_t &js) { if (JSON::check_key(key, js)) { var.value(js[key].get()); return true; @@ -63,7 +59,7 @@ bool get_value(optional &var, const std::string& key, const json_t &js) { } template -bool get_value(T &var, const std::string& key, const json_t &js) { +bool get_value(T &var, const std::string &key, const json_t &js) { return JSON::get_value(var, key, js); } @@ -74,7 +70,7 @@ struct Config { uint_t shots = 1024; std::string method = "automatic"; std::string device = "CPU"; - std::string precision ="double"; + std::string precision = "double"; // executor=None, // max_job_size=None, // max_shot_size=None, @@ -85,8 +81,8 @@ struct Config { optional max_parallel_experiments; optional max_parallel_shots; optional max_memory_mb; - bool fusion_enable=true; - bool fusion_verbose=false; + bool fusion_enable = true; + bool fusion_verbose = false; optional fusion_max_qubit; optional fusion_threshold; optional accept_distributed_results; @@ -173,7 +169,7 @@ struct Config { shots = 1024; method = "automatic"; device = "CPU"; - precision ="double"; + precision = "double"; // executor=None, // max_job_size=None, // max_shot_size=None, @@ -184,8 +180,8 @@ struct Config { max_parallel_experiments.clear(); max_parallel_shots.clear(); max_memory_mb.clear(); - fusion_enable=true; - fusion_verbose=false; + fusion_enable = true; + fusion_verbose = false; fusion_max_qubit.clear(); fusion_threshold.clear(); accept_distributed_results.clear(); @@ -266,7 +262,7 @@ struct Config { extended_stabilizer_norm_estimation_default_samples.clear(); } - void merge(const Config& other) { + void merge(const Config &other) { shots = other.shots; method = other.method; device = other.device; @@ -277,44 +273,69 @@ struct Config { enable_truncation = other.enable_truncation; zero_threshold = other.zero_threshold; validation_threshold = other.validation_threshold; - if (other.max_parallel_threads.has_value()) max_parallel_threads.value(other.max_parallel_threads.value()); - if (other.max_parallel_experiments.has_value()) max_parallel_experiments.value(other.max_parallel_experiments.value()); - if (other.max_parallel_shots.has_value()) max_parallel_shots.value(other.max_parallel_shots.value()); - if (other.max_memory_mb.has_value()) max_memory_mb.value(other.max_memory_mb.value()); + if (other.max_parallel_threads.has_value()) + max_parallel_threads.value(other.max_parallel_threads.value()); + if (other.max_parallel_experiments.has_value()) + max_parallel_experiments.value(other.max_parallel_experiments.value()); + if (other.max_parallel_shots.has_value()) + max_parallel_shots.value(other.max_parallel_shots.value()); + if (other.max_memory_mb.has_value()) + max_memory_mb.value(other.max_memory_mb.value()); fusion_enable = other.fusion_enable; fusion_verbose = other.fusion_verbose; - if (other.fusion_max_qubit.has_value()) fusion_max_qubit.value(other.fusion_max_qubit.value()); - if (other.fusion_threshold.has_value()) fusion_threshold.value(other.fusion_threshold.value()); - if (other.accept_distributed_results.has_value()) accept_distributed_results.value(other.accept_distributed_results.value()); - if (other.memory.has_value()) memory.value(other.memory.value()); + if (other.fusion_max_qubit.has_value()) + fusion_max_qubit.value(other.fusion_max_qubit.value()); + if (other.fusion_threshold.has_value()) + fusion_threshold.value(other.fusion_threshold.value()); + if (other.accept_distributed_results.has_value()) + accept_distributed_results.value( + other.accept_distributed_results.value()); + if (other.memory.has_value()) + memory.value(other.memory.value()); // noise_model=None, - if (other.seed_simulator.has_value()) seed_simulator.value(other.seed_simulator.value()); + if (other.seed_simulator.has_value()) + seed_simulator.value(other.seed_simulator.value()); // # cuStateVec (cuQuantum) option - if (other.cuStateVec_enable.has_value()) cuStateVec_enable.value(other.cuStateVec_enable.value()); + if (other.cuStateVec_enable.has_value()) + cuStateVec_enable.value(other.cuStateVec_enable.value()); // # cache blocking for multi-GPUs/MPI options - if (other.blocking_qubits.has_value()) blocking_qubits.value(other.blocking_qubits.value()); + if (other.blocking_qubits.has_value()) + blocking_qubits.value(other.blocking_qubits.value()); blocking_enable = other.blocking_enable; - if (other.chunk_swap_buffer_qubits.has_value()) chunk_swap_buffer_qubits.value(other.chunk_swap_buffer_qubits.value()); + if (other.chunk_swap_buffer_qubits.has_value()) + chunk_swap_buffer_qubits.value(other.chunk_swap_buffer_qubits.value()); // # multi-shots optimization options (GPU only) batched_shots_gpu = other.batched_shots_gpu; batched_shots_gpu_max_qubits = other.batched_shots_gpu_max_qubits; - if (other.num_threads_per_device.has_value()) num_threads_per_device.value(other.num_threads_per_device.value()); + if (other.num_threads_per_device.has_value()) + num_threads_per_device.value(other.num_threads_per_device.value()); // # statevector options statevector_parallel_threshold = other.statevector_parallel_threshold; statevector_sample_measure_opt = other.statevector_sample_measure_opt; // # stabilizer options - stabilizer_max_snapshot_probabilities = other.stabilizer_max_snapshot_probabilities; + stabilizer_max_snapshot_probabilities = + other.stabilizer_max_snapshot_probabilities; // # extended stabilizer options - extended_stabilizer_sampling_method = other.extended_stabilizer_sampling_method; - extended_stabilizer_metropolis_mixing_time = other.extended_stabilizer_metropolis_mixing_time; - extended_stabilizer_approximation_error = other.extended_stabilizer_approximation_error; - extended_stabilizer_norm_estimation_samples = other.extended_stabilizer_norm_estimation_samples; - extended_stabilizer_norm_estimation_repetitions = other.extended_stabilizer_norm_estimation_repetitions; - extended_stabilizer_parallel_threshold = other.extended_stabilizer_parallel_threshold; - extended_stabilizer_probabilities_snapshot_samples = other.extended_stabilizer_probabilities_snapshot_samples; + extended_stabilizer_sampling_method = + other.extended_stabilizer_sampling_method; + extended_stabilizer_metropolis_mixing_time = + other.extended_stabilizer_metropolis_mixing_time; + extended_stabilizer_approximation_error = + other.extended_stabilizer_approximation_error; + extended_stabilizer_norm_estimation_samples = + other.extended_stabilizer_norm_estimation_samples; + extended_stabilizer_norm_estimation_repetitions = + other.extended_stabilizer_norm_estimation_repetitions; + extended_stabilizer_parallel_threshold = + other.extended_stabilizer_parallel_threshold; + extended_stabilizer_probabilities_snapshot_samples = + other.extended_stabilizer_probabilities_snapshot_samples; // # MPS options - matrix_product_state_truncation_threshold = other.matrix_product_state_truncation_threshold; - if (other.matrix_product_state_max_bond_dimension.has_value()) matrix_product_state_max_bond_dimension.value(other.matrix_product_state_max_bond_dimension.value()); + matrix_product_state_truncation_threshold = + other.matrix_product_state_truncation_threshold; + if (other.matrix_product_state_max_bond_dimension.has_value()) + matrix_product_state_max_bond_dimension.value( + other.matrix_product_state_max_bond_dimension.value()); mps_sample_measure_algorithm = other.mps_sample_measure_algorithm; mps_log_data = other.mps_log_data; mps_swap_direction = other.mps_swap_direction; @@ -322,40 +343,66 @@ struct Config { mps_parallel_threshold = other.mps_parallel_threshold; mps_omp_threads = other.mps_omp_threads; // # tensor network options - tensor_network_num_sampling_qubits = other.tensor_network_num_sampling_qubits; + tensor_network_num_sampling_qubits = + other.tensor_network_num_sampling_qubits; use_cuTensorNet_autotuning = other.use_cuTensorNet_autotuning; // system configurations param_table = other.param_table; library_dir = other.library_dir; - if (other.n_qubits.has_value()) n_qubits.value(other.n_qubits.value()); + if (other.n_qubits.has_value()) + n_qubits.value(other.n_qubits.value()); global_phase = other.global_phase; memory_slots = other.memory_slots; - if (other._parallel_experiments.has_value()) _parallel_experiments.value(other._parallel_experiments.value()); - if (other._parallel_shots.has_value()) _parallel_shots.value(other._parallel_shots.value()); - if (other._parallel_state_update.has_value()) _parallel_state_update.value(other._parallel_state_update.value()); - if (other._parallel_experiments.has_value()) _parallel_experiments.value(other._parallel_experiments.value()); - if (other.fusion_allow_kraus.has_value()) fusion_allow_kraus.value(other.fusion_allow_kraus.value()); - if (other.fusion_allow_superop.has_value()) fusion_allow_superop.value(other.fusion_allow_superop.value()); - if (other.fusion_parallelization_threshold.has_value()) fusion_parallelization_threshold.value(other.fusion_parallelization_threshold.value()); - if (other._fusion_enable_n_qubits.has_value()) _fusion_enable_n_qubits.value(other._fusion_enable_n_qubits.value()); - if (other._fusion_enable_n_qubits_1.has_value()) _fusion_enable_n_qubits_1.value(other._fusion_enable_n_qubits_1.value()); - if (other._fusion_enable_n_qubits_2.has_value()) _fusion_enable_n_qubits_2.value(other._fusion_enable_n_qubits_2.value()); - if (other._fusion_enable_n_qubits_3.has_value()) _fusion_enable_n_qubits_3.value(other._fusion_enable_n_qubits_3.value()); - if (other._fusion_enable_n_qubits_4.has_value()) _fusion_enable_n_qubits_4.value(other._fusion_enable_n_qubits_4.value()); - if (other._fusion_enable_n_qubits_5.has_value()) _fusion_enable_n_qubits_5.value(other._fusion_enable_n_qubits_5.value()); - if (other._fusion_enable_diagonal.has_value()) _fusion_enable_diagonal.value(other._fusion_enable_diagonal.value()); - if (other._fusion_min_qubit.has_value()) _fusion_min_qubit.value(other._fusion_min_qubit.value()); - if (other.fusion_cost_factor.has_value()) fusion_cost_factor.value(other.fusion_cost_factor.value()); + if (other._parallel_experiments.has_value()) + _parallel_experiments.value(other._parallel_experiments.value()); + if (other._parallel_shots.has_value()) + _parallel_shots.value(other._parallel_shots.value()); + if (other._parallel_state_update.has_value()) + _parallel_state_update.value(other._parallel_state_update.value()); + if (other._parallel_experiments.has_value()) + _parallel_experiments.value(other._parallel_experiments.value()); + if (other.fusion_allow_kraus.has_value()) + fusion_allow_kraus.value(other.fusion_allow_kraus.value()); + if (other.fusion_allow_superop.has_value()) + fusion_allow_superop.value(other.fusion_allow_superop.value()); + if (other.fusion_parallelization_threshold.has_value()) + fusion_parallelization_threshold.value( + other.fusion_parallelization_threshold.value()); + if (other._fusion_enable_n_qubits.has_value()) + _fusion_enable_n_qubits.value(other._fusion_enable_n_qubits.value()); + if (other._fusion_enable_n_qubits_1.has_value()) + _fusion_enable_n_qubits_1.value(other._fusion_enable_n_qubits_1.value()); + if (other._fusion_enable_n_qubits_2.has_value()) + _fusion_enable_n_qubits_2.value(other._fusion_enable_n_qubits_2.value()); + if (other._fusion_enable_n_qubits_3.has_value()) + _fusion_enable_n_qubits_3.value(other._fusion_enable_n_qubits_3.value()); + if (other._fusion_enable_n_qubits_4.has_value()) + _fusion_enable_n_qubits_4.value(other._fusion_enable_n_qubits_4.value()); + if (other._fusion_enable_n_qubits_5.has_value()) + _fusion_enable_n_qubits_5.value(other._fusion_enable_n_qubits_5.value()); + if (other._fusion_enable_diagonal.has_value()) + _fusion_enable_diagonal.value(other._fusion_enable_diagonal.value()); + if (other._fusion_min_qubit.has_value()) + _fusion_min_qubit.value(other._fusion_min_qubit.value()); + if (other.fusion_cost_factor.has_value()) + fusion_cost_factor.value(other.fusion_cost_factor.value()); - if (other.superoperator_parallel_threshold.has_value()) superoperator_parallel_threshold.value(other.superoperator_parallel_threshold.value()); - if (other.unitary_parallel_threshold.has_value()) unitary_parallel_threshold.value(other.unitary_parallel_threshold.value()); - if (other.memory_blocking_bits.has_value()) memory_blocking_bits.value(other.memory_blocking_bits.value()); - if (other.extended_stabilizer_norm_estimation_default_samples.has_value()) extended_stabilizer_norm_estimation_default_samples.value(other.extended_stabilizer_norm_estimation_default_samples.value()); + if (other.superoperator_parallel_threshold.has_value()) + superoperator_parallel_threshold.value( + other.superoperator_parallel_threshold.value()); + if (other.unitary_parallel_threshold.has_value()) + unitary_parallel_threshold.value( + other.unitary_parallel_threshold.value()); + if (other.memory_blocking_bits.has_value()) + memory_blocking_bits.value(other.memory_blocking_bits.value()); + if (other.extended_stabilizer_norm_estimation_default_samples.has_value()) + extended_stabilizer_norm_estimation_default_samples.value( + other.extended_stabilizer_norm_estimation_default_samples.value()); } }; // Json conversion function -inline void from_json(const json_t& js, Config &config) { +inline void from_json(const json_t &js, Config &config) { get_value(config.shots, "shots", js); get_value(config.method, "method", js); get_value(config.device, "device", js); @@ -374,7 +421,8 @@ inline void from_json(const json_t& js, Config &config) { get_value(config.fusion_verbose, "fusion_verbose", js); get_value(config.fusion_max_qubit, "fusion_max_qubit", js); get_value(config.fusion_threshold, "fusion_threshold", js); - get_value(config.accept_distributed_results, "accept_distributed_results", js); + get_value(config.accept_distributed_results, "accept_distributed_results", + js); get_value(config.memory, "memory", js); // noise_model=None, get_value(config.seed_simulator, "seed_simulator", js); @@ -386,33 +434,49 @@ inline void from_json(const json_t& js, Config &config) { get_value(config.chunk_swap_buffer_qubits, "chunk_swap_buffer_qubits", js); // # multi-shots optimization options (GPU only) get_value(config.batched_shots_gpu, "batched_shots_gpu", js); - get_value(config.batched_shots_gpu_max_qubits, "batched_shots_gpu_max_qubits", js); + get_value(config.batched_shots_gpu_max_qubits, "batched_shots_gpu_max_qubits", + js); get_value(config.num_threads_per_device, "num_threads_per_device", js); // # statevector options - get_value(config.statevector_parallel_threshold, "statevector_parallel_threshold", js); - get_value(config.statevector_sample_measure_opt, "statevector_sample_measure_opt", js); + get_value(config.statevector_parallel_threshold, + "statevector_parallel_threshold", js); + get_value(config.statevector_sample_measure_opt, + "statevector_sample_measure_opt", js); // # stabilizer options - get_value(config.stabilizer_max_snapshot_probabilities, "stabilizer_max_snapshot_probabilities", js); + get_value(config.stabilizer_max_snapshot_probabilities, + "stabilizer_max_snapshot_probabilities", js); // # extended stabilizer options - get_value(config.extended_stabilizer_sampling_method, "extended_stabilizer_sampling_method", js); - get_value(config.extended_stabilizer_metropolis_mixing_time, "extended_stabilizer_metropolis_mixing_time", js); - get_value(config.extended_stabilizer_approximation_error, "extended_stabilizer_approximation_error", js); - get_value(config.extended_stabilizer_norm_estimation_samples, "extended_stabilizer_norm_estimation_samples", js); - get_value(config.extended_stabilizer_norm_estimation_repetitions, "extended_stabilizer_norm_estimation_repetitions", js); - get_value(config.extended_stabilizer_parallel_threshold, "extended_stabilizer_parallel_threshold", js); - get_value(config.extended_stabilizer_probabilities_snapshot_samples, "extended_stabilizer_probabilities_snapshot_samples", js); + get_value(config.extended_stabilizer_sampling_method, + "extended_stabilizer_sampling_method", js); + get_value(config.extended_stabilizer_metropolis_mixing_time, + "extended_stabilizer_metropolis_mixing_time", js); + get_value(config.extended_stabilizer_approximation_error, + "extended_stabilizer_approximation_error", js); + get_value(config.extended_stabilizer_norm_estimation_samples, + "extended_stabilizer_norm_estimation_samples", js); + get_value(config.extended_stabilizer_norm_estimation_repetitions, + "extended_stabilizer_norm_estimation_repetitions", js); + get_value(config.extended_stabilizer_parallel_threshold, + "extended_stabilizer_parallel_threshold", js); + get_value(config.extended_stabilizer_probabilities_snapshot_samples, + "extended_stabilizer_probabilities_snapshot_samples", js); // # MPS options - get_value(config.matrix_product_state_truncation_threshold, "matrix_product_state_truncation_threshold", js); - get_value(config.matrix_product_state_max_bond_dimension, "matrix_product_state_max_bond_dimension", js); - get_value(config.mps_sample_measure_algorithm, "mps_sample_measure_algorithm", js); + get_value(config.matrix_product_state_truncation_threshold, + "matrix_product_state_truncation_threshold", js); + get_value(config.matrix_product_state_max_bond_dimension, + "matrix_product_state_max_bond_dimension", js); + get_value(config.mps_sample_measure_algorithm, "mps_sample_measure_algorithm", + js); get_value(config.mps_log_data, "mps_log_data", js); get_value(config.mps_swap_direction, "mps_swap_direction", js); get_value(config.chop_threshold, "chop_threshold", js); get_value(config.mps_parallel_threshold, "mps_parallel_threshold", js); get_value(config.mps_omp_threads, "mps_omp_threads", js); // # tensor network options - get_value(config.tensor_network_num_sampling_qubits, "tensor_network_num_sampling_qubits", js); - get_value(config.use_cuTensorNet_autotuning, "use_cuTensorNet_autotuning", js); + get_value(config.tensor_network_num_sampling_qubits, + "tensor_network_num_sampling_qubits", js); + get_value(config.use_cuTensorNet_autotuning, "use_cuTensorNet_autotuning", + js); // system configurations get_value(config.param_table, "parameterizations", js); get_value(config.library_dir, "library_dir", js); @@ -425,7 +489,8 @@ inline void from_json(const json_t& js, Config &config) { get_value(config.fusion_allow_kraus, "fusion_allow_kraus", js); get_value(config.fusion_allow_superop, "fusion_allow_superop", js); - get_value(config.fusion_parallelization_threshold, "fusion_parallelization_threshold", js); + get_value(config.fusion_parallelization_threshold, + "fusion_parallelization_threshold", js); get_value(config._fusion_enable_n_qubits, "_fusion_enable_n_qubits", js); get_value(config._fusion_enable_n_qubits_1, "_fusion_enable_n_qubits_1", js); get_value(config._fusion_enable_n_qubits_2, "_fusion_enable_n_qubits_2", js); @@ -436,12 +501,15 @@ inline void from_json(const json_t& js, Config &config) { get_value(config._fusion_min_qubit, "_fusion_min_qubit", js); get_value(config.fusion_cost_factor, "fusion_cost_factor", js); - get_value(config.superoperator_parallel_threshold, "superoperator_parallel_threshold", js); - get_value(config.unitary_parallel_threshold, "unitary_parallel_threshold", js); + get_value(config.superoperator_parallel_threshold, + "superoperator_parallel_threshold", js); + get_value(config.unitary_parallel_threshold, "unitary_parallel_threshold", + js); get_value(config.memory_blocking_bits, "memory_blocking_bits", js); - get_value(config.extended_stabilizer_norm_estimation_default_samples, "extended_stabilizer_norm_estimation_default_samples", js); + get_value(config.extended_stabilizer_norm_estimation_default_samples, + "extended_stabilizer_norm_estimation_default_samples", js); } -} +} // namespace AER #endif \ No newline at end of file diff --git a/src/framework/creg.hpp b/src/framework/creg.hpp old mode 100755 new mode 100644 index 2a79a0e871..1a0d012865 --- a/src/framework/creg.hpp +++ b/src/framework/creg.hpp @@ -16,8 +16,8 @@ #define _aer_framework_creg_hpp_ #include "framework/operations.hpp" -#include "framework/utils.hpp" #include "framework/rng.hpp" +#include "framework/utils.hpp" namespace AER { @@ -29,39 +29,39 @@ namespace AER { class ClassicalRegister { public: - // Return the current value of the memory as little-endian hex-string - inline std::string memory_hex() const {return Utils::bin2hex(creg_memory_);} + inline std::string memory_hex() const { return Utils::bin2hex(creg_memory_); } // Return the current value of the memory as little-endian bit-string - inline std::string memory_bin() const {return "0b" + creg_memory_;} + inline std::string memory_bin() const { return "0b" + creg_memory_; } // Return the current value of the memory as little-endian hex-string - inline std::string register_hex() const {return Utils::bin2hex(creg_register_);} + inline std::string register_hex() const { + return Utils::bin2hex(creg_register_); + } // Return the current value of the memory as little-endian bit-string - inline std::string register_bin() const {return "0b" + creg_register_;} + inline std::string register_bin() const { return "0b" + creg_register_; } // Return the size of the memory bits - size_t memory_size() const {return creg_memory_.size();} + size_t memory_size() const { return creg_memory_.size(); } // Return the size of the register bits - size_t register_size() const {return creg_register_.size();} + size_t register_size() const { return creg_register_.size(); } // Return a reference to the current value of the memory // this is a bit-string without the "0b" prefix. - inline auto& creg_memory() {return creg_memory_;} + inline auto &creg_memory() { return creg_memory_; } // Return a reference to the current value of the memory // this is a bit-string without the "0b" prefix. - inline auto& creg_register() {return creg_register_;} + inline auto &creg_register() { return creg_register_; } // Initialize the memory and register bits to default values (all 0) void initialize(size_t num_memory, size_t num_registers); // Initialize the memory and register bits to specific values - void initialize(size_t num_memory, - size_t num_registers, + void initialize(size_t num_memory, size_t num_registers, const std::string &memory_hex, const std::string ®ister_hex); @@ -76,17 +76,18 @@ class ClassicalRegister { // Apply readout error instruction to classical registers void apply_roerror(const Operations::Op &op, RngEngine &rng); - // Store a measurement outcome in the specified memory and register bit locations - void store_measure(const reg_t &outcome, const reg_t &memory, const reg_t ®isters); + // Store a measurement outcome in the specified memory and register bit + // locations + void store_measure(const reg_t &outcome, const reg_t &memory, + const reg_t ®isters); protected: - // Classical registers std::string creg_memory_; // standard classical bit memory std::string creg_register_; // optional classical bit register // Measurement config settings - bool return_hex_strings_ = true; // Set to false for bit-string output + bool return_hex_strings_ = true; // Set to false for bit-string output }; //============================================================================ @@ -99,9 +100,7 @@ void ClassicalRegister::initialize(size_t num_memory, size_t num_register) { creg_register_ = std::string(num_register, '0'); } - -void ClassicalRegister::initialize(size_t num_memory, - size_t num_register, +void ClassicalRegister::initialize(size_t num_memory, size_t num_register, const std::string &memory_hex, const std::string ®ister_hex) { // Convert to bit-string for internal storage @@ -109,74 +108,77 @@ void ClassicalRegister::initialize(size_t num_memory, creg_memory_ = std::move(Utils::padleft_inplace(memory_bin, '0', num_memory)); std::string register_bin = Utils::hex2bin(register_hex, false); - creg_register_ = std::move(Utils::padleft_inplace(memory_bin, '0', num_register)); + creg_register_ = + std::move(Utils::padleft_inplace(memory_bin, '0', num_register)); } - -void ClassicalRegister::store_measure(const reg_t &outcome, - const reg_t &memory, +void ClassicalRegister::store_measure(const reg_t &outcome, const reg_t &memory, const reg_t ®isters) { // Assumes memory and registers are either empty or same size as outcome! bool use_mem = !memory.empty(); bool use_reg = !registers.empty(); - for (size_t j=0; j < outcome.size(); j++) { + for (size_t j = 0; j < outcome.size(); j++) { if (use_mem) { // least significant bit first ordering - const size_t pos = creg_memory_.size() - memory[j] - 1; + const size_t pos = creg_memory_.size() - memory[j] - 1; creg_memory_[pos] = std::to_string(outcome[j])[0]; // int->string->char } if (use_reg) { // least significant bit first ordering - const size_t pos = creg_register_.size() - registers[j] - 1; - creg_register_[pos] = std::to_string(outcome[j])[0]; // int->string->char + const size_t pos = creg_register_.size() - registers[j] - 1; + creg_register_[pos] = std::to_string(outcome[j])[0]; // int->string->char } } } - bool ClassicalRegister::check_conditional(const Operations::Op &op) const { // Check if op is conditional if (op.conditional) - return (creg_register_[creg_register_.size() - op.conditional_reg - 1] == '1'); + return (creg_register_[creg_register_.size() - op.conditional_reg - 1] == + '1'); // Op is not conditional return true; } - void ClassicalRegister::apply_bfunc(const Operations::Op &op) { // Check input is boolean function op if (op.type != Operations::OpType::bfunc) { - throw std::invalid_argument("ClassicalRegister::apply_bfunc: Input is not a bfunc op."); + throw std::invalid_argument( + "ClassicalRegister::apply_bfunc: Input is not a bfunc op."); } const std::string &mask = op.string_params[0]; const std::string &target_val = op.string_params[1]; - int_t compared; // if equal this should be 0, if less than -1, if greater than +1 + int_t compared; // if equal this should be 0, if less than -1, if greater than + // +1 // Check if register size fits into a 64-bit integer if (creg_register_.size() <= 64) { - uint_t reg_int = std::stoull(creg_register_, nullptr, 2); // stored as bitstring + uint_t reg_int = + std::stoull(creg_register_, nullptr, 2); // stored as bitstring uint_t mask_int = std::stoull(mask, nullptr, 16); // stored as hexstring - uint_t target_int = std::stoull(target_val, nullptr, 16); // stored as hexstring + uint_t target_int = + std::stoull(target_val, nullptr, 16); // stored as hexstring compared = (reg_int & mask_int) - target_int; } else { - // We need to use big ints so we implement the bit-mask via the binary string - // representation rather than using a big integer class + // We need to use big ints so we implement the bit-mask via the binary + // string representation rather than using a big integer class std::string mask_bin = Utils::hex2bin(mask, false); size_t length = std::min(mask_bin.size(), creg_register_.size()); std::string masked_val = std::string(length, '0'); for (size_t rev_pos = 0; rev_pos < length; rev_pos++) { - masked_val[length - 1 - rev_pos] = (mask_bin[mask_bin.size() - 1 - rev_pos] - & creg_register_[creg_register_.size() - 1 - rev_pos]); + masked_val[length - 1 - rev_pos] = + (mask_bin[mask_bin.size() - 1 - rev_pos] & + creg_register_[creg_register_.size() - 1 - rev_pos]); } // remove leading 0's size_t end_i = masked_val.find('1'); if (end_i == std::string::npos) - masked_val = "0"; + masked_val = "0"; else - masked_val.erase(0, end_i); + masked_val.erase(0, end_i); masked_val = Utils::bin2hex(masked_val); // convert to hex string // Using string comparison to compare to target value @@ -185,51 +187,53 @@ void ClassicalRegister::apply_bfunc(const Operations::Op &op) { // check value of compared integer for different comparison operations bool outcome; switch (op.bfunc) { - case Operations::RegComparison::Equal: - outcome = (compared == 0); - break; - case Operations::RegComparison::NotEqual: - outcome = (compared != 0); - break; - case Operations::RegComparison::Less: - outcome = (compared < 0); - break; - case Operations::RegComparison::LessEqual: - outcome = (compared <= 0); - break; - case Operations::RegComparison::Greater: - outcome = (compared > 0); - break; - case Operations::RegComparison::GreaterEqual: - outcome = (compared >= 0); - break; - default: - // we shouldn't ever get here - throw std::invalid_argument("Invalid boolean function relation."); + case Operations::RegComparison::Equal: + outcome = (compared == 0); + break; + case Operations::RegComparison::NotEqual: + outcome = (compared != 0); + break; + case Operations::RegComparison::Less: + outcome = (compared < 0); + break; + case Operations::RegComparison::LessEqual: + outcome = (compared <= 0); + break; + case Operations::RegComparison::Greater: + outcome = (compared > 0); + break; + case Operations::RegComparison::GreaterEqual: + outcome = (compared >= 0); + break; + default: + // we shouldn't ever get here + throw std::invalid_argument("Invalid boolean function relation."); } // Store outcome in register if (op.registers.size() > 0) { - const size_t pos = creg_register_.size() - op.registers[0] - 1; + const size_t pos = creg_register_.size() - op.registers[0] - 1; creg_register_[pos] = (outcome) ? '1' : '0'; } // Optionally store outcome in memory if (op.memory.size() > 0) { - const size_t pos = creg_memory_.size() - op.memory[0] - 1; + const size_t pos = creg_memory_.size() - op.memory[0] - 1; creg_memory_[pos] = (outcome) ? '1' : '0'; } } // Apply readout error instruction to classical registers -void ClassicalRegister::apply_roerror(const Operations::Op &op, RngEngine &rng) { - +void ClassicalRegister::apply_roerror(const Operations::Op &op, + RngEngine &rng) { + // Check input is readout error op if (op.type != Operations::OpType::roerror) { - throw std::invalid_argument("ClassicalRegister::apply_roerror Input is not a readout error op."); + throw std::invalid_argument( + "ClassicalRegister::apply_roerror Input is not a readout error op."); } - + // Get current classical bit (and optionally register bit) values std::string mem_str; - + // Get values of bits as binary string // We iterate from the end of the list of memory bits for (auto it = op.memory.rbegin(); it < op.memory.rend(); ++it) { @@ -241,12 +245,14 @@ void ClassicalRegister::apply_roerror(const Operations::Op &op, RngEngine &rng) auto noise_str = Utils::int2string(outcome, 2, op.memory.size()); for (size_t pos = 0; pos < op.memory.size(); ++pos) { auto bit = op.memory[pos]; - creg_memory_[creg_memory_.size() - 1 - bit] = noise_str[noise_str.size() - 1 - pos]; + creg_memory_[creg_memory_.size() - 1 - bit] = + noise_str[noise_str.size() - 1 - pos]; } // and the same error to register classical bits if they are used for (size_t pos = 0; pos < op.registers.size(); ++pos) { auto bit = op.registers[pos]; - creg_register_[creg_register_.size() - 1 - bit] = noise_str[noise_str.size() - 1 - pos]; + creg_register_[creg_register_.size() - 1 - bit] = + noise_str[noise_str.size() - 1 - pos]; } } diff --git a/src/framework/json.hpp b/src/framework/json.hpp old mode 100755 new mode 100644 index f6f79113f3..172f4eb1ee --- a/src/framework/json.hpp +++ b/src/framework/json.hpp @@ -29,8 +29,8 @@ DISABLE_WARNING_PUSH #include DISABLE_WARNING_POP -#include "framework/matrix.hpp" #include "framework/linalg/vector.hpp" +#include "framework/matrix.hpp" namespace nl = nlohmann; using json_t = nlohmann::json; @@ -48,7 +48,7 @@ namespace JSON { * @param name: file name to load. * @returns: the loaded json. */ -inline json_t load(const std::string& name); +inline json_t load(const std::string &name); /** * Check if a key exists in a json_t object. @@ -56,7 +56,7 @@ inline json_t load(const std::string& name); * @param js: the json_t to search for key. * @returns: true if the key exists, false otherwise. */ -inline bool check_key(const std::string& key, const json_t &js); +inline bool check_key(const std::string &key, const json_t &js); /** * Check if all keys exists in a json_t object. @@ -64,7 +64,7 @@ inline bool check_key(const std::string& key, const json_t &js); * @param js: the json_t to search for keys. * @returns: true if all keys exists, false otherwise. */ -inline bool check_keys(const std::vector& keys, const json_t &js); +inline bool check_keys(const std::vector &keys, const json_t &js); /** * Load a json_t object value into a variable if the key name exists. @@ -73,9 +73,10 @@ inline bool check_keys(const std::vector& keys, const json_t &js); * @param js: the json_t to search for key. * @returns: true if the keys exists and val was set, false otherwise. */ -template bool get_value(T &var, const std::string& key, const json_t &js); +template +bool get_value(T &var, const std::string &key, const json_t &js); -const json_t& get_value(const std::string& key, const json_t &js); +const json_t &get_value(const std::string &key, const json_t &js); } // end namespace JSON @@ -90,7 +91,8 @@ namespace std { * @param js a json_t object to contain converted type. * @param z a complex number to convert. */ -template void to_json(json_t &js, const std::complex &z); +template +void to_json(json_t &js, const std::complex &z); /** * Convert a JSON value to a complex number z. If the json value is a float @@ -99,7 +101,8 @@ template void to_json(json_t &js, const std::complex &z); * @param js a json_t object to convert. * @param z a complex number to contain result. */ -template void from_json(const json_t &js, std::complex &z); +template +void from_json(const json_t &js, std::complex &z); /** * Convert a complex vector to a json list @@ -150,9 +153,9 @@ void to_json(json_t &js, const std::map &map); * @param js a json_t object to contain converted type. * @param mat a matrix to convert. */ -template +template void from_json(const json_t &js, matrix &mat); -template +template void to_json(json_t &js, const matrix &mat); /******************************************************************************* @@ -165,7 +168,7 @@ void to_json(json_t &js, const matrix &mat); // JSON Helper Functions //------------------------------------------------------------------------------ -json_t JSON::load(const std::string& name) { +json_t JSON::load(const std::string &name) { if (name == "") { json_t js; return js; // Return empty node if no config file @@ -186,7 +189,7 @@ json_t JSON::load(const std::string& name) { return js; } -bool JSON::check_key(const std::string& key, const json_t &js) { +bool JSON::check_key(const std::string &key, const json_t &js) { // returns false if the value is 'null' if (js.find(key) != js.end() && !js[key].is_null()) return true; @@ -194,15 +197,15 @@ bool JSON::check_key(const std::string& key, const json_t &js) { return false; } -bool JSON::check_keys(const std::vector& keys, const json_t &js) { +bool JSON::check_keys(const std::vector &keys, const json_t &js) { bool pass = true; - for (const auto& s : keys) + for (const auto &s : keys) pass &= check_key(s, js); return pass; } template -bool JSON::get_value(T &var, const std::string& key, const json_t &js) { +bool JSON::get_value(T &var, const std::string &key, const json_t &js) { if (check_key(key, js)) { var = js[key].get(); return true; @@ -211,8 +214,8 @@ bool JSON::get_value(T &var, const std::string& key, const json_t &js) { } } -const json_t& JSON::get_value(const std::string& key, const json_t &js){ - return js[key]; +const json_t &JSON::get_value(const std::string &key, const json_t &js) { + return js[key]; } //------------------------------------------------------------------------------ @@ -231,8 +234,7 @@ void std::from_json(const json_t &js, std::complex &z) { else if (js.is_array() && js.size() == 2) { z = std::complex{js[0].get(), js[1].get()}; } else { - throw std::invalid_argument( - std::string("JSON: invalid complex number")); + throw std::invalid_argument(std::string("JSON: invalid complex number")); } } @@ -246,16 +248,15 @@ void std::to_json(json_t &js, const std::vector> &vec) { } template -void std::from_json(const json_t &js, std::vector> &vec) { +void std::from_json(const json_t &js, + std::vector> &vec) { std::vector> ret; if (js.is_array()) { for (auto &elt : js) ret.push_back(elt); vec = ret; - } - else { - throw std::invalid_argument( - std::string("JSON: invalid complex vector.")); + } else { + throw std::invalid_argument(std::string("JSON: invalid complex vector.")); } } @@ -263,7 +264,7 @@ template void std::to_json(json_t &js, const AER::Vector> &vec) { std::vector> out; for (int64_t i = 0; i < vec.size(); ++i) { - auto& z = vec[i]; + auto &z = vec[i]; out.push_back(std::vector{real(z), imag(z)}); } js = out; @@ -294,7 +295,8 @@ void std::to_json(json_t &js, const std::map &map) { // Implementation: JSON Conversion //------------------------------------------------------------------------------ -template void to_json(json_t &js, const matrix &mat) { +template +void to_json(json_t &js, const matrix &mat) { js = json_t(); size_t rows = mat.GetRows(); size_t cols = mat.GetColumns(); @@ -306,15 +308,15 @@ template void to_json(json_t &js, const matrix &mat) { } } - -template void from_json(const json_t &js, matrix &mat) { +template +void from_json(const json_t &js, matrix &mat) { // Check JSON is an array - if(!js.is_array()) { + if (!js.is_array()) { throw std::invalid_argument( std::string("JSON: invalid matrix (not array).")); } // Check JSON isn't empty - if(js.empty()) { + if (js.empty()) { throw std::invalid_argument( std::string("JSON: invalid matrix (empty array).")); } @@ -325,7 +327,7 @@ template void from_json(const json_t &js, matrix &mat) { size_t nrows = js.size(); for (auto &row : js) rows_valid &= (row.is_array() && row.size() == ncols); - if(!rows_valid) { + if (!rows_valid) { throw std::invalid_argument( std::string("JSON: invalid matrix (rows different sizes).")); } diff --git a/src/framework/json_parser.hpp b/src/framework/json_parser.hpp index 882af3efe0..d9576338e8 100644 --- a/src/framework/json_parser.hpp +++ b/src/framework/json_parser.hpp @@ -17,8 +17,7 @@ #include "json.hpp" - -namespace AER{ +namespace AER { // This structure is to avoid overload resolving to the wron function, // as py::objects can always be implicitly converted to json, though // can break at runtime, or even worse trasnform to json and then to c++ @@ -28,61 +27,57 @@ struct Parser {}; template <> struct Parser { - Parser() = delete; + Parser() = delete; - template - static bool get_value(T &var, const std::string& key, const json_t &js){ - return JSON::get_value(var, key, js); - } + template + static bool get_value(T &var, const std::string &key, const json_t &js) { + return JSON::get_value(var, key, js); + } - static bool check_key(const std::string& key, const json_t &js){ - return JSON::check_key(key, js); - } + static bool check_key(const std::string &key, const json_t &js) { + return JSON::check_key(key, js); + } - static const json_t& get_value(const std::string& key, const json_t &js){ - return JSON::get_value(key, js); - } + static const json_t &get_value(const std::string &key, const json_t &js) { + return JSON::get_value(key, js); + } - static bool check_keys(const std::vector& keys, const json_t &js) { - return JSON::check_keys(keys, js); - } + static bool check_keys(const std::vector &keys, + const json_t &js) { + return JSON::check_keys(keys, js); + } - static bool is_array(const json_t &js){ - return js.is_array(); - } + static bool is_array(const json_t &js) { return js.is_array(); } - static bool is_array(const std::string& key, const json_t &js){ - return js[key].is_array(); - } + static bool is_array(const std::string &key, const json_t &js) { + return js[key].is_array(); + } - static const json_t& get_as_list(const json_t& js){ - if(!is_array(js)){ - throw std::runtime_error("Object is not a list!"); - } - return js; + static const json_t &get_as_list(const json_t &js) { + if (!is_array(js)) { + throw std::runtime_error("Object is not a list!"); } + return js; + } - static const json_t& get_list(const std::string& key, const json_t &js){ - if(!is_array(key, js)){ - throw std::runtime_error("Object " + key + "is not a list!"); - } - return JSON::get_value(key, js); + static const json_t &get_list(const std::string &key, const json_t &js) { + if (!is_array(key, js)) { + throw std::runtime_error("Object " + key + "is not a list!"); } + return JSON::get_value(key, js); + } + static bool is_number(const std::string &key, const json_t &js) { + return js[key].is_number(); + } - static bool is_number(const std::string& key, const json_t &js){ - return js[key].is_number(); - } + static std::string dump(const json_t &js) { return js.dump(); } - static std::string dump(const json_t& js){ - return js.dump(); - } - - template - static T get_list_elem(const json_t& js, unsigned int i){ - return js[i]; - } + template + static T get_list_elem(const json_t &js, unsigned int i) { + return js[i]; + } }; -} +} // namespace AER #endif // _aer_framework_json_parser_hpp_ diff --git a/src/framework/linalg/almost_equal.hpp b/src/framework/linalg/almost_equal.hpp old mode 100755 new mode 100644 index 387cd9d3bc..f4a645d455 --- a/src/framework/linalg/almost_equal.hpp +++ b/src/framework/linalg/almost_equal.hpp @@ -29,27 +29,28 @@ namespace Linalg { // If we have numbers closer to 0, then max_diff can be set to a value // way smaller than epsilon. For numbers larger than 1.0, epsilon will // scale (the bigger the number, the bigger the epsilon). -template ::value, T>::type > -bool almost_equal(T f1, T f2, - T max_diff = std::numeric_limits::epsilon(), +template ::value, T>::type> +bool almost_equal(T f1, T f2, T max_diff = std::numeric_limits::epsilon(), T max_relative_diff = std::numeric_limits::epsilon()) { - T diff = std::abs(f1 - f2); - if (diff <= max_diff) return true; + T diff = std::abs(f1 - f2); + if (diff <= max_diff) + return true; - return diff <= max_relative_diff * std::max(std::abs(f1), std::abs(f2)); + return diff <= max_relative_diff * std::max(std::abs(f1), std::abs(f2)); } template -bool almost_equal(const std::complex& f1, const std::complex& f2, +bool almost_equal(const std::complex &f1, const std::complex &f2, T max_diff = std::numeric_limits::epsilon(), T max_relative_diff = std::numeric_limits::epsilon()) { - return almost_equal(f1.real(), f2.real(), max_diff, max_relative_diff) - && almost_equal(f1.imag(), f2.imag(), max_diff, max_relative_diff); + return almost_equal(f1.real(), f2.real(), max_diff, max_relative_diff) && + almost_equal(f1.imag(), f2.imag(), max_diff, max_relative_diff); } //------------------------------------------------------------------------------ -} // namespace Linalg +} // namespace Linalg //------------------------------------------------------------------------------ -} // end namespace AER +} // end namespace AER //------------------------------------------------------------------------------ #endif diff --git a/src/framework/linalg/eigensystem.hpp b/src/framework/linalg/eigensystem.hpp index da0cc10d58..3f7d463b31 100644 --- a/src/framework/linalg/eigensystem.hpp +++ b/src/framework/linalg/eigensystem.hpp @@ -15,66 +15,65 @@ #ifndef _aer_framework_linalg_eigensystem_hpp_ #define _aer_framework_linalg_eigensystem_hpp_ -#include #include "framework/blas_protos.hpp" #include "framework/matrix.hpp" - +#include /** * Returns the eigenvalues and eigenvectors * of a Hermitian matrix. * Uses the blas function ?heevx * @param hermitian_matrix: The Hermitian matrix. - * @param eigenvalues: On output: vector with the eignevalues of the matrix (input is overwritten) - * @param eigenvectors: On output: matrix with the eigenvectors stored as columns. + * @param eigenvalues: On output: vector with the eignevalues of the matrix + * (input is overwritten) + * @param eigenvectors: On output: matrix with the eigenvectors stored as + * columns. * * @returns: void */ template -void eigensystem_hermitian(const matrix>& hermitian_matrix, - /* out */ std::vector& eigenvalues, - /* out */ matrix>& eigenvectors); +void eigensystem_hermitian(const matrix> &hermitian_matrix, + /* out */ std::vector &eigenvalues, + /* out */ matrix> &eigenvectors); - -template +template struct HeevxFuncs; -template<> -struct HeevxFuncs{ +template <> +struct HeevxFuncs { HeevxFuncs() = delete; - static decltype(zheevx_)& heevx; - static decltype(dlamch_)& lamch; + static decltype(zheevx_) &heevx; + static decltype(dlamch_) &lamch; }; -decltype(zheevx_)& HeevxFuncs::heevx = zheevx_; -decltype(dlamch_)& HeevxFuncs::lamch = dlamch_; +decltype(zheevx_) &HeevxFuncs::heevx = zheevx_; +decltype(dlamch_) &HeevxFuncs::lamch = dlamch_; -template<> -struct HeevxFuncs{ +template <> +struct HeevxFuncs { HeevxFuncs() = delete; - static decltype(cheevx_)& heevx; - static decltype(slamch_)& lamch; + static decltype(cheevx_) &heevx; + static decltype(slamch_) &lamch; }; -decltype(cheevx_)& HeevxFuncs::heevx = cheevx_; -decltype(slamch_)& HeevxFuncs::lamch = slamch_; - +decltype(cheevx_) &HeevxFuncs::heevx = cheevx_; +decltype(slamch_) &HeevxFuncs::lamch = slamch_; template -void eigensystem_hermitian(const matrix>& hermitian_matrix, - std::vector& eigenvalues, - matrix>& eigenvectors) { - if ( hermitian_matrix.GetRows() != hermitian_matrix.GetColumns() ) { +void eigensystem_hermitian(const matrix> &hermitian_matrix, + std::vector &eigenvalues, + matrix> &eigenvectors) { + if (hermitian_matrix.GetRows() != hermitian_matrix.GetColumns()) { throw std::runtime_error("Input matrix in eigensystem_hermitian " "function is not a square matrix."); } int n = static_cast(hermitian_matrix.GetLD()); - int ldz{n}, lda{n}, lwork{2*n}; - int il{0}, iu{0}; // not referenced if range='A' + int ldz{n}, lda{n}, lwork{2 * n}; + int il{0}, iu{0}; // not referenced if range='A' T vl{0.0}, vu{0.0}; // not referenced if range='A' char cmach{'S'}; - T abstol{static_cast(2.0*HeevxFuncs::lamch(&cmach))}; + T abstol{static_cast(2.0 * HeevxFuncs::lamch(&cmach))}; int m{0}; // number of eigenvalues found int info{0}; @@ -83,18 +82,20 @@ void eigensystem_hermitian(const matrix>& hermitian_matrix, eigenvalues.resize(n); matrix> heevx_copy{hermitian_matrix}; auto work = std::vector>(lwork, {0.0, 0.0}); - auto rwork = std::vector(7*n, 0.0); - auto iwork = std::vector(5*n, 0); + auto rwork = std::vector(7 * n, 0.0); + auto iwork = std::vector(5 * n, 0); auto ifail = std::vector(n, 0); - HeevxFuncs::heevx(&AerBlas::Jobz[0], &AerBlas::Range[0], &AerBlas::UpLo[0], &n, - heevx_copy.data(), &lda, &vl, &vu, &il, &iu, - &abstol, &m, eigenvalues.data(), eigenvectors.data(), &ldz, work.data(), - &lwork, rwork.data(), iwork.data(), ifail.data(), &info); + HeevxFuncs::heevx(&AerBlas::Jobz[0], &AerBlas::Range[0], &AerBlas::UpLo[0], + &n, heevx_copy.data(), &lda, &vl, &vu, &il, &iu, &abstol, + &m, eigenvalues.data(), eigenvectors.data(), &ldz, + work.data(), &lwork, rwork.data(), iwork.data(), + ifail.data(), &info); - if(info){ - throw std::runtime_error("Something went wrong in heevx call within eigensystem_hermitian funcion. " - "Check that input matrix is really hermitian"); + if (info) { + throw std::runtime_error("Something went wrong in heevx call within " + "eigensystem_hermitian funcion. " + "Check that input matrix is really hermitian"); } } diff --git a/src/framework/linalg/linops/linops_aer_vector.hpp b/src/framework/linalg/linops/linops_aer_vector.hpp old mode 100755 new mode 100644 index ba6ebc190f..708d04cfae --- a/src/framework/linalg/linops/linops_aer_vector.hpp +++ b/src/framework/linalg/linops/linops_aer_vector.hpp @@ -31,23 +31,23 @@ namespace Linalg { // Linear operations //---------------------------------------------------------------------------- template > -Vector add(const Vector& lhs, const Vector& rhs) { +Vector add(const Vector &lhs, const Vector &rhs) { return lhs + rhs; } template > -Vector& iadd(Vector& lhs, const Vector& rhs) { +Vector &iadd(Vector &lhs, const Vector &rhs) { lhs += rhs; return lhs; } template > -Vector sub(const Vector& lhs, const Vector& rhs) { +Vector sub(const Vector &lhs, const Vector &rhs) { return lhs - rhs; } template > -Vector& isub(Vector& lhs, const Vector& rhs) { +Vector &isub(Vector &lhs, const Vector &rhs) { lhs -= rhs; return lhs; } @@ -57,30 +57,29 @@ Vector& isub(Vector& lhs, const Vector& rhs) { //---------------------------------------------------------------------------- template , typename = enable_if_numeric_t> -Vector& iadd(Vector& data, const Scalar& val) { +Vector &iadd(Vector &data, const Scalar &val) { const T cast_val(val); std::for_each(data.data(), data.data() + data.size(), - [&cast_val](T& a)->T{ a += cast_val; }); + [&cast_val](T &a) -> T { a += cast_val; }); return data; } template , typename = enable_if_numeric_t> -Vector add(const Vector& data, const Scalar& val) { +Vector add(const Vector &data, const Scalar &val) { auto ret = data; return iadd(data, val); } - template , typename = enable_if_numeric_t> -Vector sub(const Vector& data, const Scalar& val) { +Vector sub(const Vector &data, const Scalar &val) { return add(data, -val); } template , typename = enable_if_numeric_t> -Vector& isub(Vector& data, const Scalar& val) { +Vector &isub(Vector &data, const Scalar &val) { return iadd(data, -val); } @@ -89,7 +88,7 @@ Vector& isub(Vector& data, const Scalar& val) { //---------------------------------------------------------------------------- template , typename = enable_if_numeric_t> -Vector& imul(Vector& data, const Scalar& val) { +Vector &imul(Vector &data, const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -99,14 +98,14 @@ Vector& imul(Vector& data, const Scalar& val) { template , typename = enable_if_numeric_t> -Vector mul(const Vector& data, const Scalar& val) { +Vector mul(const Vector &data, const Scalar &val) { auto ret = data; return imul(ret, val); } template , typename = enable_if_numeric_t> -Vector& idiv(Vector& data, const Scalar& val) { +Vector &idiv(Vector &data, const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -114,17 +113,16 @@ Vector& idiv(Vector& data, const Scalar& val) { return data; } - template , typename = enable_if_numeric_t> -Vector div(const Vector& data, const Scalar& val) { +Vector div(const Vector &data, const Scalar &val) { auto ret = data; return idiv(ret, val); } //------------------------------------------------------------------------------ -} // end namespace Linalg +} // end namespace Linalg //------------------------------------------------------------------------------ -} // end namespace AER +} // end namespace AER //------------------------------------------------------------------------------ #endif \ No newline at end of file diff --git a/src/framework/linalg/linops/linops_array.hpp b/src/framework/linalg/linops/linops_array.hpp old mode 100755 new mode 100644 index 1211cb7dbe..4c1df3bac0 --- a/src/framework/linalg/linops/linops_array.hpp +++ b/src/framework/linalg/linops/linops_array.hpp @@ -31,27 +31,27 @@ namespace Linalg { // Linear operations //---------------------------------------------------------------------------- template > -std::array& iadd(std::array& lhs, const std::array& rhs) { +std::array &iadd(std::array &lhs, const std::array &rhs) { std::transform(lhs.begin(), lhs.end(), rhs.begin(), lhs.begin(), std::plus()); return lhs; } template > -std::array add(const std::array& lhs, const std::array& rhs) { +std::array add(const std::array &lhs, const std::array &rhs) { std::array result = lhs; return iadd(result, rhs); } template > -std::array& isub(std::array& lhs, const std::array& rhs) { +std::array &isub(std::array &lhs, const std::array &rhs) { std::transform(lhs.begin(), lhs.end(), rhs.begin(), lhs.begin(), std::minus()); return lhs; } template > -std::array sub(const std::array& lhs, const std::array& rhs) { +std::array sub(const std::array &lhs, const std::array &rhs) { std::array result = lhs; return isub(result, rhs); } @@ -61,7 +61,7 @@ std::array sub(const std::array& lhs, const std::array& rhs) { //---------------------------------------------------------------------------- template , typename = enable_if_numeric_t> -std::array& iadd(std::array& data, const Scalar& val) { +std::array &iadd(std::array &data, const Scalar &val) { std::transform(data.begin(), data.end(), data.begin(), std::bind(std::plus(), std::placeholders::_1, val)); return data; @@ -69,14 +69,14 @@ std::array& iadd(std::array& data, const Scalar& val) { template , typename = enable_if_numeric_t> -std::array add(const std::array& data, const Scalar& val) { +std::array add(const std::array &data, const Scalar &val) { std::array result = data; return iadd(result, val); } template , typename = enable_if_numeric_t> -std::array& isub(std::array& data, const Scalar& val) { +std::array &isub(std::array &data, const Scalar &val) { std::transform(data.begin(), data.end(), data.begin(), std::bind(std::minus(), std::placeholders::_1, val)); return data; @@ -84,7 +84,7 @@ std::array& isub(std::array& data, const Scalar& val) { template , typename = enable_if_numeric_t> -std::array sub(const std::array& data, const Scalar& val) { +std::array sub(const std::array &data, const Scalar &val) { std::array result = data; return isub(result, val); } @@ -94,7 +94,7 @@ std::array sub(const std::array& data, const Scalar& val) { //---------------------------------------------------------------------------- template , typename = enable_if_numeric_t> -std::array& imul(std::array& data, const Scalar& val) { +std::array &imul(std::array &data, const Scalar &val) { std::transform(data.begin(), data.end(), data.begin(), std::bind(std::multiplies(), std::placeholders::_1, val)); return data; @@ -102,14 +102,14 @@ std::array& imul(std::array& data, const Scalar& val) { template , typename = enable_if_numeric_t> -std::array mul(const std::array& data, const Scalar& val) { +std::array mul(const std::array &data, const Scalar &val) { std::array result = data; return imul(result, val); } template , typename = enable_if_numeric_t> -std::array& idiv(std::array& data, const Scalar& val) { +std::array &idiv(std::array &data, const Scalar &val) { std::transform(data.begin(), data.end(), data.begin(), std::bind(std::divides(), std::placeholders::_1, val)); return data; @@ -117,14 +117,14 @@ std::array& idiv(std::array& data, const Scalar& val) { template , typename = enable_if_numeric_t> -std::array div(const std::array& data, const Scalar& val) { +std::array div(const std::array &data, const Scalar &val) { std::array result = data; return idiv(result, val); } //------------------------------------------------------------------------------ -} // end namespace Linalg +} // end namespace Linalg //------------------------------------------------------------------------------ -} // end namespace AER +} // end namespace AER //------------------------------------------------------------------------------ #endif \ No newline at end of file diff --git a/src/framework/linalg/linops/linops_generic.hpp b/src/framework/linalg/linops/linops_generic.hpp old mode 100755 new mode 100644 index f85b04e370..11ae56cd04 --- a/src/framework/linalg/linops/linops_generic.hpp +++ b/src/framework/linalg/linops/linops_generic.hpp @@ -30,23 +30,23 @@ namespace Linalg { // Linear operations //---------------------------------------------------------------------------- template -T add(const T& lhs, const T& rhs) { +T add(const T &lhs, const T &rhs) { return std::plus()(lhs, rhs); } template -T& iadd(T& lhs, const T& rhs) { +T &iadd(T &lhs, const T &rhs) { lhs = std::plus()(lhs, rhs); return lhs; } template -T sub(const T& lhs, const T& rhs) { +T sub(const T &lhs, const T &rhs) { return std::minus()(lhs, rhs); } template -T& isub(T& lhs, const T& rhs) { +T &isub(T &lhs, const T &rhs) { lhs = std::minus()(lhs, rhs); return lhs; } @@ -55,23 +55,23 @@ T& isub(T& lhs, const T& rhs) { // Affine operations //---------------------------------------------------------------------------- template > -T add(const T& data, const Scalar& val) { +T add(const T &data, const Scalar &val) { return std::plus()(data, val); } template > -T& iadd(T& data, const Scalar& val) { +T &iadd(T &data, const Scalar &val) { data = std::plus()(data, val); return data; } template > -T sub(const T& data, const Scalar& val) { +T sub(const T &data, const Scalar &val) { return std::minus()(data, val); } template > -T& isub(T& data, const Scalar& val) { +T &isub(T &data, const Scalar &val) { data = std::minus()(data, val); return data; } @@ -80,7 +80,7 @@ T& isub(T& data, const Scalar& val) { // Scalar operations //---------------------------------------------------------------------------- template > -T mul(const T& data, const Scalar& val) { +T mul(const T &data, const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -88,7 +88,7 @@ T mul(const T& data, const Scalar& val) { } template > -T& imul(T& data, const Scalar& val) { +T &imul(T &data, const Scalar &val) { if (!almost_equal(val, 1)) { data = std::multiplies()(data, val); } @@ -96,7 +96,7 @@ T& imul(T& data, const Scalar& val) { } template > -T div(const T& data, const Scalar& val) { +T div(const T &data, const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -104,7 +104,7 @@ T div(const T& data, const Scalar& val) { } template > -T& idiv(T& data, const Scalar& val) { +T &idiv(T &data, const Scalar &val) { if (!almost_equal(val, 1)) { data = std::divides()(data, val); } @@ -112,8 +112,8 @@ T& idiv(T& data, const Scalar& val) { } //------------------------------------------------------------------------------ -} // end namespace Linalg +} // end namespace Linalg //------------------------------------------------------------------------------ -} // end namespace AER +} // end namespace AER //------------------------------------------------------------------------------ #endif \ No newline at end of file diff --git a/src/framework/linalg/linops/linops_json.hpp b/src/framework/linalg/linops/linops_json.hpp old mode 100755 new mode 100644 index 8473bfbb82..1d8adb3a6b --- a/src/framework/linalg/linops/linops_json.hpp +++ b/src/framework/linalg/linops/linops_json.hpp @@ -28,7 +28,7 @@ namespace Linalg { //---------------------------------------------------------------------------- // Linear operations //---------------------------------------------------------------------------- -inline json_t& iadd(json_t& lhs, const json_t& rhs) { +inline json_t &iadd(json_t &lhs, const json_t &rhs) { // Null case if (lhs.is_null()) { lhs = rhs; @@ -57,12 +57,12 @@ inline json_t& iadd(json_t& lhs, const json_t& rhs) { return lhs; } -inline json_t add(const json_t& lhs, const json_t& rhs) { +inline json_t add(const json_t &lhs, const json_t &rhs) { json_t result = lhs; return iadd(result, rhs); } -inline json_t& isub(json_t& lhs, const json_t& rhs) { +inline json_t &isub(json_t &lhs, const json_t &rhs) { // Null case if (rhs.is_null()) { return lhs; @@ -88,7 +88,7 @@ inline json_t& isub(json_t& lhs, const json_t& rhs) { } template -json_t sub(const T& lhs, const json_t& rhs) { +json_t sub(const T &lhs, const json_t &rhs) { json_t result = lhs; return isub(result, rhs); } @@ -97,7 +97,7 @@ json_t sub(const T& lhs, const json_t& rhs) { // Affine operations //---------------------------------------------------------------------------- template > -json_t& iadd(json_t& data, const Scalar& val) { +json_t &iadd(json_t &data, const Scalar &val) { // Null case if (val == 0) { return data; @@ -123,13 +123,13 @@ json_t& iadd(json_t& data, const Scalar& val) { } template > -json_t add(const json_t& data, const Scalar& val) { +json_t add(const json_t &data, const Scalar &val) { json_t result = data; return iadd(result, val); } template > -json_t& isub(json_t& data, const Scalar& val) { +json_t &isub(json_t &data, const Scalar &val) { // Null case if (val == 0) { return data; @@ -156,7 +156,7 @@ json_t& isub(json_t& data, const Scalar& val) { } template > -json_t sub(const json_t& data, const Scalar& val) { +json_t sub(const json_t &data, const Scalar &val) { json_t result = data; return isub(result, val); } @@ -166,7 +166,7 @@ json_t sub(const json_t& data, const Scalar& val) { //---------------------------------------------------------------------------- template > -json_t& imul(json_t& data, const Scalar& val) { +json_t &imul(json_t &data, const Scalar &val) { // Trival case if (almost_equal(val, 1)) { return data; @@ -194,14 +194,14 @@ json_t& imul(json_t& data, const Scalar& val) { } template > -json_t mul(const json_t& data, const Scalar& val) { +json_t mul(const json_t &data, const Scalar &val) { // Null case json_t result = data; return imul(result, val); } template > -json_t& idiv(json_t& data, const Scalar& val) { +json_t &idiv(json_t &data, const Scalar &val) { // Trival case if (almost_equal(val, 1)) { return data; @@ -228,15 +228,15 @@ json_t& idiv(json_t& data, const Scalar& val) { } template > -json_t div(const json_t& data, const Scalar& val) { +json_t div(const json_t &data, const Scalar &val) { // Null case json_t result = data; return idiv(result, val); } //------------------------------------------------------------------------------ -} // end namespace Linalg +} // end namespace Linalg //------------------------------------------------------------------------------ -} // end namespace AER +} // end namespace AER //------------------------------------------------------------------------------ #endif \ No newline at end of file diff --git a/src/framework/linalg/linops/linops_map.hpp b/src/framework/linalg/linops/linops_map.hpp old mode 100755 new mode 100644 index f42cb80c6c..f69c8a675d --- a/src/framework/linalg/linops/linops_map.hpp +++ b/src/framework/linalg/linops/linops_map.hpp @@ -15,10 +15,10 @@ #ifndef _aer_framework_linalg_linops_map_hpp_ #define _aer_framework_linalg_linops_map_hpp_ -#include -#include #include "framework/linalg/almost_equal.hpp" #include "framework/linalg/enable_if_numeric.hpp" +#include +#include namespace AER { namespace Linalg { @@ -31,8 +31,8 @@ namespace Linalg { //---------------------------------------------------------------------------- template > -std::map add(const std::map& lhs, - const std::map& rhs) { +std::map add(const std::map &lhs, + const std::map &rhs) { std::map result = lhs; for (const auto &pair : rhs) { result[pair.first] = std::plus()(result[pair.first], pair.second); @@ -42,8 +42,8 @@ std::map add(const std::map& lhs, template > -std::map& iadd(std::map& lhs, - const std::map& rhs) { +std::map &iadd(std::map &lhs, + const std::map &rhs) { for (const auto &pair : rhs) { lhs[pair.first] = std::plus()(lhs[pair.first], pair.second); } @@ -52,8 +52,8 @@ std::map& iadd(std::map& lhs, template > -std::map sub(const std::map& lhs, - const std::map& rhs) { +std::map sub(const std::map &lhs, + const std::map &rhs) { std::map result = lhs; for (const auto &pair : rhs) { result[pair.first] = std::minus()(result[pair.first], pair.second); @@ -63,8 +63,8 @@ std::map sub(const std::map& lhs, template > -std::map& isub(std::map& lhs, - const std::map& rhs) { +std::map &isub(std::map &lhs, + const std::map &rhs) { for (const auto &pair : rhs) { lhs[pair.first] = std::minus()(lhs[pair.first], pair.second); } @@ -77,8 +77,8 @@ std::map& isub(std::map& lhs, template , typename = enable_if_numeric_t> -std::map add(const std::map& data, - const Scalar& val) { +std::map add(const std::map &data, + const Scalar &val) { std::map result; for (const auto &pair : data) { result[pair.first] = std::plus()(pair.second, val); @@ -89,8 +89,8 @@ std::map add(const std::map& data, template , typename = enable_if_numeric_t> -std::map& iadd(std::map& data, - const Scalar& val) { +std::map &iadd(std::map &data, + const Scalar &val) { for (const auto &pair : data) { data[pair.first] = std::plus()(data[pair.first], val); } @@ -100,8 +100,8 @@ std::map& iadd(std::map& data, template , typename = enable_if_numeric_t> -std::map sub(const std::map& data, - const Scalar& val) { +std::map sub(const std::map &data, + const Scalar &val) { std::map result; for (const auto &pair : data) { result[pair.first] = std::minus()(pair.second, val); @@ -112,8 +112,8 @@ std::map sub(const std::map& data, template , typename = enable_if_numeric_t> -std::map& isub(std::map& data, - const Scalar& val) { +std::map &isub(std::map &data, + const Scalar &val) { for (const auto &pair : data) { data[pair.first] = std::plus()(data[pair.first], val); } @@ -127,8 +127,8 @@ std::map& isub(std::map& data, template , typename = enable_if_numeric_t> -std::map mul(const std::map& data, - const Scalar& val) { +std::map mul(const std::map &data, + const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -142,8 +142,8 @@ std::map mul(const std::map& data, template , typename = enable_if_numeric_t> -std::map& imul(std::map& data, - const Scalar& val) { +std::map &imul(std::map &data, + const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -156,8 +156,8 @@ std::map& imul(std::map& data, template , typename = enable_if_numeric_t> -std::map div(const std::map& data, - const Scalar& val) { +std::map div(const std::map &data, + const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -171,8 +171,8 @@ std::map div(const std::map& data, template , typename = enable_if_numeric_t> -std::map& idiv(std::map& data, - const Scalar& val) { +std::map &idiv(std::map &data, + const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -183,8 +183,8 @@ std::map& idiv(std::map& data, } //------------------------------------------------------------------------------ -} // end namespace Linalg +} // end namespace Linalg //------------------------------------------------------------------------------ -} // end namespace AER +} // end namespace AER //------------------------------------------------------------------------------ #endif \ No newline at end of file diff --git a/src/framework/linalg/linops/linops_matrix.hpp b/src/framework/linalg/linops/linops_matrix.hpp old mode 100755 new mode 100644 index 4b510389c3..7fdac60fd7 --- a/src/framework/linalg/linops/linops_matrix.hpp +++ b/src/framework/linalg/linops/linops_matrix.hpp @@ -31,23 +31,23 @@ namespace Linalg { // Linear operations //---------------------------------------------------------------------------- template > -matrix add(const matrix& lhs, const matrix& rhs) { +matrix add(const matrix &lhs, const matrix &rhs) { return lhs + rhs; } template > -matrix& iadd(matrix& lhs, const matrix& rhs) { +matrix &iadd(matrix &lhs, const matrix &rhs) { lhs = lhs + rhs; return lhs; } template > -matrix sub(const matrix& lhs, const matrix& rhs) { +matrix sub(const matrix &lhs, const matrix &rhs) { return lhs - rhs; } template > -matrix& isub(matrix& lhs, const matrix& rhs) { +matrix &isub(matrix &lhs, const matrix &rhs) { lhs = lhs - rhs; return lhs; } @@ -57,7 +57,7 @@ matrix& isub(matrix& lhs, const matrix& rhs) { //---------------------------------------------------------------------------- template , typename = enable_if_numeric_t> -matrix& iadd(matrix& data, const Scalar& val) { +matrix &iadd(matrix &data, const Scalar &val) { if (val == 0) { return data; } @@ -69,20 +69,20 @@ matrix& iadd(matrix& data, const Scalar& val) { template , typename = enable_if_numeric_t> -matrix add(const matrix& data, const Scalar& val) { +matrix add(const matrix &data, const Scalar &val) { matrix result(data); return iadd(result, val); } template , typename = enable_if_numeric_t> -matrix sub(const matrix& data, const Scalar& val) { +matrix sub(const matrix &data, const Scalar &val) { return add(data, -val); } template , typename = enable_if_numeric_t> -matrix& isub(matrix& data, const Scalar& val) { +matrix &isub(matrix &data, const Scalar &val) { return iadd(data, -val); } @@ -92,7 +92,7 @@ matrix& isub(matrix& data, const Scalar& val) { template , typename = enable_if_numeric_t> -matrix& imul(matrix& data, const Scalar& val) { +matrix &imul(matrix &data, const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -104,7 +104,7 @@ matrix& imul(matrix& data, const Scalar& val) { template , typename = enable_if_numeric_t> -matrix mul(const matrix& data, const Scalar& val) { +matrix mul(const matrix &data, const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -115,7 +115,7 @@ matrix mul(const matrix& data, const Scalar& val) { template , typename = enable_if_numeric_t> -matrix& idiv(matrix& data, const Scalar& val) { +matrix &idiv(matrix &data, const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -127,7 +127,7 @@ matrix& idiv(matrix& data, const Scalar& val) { template , typename = enable_if_numeric_t> -matrix div(const matrix& data, const Scalar& val) { +matrix div(const matrix &data, const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -137,8 +137,8 @@ matrix div(const matrix& data, const Scalar& val) { } //------------------------------------------------------------------------------ -} // end namespace Linalg +} // end namespace Linalg //------------------------------------------------------------------------------ -} // end namespace AER +} // end namespace AER //------------------------------------------------------------------------------ #endif \ No newline at end of file diff --git a/src/framework/linalg/linops/linops_unordered_map.hpp b/src/framework/linalg/linops/linops_unordered_map.hpp old mode 100755 new mode 100644 index 7df754b5de..2245172f0c --- a/src/framework/linalg/linops/linops_unordered_map.hpp +++ b/src/framework/linalg/linops/linops_unordered_map.hpp @@ -31,9 +31,9 @@ namespace Linalg { //---------------------------------------------------------------------------- template > -std::unordered_map add( - const std::unordered_map& lhs, - const std::unordered_map& rhs) { +std::unordered_map +add(const std::unordered_map &lhs, + const std::unordered_map &rhs) { std::unordered_map result = lhs; for (const auto &pair : rhs) { result[pair.first] = std::plus()(result[pair.first], pair.second); @@ -43,9 +43,9 @@ std::unordered_map add( template > -std::unordered_map& iadd( - std::unordered_map& lhs, - const std::unordered_map& rhs) { +std::unordered_map & +iadd(std::unordered_map &lhs, + const std::unordered_map &rhs) { for (const auto &pair : rhs) { lhs[pair.first] = std::plus()(lhs[pair.first], pair.second); } @@ -54,9 +54,9 @@ std::unordered_map& iadd( template > -std::unordered_map sub( - const std::unordered_map& lhs, - const std::unordered_map& rhs) { +std::unordered_map +sub(const std::unordered_map &lhs, + const std::unordered_map &rhs) { std::unordered_map result = lhs; for (const auto &pair : rhs) { result[pair.first] = std::minus()(result[pair.first], pair.second); @@ -66,9 +66,9 @@ std::unordered_map sub( template > -std::unordered_map& isub( - std::unordered_map& lhs, - const std::unordered_map& rhs) { +std::unordered_map & +isub(std::unordered_map &lhs, + const std::unordered_map &rhs) { for (const auto &pair : rhs) { lhs[pair.first] = std::minus()(lhs[pair.first], pair.second); } @@ -81,8 +81,8 @@ std::unordered_map& isub( template , typename = enable_if_numeric_t> -std::unordered_map add( - const std::unordered_map& data, const Scalar& val) { +std::unordered_map +add(const std::unordered_map &data, const Scalar &val) { std::unordered_map result; for (const auto &pair : data) { result[pair.first] = std::plus()(pair.second, val); @@ -93,8 +93,8 @@ std::unordered_map add( template , typename = enable_if_numeric_t> -std::unordered_map& iadd( - std::unordered_map& data, const Scalar& val) { +std::unordered_map & +iadd(std::unordered_map &data, const Scalar &val) { for (const auto &pair : data) { data[pair.first] = std::plus()(data[pair.first], val); } @@ -104,8 +104,8 @@ std::unordered_map& iadd( template , typename = enable_if_numeric_t> -std::unordered_map sub( - const std::unordered_map& data, const Scalar& val) { +std::unordered_map +sub(const std::unordered_map &data, const Scalar &val) { std::unordered_map result; for (const auto &pair : data) { result[pair.first] = std::minus()(pair.second, val); @@ -116,8 +116,8 @@ std::unordered_map sub( template , typename = enable_if_numeric_t> -std::unordered_map& isub( - std::unordered_map& data, const Scalar& val) { +std::unordered_map & +isub(std::unordered_map &data, const Scalar &val) { for (const auto &pair : data) { data[pair.first] = std::plus()(data[pair.first], val); } @@ -131,8 +131,8 @@ std::unordered_map& isub( template , typename = enable_if_numeric_t> -std::unordered_map mul( - const std::unordered_map& data, const Scalar& val) { +std::unordered_map +mul(const std::unordered_map &data, const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -146,8 +146,8 @@ std::unordered_map mul( template , typename = enable_if_numeric_t> -std::unordered_map& imul( - std::unordered_map& data, const Scalar& val) { +std::unordered_map & +imul(std::unordered_map &data, const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -160,8 +160,8 @@ std::unordered_map& imul( template , typename = enable_if_numeric_t> -std::unordered_map div( - const std::unordered_map& data, const Scalar& val) { +std::unordered_map +div(const std::unordered_map &data, const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -175,8 +175,8 @@ std::unordered_map div( template , typename = enable_if_numeric_t> -std::unordered_map& idiv( - std::unordered_map& data, const Scalar& val) { +std::unordered_map & +idiv(std::unordered_map &data, const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -187,8 +187,8 @@ std::unordered_map& idiv( } //------------------------------------------------------------------------------ -} // end namespace Linalg +} // end namespace Linalg //------------------------------------------------------------------------------ -} // end namespace AER +} // end namespace AER //------------------------------------------------------------------------------ #endif \ No newline at end of file diff --git a/src/framework/linalg/linops/linops_vector.hpp b/src/framework/linalg/linops/linops_vector.hpp old mode 100755 new mode 100644 index 759442d9f4..c1b86d79d8 --- a/src/framework/linalg/linops/linops_vector.hpp +++ b/src/framework/linalg/linops/linops_vector.hpp @@ -31,7 +31,7 @@ namespace Linalg { // Linear operations //---------------------------------------------------------------------------- template > -std::vector add(const std::vector& lhs, const std::vector& rhs) { +std::vector add(const std::vector &lhs, const std::vector &rhs) { if (lhs.size() != rhs.size()) { throw std::runtime_error("Cannot add two vectors of different sizes."); } @@ -43,7 +43,7 @@ std::vector add(const std::vector& lhs, const std::vector& rhs) { } template > -std::vector& iadd(std::vector& lhs, const std::vector& rhs) { +std::vector &iadd(std::vector &lhs, const std::vector &rhs) { if (lhs.size() != rhs.size()) { throw std::runtime_error("Cannot add two vectors of different sizes."); } @@ -53,7 +53,7 @@ std::vector& iadd(std::vector& lhs, const std::vector& rhs) { } template > -std::vector sub(const std::vector& lhs, const std::vector& rhs) { +std::vector sub(const std::vector &lhs, const std::vector &rhs) { if (lhs.size() != rhs.size()) { throw std::runtime_error("Cannot add two vectors of different sizes."); } @@ -65,7 +65,7 @@ std::vector sub(const std::vector& lhs, const std::vector& rhs) { } template > -std::vector& isub(std::vector& lhs, const std::vector& rhs) { +std::vector &isub(std::vector &lhs, const std::vector &rhs) { if (lhs.size() != rhs.size()) { throw std::runtime_error("Cannot add two vectors of different sizes."); } @@ -79,7 +79,7 @@ std::vector& isub(std::vector& lhs, const std::vector& rhs) { //---------------------------------------------------------------------------- template , typename = enable_if_numeric_t> -std::vector add(const std::vector& data, const Scalar& val) { +std::vector add(const std::vector &data, const Scalar &val) { std::vector result; result.reserve(data.size()); std::transform(data.begin(), data.end(), std::back_inserter(result), @@ -89,7 +89,7 @@ std::vector add(const std::vector& data, const Scalar& val) { template , typename = enable_if_numeric_t> -std::vector& iadd(std::vector& data, const Scalar& val) { +std::vector &iadd(std::vector &data, const Scalar &val) { std::transform(data.begin(), data.end(), data.begin(), std::bind(std::plus(), std::placeholders::_1, val)); return data; @@ -97,7 +97,7 @@ std::vector& iadd(std::vector& data, const Scalar& val) { template , typename = enable_if_numeric_t> -std::vector sub(const std::vector& data, const Scalar& val) { +std::vector sub(const std::vector &data, const Scalar &val) { std::vector result; result.reserve(data.size()); std::transform(data.begin(), data.end(), std::back_inserter(result), @@ -107,7 +107,7 @@ std::vector sub(const std::vector& data, const Scalar& val) { template , typename = enable_if_numeric_t> -std::vector& isub(std::vector& data, const Scalar& val) { +std::vector &isub(std::vector &data, const Scalar &val) { std::transform(data.begin(), data.end(), data.begin(), std::bind(std::minus(), std::placeholders::_1, val)); return data; @@ -118,7 +118,7 @@ std::vector& isub(std::vector& data, const Scalar& val) { //---------------------------------------------------------------------------- template , typename = enable_if_numeric_t> -std::vector mul(const std::vector& data, const Scalar& val) { +std::vector mul(const std::vector &data, const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -131,7 +131,7 @@ std::vector mul(const std::vector& data, const Scalar& val) { template , typename = enable_if_numeric_t> -std::vector& imul(std::vector& data, const Scalar& val) { +std::vector &imul(std::vector &data, const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -142,7 +142,7 @@ std::vector& imul(std::vector& data, const Scalar& val) { template , typename = enable_if_numeric_t> -std::vector div(const std::vector& data, const Scalar& val) { +std::vector div(const std::vector &data, const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -155,7 +155,7 @@ std::vector div(const std::vector& data, const Scalar& val) { template , typename = enable_if_numeric_t> -std::vector& idiv(std::vector& data, const Scalar& val) { +std::vector &idiv(std::vector &data, const Scalar &val) { if (almost_equal(val, 1)) { return data; } @@ -165,8 +165,8 @@ std::vector& idiv(std::vector& data, const Scalar& val) { } //------------------------------------------------------------------------------ -} // end namespace Linalg +} // end namespace Linalg //------------------------------------------------------------------------------ -} // end namespace AER +} // end namespace AER //------------------------------------------------------------------------------ #endif \ No newline at end of file diff --git a/src/framework/linalg/matrix_utils.hpp b/src/framework/linalg/matrix_utils.hpp old mode 100755 new mode 100644 index bd6903dde4..d557abd898 --- a/src/framework/linalg/matrix_utils.hpp +++ b/src/framework/linalg/matrix_utils.hpp @@ -16,7 +16,7 @@ #define _aer_framework_linalg_matrix_utils_hpp_ #include "framework/linalg/matrix_utils/matrix_defs.hpp" -#include "framework/linalg/matrix_utils/vmatrix_defs.hpp" #include "framework/linalg/matrix_utils/smatrix_defs.hpp" +#include "framework/linalg/matrix_utils/vmatrix_defs.hpp" #endif \ No newline at end of file diff --git a/src/framework/linalg/matrix_utils/matrix_defs.hpp b/src/framework/linalg/matrix_utils/matrix_defs.hpp old mode 100755 new mode 100644 index 9e82e9dd4d..db67b95163 --- a/src/framework/linalg/matrix_utils/matrix_defs.hpp +++ b/src/framework/linalg/matrix_utils/matrix_defs.hpp @@ -33,18 +33,18 @@ namespace Linalg { class Matrix { public: // Single-qubit gates - const static cmatrix_t I; // name: "id" - const static cmatrix_t X; // name: "x" - const static cmatrix_t Y; // name: "y" - const static cmatrix_t Z; // name: "z" - const static cmatrix_t H; // name: "h" - const static cmatrix_t S; // name: "s" - const static cmatrix_t SDG; // name: "sdg" - const static cmatrix_t T; // name: "t" - const static cmatrix_t TDG; // name: "tdg" - const static cmatrix_t SX; // name: "sx" - const static cmatrix_t SXDG;// name: "sxdg" - const static cmatrix_t X90; // name: "x90" + const static cmatrix_t I; // name: "id" + const static cmatrix_t X; // name: "x" + const static cmatrix_t Y; // name: "y" + const static cmatrix_t Z; // name: "z" + const static cmatrix_t H; // name: "h" + const static cmatrix_t S; // name: "s" + const static cmatrix_t SDG; // name: "sdg" + const static cmatrix_t T; // name: "t" + const static cmatrix_t TDG; // name: "tdg" + const static cmatrix_t SX; // name: "sx" + const static cmatrix_t SXDG; // name: "sxdg" + const static cmatrix_t X90; // name: "x90" // Two-qubit gates const static cmatrix_t CX; // name: "cx" @@ -92,8 +92,10 @@ class Matrix { static cmatrix_t u3(complex_t theta, complex_t phi, complex_t lam) { return u3(std::real(theta), std::real(phi), std::real(lam)); }; - static cmatrix_t u4(complex_t theta, complex_t phi, complex_t lam, complex_t gamma) { - return u4(std::real(theta), std::real(phi), std::real(lam), std::real(gamma)); + static cmatrix_t u4(complex_t theta, complex_t phi, complex_t lam, + complex_t gamma) { + return u4(std::real(theta), std::real(phi), std::real(lam), + std::real(gamma)); }; static cmatrix_t r(complex_t theta, complex_t phi) { return r(std::real(theta), std::real(phi)); @@ -106,11 +108,17 @@ class Matrix { static cmatrix_t rzz(complex_t theta) { return rzz(std::real(theta)); } static cmatrix_t rzx(complex_t theta) { return rzx(std::real(theta)); } static cmatrix_t phase(complex_t theta) { return phase(std::real(theta)); } - static cmatrix_t phase_diag(complex_t theta) { return phase_diag(std::real(theta)); } + static cmatrix_t phase_diag(complex_t theta) { + return phase_diag(std::real(theta)); + } static cmatrix_t cphase(complex_t theta) { return cphase(std::real(theta)); } - static cmatrix_t cphase_diag(complex_t theta) { return cphase_diag(std::real(theta)); } - static cmatrix_t cu(complex_t theta, complex_t phi, complex_t lam, complex_t gamma) { - return cu(std::real(theta), std::real(phi), std::real(lam), std::real(gamma)); + static cmatrix_t cphase_diag(complex_t theta) { + return cphase_diag(std::real(theta)); + } + static cmatrix_t cu(complex_t theta, complex_t phi, complex_t lam, + complex_t gamma) { + return cu(std::real(theta), std::real(phi), std::real(lam), + std::real(gamma)); } // Return the matrix for a named matrix string @@ -183,7 +191,7 @@ const cmatrix_t Matrix::CY = {{0, 0}, {0, 0}, {0, 0}, {0, -1}}, {{0, 0}, {0, 0}, {1, 0}, {0, 0}}, {{0, 0}, {0, 1}, {0, 0}, {0, 0}}}); - + const cmatrix_t Matrix::CZ = Utils::make_matrix({{{1, 0}, {0, 0}, {0, 0}, {0, 0}}, {{0, 0}, {1, 0}, {0, 0}, {0, 0}}, @@ -196,20 +204,20 @@ const cmatrix_t Matrix::SWAP = {{0, 0}, {1, 0}, {0, 0}, {0, 0}}, {{0, 0}, {0, 0}, {0, 0}, {1, 0}}}); -const cmatrix_t Matrix::ECR = - Utils::make_matrix({{{0, 0}, {1. / std::sqrt(2.), 0}, {0, 0}, {0, 1. / std::sqrt(2.)}}, - {{1. / std::sqrt(2.), 0}, {0, 0}, {0, -1. / std::sqrt(2.)}, {0, 0}}, - {{0, 0}, {0, 1. / std::sqrt(2.)}, {0, 0}, {1. / std::sqrt(2.), 0}}, - {{0, -1. / std::sqrt(2.)}, {0, 0}, {1. / std::sqrt(2.), 0}, {0, 0}}}); +const cmatrix_t Matrix::ECR = Utils::make_matrix( + {{{0, 0}, {1. / std::sqrt(2.), 0}, {0, 0}, {0, 1. / std::sqrt(2.)}}, + {{1. / std::sqrt(2.), 0}, {0, 0}, {0, -1. / std::sqrt(2.)}, {0, 0}}, + {{0, 0}, {0, 1. / std::sqrt(2.)}, {0, 0}, {1. / std::sqrt(2.), 0}}, + {{0, -1. / std::sqrt(2.)}, {0, 0}, {1. / std::sqrt(2.), 0}, {0, 0}}}); // Lookup table const stringmap_t Matrix::label_map_ = { - {"id", &Matrix::I}, {"x", &Matrix::X}, {"y", &Matrix::Y}, - {"z", &Matrix::Z}, {"h", &Matrix::H}, {"s", &Matrix::S}, - {"sdg", &Matrix::SDG}, {"t", &Matrix::T}, {"tdg", &Matrix::TDG}, - {"x90", &Matrix::X90}, {"cx", &Matrix::CX}, {"cy", &Matrix::CY}, - {"cz", &Matrix::CZ}, {"swap", &Matrix::SWAP}, {"sx", &Matrix::SX}, - {"sxdg", &Matrix::SXDG}, {"delay", &Matrix::I}, {"ecr", &Matrix::ECR}}; + {"id", &Matrix::I}, {"x", &Matrix::X}, {"y", &Matrix::Y}, + {"z", &Matrix::Z}, {"h", &Matrix::H}, {"s", &Matrix::S}, + {"sdg", &Matrix::SDG}, {"t", &Matrix::T}, {"tdg", &Matrix::TDG}, + {"x90", &Matrix::X90}, {"cx", &Matrix::CX}, {"cy", &Matrix::CY}, + {"cz", &Matrix::CZ}, {"swap", &Matrix::SWAP}, {"sx", &Matrix::SX}, + {"sxdg", &Matrix::SXDG}, {"delay", &Matrix::I}, {"ecr", &Matrix::ECR}}; cmatrix_t Matrix::identity(size_t dim) { cmatrix_t mat(dim, dim); @@ -218,9 +226,7 @@ cmatrix_t Matrix::identity(size_t dim) { return mat; } -cmatrix_t Matrix::u1(double lambda) { - return phase(lambda); -} +cmatrix_t Matrix::u1(double lambda) { return phase(lambda); } cmatrix_t Matrix::u2(double phi, double lambda) { cmatrix_t mat(2, 2); diff --git a/src/framework/linalg/matrix_utils/smatrix_defs.hpp b/src/framework/linalg/matrix_utils/smatrix_defs.hpp old mode 100755 new mode 100644 index 83598fe21d..0ecaf1bde3 --- a/src/framework/linalg/matrix_utils/smatrix_defs.hpp +++ b/src/framework/linalg/matrix_utils/smatrix_defs.hpp @@ -34,18 +34,18 @@ namespace Linalg { class SMatrix { public: // Single-qubit gates - const static cmatrix_t I; // name: "id" - const static cmatrix_t X; // name: "x" - const static cmatrix_t Y; // name: "y" - const static cmatrix_t Z; // name: "z" - const static cmatrix_t H; // name: "h" - const static cmatrix_t S; // name: "s" - const static cmatrix_t SDG; // name: "sdg" - const static cmatrix_t T; // name: "t" - const static cmatrix_t TDG; // name: "tdg" - const static cmatrix_t SX; // name: "sx" - const static cmatrix_t SXDG;// name: "sxdg" - const static cmatrix_t X90; // name: "x90" + const static cmatrix_t I; // name: "id" + const static cmatrix_t X; // name: "x" + const static cmatrix_t Y; // name: "y" + const static cmatrix_t Z; // name: "z" + const static cmatrix_t H; // name: "h" + const static cmatrix_t S; // name: "s" + const static cmatrix_t SDG; // name: "sdg" + const static cmatrix_t T; // name: "t" + const static cmatrix_t TDG; // name: "tdg" + const static cmatrix_t SX; // name: "sx" + const static cmatrix_t SXDG; // name: "sxdg" + const static cmatrix_t X90; // name: "x90" // Two-qubit gates const static cmatrix_t CX; // name: "cx" @@ -93,8 +93,10 @@ class SMatrix { static cmatrix_t u3(complex_t theta, complex_t phi, complex_t lam) { return u3(std::real(theta), std::real(phi), std::real(lam)); }; - static cmatrix_t u4(complex_t theta, complex_t phi, complex_t lam, complex_t gamma) { - return u4(std::real(theta), std::real(phi), std::real(lam), std::real(gamma)); + static cmatrix_t u4(complex_t theta, complex_t phi, complex_t lam, + complex_t gamma) { + return u4(std::real(theta), std::real(phi), std::real(lam), + std::real(gamma)); } static cmatrix_t r(complex_t theta, complex_t phi) { return r(std::real(theta), std::real(phi)); @@ -107,11 +109,17 @@ class SMatrix { static cmatrix_t rzz(complex_t theta) { return rzz(std::real(theta)); } static cmatrix_t rzx(complex_t theta) { return rzx(std::real(theta)); } static cmatrix_t phase(complex_t theta) { return phase(std::real(theta)); } - static cmatrix_t phase_diag(complex_t theta) { return phase_diag(std::real(theta)); } + static cmatrix_t phase_diag(complex_t theta) { + return phase_diag(std::real(theta)); + } static cmatrix_t cphase(complex_t theta) { return cphase(std::real(theta)); } - static cmatrix_t cphase_diag(complex_t theta) { return cphase_diag(std::real(theta)); } - static cmatrix_t cu(complex_t theta, complex_t phi, complex_t lam, complex_t gamma) { - return cu(std::real(theta), std::real(phi), std::real(lam), std::real(gamma)); + static cmatrix_t cphase_diag(complex_t theta) { + return cphase_diag(std::real(theta)); + } + static cmatrix_t cu(complex_t theta, complex_t phi, complex_t lam, + complex_t gamma) { + return cu(std::real(theta), std::real(phi), std::real(lam), + std::real(gamma)); } // Return superoperator matrix for reset instruction @@ -174,22 +182,18 @@ const cmatrix_t SMatrix::SWAP = Utils::unitary_superop(Matrix::SWAP); const cmatrix_t SMatrix::ECR = Utils::unitary_superop(Matrix::ECR); - - // Lookup table const stringmap_t SMatrix::label_map_ = { - {"id", &SMatrix::I}, {"x", &SMatrix::X}, {"y", &SMatrix::Y}, - {"z", &SMatrix::Z}, {"h", &SMatrix::H}, {"s", &SMatrix::S}, - {"sdg", &SMatrix::SDG}, {"t", &SMatrix::T}, {"tdg", &SMatrix::TDG}, - {"x90", &SMatrix::X90}, {"cx", &SMatrix::CX}, {"cy", &SMatrix::CY}, - {"cz", &SMatrix::CZ}, {"swap", &SMatrix::SWAP}, {"sx", &SMatrix::SX}, - {"sxdg", &SMatrix::SXDG}, {"delay", &SMatrix::I}, {"ecr", &SMatrix::ECR}}; + {"id", &SMatrix::I}, {"x", &SMatrix::X}, {"y", &SMatrix::Y}, + {"z", &SMatrix::Z}, {"h", &SMatrix::H}, {"s", &SMatrix::S}, + {"sdg", &SMatrix::SDG}, {"t", &SMatrix::T}, {"tdg", &SMatrix::TDG}, + {"x90", &SMatrix::X90}, {"cx", &SMatrix::CX}, {"cy", &SMatrix::CY}, + {"cz", &SMatrix::CZ}, {"swap", &SMatrix::SWAP}, {"sx", &SMatrix::SX}, + {"sxdg", &SMatrix::SXDG}, {"delay", &SMatrix::I}, {"ecr", &SMatrix::ECR}}; cmatrix_t SMatrix::identity(size_t dim) { return Matrix::identity(dim * dim); } -cmatrix_t SMatrix::u1(double lambda) { - return phase(lambda); -} +cmatrix_t SMatrix::u1(double lambda) { return phase(lambda); } cmatrix_t SMatrix::u2(double phi, double lambda) { return Utils::tensor_product(Matrix::u2(-phi, -lambda), diff --git a/src/framework/linalg/matrix_utils/vmatrix_defs.hpp b/src/framework/linalg/matrix_utils/vmatrix_defs.hpp old mode 100755 new mode 100644 index 24248de12c..3c5c3ab513 --- a/src/framework/linalg/matrix_utils/vmatrix_defs.hpp +++ b/src/framework/linalg/matrix_utils/vmatrix_defs.hpp @@ -34,18 +34,18 @@ namespace Linalg { class VMatrix { public: // Single-qubit gates - const static cvector_t I; // name: "id" - const static cvector_t X; // name: "x" - const static cvector_t Y; // name: "y" - const static cvector_t Z; // name: "z" - const static cvector_t H; // name: "h" - const static cvector_t S; // name: "s" - const static cvector_t SDG; // name: "sdg" - const static cvector_t T; // name: "t" - const static cvector_t TDG; // name: "tdg" - const static cvector_t SX; // name: "sx" - const static cvector_t SXDG;// name: "sxdg" - const static cvector_t X90; // name: "x90" + const static cvector_t I; // name: "id" + const static cvector_t X; // name: "x" + const static cvector_t Y; // name: "y" + const static cvector_t Z; // name: "z" + const static cvector_t H; // name: "h" + const static cvector_t S; // name: "s" + const static cvector_t SDG; // name: "sdg" + const static cvector_t T; // name: "t" + const static cvector_t TDG; // name: "tdg" + const static cvector_t SX; // name: "sx" + const static cvector_t SXDG; // name: "sxdg" + const static cvector_t X90; // name: "x90" // Two-qubit gates const static cvector_t CX; // name: "cx" @@ -74,7 +74,7 @@ class VMatrix { static cvector_t rxx(double theta); static cvector_t ryy(double theta); static cvector_t rzz(double theta); - static cvector_t rzx(double theta); // rotation around Tensor(X, Z) + static cvector_t rzx(double theta); // rotation around Tensor(X, Z) static cvector_t rzz_diag(double theta); // return the matrix diagonal // Phase Gates @@ -95,8 +95,10 @@ class VMatrix { static cvector_t u3(complex_t theta, complex_t phi, complex_t lam) { return u3(std::real(theta), std::real(phi), std::real(lam)); }; - static cvector_t u4(complex_t theta, complex_t phi, complex_t lam, complex_t gamma) { - return u4(std::real(theta), std::real(phi), std::real(lam), std::real(gamma)); + static cvector_t u4(complex_t theta, complex_t phi, complex_t lam, + complex_t gamma) { + return u4(std::real(theta), std::real(phi), std::real(lam), + std::real(gamma)); }; static cvector_t r(complex_t theta, complex_t phi) { return r(std::real(theta), std::real(phi)); @@ -104,18 +106,28 @@ class VMatrix { static cvector_t rx(complex_t theta) { return rx(std::real(theta)); } static cvector_t ry(complex_t theta) { return ry(std::real(theta)); } static cvector_t rz(complex_t theta) { return rz(std::real(theta)); } - static cvector_t rz_diag(complex_t theta) { return rz_diag(std::real(theta)); } + static cvector_t rz_diag(complex_t theta) { + return rz_diag(std::real(theta)); + } static cvector_t rxx(complex_t theta) { return rxx(std::real(theta)); } static cvector_t ryy(complex_t theta) { return ryy(std::real(theta)); } static cvector_t rzz(complex_t theta) { return rzz(std::real(theta)); } - static cvector_t rzz_diag(complex_t theta) { return rzz_diag(std::real(theta)); } + static cvector_t rzz_diag(complex_t theta) { + return rzz_diag(std::real(theta)); + } static cvector_t rzx(complex_t theta) { return rzx(std::real(theta)); } static cvector_t phase(complex_t theta) { return phase(std::real(theta)); } - static cvector_t phase_diag(complex_t theta) { return phase_diag(std::real(theta)); } + static cvector_t phase_diag(complex_t theta) { + return phase_diag(std::real(theta)); + } static cvector_t cphase(complex_t theta) { return cphase(std::real(theta)); } - static cvector_t cphase_diag(complex_t theta) { return cphase_diag(std::real(theta)); } - static cvector_t cu(complex_t theta, complex_t phi, complex_t lam, complex_t gamma) { - return cu(std::real(theta), std::real(phi), std::real(lam), std::real(gamma)); + static cvector_t cphase_diag(complex_t theta) { + return cphase_diag(std::real(theta)); + } + static cvector_t cu(complex_t theta, complex_t phi, complex_t lam, + complex_t gamma) { + return cu(std::real(theta), std::real(phi), std::real(lam), + std::real(gamma)); } // Return the matrix for a named matrix string @@ -173,15 +185,14 @@ const cvector_t VMatrix::SWAP = Utils::vectorize_matrix(Matrix::SWAP); const cvector_t VMatrix::ECR = Utils::vectorize_matrix(Matrix::ECR); - // Lookup table const stringmap_t VMatrix::label_map_ = { - {"id", &VMatrix::I}, {"x", &VMatrix::X}, {"y", &VMatrix::Y}, - {"z", &VMatrix::Z}, {"h", &VMatrix::H}, {"s", &VMatrix::S}, - {"sdg", &VMatrix::SDG}, {"t", &VMatrix::T}, {"tdg", &VMatrix::TDG}, - {"x90", &VMatrix::X90}, {"cx", &VMatrix::CX}, {"cy", &VMatrix::CY}, - {"cz", &VMatrix::CZ}, {"swap", &VMatrix::SWAP}, {"sx", &VMatrix::SX}, - {"sxdg", &VMatrix::SXDG}, {"delay", &VMatrix::I}, {"ecr", &VMatrix::ECR}}; + {"id", &VMatrix::I}, {"x", &VMatrix::X}, {"y", &VMatrix::Y}, + {"z", &VMatrix::Z}, {"h", &VMatrix::H}, {"s", &VMatrix::S}, + {"sdg", &VMatrix::SDG}, {"t", &VMatrix::T}, {"tdg", &VMatrix::TDG}, + {"x90", &VMatrix::X90}, {"cx", &VMatrix::CX}, {"cy", &VMatrix::CY}, + {"cz", &VMatrix::CZ}, {"swap", &VMatrix::SWAP}, {"sx", &VMatrix::SX}, + {"sxdg", &VMatrix::SXDG}, {"delay", &VMatrix::I}, {"ecr", &VMatrix::ECR}}; cvector_t VMatrix::identity(size_t dim) { cvector_t mat(dim * dim); @@ -190,9 +201,7 @@ cvector_t VMatrix::identity(size_t dim) { return mat; } -cvector_t VMatrix::u1(double lambda) { - return phase(lambda); -} +cvector_t VMatrix::u1(double lambda) { return phase(lambda); } cvector_t VMatrix::u2(double phi, double lambda) { cvector_t mat(2 * 2); @@ -316,7 +325,7 @@ cvector_t VMatrix::rzz_diag(double theta) { const complex_t i(0., 1.); const complex_t exp_p = std::exp(i * 0.5 * theta); const complex_t exp_m = std::exp(-i * 0.5 * theta); - return cvector_t({exp_m, exp_p, exp_p, exp_m}); + return cvector_t({exp_m, exp_p, exp_p, exp_m}); } cvector_t VMatrix::rzx(double theta) { diff --git a/src/framework/linalg/square.hpp b/src/framework/linalg/square.hpp old mode 100755 new mode 100644 index 6baae7054f..4c2b28d180 --- a/src/framework/linalg/square.hpp +++ b/src/framework/linalg/square.hpp @@ -22,10 +22,10 @@ #include #include "framework/json.hpp" -#include "framework/matrix.hpp" +#include "framework/linalg/enable_if_numeric.hpp" #include "framework/linalg/vector.hpp" +#include "framework/matrix.hpp" #include "framework/types.hpp" -#include "framework/linalg/enable_if_numeric.hpp" namespace AER { namespace Linalg { @@ -39,14 +39,14 @@ namespace Linalg { // Return entrywise square of a vector template > -std::array square(const std::array& data) { +std::array square(const std::array &data) { std::array result = data; return isquare(result); } // Return inplace entrywise square of a vector template > -std::array& isquare(std::array& data) { +std::array &isquare(std::array &data) { std::transform(data.begin(), data.end(), data.begin(), data.begin(), std::multiplies()); return data; @@ -58,17 +58,17 @@ std::array& isquare(std::array& data) { // Return entrywise square of a vector template > -std::vector square(const std::vector& data) { +std::vector square(const std::vector &data) { std::vector result; result.reserve(data.size()); - std::transform(data.begin(), data.end(), data.begin(), std::back_inserter(result), - std::multiplies()); + std::transform(data.begin(), data.end(), data.begin(), + std::back_inserter(result), std::multiplies()); return result; } // Return inplace entrywise square of a vector template > -std::vector& isquare(std::vector& data) { +std::vector &isquare(std::vector &data) { std::transform(data.begin(), data.end(), data.begin(), data.begin(), std::multiplies()); return data; @@ -78,18 +78,20 @@ std::vector& isquare(std::vector& data) { // Entrywise square of std::map //---------------------------------------------------------------------------- -template > -std::map square(const std::map& data) { +template > +std::map square(const std::map &data) { std::map result; - for (const auto& pair : data) { + for (const auto &pair : data) { result[pair.first] = pair.second * pair.second; } return result; } -template > -std::map& isquare(std::map& data) { - for (auto& pair : data) { +template > +std::map &isquare(std::map &data) { + for (auto &pair : data) { pair.second *= pair.second; } return data; @@ -99,19 +101,22 @@ std::map& isquare(std::map& data) { // Entrywise square of std::unordered_map //---------------------------------------------------------------------------- -template > -std::unordered_map square( - const std::unordered_map& data) { +template > +std::unordered_map +square(const std::unordered_map &data) { std::unordered_map result; - for (const auto& pair : data) { + for (const auto &pair : data) { result[pair.first] = pair.second * pair.second; } return result; } -template > -std::unordered_map& isquare(std::unordered_map& data) { - for (auto& pair : data) { +template > +std::unordered_map & +isquare(std::unordered_map &data) { + for (auto &pair : data) { pair.second *= pair.second; } return data; @@ -122,7 +127,7 @@ std::unordered_map& isquare(std::unordered_map> -matrix& isquare(matrix& data) { +matrix &isquare(matrix &data) { for (size_t j = 0; j < data.size(); j++) { data[j] *= data[j]; } @@ -130,7 +135,7 @@ matrix& isquare(matrix& data) { } template > -matrix square(const matrix& data) { +matrix square(const matrix &data) { matrix result = data; return isquare(result); } @@ -140,16 +145,17 @@ matrix square(const matrix& data) { //---------------------------------------------------------------------------- template > -Vector& isquare(Vector& vec) { - std::for_each(vec.data(), vec.data() + vec.size(), [](T&val) { val *= val; }); +Vector &isquare(Vector &vec) { + std::for_each(vec.data(), vec.data() + vec.size(), + [](T &val) { val *= val; }); return vec; } template > -Vector square(const Vector& vec) { +Vector square(const Vector &vec) { Vector ret(vec.size(), false); std::transform(vec.data(), vec.data() + vec.size(), ret.data(), - [](const T&val) { return val * val; }); + [](const T &val) { return val * val; }); return ret; } @@ -157,7 +163,7 @@ Vector square(const Vector& vec) { // Entrywise square of JSON //---------------------------------------------------------------------------- -inline json_t& isquare(json_t& data) { +inline json_t &isquare(json_t &data) { // Terminating case if (data.is_number()) { double val = data; @@ -170,7 +176,7 @@ inline json_t& isquare(json_t& data) { isquare(data[pos]); } return data; - } + } if (data.is_object()) { for (auto it = data.begin(); it != data.end(); ++it) { isquare(data[it.key()]); @@ -180,7 +186,7 @@ inline json_t& isquare(json_t& data) { throw std::invalid_argument("Input JSONs cannot be squared."); } -inline json_t square(const json_t& data) { +inline json_t square(const json_t &data) { json_t result = data; return isquare(result); } @@ -190,19 +196,19 @@ inline json_t square(const json_t& data) { //---------------------------------------------------------------------------- template -T square(const T& data) { +T square(const T &data) { return data * data; } template -T& isquare(T& data) { +T &isquare(T &data) { data *= data; return data; } //------------------------------------------------------------------------------ -} // end namespace Linalg +} // end namespace Linalg //------------------------------------------------------------------------------ -} // end namespace AER +} // end namespace AER //------------------------------------------------------------------------------ #endif \ No newline at end of file diff --git a/src/framework/linalg/vector.hpp b/src/framework/linalg/vector.hpp old mode 100755 new mode 100644 index 6098943a52..985b64f5b3 --- a/src/framework/linalg/vector.hpp +++ b/src/framework/linalg/vector.hpp @@ -29,15 +29,18 @@ namespace AER { -template T *malloc_data(size_t size) { +template +T *malloc_data(size_t size) { return reinterpret_cast(malloc(sizeof(T) * size)); } -template T *calloc_data(size_t size) { +template +T *calloc_data(size_t size) { return reinterpret_cast(calloc(size, sizeof(T))); } -template class Vector { +template +class Vector { public: //----------------------------------------------------------------------- @@ -60,8 +63,7 @@ template class Vector { Vector(Vector &&other) noexcept; // Destructor - virtual ~Vector() { - free(data_); } + virtual ~Vector() { free(data_); } //----------------------------------------------------------------------- // Assignment @@ -74,7 +76,8 @@ template class Vector { Vector &operator=(Vector &&other) noexcept; // Copy and cast assignment - template Vector &operator=(const Vector &other); + template + Vector &operator=(const Vector &other); //----------------------------------------------------------------------- // Buffer conversion @@ -192,7 +195,8 @@ template class Vector { template Vector::Vector(size_t sz, bool fill) - : size_(sz), data_((fill) ? calloc_data(size_) : malloc_data(size_)) {} + : size_(sz), data_((fill) ? calloc_data(size_) : malloc_data(size_)) { +} template Vector::Vector(const Vector &other) @@ -211,7 +215,8 @@ Vector::Vector(Vector &&other) noexcept // Assignment //----------------------------------------------------------------------- -template Vector &Vector::operator=(Vector &&other) noexcept { +template +Vector &Vector::operator=(Vector &&other) noexcept { free(data_); size_ = other.size_; data_ = other.data_; @@ -220,7 +225,8 @@ template Vector &Vector::operator=(Vector &&other) noexcept { return *this; } -template Vector &Vector::operator=(const Vector &other) { +template +Vector &Vector::operator=(const Vector &other) { if (size_ != other.size_) { free(data_); size_ = other.size_; @@ -265,13 +271,15 @@ Vector Vector::move_from_buffer(size_t sz, T *buffer) { return ret; } -template T *Vector::copy_to_buffer() const { +template +T *Vector::copy_to_buffer() const { T *buffer = malloc_data(size_); std::copy(data_, data_ + size_, buffer); return buffer; } -template T *Vector::move_to_buffer() { +template +T *Vector::move_to_buffer() { T *buffer = data_; data_ = nullptr; size_ = 0; @@ -282,17 +290,20 @@ template T *Vector::move_to_buffer() { // Operations //----------------------------------------------------------------------- -template void Vector::clear() noexcept { +template +void Vector::clear() noexcept { free(data_); size_ = 0; } -template void Vector::swap(Vector &other) { +template +void Vector::swap(Vector &other) { std::swap(size_, other.size_); std::swap(data_, other.data_); } -template void Vector::resize(size_t sz) { +template +void Vector::resize(size_t sz) { if (size_ == sz) return; T *tmp = calloc_data(sz); @@ -302,7 +313,8 @@ template void Vector::resize(size_t sz) { data_ = tmp; } -template void Vector::fill(const T &val) { +template +void Vector::fill(const T &val) { std::fill(data_, data_ + size_, val); } @@ -323,7 +335,8 @@ Vector Vector::operator+(const Vector &other) const { return result; } -template Vector &Vector::operator+=(const Vector &other) { +template +Vector &Vector::operator+=(const Vector &other) { if (size_ != other.size_) { throw std::runtime_error("Cannot add two vectors of different sizes."); } @@ -345,7 +358,8 @@ Vector Vector::operator-(const Vector &other) const { return result; } -template Vector &Vector::operator-=(const Vector &other) { +template +Vector &Vector::operator-=(const Vector &other) { if (size_ != other.size_) { throw std::runtime_error("Cannot add two vectors of different sizes."); } @@ -354,7 +368,8 @@ template Vector &Vector::operator-=(const Vector &other) { return *this; } -template Vector Vector::operator*(const T &other) const { +template +Vector Vector::operator*(const T &other) const { Vector ret; ret.size_ = size_; ret.data_ = malloc_data(size_); @@ -363,13 +378,14 @@ template Vector Vector::operator*(const T &other) const { return ret; } -template Vector &Vector::operator*=(const T &other) { - std::for_each(data_, data_ + size_, - [&other](T &a) { a *= other; }); +template +Vector &Vector::operator*=(const T &other) { + std::for_each(data_, data_ + size_, [&other](T &a) { a *= other; }); return *this; } -template Vector Vector::operator/(const T &other) const { +template +Vector Vector::operator/(const T &other) const { Vector ret; ret.size_ = size_; ret.data_ = malloc_data(size_); @@ -378,12 +394,12 @@ template Vector Vector::operator/(const T &other) const { return ret; } -template Vector &Vector::operator/=(const T &other) { +template +Vector &Vector::operator/=(const T &other) { std::for_each(data_, data_ + size_, [&other](T &a) { a /= other; }); return *this; } - //------------------------------------------------------------------------------ } // end Namespace AER //------------------------------------------------------------------------------ diff --git a/src/framework/linalg/vector_json.hpp b/src/framework/linalg/vector_json.hpp old mode 100755 new mode 100644 index 8f3f8d2a67..3a03339c61 --- a/src/framework/linalg/vector_json.hpp +++ b/src/framework/linalg/vector_json.hpp @@ -24,23 +24,23 @@ namespace AER { // Implementation: JSON Conversion //------------------------------------------------------------------------------ - -template void to_json(nlohmann::json &js, const Vector &vec) { +template +void to_json(nlohmann::json &js, const Vector &vec) { js = nlohmann::json(); for (size_t i = 0; i < vec.size(); i++) { js.push_back(vec[i]); } } - -template void from_json(const nlohmann::json &js, Vector &vec) { +template +void from_json(const nlohmann::json &js, Vector &vec) { // Check JSON is an array - if(!js.is_array()) { + if (!js.is_array()) { throw std::invalid_argument( std::string("JSON: invalid Vector (not array).")); } // Check if JSON is empty - if(js.empty()) { + if (js.empty()) { return; } diff --git a/src/framework/matrix.hpp b/src/framework/matrix.hpp old mode 100755 new mode 100644 index bc22bc9306..6a0a0ffe06 --- a/src/framework/matrix.hpp +++ b/src/framework/matrix.hpp @@ -31,10 +31,10 @@ Multiplication is done with the C wrapper of the fortran blas library. #ifndef _aer_framework_matrix_hpp #define _aer_framework_matrix_hpp +#include #include #include #include -#include #include "framework/blas_protos.hpp" #include "framework/linalg/enable_if_numeric.hpp" @@ -46,16 +46,15 @@ Multiplication is done with the C wrapper of the fortran blas library. ******************************************************************************/ template -T* malloc_array(size_t size) { - return reinterpret_cast(malloc(sizeof(T) * size)); +T *malloc_array(size_t size) { + return reinterpret_cast(malloc(sizeof(T) * size)); } template -T* calloc_array(size_t size) { - return reinterpret_cast(calloc(size, sizeof(T))); +T *calloc_array(size_t size) { + return reinterpret_cast(calloc(size, sizeof(T))); } - template // define a class template class matrix { // friend functions get to use the private variables of the class as well as @@ -136,13 +135,13 @@ class matrix { matrix(size_t rows, size_t cols, bool fill = true); // Construct a matrix of specified size and an array - matrix(size_t rows, size_t cols, T* data); + matrix(size_t rows, size_t cols, T *data); // Copy construct a matrix matrix(const matrix &other); // Move construct a matrix - matrix(matrix&& other) noexcept; + matrix(matrix &&other) noexcept; // Destructor virtual ~matrix() { free(data_); } @@ -167,33 +166,33 @@ class matrix { // Copy construct a matrix from C-array buffer // The buffer should have size = rows * cols. - static matrix copy_from_buffer(size_t rows, size_t cols, const T* buffer); + static matrix copy_from_buffer(size_t rows, size_t cols, const T *buffer); // Move construct a matrix from C-array buffer // The buffer should have size = rows * cols. - static matrix move_from_buffer(size_t rows, size_t cols, T* buffer); + static matrix move_from_buffer(size_t rows, size_t cols, T *buffer); // Copy matrix to a new C-array - T* copy_to_buffer() const; + T *copy_to_buffer() const; // Move matrix to a C-array - T* move_to_buffer(); + T *move_to_buffer(); //----------------------------------------------------------------------- // Element access //----------------------------------------------------------------------- // Addressing elements by vector representation - T& operator[](size_t element); - const T& operator[](size_t element) const; + T &operator[](size_t element); + const T &operator[](size_t element) const; // Addressing elements by matrix representation - T& operator()(size_t row, size_t col); - const T& operator()(size_t row, size_t col) const; + T &operator()(size_t row, size_t col); + const T &operator()(size_t row, size_t col) const; // Access the array data pointer - const T* data() const noexcept { return data_; } - T* data() noexcept { return data_; } + const T *data() const noexcept { return data_; } + T *data() noexcept { return data_; } //----------------------------------------------------------------------- // Other methods @@ -209,7 +208,7 @@ class matrix { void clear(); // Fill with constant value - void fill(const T& val); + void fill(const T &val); // Resize the matrix and reset to zero if different size void initialize(size_t row, size_t col); @@ -245,7 +244,7 @@ class matrix { // to rows // the ptr to the vector containing the matrix - T* data_ = nullptr; + T *data_ = nullptr; }; /******************************************************************************* @@ -264,28 +263,28 @@ matrix::matrix(size_t rows, size_t cols, bool fill) data_((fill) ? calloc_array(size_) : malloc_array(size_)) {} template -matrix::matrix(const matrix &other) : matrix(other.rows_, other.cols_, false) { +matrix::matrix(const matrix &other) + : matrix(other.rows_, other.cols_, false) { std::copy(other.data_, other.data_ + other.size_, data_); } template -matrix::matrix(matrix&& other) noexcept - : rows_(other.rows_), cols_(other.cols_), size_(other.size_), LD_(rows_), - data_(other.data_) { +matrix::matrix(matrix &&other) noexcept + : rows_(other.rows_), cols_(other.cols_), size_(other.size_), LD_(rows_), + data_(other.data_) { other.data_ = nullptr; } template -matrix::matrix(size_t rows, size_t cols, T* data) - : rows_(rows), cols_(cols), size_(rows * cols), LD_(rows), - data_(data) {} +matrix::matrix(size_t rows, size_t cols, T *data) + : rows_(rows), cols_(cols), size_(rows * cols), LD_(rows), data_(data) {} //----------------------------------------------------------------------- // Assignment //----------------------------------------------------------------------- template -matrix& matrix::operator=(matrix&& other) noexcept { +matrix &matrix::operator=(matrix &&other) noexcept { free(data_); rows_ = other.rows_; cols_ = other.cols_; @@ -316,8 +315,7 @@ template template inline matrix &matrix::operator=(const matrix &other) { - if (rows_ != other.GetRows() || - cols_ != other.GetColumns()) { + if (rows_ != other.GetRows() || cols_ != other.GetColumns()) { free(data_); rows_ = other.GetRows(); cols_ = other.GetColumns(); @@ -336,7 +334,8 @@ inline matrix &matrix::operator=(const matrix &other) { //----------------------------------------------------------------------- template -matrix matrix::copy_from_buffer(size_t rows, size_t cols, const T* buffer) { +matrix matrix::copy_from_buffer(size_t rows, size_t cols, + const T *buffer) { matrix ret; ret.size_ = rows * cols; ret.rows_ = rows; @@ -348,7 +347,7 @@ matrix matrix::copy_from_buffer(size_t rows, size_t cols, const T* buffer) } template -matrix matrix::move_from_buffer(size_t rows, size_t cols, T* buffer) { +matrix matrix::move_from_buffer(size_t rows, size_t cols, T *buffer) { matrix ret; ret.size_ = rows * cols; ret.rows_ = rows; @@ -359,15 +358,15 @@ matrix matrix::move_from_buffer(size_t rows, size_t cols, T* buffer) { } template -T* matrix::copy_to_buffer() const { - T* buffer = malloc_array(size_); +T *matrix::copy_to_buffer() const { + T *buffer = malloc_array(size_); std::copy(data_, data_ + size_, buffer); return buffer; } template -T* matrix::move_to_buffer() { - T* buffer = data_; +T *matrix::move_to_buffer() { + T *buffer = data_; data_ = nullptr; size_ = 0; rows_ = 0; @@ -380,7 +379,7 @@ T* matrix::move_to_buffer() { //----------------------------------------------------------------------- template -T& matrix::operator[](size_t p) { +T &matrix::operator[](size_t p) { #ifdef DEBUG if (p >= size_) { std::cerr @@ -392,7 +391,7 @@ T& matrix::operator[](size_t p) { return data_[p]; } template -const T& matrix::operator[](size_t p) const { +const T &matrix::operator[](size_t p) const { #ifdef DEBUG if (p >= size_) { std::cerr << "Error: matrix class operator [] const: Matrix subscript out " @@ -405,7 +404,7 @@ const T& matrix::operator[](size_t p) const { } template -T& matrix::operator()(size_t i, size_t j) { +T &matrix::operator()(size_t i, size_t j) { #ifdef DEBUG if (i >= rows_ || j >= cols_) { std::cerr @@ -418,7 +417,7 @@ T& matrix::operator()(size_t i, size_t j) { } template -const T& matrix::operator()(size_t i, size_t j) const { +const T &matrix::operator()(size_t i, size_t j) const { #ifdef DEBUG if (i >= rows_ || j >= cols_) { std::cerr << "Error: matrix class operator () const: Matrices subscript " @@ -438,7 +437,8 @@ void matrix::clear() { free(data_); } -template inline void matrix::initialize(size_t rows, size_t cols) { +template +inline void matrix::initialize(size_t rows, size_t cols) { if (rows_ != rows || cols_ != cols) { free(data_); rows_ = rows; @@ -450,7 +450,7 @@ template inline void matrix::initialize(size_t rows, size_t cols) { } template -void matrix::fill(const T& val) { +void matrix::fill(const T &val) { std::fill(data_, data_ + size_, val); } @@ -473,52 +473,58 @@ void matrix::resize(size_t rows, size_t cols) { } // Addressing elements by row or column -template inline std::vector matrix::row_index(size_t row) const { +template +inline std::vector matrix::row_index(size_t row) const { #ifdef DEBUG if (row >= rows_) { - std::cerr << "Error: matrix class operator row_index out of bounds " - << row << " >= " << rows_ << std::endl; + std::cerr << "Error: matrix class operator row_index out of bounds " << row + << " >= " << rows_ << std::endl; exit(1); } #endif std::vector ret; ret.reserve(cols_); - for(size_t i = 0; i < cols_; i++) + for (size_t i = 0; i < cols_; i++) ret.emplace_back(data_[i * rows_ + row]); // Allow for Named Return Value Optimization (NRVO) by not using std::move return ret; } -template inline std::vector matrix::col_index(size_t col) const { +template +inline std::vector matrix::col_index(size_t col) const { #ifdef DEBUG if (col >= cols_) { - std::cerr << "Error: matrix class operator col_index out of bounds " - << col << " >= " << cols_ << std::endl; + std::cerr << "Error: matrix class operator col_index out of bounds " << col + << " >= " << cols_ << std::endl; exit(1); } #endif std::vector ret; ret.reserve(rows_); // we want the elements for all rows i..rows_ and column col - for(size_t i = 0; i < rows_; i++) + for (size_t i = 0; i < rows_; i++) ret.emplace_back(data_[col * rows_ + i]); // Allow for Named Return Value Optimization (NRVO) by not using std::move return ret; } -template inline size_t matrix::GetRows() const { +template +inline size_t matrix::GetRows() const { // returns the rows of the matrix return rows_; } -template inline size_t matrix::GetColumns() const { +template +inline size_t matrix::GetColumns() const { // returns the colums of the matrix return cols_; } -template inline size_t matrix::GetLD() const { +template +inline size_t matrix::GetLD() const { // returns the leading dimension return LD_; } -template inline matrix matrix::operator+(const matrix &A) { +template +inline matrix matrix::operator+(const matrix &A) { // overloads the + for matrix addition, can this be more efficient #ifdef DEBUG if (rows_ != A.rows_ || cols_ != A.cols_) { @@ -534,7 +540,8 @@ template inline matrix matrix::operator+(const matrix &A) { } return temp; } -template inline matrix matrix::operator-(const matrix &A) { +template +inline matrix matrix::operator-(const matrix &A) { // overloads the - for matrix substraction, can this be more efficient #ifdef DEBUG if (rows_ != A.rows_ || cols_ != A.cols_) { @@ -585,7 +592,8 @@ inline matrix matrix::operator-(const matrix &A) const { } return temp; } -template inline matrix &matrix::operator+=(const matrix &A) { +template +inline matrix &matrix::operator+=(const matrix &A) { // overloads the += for matrix addition and assignment, can this be more // efficient #ifdef DEBUG @@ -601,7 +609,8 @@ template inline matrix &matrix::operator+=(const matrix &A) { } return *this; } -template inline matrix &matrix::operator-=(const matrix &A) { +template +inline matrix &matrix::operator-=(const matrix &A) { // overloads the -= for matrix subtraction and assignement, can this be more // efficient #ifdef DEBUG @@ -686,8 +695,8 @@ inline matrix operator*(const matrix &A, // C-> alpha*op(A)*op(B) +beta C matrix C(A.rows_, B.cols_); double alpha = 1.0, beta = 0.0; - dgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &B.cols_, &A.cols_, &alpha, A.data_, - &A.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); + dgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &B.cols_, &A.cols_, + &alpha, A.data_, &A.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); // cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, A.rows_, B.cols_, // A.cols_, 1.0, A.data_, A.LD_, B.data_, B.LD_, 0.0, C.data_, C.LD_); return C; @@ -698,8 +707,8 @@ inline matrix operator*(const matrix &A, const matrix &B) { // C-> alpha*op(A)*op(B) +beta C matrix C(A.rows_, B.cols_); float alpha = 1.0, beta = 0.0; - sgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &B.cols_, &A.cols_, &alpha, A.data_, - &A.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); + sgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &B.cols_, &A.cols_, + &alpha, A.data_, &A.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); // cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, A.rows_, B.cols_, // A.cols_, 1.0, A.data_, A.LD_, B.data_, B.LD_, 0.0, C.data_, C.LD_); return C; @@ -712,8 +721,8 @@ operator*(const matrix> &A, // C-> alpha*op(A)*op(B) +beta C matrix> C(A.rows_, B.cols_); std::complex alpha = 1.0, beta = 0.0; - cgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &B.cols_, &A.cols_, &alpha, A.data_, - &A.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); + cgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &B.cols_, &A.cols_, + &alpha, A.data_, &A.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); // cblas_zgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, A.rows_, B.cols_, // A.cols_, &alpha, A.data_, A.LD_, B.data_, B.LD_, &beta, C.data_, C.LD_); return C; @@ -726,8 +735,8 @@ operator*(const matrix> &A, // C-> alpha*op(A)*op(B) +beta C matrix> C(A.rows_, B.cols_); std::complex alpha = 1.0, beta = 0.0; - zgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &B.cols_, &A.cols_, &alpha, A.data_, - &A.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); + zgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &B.cols_, &A.cols_, + &alpha, A.data_, &A.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); // cblas_zgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, A.rows_, B.cols_, // A.cols_, &alpha, A.data_, A.LD_, B.data_, B.LD_, &beta, C.data_, C.LD_); return C; @@ -740,8 +749,8 @@ operator*(const matrix &A, const matrix> &B) { matrix> C(A.rows_, B.cols_), Ac(A.rows_, A.cols_); Ac = A; std::complex alpha = 1.0, beta = 0.0; - cgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &Ac.rows_, &B.cols_, &Ac.cols_, &alpha, Ac.data_, - &Ac.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); + cgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &Ac.rows_, &B.cols_, &Ac.cols_, + &alpha, Ac.data_, &Ac.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); // cblas_zgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, Ac.rows_, B.cols_, // Ac.cols_, &alpha, Ac.data_, Ac.LD_, B.data_, B.LD_, &beta, C.data_, C.LD_); return C; @@ -754,8 +763,8 @@ operator*(const matrix &A, const matrix> &B) { matrix> C(A.rows_, B.cols_), Ac(A.rows_, A.cols_); Ac = A; std::complex alpha = 1.0, beta = 0.0; - zgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &Ac.rows_, &B.cols_, &Ac.cols_, &alpha, Ac.data_, - &Ac.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); + zgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &Ac.rows_, &B.cols_, &Ac.cols_, + &alpha, Ac.data_, &Ac.LD_, B.data_, &B.LD_, &beta, C.data_, &C.LD_); // cblas_zgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, Ac.rows_, B.cols_, // Ac.cols_, &alpha, Ac.data_, Ac.LD_, B.data_, B.LD_, &beta, C.data_, C.LD_); return C; @@ -768,8 +777,8 @@ operator*(const matrix> &A, const matrix &B) { matrix> C(A.rows_, B.cols_), Bc(B.rows_, B.cols_); Bc = B; std::complex alpha = 1.0, beta = 0.0; - cgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &Bc.cols_, &A.cols_, &alpha, A.data_, - &A.LD_, Bc.data_, &Bc.LD_, &beta, C.data_, &C.LD_); + cgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &Bc.cols_, &A.cols_, + &alpha, A.data_, &A.LD_, Bc.data_, &Bc.LD_, &beta, C.data_, &C.LD_); // cblas_zgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, A.rows_, Bc.cols_, // A.cols_, &alpha, A.data_, A.LD_, Bc.data_, Bc.LD_, &beta, C.data_, C.LD_); return C; @@ -782,8 +791,8 @@ operator*(const matrix> &A, const matrix &B) { matrix> C(A.rows_, B.cols_), Bc(B.rows_, B.cols_); Bc = B; std::complex alpha = 1.0, beta = 0.0; - zgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &Bc.cols_, &A.cols_, &alpha, A.data_, - &A.LD_, Bc.data_, &Bc.LD_, &beta, C.data_, &C.LD_); + zgemm_(&AerBlas::Trans[0], &AerBlas::Trans[0], &A.rows_, &Bc.cols_, &A.cols_, + &alpha, A.data_, &A.LD_, Bc.data_, &Bc.LD_, &beta, C.data_, &C.LD_); // cblas_zgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, A.rows_, Bc.cols_, // A.cols_, &alpha, A.data_, A.LD_, Bc.data_, Bc.LD_, &beta, C.data_, C.LD_); return C; @@ -796,8 +805,8 @@ inline std::vector operator*(const matrix &A, std::vector y(A.rows_); float alpha = 1.0, beta = 0.0; const size_t incx = 1, incy = 1; - sgemv_(&AerBlas::Trans[0], &A.rows_, &A.cols_, &alpha, A.data_, &A.LD_, x.data(), &incx, - &beta, y.data(), &incy); + sgemv_(&AerBlas::Trans[0], &A.rows_, &A.cols_, &alpha, A.data_, &A.LD_, + x.data(), &incx, &beta, y.data(), &incy); return y; } // Double-Precision Real @@ -807,8 +816,8 @@ inline std::vector operator*(const matrix &A, std::vector y(A.rows_); double alpha = 1.0, beta = 0.0; const size_t incx = 1, incy = 1; - dgemv_(&AerBlas::Trans[0], &A.rows_, &A.cols_, &alpha, A.data_, &A.LD_, x.data(), &incx, - &beta, y.data(), &incy); + dgemv_(&AerBlas::Trans[0], &A.rows_, &A.cols_, &alpha, A.data_, &A.LD_, + x.data(), &incx, &beta, y.data(), &incy); return y; } // Single-Precision Complex @@ -819,8 +828,8 @@ operator*(const matrix> &A, std::vector> y(A.rows_); std::complex alpha = 1.0, beta = 0.0; const size_t incx = 1, incy = 1; - cgemv_(&AerBlas::Trans[0], &A.rows_, &A.cols_, &alpha, A.data_, &A.LD_, x.data(), &incx, - &beta, y.data(), &incy); + cgemv_(&AerBlas::Trans[0], &A.rows_, &A.cols_, &alpha, A.data_, &A.LD_, + x.data(), &incx, &beta, y.data(), &incy); return y; } // Double-Precision Complex @@ -831,8 +840,8 @@ operator*(const matrix> &A, std::vector> y(A.rows_); std::complex alpha = 1.0, beta = 0.0; const size_t incx = 1, incy = 1; - zgemv_(&AerBlas::Trans[0], &A.rows_, &A.cols_, &alpha, A.data_, &A.LD_, x.data(), &incx, - &beta, y.data(), &incy); + zgemv_(&AerBlas::Trans[0], &A.rows_, &A.cols_, &alpha, A.data_, &A.LD_, + x.data(), &incx, &beta, y.data(), &incy); return y; } diff --git a/src/framework/noise_utils.hpp b/src/framework/noise_utils.hpp index eb3947fbd3..5694bd88ba 100644 --- a/src/framework/noise_utils.hpp +++ b/src/framework/noise_utils.hpp @@ -26,28 +26,30 @@ namespace Utils { // Transform a superoperator matrix to a Choi matrix template -matrix superop2choi(const matrix& superop, size_t dim); +matrix superop2choi(const matrix &superop, size_t dim); // Transform a superoperator matrix to a set of Kraus matrices template -std::vector> superop2kraus(const matrix& superop, size_t dim, double threshold = 1e-10); +std::vector> superop2kraus(const matrix &superop, size_t dim, + double threshold = 1e-10); // Transform a Choi matrix to a superoperator matrix template -matrix choi2superop(const matrix& choi, size_t dim); +matrix choi2superop(const matrix &choi, size_t dim); // Transform a Choi matrix to a set of Kraus matrices template std::vector>> -choi2kraus(const matrix>& choi, size_t dim, double threshold = 1e-10); +choi2kraus(const matrix> &choi, size_t dim, + double threshold = 1e-10); // Transform a set of Kraus matrices to a Choi matrix template -matrix kraus2choi(const std::vector>& kraus, size_t dim); +matrix kraus2choi(const std::vector> &kraus, size_t dim); // Transform a set of Kraus matrices to a superoperator matrix template -matrix kraus2superop(const std::vector>& kraus, size_t dim); +matrix kraus2superop(const std::vector> &kraus, size_t dim); // Reshuffle transformation // Transforms a matrix with dimension (d0 * d1, d2 * d3) @@ -55,15 +57,15 @@ matrix kraus2superop(const std::vector>& kraus, size_t dim); // by transposition of bipartite indices // M[(i, j), (k, l)] -> M[(i, j), (k, i)] template -matrix reshuffle(const matrix &mat, size_t d0, size_t d1, size_t d2, size_t d3); - +matrix reshuffle(const matrix &mat, size_t d0, size_t d1, size_t d2, + size_t d3); //========================================================================= // Implementations //========================================================================= template -matrix kraus2superop(const std::vector>& kraus, size_t dim) { +matrix kraus2superop(const std::vector> &kraus, size_t dim) { matrix superop(dim * dim, dim * dim); for (const auto mat : kraus) { superop += Utils::tensor_product(Utils::conjugate(mat), mat); @@ -72,28 +74,29 @@ matrix kraus2superop(const std::vector>& kraus, size_t dim) { } template -matrix kraus2choi(const std::vector>& kraus, size_t dim) { +matrix kraus2choi(const std::vector> &kraus, size_t dim) { return superop2choi(kraus2superop(kraus, dim), dim); } template -matrix superop2choi(const matrix& superop, size_t dim) { +matrix superop2choi(const matrix &superop, size_t dim) { return reshuffle(superop, dim, dim, dim, dim); } template -std::vector> superop2kraus(const matrix& superop, size_t dim, double threshold) { +std::vector> superop2kraus(const matrix &superop, size_t dim, + double threshold) { return choi2kraus(superop2choi(superop, dim), dim, threshold); } template -matrix choi2superop(const matrix& choi, size_t dim) { +matrix choi2superop(const matrix &choi, size_t dim) { return reshuffle(choi, dim, dim, dim, dim); } template std::vector>> -choi2kraus(const matrix>& choi, size_t dim, double threshold) { +choi2kraus(const matrix> &choi, size_t dim, double threshold) { size_t dim2 = dim * dim; std::vector evals; @@ -108,7 +111,7 @@ choi2kraus(const matrix>& choi, size_t dim, double threshold) { const size_t idx = dim2 - 1 - i; const T eval = evals[idx]; if (eval > 0.0 && !Linalg::almost_equal(eval, 0.0, threshold)) { - std::complex coeff(std::sqrt(eval), 0.0); + std::complex coeff(std::sqrt(eval), 0.0); matrix> kmat(dim, dim); for (size_t col = 0; col < dim; col++) for (size_t row = 0; row < dim; row++) { @@ -121,19 +124,20 @@ choi2kraus(const matrix>& choi, size_t dim, double threshold) { } template -matrix reshuffle(const matrix &mat, size_t d0, size_t d1, size_t d2, size_t d3) { +matrix reshuffle(const matrix &mat, size_t d0, size_t d1, size_t d2, + size_t d3) { matrix ret(d1 * d3, d0 * d2); for (size_t i0 = 0; i0 < d0; ++i0) for (size_t i1 = 0; i1 < d1; ++i1) for (size_t i2 = 0; i2 < d2; ++i2) for (size_t i3 = 0; i3 < d3; ++i3) { - ret(d1 * i3 + i1, d0 * i2 + i0) = mat(d1 * i0 + i1, d3 * i2 + i3); + ret(d1 * i3 + i1, d0 * i2 + i0) = mat(d1 * i0 + i1, d3 * i2 + i3); } return ret; } //------------------------------------------------------------------------- -} // end namespace Noise +} // namespace Utils //------------------------------------------------------------------------- } // end namespace AER //------------------------------------------------------------------------- diff --git a/src/framework/operations.hpp b/src/framework/operations.hpp old mode 100755 new mode 100644 index c1eb65c2fe..3e52f2bbea --- a/src/framework/operations.hpp +++ b/src/framework/operations.hpp @@ -16,15 +16,15 @@ #define _aer_framework_operations_hpp_ #include -#include #include #include +#include #include -#include "framework/types.hpp" #include "framework/json_parser.hpp" -#include "framework/utils.hpp" #include "framework/linalg/almost_equal.hpp" +#include "framework/types.hpp" +#include "framework/utils.hpp" #include "simulators/stabilizer/clifford.hpp" namespace AER { @@ -33,39 +33,81 @@ namespace Operations { // Comparisons enum class used for Boolean function operation. // these are used to compare two hexadecimal strings and return a bool // for now we only have one comparison Equal, but others will be added -enum class RegComparison {Equal, NotEqual, Less, LessEqual, Greater, GreaterEqual}; +enum class RegComparison { + Equal, + NotEqual, + Less, + LessEqual, + Greater, + GreaterEqual +}; // Enum class for operation types enum class OpType { - gate, measure, reset, bfunc, barrier, qerror_loc, - matrix, diagonal_matrix, multiplexer, initialize, sim_op, nop, + gate, + measure, + reset, + bfunc, + barrier, + qerror_loc, + matrix, + diagonal_matrix, + multiplexer, + initialize, + sim_op, + nop, // Noise instructions - kraus, superop, roerror, noise_switch, + kraus, + superop, + roerror, + noise_switch, // Save instructions - save_state, save_expval, save_expval_var, save_statevec, save_statevec_dict, - save_densmat, save_probs, save_probs_ket, save_amps, save_amps_sq, - save_stabilizer, save_clifford, save_unitary, save_mps, save_superop, + save_state, + save_expval, + save_expval_var, + save_statevec, + save_statevec_dict, + save_densmat, + save_probs, + save_probs_ket, + save_amps, + save_amps_sq, + save_stabilizer, + save_clifford, + save_unitary, + save_mps, + save_superop, // Set instructions - set_statevec, set_densmat, set_unitary, set_superop, - set_stabilizer, set_mps, + set_statevec, + set_densmat, + set_unitary, + set_superop, + set_stabilizer, + set_mps, // Control Flow - jump, mark + jump, + mark }; enum class DataSubType { - single, c_single, list, c_list, accum, c_accum, average, c_average + single, + c_single, + list, + c_list, + accum, + c_accum, + average, + c_average }; static const std::unordered_set SAVE_TYPES = { - OpType::save_state, OpType::save_expval, OpType::save_expval_var, - OpType::save_statevec, OpType::save_statevec_dict, - OpType::save_densmat, OpType::save_probs, OpType::save_probs_ket, - OpType::save_amps, OpType::save_amps_sq, OpType::save_stabilizer, - OpType::save_clifford, - OpType::save_unitary, OpType::save_mps, OpType::save_superop -}; + OpType::save_state, OpType::save_expval, OpType::save_expval_var, + OpType::save_statevec, OpType::save_statevec_dict, OpType::save_densmat, + OpType::save_probs, OpType::save_probs_ket, OpType::save_amps, + OpType::save_amps_sq, OpType::save_stabilizer, OpType::save_clifford, + OpType::save_unitary, OpType::save_mps, OpType::save_superop}; -inline std::ostream& operator<<(std::ostream& stream, const OpType& type) { +inline std::ostream &operator<<(std::ostream &stream, const OpType &type) { switch (type) { case OpType::gate: stream << "gate"; @@ -189,40 +231,39 @@ inline std::ostream& operator<<(std::ostream& stream, const OpType& type) { return stream; } - -inline std::ostream& operator<<(std::ostream& stream, const DataSubType& subtype) { +inline std::ostream &operator<<(std::ostream &stream, + const DataSubType &subtype) { switch (subtype) { - case DataSubType::single: - stream << "single"; - break; - case DataSubType::c_single: - stream << "c_single"; - break; - case DataSubType::list: - stream << "list"; - break; - case DataSubType::c_list: - stream << "c_list"; - break; - case DataSubType::accum: - stream << "accum"; - break; - case DataSubType::c_accum: - stream << "c_accum"; - break; - case DataSubType::average: - stream << "average"; - break; - case DataSubType::c_average: - stream << "c_average"; - break; - default: - stream << "unknown"; + case DataSubType::single: + stream << "single"; + break; + case DataSubType::c_single: + stream << "c_single"; + break; + case DataSubType::list: + stream << "list"; + break; + case DataSubType::c_list: + stream << "c_list"; + break; + case DataSubType::accum: + stream << "accum"; + break; + case DataSubType::c_accum: + stream << "c_accum"; + break; + case DataSubType::average: + stream << "average"; + break; + case DataSubType::c_average: + stream << "c_average"; + break; + default: + stream << "unknown"; } return stream; } - //------------------------------------------------------------------------------ // Op Class //------------------------------------------------------------------------------ @@ -234,17 +275,19 @@ struct Op { reg_t qubits; // qubits operation acts on std::vector regs; // list of qubits for matrixes std::vector params; // real or complex params for gates - std::vector int_params; // integer parameters - std::vector string_params; // used for label, control-flow, and boolean functions + std::vector int_params; // integer parameters + std::vector + string_params; // used for label, control-flow, and boolean functions // Conditional Operations bool conditional = false; // is gate conditional gate - uint_t conditional_reg; // (opt) the (single) register location to look up for conditional - RegComparison bfunc; // (opt) boolean function relation + uint_t conditional_reg; // (opt) the (single) register location to look up for + // conditional + RegComparison bfunc; // (opt) boolean function relation // Measurement - reg_t memory; // (opt) register operation it acts on (measure) - reg_t registers; // (opt) register locations it acts on (measure, conditional) + reg_t memory; // (opt) register operation it acts on (measure) + reg_t registers; // (opt) register locations it acts on (measure, conditional) // Mat and Kraus std::vector mats; @@ -263,22 +306,25 @@ struct Op { DataSubType save_type = DataSubType::single; }; -inline std::ostream& operator<<(std::ostream& s, const Op& op) { +inline std::ostream &operator<<(std::ostream &s, const Op &op) { s << op.name << "["; bool first = true; - for (size_t qubit: op.qubits) { - if (!first) s << ","; + for (size_t qubit : op.qubits) { + if (!first) + s << ","; s << qubit; first = false; } s << "],["; first = true; - for (reg_t reg: op.regs) { - if (!first) s << ","; + for (reg_t reg : op.regs) { + if (!first) + s << ","; s << "["; bool first0 = true; - for (size_t qubit: reg) { - if (!first0) s << ","; + for (size_t qubit : reg) { + if (!first0) + s << ","; s << qubit; first0 = false; } @@ -296,7 +342,8 @@ inline std::ostream& operator<<(std::ostream& s, const Op& op) { // Raise an exception if name string is empty inline void check_empty_name(const Op &op) { if (op.name.empty()) - throw std::invalid_argument(R"(Invalid qobj instruction ("name" is empty).)"); + throw std::invalid_argument( + R"(Invalid qobj instruction ("name" is empty).)"); } // Raise an exception if qubits list is empty @@ -316,8 +363,9 @@ inline void check_empty_params(const Op &op) { // Raise an exception if params is empty inline void check_length_params(const Op &op, const size_t size) { if (op.params.size() != size) - throw std::invalid_argument(R"(Invalid qobj ")" + op.name + - R"(" instruction ("params" is incorrect length).)"); + throw std::invalid_argument( + R"(Invalid qobj ")" + op.name + + R"(" instruction ("params" is incorrect length).)"); } // Raise an exception if qubits list contains duplications @@ -333,7 +381,8 @@ inline void check_duplicate_qubits(const Op &op) { // Generator functions //------------------------------------------------------------------------------ -inline Op make_initialize(const reg_t &qubits, const std::vector &init_data) { +inline Op make_initialize(const reg_t &qubits, + const std::vector &init_data) { Op op; op.type = OpType::initialize; op.name = "initialize"; @@ -342,7 +391,8 @@ inline Op make_initialize(const reg_t &qubits, const std::vector &ini return op; } -inline Op make_unitary(const reg_t &qubits, const cmatrix_t &mat, const int_t conditional = -1, std::string label = "") { +inline Op make_unitary(const reg_t &qubits, const cmatrix_t &mat, + const int_t conditional = -1, std::string label = "") { Op op; op.type = OpType::matrix; op.name = "unitary"; @@ -357,7 +407,8 @@ inline Op make_unitary(const reg_t &qubits, const cmatrix_t &mat, const int_t co return op; } -inline Op make_unitary(const reg_t &qubits, cmatrix_t &&mat, std::string label = "") { +inline Op make_unitary(const reg_t &qubits, cmatrix_t &&mat, + std::string label = "") { Op op; op.type = OpType::matrix; op.name = "unitary"; @@ -369,7 +420,8 @@ inline Op make_unitary(const reg_t &qubits, cmatrix_t &&mat, std::string label = return op; } -inline Op make_diagonal(const reg_t &qubits, const cvector_t &vec, const std::string label = "") { +inline Op make_diagonal(const reg_t &qubits, const cvector_t &vec, + const std::string label = "") { Op op; op.type = OpType::diagonal_matrix; op.name = "diagonal"; @@ -382,7 +434,8 @@ inline Op make_diagonal(const reg_t &qubits, const cvector_t &vec, const std::st return op; } -inline Op make_diagonal(const reg_t &qubits, cvector_t &&vec, const std::string label = "") { +inline Op make_diagonal(const reg_t &qubits, cvector_t &&vec, + const std::string label = "") { Op op; op.type = OpType::diagonal_matrix; op.name = "diagonal"; @@ -395,7 +448,8 @@ inline Op make_diagonal(const reg_t &qubits, cvector_t &&vec, const std::string return op; } -inline Op make_superop(const reg_t &qubits, const cmatrix_t &mat, const int_t conditional = -1) { +inline Op make_superop(const reg_t &qubits, const cmatrix_t &mat, + const int_t conditional = -1) { Op op; op.type = OpType::superop; op.name = "superop"; @@ -418,7 +472,8 @@ inline Op make_superop(const reg_t &qubits, cmatrix_t &&mat) { return op; } -inline Op make_kraus(const reg_t &qubits, const std::vector &mats, const int_t conditional = -1) { +inline Op make_kraus(const reg_t &qubits, const std::vector &mats, + const int_t conditional = -1) { Op op; op.type = OpType::kraus; op.name = "kraus"; @@ -440,7 +495,8 @@ inline Op make_kraus(const reg_t &qubits, std::vector &&mats) { return op; } -inline Op make_roerror(const reg_t &memory, const std::vector &probs) { +inline Op make_roerror(const reg_t &memory, + const std::vector &probs) { Op op; op.type = OpType::roerror; op.name = "roerror"; @@ -458,7 +514,8 @@ inline Op make_roerror(const reg_t &memory, std::vector &&probs) { return op; } -inline Op make_bfunc(const std::string &mask, const std::string &val, const std::string &relation, const uint_t regidx) { +inline Op make_bfunc(const std::string &mask, const std::string &val, + const std::string &relation, const uint_t regidx) { Op op; op.type = OpType::bfunc; op.name = "bfunc"; @@ -469,39 +526,37 @@ inline Op make_bfunc(const std::string &mask, const std::string &val, const std: // Load single register op.registers.push_back(regidx); - + // Format hex strings Utils::format_hex_inplace(op.string_params[0]); Utils::format_hex_inplace(op.string_params[1]); const stringmap_t comp_table({ - {"==", RegComparison::Equal}, - {"!=", RegComparison::NotEqual}, - {"<", RegComparison::Less}, - {"<=", RegComparison::LessEqual}, - {">", RegComparison::Greater}, - {">=", RegComparison::GreaterEqual}, + {"==", RegComparison::Equal}, + {"!=", RegComparison::NotEqual}, + {"<", RegComparison::Less}, + {"<=", RegComparison::LessEqual}, + {">", RegComparison::Greater}, + {">=", RegComparison::GreaterEqual}, }); auto it = comp_table.find(relation); if (it == comp_table.end()) { std::stringstream msg; - msg << "Invalid bfunc relation string :\"" << it->first << "\"." << std::endl; + msg << "Invalid bfunc relation string :\"" << it->first << "\"." + << std::endl; throw std::invalid_argument(msg.str()); } else { op.bfunc = it->second; } return op; - } -Op make_gate(const std::string &name, - const reg_t &qubits, +Op make_gate(const std::string &name, const reg_t &qubits, const std::vector ¶ms, const std::vector &string_params, - const int_t conditional, - const std::string &label) { + const int_t conditional, const std::string &label) { Op op; op.type = OpType::gate; op.name = name; @@ -510,7 +565,7 @@ Op make_gate(const std::string &name, if (string_params.size() > 0) op.string_params = string_params; - else if (label != "") + else if (label != "") op.string_params = {label}; else op.string_params = {op.name}; @@ -556,7 +611,7 @@ inline Op make_u3(uint_t qubit, T theta, T phi, T lam) { return op; } -inline Op make_reset(const reg_t & qubits, uint_t state = 0) { +inline Op make_reset(const reg_t &qubits, uint_t state = 0) { Op op; op.type = OpType::reset; op.name = "reset"; @@ -623,31 +678,29 @@ inline Op make_multiplexer(const reg_t &qubits, return op; } -inline Op make_save_state(const reg_t &qubits, - const std::string &name, +inline Op make_save_state(const reg_t &qubits, const std::string &name, const std::string &snapshot_type, const std::string &label) { Op op; op.name = name; // Get subtype - static const std::unordered_map types { - {"save_state", OpType::save_state}, - {"save_statevector", OpType::save_statevec}, - {"save_statevector_dict", OpType::save_statevec_dict}, - {"save_amplitudes", OpType::save_amps}, - {"save_amplitudes_sq", OpType::save_amps_sq}, - {"save_clifford", OpType::save_clifford}, - {"save_probabilities", OpType::save_probs}, - {"save_probabilities_dict", OpType::save_probs_ket}, - {"save_matrix_product_state", OpType::save_mps}, - {"save_unitary", OpType::save_unitary}, - {"save_superop", OpType::save_superop}, - {"save_density_matrix", OpType::save_densmat}, - {"save_stabilizer", OpType::save_stabilizer}, - {"save_expval", OpType::save_expval}, - {"save_expval_var", OpType::save_expval_var} - }; + static const std::unordered_map types{ + {"save_state", OpType::save_state}, + {"save_statevector", OpType::save_statevec}, + {"save_statevector_dict", OpType::save_statevec_dict}, + {"save_amplitudes", OpType::save_amps}, + {"save_amplitudes_sq", OpType::save_amps_sq}, + {"save_clifford", OpType::save_clifford}, + {"save_probabilities", OpType::save_probs}, + {"save_probabilities_dict", OpType::save_probs_ket}, + {"save_matrix_product_state", OpType::save_mps}, + {"save_unitary", OpType::save_unitary}, + {"save_superop", OpType::save_superop}, + {"save_density_matrix", OpType::save_densmat}, + {"save_stabilizer", OpType::save_stabilizer}, + {"save_expval", OpType::save_expval}, + {"save_expval_var", OpType::save_expval_var}}; auto type_it = types.find(name); if (type_it == types.end()) { @@ -657,15 +710,11 @@ inline Op make_save_state(const reg_t &qubits, op.type = type_it->second; // Get subtype - static const std::unordered_map subtypes { - {"single", DataSubType::single}, - {"c_single", DataSubType::c_single}, - {"average", DataSubType::average}, - {"c_average", DataSubType::c_average}, - {"list", DataSubType::list}, - {"c_list", DataSubType::c_list}, - {"accum", DataSubType::accum}, - {"c_accum", DataSubType::c_accum}, + static const std::unordered_map subtypes{ + {"single", DataSubType::single}, {"c_single", DataSubType::c_single}, + {"average", DataSubType::average}, {"c_average", DataSubType::c_average}, + {"list", DataSubType::list}, {"c_list", DataSubType::c_list}, + {"accum", DataSubType::accum}, {"c_accum", DataSubType::c_accum}, }; auto subtype_it = subtypes.find(snapshot_type); @@ -674,7 +723,7 @@ inline Op make_save_state(const reg_t &qubits, "\" in save data instruction."); } op.save_type = subtype_it->second; - + op.string_params.emplace_back(label); op.qubits = qubits; @@ -682,8 +731,7 @@ inline Op make_save_state(const reg_t &qubits, return op; } -inline Op make_save_amplitudes(const reg_t &qubits, - const std::string &name, +inline Op make_save_amplitudes(const reg_t &qubits, const std::string &name, const std::vector &base_type, const std::string &snapshot_type, const std::string &label) { @@ -692,8 +740,7 @@ inline Op make_save_amplitudes(const reg_t &qubits, return op; } -inline Op make_save_expval(const reg_t &qubits, - const std::string &name, +inline Op make_save_expval(const reg_t &qubits, const std::string &name, const std::vector pauli_strings, const std::vector coeff_reals, const std::vector coeff_imags, @@ -706,7 +753,8 @@ inline Op make_save_expval(const reg_t &qubits, auto op = make_save_state(qubits, name, snapshot_type, label); for (uint_t i = 0; i < pauli_strings.size(); ++i) - op.expval_params.emplace_back(pauli_strings[i], coeff_reals[i], coeff_imags[i]); + op.expval_params.emplace_back(pauli_strings[i], coeff_reals[i], + coeff_imags[i]); if (op.expval_params.empty()) { std::string pauli(op.qubits.size(), 'I'); @@ -715,12 +763,13 @@ inline Op make_save_expval(const reg_t &qubits, return op; } -template -inline Op make_set_vector(const reg_t &qubits, const std::string &name, const inputdata_t ¶ms) { +template +inline Op make_set_vector(const reg_t &qubits, const std::string &name, + const inputdata_t ¶ms) { Op op; // Get type - static const std::unordered_map types { - {"set_statevector", OpType::set_statevec}, + static const std::unordered_map types{ + {"set_statevector", OpType::set_statevec}, }; auto type_it = types.find(name); if (type_it == types.end()) { @@ -730,19 +779,21 @@ inline Op make_set_vector(const reg_t &qubits, const std::string &name, const in op.type = type_it->second; op.name = name; op.qubits = qubits; - op.params = Parser::template get_list_elem>(params, 0); + op.params = + Parser::template get_list_elem>( + params, 0); return op; } -template -inline Op make_set_matrix(const reg_t &qubits, const std::string &name, const inputdata_t ¶ms) { +template +inline Op make_set_matrix(const reg_t &qubits, const std::string &name, + const inputdata_t ¶ms) { Op op; // Get type - static const std::unordered_map types { - {"set_density_matrix", OpType::set_densmat}, - {"set_unitary", OpType::set_unitary}, - {"set_superop", OpType::set_superop} - }; + static const std::unordered_map types{ + {"set_density_matrix", OpType::set_densmat}, + {"set_unitary", OpType::set_unitary}, + {"set_superop", OpType::set_superop}}; auto type_it = types.find(name); if (type_it == types.end()) { throw std::runtime_error("Invalid data type \"" + name + @@ -751,38 +802,45 @@ inline Op make_set_matrix(const reg_t &qubits, const std::string &name, const in op.type = type_it->second; op.name = name; op.qubits = qubits; - op.mats.push_back(Parser::template get_list_elem(params, 0)); + op.mats.push_back( + Parser::template get_list_elem(params, 0)); return op; } -template -inline Op make_set_mps(const reg_t &qubits, const std::string &name, const inputdata_t ¶ms) { +template +inline Op make_set_mps(const reg_t &qubits, const std::string &name, + const inputdata_t ¶ms) { Op op; op.type = OpType::set_mps; op.name = name; op.qubits = qubits; - op.mps = Parser::template get_list_elem(params, 0); + op.mps = + Parser::template get_list_elem(params, 0); return op; } -template -inline Op make_set_clifford(const reg_t &qubits, const std::string &name, const inputdata_t ¶ms) { +template +inline Op make_set_clifford(const reg_t &qubits, const std::string &name, + const inputdata_t ¶ms) { Op op; op.type = OpType::set_stabilizer; op.name = name; op.qubits = qubits; - op.clifford = Parser::template get_list_elem(params, 0); + op.clifford = Parser::template get_list_elem( + params, 0); return op; } -inline Op make_jump(const reg_t &qubits, const std::vector ¶ms, const int_t conditional) { +inline Op make_jump(const reg_t &qubits, const std::vector ¶ms, + const int_t conditional) { Op op; op.type = OpType::jump; op.name = "jump"; op.qubits = qubits; op.string_params = params; if (op.string_params.empty()) - throw std::invalid_argument(std::string("Invalid jump (\"params\" field missing).")); + throw std::invalid_argument( + std::string("Invalid jump (\"params\" field missing).")); if (conditional >= 0) { op.conditional = true; @@ -792,19 +850,22 @@ inline Op make_jump(const reg_t &qubits, const std::vector ¶ms, return op; } -inline Op make_mark(const reg_t &qubits, const std::vector ¶ms) { +inline Op make_mark(const reg_t &qubits, + const std::vector ¶ms) { Op op; op.type = OpType::mark; op.name = "mark"; op.qubits = qubits; op.string_params = params; if (op.string_params.empty()) - throw std::invalid_argument(std::string("Invalid mark (\"params\" field missing).")); + throw std::invalid_argument( + std::string("Invalid mark (\"params\" field missing).")); return op; } -inline Op make_measure(const reg_t &qubits, const reg_t &memory, const reg_t ®isters) { +inline Op make_measure(const reg_t &qubits, const reg_t &memory, + const reg_t ®isters) { Op op; op.type = OpType::measure; op.name = "measure"; @@ -814,7 +875,8 @@ inline Op make_measure(const reg_t &qubits, const reg_t &memory, const reg_t &re return op; } -inline Op make_qerror_loc(const reg_t &qubits, const std::string &label, const int_t conditional = -1) { +inline Op make_qerror_loc(const reg_t &qubits, const std::string &label, + const int_t conditional = -1) { Op op; op.type = OpType::qerror_loc; op.name = label; @@ -826,99 +888,97 @@ inline Op make_qerror_loc(const reg_t &qubits, const std::string &label, const i return op; } - //------------------------------------------------------------------------------ // JSON conversion //------------------------------------------------------------------------------ // Main deserialization functions -template -Op input_to_op(const inputdata_t& input); // Partial TODO -json_t op_to_json(const Op &op); // Partial TODO +template +Op input_to_op(const inputdata_t &input); // Partial TODO +json_t op_to_json(const Op &op); // Partial TODO -inline void from_json(const json_t &js, Op &op) {op = input_to_op(js);} +inline void from_json(const json_t &js, Op &op) { op = input_to_op(js); } -inline void to_json(json_t &js, const Op &op) { js = op_to_json(op);} +inline void to_json(json_t &js, const Op &op) { js = op_to_json(op); } -void to_json(json_t &js, const DataSubType& type); +void to_json(json_t &js, const DataSubType &type); // Standard operations -template -Op input_to_op_gate(const inputdata_t& input); -template -Op input_to_op_barrier(const inputdata_t& input); -template -Op input_to_op_measure(const inputdata_t& input); -template -Op input_to_op_reset(const inputdata_t& input); -template -Op input_to_op_bfunc(const inputdata_t& input); -template -Op input_to_op_initialize(const inputdata_t& input); -template -Op input_to_op_pauli(const inputdata_t& input); +template +Op input_to_op_gate(const inputdata_t &input); +template +Op input_to_op_barrier(const inputdata_t &input); +template +Op input_to_op_measure(const inputdata_t &input); +template +Op input_to_op_reset(const inputdata_t &input); +template +Op input_to_op_bfunc(const inputdata_t &input); +template +Op input_to_op_initialize(const inputdata_t &input); +template +Op input_to_op_pauli(const inputdata_t &input); // Set state -template -Op input_to_op_set_vector(const inputdata_t& input, OpType op_type); +template +Op input_to_op_set_vector(const inputdata_t &input, OpType op_type); -template -Op input_to_op_set_matrix(const inputdata_t& input, OpType op_type); +template +Op input_to_op_set_matrix(const inputdata_t &input, OpType op_type); -template -Op input_to_op_set_clifford(const inputdata_t& input, OpType op_type); +template +Op input_to_op_set_clifford(const inputdata_t &input, OpType op_type); -template -Op input_to_op_set_mps(const inputdata_t& input, OpType op_type); +template +Op input_to_op_set_mps(const inputdata_t &input, OpType op_type); // Save data -template -Op input_to_op_save_default(const inputdata_t& input, OpType op_type); -template -Op input_to_op_save_expval(const inputdata_t& input, bool variance); -template -Op input_to_op_save_amps(const inputdata_t& input, bool squared); +template +Op input_to_op_save_default(const inputdata_t &input, OpType op_type); +template +Op input_to_op_save_expval(const inputdata_t &input, bool variance); +template +Op input_to_op_save_amps(const inputdata_t &input, bool squared); // Control-Flow -template -Op input_to_op_jump(const inputdata_t& input); -template -Op input_to_op_mark(const inputdata_t& input); +template +Op input_to_op_jump(const inputdata_t &input); +template +Op input_to_op_mark(const inputdata_t &input); // Matrices -template -Op input_to_op_unitary(const inputdata_t& input); -template -Op input_to_op_diagonal(const inputdata_t& input); -template -Op input_to_op_superop(const inputdata_t& input); -template -Op input_to_op_multiplexer(const inputdata_t& input); -template -Op input_to_op_kraus(const inputdata_t& input); -template -Op input_to_op_noise_switch(const inputdata_t& input); -template -Op input_to_op_qerror_loc(const inputdata_t& input); +template +Op input_to_op_unitary(const inputdata_t &input); +template +Op input_to_op_diagonal(const inputdata_t &input); +template +Op input_to_op_superop(const inputdata_t &input); +template +Op input_to_op_multiplexer(const inputdata_t &input); +template +Op input_to_op_kraus(const inputdata_t &input); +template +Op input_to_op_noise_switch(const inputdata_t &input); +template +Op input_to_op_qerror_loc(const inputdata_t &input); // Classical bits -template -Op input_to_op_roerror(const inputdata_t& input); +template +Op input_to_op_roerror(const inputdata_t &input); // Optional instruction parameters -enum class Allowed {Yes, No}; - -template -void add_conditional(const Allowed val, Op& op, const inputdata_t& input); +enum class Allowed { Yes, No }; +template +void add_conditional(const Allowed val, Op &op, const inputdata_t &input); //------------------------------------------------------------------------------ // Implementation: JSON deserialization //------------------------------------------------------------------------------ // TODO: convert if-else to switch -template -Op input_to_op(const inputdata_t& input) { +template +Op input_to_op(const inputdata_t &input) { // load operation identifier std::string name; Parser::get_value(name, "name", input); @@ -1001,7 +1061,7 @@ Op input_to_op(const inputdata_t& input) { if (name == "pauli") return input_to_op_pauli(input); - //Control-flow + // Control-flow if (name == "jump") return input_to_op_jump(input); if (name == "mark") @@ -1032,32 +1092,30 @@ json_t op_to_json(const Op &op) { return ret; } - -void to_json(json_t &js, const OpType& type) { +void to_json(json_t &js, const OpType &type) { std::stringstream ss; ss << type; js = ss.str(); } - -void to_json(json_t &js, const DataSubType& subtype) { +void to_json(json_t &js, const DataSubType &subtype) { std::stringstream ss; ss << subtype; js = ss.str(); } - //------------------------------------------------------------------------------ // Implementation: Gates, measure, reset deserialization //------------------------------------------------------------------------------ -template -void add_conditional(const Allowed allowed, Op& op, const inputdata_t& input) { +template +void add_conditional(const Allowed allowed, Op &op, const inputdata_t &input) { // Check conditional if (Parser::check_key("conditional", input)) { // If instruction isn't allow to be conditional throw an exception if (allowed == Allowed::No) { - throw std::invalid_argument("Invalid instruction: \"" + op.name + "\" cannot be conditional."); + throw std::invalid_argument("Invalid instruction: \"" + op.name + + "\" cannot be conditional."); } // If instruction is allowed to be conditional add parameters Parser::get_value(op.conditional_reg, "conditional", input); @@ -1065,8 +1123,8 @@ void add_conditional(const Allowed allowed, Op& op, const inputdata_t& input) { } } -template -Op input_to_op_gate(const inputdata_t& input) { +template +Op input_to_op_gate(const inputdata_t &input) { Op op; op.type = OpType::gate; Parser::get_value(op.name, "name", input); @@ -1077,7 +1135,7 @@ Op input_to_op_gate(const inputdata_t& input) { // If label is not specified record the gate name as the label std::string label; Parser::get_value(label, "label", input); - if (label != "") + if (label != "") op.string_params = {label}; else op.string_params = {op.name}; @@ -1098,8 +1156,8 @@ Op input_to_op_gate(const inputdata_t& input) { return op; } -template -Op input_to_op_qerror_loc(const inputdata_t& input) { +template +Op input_to_op_qerror_loc(const inputdata_t &input) { Op op; op.type = OpType::qerror_loc; Parser::get_value(op.name, "label", input); @@ -1108,7 +1166,7 @@ Op input_to_op_qerror_loc(const inputdata_t& input) { return op; } -template +template Op input_to_op_barrier(const inputdata_t &input) { Op op; op.type = OpType::barrier; @@ -1119,8 +1177,8 @@ Op input_to_op_barrier(const inputdata_t &input) { return op; } -template -Op input_to_op_measure(const inputdata_t& input) { +template +Op input_to_op_measure(const inputdata_t &input) { Op op; op.type = OpType::measure; op.name = "measure"; @@ -1135,16 +1193,19 @@ Op input_to_op_measure(const inputdata_t& input) { check_empty_qubits(op); check_duplicate_qubits(op); if (op.memory.empty() == false && op.memory.size() != op.qubits.size()) { - throw std::invalid_argument(R"(Invalid measure operation: "memory" and "qubits" are different lengths.)"); + throw std::invalid_argument( + R"(Invalid measure operation: "memory" and "qubits" are different lengths.)"); } - if (op.registers.empty() == false && op.registers.size() != op.qubits.size()) { - throw std::invalid_argument(R"(Invalid measure operation: "register" and "qubits" are different lengths.)"); + if (op.registers.empty() == false && + op.registers.size() != op.qubits.size()) { + throw std::invalid_argument( + R"(Invalid measure operation: "register" and "qubits" are different lengths.)"); } return op; } -template -Op input_to_op_reset(const inputdata_t& input) { +template +Op input_to_op_reset(const inputdata_t &input) { Op op; op.type = OpType::reset; op.name = "reset"; @@ -1159,8 +1220,8 @@ Op input_to_op_reset(const inputdata_t& input) { return op; } -template -Op input_to_op_initialize(const inputdata_t& input) { +template +Op input_to_op_initialize(const inputdata_t &input) { Op op; op.type = OpType::initialize; op.name = "initialize"; @@ -1176,8 +1237,8 @@ Op input_to_op_initialize(const inputdata_t& input) { check_length_params(op, 1ULL << op.qubits.size()); return op; } -template -Op input_to_op_pauli(const inputdata_t& input){ +template +Op input_to_op_pauli(const inputdata_t &input) { Op op; op.type = OpType::gate; op.name = "pauli"; @@ -1188,7 +1249,7 @@ Op input_to_op_pauli(const inputdata_t& input){ // If label is not specified record the gate name as the label std::string label; Parser::get_value(label, "label", input); - if (label != "") + if (label != "") op.string_params.push_back(label); else op.string_params.push_back(op.name); @@ -1206,16 +1267,19 @@ Op input_to_op_pauli(const inputdata_t& input){ //------------------------------------------------------------------------------ // Implementation: Boolean Functions //------------------------------------------------------------------------------ -template -Op input_to_op_bfunc(const inputdata_t& input) { +template +Op input_to_op_bfunc(const inputdata_t &input) { Op op; op.type = OpType::bfunc; op.name = "bfunc"; op.string_params.resize(2); std::string relation; - Parser::get_value(op.string_params[0], "mask", input); // mask hexadecimal string - Parser::get_value(op.string_params[1], "val", input); // value hexadecimal string - Parser::get_value(relation, "relation", input); // relation string + Parser::get_value(op.string_params[0], "mask", + input); // mask hexadecimal string + Parser::get_value(op.string_params[1], "val", + input); // value hexadecimal string + Parser::get_value(relation, "relation", + input); // relation string // Load single register / memory bit for storing result uint_t tmp; if (Parser::get_value(tmp, "register", input)) { @@ -1224,24 +1288,25 @@ Op input_to_op_bfunc(const inputdata_t& input) { if (Parser::get_value(tmp, "memory", input)) { op.memory.push_back(tmp); } - + // Format hex strings Utils::format_hex_inplace(op.string_params[0]); Utils::format_hex_inplace(op.string_params[1]); const stringmap_t comp_table({ - {"==", RegComparison::Equal}, - {"!=", RegComparison::NotEqual}, - {"<", RegComparison::Less}, - {"<=", RegComparison::LessEqual}, - {">", RegComparison::Greater}, - {">=", RegComparison::GreaterEqual}, + {"==", RegComparison::Equal}, + {"!=", RegComparison::NotEqual}, + {"<", RegComparison::Less}, + {"<=", RegComparison::LessEqual}, + {">", RegComparison::Greater}, + {">=", RegComparison::GreaterEqual}, }); auto it = comp_table.find(relation); if (it == comp_table.end()) { std::stringstream msg; - msg << "Invalid bfunc relation string :\"" << it->first << "\"." << std::endl; + msg << "Invalid bfunc relation string :\"" << it->first << "\"." + << std::endl; throw std::invalid_argument(msg.str()); } else { op.bfunc = it->second; @@ -1252,13 +1317,14 @@ Op input_to_op_bfunc(const inputdata_t& input) { // Validation if (op.registers.empty()) { - throw std::invalid_argument("Invalid measure operation: \"register\" is empty."); + throw std::invalid_argument( + "Invalid measure operation: \"register\" is empty."); } return op; } -template -Op input_to_op_roerror(const inputdata_t& input) { +template +Op input_to_op_roerror(const inputdata_t &input) { Op op; op.type = OpType::roerror; op.name = "roerror"; @@ -1273,8 +1339,8 @@ Op input_to_op_roerror(const inputdata_t& input) { //------------------------------------------------------------------------------ // Implementation: Matrix and Kraus deserialization //------------------------------------------------------------------------------ -template -Op input_to_op_unitary(const inputdata_t& input) { +template +Op input_to_op_unitary(const inputdata_t &input) { Op op; op.type = OpType::matrix; op.name = "unitary"; @@ -1300,8 +1366,8 @@ Op input_to_op_unitary(const inputdata_t& input) { add_conditional(Allowed::Yes, op, input); return op; } -template -Op input_to_op_diagonal(const inputdata_t& input) { +template +Op input_to_op_diagonal(const inputdata_t &input) { Op op; op.type = OpType::diagonal_matrix; op.name = "diagonal"; @@ -1329,8 +1395,8 @@ Op input_to_op_diagonal(const inputdata_t& input) { add_conditional(Allowed::Yes, op, input); return op; } -template -Op input_to_op_superop(const inputdata_t& input) { +template +Op input_to_op_superop(const inputdata_t &input) { // Warning: we don't check superoperator is valid! Op op; op.type = OpType::superop; @@ -1347,8 +1413,8 @@ Op input_to_op_superop(const inputdata_t& input) { } return op; } -template -Op input_to_op_multiplexer(const inputdata_t& input) { +template +Op input_to_op_multiplexer(const inputdata_t &input) { // Parse parameters reg_t qubits; std::vector mats; @@ -1362,8 +1428,8 @@ Op input_to_op_multiplexer(const inputdata_t& input) { add_conditional(Allowed::Yes, op, input); return op; } -template -Op input_to_op_kraus(const inputdata_t& input) { +template +Op input_to_op_kraus(const inputdata_t &input) { Op op; op.type = OpType::kraus; op.name = "kraus"; @@ -1378,8 +1444,8 @@ Op input_to_op_kraus(const inputdata_t& input) { return op; } -template -Op input_to_op_noise_switch(const inputdata_t& input) { +template +Op input_to_op_noise_switch(const inputdata_t &input) { Op op; op.type = OpType::noise_switch; op.name = "noise_switch"; @@ -1392,48 +1458,53 @@ Op input_to_op_noise_switch(const inputdata_t& input) { //------------------------------------------------------------------------------ // Implementation: Set state //------------------------------------------------------------------------------ -template +template Op input_to_op_set_vector(const inputdata_t &input, OpType op_type) { Op op; op.type = op_type; - const inputdata_t& params = Parser::get_value("params", input); - op.params = Parser::template get_list_elem>(params, 0); + const inputdata_t ¶ms = Parser::get_value("params", input); + op.params = + Parser::template get_list_elem>( + params, 0); Parser::get_value(op.name, "name", input); Parser::get_value(op.qubits, "qubits", input); add_conditional(Allowed::No, op, input); return op; } -template +template Op input_to_op_set_matrix(const inputdata_t &input, OpType op_type) { Op op; op.type = op_type; - const inputdata_t& params = Parser::get_value("params", input); - op.mats.push_back(Parser::template get_list_elem(params, 0)); + const inputdata_t ¶ms = Parser::get_value("params", input); + op.mats.push_back( + Parser::template get_list_elem(params, 0)); Parser::get_value(op.name, "name", input); Parser::get_value(op.qubits, "qubits", input); add_conditional(Allowed::No, op, input); return op; } -template +template Op input_to_op_set_clifford(const inputdata_t &input, OpType op_type) { Op op; op.type = op_type; - const inputdata_t& params = Parser::get_value("params", input); - op.clifford = Parser::template get_list_elem(params, 0); + const inputdata_t ¶ms = Parser::get_value("params", input); + op.clifford = Parser::template get_list_elem( + params, 0); Parser::get_value(op.name, "name", input); Parser::get_value(op.qubits, "qubits", input); add_conditional(Allowed::No, op, input); return op; } -template +template Op input_to_op_set_mps(const inputdata_t &input, OpType op_type) { Op op; op.type = op_type; - const inputdata_t& params = Parser::get_value("params", input); - op.mps = Parser::template get_list_elem(params, 0); + const inputdata_t ¶ms = Parser::get_value("params", input); + op.mps = + Parser::template get_list_elem(params, 0); Parser::get_value(op.name, "name", input); Parser::get_value(op.qubits, "qubits", input); @@ -1444,22 +1515,18 @@ Op input_to_op_set_mps(const inputdata_t &input, OpType op_type) { //------------------------------------------------------------------------------ // Implementation: Save data deserialization //------------------------------------------------------------------------------ -template -Op input_to_op_save_default(const inputdata_t& input, OpType op_type) { +template +Op input_to_op_save_default(const inputdata_t &input, OpType op_type) { Op op; op.type = op_type; Parser::get_value(op.name, "name", input); // Get subtype - static const std::unordered_map subtypes { - {"single", DataSubType::single}, - {"c_single", DataSubType::c_single}, - {"average", DataSubType::average}, - {"c_average", DataSubType::c_average}, - {"list", DataSubType::list}, - {"c_list", DataSubType::c_list}, - {"accum", DataSubType::accum}, - {"c_accum", DataSubType::c_accum}, + static const std::unordered_map subtypes{ + {"single", DataSubType::single}, {"c_single", DataSubType::c_single}, + {"average", DataSubType::average}, {"c_average", DataSubType::c_average}, + {"list", DataSubType::list}, {"c_list", DataSubType::c_list}, + {"accum", DataSubType::accum}, {"c_accum", DataSubType::c_accum}, }; std::string subtype; Parser::get_value(subtype, "snapshot_type", input); @@ -1469,7 +1536,7 @@ Op input_to_op_save_default(const inputdata_t& input, OpType op_type) { "\" in save data instruction."); } op.save_type = subtype_it->second; - + // Get data key op.string_params.emplace_back(""); Parser::get_value(op.string_params[0], "label", input); @@ -1478,26 +1545,30 @@ Op input_to_op_save_default(const inputdata_t& input, OpType op_type) { Parser::get_value(op.qubits, "qubits", input); return op; } -template -Op input_to_op_save_expval(const inputdata_t& input, bool variance) { +template +Op input_to_op_save_expval(const inputdata_t &input, bool variance) { // Initialized default save instruction params - auto op_type = (variance) ? OpType::save_expval_var - : OpType::save_expval; + auto op_type = (variance) ? OpType::save_expval_var : OpType::save_expval; Op op = input_to_op_save_default(input, op_type); // Parse Pauli operator components const auto threshold = 1e-12; // drop small components // Get components - if (Parser::check_key("params", input) && Parser::is_array("params", input)) { + if (Parser::check_key("params", input) && + Parser::is_array("params", input)) { for (const auto &comp_ : Parser::get_value("params", input)) { - const auto& comp = Parser::get_as_list(comp_); + const auto &comp = Parser::get_as_list(comp_); // Get complex coefficient - std::vector coeffs = Parser::template get_list_elem>(comp, 1); + std::vector coeffs = + Parser::template get_list_elem>(comp, + 1); if (std::abs(coeffs[0]) > threshold || std::abs(coeffs[1]) > threshold) { - std::string pauli = Parser::template get_list_elem(comp, 0); + std::string pauli = + Parser::template get_list_elem(comp, 0); if (pauli.size() != op.qubits.size()) { - throw std::invalid_argument(std::string("Invalid expectation value save instruction ") + - "(Pauli label does not match qubit number.)."); + throw std::invalid_argument( + std::string("Invalid expectation value save instruction ") + + "(Pauli label does not match qubit number.)."); } op.expval_params.emplace_back(pauli, coeffs[0], coeffs[1]); } @@ -1516,17 +1587,16 @@ Op input_to_op_save_expval(const inputdata_t& input, bool variance) { return op; } -template -Op input_to_op_save_amps(const inputdata_t& input, bool squared) { +template +Op input_to_op_save_amps(const inputdata_t &input, bool squared) { // Initialized default save instruction params - auto op_type = (squared) ? OpType::save_amps_sq - : OpType::save_amps; + auto op_type = (squared) ? OpType::save_amps_sq : OpType::save_amps; Op op = input_to_op_save_default(input, op_type); Parser::get_value(op.int_params, "params", input); return op; } -template +template Op input_to_op_jump(const inputdata_t &input) { Op op; op.type = OpType::jump; @@ -1534,7 +1604,8 @@ Op input_to_op_jump(const inputdata_t &input) { Parser::get_value(op.qubits, "qubits", input); Parser::get_value(op.string_params, "params", input); if (op.string_params.empty()) - throw std::invalid_argument(std::string("Invalid jump (\"params\" field missing).")); + throw std::invalid_argument( + std::string("Invalid jump (\"params\" field missing).")); // Conditional add_conditional(Allowed::Yes, op, input); @@ -1542,7 +1613,7 @@ Op input_to_op_jump(const inputdata_t &input) { return op; } -template +template Op input_to_op_mark(const inputdata_t &input) { Op op; op.type = OpType::mark; @@ -1550,7 +1621,8 @@ Op input_to_op_mark(const inputdata_t &input) { Parser::get_value(op.qubits, "qubits", input); Parser::get_value(op.string_params, "params", input); if (op.string_params.empty()) - throw std::invalid_argument(std::string("Invalid mark (\"params\" field missing).")); + throw std::invalid_argument( + std::string("Invalid mark (\"params\" field missing).")); // Conditional add_conditional(Allowed::No, op, input); @@ -1558,7 +1630,6 @@ Op input_to_op_mark(const inputdata_t &input) { return op; } - //------------------------------------------------------------------------------ } // end namespace Operations //------------------------------------------------------------------------------ diff --git a/src/framework/opset.hpp b/src/framework/opset.hpp old mode 100755 new mode 100644 index 4516c1c0e5..92cc3e2b15 --- a/src/framework/opset.hpp +++ b/src/framework/opset.hpp @@ -15,8 +15,8 @@ #ifndef _aer_framework_opset_hpp_ #define _aer_framework_opset_hpp_ -#include #include "framework/operations.hpp" +#include namespace AER { namespace Operations { @@ -31,7 +31,8 @@ class OpSet { // Hash function so that we can use an enum class as a std::unordered_set // key on older C++11 compilers like GCC 5. struct EnumClassHash { - template size_t operator()(T t) const { + template + size_t operator()(T t) const { return static_cast(t); } }; @@ -41,8 +42,8 @@ class OpSet { using optypeset_t = std::unordered_set; // Public data members - optypeset_t optypes; // A set of op types - stringset_t gates; // A set of names for OpType::gates + optypeset_t optypes; // A set of op types + stringset_t gates; // A set of names for OpType::gates OpSet() = default; diff --git a/src/framework/pybind_basics.hpp b/src/framework/pybind_basics.hpp old mode 100755 new mode 100644 index e32f214482..cfcb1f2fe5 --- a/src/framework/pybind_basics.hpp +++ b/src/framework/pybind_basics.hpp @@ -33,36 +33,48 @@ namespace AerToPy { // Template specialization is used with this function for adding custom // conversion for other types // NOTE: Can this function be replaced by overload py::cast for custom types? -template py::object to_python(T &&obj); +template +py::object to_python(T &&obj); // Move a matrix to Python via conversion to Numpy array -template py::object to_python(matrix &&obj); +template +py::object to_python(matrix &&obj); // Move a Vector to Python via conversion to Numpy array -template py::object to_python(AER::Vector &&obj); +template +py::object to_python(AER::Vector &&obj); // Move a Vector to Python via recusivly calling to_python on elements -template py::object to_python(std::vector &&obj); +template +py::object to_python(std::vector &&obj); -// Move an Unordered string map to Python object by calling to_python on elements -template py::object to_python(std::unordered_map &&obj); +// Move an Unordered string map to Python object by calling to_python on +// elements +template +py::object to_python(std::unordered_map &&obj); // Move an Unordered string map into an existing Python dict template void add_to_python(py::dict &pydata, std::unordered_map &&obj); - // Template specialization for moving numeric std::vectors to Numpy arrays -template <> py::object to_python(std::vector &&obj); -template <> py::object to_python(std::vector &&obj); -template <> py::object to_python(std::vector &&obj); -template <> py::object to_python(std::vector &&obj); -template <> py::object to_python(std::vector> &&obj); -template <> py::object to_python(std::vector> &&obj); +template <> +py::object to_python(std::vector &&obj); +template <> +py::object to_python(std::vector &&obj); +template <> +py::object to_python(std::vector &&obj); +template <> +py::object to_python(std::vector &&obj); +template <> +py::object to_python(std::vector> &&obj); +template <> +py::object to_python(std::vector> &&obj); // Template specialization for JSON // NOTE: this copies rather than moves -template <> py::object to_python(json_t &&obj); +template <> +py::object to_python(json_t &&obj); //------------------------------------------------------------------------------ // Convert To Numpy Arrays @@ -109,7 +121,7 @@ py::object to_python(std::unordered_map &&obj) { template void add_to_python(py::dict &pydata, std::unordered_map &&obj) { - for(auto& elt : obj) { + for (auto &elt : obj) { pydata[elt.first.data()] = to_python(std::move(elt.second)); } } @@ -117,7 +129,7 @@ void add_to_python(py::dict &pydata, std::unordered_map &&obj) { template py::object to_python(std::vector &&obj) { py::list pydata; - for(auto& elt : obj) { + for (auto &elt : obj) { pydata.append(to_python(std::move(elt))); } return std::move(pydata); @@ -169,39 +181,39 @@ py::object to_python(std::vector> &&obj) { template py::array_t to_numpy(matrix &&src) { - std::array shape {static_cast(src.GetRows()), - static_cast(src.GetColumns())}; - matrix* src_ptr = new matrix(std::move(src)); - auto capsule = py::capsule(src_ptr, [](void* p) { delete reinterpret_cast*>(p); }); + std::array shape{static_cast(src.GetRows()), + static_cast(src.GetColumns())}; + matrix *src_ptr = new matrix(std::move(src)); + auto capsule = py::capsule( + src_ptr, [](void *p) { delete reinterpret_cast *>(p); }); return py::array_t(shape, src_ptr->data(), capsule); } template py::array_t to_numpy(AER::Vector &&src) { - AER::Vector* src_ptr = new AER::Vector(std::move(src)); - auto capsule = py::capsule(src_ptr, [](void* p) { - delete reinterpret_cast*>(p); - }); + AER::Vector *src_ptr = new AER::Vector(std::move(src)); + auto capsule = py::capsule( + src_ptr, [](void *p) { delete reinterpret_cast *>(p); }); return py::array_t( - src_ptr->size(), // shape of array - src_ptr->data(), // c-style contiguous strides for vector - capsule // numpy array references this parent + src_ptr->size(), // shape of array + src_ptr->data(), // c-style contiguous strides for vector + capsule // numpy array references this parent ); } - template py::array_t to_numpy(std::vector &&src) { - std::vector* src_ptr = new std::vector(std::move(src)); - auto capsule = py::capsule(src_ptr, [](void* p) { delete reinterpret_cast*>(p); }); + std::vector *src_ptr = new std::vector(std::move(src)); + auto capsule = py::capsule( + src_ptr, [](void *p) { delete reinterpret_cast *>(p); }); return py::array_t( - src_ptr->size(), // shape of array - src_ptr->data(), // c-style contiguous strides for vector - capsule // numpy array references this parent + src_ptr->size(), // shape of array + src_ptr->data(), // c-style contiguous strides for vector + capsule // numpy array references this parent ); } //------------------------------------------------------------------------------ -} // end namespace AerToPy +} // end namespace AerToPy //------------------------------------------------------------------------------ #endif diff --git a/src/framework/pybind_casts.hpp b/src/framework/pybind_casts.hpp index e74b6d22f6..1db098fb7e 100644 --- a/src/framework/pybind_casts.hpp +++ b/src/framework/pybind_casts.hpp @@ -21,55 +21,63 @@ namespace py = pybind11; namespace pybind11 { namespace detail { -template struct type_caster>{ +template +struct type_caster> { using base = type_caster_base>; + public: PYBIND11_TYPE_CASTER(matrix, _("matrix_t")); // Conversion part 1 (Python->C++): - bool load(py::handle src, bool convert){ - // TODO: Check if make sense have to flavors of matrix: F-style and C-style - auto py_matrix = py::cast>(src); - auto c_order = py_matrix.attr("flags").attr("carray").template cast(); - if(py_matrix.ndim() != 2){ - throw std::invalid_argument(std::string("Python: invalid matrix (empty array).")); - } - size_t nrows = py_matrix.shape(0); - size_t ncols = py_matrix.shape(1); - // Matrix looks ok, now we parse it - auto raw_mat = py_matrix.template unchecked<2>(); - if(c_order){ - value = matrix(nrows, ncols, false); - for (size_t r = 0; r < nrows; r++) { - for (size_t c = 0; c < ncols; c++) { - value(r, c) = raw_mat(r, c); - } - } - } else { - value = matrix::copy_from_buffer(nrows, ncols, static_cast(py_matrix.request().ptr)); + bool load(py::handle src, bool convert) { + // TODO: Check if make sense have to flavors of matrix: F-style and C-style + auto py_matrix = py::cast>(src); + auto c_order = py_matrix.attr("flags").attr("carray").template cast(); + if (py_matrix.ndim() != 2) { + throw std::invalid_argument( + std::string("Python: invalid matrix (empty array).")); + } + size_t nrows = py_matrix.shape(0); + size_t ncols = py_matrix.shape(1); + // Matrix looks ok, now we parse it + auto raw_mat = py_matrix.template unchecked<2>(); + if (c_order) { + value = matrix(nrows, ncols, false); + for (size_t r = 0; r < nrows; r++) { + for (size_t c = 0; c < ncols; c++) { + value(r, c) = raw_mat(r, c); + } } - return true; + } else { + value = matrix::copy_from_buffer( + nrows, ncols, static_cast(py_matrix.request().ptr)); + } + return true; } // Conversion part 2 (C++ -> Python): - static py::handle cast(matrix, py::return_value_policy policy, py::handle parent){ - throw std::runtime_error("Casting from matrix to python not supported."); + static py::handle cast(matrix, py::return_value_policy policy, + py::handle parent) { + throw std::runtime_error("Casting from matrix to python not supported."); } }; -template <> struct type_caster{ - using base = type_caster_base; +template <> +struct type_caster { + using base = type_caster_base; + public: - PYBIND11_TYPE_CASTER(AER::Clifford::Clifford, _("clifford")); - // Conversion part 1 (Python->C++): - bool load(py::handle src, bool convert){ - AER::Clifford::build_from(src, value); - return true; - } - // Conversion part 2 (C++ -> Python): - static py::handle cast(AER::Clifford::Clifford, py::return_value_policy policy, py::handle parent){ - throw std::runtime_error("Casting from Clifford to python not supported."); - } + PYBIND11_TYPE_CASTER(AER::Clifford::Clifford, _("clifford")); + // Conversion part 1 (Python->C++): + bool load(py::handle src, bool convert) { + AER::Clifford::build_from(src, value); + return true; + } + // Conversion part 2 (C++ -> Python): + static py::handle cast(AER::Clifford::Clifford, + py::return_value_policy policy, py::handle parent) { + throw std::runtime_error("Casting from Clifford to python not supported."); + } }; -} -} +} // namespace detail +} // namespace pybind11 #endif // _aer_framework_pybind_casts_hpp_ \ No newline at end of file diff --git a/src/framework/pybind_json.hpp b/src/framework/pybind_json.hpp old mode 100755 new mode 100644 index 6aa9dc89da..7ac889c3c2 --- a/src/framework/pybind_json.hpp +++ b/src/framework/pybind_json.hpp @@ -26,18 +26,17 @@ #include #include #include -#include #include -#include #include +#include #include "misc/warnings.hpp" DISABLE_WARNING_PUSH -#include #include -#include #include #include +#include +#include #include DISABLE_WARNING_POP @@ -109,9 +108,9 @@ json_t numpy_to_json_2d(py::array_t arr); template json_t numpy_to_json_3d(py::array_t arr); -json_t iterable_to_json_list(const py::handle& obj); +json_t iterable_to_json_list(const py::handle &obj); -} //end namespace JSON +} // end namespace JSON /******************************************************************************* * @@ -125,190 +124,195 @@ json_t iterable_to_json_list(const py::handle& obj); template json_t JSON::numpy_to_json_1d(py::array_t arr) { - py::buffer_info buf = arr.request(); - if (buf.ndim != 1) { - throw std::runtime_error("Number of dims must be 1"); - } + py::buffer_info buf = arr.request(); + if (buf.ndim != 1) { + throw std::runtime_error("Number of dims must be 1"); + } - T *ptr = (T *) buf.ptr; - size_t D0 = buf.shape[0]; + T *ptr = (T *)buf.ptr; + size_t D0 = buf.shape[0]; - std::vector tbr; // to be returned - for (size_t n0 = 0; n0 < D0; n0++) - tbr.push_back(ptr[n0]); + std::vector tbr; // to be returned + for (size_t n0 = 0; n0 < D0; n0++) + tbr.push_back(ptr[n0]); - return std::move(tbr); + return std::move(tbr); } template json_t JSON::numpy_to_json_2d(py::array_t arr) { - py::buffer_info buf = arr.request(); - if (buf.ndim != 2) { - throw std::runtime_error("Number of dims must be 2"); - } - - T *ptr = (T *) buf.ptr; - size_t D0 = buf.shape[0]; - size_t D1 = buf.shape[1]; - - std::vector > tbr; // to be returned - for (size_t n0 = 0; n0 < D0; n0++) { - std::vector tbr1; - for (size_t n1 = 0; n1 < D1; n1++) { - tbr1.push_back(ptr[n1 + D1*n0]); - } - tbr.push_back(tbr1); + py::buffer_info buf = arr.request(); + if (buf.ndim != 2) { + throw std::runtime_error("Number of dims must be 2"); + } + + T *ptr = (T *)buf.ptr; + size_t D0 = buf.shape[0]; + size_t D1 = buf.shape[1]; + + std::vector> tbr; // to be returned + for (size_t n0 = 0; n0 < D0; n0++) { + std::vector tbr1; + for (size_t n1 = 0; n1 < D1; n1++) { + tbr1.push_back(ptr[n1 + D1 * n0]); } + tbr.push_back(tbr1); + } - return std::move(tbr); - + return std::move(tbr); } template json_t JSON::numpy_to_json_3d(py::array_t arr) { - py::buffer_info buf = arr.request(); - if (buf.ndim != 3) { - throw std::runtime_error("Number of dims must be 3"); - } - T *ptr = (T *) buf.ptr; - size_t D0 = buf.shape[0]; - size_t D1 = buf.shape[1]; - size_t D2 = buf.shape[2]; - - // to be returned - std::vector > > tbr; - for (size_t n0 = 0; n0 < D0; n0++) { - std::vector > tbr1; - for (size_t n1 = 0; n1 < D1; n1++) { - std::vector tbr2; - for (size_t n2 = 0; n2 < D2; n2++) { - tbr2.push_back(ptr[n2 + D2*(n1 + D1*n0)]); - } - tbr1.push_back(tbr2); - } - tbr.push_back(tbr1); + py::buffer_info buf = arr.request(); + if (buf.ndim != 3) { + throw std::runtime_error("Number of dims must be 3"); + } + T *ptr = (T *)buf.ptr; + size_t D0 = buf.shape[0]; + size_t D1 = buf.shape[1]; + size_t D2 = buf.shape[2]; + + // to be returned + std::vector>> tbr; + for (size_t n0 = 0; n0 < D0; n0++) { + std::vector> tbr1; + for (size_t n1 = 0; n1 < D1; n1++) { + std::vector tbr2; + for (size_t n2 = 0; n2 < D2; n2++) { + tbr2.push_back(ptr[n2 + D2 * (n1 + D1 * n0)]); + } + tbr1.push_back(tbr2); } + tbr.push_back(tbr1); + } - return std::move(tbr); - + return std::move(tbr); } template json_t JSON::numpy_to_json(py::array_t arr) { - py::buffer_info buf = arr.request(); - - if (buf.ndim == 1) { - return JSON::numpy_to_json_1d(arr); - } else if (buf.ndim == 2) { - return JSON::numpy_to_json_2d(arr); - } else if (buf.ndim == 3) { - return JSON::numpy_to_json_3d(arr); - } else { - throw std::runtime_error("Invalid number of dimensions!"); - } - json_t tbr; - return tbr; + py::buffer_info buf = arr.request(); + + if (buf.ndim == 1) { + return JSON::numpy_to_json_1d(arr); + } else if (buf.ndim == 2) { + return JSON::numpy_to_json_2d(arr); + } else if (buf.ndim == 3) { + return JSON::numpy_to_json_3d(arr); + } else { + throw std::runtime_error("Invalid number of dimensions!"); + } + json_t tbr; + return tbr; } -json_t JSON::iterable_to_json_list(const py::handle& obj){ - json_t js = nl::json::array(); - for (py::handle value: obj) { - js.push_back(value); - } - return js; +json_t JSON::iterable_to_json_list(const py::handle &obj) { + json_t js = nl::json::array(); + for (py::handle value : obj) { + js.push_back(value); + } + return js; } void std::to_json(json_t &js, const py::handle &obj) { - static py::object PyNoiseModel = py::module::import("qiskit_aer.noise.noise_model").attr("NoiseModel"); - static py::object PyQasmQobj = py::module::import("qiskit.qobj.qasm_qobj").attr("QasmQobj"); - static py::object PyQasmQobjHeader = py::module::import("qiskit.qobj.common").attr("QobjExperimentHeader"); - if (py::isinstance(obj)) { - js = obj.cast(); - } else if (py::isinstance(obj)) { - js = obj.cast(); - } else if (py::isinstance(obj)) { - js = obj.cast(); - } else if (py::isinstance(obj)) { - js = obj.cast(); - } else if (py::isinstance(obj) || py::isinstance(obj)) { - js = JSON::iterable_to_json_list(obj); - } else if (py::isinstance(obj)) { - for (auto item : py::cast(obj)) { - js[item.first.cast()] = item.second; - } - } else if (py::isinstance >(obj)) { - js = JSON::numpy_to_json(obj.cast >()); - } else if (py::isinstance > >(obj)) { - js = JSON::numpy_to_json(obj.cast, py::array::c_style> >()); - } else if (obj.is_none()) { - return; - } else if (py::isinstance(obj, PyNoiseModel)){ - std::to_json(js, obj.attr("to_dict")()); - } else if (py::isinstance(obj, PyQasmQobj)){ - std::to_json(js, obj.attr("to_dict")()); - } else if (py::isinstance(obj, PyQasmQobjHeader)){ - std::to_json(js, obj.attr("to_dict")()); + static py::object PyNoiseModel = + py::module::import("qiskit_aer.noise.noise_model").attr("NoiseModel"); + static py::object PyQasmQobj = + py::module::import("qiskit.qobj.qasm_qobj").attr("QasmQobj"); + static py::object PyQasmQobjHeader = + py::module::import("qiskit.qobj.common").attr("QobjExperimentHeader"); + if (py::isinstance(obj)) { + js = obj.cast(); + } else if (py::isinstance(obj)) { + js = obj.cast(); + } else if (py::isinstance(obj)) { + js = obj.cast(); + } else if (py::isinstance(obj)) { + js = obj.cast(); + } else if (py::isinstance(obj) || py::isinstance(obj)) { + js = JSON::iterable_to_json_list(obj); + } else if (py::isinstance(obj)) { + for (auto item : py::cast(obj)) { + js[item.first.cast()] = item.second; + } + } else if (py::isinstance>(obj)) { + js = JSON::numpy_to_json( + obj.cast>()); + } else if (py::isinstance>>(obj)) { + js = JSON::numpy_to_json( + obj.cast, py::array::c_style>>()); + } else if (obj.is_none()) { + return; + } else if (py::isinstance(obj, PyNoiseModel)) { + std::to_json(js, obj.attr("to_dict")()); + } else if (py::isinstance(obj, PyQasmQobj)) { + std::to_json(js, obj.attr("to_dict")()); + } else if (py::isinstance(obj, PyQasmQobjHeader)) { + std::to_json(js, obj.attr("to_dict")()); + } else { + auto type_str = std::string(py::str(obj.get_type())); + if (type_str == "" || + type_str == "" || + type_str == "" || + type_str == "") { + auto tmp = obj.cast>(); + js.push_back(tmp.real()); + js.push_back(tmp.imag()); + } else if (type_str == "" || + type_str == "" || + type_str == "" || + type_str == "") { + js = obj.cast(); + } else if (type_str == "" || + type_str == "") { + js = obj.cast(); + } else if (py::isinstance( + obj)) { // last one to avoid intercepting numpy arrays, etc + js = JSON::iterable_to_json_list(obj); } else { - auto type_str = std::string(py::str(obj.get_type())); - if ( type_str == "" - || type_str == "" - || type_str == "" - || type_str == "" ) { - auto tmp = obj.cast>(); - js.push_back(tmp.real()); - js.push_back(tmp.imag()); - } else if ( type_str == "" - || type_str == "" - || type_str == "" - || type_str == "" ) { - js = obj.cast(); - } else if ( type_str == "" - || type_str == "" ) { - js = obj.cast(); - } else if ( py::isinstance(obj) ){ // last one to avoid intercepting numpy arrays, etc - js = JSON::iterable_to_json_list(obj); - } else { - throw std::runtime_error("to_json not implemented for this type of object: " + std::string(py::str(obj.get_type()))); - } + throw std::runtime_error( + "to_json not implemented for this type of object: " + + std::string(py::str(obj.get_type()))); } + } } void std::from_json(const json_t &js, py::object &o) { - if (js.is_boolean()) { - o = py::bool_(js.get()); - } else if (js.is_number()) { - if (js.is_number_float()) { - o = py::float_(js.get()); - } else if (js.is_number_unsigned()) { - o = py::int_(js.get()); - } else { - o = py::int_(js.get()); - } - } else if (js.is_string()) { - o = py::str(js.get()); - } else if (js.is_array()) { - std::vector obj(js.size()); - for (auto i = 0; i < js.size(); i++) - { - py::object tmp; - from_json(js[i], tmp); - obj[i] = tmp; - } - o = py::cast(obj); - } else if (js.is_object()) { - py::dict obj; - for (json_t::const_iterator it = js.cbegin(); it != js.cend(); ++it) - { - py::object tmp; - from_json(it.value(), tmp); - obj[py::str(it.key())] = tmp; - } - o = std::move(obj); - } else if (js.is_null()) { - o = py::none(); + if (js.is_boolean()) { + o = py::bool_(js.get()); + } else if (js.is_number()) { + if (js.is_number_float()) { + o = py::float_(js.get()); + } else if (js.is_number_unsigned()) { + o = py::int_(js.get()); } else { - throw std::runtime_error("from_json not implemented for this json::type: " + js.dump()); + o = py::int_(js.get()); + } + } else if (js.is_string()) { + o = py::str(js.get()); + } else if (js.is_array()) { + std::vector obj(js.size()); + for (auto i = 0; i < js.size(); i++) { + py::object tmp; + from_json(js[i], tmp); + obj[i] = tmp; + } + o = py::cast(obj); + } else if (js.is_object()) { + py::dict obj; + for (json_t::const_iterator it = js.cbegin(); it != js.cend(); ++it) { + py::object tmp; + from_json(it.value(), tmp); + obj[py::str(it.key())] = tmp; } + o = std::move(obj); + } else if (js.is_null()) { + o = py::none(); + } else { + throw std::runtime_error("from_json not implemented for this json::type: " + + js.dump()); + } } //------------------------------------------------------------------------------ diff --git a/src/framework/python_parser.hpp b/src/framework/python_parser.hpp index e2867a8a0c..1e089cd349 100644 --- a/src/framework/python_parser.hpp +++ b/src/framework/python_parser.hpp @@ -19,136 +19,139 @@ #include "json_parser.hpp" #include "pybind_json.hpp" -namespace AER{ +namespace AER { template <> struct Parser { - Parser() = delete; - - static bool check_key(const std::string& key, const py::handle& po){ - if(py::isinstance(po)){ - return !py::cast(po)[key.c_str()].is_none(); - } - return py::hasattr(po, key.c_str()); - } - - static bool check_keys(const std::vector& keys, const py::handle& po) { - bool pass = true; - for (const auto &s : keys){ - pass &= check_key(s, po); - } - return pass; - } - - static py::object get_py_value(const std::string& key, const py::handle& po){ - if(py::isinstance(po)){ - return py::cast(po)[key.c_str()]; - } - return po.attr(key.c_str()); - } - - static bool get_value(py::object& var, const std::string& key, const py::handle& po) { - if(check_key(key, po)) { - var = get_py_value(key, po); - return true; - } else { - return false; - } - } - - template - static bool get_value(T &var, const std::string& key, const py::handle& po){ - if(check_key(key, po)) { - var = get_py_value(key, po).cast(); - return true; - } else { - return false; - } - } - - static void convert_to_json(json_t &var, const py::handle& po){ - if(py::hasattr(po, "to_dict")){ - std::to_json(var, po.attr("to_dict")()); - }else if(py::isinstance(po)){ - var = nl::json::array(); - for(auto item: po){ - json_t item_js; - convert_to_json(item_js, item); - var.push_back(item_js); - } - }else{ - std::to_json(var, po); - } - } - - static py::object get_value(const std::string& key, const py::handle& po){ - return get_py_value(key, po); - } - - static bool is_array(const py::handle& po){ - return py::isinstance(po) || py::isinstance(po); - } - - static bool is_array(const std::string& key, const py::handle& po) { - py::object the_list = get_py_value(key, po); - return is_array(the_list); - } - - static bool is_list_like(const py::handle& po){ - return is_array(po) || py::isinstance(po); - } - - static py::list get_as_list(const py::handle& po){ - if(!is_list_like(po)){ - throw std::runtime_error("Object is not list like!"); - } - return py::cast(po); - } - - static py::list get_list(const std::string& key, const py::handle& po){ - py::object the_list = get_py_value(key, po); - if(!is_array(the_list)){ - throw std::runtime_error("Object " + key + "is not a list!"); - } - return py::cast(the_list); - } - - static bool is_number(const py::handle& po){ - return py::isinstance(po) || py::isinstance(po); - } - - static bool is_number(const std::string& key, const py::handle& po) { - py::object key_po = get_py_value(key, po); - return is_number(key_po); - } - - template - static T get_list_elem(const py::list& po, unsigned int i){ - return py::cast(po[i]).cast(); - } - - template - static T get_list_elem(const py::handle& po, unsigned int i){ - auto py_list = get_as_list(po); - return get_list_elem(py_list, i); - } - - static std::string dump(const py::handle& po){ - json_t js; - convert_to_json(js, po); - return js.dump(); - } + Parser() = delete; + + static bool check_key(const std::string &key, const py::handle &po) { + if (py::isinstance(po)) { + return !py::cast(po)[key.c_str()].is_none(); + } + return py::hasattr(po, key.c_str()); + } + + static bool check_keys(const std::vector &keys, + const py::handle &po) { + bool pass = true; + for (const auto &s : keys) { + pass &= check_key(s, po); + } + return pass; + } + + static py::object get_py_value(const std::string &key, const py::handle &po) { + if (py::isinstance(po)) { + return py::cast(po)[key.c_str()]; + } + return po.attr(key.c_str()); + } + + static bool get_value(py::object &var, const std::string &key, + const py::handle &po) { + if (check_key(key, po)) { + var = get_py_value(key, po); + return true; + } else { + return false; + } + } + + template + static bool get_value(T &var, const std::string &key, const py::handle &po) { + if (check_key(key, po)) { + var = get_py_value(key, po).cast(); + return true; + } else { + return false; + } + } + + static void convert_to_json(json_t &var, const py::handle &po) { + if (py::hasattr(po, "to_dict")) { + std::to_json(var, po.attr("to_dict")()); + } else if (py::isinstance(po)) { + var = nl::json::array(); + for (auto item : po) { + json_t item_js; + convert_to_json(item_js, item); + var.push_back(item_js); + } + } else { + std::to_json(var, po); + } + } + + static py::object get_value(const std::string &key, const py::handle &po) { + return get_py_value(key, po); + } + + static bool is_array(const py::handle &po) { + return py::isinstance(po) || py::isinstance(po); + } + + static bool is_array(const std::string &key, const py::handle &po) { + py::object the_list = get_py_value(key, po); + return is_array(the_list); + } + + static bool is_list_like(const py::handle &po) { + return is_array(po) || py::isinstance(po); + } + + static py::list get_as_list(const py::handle &po) { + if (!is_list_like(po)) { + throw std::runtime_error("Object is not list like!"); + } + return py::cast(po); + } + + static py::list get_list(const std::string &key, const py::handle &po) { + py::object the_list = get_py_value(key, po); + if (!is_array(the_list)) { + throw std::runtime_error("Object " + key + "is not a list!"); + } + return py::cast(the_list); + } + + static bool is_number(const py::handle &po) { + return py::isinstance(po) || py::isinstance(po); + } + + static bool is_number(const std::string &key, const py::handle &po) { + py::object key_po = get_py_value(key, po); + return is_number(key_po); + } + + template + static T get_list_elem(const py::list &po, unsigned int i) { + return py::cast(po[i]).cast(); + } + + template + static T get_list_elem(const py::handle &po, unsigned int i) { + auto py_list = get_as_list(po); + return get_list_elem(py_list, i); + } + + static std::string dump(const py::handle &po) { + json_t js; + convert_to_json(js, po); + return js.dump(); + } }; template <> -bool Parser::get_value(json_t &var, const std::string& key, const py::handle& po){ - py::object ret_po; - auto success = get_value(ret_po, key, po); - if(success){ - convert_to_json(var, ret_po); - } - return success; -} +bool Parser::get_value(json_t &var, const std::string &key, + const py::handle &po) { + py::object ret_po; + auto success = get_value(ret_po, key, po); + if (success) { + convert_to_json(var, ret_po); + } + return success; } +} // namespace AER #endif // _aer_framework_python_parser_hpp_ diff --git a/src/framework/qobj.hpp b/src/framework/qobj.hpp old mode 100755 new mode 100644 index 7eb7313a1b..0e502b978c --- a/src/framework/qobj.hpp +++ b/src/framework/qobj.hpp @@ -30,7 +30,7 @@ namespace AER { //============================================================================ class Qobj { - public: +public: //---------------------------------------------------------------- // Constructors //---------------------------------------------------------------- @@ -46,12 +46,12 @@ class Qobj { //---------------------------------------------------------------- // Data //---------------------------------------------------------------- - std::string id; // qobj identifier passed to result - std::string type = "QASM"; // currently we only support QASM - std::vector circuits; // List of circuits - json_t header; // (optional) passed through to result - json_t config; // (optional) qobj level config data - Noise::NoiseModel noise_model; // (optional) noise model + std::string id; // qobj identifier passed to result + std::string type = "QASM"; // currently we only support QASM + std::vector circuits; // List of circuits + json_t header; // (optional) passed through to result + json_t config; // (optional) qobj level config data + Noise::NoiseModel noise_model; // (optional) noise model }; //============================================================================ @@ -67,7 +67,7 @@ Qobj::Qobj(const inputdata_t &input) { if (Parser::get_value(id, "qobj_id", input) == false) { throw std::invalid_argument(R"(Invalid qobj: no "qobj_id" field)"); }; - Parser::get_value(type, "type", input); + Parser::get_value(type, "type", input); if (type != "QASM") { throw std::invalid_argument(R"(Invalid qobj: "type" != "QASM".)"); }; @@ -100,12 +100,13 @@ Qobj::Qobj(const inputdata_t &input) { } // Check for fixed simulator seed - // If simulator seed is set, each experiment will be set to a fixed (but different) seed - // Otherwise a random seed will be chosen for each experiment + // If simulator seed is set, each experiment will be set to a fixed (but + // different) seed Otherwise a random seed will be chosen for each experiment int_t seed = -1; uint_t seed_shift = 0; - bool has_simulator_seed = Parser::get_value(seed, "seed_simulator", config); // config always json - const auto& circs = Parser::get_list("experiments", input); + bool has_simulator_seed = Parser::get_value( + seed, "seed_simulator", config); // config always json + const auto &circs = Parser::get_list("experiments", input); const size_t num_circs = circs.size(); // Check if parameterized qobj @@ -128,7 +129,7 @@ Qobj::Qobj(const inputdata_t &input) { } // Load circuits - for (size_t i=0; i(circs[i]), config, truncation); @@ -141,7 +142,7 @@ Qobj::Qobj(const inputdata_t &input) { const auto circ_params = param_table[i]; const size_t num_params = circ_params[0].second.size(); const size_t num_instr = circuit.ops.size(); - for (size_t j=0; j= num_instr) { - throw std::invalid_argument(R"(Invalid parameterized qobj: instruction position out of range)"); + throw std::invalid_argument( + R"(Invalid parameterized qobj: instruction position out of range)"); } auto &op = param_circuit.ops[instr_pos]; if (param_pos >= op.params.size()) { - throw std::invalid_argument(R"(Invalid parameterized qobj: instruction param position out of range)"); + throw std::invalid_argument( + R"(Invalid parameterized qobj: instruction param position out of range)"); } if (j >= params.second.size()) { - throw std::invalid_argument(R"(Invalid parameterized qobj: parameterization value out of range)"); + throw std::invalid_argument( + R"(Invalid parameterized qobj: parameterization value out of range)"); } // Update the param op.params[param_pos] = params.second[j]; } // Run truncation. - // TODO: Truncation should be performed and parameters should be resolved after it. - // However, parameters are associated with indices of instructions, which can be changed in truncation. - // Therefore, current implementation performs truncation for each parameter set. + // TODO: Truncation should be performed and parameters should be + // resolved after it. However, parameters are associated with indices of + // instructions, which can be changed in truncation. Therefore, current + // implementation performs truncation for each parameter set. if (truncation) param_circuit.set_params(true); circuits.push_back(std::move(param_circuit)); @@ -177,13 +182,13 @@ Qobj::Qobj(const inputdata_t &input) { if (!has_simulator_seed) { seed = circuits[0].seed; } - for (auto& circuit : circuits) { + for (auto &circuit : circuits) { circuit.seed = seed + seed_shift; - seed_shift += 2113; // Shift the seed + seed_shift += 2113; // Shift the seed } } //------------------------------------------------------------------------------ -} // namespace AER +} // namespace AER //------------------------------------------------------------------------------ #endif diff --git a/src/framework/results/data/data.hpp b/src/framework/results/data/data.hpp index 878c117af0..82ccdd8650 100644 --- a/src/framework/results/data/data.hpp +++ b/src/framework/results/data/data.hpp @@ -16,22 +16,22 @@ #define _aer_framework_results_data_hpp_ // Data primatives -#include "framework/results/data/subtypes/data_map.hpp" #include "framework/results/data/subtypes/accum_data.hpp" #include "framework/results/data/subtypes/average_data.hpp" +#include "framework/results/data/subtypes/data_map.hpp" #include "framework/results/data/subtypes/list_data.hpp" #include "framework/results/data/subtypes/single_data.hpp" // Data Containers -#include "framework/results/data/mixins/data_creg.hpp" -#include "framework/results/data/mixins/data_rvalue.hpp" -#include "framework/results/data/mixins/data_rvector.hpp" -#include "framework/results/data/mixins/data_rdict.hpp" +#include "framework/results/data/mixins/data_cdict.hpp" #include "framework/results/data/mixins/data_cmatrix.hpp" +#include "framework/results/data/mixins/data_creg.hpp" #include "framework/results/data/mixins/data_cvector.hpp" -#include "framework/results/data/mixins/data_cdict.hpp" #include "framework/results/data/mixins/data_json.hpp" #include "framework/results/data/mixins/data_mps.hpp" +#include "framework/results/data/mixins/data_rdict.hpp" +#include "framework/results/data/mixins/data_rvalue.hpp" +#include "framework/results/data/mixins/data_rvector.hpp" namespace AER { @@ -65,60 +65,60 @@ struct Data : public DataCreg, //---------------------------------------------------------------- template void add_single(const T &data, const std::string &outer_key, - const Args &... inner_keys); + const Args &...inner_keys); template void add_single(T &data, const std::string &outer_key, - const Args &... inner_keys); + const Args &...inner_keys); template void add_single(T &&data, const std::string &outer_key, - const Args &... inner_keys); + const Args &...inner_keys); //---------------------------------------------------------------- // Add list data //---------------------------------------------------------------- template void add_list(const T &data, const std::string &outer_key, - const Args &... inner_keys); + const Args &...inner_keys); template void add_list(T &data, const std::string &outer_key, - const Args &... inner_keys); + const Args &...inner_keys); template void add_list(T &&data, const std::string &outer_key, - const Args &... inner_keys); + const Args &...inner_keys); //---------------------------------------------------------------- // Add accum data //---------------------------------------------------------------- template void add_accum(const T &data, const std::string &outer_key, - const Args &... inner_keys); + const Args &...inner_keys); template void add_accum(T &data, const std::string &outer_key, - const Args &... inner_keys); + const Args &...inner_keys); template void add_accum(T &&data, const std::string &outer_key, - const Args &... inner_keys); + const Args &...inner_keys); //---------------------------------------------------------------- // Add average data //---------------------------------------------------------------- template void add_average(const T &data, const std::string &outer_key, - const Args &... inner_keys); + const Args &...inner_keys); template void add_average(T &data, const std::string &outer_key, - const Args &... inner_keys); + const Args &...inner_keys); template void add_average(T &&data, const std::string &outer_key, - const Args &... inner_keys); + const Args &...inner_keys); //---------------------------------------------------------------- // Utility and config @@ -162,87 +162,86 @@ json_t Data::to_json() { return result; } - template void Data::add_single(const T &data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { DataMap::add(data, outer_key, inner_keys...); } template void Data::add_single(T &data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { DataMap::add(data, outer_key, inner_keys...); } template void Data::add_single(T &&data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { DataMap::add(std::move(data), outer_key, inner_keys...); } template void Data::add_list(const T &data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { DataMap::add(data, outer_key, inner_keys...); } template void Data::add_list(T &data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { DataMap::add(data, outer_key, inner_keys...); } template void Data::add_list(T &&data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { DataMap::add(std::move(data), outer_key, inner_keys...); } template void Data::add_accum(const T &data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { DataMap::add(data, outer_key, inner_keys...); } template void Data::add_accum(T &data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { DataMap::add(data, outer_key, inner_keys...); } template void Data::add_accum(T &&data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { DataMap::add(std::move(data), outer_key, inner_keys...); } template void Data::add_average(const T &data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { DataMap::add(data, outer_key, inner_keys...); } template void Data::add_average(T &data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { DataMap::add(data, outer_key, inner_keys...); } template void Data::add_average(T &&data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { DataMap::add(std::move(data), outer_key, inner_keys...); } diff --git a/src/framework/results/data/metadata.hpp b/src/framework/results/data/metadata.hpp index 969179ca3a..cf7cb39bb1 100644 --- a/src/framework/results/data/metadata.hpp +++ b/src/framework/results/data/metadata.hpp @@ -33,15 +33,15 @@ struct Metadata : public DataMap, //---------------------------------------------------------------- template void add(const json_t &data, const std::string &outer_key, - const Args &... inner_keys); + const Args &...inner_keys); template void add(json_t &data, const std::string &outer_key, - const Args &... inner_keys); + const Args &...inner_keys); template void add(json_t &&data, const std::string &outer_key, - const Args &... inner_keys); + const Args &...inner_keys); //---------------------------------------------------------------- // Add general metadata @@ -51,13 +51,13 @@ struct Metadata : public DataMap, //---------------------------------------------------------------- template void add(const T &data, const std::string &outer_key, - const Args &... inner_keys); + const Args &...inner_keys); template - void add(T &data, const std::string &outer_key, const Args &... inner_keys); + void add(T &data, const std::string &outer_key, const Args &...inner_keys); template - void add(T &&data, const std::string &outer_key, const Args &... inner_keys); + void add(T &&data, const std::string &outer_key, const Args &...inner_keys); // Serialize engine data to JSON json_t to_json(); @@ -87,7 +87,7 @@ json_t Metadata::to_json() { template void Metadata::add(const T &data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { json_t tmp = data; DataMap::add( std::move(tmp), outer_key, inner_keys...); @@ -95,7 +95,7 @@ void Metadata::add(const T &data, const std::string &outer_key, template void Metadata::add(T &data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { json_t tmp = data; DataMap::add( std::move(tmp), outer_key, inner_keys...); @@ -103,7 +103,7 @@ void Metadata::add(T &data, const std::string &outer_key, template void Metadata::add(T &&data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { json_t tmp = data; DataMap::add( std::move(tmp), outer_key, inner_keys...); @@ -111,21 +111,21 @@ void Metadata::add(T &&data, const std::string &outer_key, template void Metadata::add(const json_t &data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { DataMap::add(data, outer_key, inner_keys...); } template void Metadata::add(json_t &data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { DataMap::add(data, outer_key, inner_keys...); } template void Metadata::add(json_t &&data, const std::string &outer_key, - const Args &... inner_keys) { + const Args &...inner_keys) { DataMap::add( std::move(data), outer_key, inner_keys...); } diff --git a/src/framework/results/data/mixins/data_cdict.hpp b/src/framework/results/data/mixins/data_cdict.hpp index 16d1e3b8d7..69b4670c3b 100644 --- a/src/framework/results/data/mixins/data_cdict.hpp +++ b/src/framework/results/data/mixins/data_cdict.hpp @@ -29,10 +29,11 @@ namespace AER { // Result container for Qiskit-Aer //============================================================================ -struct DataCDict : public DataMap, 1>, - public DataMap, 2>, - public DataMap, 1>, - public DataMap, 2> { +struct DataCDict + : public DataMap, 1>, + public DataMap, 2>, + public DataMap, 1>, + public DataMap, 2> { // Serialize engine data to JSON void add_to_json(json_t &result); @@ -46,10 +47,14 @@ struct DataCDict : public DataMap, //------------------------------------------------------------------------------ DataCDict &DataCDict::combine(DataCDict &&other) { - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); + DataMap, 1>::combine( + std::move(other)); + DataMap, 2>::combine( + std::move(other)); + DataMap, 1>::combine( + std::move(other)); + DataMap, 2>::combine( + std::move(other)); return *this; } diff --git a/src/framework/results/data/mixins/data_cmatrix.hpp b/src/framework/results/data/mixins/data_cmatrix.hpp index 0aa1920603..f1e23b6707 100644 --- a/src/framework/results/data/mixins/data_cmatrix.hpp +++ b/src/framework/results/data/mixins/data_cmatrix.hpp @@ -15,9 +15,9 @@ #ifndef _aer_framework_results_data_cmatrix_hpp_ #define _aer_framework_results_data_cmatrix_hpp_ -#include "framework/results/data/subtypes/data_map.hpp" #include "framework/results/data/subtypes/accum_data.hpp" #include "framework/results/data/subtypes/average_data.hpp" +#include "framework/results/data/subtypes/data_map.hpp" #include "framework/results/data/subtypes/list_data.hpp" #include "framework/results/data/subtypes/single_data.hpp" #include "framework/types.hpp" @@ -28,23 +28,22 @@ namespace AER { // Result container for Qiskit-Aer //============================================================================ -struct DataCMatrix : - public DataMap, 1>, - public DataMap, 1>, - public DataMap, 2>, - public DataMap, 2>, - public DataMap, 1>, - public DataMap, 1>, - public DataMap, 2>, - public DataMap, 2>, - public DataMap, 1>, - public DataMap, 1>, - public DataMap, 2>, - public DataMap, 2>, - public DataMap, 1>, - public DataMap, 1>, - public DataMap, 2>, - public DataMap, 2> { +struct DataCMatrix : public DataMap, 1>, + public DataMap, 1>, + public DataMap, 2>, + public DataMap, 2>, + public DataMap, 1>, + public DataMap, 1>, + public DataMap, 2>, + public DataMap, 2>, + public DataMap, 1>, + public DataMap, 1>, + public DataMap, 2>, + public DataMap, 2>, + public DataMap, 1>, + public DataMap, 1>, + public DataMap, 2>, + public DataMap, 2> { // Serialize engine data to JSON void add_to_json(json_t &result); diff --git a/src/framework/results/data/mixins/data_creg.hpp b/src/framework/results/data/mixins/data_creg.hpp index 73a68acb11..f97b769ce6 100644 --- a/src/framework/results/data/mixins/data_creg.hpp +++ b/src/framework/results/data/mixins/data_creg.hpp @@ -26,8 +26,8 @@ namespace AER { // Result container for Qiskit-Aer //============================================================================ -struct DataCreg : public DataMap, // Counts - public DataMap // Memory +struct DataCreg : public DataMap, // Counts + public DataMap // Memory { // Serialize engine data to JSON void add_to_json(json_t &result); diff --git a/src/framework/results/data/mixins/data_mps.hpp b/src/framework/results/data/mixins/data_mps.hpp index 21e20619c6..281a91bf70 100644 --- a/src/framework/results/data/mixins/data_mps.hpp +++ b/src/framework/results/data/mixins/data_mps.hpp @@ -25,7 +25,7 @@ namespace AER { //============================================================================ // Result container for Qiskit-Aer //============================================================================ -//using cmat = std::vector>; +// using cmat = std::vector>; struct DataMPS : public DataMap, public DataMap, public DataMap, diff --git a/src/framework/results/data/mixins/data_rdict.hpp b/src/framework/results/data/mixins/data_rdict.hpp index 8f9e0f55a2..9e470267b4 100644 --- a/src/framework/results/data/mixins/data_rdict.hpp +++ b/src/framework/results/data/mixins/data_rdict.hpp @@ -15,12 +15,12 @@ #ifndef _aer_framework_results_data_rdict_hpp_ #define _aer_framework_results_data_rdict_hpp_ -#include -#include "framework/results/data/subtypes/data_map.hpp" -#include "framework/results/data/subtypes/list_data.hpp" #include "framework/results/data/subtypes/accum_data.hpp" #include "framework/results/data/subtypes/average_data.hpp" +#include "framework/results/data/subtypes/data_map.hpp" +#include "framework/results/data/subtypes/list_data.hpp" #include "framework/types.hpp" +#include namespace AER { @@ -28,12 +28,13 @@ namespace AER { // Result container for Qiskit-Aer //============================================================================ -struct DataRDict : public DataMap, 1>, - public DataMap, 2>, - public DataMap, 1>, - public DataMap, 2>, - public DataMap, 1>, - public DataMap, 2> { +struct DataRDict + : public DataMap, 1>, + public DataMap, 2>, + public DataMap, 1>, + public DataMap, 2>, + public DataMap, 1>, + public DataMap, 2> { // Serialize engine data to JSON void add_to_json(json_t &result); @@ -47,12 +48,18 @@ struct DataRDict : public DataMap, 1>, //------------------------------------------------------------------------------ DataRDict &DataRDict::combine(DataRDict &&other) { - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); - DataMap, 1>::combine(std::move(other)); - DataMap, 2>::combine(std::move(other)); + DataMap, 1>::combine( + std::move(other)); + DataMap, 2>::combine( + std::move(other)); + DataMap, 1>::combine( + std::move(other)); + DataMap, 2>::combine( + std::move(other)); + DataMap, 1>::combine( + std::move(other)); + DataMap, 2>::combine( + std::move(other)); return *this; } diff --git a/src/framework/results/data/mixins/data_rvalue.hpp b/src/framework/results/data/mixins/data_rvalue.hpp index 901c84eb30..8f89412ea4 100644 --- a/src/framework/results/data/mixins/data_rvalue.hpp +++ b/src/framework/results/data/mixins/data_rvalue.hpp @@ -15,9 +15,9 @@ #ifndef _aer_framework_results_data_rvalue_hpp_ #define _aer_framework_results_data_rvalue_hpp_ -#include "framework/results/data/subtypes/data_map.hpp" #include "framework/results/data/subtypes/accum_data.hpp" #include "framework/results/data/subtypes/average_data.hpp" +#include "framework/results/data/subtypes/data_map.hpp" #include "framework/results/data/subtypes/list_data.hpp" #include "framework/results/data/subtypes/single_data.hpp" #include "framework/types.hpp" @@ -28,13 +28,12 @@ namespace AER { // Result container for Qiskit-Aer //============================================================================ -struct DataRValue : - public DataMap, - public DataMap, - public DataMap, - public DataMap, - public DataMap, - public DataMap { +struct DataRValue : public DataMap, + public DataMap, + public DataMap, + public DataMap, + public DataMap, + public DataMap { // Serialize engine data to JSON void add_to_json(json_t &result); diff --git a/src/framework/results/data/mixins/data_rvector.hpp b/src/framework/results/data/mixins/data_rvector.hpp index ab283f7ac1..6688b80db1 100644 --- a/src/framework/results/data/mixins/data_rvector.hpp +++ b/src/framework/results/data/mixins/data_rvector.hpp @@ -15,11 +15,11 @@ #ifndef _aer_framework_results_data_rvector_hpp_ #define _aer_framework_results_data_rvector_hpp_ +#include "framework/results/data/subtypes/accum_data.hpp" +#include "framework/results/data/subtypes/average_data.hpp" #include "framework/results/data/subtypes/data_map.hpp" #include "framework/results/data/subtypes/list_data.hpp" #include "framework/results/data/subtypes/single_data.hpp" -#include "framework/results/data/subtypes/accum_data.hpp" -#include "framework/results/data/subtypes/average_data.hpp" #include "framework/types.hpp" namespace AER { diff --git a/src/framework/results/data/mixins/pybind_data_cdict.hpp b/src/framework/results/data/mixins/pybind_data_cdict.hpp old mode 100755 new mode 100644 index 7bcddf3cdc..9f025e39b2 --- a/src/framework/results/data/mixins/pybind_data_cdict.hpp +++ b/src/framework/results/data/mixins/pybind_data_cdict.hpp @@ -30,8 +30,7 @@ py::object to_python(AER::DataCDict &&data); // Move an DataCDict container object to an existing new Python dict void add_to_python(py::dict &pydata, AER::DataCDict &&data); -} //end namespace AerToPy - +} // end namespace AerToPy //============================================================================ // Implementations @@ -44,10 +43,26 @@ py::object AerToPy::to_python(AER::DataCDict &&data) { } void AerToPy::add_to_python(py::dict &pydata, AER::DataCDict &&data) { - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> &&>( + data)); } #endif diff --git a/src/framework/results/data/mixins/pybind_data_cmatrix.hpp b/src/framework/results/data/mixins/pybind_data_cmatrix.hpp old mode 100755 new mode 100644 index 4b53de3c8a..994adc2e8b --- a/src/framework/results/data/mixins/pybind_data_cmatrix.hpp +++ b/src/framework/results/data/mixins/pybind_data_cmatrix.hpp @@ -30,8 +30,7 @@ py::object to_python(AER::DataCMatrix &&data); // Move an DataCMatrix container object to an existing new Python dict void add_to_python(py::dict &pydata, AER::DataCMatrix &&data); -} //end namespace AerToPy - +} // end namespace AerToPy //============================================================================ // Implementations @@ -44,22 +43,70 @@ py::object AerToPy::to_python(AER::DataCMatrix &&data) { } void AerToPy::add_to_python(py::dict &pydata, AER::DataCMatrix &&data) { - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast< + AER::DataMap, 1> &&>(data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast< + AER::DataMap, 2> &&>(data)); } #endif diff --git a/src/framework/results/data/mixins/pybind_data_creg.hpp b/src/framework/results/data/mixins/pybind_data_creg.hpp old mode 100755 new mode 100644 index 9585154c42..2156dd1d9b --- a/src/framework/results/data/mixins/pybind_data_creg.hpp +++ b/src/framework/results/data/mixins/pybind_data_creg.hpp @@ -30,8 +30,7 @@ py::object to_python(AER::DataCreg &&data); // Move an DataCreg container object to an existing new Python dict void add_to_python(py::dict &pydata, AER::DataCreg &&data); -} //end namespace AerToPy - +} // end namespace AerToPy //============================================================================ // Implementations @@ -44,8 +43,12 @@ py::object AerToPy::to_python(AER::DataCreg &&data) { } void AerToPy::add_to_python(py::dict &pydata, AER::DataCreg &&data) { - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); + AerToPy::add_to_python( + pydata, + static_cast &&>(data)); + AerToPy::add_to_python( + pydata, + static_cast &&>(data)); } #endif diff --git a/src/framework/results/data/mixins/pybind_data_cvector.hpp b/src/framework/results/data/mixins/pybind_data_cvector.hpp old mode 100755 new mode 100644 index 3115cc8b09..15c7991780 --- a/src/framework/results/data/mixins/pybind_data_cvector.hpp +++ b/src/framework/results/data/mixins/pybind_data_cvector.hpp @@ -30,8 +30,7 @@ py::object to_python(AER::DataCVector &&data); // Move an DataCVector container object to an existing new Python dict void add_to_python(py::dict &pydata, AER::DataCVector &&data); -} //end namespace AerToPy - +} // end namespace AerToPy //============================================================================ // Implementations @@ -44,14 +43,38 @@ py::object AerToPy::to_python(AER::DataCVector &&data) { } void AerToPy::add_to_python(py::dict &pydata, AER::DataCVector &&data) { - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> + &&>(data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> + &&>(data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> + &&>(data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> + &&>(data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> + &&>(data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> + &&>(data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> + &&>(data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> + &&>(data)); } #endif diff --git a/src/framework/results/data/mixins/pybind_data_json.hpp b/src/framework/results/data/mixins/pybind_data_json.hpp old mode 100755 new mode 100644 index 89759ed3ce..51bebb049b --- a/src/framework/results/data/mixins/pybind_data_json.hpp +++ b/src/framework/results/data/mixins/pybind_data_json.hpp @@ -30,8 +30,7 @@ py::object to_python(AER::DataJSON &&data); // Move an DataJSON container object to an existing new Python dict void add_to_python(py::dict &pydata, AER::DataJSON &&data); -} //end namespace AerToPy - +} // end namespace AerToPy //============================================================================ // Implementations @@ -44,10 +43,14 @@ py::object AerToPy::to_python(AER::DataJSON &&data) { } void AerToPy::add_to_python(py::dict &pydata, AER::DataJSON &&data) { - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); + AerToPy::add_to_python( + pydata, static_cast &&>(data)); + AerToPy::add_to_python( + pydata, static_cast &&>(data)); + AerToPy::add_to_python( + pydata, static_cast &&>(data)); + AerToPy::add_to_python( + pydata, static_cast &&>(data)); } #endif diff --git a/src/framework/results/data/mixins/pybind_data_mps.hpp b/src/framework/results/data/mixins/pybind_data_mps.hpp old mode 100755 new mode 100644 index 7196d884a4..b7be3fcc00 --- a/src/framework/results/data/mixins/pybind_data_mps.hpp +++ b/src/framework/results/data/mixins/pybind_data_mps.hpp @@ -25,7 +25,8 @@ namespace AerToPy { // Move mps_container_t to python object -template <> py::object to_python(AER::mps_container_t &&mps); +template <> +py::object to_python(AER::mps_container_t &&mps); // Move an DataMPS container object to a new Python dict py::object to_python(AER::DataMPS &&data); @@ -33,21 +34,21 @@ py::object to_python(AER::DataMPS &&data); // Move an DataMPS container object to an existing new Python dict void add_to_python(py::dict &pydata, AER::DataMPS &&data); -} //end namespace AerToPy - +} // end namespace AerToPy //============================================================================ // Implementations //============================================================================ -template <> py::object AerToPy::to_python(AER::mps_container_t &&data) { +template <> +py::object AerToPy::to_python(AER::mps_container_t &&data) { py::list mats; - for (auto& pair: data.first) { + for (auto &pair : data.first) { mats.append(py::make_tuple(AerToPy::to_python(std::move(pair.first)), AerToPy::to_python(std::move(pair.second)))); } py::list vecs; - for (auto&& vec: data.second) { + for (auto &&vec : data.second) { vecs.append(AerToPy::to_python(std::move(vec))); } return py::make_tuple(std::move(mats), std::move(vecs)); @@ -60,10 +61,22 @@ py::object AerToPy::to_python(AER::DataMPS &&data) { } void AerToPy::add_to_python(py::dict &pydata, AER::DataMPS &&data) { - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); + AerToPy::add_to_python( + pydata, + static_cast &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast &&>( + data)); } #endif diff --git a/src/framework/results/data/mixins/pybind_data_rdict.hpp b/src/framework/results/data/mixins/pybind_data_rdict.hpp old mode 100755 new mode 100644 index 03e2a0a30c..1a92571c63 --- a/src/framework/results/data/mixins/pybind_data_rdict.hpp +++ b/src/framework/results/data/mixins/pybind_data_rdict.hpp @@ -30,8 +30,7 @@ py::object to_python(AER::DataRDict &&data); // Move an DataRDict container object to an existing new Python dict void add_to_python(py::dict &pydata, AER::DataRDict &&data); -} //end namespace AerToPy - +} // end namespace AerToPy //============================================================================ // Implementations @@ -44,12 +43,32 @@ py::object AerToPy::to_python(AER::DataRDict &&data) { } void AerToPy::add_to_python(py::dict &pydata, AER::DataRDict &&data) { - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> + &&>(data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> + &&>(data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> + &&>(data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> + &&>(data)); + AerToPy::add_to_python( + pydata, + static_cast< + AER::DataMap, 1> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast< + AER::DataMap, 2> &&>( + data)); } #endif diff --git a/src/framework/results/data/mixins/pybind_data_rvalue.hpp b/src/framework/results/data/mixins/pybind_data_rvalue.hpp old mode 100755 new mode 100644 index 15d9f18469..dfed06ea4c --- a/src/framework/results/data/mixins/pybind_data_rvalue.hpp +++ b/src/framework/results/data/mixins/pybind_data_rvalue.hpp @@ -30,8 +30,7 @@ py::object to_python(AER::DataRValue &&data); // Move an DataRValue container object to an existing new Python dict void add_to_python(py::dict &pydata, AER::DataRValue &&data); -} //end namespace AerToPy - +} // end namespace AerToPy //============================================================================ // Implementations @@ -44,12 +43,18 @@ py::object AerToPy::to_python(AER::DataRValue &&data) { } void AerToPy::add_to_python(py::dict &pydata, AER::DataRValue &&data) { - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); - AerToPy::add_to_python(pydata, static_cast&&>(data)); + AerToPy::add_to_python( + pydata, static_cast &&>(data)); + AerToPy::add_to_python( + pydata, static_cast &&>(data)); + AerToPy::add_to_python( + pydata, static_cast &&>(data)); + AerToPy::add_to_python( + pydata, static_cast &&>(data)); + AerToPy::add_to_python( + pydata, static_cast &&>(data)); + AerToPy::add_to_python( + pydata, static_cast &&>(data)); } #endif diff --git a/src/framework/results/data/mixins/pybind_data_rvector.hpp b/src/framework/results/data/mixins/pybind_data_rvector.hpp old mode 100755 new mode 100644 index 58ca61ec9d..212bef99bb --- a/src/framework/results/data/mixins/pybind_data_rvector.hpp +++ b/src/framework/results/data/mixins/pybind_data_rvector.hpp @@ -30,8 +30,7 @@ py::object to_python(AER::DataRVector &&data); // Move an DataRVector container object to an existing new Python dict void add_to_python(py::dict &pydata, AER::DataRVector &&data); -} //end namespace AerToPy - +} // end namespace AerToPy //============================================================================ // Implementations @@ -44,12 +43,30 @@ py::object AerToPy::to_python(AER::DataRVector &&data) { } void AerToPy::add_to_python(py::dict &pydata, AER::DataRVector &&data) { - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 1>&&>(data)); - AerToPy::add_to_python(pydata, static_cast, 2>&&>(data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 1> &&>( + data)); + AerToPy::add_to_python( + pydata, + static_cast, 2> &&>( + data)); } #endif diff --git a/src/framework/results/data/pybind_data.hpp b/src/framework/results/data/pybind_data.hpp old mode 100755 new mode 100644 index dcd25fb17f..53b338c372 --- a/src/framework/results/data/pybind_data.hpp +++ b/src/framework/results/data/pybind_data.hpp @@ -16,23 +16,23 @@ #define _aer_framework_result_data_pybind_data_hpp_ #include "framework/results/data/data.hpp" -#include "framework/results/data/mixins/pybind_data_creg.hpp" -#include "framework/results/data/mixins/pybind_data_rdict.hpp" -#include "framework/results/data/mixins/pybind_data_rvalue.hpp" -#include "framework/results/data/mixins/pybind_data_rvector.hpp" +#include "framework/results/data/mixins/pybind_data_cdict.hpp" #include "framework/results/data/mixins/pybind_data_cmatrix.hpp" +#include "framework/results/data/mixins/pybind_data_creg.hpp" #include "framework/results/data/mixins/pybind_data_cvector.hpp" -#include "framework/results/data/mixins/pybind_data_cdict.hpp" #include "framework/results/data/mixins/pybind_data_json.hpp" #include "framework/results/data/mixins/pybind_data_mps.hpp" +#include "framework/results/data/mixins/pybind_data_rdict.hpp" +#include "framework/results/data/mixins/pybind_data_rvalue.hpp" +#include "framework/results/data/mixins/pybind_data_rvector.hpp" namespace AerToPy { // Move an ExperimentResult data object to a Python dict -template <> py::object to_python(AER::Data &&data); - -} //end namespace AerToPy +template <> +py::object to_python(AER::Data &&data); +} // end namespace AerToPy //============================================================================ // Implementations @@ -41,15 +41,15 @@ template <> py::object to_python(AER::Data &&data); template <> py::object AerToPy::to_python(AER::Data &&data) { py::dict pydata; - AerToPy::add_to_python(pydata, static_cast(data)); - AerToPy::add_to_python(pydata, static_cast(data)); - AerToPy::add_to_python(pydata, static_cast(data)); - AerToPy::add_to_python(pydata, static_cast(data)); - AerToPy::add_to_python(pydata, static_cast(data)); - AerToPy::add_to_python(pydata, static_cast(data)); - AerToPy::add_to_python(pydata, static_cast(data)); - AerToPy::add_to_python(pydata, static_cast(data)); - AerToPy::add_to_python(pydata, static_cast(data)); + AerToPy::add_to_python(pydata, static_cast(data)); + AerToPy::add_to_python(pydata, static_cast(data)); + AerToPy::add_to_python(pydata, static_cast(data)); + AerToPy::add_to_python(pydata, static_cast(data)); + AerToPy::add_to_python(pydata, static_cast(data)); + AerToPy::add_to_python(pydata, static_cast(data)); + AerToPy::add_to_python(pydata, static_cast(data)); + AerToPy::add_to_python(pydata, static_cast(data)); + AerToPy::add_to_python(pydata, static_cast(data)); return std::move(pydata); } diff --git a/src/framework/results/data/pybind_metadata.hpp b/src/framework/results/data/pybind_metadata.hpp old mode 100755 new mode 100644 index 244083d931..ca2f8a58bb --- a/src/framework/results/data/pybind_metadata.hpp +++ b/src/framework/results/data/pybind_metadata.hpp @@ -21,10 +21,10 @@ namespace AerToPy { // Move an ExperimentResult metdata object to a Python dict -template <> py::object to_python(AER::Metadata &&metadata); - -} //end namespace AerToPy +template <> +py::object to_python(AER::Metadata &&metadata); +} // end namespace AerToPy //============================================================================ // Implementations @@ -33,9 +33,15 @@ template <> py::object to_python(AER::Metadata &&metadata); template <> py::object AerToPy::to_python(AER::Metadata &&metadata) { py::dict pydata; - add_to_python(pydata, static_cast&&>(metadata)); - add_to_python(pydata, static_cast&&>(metadata)); - add_to_python(pydata, static_cast&&>(metadata)); + add_to_python( + pydata, + static_cast &&>(metadata)); + add_to_python( + pydata, + static_cast &&>(metadata)); + add_to_python( + pydata, + static_cast &&>(metadata)); return std::move(pydata); } diff --git a/src/framework/results/data/subtypes/accum_data.hpp b/src/framework/results/data/subtypes/accum_data.hpp old mode 100755 new mode 100644 index a424f8a107..3e34f24caf --- a/src/framework/results/data/subtypes/accum_data.hpp +++ b/src/framework/results/data/subtypes/accum_data.hpp @@ -22,16 +22,17 @@ namespace AER { template class AccumData : public SingleData { -using Base = SingleData; + using Base = SingleData; + public: // Add data (copy) - void add(const T& data); + void add(const T &data); // Add data (move) - void add(T&& data); + void add(T &&data); // Combine data (move) - void combine(AccumData&& other); + void combine(AccumData &&other); // Clear all stored data void clear(); @@ -45,7 +46,7 @@ using Base = SingleData; //------------------------------------------------------------------------------ template -void AccumData::add(const T& data) { +void AccumData::add(const T &data) { if (empty_) { Base::data_ = data; empty_ = false; @@ -55,7 +56,7 @@ void AccumData::add(const T& data) { } template -void AccumData::add(T&& data) { +void AccumData::add(T &&data) { if (empty_) { Base::data_ = std::move(data); empty_ = false; @@ -65,7 +66,7 @@ void AccumData::add(T&& data) { } template -void AccumData::combine(AccumData&& other) { +void AccumData::combine(AccumData &&other) { add(std::move(other.data_)); } @@ -76,6 +77,6 @@ void AccumData::clear() { } //------------------------------------------------------------------------------ -} // end namespace AER +} // end namespace AER //------------------------------------------------------------------------------ #endif diff --git a/src/framework/results/data/subtypes/average_data.hpp b/src/framework/results/data/subtypes/average_data.hpp old mode 100755 new mode 100644 index fea9a7c858..25db5a8cd3 --- a/src/framework/results/data/subtypes/average_data.hpp +++ b/src/framework/results/data/subtypes/average_data.hpp @@ -21,19 +21,20 @@ namespace AER { template class AverageData : public AccumData { -using Base = AccumData; + using Base = AccumData; + public: // Access data - T& value(); + T &value(); // Add data (copy) - void add(const T& data); + void add(const T &data); // Add data (move) - void add(T&& data); + void add(T &&data); // Add data - void combine(AverageData&& other); + void combine(AverageData &&other); // Clear all stored data void clear(); @@ -58,21 +59,21 @@ using Base = AccumData; //------------------------------------------------------------------------------ template -void AverageData::add(const T& data) { +void AverageData::add(const T &data) { denormalize(); Base::add(data); count_ += 1; } template -void AverageData::add(T&& data) { +void AverageData::add(T &&data) { denormalize(); Base::add(std::move(data)); count_ += 1; } template -void AverageData::combine(AverageData&& other) { +void AverageData::combine(AverageData &&other) { denormalize(); other.denormalize(); Base::combine(std::move(other)); @@ -103,12 +104,12 @@ void AverageData::denormalize() { } template -T& AverageData::value() { +T &AverageData::value() { normalize(); return Base::data_; } //------------------------------------------------------------------------------ -} // end namespace AER +} // end namespace AER //------------------------------------------------------------------------------ #endif diff --git a/src/framework/results/data/subtypes/data_map.hpp b/src/framework/results/data/subtypes/data_map.hpp old mode 100755 new mode 100644 index 7f0d4fb0a6..8c942ae0ac --- a/src/framework/results/data/subtypes/data_map.hpp +++ b/src/framework/results/data/subtypes/data_map.hpp @@ -25,23 +25,23 @@ template