Exemplo n.º 1
0
    def synthesize(self, utry, **kwargs):
        """
        Synthesis function with this tool.

        Args:
            utry (np.ndarray): The unitary to synthesize.

        Returns
            qasm (str): The synthesized QASM output.

        Raises:
            TypeError: If utry is not a valid unitary.

            ValueError: If the utry has invalid dimensions.
        """

        if not utils.is_unitary(utry, tol=1e-14):
            raise TypeError("utry must be a valid unitary.")

        if utry.shape[0] > 2**self.get_maximum_size():
            raise ValueError("utry has incorrect dimensions.")

        num_qubits = utils.get_num_qubits(utry)
        basis_gates = ['u1', 'u2', 'u3', 'cx', 'id']

        circ = qiskit.QuantumCircuit(num_qubits)
        circ.iso(utry, list(reversed(range(num_qubits))), [])
        circ = qiskit.transpile(circ,
                                optimization_level=3,
                                basis_gates=basis_gates)
        return circ.qasm()
Exemplo n.º 2
0
    def test_is_unitary1(self):
        paulis = get_norder_paulis(3)

        for i in range(10):
            alpha = np.random.random(4**3)
            U = sp.linalg.expm(1j * dot_product(alpha, paulis))
            self.assertTrue(is_unitary(U, tol=1e-14))
Exemplo n.º 3
0
    def synthesize(self, utry):
        """
        Synthesis function with this tool.

        Args:
            utry (np.ndarray): The unitary to synthesize.

        Returns
            qasm (str): The synthesized QASM output.

        Raises:
            TypeError: If utry is not a valid unitary.

            ValueError: If the utry has invalid dimensions.
        """

        if not utils.is_unitary(utry, tol=1e-14):
            raise TypeError("utry must be a valid unitary.")

        if utry.shape[0] > 2**self.get_maximum_size():
            raise ValueError("utry has incorrect dimensions.")

        solver = qsearch.solvers.LeastSquares_Jac_SolverNative()
        assembler_style = qsearch.assembler.ASSEMBLY_IBMOPENQASM
        options = qsearch.options.Options()
        options.target = utry
        options.verbosity = 0
        compiler = qsearch.leap_compiler.LeapCompiler(solver=solver)
        output = compiler.compile(options)
        output = qsearch.assembler.assemble(output["structure"],
                                            output["vector"], assembler_style)
        return output
Exemplo n.º 4
0
    def __init__(self, utry, location):
        """
        Gate Class Constructor

        Args:
            utry (np.ndarray): The gate's unitary operation.

            location (tuple[int]): The set of qubits the gate acts on.

        Raises:
            TypeError: If unitary or location are invalid.
        """

        if not utils.is_unitary(utry, tol=1e-14):
            raise TypeError("Invalid unitary.")

        self.utry = utry
        self.num_qubits = utils.get_num_qubits(self.utry)

        if not utils.is_valid_location(location):
            raise TypeError("Invalid location.")

        if len(location) != self.num_qubits:
            raise ValueError("Invalid size of location.")

        self.location = location
Exemplo n.º 5
0
    def synthesize(self, utry, **kwargs):
        """
        Synthesis function with QISKit's KAK implementation.

        Args:
            utry (np.ndarray): The unitary to synthesize.

        Returns
            qasm (str): The synthesized QASM output.

        Raises:
            TypeError: If utry is not a valid unitary.

            ValueError: If the utry has invalid dimensions.
        """

        if not utils.is_unitary(utry, tol=1e-14):
            raise TypeError("utry must be a valid unitary.")

        if utry.shape[0] > 2**self.get_maximum_size():
            raise ValueError("utry has incorrect dimensions.")

        if utry.shape[0] == 4:
            circ = qiskit.QuantumCircuit(2)
            circ.unitary(utry, [1, 0])
        else:
            circ = qiskit.QuantumCircuit(1)
            circ.unitary(utry)

        circ = qiskit.compiler.transpile(circ,
                                         basis_gates=['u3', 'cx'],
                                         optimization_level=3)
        return circ.qasm()
Exemplo n.º 6
0
    def test_closest_unitary_valid_nonunitary1(self):
        valid_matrix = np.identity(4) + (1e-3 * np.ones((4, 4)))

        out_matrix = closest_unitary(valid_matrix)

        self.assertTrue(valid_matrix.shape == out_matrix.shape)
        self.assertTrue(is_unitary(out_matrix))
        self.assertTrue(np.linalg.norm(out_matrix - valid_matrix) <= 4 * 1e-3)
Exemplo n.º 7
0
    def test_closest_unitary_valid_unitary2(self):
        valid_matrix = np.identity(4)

        out_matrix = closest_unitary(valid_matrix)

        self.assertTrue(valid_matrix.shape == out_matrix.shape)
        self.assertTrue(np.linalg.norm(out_matrix - valid_matrix) <= 1e-16)
        self.assertTrue(is_unitary(out_matrix))
Exemplo n.º 8
0
    def test_closest_unitary_valid_unitary1(self):
        valid_matrix = np.array([[0, 1], [1, 0]])

        out_matrix = closest_unitary(valid_matrix)

        self.assertTrue(valid_matrix.shape == out_matrix.shape)
        self.assertTrue(np.linalg.norm(out_matrix - valid_matrix) <= 1e-16)
        self.assertTrue(is_unitary(out_matrix))
Exemplo n.º 9
0
def unitary_log_no_i(U, tol=1e-15):
    """
    Solves for H in U = e^{iH}

    Args:
        U (np.ndarray): The unitary to decompose

    Returns:
        H (np.ndarray): e^{iH} = U
    """

    if not utils.is_unitary(U, tol):
        raise TypeError("Input is not unitary.")

    T, Z = scipy.linalg.schur(U)
    T = np.diag(T)
    D = T / np.abs(T)
    D = np.diag(np.log(D))
    H0 = -1j * (Z @ D @ Z.conj().T)
    return 0.5 * H0 + 0.5 * H0.conj().T
Exemplo n.º 10
0
 def test_is_unitary_invalid(self):
     self.assertFalse(is_unitary(1j * np.ones((4, 4))))
     self.assertFalse(is_unitary(np.ones((4, 3))))
     self.assertFalse(is_unitary(np.ones((4, ))))
     self.assertFalse(is_unitary(1))
     self.assertFalse(is_unitary("a"))
Exemplo n.º 11
0
    def __init__ ( self, utry, target_gate_size = 2, model = "PermModel",
                   optimizer = "LBFGSOptimizer",
                   hierarchy_fn = lambda x : x // 3 if x > 5 else 2,
                   topology = None, intermediate_solution_callback = None,
                   model_options = {} ):
        """
        Initializes a decomposer.

        Args:
            utry (np.ndarray): A unitary matrix to decompose

            target_gate_size (int): After decomposition, this will be
                the largest size of any gate in the returned list.

            model (str): The circuit model to use during decomposition.

            optimizer (str): The optimizer to use during decomposition.

            hierarchy_fn (callable): This function determines the
                decomposition hierarchy.

            topoology (Topology): Determines the connection of qubits.
                If none, will be set to all-to-all.

            intermediate_solution_callback (None or callable): Callback
                function for intermediate solutions. If not None, then
                a function that takes in a list[Gates] and returns nothing.

        Raises:
            ValueError: If the target_gate_size is nonpositive or too large.

            RuntimeError: If the model or optimizer cannot be found.
        """

        if not utils.is_unitary( utry, tol = 1e-14 ):
            logger.warning( "Unitary is not doubly-precise." )
            logger.warning( "Proceeding with closest unitary to input." )
            self.utry = utils.closest_unitary( utry )
        else:
            self.utry = utry

        self.num_qubits = utils.get_num_qubits( utry )

        if target_gate_size <= 0 or target_gate_size > self.num_qubits:
            raise ValueError( "Invalid target gate size." )

        self.target_gate_size = target_gate_size

        if not callable( hierarchy_fn ):
            raise TypeError( "Invalid hierarchy function." )

        if intermediate_solution_callback is not None:
            if not callable( intermediate_solution_callback ):
                raise TypeError( "Invalid intermediate solution callback." )

        self.hierarchy_fn = hierarchy_fn
        self.intermediate_solution_callback = intermediate_solution_callback

        if topology is not None and not isinstance( topology, Topology ):
            raise TypeError( "Invalid topology." )

        self.topology = topology or Topology( self.num_qubits )

        if model not in plugins.get_models():
            raise RuntimeError( f"Cannot find decomposition model: {model}" )

        self.model = plugins.get_model( model )

        if optimizer not in plugins.get_optimizers():
            raise RuntimeError( f"Cannot find optimizer: {optimizer}" )

        self.model_options = model_options
        self.optimizer = plugins.get_optimizer( optimizer )

        logger.debug( "Created decomposer with %s and %s."
                      % ( model, optimizer ) )
Exemplo n.º 12
0
Arquivo: qs.py Projeto: BQSKit/qfast
    def synthesize(self, utry, **kwargs):
        """
        Synthesis function with this tool.

        Args:
            utry (np.ndarray): The unitary to synthesize.

        Returns
            qasm (str): The synthesized QASM output.

        Raises:
            TypeError: If utry is not a valid unitary.

            ValueError: If the utry has invalid dimensions.
        """

        if not utils.is_unitary(utry, tol=1e-14):
            raise TypeError("utry must be a valid unitary.")

        if utry.shape[0] > 2**self.get_maximum_size():
            raise ValueError("utry has incorrect dimensions.")

        # Parse kwargs
        basis_gates = ["cx"]
        coupling_graph = [(0, 1), (1, 2)]
        if "basis_gates" in kwargs:
            basis_gates = kwargs["basis_gates"] or basis_gates
        if "coupling_graph" in kwargs:
            coupling_graph = kwargs["coupling_graph"] or coupling_graph

        # Prepermute unitary to line up coupling_graph
        # This is done because qsearch handles pure linear topologies best
        if utils.get_num_qubits(utry) == 3:
            a = (0, 1) in coupling_graph
            b = (1, 2) in coupling_graph
            c = (0, 2) in coupling_graph

            if not (a and b):
                if (a and c):
                    # Permute 0 and 1
                    P = perm.calc_permutation_matrix(3, (1, 0, 2))
                    utry = P @ utry @ P.T
                elif (b and c):
                    # Permute 1 and 2
                    P = perm.calc_permutation_matrix(3, (0, 2, 1))
                    utry = P @ utry @ P.T
                else:
                    raise ValueError("Invalid coupling graph.")

        # Pass options into qsearch, being maximally quiet,
        # and set the target to utry
        opts = options.Options()
        opts.target = utry
        opts.gateset = self.map_basis_str_to_gateset(basis_gates)
        opts.verbosity = 0
        opts.write_to_stdout = False
        opts.reoptimize_size = 7

        # use the LEAP compiler, which scales better than normal qsearch
        compiler = leap_compiler.LeapCompiler()
        output = compiler.compile(opts)

        # LEAP requires some post-processing
        pp = post_processing.LEAPReoptimizing_PostProcessor()
        output = pp.post_process_circuit(output, opts)
        output = assemblers.ASSEMBLER_IBMOPENQASM.assemble(output)

        # Renumber qubits in circuit if we flipped the unitary
        if utils.get_num_qubits(utry) == 3:
            a = (0, 1) in coupling_graph
            b = (1, 2) in coupling_graph
            c = (0, 2) in coupling_graph

            if not (a and b):
                if (a and c):
                    # Permute 0 and 1
                    str0 = "[0]"
                    str1 = "[1]"

                elif (b and c):
                    # Permute 1 and 2
                    str0 = "[1]"
                    str1 = "[2]"

                output = output.replace(str0, "[tmp]")
                output = output.replace(str1, str0)
                output = output.replace("[tmp]", str1)

        return output