def measure(self): """ Measures a circuit on the computational basis. Returns ------- array : np.ndarray with real entries and the same shape as :code:`self.eval().array`. Examples -------- >>> m = X.measure() >>> list(np.round(m.flatten())) [0.0, 1.0, 1.0, 0.0] >>> assert (Ket(0) >> X >> Bra(1)).measure() == m[0, 1] """ def bitstring(i, length): return map(int, '{{:0{}b}}'.format(length).format(i)) process = self.eval() states, effects = [], [] states = [ Ket(*bitstring(i, len(self.dom))).eval() for i in range(2**len(self.dom)) ] effects = [ Bra(*bitstring(j, len(self.cod))).eval() for j in range(2**len(self.cod)) ] array = np.zeros(len(self.dom + self.cod) * (2, )) for state in states if self.dom else [Tensor.id(1)]: for effect in effects if self.cod else [Tensor.id(1)]: scalar = np.absolute((state >> process >> effect).array)**2 array += scalar * (state.dagger() >> effect.dagger()).array return array
def __init__(self, *bitstring, _dagger=False): utensor = Tensor.id( Dim(1)).tensor(*(Tensor(Dim(1), Dim(2), [0, 1] if bit else [1, 0]) for bit in bitstring)) name = "Bits({})".format(', '.join(map(str, bitstring))) dom, cod = (len(bitstring), 0) if _dagger else (0, len(bitstring)) super().__init__(name, dom, cod, array=utensor.array, _dagger=_dagger) self.bitstring = bitstring
def discard(dom): """ Discard a quantum dimension or take the marginal distribution. """ array = Tensor.np.tensordot(Tensor.np.ones(dom.classical), Tensor.id(dom.quantum).array, 0) return CQMap(dom, CQ(), array)
def id(dom=CQ()): utensor = Tensor.id(dom.classical @ dom.quantum @ dom.quantum) return CQMap(dom, dom, utensor=utensor)
def id(dom): data = Tensor.id(dom.classical @ dom.quantum @ dom.quantum) return CQMap(dom, dom, data.array)