Exemplo n.º 1
0
    def _trigger(self):
        if self.scalar not in self.trainer.summary:
            logger.warning(
                f'`{self.scalar}` has not been added to `trainer.summary`.')
            return
        step, value = self.trainer.summary[self.scalar][-1]

        if self.step is not None and step <= self.step:
            logger.warning(
                f'`{self.scalar}` has not been updated since last trigger.')
            return
        self.step = step

        if (self.best is None
                or (self.extreme == 'min' and value < self.best[1])
                or (self.extreme == 'max' and value > self.best[1])):
            self.best = (step, value)
            save_path = os.path.join(self.save_dir, self.name + '.pt')
            try:
                io.save(save_path, self.trainer.state_dict())
            except OSError:
                logger.exception(
                    f'Error occurred when saving checkpoint "{save_path}".')
            else:
                logger.info(f'Checkpoint saved: "{save_path}" ({value:.5g}).')

        if self.best is not None:
            self.trainer.summary.add_scalar(self.scalar + '/' + self.extreme,
                                            self.best[1])
Exemplo n.º 2
0
def switch_little_big_endian_state(state):
    if len(state.shape) > 1:
        is_batch_state = True
        bsz = state.shape[0]
        reshape = [bsz] + [2] * int(np.log2(state[0].size))
    elif len(state.shape) == 1:
        is_batch_state = False
        reshape = [2] * int(np.log2(state.size))
    else:
        logger.exception(f"Dimension of statevector should be 1 or 2")
        raise ValueError

    original_shape = state.shape
    state = state.reshape(reshape)

    if is_batch_state:
        axes = list(range(1, len(state.shape)))
        axes.reverse()
        axes = [0] + axes
    else:
        axes = list(range(len(state.shape)))
        axes.reverse()

    mat = np.transpose(state, axes=axes).reshape(original_shape)

    return mat
Exemplo n.º 3
0
def qubitunitary_matrix(params):
    matrix = params.squeeze(0)
    try:
        assert matrix.shape[-1] == matrix.shape[-2]
    except AssertionError as err:
        logger.exception(f"Operator must be a square matrix.")
        raise err

    try:
        U = matrix.cpu().detach().numpy()
        if matrix.dim() > 2:
            # batched unitary
            bsz = matrix.shape[0]
            assert np.allclose(np.matmul(U, np.transpose(U.conj(), [0, 2, 1])),
                               np.stack([np.identity(U.shape[-1])] * bsz),
                               atol=1e-5)
        else:
            assert np.allclose(np.matmul(U, np.transpose(U.conj(), [1, 0])),
                               np.identity(U.shape[0]),
                               atol=1e-5)
    except AssertionError as err:
        logger.exception(f"Operator must be unitary.")
        raise err

    return matrix
Exemplo n.º 4
0
 def _add_checkpoint(self, fpath: str) -> None:
     self.checkpoints.append(fpath)
     while (self.max_to_keep is not None
            and len(self.checkpoints) > self.max_to_keep):
         fpath = self.checkpoints.popleft()
         try:
             fs.remove(fpath)
         except OSError:
             logger.exception(
                 f'Error occurred when removing checkpoint "{fpath}".')
Exemplo n.º 5
0
 def _trigger(self) -> None:
     save_path = os.path.join(self.save_dir,
                              f'step-{self.trainer.global_step}.pt')
     try:
         io.save(save_path, self.trainer.state_dict())
     except OSError:
         logger.exception(
             f'Error occurred when saving checkpoint "{save_path}".')
     else:
         logger.info(f'Checkpoint saved: "{save_path}".')
         self._add_checkpoint(save_path)
Exemplo n.º 6
0
    def get_unitary(self):
        """
        To get the whole unitary of the module, need to make sure all
        modules are in the same schedule
        """
        try:
            assert len(self.schedules) == 1
        except AssertionError:
            logger.exception(f"More than one block schedule in on module")

        return self.get_schedule_unitary(self.schedules[0])
def state_tq_vs_qiskit_test():
    bsz = 1
    for n_wires in range(2, 10):
        q_dev = tq.QuantumDevice(n_wires=n_wires)
        q_dev.reset_states(bsz=bsz)

        x = torch.randn((1, 100000), dtype=F_DTYPE)
        q_layer = AllRandomLayer(n_wires=n_wires,
                                 wires=list(range(n_wires)),
                                 n_ops_rd=500,
                                 n_ops_cin=500,
                                 n_funcs=500,
                                 qiskit_compatible=True)

        q_layer(q_dev, x)
        state_tq = q_dev.states.reshape(bsz, -1)
        state_tq = switch_little_big_endian_state(state_tq.data.numpy())

        # qiskit
        circ = tq2qiskit(q_layer, x)
        # Select the StatevectorSimulator from the Aer provider
        simulator = Aer.get_backend('statevector_simulator')

        # Execute and get counts
        result = execute(circ, simulator).result()
        state_qiskit = result.get_statevector(circ)

        stable_threshold = 1e-5
        try:
            # WARNING: need to remove the global phase! The qiskit simulated
            # results sometimes has global phase shift.
            global_phase = find_global_phase(state_tq,
                                             np.expand_dims(state_qiskit, 0),
                                             stable_threshold)

            if global_phase is None:
                logger.exception(f"Cannot find a stable enough factor to "
                                 f"reduce the global phase, increase the "
                                 f"stable_threshold and try again")
                raise RuntimeError

            assert np.allclose(state_tq * global_phase,
                               state_qiskit,
                               atol=1e-6)
            logger.info(f"PASS tq vs qiskit [n_wires]={n_wires}")

        except AssertionError:
            logger.exception(f"FAIL tq vs qiskit [n_wires]={n_wires}")
            raise AssertionError

        except RuntimeError:
            raise RuntimeError

    logger.info(f"PASS tq vs qiskit statevector test")
Exemplo n.º 8
0
    def _trigger_epoch(self) -> None:
        try:
            meters = self.queue.get(timeout=60)
        except Empty:
            logger.exception('Error occurred in `GPUUtilizationTracker`.')
            return

        self.trainer.summary.add_scalar('utilization/gpu', np.mean(meters))
        if len(self.devices) > 1:
            for k, device in enumerate(self.devices):
                self.trainer.summary.add_scalar(
                    'utilization/gpu{}'.format(device), meters[k])
def measurement_tq_vs_qiskit_test():
    bsz = 1
    for n_wires in range(2, 10):
        q_dev = tq.QuantumDevice(n_wires=n_wires)
        q_dev.reset_states(bsz=bsz)

        x = torch.randn((1, 100000), dtype=F_DTYPE)
        q_layer = AllRandomLayer(n_wires=n_wires,
                                 wires=list(range(n_wires)),
                                 n_ops_rd=500,
                                 n_ops_cin=500,
                                 n_funcs=500,
                                 qiskit_compatible=True)

        q_layer(q_dev, x)
        measurer = tq.MeasureAll(obs=tq.PauliZ)
        # flip because qiskit is from N to 0, tq is from 0 to N
        measured_tq = np.flip(measurer(q_dev).data[0].numpy())

        # qiskit
        circ = tq2qiskit(q_layer, x)
        circ.measure(list(range(n_wires)), list(range(n_wires)))

        # Select the QasmSimulator from the Aer provider
        simulator = Aer.get_backend('qasm_simulator')

        # Execute and get counts
        result = execute(circ, simulator, shots=1000000).result()
        counts = result.get_counts(circ)
        measured_qiskit = get_expectations_from_counts(counts, n_wires=n_wires)

        try:
            # WARNING: the measurement has randomness, so tolerate larger
            # differences (MAX 20%) between tq and qiskit
            # typical mean difference is less than 1%
            diff = np.abs(measured_tq - measured_qiskit).mean()
            diff_ratio = (np.abs(
                (measured_tq - measured_qiskit) / measured_qiskit)).mean()
            logger.info(f"Diff: tq vs qiskit {diff} \t Diff Ratio: "
                        f"{diff_ratio}")
            assert np.allclose(measured_tq,
                               measured_qiskit,
                               atol=1e-4,
                               rtol=2e-1)
            logger.info(f"PASS tq vs qiskit [n_wires]={n_wires}")

        except AssertionError:
            logger.exception(f"FAIL tq vs qiskit [n_wires]={n_wires}")
            raise AssertionError

    logger.info(f"PASS tq vs qiskit measurement test")
Exemplo n.º 10
0
    def _before_train(self) -> None:
        checkpoints = glob.glob(os.path.join(self.load_dir, 'step-*.pt'))
        if not checkpoints:
            logger.warning(f'No checkpoints found: "{self.load_dir}".')
            return

        load_path = max(checkpoints, key=os.path.getmtime)
        try:
            state_dict = io.load(load_path, map_location='cpu')
            self.trainer.load_state_dict(state_dict)
        except OSError:
            logger.exception(
                f'Error occurred when loading checkpoint "{load_path}".')
        else:
            logger.info(f'Checkpoint loaded: "{load_path}".')
def unitary_tq_vs_qiskit_test():
    for n_wires in range(2, 10):
        q_dev = tq.QuantumDevice(n_wires=n_wires)
        x = torch.randn((1, 100000), dtype=F_DTYPE)
        q_layer = AllRandomLayer(n_wires=n_wires,
                                 wires=list(range(n_wires)),
                                 n_ops_rd=500,
                                 n_ops_cin=500,
                                 n_funcs=500,
                                 qiskit_compatible=True)

        unitary_tq = q_layer.get_unitary(q_dev, x)
        unitary_tq = switch_little_big_endian_matrix(unitary_tq.data.numpy())

        # qiskit
        circ = tq2qiskit(q_layer, x)
        simulator = Aer.get_backend('unitary_simulator')
        result = execute(circ, simulator).result()
        unitary_qiskit = result.get_unitary(circ)

        stable_threshold = 1e-5
        try:
            # WARNING: need to remove the global phase! The qiskit simulated
            # results sometimes has global phase shift.
            global_phase = find_global_phase(unitary_tq, unitary_qiskit,
                                             stable_threshold)

            if global_phase is None:
                logger.exception(f"Cannot find a stable enough factor to "
                                 f"reduce the global phase, increase the "
                                 f"stable_threshold and try again")
                raise RuntimeError

            assert np.allclose(unitary_tq * global_phase,
                               unitary_qiskit,
                               atol=1e-6)
            logger.info(f"PASS tq vs qiskit [n_wires]={n_wires}")

        except AssertionError:
            logger.exception(f"FAIL tq vs qiskit [n_wires]={n_wires}")
            raise AssertionError

        except RuntimeError:
            raise RuntimeError

    logger.info(f"PASS tq vs qiskit unitary test")
Exemplo n.º 12
0
    def acc_m_unitary_einsum(u, wires, module):
        if u.dim() % 2 == 1:
            is_u_batch = True
        else:
            is_u_batch = False

        device_wires = module.wires
        n_device_wires = len(device_wires)
        n_block_wires = len(wires)

        # module_matrix = module.matrix.to(self.device)
        module_matrix = module.static_matrix
        if module_matrix.dim() > 2:
            bsz = module_matrix.shape[0]
            is_module_matrix_batch = True
            shape_extension = [bsz]
        else:
            is_module_matrix_batch = False
            shape_extension = []

        if module.inverse:
            module_matrix = module_matrix.conj()
            if is_module_matrix_batch:
                module_matrix = module_matrix.permute(0, 2, 1)
            else:
                module_matrix = module_matrix.permute(1, 0)

        if n_device_wires > 1:
            module_matrix = module_matrix.view(shape_extension +
                                               [2] * n_device_wires * 2)

        # tensor indices for the quantum unitary
        n_block_letters = n_block_wires * 2
        unitary_indices = ABC[:n_block_letters]

        # indices of the quantum unitary affected by this operation
        locations_dim0 = [wires.index(wi) for wi in module.wires]
        affected_indices = "".join(ABC_ARRAY[locations_dim0].tolist())

        new_indices = ABC[n_block_letters:n_block_letters + n_device_wires]
        try:
            assert n_block_letters + n_device_wires < 26
        except AssertionError:
            logger.exception(f"Einsum letters insufficient, please switch to "
                             f"bmm implementation.")
            raise AssertionError

        new_unitary_indices = functools.reduce(
            lambda old_string, idx_pair: old_string.replace(
                idx_pair[0], idx_pair[1]),
            zip(affected_indices, new_indices),
            unitary_indices,
        )

        if is_u_batch:
            unitary_indices = ABC[-1] + unitary_indices

        if is_module_matrix_batch:
            new_indices = ABC[-1] + new_indices

        if is_u_batch or is_module_matrix_batch:
            new_unitary_indices = ABC[-1] + new_unitary_indices

        einsum_indices = f"{new_indices}{affected_indices}," \
                         f"{unitary_indices}->{new_unitary_indices}"

        new_unitary = torch.einsum(einsum_indices, module_matrix, u)

        return new_unitary
Exemplo n.º 13
0
def tq2qiskit(q_device: tq.QuantumDevice,
              m: tq.QuantumModule,
              x=None,
              draw=False,
              remove_ops=False,
              remove_ops_thres=1e-4):
    # build the module list without changing the statevector of QuantumDevice
    original_wires_per_block = m.wires_per_block
    original_static_mode = m.static_mode
    m.static_off()
    m.static_on(wires_per_block=q_device.n_wires)
    m.is_graph_top = False

    # forward to register all modules and parameters
    if x is None:
        m.forward(q_device)
    else:
        m.forward(q_device, x)

    m.is_graph_top = True
    m.graph.build_flat_module_list()

    module_list = m.graph.flat_module_list
    m.static_off()

    if original_static_mode:
        m.static_on(wires_per_block=original_wires_per_block)

    circ = QuantumCircuit(q_device.n_wires, q_device.n_wires)

    for module in module_list:
        try:
            # no params in module or batch size == 1, because we will
            # generate only one qiskit QuantumCircuit
            assert (module.params is None or module.params.shape[0] == 1)
        except AssertionError:
            logger.exception(f"Cannot convert batch model tq module")

    n_removed_ops = 0

    for module in module_list:
        if remove_ops:
            if module.name in [
                    'RX', 'RY', 'RZ', 'RXX', 'RYY', 'RZZ', 'RZX', 'PhaseShift',
                    'CRX', 'CRY', 'CRZ', 'U1', 'CU1'
            ]:
                param = module.params[0][0].item()
                param = param % (2 * np.pi)
                param = param - 2 * np.pi if param > np.pi else param
                if abs(param) < remove_ops_thres:
                    n_removed_ops += 1
                    continue

            elif module.name in ['U2', 'U3', 'CU3']:
                param = module.params[0].data.cpu().numpy()
                param = param % (2 * np.pi)
                param[param > np.pi] -= 2 * np.pi
                if all(abs(param) < remove_ops_thres):
                    n_removed_ops += 1
                    continue

        if module.name == 'Hadamard':
            circ.h(*module.wires)
        elif module.name == 'SHadamard':
            circ.ry(np.pi / 4, *module.wires)
        elif module.name == 'PauliX':
            circ.x(*module.wires)
        elif module.name == 'PauliY':
            circ.y(*module.wires)
        elif module.name == 'PauliZ':
            circ.z(*module.wires)
        elif module.name == 'S':
            circ.s(*module.wires)
        elif module.name == 'T':
            circ.t(*module.wires)
        elif module.name == 'SX':
            circ.sx(*module.wires)
        elif module.name == 'CNOT':
            circ.cnot(*module.wires)
        elif module.name == 'CZ':
            circ.cz(*module.wires)
        elif module.name == 'CY':
            circ.cy(*module.wires)
        elif module.name == 'RX':
            circ.rx(module.params[0][0].item(), *module.wires)
        elif module.name == 'RY':
            circ.ry(module.params[0][0].item(), *module.wires)
        elif module.name == 'RZ':
            circ.rz(module.params[0][0].item(), *module.wires)
        elif module.name == 'RXX':
            circ.rxx(module.params[0][0].item(), *module.wires)
        elif module.name == 'RYY':
            circ.ryy(module.params[0][0].item(), *module.wires)
        elif module.name == 'RZZ':
            circ.rzz(module.params[0][0].item(), *module.wires)
        elif module.name == 'RZX':
            circ.rzx(module.params[0][0].item(), *module.wires)
        elif module.name == 'SWAP':
            circ.swap(*module.wires)
        elif module.name == 'SSWAP':
            # square root of swap
            from torchquantum.plugins.qiskit_unitary_gate import UnitaryGate
            mat = module.matrix.data.cpu().numpy()
            mat = switch_little_big_endian_matrix(mat)
            circ.append(UnitaryGate(mat), module.wires, [])
        elif module.name == 'CSWAP':
            circ.cswap(*module.wires)
        elif module.name == 'Toffoli':
            circ.ccx(*module.wires)
        elif module.name == 'PhaseShift':
            circ.p(module.params[0][0].item(), *module.wires)
        elif module.name == 'CRX':
            circ.crx(module.params[0][0].item(), *module.wires)
        elif module.name == 'CRY':
            circ.cry(module.params[0][0].item(), *module.wires)
        elif module.name == 'CRZ':
            circ.crz(module.params[0][0].item(), *module.wires)
        elif module.name == 'U1':
            circ.u1(module.params[0][0].item(), *module.wires)
        elif module.name == 'CU1':
            circ.cu1(module.params[0][0].item(), *module.wires)
        elif module.name == 'U2':
            circ.u2(*list(module.params[0].data.cpu().numpy()), *module.wires)
        elif module.name == 'U3':
            circ.u3(*list(module.params[0].data.cpu().numpy()), *module.wires)
        elif module.name == 'CU3':
            circ.cu3(*list(module.params[0].data.cpu().numpy()), *module.wires)
        elif module.name == 'QubitUnitary' or \
                module.name == 'QubitUnitaryFast' or \
                module.name == 'TrainableUnitary' or \
                module.name == 'TrainableUnitaryStrict':
            from torchquantum.plugins.qiskit_unitary_gate import UnitaryGate
            mat = module.params[0].data.cpu().numpy()
            mat = switch_little_big_endian_matrix(mat)
            circ.append(UnitaryGate(mat), module.wires, [])
        elif module.name == 'MultiCNOT':
            circ.mcx(module.wires[:-1], module.wires[-1])
        elif module.name == 'MultiXCNOT':
            controls = module.wires[:-1]
            target = module.wires[-1]
            num_ctrl_qubits = len(controls)

            gate = qiskit_gate.MCXGrayCode(num_ctrl_qubits,
                                           ctrl_state='0' * num_ctrl_qubits)
            circ.append(gate, controls + [target], [])
        else:
            logger.exception(f"{module.name} cannot be converted to Qiskit.")
            raise NotImplementedError(module.name)

        if module.inverse:
            data = list(circ.data[-1])
            del circ.data[-1]
            circ.data.append(tuple([data[0].inverse()] + data[1:]))
    if draw:
        import matplotlib.pyplot as plt
        circ.draw()
        plt.show()

    if n_removed_ops > 0:
        logger.warning(f"Remove {n_removed_ops} operations with small "
                       f"parameter magnitude.")

    return circ
Exemplo n.º 14
0
    if args.pdb:
        pdb.set_trace()

    for pair in pair_list:
        try:
            if pair['tq'].num_params == 0:
                if pair['tq']().name == 'SHadamard':
                    """Square root of Hadamard is RY(pi/4)"""
                    qiskit_matrix = qiskit_gate.RYGate(theta=np.pi /
                                                       4).to_matrix()
                else:
                    qiskit_matrix = pair['qiskit']().to_matrix()
                tq_matrix = pair['tq'].matrix.numpy()
                tq_matrix = switch_little_big_endian_matrix(tq_matrix)
                assert np.allclose(qiskit_matrix, tq_matrix)
            else:
                for k in tqdm(range(RND_TIMES)):
                    rnd_params = np.random.rand(pair['tq'].num_params).tolist()
                    qiskit_matrix = pair['qiskit'](*rnd_params).to_matrix()
                    tq_matrix = pair['tq'](
                        has_params=True,
                        trainable=False,
                        init_params=rnd_params).matrix.numpy()
                    tq_matrix = switch_little_big_endian_matrix(tq_matrix)
                    assert np.allclose(qiskit_matrix, tq_matrix)

            logger.info(f"Gate {pair['tq']().name} match.")
        except AssertionError:
            logger.exception(f"Gate {pair['tq']().name} not match.")
            raise AssertionError