Skip to content

Commit 759c378

Browse files
CryorisElePT
authored andcommitted
Oxidize PauliFeatureMap (Qiskit#13045)
* port PauliFeatureMap to Rust * more docs, less error expecting * cleanup, docstrings * clippy & speedup * base for dictionary entanglement * rm unnecessary pub * add reno * refactor ``rmultiply_param`` * fix & test dict entanglement * clippy * Refactor Rust code a bit - improve readability - only create barrier if necessary * RIP iterators (for proper error handling) performance seems to be unaffected :)
1 parent 804ce60 commit 759c378

12 files changed

Lines changed: 1119 additions & 96 deletions

File tree

crates/accelerate/src/circuit_library/entanglement.rs

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
use itertools::Itertools;
1414
use pyo3::prelude::*;
15+
use pyo3::types::PyDict;
1516
use pyo3::{
1617
types::{PyAnyMethods, PyInt, PyList, PyListMethods, PyString, PyTuple},
1718
Bound, PyAny, PyResult,
@@ -173,30 +174,45 @@ pub fn get_entanglement<'a>(
173174
return Ok(Box::new(
174175
get_entanglement_from_str(num_qubits, block_size, as_str.as_str(), offset)?.map(Ok),
175176
));
177+
} else if let Ok(dict) = entanglement.downcast::<PyDict>() {
178+
if let Some(value) = dict.get_item(block_size)? {
179+
let list = value.downcast::<PyList>()?;
180+
return _check_entanglement_list(list.to_owned(), block_size);
181+
} else {
182+
return Ok(Box::new(std::iter::empty()));
183+
}
176184
} else if let Ok(list) = entanglement.downcast::<PyList>() {
177-
let entanglement_iter = list.iter().map(move |el| {
178-
let connections = el
179-
.downcast::<PyTuple>()?
180-
// .expect("Entanglement must be list of tuples") // clearer error message than `?`
181-
.iter()
182-
.map(|index| index.downcast::<PyInt>()?.extract())
183-
.collect::<Result<Vec<u32>, _>>()?;
184-
185-
if connections.len() != block_size as usize {
186-
return Err(QiskitError::new_err(format!(
187-
"Entanglement {:?} does not match block size {}",
188-
connections, block_size
189-
)));
190-
}
191-
Ok(connections)
192-
});
193-
return Ok(Box::new(entanglement_iter));
185+
return _check_entanglement_list(list.to_owned(), block_size);
194186
}
195187
Err(QiskitError::new_err(
196188
"Entanglement must be a string or list of qubit indices.",
197189
))
198190
}
199191

192+
fn _check_entanglement_list<'a>(
193+
list: Bound<'a, PyList>,
194+
block_size: u32,
195+
) -> PyResult<Box<dyn Iterator<Item = PyResult<Vec<u32>>> + 'a>> {
196+
let entanglement_iter = list.iter().map(move |el| {
197+
let connections = el
198+
.downcast::<PyTuple>()?
199+
// .expect("Entanglement must be list of tuples") // clearer error message than `?`
200+
.iter()
201+
.map(|index| index.downcast::<PyInt>()?.extract())
202+
.collect::<Result<Vec<u32>, _>>()?;
203+
204+
if connections.len() != block_size as usize {
205+
return Err(QiskitError::new_err(format!(
206+
"Entanglement {:?} does not match block size {}",
207+
connections, block_size
208+
)));
209+
}
210+
211+
Ok(connections)
212+
});
213+
Ok(Box::new(entanglement_iter))
214+
}
215+
200216
/// Get the entanglement for given number of qubits and block size.
201217
///
202218
/// Args:

crates/accelerate/src/circuit_library/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
use pyo3::prelude::*;
1414

1515
mod entanglement;
16+
mod pauli_feature_map;
1617

1718
pub fn circuit_library(m: &Bound<PyModule>) -> PyResult<()> {
19+
m.add_wrapped(wrap_pyfunction!(pauli_feature_map::pauli_feature_map))?;
1820
m.add_wrapped(wrap_pyfunction!(entanglement::get_entangler_map))?;
1921
Ok(())
2022
}

0 commit comments

Comments
 (0)