예제 #1
0
    def _get_cccu_commands(
            control_mapping: _ControlQubits, rsrc: ResourceAllocator,
            max_num_qubits: int) -> Tuple[_ControlQubits, List[ICommand]]:
        """
        Builds a circuit that computes the AND condition on the `control_mapping`
        qubits (some possibly negated) into one qubit.
        To acheive this, when the number of control bits is greater than `max_num_qubits`,
        an `ancilla_allocator` may be used to allocate extra qubits.
        The resulting computation consists of X gates (for negation) and CCX gates to
        construct a computation tree. This tree has a logarithmic depth.
        Returns a tuple consisting of a new control qubits dict and the computation commands.
        """

        commands: List[ICommand] = []

        for (qubit_id, is_positive) in control_mapping.items():
            if is_positive == 0:
                commands.append(GateCmd(X_GATE, qubit_id))

        control_qubit_ids = list(control_mapping)

        while len(control_qubit_ids) > max_num_qubits:
            q1 = control_qubit_ids.pop(0)
            q2 = control_qubit_ids.pop(0)
            q3 = rsrc.allocate_qubit()
            commands.append(GateCmd(X_GATE, q3, control_qubit_ids={q1, q2}))
            control_qubit_ids.append(q3)

        return {q: 1 for q in control_qubit_ids}, commands
예제 #2
0
 def _test_one_qubit_command_3(self, cmd_class) -> None:
   min_unused_qubit_id = 2
   cmd_1: ICommand = GateCmd(cmd_class, 0)
   cmd_2: ICommand = GateCmd(cmd_class, 1)
   commands: List[ICommand] = [cmd_1,cmd_2]
   actual: List[ICommand] = QuasarOpt().run(commands, min_unused_qubit_id)
   expected: List[ICommand] = [cmd_1, cmd_2]
   self.assertListEqual(actual, expected)
예제 #3
0
 def _test_two_qubits_cu3_command_2(self) -> None:
   min_unused_qubit_id = 2
   cmd_1: ICommand = GateCmd(U3_GATE, 1, params=[2.2, 3.3, 4.4], control_qubit_ids={0})
   cmd_2: ICommand = GateCmd(U3_GATE, 1, params=[2.2, 3.3, 4.4], control_qubit_ids={0})
   commands: List[ICommand] = [cmd_1, cmd_2]
   actual: List[ICommand] = QuasarOpt().run(commands, min_unused_qubit_id)
   expected: List[ICommand] = [cmd_1, cmd_2]
   self.assertListEqual(actual, expected)
예제 #4
0
 def _test_one_qubit_u3_command_2(self) -> None:
   min_unused_qubit_id = 1
   cmd_1: ICommand = GateCmd(U3_GATE, 0, params=[1.1, 2.2, 3.3])
   cmd_2: ICommand = GateCmd(U3_GATE, 0, params=[1.1, 3.3, 2.2])
   commands: List[ICommand] = [cmd_1, cmd_2]
   actual: List[ICommand] = QuasarOpt().run(commands, min_unused_qubit_id)
   expected: List[ICommand] = [cmd_1, cmd_2]
   self.assertListEqual(actual, expected)
예제 #5
0
 def _test_three_qubits_command_5(self, cmd_class) -> None:
   min_unused_qubit_id = 5
   cmd_1: ICommand = GateCmd(cmd_class, 2, control_qubit_ids={0, 1})
   cmd_2: ICommand = GateCmd(cmd_class, 0, control_qubit_ids={2, 1})
   commands: List[ICommand] = [cmd_1, cmd_2]
   actual: List[ICommand] = QuasarOpt().run(commands, min_unused_qubit_id)
   expected: List[ICommand] = [cmd_1, cmd_2]
   self.assertListEqual(actual, expected)
예제 #6
0
 def _test_three_qubits_reset_command_3(self, cmd_class_1, cmd_class_2) -> None:
   min_unused_qubit_id = 3
   cmd_1: ICommand = GateCmd(cmd_class_1, 2, control_qubit_ids={0, 1})
   cmd_2: ICommand = cmd_class_2(2)
   cmd_3: ICommand = GateCmd(cmd_class_1, 2, control_qubit_ids={0, 1})
   commands: List[ICommand] = [cmd_1, cmd_2, cmd_3]
   actual: List[ICommand] = QuasarOpt().run(commands, min_unused_qubit_id)
   expected: List[ICommand] = [cmd_1, cmd_2, cmd_3]
   self.assertListEqual(actual, expected)
예제 #7
0
 def _test_two_qubits_command_6(self, cmd_class) -> None:
   min_unused_qubit_id = 4
   cmd_1: ICommand = GateCmd(cmd_class, 1, control_qubit_ids={0})
   cmd_2: ICommand = GateCmd(cmd_class, 3, control_qubit_ids={2})
   cmd_3: ICommand = GateCmd(cmd_class, 1, control_qubit_ids={2})
   commands: List[ICommand] = [cmd_1, cmd_2, cmd_3]
   actual: List[ICommand] = QuasarOpt().run(commands, min_unused_qubit_id)
   expected: List[ICommand] = [cmd_1, cmd_2, cmd_3]
   self.assertListEqual(actual, expected)
예제 #8
0
 def _test_one_qubit_commands_2(self, cmd_class_1, cmd_class_2) -> None:
   min_unused_qubit_id = 1
   cmd_1: ICommand = GateCmd(cmd_class_1, 0)
   cmd_2: ICommand = GateCmd(cmd_class_2, 0)
   cmd_3: ICommand = GateCmd(cmd_class_2, 0)
   cmd_4: ICommand = GateCmd(cmd_class_1, 0)
   commands: List[ICommand] = [cmd_1, cmd_2, cmd_3, cmd_4]
   actual: List[ICommand] = QuasarOpt().run(commands, min_unused_qubit_id)
   expected: List[ICommand] = []
   self.assertListEqual(actual, expected)
예제 #9
0
 def _test_two_qubits_commands_3(self, cmd_class_1, cmd_class_2) -> None:
   min_unused_qubit_id = 2
   cmd_1: ICommand = GateCmd(cmd_class_1, 1, control_qubit_ids={0})
   cmd_2: ICommand = GateCmd(cmd_class_2, 0, control_qubit_ids={1})
   cmd_3: ICommand = GateCmd(cmd_class_2, 1, control_qubit_ids={0})
   cmd_4: ICommand = GateCmd(cmd_class_1, 0, control_qubit_ids={1})
   commands: List[ICommand] = [cmd_1, cmd_2, cmd_3, cmd_4]
   actual: List[ICommand] = QuasarOpt().run(commands, min_unused_qubit_id)
   expected: List[ICommand] = [cmd_1, cmd_2, cmd_3, cmd_4]
   self.assertListEqual(actual, expected)
예제 #10
0
        def inverse_command(command: ICommand):
            if not isinstance(command, GateCmd):
                raise ValueError(f"Inverse of {type(command)} is impossible.")

            inv_gate, inv_params = invert_gate(command._gate, command._params)

            return GateCmd(inv_gate, command.get_target_qubit_id(),
                           command.get_control_qubit_ids(), inv_params)
예제 #11
0
    def _get_on_gate_commands(self, node: GateNode) -> List[ICommand]:
        if not self._control_mapping:
            return [
                GateCmd(node.gate,
                        node.get_target_qubit_id(),
                        params=node.params)
            ]

        negate_negative_commands: List[ICommand] = []

        for qubit_id, mask in self._control_mapping.items():
            if mask == 0:
                negate_negative_commands.append(GateCmd(X_GATE, qubit_id))

        num_ancillas = 0
        commands: List[ICommand]
        control_commands: List[ICommand] = []
        control_qubit_ids = list(self._control_mapping)
        max_controls = 2 if node.gate == X_GATE else 1  # TODO(adsz): to be defined by gate / target architecture

        while len(control_qubit_ids) > max_controls:
            control_1 = control_qubit_ids.pop(0)
            control_2 = control_qubit_ids.pop(0)
            ancilla = self._rsrc.allocate_qubit()
            num_ancillas += 1
            control_qubit_ids.append(ancilla)
            control_commands.append(
                GateCmd(X_GATE,
                        ancilla,
                        control_qubit_ids={control_1, control_2}))

        controlled_command = GateCmd(node.gate,
                                     node.get_target_qubit_id(),
                                     params=node.params,
                                     control_qubit_ids=set(control_qubit_ids))

        commands = (control_commands + [controlled_command] +
                    self._inversed(control_commands))

        self._rsrc.free_qubits(num_ancillas)

        return (negate_negative_commands + commands +
                self._inversed(negate_negative_commands))
예제 #12
0
    def _get_qubit_negation_commands(control_mapping) -> List[ICommand]:
        """ This function makes sure that all control qubits
        are in fact positively controlling. """
        result: List[ICommand] = []

        for qubit_id, mask in control_mapping.items():
            if mask == 0:
                result.append(GateCmd(X_GATE, qubit_id))
                control_mapping[qubit_id] = 1

        return result
예제 #13
0
def check_commutation(cmd1: GateCmd, cmd2: GateCmd) -> bool:
    """ Returns True if two gates can be swapped with no change to the outcome. """
    # TODO(adsz): In future, it might be also beneficial to check commutation
    #  that alters the gates (with similar gate complexity).

    if cmd1 == cmd2:
        return True
    if not ((cmd1.get_control_qubit_ids() | {cmd1.get_target_qubit_id()}) &
            (cmd2.get_control_qubit_ids() | {cmd2.get_target_qubit_id()})):
        return True
    if cmd1.gate == Z_GATE and cmd2.gate == Z_GATE:
        return True
    if cmd1.gate == X_GATE and cmd2.gate == X_GATE:
        if cmd1.get_target_qubit_id() in cmd2.get_control_qubit_ids():
            return False
        elif cmd2.get_target_qubit_id() in cmd1.get_control_qubit_ids():
            return False
        else:
            return True
    # TODO(adsz): Two simplest rules as a starting point. Add more rules.

    return False
예제 #14
0
    def on_if_flip(self, if_flip: IfFlipNode) -> None:
        qubits_counter = self._rsrc.get_min_unused_qubit_id()
        cvis = CompileVisitor(self._rsrc)
        if_flip.get_condition().accept(cvis)

        cvis._commands.extend(
            CompileVisitor._get_reduced_commands(2, cvis._control_mapping,
                                                 cvis._rsrc))

        cvis._commands.extend(
            CompileVisitor._get_qubit_negation_commands(cvis._control_mapping))
        control_qubit_ids = list(cvis._control_mapping)

        if_commands: List[ICommand] = cvis._commands

        flip_command = GateCmd(Z_GATE,
                               control_qubit_ids[-1],
                               control_qubit_ids=set(control_qubit_ids[:-1]))

        self._commands.extend(if_commands + [flip_command] +
                              self._inversed(if_commands))

        num_ancillas = self._rsrc.get_min_unused_qubit_id() - qubits_counter
        self._rsrc.free_qubits(num_ancillas)