diff --git a/.travis.yml b/.travis.yml index f92ee6082775..df55f8c07884 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,6 @@ notifications: email: false cache: pip -sudo: false ############################################################################### # Anchored and aliased definitions. diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index a028e7c863f6..000000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,1326 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog]. - -> **Types of changes:** -> -> - **Added**: for new features. -> - **Changed**: for changes in existing functionality. -> - **Deprecated**: for soon-to-be removed features. -> - **Removed**: for now removed features. -> - **Fixed**: for any bug fixes. -> - **Security**: in case of vulnerabilities. - -## [UNRELEASED] - -### Changed - -- Assignments and modifications to `QuantumCircuit.data` will now be broadcast - and validated following the same rules used throughout the - `QuantumCircuit` API. (\#2826) - -### Added -- The mock backends in `qiskit.test.mock` now have a snapshot of real - calibration data, returned via `backend.properties()`. - -### Fixed -- Fixed a bug in drawing conditional gates with matplotlib circuit drawer. - -### Changed -- Returned `matplotlib.figure.Figure` objects are only closed in jupyter - notebooks configured with an inline backend (\#3051) - -### Removed - -- Removed `DeviceSpecification` in favor of `PulseChannelSpec`. (\#3033) -- Removed deprecated `ops.py` from pulse. Use `Schedule` and `Instruction` - methods directly. (\#3034) - -### Deprecated - -- Comparing tuples to `Bit`s is being deprecated. Representing a qubit or - a classical bit as a tuple is being abandon in favor of `Qubit` and `Clbit` - objects. - -## [0.9.0] - 2019-08-22 - -### Deprecated - -- The full import path `qiskit.pulse.channels.pulse_channels` is deprecated; - code is moved to `qiskit.pulse.channels.channels` instead. Users should - keep importing from `qiskit.pulse.channels` (\#3094). -- The gates `U` and `CX` are being deprecated in favor of `u3` and - `cx`. (\#2380) -- The gate `u0` is being deprecated in favor of using multiple `id` gates - to insert delays (\#2664) -- The decorator `requires_qe_access` is being deprecated in favor of - `online_test`. -- The `as_dict` method of Qobj is deprecated in favor of `to_dict`. (\#2556) - -### Added - -- Added in tests for `ccx` and `crz` under `test_gate_definitions`. (\#2964) -- A new pulse instruction, `Delay`. A `Delay` occupies a pulse channel for a - duration of time, blocking other instructions from being inserted in this time. (\#2869) -- Ability to check for equality of pulse `Schedule` and `Instruction`. (\#2873) -- Added tests for `gate_map` and reference images for testing `plot_gate_map` -- New `CountOpsLongest` analysis pass to retrieve the number of operations - on the longest path of the DAGCircuit. (\#2734) -- Added `sech` and `sech_deriv` pulses in `qiskit.pulse.pulse_lib`. -- The option `vertical_compression` was added to the text drawer and - to the `QuantumCircuit.draw` method. The option allows to control - how much room the text circuit drawing takes. -- The option `idle_wires` was added to the drawers to control - if wires without any operation should be included in the drawing. (\#2692) -- Introduced a visualization for the Pass Manager. (\#2445) -- New pulse schedule method `Schedule.filter` to filter by instruction - channel, time, and type. (\#2597) -- Decomposition of arbitrary isometries (\#2600) -- Decomposition of diagonal gates (\#2600) -- Decomposition of multiplexed rotation gates (\#2600) -- Decomposition of multiplexed single-qubit unitaries (Option: decompose - up to a diagonal gate) (\#2600) -- ZYZ decomposition for single-qubit unitaries (\#2600) -- Gray-Synth and Patel–Markov–Hayes algorithms for synthesis of - CNOT-Phase and CNOT-only (linear) circuits (\#2457) -- Added n-qubit unitaries to BasicAer simulator basis gates (\#2342) -- Added a ``random_circuit`` function under ``qiskit.circuit.random`` - (\#2553) -- Added `equiv` method to `Operator` and `Statevector` classes for - testing if two objects are equivalent up to global phase (\#2910) -- Added ``output_name`` as a transpiler parameter to set the name of - output circuits (\#2745) -- Simple expressions of Parameters can now be created via the four basic math - operations (+,-,\*,/). (\#2537) -- A `ParmeterVector` class has been added to ease the construction of circuits - requiring a large number of parameters. (\#2379) -- dag.draw() method to visualize DAGCircuit objects (\#3016) - - -### Changed - -- Intervals are now defined by start and stop, rather than begin and end. (\#2870) -- TimeslotCollections now are sorted by default and have more efficient merges. (\#2870) -- Pulse samples are now clipped if their norm is between 1 and 1+epsilon. - Otherwise an error is raised. -- `Schedule.instructions` now returns with time-ordering. -- More informative errors are now raised if `qubit_lo_freq` and - `meas_lo_freq` are not supplied to `assemble_schedules`. (\#2833) -- `pulse.samplers` module has now been moved to `pulse.pulse_lib.samplers`. (\#2881) -- The number of memory slots required will now be inferred from the supplied - schedules if `memory_slots` is not supplied. -- All circuit drawers now express most commonly used fractions - of PI (\#2808). -- Set default repetition time to be the first available. -- Pulse commands may now start with capitalized letters. -- The `pylatexenc` and `pillow` requirements are now optional. These - are only used by the `latex` and `latex_source` circuit - visualization backends. To continue using them ensure these are - installed. (\#2451) -- When adding a register to a circuit, an error will now be raised if - a register of the same name is already present. Previously, an error - would only be raised if the same register was added twice. -- Qubits and classical bits are not represented as a tuples anymore, - but as instances of `Qubit` and `Clbit` respectively. (\#2414) -- The ApplyLayout pass is incorporated in all preset pass managers to - delineate a virtual circuit from a physical circuit (\#2672) -- Mapping passes (`CXDirection`, Swap passes, `CheckMap`, `CheckCnotDirection`) - now operate on a register-less circuit corresponding to - an already embedded physical circuit. (\#2672) -- Replaces `LegacySwap` by faster, more stable `StochasticSwap` pass (\#2672) -- Uses level 1 by default as transpiler optimization level (\#2672) -- Change `Snapshot` signature to match `simulator.snapshot` (\#2592) -- `DAGCircuit.width()` formerly returned number of qubits, now returns total - number of qubits + classical bits (\#2564) -- Functions assuming the former semantics of `DAGCircuit.width()` now call - `DAGCircuit.num_qubits()` (\#2564) -- `DAGCircuit.num_cbits()` renamed to `DAGCircuit.num_clbits()` (\#2564) -- Changed definition of `Cu3Gate` to to equivalent to the canonical - definition of a controlled `U3Gate` (\#2755) -- `coupling_map` now required to validate a `backend.configuration()` (\#2836) -- The method `QuantumCircuit.count_ops` now returns an `OrderedDict` instead of a dict. -- If layout information is available in - the circuit, it will be included to the circuit drawing. This can be removed - using the option ``with_layout=False`` in the method - ``QuantumCircuit.draw``. (\#2739) -- Q-sphere visualization is enhanced and corrected (\#2932) -- Shorter CH gate definition involving only 1 CX (\#2837) -- Now PassManager.draw() (without any argument) will return an in-memory PIL image. - -### Removed -- The ability to set the `Timeslot`s for a pulse `Instruction` at initialization. -- The previously deprecated functions - `qiskit.visualization.plot_state` and - `qiskit.visualization.iplot_state` have been removed. Instead use - the specific functions for each plot type (\#2325). -- International documentation of outdated readme etc (\#2302) -- Removed deprecated options in `execute`, `transpile`, and `assemble`. - Removed deprecated `compiler`. -- Removed deprecated `qcvv `in tools. Removed deprecated converters - `qobj_to_circuits` and `circuits_to_qobj` (\#2301) -- The previously deprecated `qiskit._util` module has been removed. - Use `qiskit.util` instead. (\#2329) -- The logging tools in `qiskit.tools.logging` are removed. (\#2387) -- The `qiskit.qiskiterror` module has been removed. Please use - `qiskit.exceptions` instead. (\#2399) -- Removed previously deprecated `DAGCircuit` methods (\#2542) -- Removed `CompositeGate` class, in favor of adding Instruction - objects directly (\#2543) -- Removed `ignore_requires` and `ignore_preserves` options from - `PassManager` (\#2565). - -### Fixed - -- Fixes a bug where the `CmdDef` was getting built without buffers on channels. -- Fixed bug in `Pulse` for multiple parameters being added (\#2742) -- Fixed bug in `Pulse` for `CmdDef` arguments (\#2741) -- Fixed bug in `Operator` and `SuperOp` for initializing from circuit - containing gates without an explicit matrix definition (\#2723) -- Possible to decompose SU(4) gate into non-CNOT basis with - `TwoQubitDecomposer` -- Fixes a bug that removed `id` gates from circuit. id gates are - like a `wait` command and will never be removed (\#2663) -- Fixed bug in `CommutationAnalysis` pass affecting conditional gates (\#2669) -- Fixed bug in measure sampling for `BasicAer` Qasm simulator if a qubit - was measured into more than one classical bit (\#2735) -- Correctly serialize complex numbers with a nonzero real part -- Fixed bug in measure sampling for `BasicAer` Qasm simulator if only a - subset of qubits are measured (\#2790) -- Parameter objects can be serialized and communicated between - sub-processes (\#2429) -- Parameterized circuits no longer need to be transpiled individually (\#2864) - - -## [0.8.2] - 2019-06-14 - -### Fixed - -- Fixed an issue with latex circuit drawer backend that could lead to an - empty image output (\#2531) -- Fixes for issues with the backend monitors for recent changes to IBMQ - backends (\#2637) -- Fixed an issue where a `TimeSlotCollection` object would be mutated by - the `is_mergable_with()` method (\#2639) - - -## [0.8.1] - 2019-05-29 - -### Fixed - -- Corrected the deprecation warning message for - `qiskit.converters.qobj_to_circuits` (\#2350) -- Fixed `execute()` and `transpile()` functions to enable setting - optimization level 0. (\#2370) -- Set the swapper with the seed transpiler for optimization level 2 and 3 - (\#2361) -- Fix default basis gate set for other transpiler passes (\#2357) -- Fix the docstring for transpile to include optimization_level 3 (\#2367) -- Fix spacing in the text circuit drawer (\#2382) -- Fix for too strict math sanitization pulse instructions (\#2397) -- Arguments to `assemble_schedule` were not actually optional, ensure - they're required (\#2398) -- Fix for framechange instructions being converted to a string instead of a - float (\#2437) -- Fix for rep_times as a float, now it's an integer (\#2438) -- Fix type error for integer framechange instructions (\#2458) -- Fix for missing cython source files in sdist (\#2436) -- Fix for different pulse schedules created with the same name (\#2431) -- Only create a single AquireInstruction for all qubits (\#2485) -- Stop modifying layout in stochastic swap pass (\#2507) -- Only call CXDirection pass on optimization_level=3 if coupling map is - provided (\#2526) -- Fix `optimization_level=0` without a coupling map (\#2509) - - -## [0.8.0] - 2019-05-02 - -### Added - -- Added exact and approximate decomposition of SU(4) to arbitrary - supercontrolled basis -- Introduced schedule lo configuration. (\#2115) -- Introduced pulse schedule assembler. (\#2115) -- Builtin library of continuous pulses and builtin library of discrete - pulses which are obtained by sampling continuous pulses with default - sampling strategy. -- Sampler decorator and standard sampler library for conversion of - continuous pulses to discrete `SamplePulse` (\#2042). -- Core StochasticSwap routine implimented in Cython (\#1789). -- Added QuantumChannel classes SuperOp, Choi, Kraus, Stinespring, PTM, - Chi to quantum\_info for manipulating quantum channels and CPTP - maps. -- Added Operator object to quantum\_info for representing matrix - operators. -- Introduced the backend defaults model and endpoint for pulse - backends (\#2101). -- `meas_level` to result schema (\#2085). -- Core StochasticSwap routine implemented in Cython (\#1789). -- New EnlargeWithAncilla pass for adding ancilla qubits after a Layout - selection pass (\#1603). -- New Unroll2Q pass for unrolling gates down to just 1q or 2q gates - (\#1614). -- Added support for register slicing when applying operations to a - register (\#1643). -- Added in new parameter `justify` to the text, mpl and latex circuit - drawers to say how the circuit should be aligned. (\#1725, \#1797, - \#1977) -- Added function for purity of a mixed state in - `qiskit.quantum_information` (\#1733) -- Added parameter to the TextProgressBar to allow the output to be - sent to a different output stream -- Added a `__qiskit_version__` parameter to the qiskit namespace. This - will contain a dictionary of versions for all installed qiskit - elements. (\#1885). -- Added a `RunConfig` object for configurations related to running an - experiment (e.g. shots, memory) (\#1856) -- Added a `TranspileConfig` object for configurations related to - transforming circuits (e.g. basis\_gates, coupling\_map, - initial\_layout) (\#1856) -- Added a `qiskit.compiler` namespace for all functions that - transpile, schedule and assemble circuits and pulses (\#1856) -- Added support for passing a list of `basis_gates`, `coupling_map` - etc. to the `qiskit.compiler.transpile()` function, each - corresponding to one of the circuits (\#2163) -- Added a `qiskit.compiler.assemble_circuits()` function to generate - qobj from some circuits and a RunConfig (\#1856) -- `execute()` and `assemble()` allow setting a qobj\_header, of type - QobjHeader or dict, to add extra information to the qobj (and thus - result). -- Register indexing supports negative indices (\#1875) -- Added new resource estimation passes: `Depth`, `Width`, `Size`, - `CountOps`, and `NumTensorFactors`, all grouped in the - `ResourceEstimation` analysis pass. -- Added `nodes_on_wire()` to DAGCircuit which returns an iterator over - all the operations on the given wire -- Added new properties to an Instruction: `num_qubits`, `num_clbits` - (\#1816). -- Added a `QuantumCircuit.append` public method for appending - arbitrary instructions to some qubits and clbits in the circuit - (\#1816). -- Added an `Instruction.definition` property that defines a composite - instruction in terms of other, simpler instructions (\#1816). -- Added an `Instruction.mirror()` method that mirrors a composite - instruction (reverses its sub-instructions) (\#1816). -- Added an `PassManager.passes()` method that returns a list of the - passes that have been added to the pass manager, including options - and flow controllers. -- Added a `PassManager.run()` that transforms a `QuantumCircuit` - according to its pass schedule and returns a `QuantumCircuit`. -- Added a `qiskit.quantum_info.random` for generating random states, - unitaries, etc (\#2119). -- Added a `qiskit.quantum_info.synthesis` for algorithms that - synthesize circuits (\#2119). -- Added a `NoiseAdaptiveLayout` pass to compute a backend - calibration-data aware initial qubit layout. (\#2089) -- Gates and instructions in a circuit accept integers as parameters to - refer to wires instead of named bits. -- Added a `OptimizeSwapBeforeMeasure` pass that removes the swap gates - when they are followed by a measurement instruction, moving the - latter to the proper wire. (\#1890) -- Added a `RemoveDiagonalGatesBeforeMeasure` pass that removes the - diagonal gates when they are followed by a measurement instruction. - (\#2208) -- Added a `CommutativeCancellation` pass that cancels self-inverse - gates and combines rotations about the Z axis, leveraging - previously-found gate commutation relations. (\#2012) -- Add an option for using a user config file to enable changing - default settings for various functions in qiskit. Right now it only - supports setting the default circuit drawing backend. (\#2122) -- Added a `Collect2qBlocks` pass that analyzes the circuit for - uninterrupted sequences of gates (blocks) acting on 2 qubits. - (\#2134) -- Added a `ConsolidateBlocks` that turns previously-collected blocks - of any size into equivalent Unitary operators in the circuit. - (\#2134) -- Added support for parameterized circuits. (\#2103) -- Added preset PassManagers that offer predetermined pipelines of - transpiler passes. (\#2163) - -### Changed - -- require scipy\>=1.0, use - `scipy.stats.unitary_group.rvs` for - `random_unitary()`. -- two\_qubit\_kak decomposition works with Operator or raw matrix - input objects. -- process\_fidelity works with QuantumChannel and Operator object - inputs. -- Backend defaults values are no longer required (\#2101). -- QuantumCircuit properties more self-consistent and no longer need - DAG (\#1993). -- The most connected subset in DenseLayout is now reduced bandwidth - (\#2021). -- plot\_histogram now allows sorting by Hamming distance from - target\_string (\#2064). -- FunctionalPulse is no longer a class and instead is a decorator, - `functional_pulse` that returns a - `SamplePulse` when called. (\#2043) -- Changed `average_data` to accept observable input in matrix form - (\#1858) -- Change random\_state to take in dim over number of qubits (\#1857) -- The `Exception` subclasses have been moved to an `.exceptions` - module within each package (for example, - `qiskit.exceptions.QiskitError`) (\#1600). -- The `QiskitTestCase` and testing utilities are now included as part - of `qiskit.test` and thus available for third-party implementations, - with convenience test cases for providers and backends. (\#1616, - \#1844) -- The snapshot instruction now takes `label` and `snap_type` instead - of `slot` (\#1615). -- The test folders have been reorganized to match the python modules - (\#1625) -- The circuits\_to\_qobj no longers uses the unrollers (\#1629) -- The previously deprecated default output of `circuit_drawer()` - (using latex and falling back to mpl) is no longer present. Instead - the default output is the ascii art `text` output backend. -- Changed param to params in Instruction (\#1665). -- `dag_drawer` and `plot_gate_map` are available via importing - `qiskit.tools.visualization`. They will raise at the point of use, - if dependencies are not installed (\#1669). -- The `qiskit.validation` schemas are now strict and raise a more - specific `ModelValidationError` (\#1695). -- The default transpile pipeline will now add a barrier before the set - of final measurements when compiling for both simulators and devices - (\#1591). -- Purity function in `qiskit.tools.qi.qi` calls new version in - `qiskit.quantum_information` and issues deprecation warning (\#1733) -- Updated `dag.node_counter` to return the current number - of nodes (\#1763) -- The argument `basis_gates` used in `compile`, `execute`, and - `transpile` is not longer a comma-separated string but a list of - strings. For example, this basis `['u1','u2','u3','cx']` should be - used instead of `'u1,u2,u3,cx'` (\#1333) -- Methods on the `DAGCircuit` which previously returned node\_ids - and/or dicts now return `DAGNodes` -- The `Qobj` classes have been reimplemented using models and schemas, - as the rest of spec-defined entities. (\#1909). -- The rzz gate is now represented as a line when printed in text - (\#1957). -- Text drawer has support for multi-q gates (\#1939). -- Separate `Qobj` into `PulseQobj` and `QasmQobj` (\#1969). -- It is possible to define a layout as a list of integers. This maps - the ordered list of virtual circuit qubits to physical qubits as - defined by the list of integers (\#1946). -- Instructions no longer have context about where they are in a - circuit. Instead, the circuit keeps this context. So Instructions - are now light-weight and only have a name, num\_qubits, num\_clbits - and params (\#1816). -- The old syntax for attaching a gate to the circuit then modifying it - is no longer supported (e.g. `circuit.s(qr).inverse()` or - `circuit.s(qr).c_if(cr, 4)`). Instead, you must first modify the - gate then attach it (\#1816). -- `QuantumCircuit.data` now contains a list of tuples, where each - tuple is a (instruction, qarg, carg) (\#1816). -- The visualization subpackage has moved from - `qiskit.tools.visualization` to `qiskit.visualization`. The public - API (which was declared stable in the 0.7 release) is still - accessible off of `qiskit.tools.visualization`. (\#1878) -- Layout object can now only be constructed from a dictionary, and - must be bijective (\#2157). -- `transpile()` accepts `initial_layout` in the form of dict, list or - Layout (\#2157). -- Not specifying a basis in `execute()` or `transpile()` no longer - defaults to unrolling to the \[\'u1\', \'u2\', \'u3\', \'cx\'\] - basis. Instead the default behavior is to not unroll, unless - specifically requested (\#2166). -- Instruction.copy() is now a shallow copy instead of deep (\#2214) -- Layout and CouplingMap classes are now accessible from - qiskit.transpiler (\#2222). - -### Deprecated - -- The methods prefixed by `\_get` in the DAGCircuit object - are being renamed without that prefix (see \#1346) -- Changed elements in `couplinglist` of `CouplingMap` from tuples to - lists (\#1666). -- Unroller bases must now be explicit, and violation raises an - informative `QiskitError` (\#1802). -- The `qiskit.tools.qcvv` package is deprecated in favor of Qiskit - Ignis (\#1884). -- The `qiskit.compile()` function is now deprecated in favor of - explicitly using the `qiskit.compiler.transpile()` function to - transform a circuit followed by `qiskit.compiler.assemble()` to make - a qobj out of it. -- `qiskit.converters.qobj_to_circuits()` has been deprecated and will - be removed in a future release. Instead - `qiskit.compiler.disassemble_circuits()` should be used to extract - `QuantumCircuit` objects from a compiled qobj. (\#2137) -- The `qiskit.transpiler.transpile()` function is deprecated in favor - of `qiskit.compiler.transpile()` (\#2166). -- The `seed_mapper` argument in `transpile()` and `execute()` is - deprecated in favor of `seed_transpile()`, which sets the seed for - all stochastic stages of the transpiler (\#2166). -- The `seed` argument is `execute()` is deprecated in favor of - `seed_simulator` (\#2166). -- The `pass_manager` argument in `transpile()` is deprecated. Instead, - the `pass_manager.run()` methdod can be used directly to transform - the circuit (\#2166). -- The `qiskit._util` module is deprecated and replaced by - `qiskit.util`. `qiskit._util` will be removed in the 0.9 release. - (\#2154) - -### Fixed - -- Fixed \#1892, whereby inheriting from QuantumRegister or - ClassicalRegister would cause a QiskitError in instruction.py - (\#1908). -- Fixed \#829 by removing dependence on scipy unitary\_group (\#1857). -- Fixed a bug with measurement sampling optimization in BasicAer - qasm\_simulator (\#1624). -- Fixed a bug where barriers didn\'t plot over all qubits when using - matplotlib (\#1718). -- Fixed a minor conda env bug in Makefile (\#1691). -- Fixed a bug in BasicMapper pass operating over multiple registers - (\#1611). -- Fixed a bug in BarrierBeforeFinalMeasurements which incorrectly - moved measurements used in conditional operations (\#1705). -- Fixed a bug that with transpile ignoring initial layout when - coupling map is provided (\#1711). -- Fixed a bug in the definition of the rzz gate (\#1940). -- Fixed a bug in DAGCircuit.collect\_runs() that did not exclude - conditional gates (\#1943). -- Fixed a mapping issue with layouts on non-adjacent qubits, by adding - ancillas (\#2023). -- Fixed a bug in which an `initial_layout` could be - changed even if it made the circuit compatible with the device - `coupling_map` (\#2036). -- Fixed `qobj_to_circuits` for circuits that contain initialize - instructions (\#2138) - -### Removed - -- The previously deprecated functions `plot_circuit()`, - `latex_circuit_drawer()`, `generate_latex_source()`, and - `matplotlib_circuit_drawer()` from `qiskit.tools.visualization` have - been removed. The `circuit_drawer()` function from the same module - should be used instead. -- The previously deprecated keys `plot_barriers` and `reverse_bits` - keys in the `style` kwarg dict are deprecated, instead the - `qiskit.tools.visualization.circuit_drawer()` kwargs `plot_barriers` - and `reverse_bits` should be used instead. -- Removed the wrapper folder as part of the post 0.7 cleanup (\#1613). -- Removed the python wrappers of the legacy simualtors now that Qiskit - Aer is out (\#1615). -- Removed simulator instructions `save`, `load`, `wait`, `noise` as - unsupported in Aer (\#1615). -- Removed circuit.add as deprecated (\#1627) -- Removed the unroller (\#1629) -- Removed deprecated `result` methods (\#1659) -- Removed deprecated `couplingdict` kwarg from `CouplingMap` (\#1666) -- Removed deprecated `transpile_dag()` `format` kwarg (\#1664) -- Removed deprecated `Pauli` `v`, `w`, and `pauli_group` case arg as - int (\#1680) -- Removed deprecated `state_fidelity()` function from `tools.qi` - (\#1681) -- Removed `QISKitError` in favor of `QiskitError`. (\#1684) -- The IBMQ provider (`qiskit.providers.ibmq`) has been moved to its - own package (`pip install qiskit-ibmq-provider`). (\#1700) -- `compiled_circuit_qasm` has been removed from the Qobj header, since - it was part of the pre-qobj specification (\#1715). -- Removed the wigner plotting functions `plot_wigner_function`, - `plot_wigner_curve`, `plot_wigner_plaquette`, and `plot_wigner_data` - (\#1860). -- Removed `Instruction.reapply()` method (\#1816). - -## [0.7.2] - 2019-05-01 - -### Fixed - -- A potential issue where the backend configuration schema validation - would improperly reject valid responses from the API (\#2258) - -## [0.7.1] - 2019-03-04 - -### Fixed - -- Fixed a bug with measurement sampling optimization in BasicAer - qasm\_simulator (\#1624). - -## [0.7.0] - 2018-12-19 - -### Added - -- Added DAG visualizer which requires - [Graphivz](https://www.graphviz.org/) (\#1059) -- Added an ASCII art circuit visualizer (\#909) -- The QuantumCircuit class now returns an ASCII art visualization when - treated as a string (\#911) -- The QuantumCircuit class now has a `draw()` method which - behaves the same as the - `qiskit.tools.visualization.circuit_drawer()` function - for visualizing the quantum circuit (\#911) -- A new method `hinton` can be used on - `qiskit.tools.visualization.plot_state()` to draw a - hinton diagram (\#1246) -- Two new constructor methods, `from_qasm_str()` and - `from_qasm_file()`, to create a QuantumCircuit object - from OpenQASM were added to the QuantumCircuit class. (\#1172) -- New methods in QuantumCircuit for common circuit metrics: - `size()`, `depth()`, `width()`, - `count_ops()`, `num_tensor_factors()` - (\#1285) -- Added `backend_monitor` and - `backend_overview` Jupyter magics, as well as - `plot_coupling_map` (\#1231) -- Added a `Layout` object (\#1313) -- New `plot_bloch_multivector()` to plot Bloch vectors - from a tensored state vector or density matrix. (\#1359) -- Per-shot measurement results are available in simulators and select - devices. Request them by setting `memory=True` in - `compile()`/`execute()`, and retrieve them from - `result.get_memory()` (\#1385). -- Added a `qiskit.converters` module for translation between commonly - used representations of a circuit: `dag_to_circuits`, - `circuits_to_dag`, `qobj_to_circuits`, `circuits_to_qobj`, - `ast_to_dag`. -- PassManager can schedule passes at \_\_init\_\_ time (\#1510). -- Added a `.qobj()` method for IBMQ and local simulator Jobs (\#1532). -- New Decompose pass for decomposing a gate according to a rule - (\#1487). -- New Unroller pass in the transpiler for unrolling up to some basis - (\#1455). -- New BarrierBeforeFinalMeasurements pass for preventing final measure - reorder (\#1538). -- New CommutationAnalysis and CommutationTransformation transpiler - passes for modifying a DAG based on gate commutativity relations - (\#1500). -- New transpiler mapper pass: BasicSwap (\#1270). -- New transpiler mapper pass: LookaheadSwap (\#1140). -- New transpiler mapper pass: StochasticSwap (\#1520). -- New CXDirection pass for fixing the direction of cx gates (\#1410). -- New CheckMap pass for checking if circuit meets mapping requirements - (\#1433). -- New Optimize1QGate pass for combining chains of 1q rotations - (\#1442). - -### Changed - -- Schedules and underlying classes are now immutable. (\#2186) -- Evolved pass-based transpiler to support advanced functionality - (\#1060) -- `.retrieve_job()` and `.jobs()` no longer - returns results by default, instead the result must be accessed by - the `result()` method on the job objects (\#1082). -- Make `backend.status()` dictionary conform with schema. -- The different output backends for the circuit\_drawer() - visualizations have been moved into separate private modules in - `qiskit.tools.visualizations`. (\#1105, \#1111) -- DAG nodes contain pointers to Register and Instruction objects, - rather than their string names (\#1189). -- Upgraded some external dependencies to: - - networkx\>=2.2 (\#1267). - -- The `qiskit.tools.visualization.circuit_drawer()` - method now returns a matplotlib.Figure object when the - `mpl` output is used and a `TextDrawer` - object when `text` output is used. (\#1224, \#1181) -- Speed up the Pauli class and extended its operators (\#1271 \#1166). -- `IBMQ.save_account()` now takes an - `overwrite` option to replace an existing account on - disk. Default is False (\#1295). -- Backend and Provider methods defined in the specification use model - objects rather than dicts, along with validation against schemas - (\#1249, \#1277, \#1350). The updated methods include: - - `backend.status()` (\#1301). - - `backend.configuration()` (and `__init__`) (\#1323). - - `backend.properties()`, returning `None` for sims (\#1331, - \#1401). - - `qiskit.Result` (\#1360). -- `backend.provider()` is now a method instead of a property (\#1312). -- Remove local backend (Aer) fallback (\#1303) -- The signatures for the plotting functions in - `qiskit.tools.visualization._counts_visualization.py`, - `qiskit.tools.visualization._state_visualization.py`, - and `qiskit.tools.visualization.interactive` have been - modified to make them in-line with standard Matplotlib calling - conventions (\#1359). -- Remove local backend (Aer) fallback (\#1303). -- DAGCircuits store Instruction and Register objects, instead of name - references. The DAGCircuit class methods are updated accordingly - (\#1210). -- `transpile()` now takes QuantumCircuit(s) to QuantumCircuit(s), and - DAG processing is only done internally (\#1397). -- The different unrollers are deprecated. The only unrolling happens - from DAG to DAG (\#1210). -- Moved all the circuit modules into a circuit module but for most - users it is still imported in the top level for QuantumCircuit, - QuantumRegister, ClassicalRegister -- `qiskit.backends` has been renamed to `qiskit.providers` (\#1531). -- `qiskit.backends.aer` has been removed in favor of - `qiskit.providers.builtinsimulators` (Python simulators) and - `qiskit.providers.legacysimulators` (C++ simulators) (\#1484) -- `Aer` in `qiskit` root module depends on having the qiskit-aer - package installed, by default it is not present. Instead there are 2 - new provider instances in the root module `BasicAer` which provides - the Python simulators and `LegacySimulators` which provides the old - C++ simulators in qiskit-terra. (\#1484) - -### Deprecated - -- `plot_circuit()`, `latex_circuit_drawer()`, `generate_latex_source()`, - and `matplotlib_circuit_drawer()` from - qiskit.tools.visualization are deprecated. Instead the - `circuit_drawer()` function from the same module should be used. - (\#1055) -- The current default output of `circuit_drawer()` (using latex and falling - back on python) is deprecated and will be changed in the future. - (\#1055) -- The `qiskit.wrapper.load_qasm_string()` and - `qiskit.wrapper.load_qasm_file()` functions are - deprecated and the `QuantumCircuit.from_qasm_str()` - and `QuantumCircuit.from_qasm_file()` contstructor - methods should be used instead (\#1172) -- The `plot_barriers` and `reverse_bits` keys in the `style` kwarg - dict are deprecated, instead the - `qiskit.tools.visualization.circuit_drawer()` kwargs - `plot_barriers` and `reverse_bits` should be used instead. (\#1180) -- The `transpile_dag()` function `format` kwarg for emitting different - output formats is deprecated (\#1319). -- Several methods of `qiskit.Result` have been deprecated (\#1360). -- The functions `plot_state()` and - `iplot_state()` have been depreciated. Instead the - functions `plot_state_\*()` and - `iplot_state_\*()` should be called. (\#1359) -- The `skip_transpiler` arg has been deprecated from `compile()` and - `execute()` in favor of using the PassManager directly. - -### Fixed - -- Fixed a variety of typos throughout sources (\#1139) -- Fixed horizontal spacing when drawing barriers before CCNOT gates in - latex circuit plots (\#1051) -- Use case insensitive matching when comparing premium account URLs. - (\#1102) -- Fixed AerJob status when the submitted Job is in a PENDING state. - (\#1215) -- Add fallback for when CPU count can\'t be determined (\#1214) -- Fix `random_state` from returning nan (\#1258) -- The Clifford simulator `run()` method now works - correctly with the updated AerJob usage (\#1125) -- Fixed an edge case when connection checks would raise an unhandled - exception (\#1226) -- Fixed a bug where the transpiler moved middle-of-circuit - measurements to the end (\#1334) -- The `number_to_keep` kwarg in `plot_histgram()` now - functions correctly (\#1359). -- parallel\_map no longer creates a progress bar for a single circuit - (\#1394). -- The `timeout` parameter is now passed into the inner - `_wait_for_submission` function in `IBMQJob` from `_wait_for_result` - (\#1542). - -### Removed - -- Remove register, available\_backends (\#1131). -- Remove tools/apps (\#1184). -- Removed the dependency on `IBMQuantumExperience`, as it is now - included in `qiskit.backends.IBMQ` (\#1198). -- `matplotlib` is no longer in the package requirements and is now an - optional dependency. In order to use any matplotlib based - visualizations (which includes the - `qiskit.tools.visualization.circuit_drawer()` `mpl` output, - `qiskit.tools.visualization.plot_state`, - `qiskit.tools.visualization.plot_histogram`, and - `qiskit.tools.visualization.plot_bloch_vector` you will now need to - ensure you manually install and configure matplotlib independently. -- The `basis` kwarg for the `circuit_drawer()` function to provide an - alternative list of basis gates has been removed. Instead users - should adjust the basis gates prior to visualizing the circuit. - (\#1151) -- `backend.parameters()` and `backend.calibration()` have been fully - deprecated, in favour of `backend.properties()` (\#1305). -- The `qiskit.tools.file_io` module has been removed. Conversion - between `qiskit.Result` and json can be achieved using `.to_dict()` - and `.from_dict()` directly (\#1360). -- The `qiskit.Result` class method for `len()` and indexing have been - removed, along with the functions that perform post-processing - (\#1351). -- The `get_snapshot()` and `get_snapshots()` method from the `Result` - class has been removed. Instead you can access the snapshots in a - Result using `Result.data()['snapshots']`. -- Completed the deprecation of `job.backend_name()`, `job.id()`, and - the `backend_name` parameter in its constructor. -- The `qiskit.Result` class now does post-processing of results - returned from backends if they are called via the `Result.get_xxx()` - methods (i.e. `get_counts()`, `get_memory()`, `get_statevector()`, - `get_unitary()`). The raw data is accessible through `Result.data()` - (\#1404). -- The `transpile()` function kwarg `format` has been removed and will - always return a circuit object. Instead you\'ll need to manually - convert the output with the functions provided in - `qiskit.converters`. - -## [0.6.0] - 2018-10-04 - -### Added - -- Added `SchemaValidationError` to be thrown when schema - validation fails (\#881) -- Generalized Qobj schema validation functions for all qiskit schemas - (\#882). -- Added decorator to check for C++ simulator availability (\#662) -- It is possible to cancel jobs in non comercial backends (\#687) -- Introduced new `qiskit.IBMQ` provider, with centralized - handling of IBMQ credentials (qiskitrc file, environment variables). - (\#547, \#948, \#1000) -- Add OpenMP parallelization for Apple builds of the cpp simulator - (\#698). -- Add parallelization utilities (\#701) -- Parallelize transpilation (\#701) -- New interactive visualizations (\#765). -- Added option to reverse the qubit order when plotting a circuit. - (\#762, \#786) -- Jupyter notebook magic function qiskit\_job\_status, - qiskit\_progress\_bar (\#701, \#734) -- Add a new function `qobj_to_circuits` to convert a Qobj object to a - list of QuantumCircuit objects (\#877) -- Allow selective loading of accounts from disk via hub/group/project - filters to `IBMQ.load_accounts()`. -- Add new `job_monitor` function to automaically check - the status of a job (\#975). - -### Changed - -- Schema tests in `tests/schemas/test_schemas.py` - replaced with proper unit test (\#834). -- Renamed `QISKit` to `Qiskit` in the documentation. (\#634) -- Use `Qobj` as the formally defined schema for sending information to - the devices: - - introduce the `qiskit.qobj` module. (\#589, \#655) - - update the `Qobj` JSON schema. (\#668, \#677, \#703, \#709) - - update the local simulators for accepting `Qobj` as input. - (\#667) - - update the `Result` class. (\#773) -- Use `get_status_job()` for checking IBMQJob status. (\#641) -- Q network hub/group/project credentials replaced by new url format. - (\#740) -- Breaking change: `Jobs` API simplification. (\#686) -- Breaking change: altered tomography APIs to not use QuantumProgram. - (\#818) -- Breaking change: `BaseBackend` API changed, properties are now - methods (\#858) -- When `plot_histogram()` or `plot_state()` are called from a jupyter - notebook if there is network connectivity the interactive plots will - be used by default (\#862, \#866) -- Breaking change: `BaseJob` API changed, any job constructor must be - passed the backend used to run them and a unique job id (\#936). -- Add support for drawing circuit barriers to the latex circuit - drawer. This requires having the LaTeX qcircuit package - version \>=2.6.0 installed (\#764) - -### Deprecated - -- The `number_to_keep` kwarg on the `plot_histogram()` function is now - deprecated. A field of the same name should be used in the `option` - dictionary kwarg instead. (\#866) -- Breaking change: `backend.properties()` instead of - `backend.calibration()` and `backend.parameters()` (\#870) - -### Removed - -- Removed the QuantumProgram class. (\#724) - -### Fixed - -- Fixed `get_ran_qasm` methods on `Result` instances (\#688). -- Fixed `probabilities_ket` computation in C++ simulator (\#580). -- Fixed bug in the definition of `cswap` gate and its test (\#685). -- Fixed the examples to be compatible with version 0.5+ (\#672). -- Fixed swap mapper using qubits after measurement (\#691). -- Fixed error in cpp simulator for 3+ qubit operations (\#698). -- Fixed issue with combining or extending circuits that contain - CompositeGate (\#710). -- Fixed the random unitary generation from the Haar measure (\#760). -- Fixed the issue with control lines spanning through several - classical registers (\#762). -- Fixed visualizations crashing when using simulator extensions - (\#885). -- Fixed check for network connection when loading interactive - visualizations (\#892). -- Fixed bug in checking that a circuit already matches a coupling map - (\#1024). - -## [0.5.7] - 2018-07-19 - -### Changed - -- Add new backend names support, with aliasing for the old ones. - -## [0.5.6] - 2018-07-06 - -### Changed - -- Rename repository to `qiskit-terra` (\#606). -- Update Bloch sphere to QuTiP version (\#618). -- Adjust margin of matplotlib\_circuit\_drawer (\#632) - -### Removed - -- Remove OpenQuantumCompiler (\#610). - -### Fixed - -- Fixed broken process error and simulator slowdown on Windows - (\#613). -- Fixed yzy\_to\_zyz bugs (\#520, \#607) by moving to quaternions - (\#626). - -## [0.5.5] - 2018-07-02 - -### Added - -- Retrieve IBM Q jobs from server (\#563, \#585). -- Add German introductory documentation (`doc/de`) (\#592). -- Add `unregister()` for removing previously registered providers - (\#584). -- Add matplotlib-based circuit drawer (\#579). -- Adding backend filtering by least busy (\#575). -- Allow running with new display names for IBMQ devices, and return - those from `available_backends()` (\#566) -- Introduce Qiskit Transpiler and refactor compilation flow (\#578) -- Add CXCancellation pass (\#578) - -### Changed - -- Remove backend filtering in individual providers, keep only in - wrapper (\#575). -- Single source of version information (\#581) -- Bumped IBMQuantumExperience dependency to 1.9.6 (\#600). -- For backend status, `status\[\'available\'\]` is now - `status\[\'operational\'\]` (\#609). -- Added support for registering third-party providers in - `register()` (\#602). -- Order strings in the output of `available_backends()` (\#566) - -### Removed - -- Remove Clifford simulator from default available\_backends, until - its stable release (\#555). -- Remove ProjectQ simulators for moving to new repository (\#553). -- Remove QuantumJob class (\#616) - -### Fixed - -- Fix issue with unintended inversion of initializer gates (\#573). -- Fix issue with skip\_transpiler causing some gates to be ignored - silently (\#562). - -## [0.5.4] - 2018-06-11 - -### Added - -- Performance improvements: - - remove deepcopies from dagcircuit, and extra check on qasm() - (\#523). - -### Changed - -- Rename repository to `qiskit-core` (\#530). -- Repository improvements: new changelog format (\#535), updated issue - templates (\#531). -- Renamed the specification schemas (\#464). -- Convert `LocalJob` tests into unit-tests. (\#526) -- Move wrapper `load_qasm_*` methods to a submodule (\#533). - -### Removed - -- Remove Sympy simulators for moving to new repository (\#514) - -### Fixed - -- Fix erroneous density matrix and probabilities in C++ simulator - (\#518) -- Fix hardcoded backend mapping tests (\#521) -- Removed `_modifiers call` from `reapply` (\#534) -- Fix circuit drawer issue with filename location on windows (\#543) -- Change initial qubit layout only if the backend coupling map is not - satisfied (\#527) -- Fix incorrect unrolling of t to tdg in CircuitBackend (\#557) -- Fix issue with simulator extension commands not reapplying correctly - (\#556) - -## [0.5.3] - 2018-05-29 - -### Added - -- load\_qasm\_file / load\_qasm\_string methods - -### Changed - -- Dependencies version bumped - -### Fixed - -- Crash in the cpp simulator for some linux platforms -- Fixed some minor bugs - -## [0.5.2] - 2018-05-21 - -### Changed - -- Adding Result.get\_unitary() - -### Deprecated - -- Deprecating `ibmqx_hpc_qasm_simulator` and `ibmqx_qasm_simulator` in - favor of `ibmq_qasm_simulator`. - -### Fixed - -- Fixing a Mapper issue. -- Fixing Windows 7 builds. - -## [0.5.1] - 2018-05-15 - -- There are no code changes. - - MacOS simulator has been rebuilt with external user libraries - compiled statically, so there's no need for users to have a - preinstalled gcc environment. - - Pypi forces us to bump up the version number if we want to upload a - new package, so this is basically what have changed. - -## [0.5.0] - 2018-05-11 - -### Improvements - -- Introduce providers and rework backends (\#376). - - Split backends into `local` and `ibmq`. - - Each provider derives from the following classes for its - specific requirements (`BaseProvider`, `BaseBackend`, - `BaseJob`). - - Allow querying result by both circuit name and - QuantumCircuit instance. -- Introduce the Qiskit `wrapper` (\#376). - - Introduce convenience wrapper functions around commonly used - Qiskit components (e.g. `compile` and `execute` functions). - - Introduce the DefaultQISKitProvider, which acts as a context - manager for the current session (e.g. providing easy access - to all `available_backends`). - - Avoid relying on QuantumProgram (eventual deprecation). - - The functions are also available as top-level functions (for - example, `qiskit.get_backend()`). -- Introduce `BaseJob` class and asynchronous jobs (\#403). - - Return `BaseJob` after `run()`. - - Mechanisms for querying `status` and `results`, or to - `cancel` a job. -- Introduce a `skip_transpiler` flag for `compile()` (\#411). -- Introduce schemas for validating interfaces between qiskit and - backends (\#434) - - qobj\_schema - - result\_schema - - job\_status\_schema - - default\_pulse\_config\_schema - - backend\_config\_schema - - backend\_props\_schema - - backend\_status\_schema -- Improve C++ simulator (\#386) - - Add `tensor_index.hpp` for multi-partite qubit vector - indexing. - - Add `qubit_vector.hpp` for multi-partite qubit vector - algebra. - - Rework C++ simulator backends to use QubitVector class - instead of `std::vector`. -- Improve interface to simulator backends (\#435) - - Introduce `local_statevector_simulator_py` and - `local_statevector_simulator_cpp`. - - Introduce aliased and deprecated backend names and - mechanisms for resolving them. - - Introduce optional `compact` flag to query backend names - only by unique function. - - Introduce result convenience functions `get_statevector`, - `get_unitary` - - Add `snapshot` command for caching a copy of the current - simulator state. -- Introduce circuit drawing via `circuit_drawer()` and - `plot_circuit()` (\#295, \#414) -- Introduce benchmark suite for performance testing - (`test/performance`) (\#277) -- Introduce more robust probability testing via assertDictAlmostEqual - (\#390) -- Allow combining circuits across both depth and width (\#389) -- Enforce string token names (\#395) - -### Fixed - -- Fix coherent error bug in `local_qasm_simulator_cpp` (\#318) -- Fix the order and format of result bits obtained from device - backends (\#430) -- Fix support for noises in the idle gate of - `local_clifford_simulator_cpp` (\#440) -- Fix JobProcessor modifying input qobj (\#392) (and removed - JobProcessor during \#403) -- Fix ability to apply all gates on register (\#369) - -### Deprecated - -- Some methods of `QuantumProgram` are soon to be deprecated. Please - use the top-level functions instead. -- The `Register` instantiation now expects `size, name`. Using - `name, size` is still supported but will be deprecated in the - future. -- Simulators no longer return wavefunction by setting shots=1. - Instead, use the `local_statevector_simulator`, or explicitly ask - for `snapshot`. -- Return `job` instance after `run()`, rather than `result`. -- Rename simulators according to - `PROVIDERNAME_SIMPLEALIAS_simulator_LANGUAGEORPROJECT` -- Move simulator extensions to `qiskit/extensions/simulator` -- Move Rzz and CSwap to standard extension library - -## [0.4.15] - 2018-05-07 - -### Fixed - -- Fixed an issue with legacy code that was affecting Developers - Challenge. - -## [0.4.14] - 2018-04-18 - -### Fixed - -- Fixed an issue about handling Basis Gates parameters on backend - configurations. - -## [0.4.13] - 2018-04-16 - -### Changed - -- OpenQuantumCompiler.dag2json() restored for backward compatibility. - -### Fixed - -- Fixes an issue regarding barrier gate misuse in some circumstances. - -## [0.4.12] - 2018-03-11 - -### Changed - -- Improved circuit visualization. -- Improvements in infrastructure code, mostly tests and build system. -- Better documentation regarding contributors. - -### Fixed - -- A bunch of minor bugs have been fixed. - -## [0.4.11] - 2018-03-13 - -### Added - -- More testing :) - -### Changed - -- Stabilizing code related to external dependencies. - -### Fixed - -- Fixed bug in circuit drawing where some gates in the standard - library were not plotting correctly. - -## [0.4.10] - 2018-03-06 - -### Added - -- Chinese translation of README. - -### Changed - -- Changes related with infrastructure (linter, tests, automation) - enhancement. - -### Fixed - -- Fix installation issue when simulator cannot be built. -- Fix bug with auto-generated CNOT coherent error matrix in C++ - simulator. -- Fix a bug in the async code. - -## [0.4.9] - 2018-02-12 - -### Changed - -- CMake integration. -- QASM improvements. -- Mapper optimizer improvements. - -### Fixed - -- Some minor C++ Simulator bug-fixes. - -## [0.4.8] - 2018-01-29 - -### Fixed - -- Fix parsing U\_error matrix in C++ Simulator python helper class. -- Fix display of code-blocks on `.rst` pages. - -## [0.4.7] - 2018-01-26 - -### Changed - -- Changes some naming conventions for `amp_error` noise parameters to - `calibration_error`. - -### Fixed - -- Fixes several bugs with noise implementations in the simulator. -- Fixes many spelling mistakes in simulator README. - -## [0.4.6] - 2018-01-22 - -### Changed - -- We have upgraded some of out external dependencies to: - - matplotlib \>=2.1,\<2.2 - - networkx\>=1.11,\<2.1 - - numpy\>=1.13,\<1.15 - - ply==3.10 - - scipy\>=0.19,\<1.1 - - Sphinx\>=1.6,\<1.7 - - sympy\>=1.0 - -## [0.4.4] - 2018-01-09 - -### Changed - -- Update dependencies to more recent versions. - -### Fixed - -- Fix bug with process tomography reversing qubit preparation order. - -## [0.4.3] - 2018-01-08 - -### Removed - -- Static compilation has been removed because it seems to be failing - while installing Qiskit via pip on Mac. - -## [0.4.2] - 2018-01-08 - -### Fixed - -- Minor bug fixing related to pip installation process. - -## [0.4.0] - 2018-01-08 - -### Added - -- Job handling improvements. - - Allow asynchronous job submission. - - New JobProcessor class: utilizes concurrent.futures. - - New QuantumJob class: job description. -- Modularize circuit \"compilation\". - - Takes quantum circuit and information about backend to transform - circuit into one which can run on the backend. -- Standardize job description. - - All backends take QuantumJob objects which wraps `qobj` program - description. -- Simplify addition of backends, where circuits are run/simulated. - - `qiskit.backends` package added. - - Real devices and simulators are considered \"backends\" - which inherent from `BaseBackend`. -- Reorganize and improve Sphinx documentation. -- Improve unittest framework. -- Add tools for generating random circuits. -- New utilities for fermionic Hamiltonians - (`qiskit/tools/apps/fermion`). -- New utilities for classical optimization and chemistry - (`qiskit/tools/apps/optimization`). -- Randomized benchmarking data handling. -- Quantum tomography (`qiskit/tools/qcvv`). - - Added functions for generating, running and fitting process - tomography experiments. -- Quantum information functions (`qiskit/tools/qi`). - - Partial trace over subsystems of multi-partite vector. - - Partial trace over subsystems of multi-partite matrix. - - Flatten an operator to a vector in a specified basis. - - Generate random unitary matrix. - - Generate random density matrix. - - Generate normally distributed complex matrix. - - Generate random density matrix from Hilbert-Schmidt metric. - - Generate random density matrix from the Bures metric. - - Compute Shannon entropy of probability vector. - - Compute von Neumann entropy of quantum state. - - Compute mutual information of a bipartite state. - - Compute the entanglement of formation of quantum state. -- Visualization improvements (`qiskit/tools`). - - Wigner function representation. - - Latex figure of circuit. -- Use python logging facility for info, warnings, etc. -- Auto-deployment of sphinx docs to github pages. -- Check IBMQuantumExperience version at runtime. -- Add QuantumProgram method to reconfigure already generated qobj. -- Add Japanese introductory documentation (`doc/ja`). -- Add Korean translation of readme (`doc/ko`). -- Add appveyor for continuous integration on Windows. -- Enable new IBM Q parameters for hub/group/project. -- Add QuantumProgram methods for destroying registers and circuits. -- Use Sympy for evaluating expressions. -- Add support for ibmqx\_hpc\_qasm\_simulator backend. -- Add backend interface to Project Q C++ simulator. - - Requires installation of Project Q. -- Introduce `Initialize` class. - - Generates circuit which initializes qubits in arbitrary state. -- Introduce `local_qiskit_simulator` a C++ simulator with realistic noise. - - Requires C++ build environment for `make`-based build. -- Introduce `local_clifford_simulator` a C++ Clifford simulator. - - Requires C++ build environment for `make`-based build. - -### Changed - -- The standard extension for creating U base gates has been modified - to be consistent with the rest of the gate APIs (see \#203). - -### Removed - -- The `silent` parameter has been removed from a number of - `QuantumProgram` methods. The same behaviour can be achieved now by - using the `enable_logs()` and `disable_logs()` methods, which use - the standard Python logging. - -### Fixed - -- Fix basis gates (\#76). -- Enable QASM parser to work in multiuser environments. -- Correct operator precedence when parsing expressions (\#190). -- Fix \"math domain error\" in mapping (\#111, \#151). - -[UNRELEASED]: https://github.com/Qiskit/qiskit-terra/compare/0.9.0...HEAD -[0.9.0]: https://github.com/Qiskit/qiskit-terra/compare/0.8.2...0.9.0 -[0.8.2]: https://github.com/Qiskit/qiskit-terra/compare/0.8.1...0.8.2 -[0.8.1]: https://github.com/Qiskit/qiskit-terra/compare/0.8.0...0.8.1 -[0.8.0]: https://github.com/Qiskit/qiskit-terra/compare/0.7.2...0.8.0 -[0.7.2]: https://github.com/Qiskit/qiskit-terra/compare/0.7.1...0.7.2 -[0.7.1]: https://github.com/Qiskit/qiskit-terra/compare/0.7.0...0.7.1 -[0.7.0]: https://github.com/Qiskit/qiskit-terra/compare/0.6.0...0.7.0 -[0.6.0]: https://github.com/Qiskit/qiskit-terra/compare/0.5.7...0.6.0 -[0.5.7]: https://github.com/Qiskit/qiskit-terra/compare/0.5.6...0.5.7 -[0.5.6]: https://github.com/Qiskit/qiskit-terra/compare/0.5.5...0.5.6 -[0.5.5]: https://github.com/Qiskit/qiskit-terra/compare/0.5.4...0.5.5 -[0.5.4]: https://github.com/Qiskit/qiskit-terra/compare/0.5.3...0.5.4 -[0.5.3]: https://github.com/Qiskit/qiskit-terra/compare/0.5.2...0.5.3 -[0.5.2]: https://github.com/Qiskit/qiskit-terra/compare/0.5.1...0.5.2 -[0.5.1]: https://github.com/Qiskit/qiskit-terra/compare/0.5.0...0.5.1 -[0.5.0]: https://github.com/Qiskit/qiskit-terra/compare/0.4.15...0.5.0 -[0.4.15]: https://github.com/Qiskit/qiskit-terra/compare/0.4.14...0.4.15 -[0.4.14]: https://github.com/Qiskit/qiskit-terra/compare/0.4.13...0.4.14 -[0.4.13]: https://github.com/Qiskit/qiskit-terra/compare/0.4.12...0.4.13 -[0.4.12]: https://github.com/Qiskit/qiskit-terra/compare/0.4.11...0.4.12 -[0.4.11]: https://github.com/Qiskit/qiskit-terra/compare/0.4.10...0.4.11 -[0.4.10]: https://github.com/Qiskit/qiskit-terra/compare/0.4.9...0.4.10 -[0.4.9]: https://github.com/Qiskit/qiskit-terra/compare/0.4.8...0.4.9 -[0.4.8]: https://github.com/Qiskit/qiskit-terra/compare/0.4.7...0.4.8 -[0.4.7]: https://github.com/Qiskit/qiskit-terra/compare/0.4.6...0.4.7 -[0.4.6]: https://github.com/Qiskit/qiskit-terra/compare/0.4.5...0.4.6 -[0.4.4]: https://github.com/Qiskit/qiskit-terra/compare/0.4.3...0.4.4 -[0.4.3]: https://github.com/Qiskit/qiskit-terra/compare/0.4.2...0.4.3 -[0.4.2]: https://github.com/Qiskit/qiskit-terra/compare/0.4.1...0.4.2 -[0.4.0]: https://github.com/Qiskit/qiskit-terra/compare/0.3.16...0.4.0 - -[Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 09afd818d241..fcc7fcd09839 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -100,8 +100,31 @@ please ensure that: 3. If it makes sense for your change that you have added new tests that cover the changes. 4. Ensure that if your change has an end user facing impact (new feature, - deprecation, removal etc) that you have updated the CHANGELOG.md and - added a reno release note for that change. + deprecation, removal etc) that you have added a reno release note for that + change and that the PR is tagged for the changelog. + +### Changelog generation + +The changelog is automatically generated as part of the release process +automation. This works through a combination of the git log and the pull +request. When a release is tagged and pushed to github the release automation +bot looks at all commit messages from the git log for the release. It takes the +PR numbers from the git log (assuming a squash merge) and checks if that PR had +a `Changelog:` label on it. If there is a label it will add the git commit +message summary line from the git log for the release to the changelog. + +If there are multiple `Changelog:` tags on a PR the git commit message summary +line from the git log will be used for each changelog category tagged. + +The current categories for each label are as follows: + +| PR Label | Changelog Category | +| -----------------------|--------------------| +| Changelog: Deprecation | Deprecated | +| Changelog: New Feature | Added | +| Changelog: API Change | Changed | +| Changelog: Removal | Removed | +| Changelog: Bugfix | Fixed | ### Commit messages @@ -157,6 +180,10 @@ git annotate messages, gitk viewer annotations, merge commit messages, and many more places where space is at a premium. As well as summarizing the change itself, it should take care to detail what part of the code is affected. +In addition the first line of the commit message gets used as entries in the +generated changelog if the PR is tagged as being included in the changelog. +It's critically important that you write a clear and succinct summary lines. + * Describe any limitations of the current code. If the code being changed still has future scope for improvements, or any known @@ -450,7 +477,7 @@ the project boards in Github for project management. We use milestones in Github to track work for specific releases. The features or other changes that we want to include in a release will be tagged and discussed in Github. As we're preparing a new release we'll document what has changed since the -previous version in the release notes and Changelog. +previous version in the release notes. ### Branches @@ -471,11 +498,18 @@ merged to it are bugfixes. When it is time to release a new minor version of qiskit-terra we will: -1. Create a stable branch for the new minor version from the current - HEAD on the `master` branch -2. Create a new tag with the version number on the HEAD of the new stable - branch. -3. Change the `master` version to the next release version. +1. Create a new tag with the version number and push it to github +2. Change the `master` version to the next release version. + +The release automation processes will be triggered by the new tag and perform +the following steps: + +1. Create a stable branch for the new minor version from the release tag + on the `master` branch +2. Build and upload binary wheels to pypi +3. Create a github release page with a generated changelog +4. Generate a PR on the meta-repository to bump the terra version and + meta-package version. The `stable/*` branches should only receive changes in the form of bug fixes. diff --git a/README.md b/README.md index c26fc7b133c5..157908b73065 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,27 @@ Now you're set up and ready to check out some of the other examples from our Qiskit Terra is the work of [many people](https://github.com/Qiskit/qiskit-terra/graphs/contributors) who contribute to the project at different levels. If you use Qiskit, please cite as per the included [BibTeX file](https://github.com/Qiskit/qiskit/blob/master/Qiskit.bib). +## Changelog and Release Notes + +The changelog for a particular release is dynamically generated and gets +written to the release page on Github for each release. For example, you can +find the page for the `0.9.0` release here: + +https://github.com/Qiskit/qiskit-terra/releases/tag/0.9.0 + +The changelog for the current release can be found in the releases tab: +![](https://img.shields.io/github/release/Qiskit/qiskit-terra.svg?style=popout-square) +The changelog provides a quick overview of noteable changes for a given +release. + +Additionally, as part of each release detailed release notes are written to +document in detail what has changed as part of a release. This includes any +documentation on potential breaking changes on upgrade and new features. +For example, You can find the release notes for the `0.9.0` release in the +Qiskit documentation here: + +https://qiskit.org/documentation/release_notes.html#terra-0-9 + ## License [Apache License 2.0](LICENSE.txt) diff --git a/qiskit/assembler/assemble_schedules.py b/qiskit/assembler/assemble_schedules.py index 24ca27bf30e7..dd3739e607f9 100644 --- a/qiskit/assembler/assemble_schedules.py +++ b/qiskit/assembler/assemble_schedules.py @@ -83,7 +83,7 @@ def assemble_schedules(schedules, qobj_id, qobj_header, run_config): instruction = PulseInstruction( command=SamplePulse(name=name, samples=instruction.command.samples), name=instruction.name, - channel=instruction.timeslots.channels[0]) + channel=instruction.channels[0]) # add samples to pulse library user_pulselib[name] = instruction.command diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index cb3a0f991d72..809afceccdfa 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -188,7 +188,7 @@ def mirror(self): reverse_circ = self.copy(name=self.name + '_mirror') reverse_circ._data = [] for inst, qargs, cargs in reversed(self.data): - reverse_circ.append((inst.mirror(), qargs, cargs)) + reverse_circ.append(inst.mirror(), qargs, cargs) return reverse_circ def inverse(self): @@ -234,7 +234,7 @@ def combine(self, rhs): combined_cregs.append(element) circuit = QuantumCircuit(*combined_qregs, *combined_cregs) for instruction_context in itertools.chain(self.data, rhs.data): - circuit.append(*instruction_context) + circuit._append(*instruction_context) return circuit def extend(self, rhs): @@ -261,7 +261,7 @@ def extend(self, rhs): # Add new gates for instruction_context in rhs.data: - self.append(*instruction_context) + self._append(*instruction_context) return self @property diff --git a/qiskit/compiler/transpile.py b/qiskit/compiler/transpile.py index aa14d3ffeaa0..2fcacc993d54 100644 --- a/qiskit/compiler/transpile.py +++ b/qiskit/compiler/transpile.py @@ -24,6 +24,7 @@ from qiskit.circuit.quantumregister import Qubit from qiskit import user_config from qiskit.transpiler.exceptions import TranspilerError +from qiskit.converters import isinstanceint, isinstancelist def transpile(circuits, @@ -330,13 +331,17 @@ def _parse_initial_layout(initial_layout, circuits): # initial_layout could be None, or a list of ints, e.g. [0, 5, 14] # or a list of tuples/None e.g. [qr[0], None, qr[1]] or a dict e.g. {qr[0]: 0} def _layout_from_raw(initial_layout, circuit): - if isinstance(initial_layout, list): - if all(isinstance(elem, int) for elem in initial_layout): + if initial_layout is None or isinstance(initial_layout, Layout): + return initial_layout + elif isinstancelist(initial_layout): + if all(isinstanceint(elem) for elem in initial_layout): initial_layout = Layout.from_intlist(initial_layout, *circuit.qregs) elif all(elem is None or isinstance(elem, Qubit) for elem in initial_layout): initial_layout = Layout.from_qubit_list(initial_layout) elif isinstance(initial_layout, dict): initial_layout = Layout(initial_layout) + else: + raise TranspilerError("The initial_layout parameter could not be parsed") return initial_layout # multiple layouts? diff --git a/qiskit/converters/__init__.py b/qiskit/converters/__init__.py index 2c3fa89968f5..ca668d3a2d0a 100644 --- a/qiskit/converters/__init__.py +++ b/qiskit/converters/__init__.py @@ -21,3 +21,25 @@ from .dag_to_circuit import dag_to_circuit from .ast_to_dag import ast_to_dag from .circuit_to_instruction import circuit_to_instruction + + +def isinstanceint(obj): + """ Like isinstance(obj,int), but with casting. Except for strings.""" + if isinstance(obj, str): + return False + try: + int(obj) + return True + except TypeError: + return False + + +def isinstancelist(obj): + """ Like isinstance(obj, list), but with casting. Except for strings and dicts.""" + if isinstance(obj, (str, dict)): + return False + try: + list(obj) + return True + except TypeError: + return False diff --git a/qiskit/pulse/__init__.py b/qiskit/pulse/__init__.py index 5ff47d933519..87ed22e580f9 100644 --- a/qiskit/pulse/__init__.py +++ b/qiskit/pulse/__init__.py @@ -24,5 +24,4 @@ from .configuration import LoConfig, LoRange from .exceptions import PulseError from .interfaces import ScheduleComponent -# from .parser import parse_string_expr from .schedule import Schedule diff --git a/qiskit/pulse/commands/sample_pulse.py b/qiskit/pulse/commands/sample_pulse.py index ca3240bb7bf0..cbecdc361039 100644 --- a/qiskit/pulse/commands/sample_pulse.py +++ b/qiskit/pulse/commands/sample_pulse.py @@ -55,7 +55,7 @@ def samples(self): """Return sample values.""" return self._samples - def _clip(self, samples: np.ndarray, epsilon: float = 1e-6): + def _clip(self, samples: np.ndarray, epsilon: float = 1e-5): """If samples are within epsilon of unit norm, clip sample by reducing norm by (1-epsilon). If difference is greater than epsilon error is raised. @@ -86,8 +86,10 @@ def _clip(self, samples: np.ndarray, epsilon: float = 1e-6): return samples - def draw(self, dt: float = 1, style: Optional['PulseStyle'] = None, - filename: Optional[str] = None, interp_method: Optional[Callable] = None, + def draw(self, dt: float = 1, + style: Optional['PulseStyle'] = None, + filename: Optional[str] = None, + interp_method: Optional[Callable] = None, scaling: float = 1, interactive: bool = False): """Plot the interpolated envelope of pulse. diff --git a/qiskit/tools/jupyter/backend_monitor.py b/qiskit/tools/jupyter/backend_monitor.py index a1da81bba11f..7d08cf63b9f2 100644 --- a/qiskit/tools/jupyter/backend_monitor.py +++ b/qiskit/tools/jupyter/backend_monitor.py @@ -562,5 +562,4 @@ def get_date(job): ax.add_artist(Circle((0, 0), 0.7, color='white', zorder=1)) ax.text(0, 0, total_jobs, horizontalalignment='center', verticalalignment='center', fontsize=26) - fig.tight_layout() return fig diff --git a/qiskit/transpiler/layout.py b/qiskit/transpiler/layout.py index 4b10e72774a8..8a1143a1a5ff 100644 --- a/qiskit/transpiler/layout.py +++ b/qiskit/transpiler/layout.py @@ -23,6 +23,7 @@ from qiskit.circuit.quantumregister import Qubit from qiskit.transpiler.exceptions import LayoutError +from qiskit.converters import isinstanceint class Layout(): @@ -87,11 +88,11 @@ def from_dict(self, input_dict): @staticmethod def order_based_on_type(value1, value2): """decides which one is physical/virtual based on the type. Returns (virtual, physical)""" - if isinstance(value1, int) and isinstance(value2, (Qubit, type(None))): - physical = value1 + if isinstanceint(value1) and isinstance(value2, (Qubit, type(None))): + physical = int(value1) virtual = value2 - elif isinstance(value2, int) and isinstance(value1, (Qubit, type(None))): - physical = value2 + elif isinstanceint(value2) and isinstance(value1, (Qubit, type(None))): + physical = int(value2) virtual = value1 else: raise LayoutError('The map (%s -> %s) has to be a (Bit -> integer)' @@ -272,7 +273,7 @@ def from_intlist(int_list, *qregs): Raises: LayoutError: Invalid input layout. """ - if not all(isinstance(i, int) for i in int_list): + if not all(isinstanceint(i) for i in int_list): raise LayoutError('Expected a list of ints') if len(int_list) != len(set(int_list)): raise LayoutError('Duplicate values not permitted; Layout is bijective.') diff --git a/qiskit/visualization/circuit_visualization.py b/qiskit/visualization/circuit_visualization.py index 8b304d9fc9b6..d0e320622446 100644 --- a/qiskit/visualization/circuit_visualization.py +++ b/qiskit/visualization/circuit_visualization.py @@ -225,7 +225,7 @@ def circuit_drawer(circuit, return _text_circuit_drawer(circuit, filename=filename, line_length=line_length, reverse_bits=reverse_bits, - plotbarriers=plot_barriers, + plot_barriers=plot_barriers, justify=justify, vertical_compression=vertical_compression, idle_wires=idle_wires, @@ -327,7 +327,6 @@ def qx_color_scheme(): "latexdrawerstyle": True, "usepiformat": False, "cregbundle": False, - "plotbarrier": False, "showindex": False, "compress": True, "margin": [2.0, 0.0, 0.0, 0.3], @@ -342,7 +341,7 @@ def qx_color_scheme(): def _text_circuit_drawer(circuit, filename=None, line_length=None, reverse_bits=False, - plotbarriers=True, justify=None, vertical_compression='high', + plot_barriers=True, justify=None, vertical_compression='high', idle_wires=True, with_layout=True): """ Draws a circuit using ascii art. @@ -355,7 +354,7 @@ def _text_circuit_drawer(circuit, filename=None, line_length=None, reverse_bits= shutil.get_terminal_size(). If you don't want pagination at all, set line_length=-1. reverse_bits (bool): Rearrange the bits in reverse order. - plotbarriers (bool): Draws the barriers when they are there. + plot_barriers (bool): Draws the barriers when they are there. justify (str) : `left`, `right` or `none`. Defaults to `left`. Says how the circuit should be justified. vertical_compression (string): `high`, `medium`, or `low`. It merges the @@ -375,7 +374,7 @@ def _text_circuit_drawer(circuit, filename=None, line_length=None, reverse_bits= else: layout = None text_drawing = _text.TextDrawing(qregs, cregs, ops, layout=layout) - text_drawing.plotbarriers = plotbarriers + text_drawing.plotbarriers = plot_barriers text_drawing.line_length = line_length text_drawing.vertical_compression = vertical_compression diff --git a/qiskit/visualization/gate_map.py b/qiskit/visualization/gate_map.py index c5bc859866a6..cbb826ec2d22 100644 --- a/qiskit/visualization/gate_map.py +++ b/qiskit/visualization/gate_map.py @@ -128,6 +128,21 @@ def plot_gate_map(backend, figsize=None, mpl_data[5] = [[1, 0], [0, 1], [1, 1], [1, 2], [2, 1]] + mpl_data[53] = [[0, 2], [0, 3], [0, 4], [0, 5], [0, 6], + [1, 2], [1, 6], + [2, 0], [2, 1], [2, 2], [2, 3], [2, 4], + [2, 5], [2, 6], [2, 7], [2, 8], + [3, 0], [3, 4], [3, 8], + [4, 0], [4, 1], [4, 2], [4, 3], [4, 4], + [4, 5], [4, 6], [4, 7], [4, 8], + [5, 2], [5, 6], + [6, 0], [6, 1], [6, 2], [6, 3], [6, 4], + [6, 5], [6, 6], [6, 7], [6, 8], + [7, 0], [7, 4], [7, 8], + [8, 0], [8, 1], [8, 2], [8, 3], [8, 4], + [8, 5], [8, 6], [8, 7], [8, 8], + [9, 2], [9, 6]] + config = backend.configuration() n_qubits = config.n_qubits cmap = config.coupling_map @@ -161,7 +176,6 @@ def plot_gate_map(backend, figsize=None, if ax is None: fig, ax = plt.subplots(figsize=figsize) # pylint: disable=invalid-name ax.axis('off') - fig.set_tight_layout(True) # set coloring if qubit_color is None: diff --git a/qiskit/visualization/latex.py b/qiskit/visualization/latex.py index c4abde54f2fa..3b34bcfb8522 100644 --- a/qiskit/visualization/latex.py +++ b/qiskit/visualization/latex.py @@ -721,15 +721,24 @@ def _build_latex_array(self, aliases=None): if self.plot_barriers: qarglist = op.qargs indexes = [self._get_qubit_index(x) for x in qarglist] - start_bit = self.qubit_list[min(indexes)] + indexes.sort() if aliases is not None: qarglist = map(lambda x: aliases[x], qarglist) - start = self.img_regs[start_bit] - span = len(op.qargs) - 1 - self._latex[start][column - 1] += " \\barrier[0em]{" + str( - span) + "}" - self._latex[start][column] = "\\qw" + first = last = indexes[0] + for index in indexes[1:]: + if index - 1 == last: + last = index + else: + pos = self.img_regs[self.qubit_list[first]] + self._latex[pos][column - 1] += " \\barrier[0em]{" + str( + last - first) + "}" + self._latex[pos][column] = "\\qw" + first = last = index + pos = self.img_regs[self.qubit_list[first]] + self._latex[pos][column - 1] += " \\barrier[0em]{" + str( + last - first) + "}" + self._latex[pos][column] = "\\qw" else: raise exceptions.VisualizationError("bad node data") diff --git a/qiskit/visualization/matplotlib.py b/qiskit/visualization/matplotlib.py index 6c43743aeed3..9a59a8213a5e 100644 --- a/qiskit/visualization/matplotlib.py +++ b/qiskit/visualization/matplotlib.py @@ -168,11 +168,14 @@ def _registers(self, creg, qreg): def ast(self): return self._ast - def _custom_multiqubit_gate(self, xy, fc=None, wide=True, text=None, + def _custom_multiqubit_gate(self, xy, cxy=None, fc=None, wide=True, text=None, subtext=None): xpos = min([x[0] for x in xy]) ypos = min([y[1] for y in xy]) ypos_max = max([y[1] for y in xy]) + + if cxy: + ypos = min([y[1] for y in cxy]) if wide: if subtext: boxes_length = round(max([len(text), len(subtext)]) / 8) or 1 @@ -186,7 +189,10 @@ def _custom_multiqubit_gate(self, xy, fc=None, wide=True, text=None, _fc = fc else: if self._style.name != 'bw': - _fc = self._style.dispcol['multi'] + if self._style.gc != DefaultStyle().gc: + _fc = self._style.gc + else: + _fc = self._style.dispcol['multi'] _ec = self._style.dispcol['multi'] else: _fc = self._style.gc @@ -239,6 +245,8 @@ def _gate(self, xy, fc=None, wide=False, text=None, subtext=None): wid = WID if fc: _fc = fc + elif self._style.gc != DefaultStyle().gc: + _fc = self._style.gc elif text and text in self._style.dispcol: _fc = self._style.dispcol[text] else: @@ -383,6 +391,9 @@ def _conds(self, xy, istrue=False): self.ax.add_patch(box) def _ctrl_qubit(self, xy, fc=None, ec=None): + if self._style.gc != DefaultStyle().gc: + fc = self._style.gc + ec = self._style.gc if fc is None: fc = self._style.lc if ec is None: @@ -395,6 +406,9 @@ def _ctrl_qubit(self, xy, fc=None, ec=None): def _tgt_qubit(self, xy, fc=None, ec=None, ac=None, add_width=None): + if self._style.gc != DefaultStyle().gc: + fc = self._style.gc + ec = self._style.gc if fc is None: fc = self._style.dispcol['target'] if ec is None: @@ -873,7 +887,7 @@ def _draw_ops(self, verbose=False): self._line(qreg_b, qreg_t, lc=self._style.dispcol['swap']) # Custom gate else: - self._custom_multiqubit_gate(q_xy, wide=_iswide, + self._custom_multiqubit_gate(q_xy, c_xy, wide=_iswide, text=op.name) # # draw multi-qubit gates (n=3) @@ -906,12 +920,12 @@ def _draw_ops(self, verbose=False): self._line(qreg_b, qreg_t, lc=self._style.dispcol['multi']) # custom gate else: - self._custom_multiqubit_gate(q_xy, wide=_iswide, + self._custom_multiqubit_gate(q_xy, c_xy, wide=_iswide, text=op.name) # draw custom multi-qubit gate elif len(q_xy) > 3: - self._custom_multiqubit_gate(q_xy, wide=_iswide, + self._custom_multiqubit_gate(q_xy, c_xy, wide=_iswide, text=op.name) else: logger.critical('Invalid gate %s', op) diff --git a/qiskit/visualization/qcstyle.py b/qiskit/visualization/qcstyle.py index 64c6239342c8..f5beafdde21b 100644 --- a/qiskit/visualization/qcstyle.py +++ b/qiskit/visualization/qcstyle.py @@ -14,10 +14,14 @@ # pylint: disable=invalid-name,missing-docstring +from copy import copy +from warnings import warn + class DefaultStyle: """IBM Design Style colors """ + def __init__(self): # Set colors basis_color = '#FA74A6' @@ -88,37 +92,39 @@ def __init__(self): self.latexmode = False self.fold = 25 self.bundle = True - self.barrier = True self.index = False self.figwidth = -1 self.dpi = 150 self.margin = [2.0, 0.1, 0.1, 0.3] self.cline = 'doublet' - def set_style(self, dic): - self.tc = dic.get('textcolor', self.tc) - self.sc = dic.get('subtextcolor', self.sc) - self.lc = dic.get('linecolor', self.lc) - self.cc = dic.get('creglinecolor', self.cc) - self.gt = dic.get('gatetextcolor', self.tc) - self.gc = dic.get('gatefacecolor', self.gc) - self.bc = dic.get('barrierfacecolor', self.bc) - self.bg = dic.get('backgroundcolor', self.bg) - self.fs = dic.get('fontsize', self.fs) - self.sfs = dic.get('subfontsize', self.sfs) - self.disptex = dic.get('displaytext', self.disptex) - self.dispcol = dic.get('displaycolor', self.dispcol) - self.latexmode = dic.get('latexdrawerstyle', self.latexmode) - self.fold = dic.get('fold', self.fold) + def set_style(self, style_dic): + dic = copy(style_dic) + self.tc = dic.pop('textcolor', self.tc) + self.sc = dic.pop('subtextcolor', self.sc) + self.lc = dic.pop('linecolor', self.lc) + self.cc = dic.pop('creglinecolor', self.cc) + self.gt = dic.pop('gatetextcolor', self.tc) + self.gc = dic.pop('gatefacecolor', self.gc) + self.bc = dic.pop('barrierfacecolor', self.bc) + self.bg = dic.pop('backgroundcolor', self.bg) + self.fs = dic.pop('fontsize', self.fs) + self.sfs = dic.pop('subfontsize', self.sfs) + self.disptex = dic.pop('displaytext', self.disptex) + self.dispcol = dic.pop('displaycolor', self.dispcol) + self.latexmode = dic.pop('latexdrawerstyle', self.latexmode) + self.fold = dic.pop('fold', self.fold) if self.fold < 2: self.fold = -1 - self.bundle = dic.get('cregbundle', self.bundle) - self.barrier = dic.get('plotbarrier', self.barrier) - self.index = dic.get('showindex', self.index) - self.figwidth = dic.get('figwidth', self.figwidth) - self.dpi = dic.get('dpi', self.dpi) - self.margin = dic.get('margin', self.margin) - self.cline = dic.get('creglinestyle', self.cline) + self.bundle = dic.pop('cregbundle', self.bundle) + self.index = dic.pop('showindex', self.index) + self.figwidth = dic.pop('figwidth', self.figwidth) + self.dpi = dic.pop('dpi', self.dpi) + self.margin = dic.pop('margin', self.margin) + self.cline = dic.pop('creglinestyle', self.cline) + if dic: + warn('style option/s ({}) is/are not ' + 'supported'.format(', '.join(dic.keys())), DeprecationWarning, 2) class BWStyle: @@ -184,36 +190,38 @@ def __init__(self): self.latexmode = False self.fold = 25 self.bundle = True - self.barrier = True self.index = False self.figwidth = -1 self.dpi = 150 self.margin = [2.0, 0.0, 0.0, 0.3] self.cline = 'doublet' - def set_style(self, dic): - self.tc = dic.get('textcolor', self.tc) - self.sc = dic.get('subtextcolor', self.sc) - self.lc = dic.get('linecolor', self.lc) - self.cc = dic.get('creglinecolor', self.cc) - self.gt = dic.get('gatetextcolor', self.tc) - self.gc = dic.get('gatefacecolor', self.gc) - self.bc = dic.get('barrierfacecolor', self.bc) - self.bg = dic.get('backgroundcolor', self.bg) - self.fs = dic.get('fontsize', self.fs) - self.sfs = dic.get('subfontsize', self.sfs) - self.disptex = dic.get('displaytext', self.disptex) + def set_style(self, style_dic): + dic = copy(style_dic) + self.tc = dic.pop('textcolor', self.tc) + self.sc = dic.pop('subtextcolor', self.sc) + self.lc = dic.pop('linecolor', self.lc) + self.cc = dic.pop('creglinecolor', self.cc) + self.gt = dic.pop('gatetextcolor', self.tc) + self.gc = dic.pop('gatefacecolor', self.gc) + self.bc = dic.pop('barrierfacecolor', self.bc) + self.bg = dic.pop('backgroundcolor', self.bg) + self.fs = dic.pop('fontsize', self.fs) + self.sfs = dic.pop('subfontsize', self.sfs) + self.disptex = dic.pop('displaytext', self.disptex) for key in self.dispcol.keys(): self.dispcol[key] = self.gc - self.dispcol = dic.get('displaycolor', self.dispcol) - self.latexmode = dic.get('latexdrawerstyle', self.latexmode) - self.fold = dic.get('fold', self.fold) + self.dispcol = dic.pop('displaycolor', self.dispcol) + self.latexmode = dic.pop('latexdrawerstyle', self.latexmode) + self.fold = dic.pop('fold', self.fold) if self.fold < 2: self.fold = -1 - self.bundle = dic.get('cregbundle', self.bundle) - self.barrier = dic.get('plotbarrier', self.barrier) - self.index = dic.get('showindex', self.index) - self.figwidth = dic.get('figwidth', self.figwidth) - self.dpi = dic.get('dpi', self.dpi) - self.margin = dic.get('margin', self.margin) - self.cline = dic.get('creglinestyle', self.cline) + self.bundle = dic.pop('cregbundle', self.bundle) + self.index = dic.pop('showindex', self.index) + self.figwidth = dic.pop('figwidth', self.figwidth) + self.dpi = dic.pop('dpi', self.dpi) + self.margin = dic.pop('margin', self.margin) + self.cline = dic.pop('creglinestyle', self.cline) + if dic: + warn('style option/s ({}) is/are not ' + 'supported'.format(', '.join(dic.keys())), DeprecationWarning, 2) diff --git a/qiskit/visualization/state_visualization.py b/qiskit/visualization/state_visualization.py index e8c39be00c9e..0b613aeaaa81 100644 --- a/qiskit/visualization/state_visualization.py +++ b/qiskit/visualization/state_visualization.py @@ -104,7 +104,7 @@ def plot_state_hinton(rho, title='', figsize=None): ax1.set_xticklabels(column_names, fontsize=14, rotation=90) ax1.autoscale_view() ax1.invert_yaxis() - ax1.set_title('Real[rho]', fontsize=14) + ax1.set_title('Re[$\\rho$]', fontsize=14) # Imaginary ax2.patch.set_facecolor('gray') ax2.set_aspect('equal', 'box') @@ -117,17 +117,17 @@ def plot_state_hinton(rho, title='', figsize=None): rect = plt.Rectangle([x - size / 2, y - size / 2], size, size, facecolor=color, edgecolor=color) ax2.add_patch(rect) - if np.any(dataimag != 0): - ax2.set_xticks(np.arange(0, lx+0.5, 1)) - ax2.set_yticks(np.arange(0, ly+0.5, 1)) - ax2.set_yticklabels(row_names, fontsize=14) - ax2.set_xticklabels(column_names, fontsize=14, rotation=90) + + ax2.set_xticks(np.arange(0, lx+0.5, 1)) + ax2.set_yticks(np.arange(0, ly+0.5, 1)) + ax2.set_yticklabels(row_names, fontsize=14) + ax2.set_xticklabels(column_names, fontsize=14, rotation=90) + ax2.autoscale_view() ax2.invert_yaxis() - ax2.set_title('Imag[rho]', fontsize=14) + ax2.set_title('Im[$\\rho$]', fontsize=14) if title: fig.suptitle(title, fontsize=16) - plt.tight_layout() if get_backend() in ['module://ipykernel.pylab.backend_inline', 'nbAgg']: plt.close(fig) @@ -353,7 +353,6 @@ def plot_state_city(rho, title="", figsize=None, color=None, for tick in ax2.zaxis.get_major_ticks(): tick.label.set_fontsize(14) plt.suptitle(title, fontsize=16) - plt.tight_layout() if get_backend() in ['module://ipykernel.pylab.backend_inline', 'nbAgg']: plt.close(fig) @@ -636,7 +635,6 @@ def plot_state_qsphere(rho, figsize=None): ax2.text(0, -offset, r'$3\pi/2$', horizontalalignment='center', verticalalignment='center', fontsize=14) - fig.tight_layout() if get_backend() in ['module://ipykernel.pylab.backend_inline', 'nbAgg']: plt.close(fig) diff --git a/qiskit/visualization/utils.py b/qiskit/visualization/utils.py index 728903b71df7..2b5ee02861b2 100644 --- a/qiskit/visualization/utils.py +++ b/qiskit/visualization/utils.py @@ -64,7 +64,8 @@ def _trim(image): return image -def _get_layered_instructions(circuit, reverse_bits=False, justify=None, idle_wires=True): +def _get_layered_instructions(circuit, reverse_bits=False, + justify=None, idle_wires=True): """ Given a circuit, return a tuple (qregs, cregs, ops) where qregs and cregs are the quantum and classical registers @@ -95,89 +96,8 @@ def _get_layered_instructions(circuit, reverse_bits=False, justify=None, idle_wi for node in dag.topological_op_nodes(): ops.append([node]) - if justify == 'left': - for dag_layer in dag.layers(): - layers = [] - current_layer = [] - - dag_nodes = dag_layer['graph'].op_nodes() - dag_nodes.sort(key=lambda nd: nd._node_id) - - for node in dag_nodes: - multibit_gate = len(node.qargs) + len(node.cargs) > 1 - - if multibit_gate: - # need to see if it crosses over any other nodes - gate_span = _get_gate_span(qregs, node) - - all_indices = [] - for check_node in dag_nodes: - if check_node != node: - all_indices += _get_gate_span(qregs, check_node) - - if any(i in gate_span for i in all_indices): - # needs to be a new layer - layers.append([node]) - else: - # can be added - current_layer.append(node) - else: - current_layer.append(node) - - if current_layer: - layers.append(current_layer) - ops += layers - - if justify == 'right': - dag_layers = [] - - for dag_layer in dag.layers(): - dag_layers.append(dag_layer) - - # Have to work from the end of the circuit - dag_layers.reverse() - - # Dict per layer, keys are qubits and values are the gate - layer_dicts = [{}] - - for dag_layer in dag_layers: - - dag_instructions = dag_layer['graph'].op_nodes() - - # sort into the order they were input - dag_instructions.sort(key=lambda nd: nd._node_id) - for instruction_node in dag_instructions: - - gate_span = _get_gate_span(qregs, instruction_node) - - added = False - for i in range(len(layer_dicts)): - # iterate from the end - curr_dict = layer_dicts[-1 - i] - - if any(index in curr_dict for index in gate_span): - added = True - - if i == 0: - new_dict = {} - - for index in gate_span: - new_dict[index] = instruction_node - layer_dicts.append(new_dict) - else: - curr_dict = layer_dicts[-i] - for index in gate_span: - curr_dict[index] = instruction_node - - break - - if not added: - for index in gate_span: - layer_dicts[0][index] = instruction_node - - # need to convert from dict format to layers - layer_dicts.reverse() - ops = [list(layer.values()) for layer in layer_dicts] + else: + ops = _LayerSpooler(dag, justify) if reverse_bits: qregs.reverse() @@ -193,9 +113,20 @@ def _get_layered_instructions(circuit, reverse_bits=False, justify=None, idle_wi return qregs, cregs, ops -def _get_gate_span(qregs, instruction): - """Get the list of qubits drawing this gate would cover""" +def _sorted_nodes(dag_layer): + """Convert DAG layer into list of nodes sorted by node_id + qiskit-terra #2802 + """ + dag_instructions = dag_layer['graph'].op_nodes() + # sort into the order they were input + dag_instructions.sort(key=lambda nd: nd._node_id) + return dag_instructions + +def _get_gate_span(qregs, instruction): + """Get the list of qubits drawing this gate would cover + qiskit-terra #2802 + """ min_index = len(qregs) max_index = 0 for qreg in instruction.qargs: @@ -208,5 +139,139 @@ def _get_gate_span(qregs, instruction): if instruction.cargs: return qregs[min_index:] + if instruction.condition: + return qregs[min_index:] return qregs[min_index:max_index + 1] + + +def _any_crossover(qregs, node, nodes): + """Return True .IFF. 'node' crosses over any in 'nodes',""" + gate_span = _get_gate_span(qregs, node) + all_indices = [] + for check_node in nodes: + if check_node != node: + all_indices += _get_gate_span(qregs, check_node) + return any(i in gate_span for i in all_indices) + + +class _LayerSpooler(list): + """Manipulate list of layer dicts for _get_layered_instructions.""" + + def __init__(self, dag, justification): + """Create spool""" + super(_LayerSpooler, self).__init__() + self.dag = dag + self.qregs = dag.qubits() + self.justification = justification + + if self.justification == 'left': + + for dag_layer in dag.layers(): + current_index = len(self) - 1 + dag_nodes = _sorted_nodes(dag_layer) + for node in dag_nodes: + self.add(node, current_index) + + else: + dag_layers = [] + + for dag_layer in dag.layers(): + dag_layers.append(dag_layer) + + # going right to left! + dag_layers.reverse() + + for dag_layer in dag_layers: + current_index = 0 + dag_nodes = _sorted_nodes(dag_layer) + for node in dag_nodes: + self.add(node, current_index) + + def is_found_in(self, node, nodes): + """Is any qreq in node found in any of nodes?""" + all_qargs = [] + for a_node in nodes: + for qarg in a_node.qargs: + all_qargs.append(qarg) + return any(i in node.qargs for i in all_qargs) + + def insertable(self, node, nodes): + """True .IFF. we can add 'node' to layer 'nodes'""" + return not _any_crossover(self.qregs, node, nodes) + + def slide_from_left(self, node, index): + """Insert node into first layer where there is no conflict going l > r""" + if not self: + self.append([node]) + inserted = True + + else: + inserted = False + curr_index = index + last_insertable_index = None + + while curr_index > -1: + if self.is_found_in(node, self[curr_index]): + break + if self.insertable(node, self[curr_index]): + last_insertable_index = curr_index + curr_index = curr_index - 1 + + if last_insertable_index: + self[last_insertable_index].append(node) + inserted = True + + else: + inserted = False + curr_index = index + while curr_index < len(self): + if self.insertable(node, self[curr_index]): + self[curr_index].append(node) + inserted = True + break + curr_index = curr_index + 1 + + if not inserted: + self.append([node]) + + def slide_from_right(self, node, index): + """Insert node into rightmost layer as long there is no conflict.""" + if not self: + self.insert(0, [node]) + inserted = True + + else: + inserted = False + curr_index = index + last_insertable_index = None + + while curr_index < len(self): + if self.is_found_in(node, self[curr_index]): + break + if self.insertable(node, self[curr_index]): + last_insertable_index = curr_index + curr_index = curr_index + 1 + + if last_insertable_index: + self[last_insertable_index].append(node) + inserted = True + + else: + curr_index = index + while curr_index > -1: + if self.insertable(node, self[curr_index]): + self[curr_index].append(node) + inserted = True + break + curr_index = curr_index - 1 + + if not inserted: + self.insert(0, [node]) + + def add(self, node, index): + """Add 'node' where it belongs, starting the try at 'index'.""" + if self.justification == "left": + self.slide_from_left(node, index) + else: + self.slide_from_right(node, index) diff --git a/releasenotes/notes/Instruction-layering-for-circuit-drawing-has-changed-f62ce5aaeb8ce221.yaml b/releasenotes/notes/Instruction-layering-for-circuit-drawing-has-changed-f62ce5aaeb8ce221.yaml new file mode 100644 index 000000000000..4a16dcf8313f --- /dev/null +++ b/releasenotes/notes/Instruction-layering-for-circuit-drawing-has-changed-f62ce5aaeb8ce221.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + Instructions layering which underlies all types of circuit drawing has + changed to address right/left justification. This sometimes results in + output which is topologically equivalent to the rendering in prior versions + but visually different than previously rendered. The change in layering + fixes qiskit-terra issue \#2802 diff --git a/releasenotes/notes/deprecate_unknown_styles-93f84aedd1887c44.yaml b/releasenotes/notes/deprecate_unknown_styles-93f84aedd1887c44.yaml new file mode 100644 index 000000000000..7ada0d9f524c --- /dev/null +++ b/releasenotes/notes/deprecate_unknown_styles-93f84aedd1887c44.yaml @@ -0,0 +1,6 @@ +--- +deprecations: + - | + The matplotlib drawer raises a warning when the `style` argument dictonary includes + a key that is not supported by the drawer. In the future, unsupported keys will raise + an exception. diff --git a/test/python/circuit/test_circuit_operations.py b/test/python/circuit/test_circuit_operations.py index 24e5001953d8..a54fc4f23313 100644 --- a/test/python/circuit/test_circuit_operations.py +++ b/test/python/circuit/test_circuit_operations.py @@ -158,6 +158,26 @@ def test_copy_circuit(self): self.assertEqual(qc, qc.copy()) + def test_mirror(self): + """Test mirror method reverses but does not invert.""" + qc = QuantumCircuit(2, 2) + qc.h(0) + qc.s(1) + qc.cx(0, 1) + qc.measure([0, 1], [0, 1]) + qc.x(0) + qc.y(1) + + expected = QuantumCircuit(2, 2) + expected.y(1) + expected.x(0) + expected.measure([0, 1], [0, 1]) + expected.cx(0, 1) + expected.s(1) + expected.h(0) + + self.assertEqual(qc.mirror(), expected) + class TestCircuitBuilding(QiskitTestCase): """QuantumCircuit tests.""" diff --git a/test/python/transpiler/test_layout.py b/test/python/transpiler/test_layout.py index 95d90f98acd3..cd8b99bc88d5 100644 --- a/test/python/transpiler/test_layout.py +++ b/test/python/transpiler/test_layout.py @@ -17,6 +17,7 @@ import copy import unittest import warnings +import numpy from qiskit.circuit import QuantumRegister, Qubit from qiskit.transpiler.layout import Layout @@ -325,6 +326,19 @@ def test_layout_from_intlist(self): self.assertDictEqual(layout._p2v, expected._p2v) self.assertDictEqual(layout._v2p, expected._v2p) + def test_layout_from_intlist_numpy(self): + """Create a layout from a list of numpy integers. See #3097 + """ + qr1 = QuantumRegister(1, 'qr1') + qr2 = QuantumRegister(2, 'qr2') + qr3 = QuantumRegister(3, 'qr3') + intlist_layout = numpy.array([0, 1, 2, 3, 4, 5]) + layout = Layout.from_intlist(intlist_layout, qr1, qr2, qr3) + + expected = Layout.generate_trivial_layout(qr1, qr2, qr3) + self.assertDictEqual(layout._p2v, expected._p2v) + self.assertDictEqual(layout._v2p, expected._v2p) + def test_layout_from_intlist_short(self): """If the intlist is longer that your quantum register, map them to None. virtual physical diff --git a/test/python/visualization/test_circuit_matplotlib_drawer.py b/test/python/visualization/test_circuit_matplotlib_drawer.py index f38b92a6eb82..279b45564c04 100644 --- a/test/python/visualization/test_circuit_matplotlib_drawer.py +++ b/test/python/visualization/test_circuit_matplotlib_drawer.py @@ -132,7 +132,7 @@ def test_long_name(self): filename = self._get_resource_path('current_%s_long_name_matplotlib.png' % os.name) visualization.circuit_drawer(circuit, output='mpl', filename=filename) - # self.addCleanup(os.remove, filename) + self.addCleanup(os.remove, filename) ref_filename = self._get_resource_path( 'visualization/references/%s_long_name_matplotlib.png' % os.name) diff --git a/test/python/visualization/test_circuit_text_drawer.py b/test/python/visualization/test_circuit_text_drawer.py index fc1ef42c09fb..cb7c0726a2eb 100644 --- a/test/python/visualization/test_circuit_text_drawer.py +++ b/test/python/visualization/test_circuit_text_drawer.py @@ -536,7 +536,7 @@ def test_text_no_barriers(self): circuit.barrier(qr1) circuit.barrier(qr2[1]) circuit.h(qr2) - self.assertEqual(str(_text_circuit_drawer(circuit, plotbarriers=False)), expected) + self.assertEqual(str(_text_circuit_drawer(circuit, plot_barriers=False)), expected) def test_text_measure_html(self): """ The measure operator. HTML representation. """ diff --git a/test/python/visualization/test_visualization.py b/test/python/visualization/test_visualization.py index 640797e5e7b5..f798f929cb2e 100644 --- a/test/python/visualization/test_visualization.py +++ b/test/python/visualization/test_visualization.py @@ -19,6 +19,7 @@ import unittest from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit +from qiskit.circuit import Qubit, Clbit from qiskit.circuit.random import random_circuit from qiskit.visualization import utils from qiskit.visualization import circuit_drawer @@ -209,6 +210,178 @@ def test_get_layered_instructions_remove_idle_wires(self): self.assertEqual(exp, [[(op.name, op.qargs, op.cargs) for op in ops] for ops in layered_ops]) + def test_get_layered_instructions_left_justification_simple(self): + """ Test _get_layered_instructions left justification simple since #2802 +q_0: |0>───────■── + ┌───┐ │ +q_1: |0>┤ H ├──┼── + ├───┤ │ +q_2: |0>┤ H ├──┼── + └───┘┌─┴─┐ +q_3: |0>─────┤ X ├ + └───┘ +""" + qc = QuantumCircuit(4) + qc.h(1) + qc.h(2) + qc.cx(0, 3) + + (_, _, layered_ops) = utils._get_layered_instructions(qc, justify='left') + + l_exp = [[('h', [Qubit(QuantumRegister(4, 'q'), 1)], []), + ('h', [Qubit(QuantumRegister(4, 'q'), 2)], [])], + [('cx', [Qubit(QuantumRegister(4, 'q'), 0), + Qubit(QuantumRegister(4, 'q'), 3)], []) + ] + ] + + self.assertEqual(l_exp, + [[(op.name, op.qargs, op.cargs) for op in ops] for ops in layered_ops]) + + def test_get_layered_instructions_right_justification_simple(self): + """ Test _get_layered_instructions right justification simple since #2802 +q_0: |0>──■─────── + │ ┌───┐ +q_1: |0>──┼──┤ H ├ + │ ├───┤ +q_2: |0>──┼──┤ H ├ + ┌─┴─┐└───┘ +q_3: |0>┤ X ├───── + └───┘ +""" + qc = QuantumCircuit(4) + qc.h(1) + qc.h(2) + qc.cx(0, 3) + + (_, _, layered_ops) = utils._get_layered_instructions(qc, justify='right') + + r_exp = [[('cx', [Qubit(QuantumRegister(4, 'q'), 0), + Qubit(QuantumRegister(4, 'q'), 3)], [])], + [('h', [Qubit(QuantumRegister(4, 'q'), 1)], []), + ('h', [Qubit(QuantumRegister(4, 'q'), 2)], []) + ] + ] + + self.assertEqual(r_exp, + [[(op.name, op.qargs, op.cargs) for op in ops] for ops in layered_ops]) + + def test_get_layered_instructions_left_justification_less_simple(self): + """ Test _get_layered_instructions left justification + less simple example since #2802 + ┌────────────┐┌───┐┌────────────┐ ┌─┐┌────────────┐┌───┐┌────────────┐ +q_0: |0>┤ U2(0,pi/1) ├┤ X ├┤ U2(0,pi/1) ├──────────────┤M├┤ U2(0,pi/1) ├┤ X ├┤ U2(0,pi/1) ├ + ├────────────┤└─┬─┘├────────────┤┌────────────┐└╥┘└────────────┘└─┬─┘├────────────┤ +q_1: |0>┤ U2(0,pi/1) ├──■──┤ U2(0,pi/1) ├┤ U2(0,pi/1) ├─╫─────────────────■──┤ U2(0,pi/1) ├ + └────────────┘ └────────────┘└────────────┘ ║ └────────────┘ +q_2: |0>────────────────────────────────────────────────╫────────────────────────────────── + ║ +q_3: |0>────────────────────────────────────────────────╫────────────────────────────────── + ║ +q_4: |0>────────────────────────────────────────────────╫────────────────────────────────── + ║ +c1_0: 0 ════════════════════════════════════════════════╩══════════════════════════════════ + """ + qasm = """ + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[5]; + creg c1[1]; + u2(0,3.14159265358979) q[0]; + u2(0,3.14159265358979) q[1]; + cx q[1],q[0]; + u2(0,3.14159265358979) q[0]; + u2(0,3.14159265358979) q[1]; + u2(0,3.14159265358979) q[1]; + measure q[0] -> c1[0]; + u2(0,3.14159265358979) q[0]; + cx q[1],q[0]; + u2(0,3.14159265358979) q[0]; + u2(0,3.14159265358979) q[1]; + """ + qc = QuantumCircuit.from_qasm_str(qasm) + + (_, _, layered_ops) = utils._get_layered_instructions(qc, justify='left') + + l_exp = [[('u2', [Qubit(QuantumRegister(5, 'q'), 0)], []), + ('u2', [Qubit(QuantumRegister(5, 'q'), 1)], [])], + [('cx', + [Qubit(QuantumRegister(5, 'q'), 1), Qubit(QuantumRegister(5, 'q'), 0)], + [])], + [('u2', [Qubit(QuantumRegister(5, 'q'), 0)], []), + ('u2', [Qubit(QuantumRegister(5, 'q'), 1)], [])], + [('u2', [Qubit(QuantumRegister(5, 'q'), 1)], [])], + [('measure', + [Qubit(QuantumRegister(5, 'q'), 0)], + [Clbit(ClassicalRegister(1, 'c1'), 0)])], + [('u2', [Qubit(QuantumRegister(5, 'q'), 0)], [])], + [('cx', + [Qubit(QuantumRegister(5, 'q'), 1), Qubit(QuantumRegister(5, 'q'), 0)], + [])], + [('u2', [Qubit(QuantumRegister(5, 'q'), 0)], []), + ('u2', [Qubit(QuantumRegister(5, 'q'), 1)], [])]] + + self.assertEqual(l_exp, + [[(op.name, op.qargs, op.cargs) for op in ops] for ops in layered_ops]) + + def test_get_layered_instructions_right_justification_less_simple(self): + """ Test _get_layered_instructions right justification + less simple example since #2802 + ┌────────────┐┌───┐┌────────────┐┌─┐┌────────────┐┌───┐┌────────────┐ +q_0: |0>┤ U2(0,pi/1) ├┤ X ├┤ U2(0,pi/1) ├┤M├┤ U2(0,pi/1) ├┤ X ├┤ U2(0,pi/1) ├ + ├────────────┤└─┬─┘├────────────┤└╥┘├────────────┤└─┬─┘├────────────┤ +q_1: |0>┤ U2(0,pi/1) ├──■──┤ U2(0,pi/1) ├─╫─┤ U2(0,pi/1) ├──■──┤ U2(0,pi/1) ├ + └────────────┘ └────────────┘ ║ └────────────┘ └────────────┘ +q_2: |0>──────────────────────────────────╫────────────────────────────────── + ║ +q_3: |0>──────────────────────────────────╫────────────────────────────────── + ║ +q_4: |0>──────────────────────────────────╫────────────────────────────────── + ║ +c1_0: 0 ══════════════════════════════════╩══════════════════════════════════ + """ + qasm = """ + OPENQASM 2.0; + include "qelib1.inc"; + qreg q[5]; + creg c1[1]; + u2(0,3.14159265358979) q[0]; + u2(0,3.14159265358979) q[1]; + cx q[1],q[0]; + u2(0,3.14159265358979) q[0]; + u2(0,3.14159265358979) q[1]; + u2(0,3.14159265358979) q[1]; + measure q[0] -> c1[0]; + u2(0,3.14159265358979) q[0]; + cx q[1],q[0]; + u2(0,3.14159265358979) q[0]; + u2(0,3.14159265358979) q[1]; + """ + qc = QuantumCircuit.from_qasm_str(qasm) + + (_, _, layered_ops) = utils._get_layered_instructions(qc, justify='right') + + r_exp = [[('u2', [Qubit(QuantumRegister(5, 'q'), 0)], []), + ('u2', [Qubit(QuantumRegister(5, 'q'), 1)], [])], + [('cx', + [Qubit(QuantumRegister(5, 'q'), 1), Qubit(QuantumRegister(5, 'q'), 0)], + [])], + [('u2', [Qubit(QuantumRegister(5, 'q'), 0)], []), + ('u2', [Qubit(QuantumRegister(5, 'q'), 1)], [])], + [('measure', + [Qubit(QuantumRegister(5, 'q'), 0)], + [Clbit(ClassicalRegister(1, 'c1'), 0)])], + [('u2', [Qubit(QuantumRegister(5, 'q'), 0)], []), + ('u2', [Qubit(QuantumRegister(5, 'q'), 1)], [])], + [('cx', + [Qubit(QuantumRegister(5, 'q'), 1), Qubit(QuantumRegister(5, 'q'), 0)], + [])], + [('u2', [Qubit(QuantumRegister(5, 'q'), 0)], []), + ('u2', [Qubit(QuantumRegister(5, 'q'), 1)], [])]] + + self.assertEqual(r_exp, + [[(op.name, op.qargs, op.cargs) for op in ops] for ops in layered_ops]) + if __name__ == '__main__': unittest.main(verbosity=2)