11use pyo3:: prelude:: * ;
22
3+ /// Graph-state based quantum circuit simulator exposed as the `graphsim` Python module.
34#[ pymodule]
45mod graphsim {
56 use pyo3:: prelude:: * ;
@@ -15,15 +16,24 @@ mod graphsim {
1516 distr:: { Distribution , StandardUniform } ,
1617 } ;
1718
19+ /// Index of a node / qubit in the graph.
1820 pub type NodeIdx = usize ;
1921
22+ /// Result of a single-qubit measurement.
23+ ///
24+ /// Exposed to Python as `graphsim.MeasurementResult`.
2025 #[ pyclass]
2126 #[ derive( PartialEq , Eq , Debug ) ]
2227 pub enum MeasurementResult {
28+ /// Eigenvalue +1 outcome.
2329 PlusOne ,
30+ /// Eigenvalue −1 outcome.
2431 MinusOne ,
2532 }
2633
34+ /// Measurement outcome and the axis that was measured.
35+ ///
36+ /// Returned in the values of `peek_measure_set`.
2737 #[ pyclass]
2838 pub struct Outcome {
2939 result : MeasurementResult ,
@@ -2235,6 +2245,9 @@ mod graphsim {
22352245 }
22362246 }
22372247
2248+ /// Simulator for graph states over a fixed number of qubits.
2249+ ///
2250+ /// Use this class from Python to apply gates and perform measurements.
22382251 #[ derive( Clone ) ]
22392252 #[ pyclass]
22402253 pub struct GraphSim {
@@ -2464,37 +2477,57 @@ mod graphsim {
24642477
24652478 #[ pymethods]
24662479 impl GraphSim {
2480+ /// Create a new simulator with `nodes` qubits, all initialized in the |0⟩ state.
24672481 #[ new]
24682482 pub fn new ( nodes : usize ) -> GraphSim {
24692483 GraphSim {
24702484 nodes : repeat_n ( Node :: default ( ) , nodes) . collect ( ) ,
24712485 }
24722486 }
24732487
2488+ /// Apply an X (Pauli-X) gate to the given qubit.
2489+ ///
2490+ /// `node` is the index of the qubit.
24742491 fn x ( & mut self , node : NodeIdx ) {
24752492 self [ node] . vop = X_GATE * self [ node] . vop ;
24762493 }
24772494
2495+ /// Apply a Y (Pauli-Y) gate to the given qubit.
2496+ ///
2497+ /// `node` is the index of the qubit.
24782498 fn y ( & mut self , node : NodeIdx ) {
24792499 self [ node] . vop = Y_GATE * self [ node] . vop ;
24802500 }
24812501
2502+ /// Apply a Z (Pauli-Z) gate to the given qubit.
2503+ ///
2504+ /// `node` is the index of the qubit.
24822505 fn z ( & mut self , node : NodeIdx ) {
24832506 self [ node] . vop = Z_GATE * self [ node] . vop ;
24842507 }
24852508
2509+ /// Apply an H (Hadamard) gate to the given qubit.
2510+ ///
2511+ /// `node` is the index of the qubit.
24862512 fn h ( & mut self , node : NodeIdx ) {
24872513 self [ node] . vop = H_GATE * self [ node] . vop ;
24882514 }
24892515
2516+ /// Apply an S (phase) gate to the given qubit.
2517+ ///
2518+ /// `node` is the index of the qubit.
24902519 fn s ( & mut self , node : NodeIdx ) {
24912520 self [ node] . vop = S_GATE * self [ node] . vop ;
24922521 }
24932522
2523+ /// Apply an S† (inverse phase) gate to the given qubit.
2524+ ///
2525+ /// `node` is the index of the qubit.
24942526 fn sdag ( & mut self , node : NodeIdx ) {
24952527 self [ node] . vop = SDAG_GATE * self [ node] . vop ;
24962528 }
24972529
2530+ /// Apply a controlled-Z (CZ) gate with `control` and `target` qubits.
24982531 fn cz ( & mut self , control : NodeIdx , target : NodeIdx ) {
24992532 let c_has_t = self [ control] . len ( ) > 1
25002533 || ( self [ control] . len ( ) == 1 && self [ control] . adjacent [ 0 ] != target) ;
@@ -2530,54 +2563,83 @@ mod graphsim {
25302563 self [ target] . vop = val. 2 ;
25312564 }
25322565
2566+ /// Apply a controlled-X (CX) / CNOT gate with `control` and `target`.
25332567 fn cx ( & mut self , control : NodeIdx , target : NodeIdx ) {
25342568 self . h ( target) ;
25352569 self . cz ( control, target) ;
25362570 self . h ( target) ;
25372571 }
2572+
2573+ /// Apply an X-controlled X gate (CX in the X basis).
25382574 fn xcx ( & mut self , control : NodeIdx , target : NodeIdx ) {
25392575 self . h ( control) ;
25402576 self . cx ( control, target) ;
25412577 self . h ( control) ;
25422578 }
2579+
2580+ /// Apply a Y-controlled X gate (control qubit in the Y basis).
25432581 fn ycx ( & mut self , control : NodeIdx , target : NodeIdx ) {
25442582 self . sdag ( control) ;
25452583 self . xcx ( control, target) ;
25462584 self . s ( control) ;
25472585 }
2586+
2587+ /// Apply an X-controlled Z gate (target in X basis).
25482588 fn xcz ( & mut self , control : NodeIdx , target : NodeIdx ) {
25492589 self . cx ( target, control) ;
25502590 }
2591+
2592+ /// Apply a Y-controlled Z gate (target in Y basis).
25512593 fn ycz ( & mut self , control : NodeIdx , target : NodeIdx ) {
25522594 self . cy ( target, control) ;
25532595 }
2596+
2597+ /// Apply a controlled-Y (CY) gate with `control` and `target`.
25542598 fn cy ( & mut self , control : NodeIdx , target : NodeIdx ) {
25552599 self . sdag ( target) ;
25562600 self . cx ( control, target) ;
25572601 self . s ( target) ;
25582602 }
2603+
2604+ /// Apply an X-controlled Y gate (control in X basis).
25592605 fn xcy ( & mut self , control : NodeIdx , target : NodeIdx ) {
25602606 self . ycx ( target, control) ;
25612607 }
2608+
2609+ /// Apply a Y-controlled Y gate (both in Y basis).
25622610 fn ycy ( & mut self , control : NodeIdx , target : NodeIdx ) {
25632611 self . sdag ( target) ;
25642612 self . ycx ( control, target) ;
25652613 self . s ( target) ;
25662614 }
25672615
2616+ /// Perform a projective measurement of `qubit` in the X basis.
2617+ ///
2618+ /// Returns `MeasurementResult.PlusOne` or `MeasurementResult.MinusOne`.
25682619 fn measure_x ( & mut self , qubit : NodeIdx ) -> MeasurementResult {
25692620 let ( res, _) = self . measure ( qubit, Axis :: X ) ;
25702621 res
25712622 }
2623+
2624+ /// Perform a projective measurement of `qubit` in the Y basis.
2625+ ///
2626+ /// Returns `MeasurementResult.PlusOne` or `MeasurementResult.MinusOne`.
25722627 fn measure_y ( & mut self , qubit : NodeIdx ) -> MeasurementResult {
25732628 let ( res, _) = self . measure ( qubit, Axis :: Y ) ;
25742629 res
25752630 }
2631+
2632+ /// Perform a projective measurement of `qubit` in the Z basis.
2633+ ///
2634+ /// Returns `MeasurementResult.PlusOne` or `MeasurementResult.MinusOne`.
25762635 fn measure_z ( & mut self , qubit : NodeIdx ) -> MeasurementResult {
25772636 let ( res, _) = self . measure ( qubit, Axis :: Z ) ;
25782637 res
25792638 }
25802639
2640+ /// Return the set of qubits that are entangled with `qubit`.
2641+ ///
2642+ /// This follows adjacency in the underlying graph.
25812643 fn get_entangled_group ( & self , qubit : NodeIdx ) -> HashSet < NodeIdx > {
25822644 let mut queue = VecDeque :: new ( ) ;
25832645 let mut part = HashSet :: new ( ) ;
@@ -2595,6 +2657,9 @@ mod graphsim {
25952657 part
25962658 }
25972659
2660+ /// Simulate measurements on a set of `qubits` without modifying the real state.
2661+ ///
2662+ /// Returns a map from qubit index to `Outcome` (result and axis used).
25982663 fn peek_measure_set (
25992664 & self ,
26002665 qubits : HashSet < NodeIdx > ,
0 commit comments