def measure(self, state, nshots): if isinstance(state, K.tensor_types): self._set_nqubits(state) if self.density_matrix: state = self.states.MatrixState.from_tensor(state) else: state = self.states.VectorState.from_tensor(state) elif isinstance(state, self.states.AbstractState): self._set_nqubits(state.tensor) else: raise_error( TypeError, "Measurement gate called on state of type " "{} that is not supported." "".format(type(state))) def calculate_probs(): probs_dim = K.cast((2**len(self.target_qubits), ), dtype='DTYPEINT') probs = state.probabilities(measurement_gate=self) probs = K.transpose(probs, axes=self.cache.reduced_target_qubits) probs = K.reshape(probs, probs_dim) return probs probs = K.cpu_fallback(calculate_probs) if self.collapse: self._result_list = None self._result_tensor = None self.result.add_shot(probs) return self.result result = self.measurements.MeasurementResult(self.qubits, probs, nshots) if sum(sum(x.values()) for x in self.bitflip_map) > 0: result = result.apply_bitflips(*self.bitflip_map) return result
def __call__(self, state, nshots): if isinstance(state, K.tensor_types): if not self.is_prepared: self.set_nqubits(state) state = getattr(self, self._active_call)(state) elif isinstance(state, self.states.AbstractState): if not self.is_prepared: self.set_nqubits(state.tensor) else: raise_error( TypeError, "Measurement gate called on state of type " "{} that is not supported." "".format(type(state))) def calculate_probs(): probs_dim = K.cast((2**len(self.target_qubits), ), dtype='DTYPEINT') probs = state.probabilities(measurement_gate=self) probs = K.transpose(probs, axes=self.reduced_target_qubits) probs = K.reshape(probs, probs_dim) return probs probs = K.cpu_fallback(calculate_probs) result = self.measurements.MeasurementResult(self.qubits, probs, nshots) # optional bitflip noise if sum(sum(x.values()) for x in self.bitflip_map) > 0: result = result.apply_bitflips(*self.bitflip_map) return result
def _sample_shots(self): self._frequencies = None if self.probabilities is None or not self.nshots: raise_error(RuntimeError, "Cannot sample measurement shots if " "a probability distribution is not " "provided.") if math.log2(self.nshots) + self.nqubits > 31: # pragma: no cover # case not covered by GitHub workflows because it requires large example # Use CPU to avoid "aborted" error with K.device(K.get_cpu()): result = K.sample_shots(self.probabilities, self.nshots) else: result = K.cpu_fallback(K.sample_shots, self.probabilities, self.nshots) return result
def _calculate_frequencies(self): if self._binary is None and self._decimal is None: if self.probabilities is None or not self.nshots: raise_error( RuntimeError, "Cannot calculate measurement " "frequencies without a probability " "distribution or samples.") freqs = K.cpu_fallback(K.sample_frequencies, self.probabilities, self.nshots) freqs = K.to_numpy(freqs) return collections.Counter( {k: v for k, v in enumerate(freqs) if v > 0}) res, counts = K.unique(self.decimal, return_counts=True) res, counts = K.np.array(res), K.np.array(counts) return collections.Counter({k: v for k, v in zip(res, counts)})
def add_shot(self, probabilities=None): """Adds a measurement shot to an existing measurement symbol. Useful for sampling more than one shots with collapse measurement gates. """ if self.nshots: if probabilities is not None: self.probabilities = probabilities self.nshots += 1 # sample new shot new_shot = K.cpu_fallback(K.sample_shots, self.probabilities, 1) self._decimal = K.concatenate([self.decimal, new_shot], axis=0) self._binary = None else: if probabilities is None: raise_error(ValueError, "Cannot add shots in measurement that " "for which the probability distribution " "is not specified.") self.set_probabilities(probabilities)