@@ -311,44 +311,61 @@ def check_symplectic(self):
311311 def _multiply_stabilizers (s1 , s2 ):
312312 """
313313 Multiplies two stabilizers together to a third one.
314-
315- See https://www.cs.umd.edu/~amchilds/teaching/w10/project-sample.pdf
316314 """
317- def g (vals ):
318- """
319- Helper function, see https://www.cs.umd.edu/~amchilds/teaching/w10/project-sample.pdf
320- """
321- x1 , z1 , x2 , z2 = map (int , vals )
322- if x1 == 0 :
323- if z1 == 0 :
324- return 0
325- else :
326- return x2 * (1 - 2 * z2 )
327- else :
328- if z1 == 0 :
329- return z2 * (2 * x2 - 1 )
330- else :
331- return z2 - x2
332-
333315 assert len (s1 ) == len (s2 )
334316 assert (len (s1 ) - 1 ) % 2 == 0
335- num_paulis = int ((len (s1 ) - 1 ) / 2 )
336317
337318 # Update the x and z stabilizers
338- new_s = np .logical_xor (s1 , s2 )
319+ new_s = np .logical_xor (s1 [: - 1 ] , s2 [: - 1 ] )
339320
340321 # Update the phase
341- m = sum (map (g , zip (
342- s2 [:num_paulis ],
343- s2 [num_paulis :- 1 ],
344- new_s [:num_paulis ],
345- new_s [num_paulis :- 1 ],
346- )))
347- m %= 4
348-
349- new_s [- 1 ] ^= bool (m / 2 )
322+ new_s = np .append (new_s , StabilizerState ._multiply_compute_phase (s1 , s2 ))
323+
350324 return new_s
351325
326+ @staticmethod
327+ def _get_pauli_mask (s1 , s2 , p1 , p2 ):
328+ """Returns a mask for which positions where the Pauli of the first stabilier is `p1`
329+ and the Pauli of the second stabilizer is `p2`.
330+ """
331+ num_paulis = int ((len (s1 ) - 1 ) / 2 )
332+ p1_bool = StabilizerState .Pauli2bool [p1 ]
333+ p2_bool = StabilizerState .Pauli2bool [p2 ]
334+ is_p1 = (s1 [:num_paulis ] == p1_bool [0 ]) & (s1 [num_paulis :- 1 ] == p1_bool [1 ])
335+ is_p2 = (s2 [:num_paulis ] == p2_bool [0 ]) & (s2 [num_paulis :- 1 ] == p2_bool [1 ])
336+ return is_p1 & is_p2
337+
338+ @staticmethod
339+ def _get_i_mask (s1 , s2 ):
340+ """Returns a mask for which positions where the Paulis of the two stabilizers gives
341+ a `i`-phase.
342+ """
343+ has_i = False
344+ for paulis in ["XY" , "YZ" , "ZX" ]:
345+ has_i |= StabilizerState ._get_pauli_mask (s1 , s2 , * paulis )
346+ return has_i
347+
348+ @staticmethod
349+ def _get_minus_i_mask (s1 , s2 ):
350+ """Returns a mask for which positions where the Paulis of the two stabilizers gives
351+ a `-i`-phase.
352+ """
353+ has_minus_i = False
354+ for paulis in ["YX" , "ZY" , "XZ" ]:
355+ has_minus_i |= StabilizerState ._get_pauli_mask (s1 , s2 , * paulis )
356+ return has_minus_i
357+
358+ @staticmethod
359+ def _multiply_compute_phase (s1 , s2 ):
360+ """Computes the new phase of when multiplying two stabilizers"""
361+ # Compute the number of i and -i phases
362+ has_minus_i = StabilizerState ._get_minus_i_mask (s1 , s2 )
363+ has_i = StabilizerState ._get_i_mask (s1 , s2 )
364+ num_i = np .count_nonzero (has_i )
365+ num_minus_i = np .count_nonzero (has_minus_i )
366+ has_minus_phase = ((num_i - num_minus_i ) % 4 ) / 2
367+ return np .logical_xor (np .logical_xor (s1 [- 1 ], s2 [- 1 ]), has_minus_phase )
368+
352369 @staticmethod
353370 def _is_symplectic (matrix ):
354371 """
0 commit comments