Skip to content

Commit 453b5ab

Browse files
committed
lint
1 parent d880b1e commit 453b5ab

File tree

14 files changed

+643
-200
lines changed

14 files changed

+643
-200
lines changed

crates/pecos-qsim/src/pauli_prop.rs

Lines changed: 78 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub type StdPauliProp = PauliProp<VecSet<usize>, usize>;
4040
/// - `zs`: Records qubits with Z Pauli operators
4141
///
4242
/// Y operators are implicitly represented by qubits present in both sets since Y = iXZ.
43-
///
43+
///
4444
/// Optionally, the sign and phase can be tracked for full Pauli string representation.
4545
///
4646
/// # Type Parameters
@@ -127,8 +127,8 @@ where
127127
PauliProp {
128128
xs: T::new(),
129129
zs: T::new(),
130-
sign: Some(false), // Start with +1
131-
img: Some(0), // Start with no imaginary component
130+
sign: Some(false), // Start with +1
131+
img: Some(0), // Start with no imaginary component
132132
num_qubits: Some(num_qubits),
133133
_marker: PhantomData,
134134
}
@@ -263,33 +263,37 @@ where
263263
/// * `num_is` - Number of i factors to add
264264
pub fn flip_img(&mut self, num_is: usize) {
265265
if let Some(img) = self.img.as_mut() {
266-
*img = (*img + num_is as u8) % 4;
267-
266+
// Use modulo 4 on num_is first to ensure it fits in u8
267+
// Safe to cast since modulo 4 guarantees result is 0-3
268+
#[allow(clippy::cast_possible_truncation)]
269+
let num_is_mod = (num_is % 4) as u8;
270+
*img = (*img + num_is_mod) % 4;
271+
268272
// If we've accumulated 2 or 3 i's, flip the sign
269273
let should_flip = *img == 2 || *img == 3;
270-
271-
*img %= 2; // Keep only 0 or 1 for the imaginary part
272-
274+
275+
*img %= 2; // Keep only 0 or 1 for the imaginary part
276+
273277
if should_flip {
274278
self.flip_sign();
275279
}
276280
}
277281
}
278282

279-
/// Adds Pauli operators from a BTreeMap representation.
283+
/// Adds Pauli operators from a `BTreeMap` representation.
280284
///
281285
/// The map should have keys "X", "Y", and "Z" with sets of qubit indices.
282286
/// This method properly handles operator composition with phase tracking if enabled.
283287
///
284288
/// # Arguments
285-
/// * `paulis` - BTreeMap with "X", "Y", "Z" keys mapping to sets of qubit indices
289+
/// * `paulis` - `BTreeMap` with "X", "Y", "Z" keys mapping to sets of qubit indices
286290
///
287291
/// # Example
288292
/// ```rust
289293
/// use std::collections::BTreeMap;
290294
/// use pecos_qsim::StdPauliProp;
291295
/// use pecos_core::{VecSet, Set};
292-
///
296+
///
293297
/// let mut sim = StdPauliProp::with_sign_tracking(4);
294298
/// let mut paulis = BTreeMap::new();
295299
/// let mut x_set = VecSet::new();
@@ -298,7 +302,7 @@ where
298302
/// paulis.insert("X".to_string(), x_set);
299303
/// sim.add_paulis(&paulis);
300304
/// ```
301-
pub fn add_paulis(&mut self, paulis: &BTreeMap<String, T>)
305+
pub fn add_paulis(&mut self, paulis: &BTreeMap<String, T>)
302306
where
303307
T: Clone,
304308
E: Copy,
@@ -308,9 +312,9 @@ where
308312
for &item in x_set.iter() {
309313
let was_y = self.contains_y(item);
310314
let was_z = self.contains_z(item) && !was_y;
311-
315+
312316
self.add_x(item);
313-
317+
314318
if self.sign.is_some() {
315319
if was_y {
316320
// Y·X = -iZ (applying X after Y)
@@ -329,9 +333,9 @@ where
329333
for &item in z_set.iter() {
330334
let was_y = self.contains_y(item);
331335
let was_x = self.contains_x(item) && !was_y;
332-
336+
333337
self.add_z(item);
334-
338+
335339
if self.sign.is_some() {
336340
if was_x {
337341
// X·Z = -iY (applying Z after X)
@@ -350,9 +354,9 @@ where
350354
for &item in y_set.iter() {
351355
let was_x = self.contains_x(item) && !self.contains_z(item);
352356
let was_z = self.contains_z(item) && !self.contains_x(item);
353-
357+
354358
self.add_y(item);
355-
359+
356360
if self.sign.is_some() {
357361
if was_z {
358362
// Z·Y = -iX (applying Y after Z)
@@ -379,21 +383,21 @@ where
379383
count += 1;
380384
}
381385
}
382-
386+
383387
// Count Z-only qubits
384388
for item in self.zs.iter() {
385389
if !self.xs.contains(item) {
386390
count += 1;
387391
}
388392
}
389-
393+
390394
// Count Y qubits (both X and Z)
391395
for item in self.xs.iter() {
392396
if self.zs.contains(item) {
393397
count += 1;
394398
}
395399
}
396-
400+
397401
count
398402
}
399403

@@ -427,24 +431,24 @@ where
427431
/// A string like "+", "-", "+i", or "-i" depending on the phase
428432
pub fn sign_string(&self) -> String {
429433
match (self.sign, self.img) {
430-
(Some(false), Some(0)) | (Some(false), None) => "+".to_string(),
431-
(Some(true), Some(0)) | (Some(true), None) => "-".to_string(),
434+
(Some(false), Some(0) | None) => "+".to_string(),
435+
(Some(true), Some(0) | None) => "-".to_string(),
432436
(Some(false), Some(1)) => "+i".to_string(),
433437
(Some(true), Some(1)) => "-i".to_string(),
434-
_ => "".to_string(),
438+
_ => String::new(),
435439
}
436440
}
437441

438442
/// Returns the operator string representation for sparse format.
439443
///
440444
/// # Returns
441-
/// A string like "X_0 Z_2 Y_3" representing non-identity operators
442-
pub fn sparse_string(&self) -> String
445+
/// A string like "`X_0` `Z_2` `Y_3`" representing non-identity operators
446+
pub fn sparse_string(&self) -> String
443447
where
444448
E: Copy,
445449
{
446450
let mut entries = Vec::new();
447-
451+
448452
// Collect all qubit indices with operators
449453
for &item in self.xs.iter() {
450454
if self.contains_y(item) {
@@ -453,19 +457,20 @@ where
453457
entries.push((item, 'X'));
454458
}
455459
}
456-
460+
457461
for &item in self.zs.iter() {
458462
if !self.xs.contains(&item) {
459463
entries.push((item, 'Z'));
460464
}
461465
}
462-
466+
463467
if entries.is_empty() {
464468
"I".to_string()
465469
} else {
466470
// Format as sparse representation
467-
entries.iter()
468-
.map(|(idx, op)| format!("{}{:?}", op, idx))
471+
entries
472+
.iter()
473+
.map(|(idx, op)| format!("{op}{idx:?}"))
469474
.collect::<Vec<_>>()
470475
.join(" ")
471476
}
@@ -474,8 +479,8 @@ where
474479
/// Returns the full Pauli string representation with sign and operators.
475480
///
476481
/// # Returns
477-
/// A string like "+X_0 Z_2" in sparse format
478-
pub fn to_pauli_string(&self) -> String
482+
/// A string like "+`X_0` `Z_2`" in sparse format
483+
pub fn to_pauli_string(&self) -> String
479484
where
480485
E: Copy,
481486
{
@@ -486,45 +491,54 @@ where
486491
// Specialized implementation for StdPauliProp (usize indices)
487492
impl StdPauliProp {
488493
/// Get all qubits with X operators (including those with Y)
494+
#[must_use]
489495
pub fn get_x_qubits(&self) -> Vec<usize> {
490496
self.xs.iter().copied().collect()
491497
}
492-
498+
493499
/// Get all qubits with Z operators (including those with Y)
500+
#[must_use]
494501
pub fn get_z_qubits(&self) -> Vec<usize> {
495502
self.zs.iter().copied().collect()
496503
}
497-
504+
498505
/// Get all qubits with only X operators (not Y)
506+
#[must_use]
499507
pub fn get_x_only_qubits(&self) -> Vec<usize> {
500-
self.xs.iter()
508+
self.xs
509+
.iter()
501510
.filter(|&q| !self.contains_z(*q))
502511
.copied()
503512
.collect()
504513
}
505-
514+
506515
/// Get all qubits with only Z operators (not Y)
516+
#[must_use]
507517
pub fn get_z_only_qubits(&self) -> Vec<usize> {
508-
self.zs.iter()
518+
self.zs
519+
.iter()
509520
.filter(|&q| !self.contains_x(*q))
510521
.copied()
511522
.collect()
512523
}
513-
524+
514525
/// Get all qubits with Y operators (both X and Z)
526+
#[must_use]
515527
pub fn get_y_qubits(&self) -> Vec<usize> {
516-
self.xs.iter()
528+
self.xs
529+
.iter()
517530
.filter(|&q| self.contains_z(*q))
518531
.copied()
519532
.collect()
520533
}
521-
534+
522535
/// Returns the operator string as a dense representation.
523536
///
524537
/// Requires `num_qubits` to be set.
525538
///
526539
/// # Returns
527540
/// A string like "IXYZ" representing the Pauli operators on each qubit
541+
#[must_use]
528542
pub fn dense_string(&self) -> String {
529543
if let Some(n) = self.num_qubits {
530544
let mut result = String::with_capacity(n);
@@ -544,11 +558,12 @@ impl StdPauliProp {
544558
self.sparse_string()
545559
}
546560
}
547-
561+
548562
/// Returns the full dense Pauli string with sign.
549563
///
550564
/// # Returns
551565
/// A string like "+IXYZ" or "-iXYZ"
566+
#[must_use]
552567
pub fn to_dense_string(&self) -> String {
553568
format!("{}{}", self.sign_string(), self.dense_string())
554569
}
@@ -694,19 +709,19 @@ mod tests {
694709
#[test]
695710
fn test_sign_tracking() {
696711
let mut sim = StdPauliProp::with_sign_tracking(4);
697-
712+
698713
// Initially should be +
699714
assert_eq!(sim.sign_string(), "+");
700-
715+
701716
// Flip sign
702717
sim.flip_sign();
703718
assert_eq!(sim.sign_string(), "-");
704-
719+
705720
// Add imaginary phase
706721
sim.flip_sign(); // Back to +
707722
sim.flip_img(1);
708723
assert_eq!(sim.sign_string(), "+i");
709-
724+
710725
// Two i's should give -1
711726
sim.flip_img(1);
712727
assert_eq!(sim.sign_string(), "-");
@@ -715,22 +730,22 @@ mod tests {
715730
#[test]
716731
fn test_weight() {
717732
let mut sim = StdPauliProp::new();
718-
733+
719734
// Empty should have weight 0
720735
assert_eq!(sim.weight(), 0);
721-
736+
722737
// Add X on qubit 0
723738
sim.add_x(0);
724739
assert_eq!(sim.weight(), 1);
725-
740+
726741
// Add Z on qubit 1
727742
sim.add_z(1);
728743
assert_eq!(sim.weight(), 2);
729-
744+
730745
// Add Y on qubit 2 (both X and Z)
731746
sim.add_y(2);
732747
assert_eq!(sim.weight(), 3);
733-
748+
734749
// Adding X to qubit with Z makes Y
735750
sim.add_x(1);
736751
assert_eq!(sim.weight(), 3); // Still 3 operators
@@ -739,35 +754,35 @@ mod tests {
739754
#[test]
740755
fn test_dense_string() {
741756
let mut sim = StdPauliProp::with_sign_tracking(4);
742-
757+
743758
sim.add_x(0);
744759
sim.add_z(2);
745760
sim.add_y(3);
746-
761+
747762
assert_eq!(sim.dense_string(), "XIZY");
748763
assert_eq!(sim.to_dense_string(), "+XIZY");
749-
764+
750765
sim.flip_sign();
751766
assert_eq!(sim.to_dense_string(), "-XIZY");
752767
}
753768

754769
#[test]
755770
fn test_add_paulis() {
756771
let mut sim = StdPauliProp::with_sign_tracking(4);
757-
772+
758773
let mut paulis = BTreeMap::new();
759774
let mut x_set = VecSet::new();
760775
x_set.insert(0);
761776
x_set.insert(1);
762-
777+
763778
let mut z_set = VecSet::new();
764779
z_set.insert(2);
765-
780+
766781
paulis.insert("X".to_string(), x_set);
767782
paulis.insert("Z".to_string(), z_set);
768-
783+
769784
sim.add_paulis(&paulis);
770-
785+
771786
assert!(sim.contains_x(0));
772787
assert!(sim.contains_x(1));
773788
assert!(sim.contains_z(2));
@@ -777,18 +792,18 @@ mod tests {
777792
#[test]
778793
fn test_pauli_composition_with_phase() {
779794
let mut sim = StdPauliProp::with_sign_tracking(2);
780-
795+
781796
// Start with X on qubit 0
782797
sim.add_x(0);
783-
798+
784799
// Add Z to same qubit: X·Z = -iY (applying Z after X)
785800
let mut paulis = BTreeMap::new();
786801
let mut z_set = VecSet::new();
787802
z_set.insert(0);
788803
paulis.insert("Z".to_string(), z_set);
789-
804+
790805
sim.add_paulis(&paulis);
791-
806+
792807
// Should now have Y on qubit 0
793808
assert!(sim.contains_y(0));
794809
// Phase should be -i (X·Z = -iY)

0 commit comments

Comments
 (0)