Ejemplo n.º 1
0
    def __init__(self, utry_target, gate_list):
        """
        CircuitTensor Constructor

        Args:
            utry_target (np.ndarray): Unitary target matrix

            gate_list (list[Gate]): The circuit's gate list.
        """

        if not utils.is_unitary(utry_target):
            raise TypeError("Specified target matrix is not unitary.")

        if not isinstance(gate_list, list):
            raise TypeError("Gate list is not a list.")

        if not all([isinstance(gate, Gate) for gate in gate_list]):
            raise TypeError("Gate list contains non-gate objects.")

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

        if not all([
                utils.is_valid_location(gate.location, self.num_qubits)
                for gate in gate_list
        ]):
            raise ValueError("Gate location mismatch with circuit tensor.")

        self.gate_list = gate_list
        self.reinitialize()
Ejemplo n.º 2
0
    def __init__(self, utry, location, fixed=False, check_params=True):
        """
        Gate Constructor

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

            location (tuple[int]): Set of qubits this gate is applied to.

            fixed (bool): True if the gate's unitary operation is immutable.

            check_params (bool): True implies parameters are checked for
                correctness.
        """

        if check_params:
            if not utils.is_unitary(utry):
                raise TypeError("Specified matrix is not unitary.")

            if not utils.is_valid_location(location):
                raise TypeError("Specified location is not valid.")

            if len(location) != utils.get_num_qubits(utry):
                raise ValueError("Location size does not match unitary.")

            if not isinstance(fixed, bool):
                raise TypeError("Invalid fixed parameter.")

        self.utry = utry
        self.location = location
        self.gate_size = len(location)
        self.fixed = fixed
Ejemplo n.º 3
0
def optimize(circuit,
             target,
             diff_tol_a=1e-12,
             diff_tol_r=1e-6,
             dist_tol=1e-10,
             max_iters=100000,
             min_iters=1000,
             slowdown_factor=0.0):
    """
    Optimize distance between circuit and target unitary.

    Args:
        circuit (list[Gate]): The circuit to optimize.

        target (np.ndarray): The target unitary matrix.

        diff_tol_a (float): Terminate when the difference in distance
            between iterations is less than this threshold.
       
       diff_tol_r (float): Terminate when the relative difference in
            distance between iterations is iless than this threshold:
                |c1 - c2| <= diff_tol_a + diff_tol_r * abs( c1 )

        dist_tol (float): Terminate when the distance is less than
            this threshold.

        max_iters (int): Maximum number of iterations.

        min_iters (int): Minimum number of iterations.

        slowdown_factor (float): A positive number less than 1. 
            The larger this factor, the slower the optimization.

    Returns:
        (list[Gate]): The optimized circuit.
    """

    if not isinstance(circuit, list):
        raise TypeError("The circuit argument is not a list of gates.")

    if not all([isinstance(g, Gate) for g in circuit]):
        raise TypeError("The circuit argument is not a list of gates.")

    if not utils.is_unitary(target):
        raise TypeError("The target matrix is not unitary.")

    if not isinstance(diff_tol_a, float) or diff_tol_a > 0.5:
        raise TypeError("Invalid absolute difference threshold.")

    if not isinstance(diff_tol_r, float) or diff_tol_r > 0.5:
        raise TypeError("Invalid relative difference threshold.")

    if not isinstance(dist_tol, float) or dist_tol > 0.5:
        raise TypeError("Invalid distance threshold.")

    if not isinstance(max_iters, int) or max_iters < 0:
        raise TypeError("Invalid maximum number of iterations.")

    if not isinstance(min_iters, int) or min_iters < 0:
        raise TypeError("Invalid minimum number of iterations.")

    if slowdown_factor < 0 or slowdown_factor >= 1:
        raise TypeError("Slowdown factor is a positive number less than 1.")

    ct = CircuitTensor(target, circuit)

    c1 = 0
    c2 = 1
    it = 0

    while True:

        # Termination conditions
        if it > min_iters:

            if np.abs(c1 - c2) <= diff_tol_a + diff_tol_r * np.abs(c1):
                diff = np.abs(c1 - c2)
                logger.info(f"Terminated: |c1 - c2| = {diff}"
                            " <= diff_tol_a + diff_tol_r * |c1|.")
                break

            if it > max_iters:
                logger.info("Terminated: iteration limit reached.")
                break

        it += 1

        # from right to left
        for k in range(len(circuit)):
            rk = len(circuit) - 1 - k

            # Remove current gate from right of circuit tensor
            ct.apply_right(circuit[rk], inverse=True)

            # Update current gate
            if not circuit[rk].fixed:
                env = ct.calc_env_matrix(circuit[rk].location)
                circuit[rk].update(env, slowdown_factor)

            # Add updated gate to left of circuit tensor
            ct.apply_left(circuit[rk])

        # from left to right
        for k in range(len(circuit)):

            # Remove current gate from left of circuit tensor
            ct.apply_left(circuit[k], inverse=True)

            # Update current gate
            if not circuit[k].fixed:
                env = ct.calc_env_matrix(circuit[k].location)
                circuit[k].update(env, slowdown_factor)

            # Add updated gate to right of circuit tensor
            ct.apply_right(circuit[k])

        c2 = c1
        c1 = np.abs(np.trace(ct.utry))
        c1 = 1 - (c1 / (2**ct.num_qubits))

        if c1 <= dist_tol:
            logger.info(f"Terminated: c1 = {c1} <= dist_tol.")
            return circuit

        if it % 100 == 0:
            logger.info(f"iteration: {it}, cost: {c1}")

        if it % 40 == 0:
            ct.reinitialize()

    return circuit
Ejemplo n.º 4
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"))
Ejemplo n.º 5
0
 def test_is_unitary2(self):
     for i in range(1, 10):
         U = unitary_group.rvs(2 * i)
         U += 1e-13 * np.ones((2 * i, 2 * i))
         self.assertTrue(is_unitary(U, tol=1e-12))
Ejemplo n.º 6
0
 def test_is_unitary1(self):
     for i in range(1, 10):
         U = unitary_group.rvs(2 * i)
         self.assertTrue(is_unitary(U, tol=1e-14))