Skip to content

Commit

Permalink
Merge branch 'Qiskit:main' into ZZFeatureMapIssue
Browse files Browse the repository at this point in the history
  • Loading branch information
shravanpatel30 authored Jul 11, 2024
2 parents 62b6c2e + 99032fc commit 406431a
Show file tree
Hide file tree
Showing 68 changed files with 2,638 additions and 883 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
with:
components: llvm-tools-preview
- name: Build wheels
uses: pypa/cibuildwheel@v2.19.1
uses: pypa/cibuildwheel@v2.19.2
env:
CIBW_BEFORE_BUILD: 'bash ./tools/build_pgo.sh /tmp/pgo-data/merged.profdata'
CIBW_BEFORE_BUILD_WINDOWS: 'bash ./tools/build_pgo.sh /tmp/pgo-data/merged.profdata && cp /tmp/pgo-data/merged.profdata ~/.'
Expand Down Expand Up @@ -58,7 +58,7 @@ jobs:
with:
components: llvm-tools-preview
- name: Build wheels
uses: pypa/cibuildwheel@v2.19.1
uses: pypa/cibuildwheel@v2.19.2
env:
CIBW_BEFORE_ALL: rustup target add aarch64-apple-darwin
CIBW_BUILD: cp38-macosx_universal2 cp38-macosx_arm64
Expand Down Expand Up @@ -87,7 +87,7 @@ jobs:
with:
components: llvm-tools-preview
- name: Build wheels
uses: pypa/cibuildwheel@v2.19.1
uses: pypa/cibuildwheel@v2.19.2
env:
CIBW_SKIP: 'pp* cp36-* cp37-* *musllinux* *amd64 *x86_64'
- uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -133,7 +133,7 @@ jobs:
with:
platforms: all
- name: Build wheels
uses: pypa/cibuildwheel@v2.19.1
uses: pypa/cibuildwheel@v2.19.2
env:
CIBW_ARCHS_LINUX: s390x
CIBW_TEST_SKIP: "cp*"
Expand Down Expand Up @@ -167,7 +167,7 @@ jobs:
with:
platforms: all
- name: Build wheels
uses: pypa/cibuildwheel@v2.19.1
uses: pypa/cibuildwheel@v2.19.2
env:
CIBW_ARCHS_LINUX: ppc64le
CIBW_TEST_SKIP: "cp*"
Expand Down Expand Up @@ -201,7 +201,7 @@ jobs:
with:
platforms: all
- name: Build wheels
uses: pypa/cibuildwheel@v2.19.1
uses: pypa/cibuildwheel@v2.19.2
env:
CIBW_ARCHS_LINUX: aarch64
- uses: actions/upload-artifact@v4
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

**Qiskit** is an open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives.

This library is the core component of Qiskit, which contains the building blocks for creating and working with quantum circuits, quantum operators, and primitive functions (sampler and estimator).
It also contains a transpiler that supports optimizing quantum circuits and a quantum information toolbox for creating advanced quantum operators.
This library is the core component of Qiskit, which contains the building blocks for creating and working with quantum circuits, quantum operators, and primitive functions (Sampler and Estimator).
It also contains a transpiler that supports optimizing quantum circuits, and a quantum information toolbox for creating advanced operators.

For more details on how to use Qiskit, refer to the documentation located here:

Expand Down Expand Up @@ -91,12 +91,12 @@ print(f" > Expectation values: {result.values}")
Running this will give the outcome `4`. For fun, try to assign a value of +/- 1 to each single-qubit operator X and Y
and see if you can achieve this outcome. (Spoiler alert: this is not possible!)

Using the Qiskit-provided `qiskit.primitives.Sampler` and `qiskit.primitives.Estimator` will not take you very far. The power of quantum computing cannot be simulated
on classical computers and you need to use real quantum hardware to scale to larger quantum circuits. However, running a quantum
circuit on hardware requires rewriting them to the basis gates and connectivity of the quantum hardware.
The tool that does this is the [transpiler](https://docs.quantum.ibm.com/api/qiskit/transpiler)
and Qiskit includes transpiler passes for synthesis, optimization, mapping, and scheduling. However, it also includes a
default compiler which works very well in most examples. The following code will map the example circuit to the `basis_gates = ['cz', 'sx', 'rz']` and a linear chain of qubits $0 \rightarrow 1 \rightarrow 2$ with the `coupling_map =[[0, 1], [1, 2]]`.
Using the Qiskit-provided `qiskit.primitives.Sampler` and `qiskit.primitives.Estimator` will not take you very far.
The power of quantum computing cannot be simulated on classical computers and you need to use real quantum hardware to scale to larger quantum circuits.
However, running a quantum circuit on hardware requires rewriting to the basis gates and connectivity of the quantum hardware.
The tool that does this is the [transpiler](https://docs.quantum.ibm.com/api/qiskit/transpiler), and Qiskit includes transpiler passes for synthesis, optimization, mapping, and scheduling.
However, it also includes a default compiler, which works very well in most examples.
The following code will map the example circuit to the `basis_gates = ['cz', 'sx', 'rz']` and a linear chain of qubits $0 \rightarrow 1 \rightarrow 2$ with the `coupling_map =[[0, 1], [1, 2]]`.

```python
from qiskit import transpile
Expand Down
104 changes: 96 additions & 8 deletions crates/accelerate/src/convert_2q_block_matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
// copyright notice, and modified files need to carry a notice indicating
// that they have been altered from the originals.

use pyo3::intern;
use pyo3::prelude::*;
use pyo3::types::PyDict;
use pyo3::wrap_pyfunction;
use pyo3::Python;

Expand All @@ -20,32 +22,84 @@ use numpy::ndarray::{aview2, Array2, ArrayView2};
use numpy::{IntoPyArray, PyArray2, PyReadonlyArray2};
use smallvec::SmallVec;

use qiskit_circuit::bit_data::BitData;
use qiskit_circuit::circuit_instruction::{operation_type_to_py, CircuitInstruction};
use qiskit_circuit::dag_node::DAGOpNode;
use qiskit_circuit::gate_matrix::ONE_QUBIT_IDENTITY;
use qiskit_circuit::imports::QI_OPERATOR;
use qiskit_circuit::operations::{Operation, OperationType};

use crate::QiskitError;

fn get_matrix_from_inst<'py>(
py: Python<'py>,
inst: &'py CircuitInstruction,
) -> PyResult<Array2<Complex64>> {
match inst.operation.matrix(&inst.params) {
Some(mat) => Ok(mat),
None => match inst.operation {
OperationType::Standard(_) => Err(QiskitError::new_err(
"Parameterized gates can't be consolidated",
)),
OperationType::Gate(_) => Ok(QI_OPERATOR
.get_bound(py)
.call1((operation_type_to_py(py, inst)?,))?
.getattr(intern!(py, "data"))?
.extract::<PyReadonlyArray2<Complex64>>()?
.as_array()
.to_owned()),
_ => unreachable!("Only called for unitary ops"),
},
}
}

/// Return the matrix Operator resulting from a block of Instructions.
#[pyfunction]
#[pyo3(text_signature = "(op_list, /")]
pub fn blocks_to_matrix(
py: Python,
op_list: Vec<(PyReadonlyArray2<Complex64>, SmallVec<[u8; 2]>)>,
op_list: Vec<PyRef<DAGOpNode>>,
block_index_map_dict: &Bound<PyDict>,
) -> PyResult<Py<PyArray2<Complex64>>> {
// Build a BitData in block_index_map_dict order. block_index_map_dict is a dict of bits to
// indices mapping the order of the qargs in the block. There should only be 2 entries since
// there are only 2 qargs here (e.g. `{Qubit(): 0, Qubit(): 1}`) so we need to ensure that
// we added the qubits to bit data in the correct index order.
let mut index_map: Vec<PyObject> = (0..block_index_map_dict.len()).map(|_| py.None()).collect();
for bit_tuple in block_index_map_dict.items() {
let (bit, index): (PyObject, usize) = bit_tuple.extract()?;
index_map[index] = bit;
}
let mut bit_map: BitData<u32> = BitData::new(py, "qargs".to_string());
for bit in index_map {
bit_map.add(py, bit.bind(py), true)?;
}
let identity = aview2(&ONE_QUBIT_IDENTITY);
let input_matrix = op_list[0].0.as_array();
let mut matrix: Array2<Complex64> = match op_list[0].1.as_slice() {
let first_node = &op_list[0];
let input_matrix = get_matrix_from_inst(py, &first_node.instruction)?;
let mut matrix: Array2<Complex64> = match bit_map
.map_bits(first_node.instruction.qubits.bind(py).iter())?
.collect::<Vec<_>>()
.as_slice()
{
[0] => kron(&identity, &input_matrix),
[1] => kron(&input_matrix, &identity),
[0, 1] => input_matrix.to_owned(),
[1, 0] => change_basis(input_matrix),
[0, 1] => input_matrix,
[1, 0] => change_basis(input_matrix.view()),
[] => Array2::eye(4),
_ => unreachable!(),
};
for (op_matrix, q_list) in op_list.into_iter().skip(1) {
let op_matrix = op_matrix.as_array();
for node in op_list.into_iter().skip(1) {
let op_matrix = get_matrix_from_inst(py, &node.instruction)?;
let q_list = bit_map
.map_bits(node.instruction.qubits.bind(py).iter())?
.map(|x| x as u8)
.collect::<SmallVec<[u8; 2]>>();

let result = match q_list.as_slice() {
[0] => Some(kron(&identity, &op_matrix)),
[1] => Some(kron(&op_matrix, &identity)),
[1, 0] => Some(change_basis(op_matrix)),
[1, 0] => Some(change_basis(op_matrix.view())),
[] => Some(Array2::eye(4)),
_ => None,
};
Expand All @@ -71,8 +125,42 @@ pub fn change_basis(matrix: ArrayView2<Complex64>) -> Array2<Complex64> {
trans_matrix
}

#[pyfunction]
pub fn collect_2q_blocks_filter(node: &Bound<PyAny>) -> Option<bool> {
match node.downcast::<DAGOpNode>() {
Ok(bound_node) => {
let node = bound_node.borrow();
match &node.instruction.operation {
OperationType::Standard(gate) => Some(
gate.num_qubits() <= 2
&& node
.instruction
.extra_attrs
.as_ref()
.and_then(|attrs| attrs.condition.as_ref())
.is_none()
&& !node.is_parameterized(),
),
OperationType::Gate(gate) => Some(
gate.num_qubits() <= 2
&& node
.instruction
.extra_attrs
.as_ref()
.and_then(|attrs| attrs.condition.as_ref())
.is_none()
&& !node.is_parameterized(),
),
_ => Some(false),
}
}
Err(_) => None,
}
}

#[pymodule]
pub fn convert_2q_block_matrix(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(blocks_to_matrix))?;
m.add_wrapped(wrap_pyfunction!(collect_2q_blocks_filter))?;
Ok(())
}
2 changes: 2 additions & 0 deletions crates/accelerate/src/synthesis/linear/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::QiskitError;
use numpy::{IntoPyArray, PyArray2, PyReadonlyArray2, PyReadwriteArray2};
use pyo3::prelude::*;

mod pmh;
pub mod utils;

#[pyfunction]
Expand Down Expand Up @@ -186,5 +187,6 @@ pub fn linear(m: &Bound<PyModule>) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(binary_matmul))?;
m.add_wrapped(wrap_pyfunction!(random_invertible_binary_matrix))?;
m.add_wrapped(wrap_pyfunction!(check_invertible_binary_matrix))?;
m.add_wrapped(wrap_pyfunction!(pmh::synth_cnot_count_full_pmh))?;
Ok(())
}
Loading

0 comments on commit 406431a

Please sign in to comment.