Beispiel #1
0
    def __init__(self, num_qubits, coupling_graph=None):
        """
        Constructs an all-to-all topology by default.

        Args:
            num_qubits (int): The total number of qubits in the topology.

            coupling_graph (List[Tuple[int]]): List of connected qubit pairs.

        Raises:
            TypeError: If coupling_graph is invalid.
        """

        if coupling_graph is None:
            coupling_graph = []
            for l in it.combinations(range(num_qubits), 2):
                coupling_graph.append(tuple(l))

        if not utils.is_valid_coupling_graph(coupling_graph, num_qubits):
            raise TypeError("Invalid coupling graph.")

        self.coupling_graph = coupling_graph
        self.num_qubits = num_qubits
        self.cache = {}

        self.adjlist = [[] for i in range(self.num_qubits)]
        for q0, q1 in coupling_graph:
            self.adjlist[q0].append(q1)
            self.adjlist[q1].append(q0)
    def test_is_valid_coupling_graph_invalid3 ( self ):
        self.assertFalse( is_valid_coupling_graph( [ "a" ] ) )
        self.assertFalse( is_valid_coupling_graph( [ [0, 1] ] ) )
        self.assertFalse( is_valid_coupling_graph( [ [ [ 0 ], 1] ] ) )

        self.assertFalse( is_valid_coupling_graph( [ "a" ], 2 ) )
        self.assertFalse( is_valid_coupling_graph( [ [0, 1] ], 2 ) )
        self.assertFalse( is_valid_coupling_graph( [ [ [ 0 ], 1] ], 2 ) )
 def test_is_valid_coupling_graph_empty ( self ):
     self.assertTrue( is_valid_coupling_graph( [] ) )
     self.assertTrue( is_valid_coupling_graph( [], 0 ) )
     self.assertTrue( is_valid_coupling_graph( [], 5 ) )
 def test_is_valid_coupling_graph_invalid7 ( self ):
     self.assertFalse( is_valid_coupling_graph( [ (0, 0), (1, 1) ] ) )
     self.assertFalse( is_valid_coupling_graph( [ (0, 0), (1, 1) ], 5 ) )
 def test_is_valid_coupling_graph_invalid5 ( self ):
     self.assertFalse( is_valid_coupling_graph( [ (0, 1), (1, 2) ], 1 ) )
 def test_is_valid_coupling_graph_invalid4 ( self ):
     self.assertFalse( is_valid_coupling_graph( [ (0, 1, 2) ] ) )
     self.assertFalse( is_valid_coupling_graph( [ (0, 1, 2) ], 4 ) )
 def test_is_valid_coupling_graph_invalid2 ( self ):
     self.assertFalse( is_valid_coupling_graph( "a" ) )
     self.assertFalse( is_valid_coupling_graph( "a", 0 ) )
 def test_is_valid_coupling_graph_valid ( self ):
     cgraph = [ (0, 1), (1, 2), (2, 3), (4, 3), (0, 4) ]
     self.assertTrue( is_valid_coupling_graph( cgraph ) )
     self.assertTrue( is_valid_coupling_graph( cgraph, 5 ) )
Beispiel #9
0
def synthesize ( utry, model = "PermModel", optimizer = "LBFGSOptimizer",
                 tool = "QSearchTool", combiner = "NaiveCombiner",
                 hierarchy_fn = lambda x : x // 3 if x > 5 else 2,
                 coupling_graph = None, basis_gates = None,
                 intermediate_solution_callback = None, model_options = {} ):
    """
    Synthesize a unitary matrix and return qasm code using QFAST.

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

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

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

        tool (str): The native tool to use during instantiation.

        combiner (str): The combiner to use during recombination.

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

        coupling_graph (None or list[tuple[int]]): Determines the
            connection of qubits. If none, will be set to all-to-all.

        basis_gates (None or list[str]): Determines the gate set
            for the final circuit. Only works with tools that implement
            this feature.

        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.

        model_options (Dict): kwargs for model

    Returns:
        (str): Qasm code implementing utry.

    Raises:
        TypeError: If the coupling_graph is invalid.

        RuntimeError: If the native tool cannot be found.
    """

    if coupling_graph is not None:
        if not utils.is_valid_coupling_graph( coupling_graph ):
            raise TypeError( "The specified coupling graph is invalid." )


    if combiner not in plugins.get_combiners():
        raise RuntimeError( "Cannot find combiner." )

    # Get target_gate_size for decomposition
    if tool not in plugins.get_native_tools():
        raise RuntimeError( "Cannot find native tool." )

    target_gate_size = plugins.get_native_tool( tool )().get_maximum_size()

    num_qubits = utils.get_num_qubits( utry )
    topology = Topology( num_qubits, coupling_graph )

    # Decompose the big input unitary into smaller unitary gates.
    decomposer = Decomposer( utry, target_gate_size = target_gate_size,
                             model = model,
                             optimizer = optimizer,
                             topology = topology,
                             hierarchy_fn = hierarchy_fn,
                             intermediate_solution_callback = intermediate_solution_callback,
                             model_options = model_options )

    gate_list = decomposer.decompose()

    # Instantiate the small unitary gates into native code
    instantiater = Instantiater( tool, topology, basis_gates = basis_gates )
    qasm_list = instantiater.instantiate( gate_list )

    # Recombine all small circuits into one large output
    combiner = plugins.get_combiner( combiner )()
    qasm_out = combiner.combine( qasm_list )

    return qasm_out