# Buggy code
def yzy_to_zyz(xi, theta1, theta2, eps=1e-9):
    """Express a Y.Z.Y single qubit gate as a Z.Y.Z gate.

    Solve the equation

    .. math::

    Ry(2*theta1).Rz(2*xi).Ry(2*theta2) = Rz(2*phi).Ry(2*theta).Rz(2*lambda)

    for theta, phi, and lambda. This is equivalent to solving the system
    given in the comment for test_solution. Use eps for comparisons with zero.

    Return a solution theta, phi, and lambda.
    """
    solutions = []  # list of potential solutions
    # Four cases to avoid singularities
    # TODO investigate when these can be .is_zero
    if sympy.Abs(sympy.cos(xi)).evalf() < eps:
        solutions.append((theta2 - theta1, xi, 0))
    elif sympy.Abs(sympy.sin(theta1 + theta2)).evalf() < eps:
        phi_minus_lambda = [
            sympy.pi / 2,
            3 * sympy.pi / 2,
            sympy.pi / 2,
            3 * sympy.pi / 2,
        ]
        stheta_1 = sympy.asin(sympy.sin(xi) * sympy.sin(-theta1 + theta2))
        stheta_2 = sympy.asin(-sympy.sin(xi) * sympy.sin(-theta1 + theta2))
        stheta_3 = sympy.pi - stheta_1
        stheta_4 = sympy.pi - stheta_2
        stheta = [stheta_1, stheta_2, stheta_3, stheta_4]
        phi_plus_lambda = list(
            map(
                lambda x: sympy.acos(
                    sympy.cos(theta1 + theta2) * sympy.cos(xi) / sympy.cos(x)
                ),
                stheta,
            )
        )
        sphi = [
            (term[0] + term[1]) / 2 for term in zip(phi_plus_lambda, phi_minus_lambda)
        ]
        slam = [
            (term[0] - term[1]) / 2 for term in zip(phi_plus_lambda, phi_minus_lambda)
        ]
        solutions = list(zip(stheta, sphi, slam))
    elif sympy.Abs(sympy.cos(theta1 + theta2)).evalf() < eps:
        phi_plus_lambda = [
            sympy.pi / 2,
            3 * sympy.pi / 2,
            sympy.pi / 2,
            3 * sympy.pi / 2,
        ]
        stheta_1 = sympy.acos(sympy.sin(xi) * sympy.cos(theta1 - theta2))
        stheta_2 = sympy.acos(-sympy.sin(xi) * sympy.cos(theta1 - theta2))
        stheta_3 = -stheta_1
        stheta_4 = -stheta_2
        stheta = [stheta_1, stheta_2, stheta_3, stheta_4]
        phi_minus_lambda = list(
            map(
                lambda x: sympy.acos(
                    sympy.sin(theta1 + theta2) * sympy.cos(xi) / sympy.sin(x)
                ),
                stheta,
            )
        )
        sphi = [
            (term[0] + term[1]) / 2 for term in zip(phi_plus_lambda, phi_minus_lambda)
        ]
        slam = [
            (term[0] - term[1]) / 2 for term in zip(phi_plus_lambda, phi_minus_lambda)
        ]
        solutions = list(zip(stheta, sphi, slam))
    else:
        phi_plus_lambda = sympy.atan(
            sympy.sin(xi)
            * sympy.cos(theta1 - theta2)
            / (sympy.cos(xi) * sympy.cos(theta1 + theta2))
        )
        phi_minus_lambda = sympy.atan(
            sympy.sin(xi)
            * sympy.sin(-theta1 + theta2)
            / (sympy.cos(xi) * sympy.sin(theta1 + theta2))
        )
        sphi = (phi_plus_lambda + phi_minus_lambda) / 2
        slam = (phi_plus_lambda - phi_minus_lambda) / 2
        solutions.append(
            (
                sympy.acos(
                    sympy.cos(xi) * sympy.cos(theta1 + theta2) / sympy.cos(sphi + slam)
                ),
                sphi,
                slam,
            )
        )
        solutions.append(
            (
                sympy.acos(
                    sympy.cos(xi)
                    * sympy.cos(theta1 + theta2)
                    / sympy.cos(sphi + slam + sympy.pi)
                ),
                sphi + sympy.pi / 2,
                slam + sympy.pi / 2,
            )
        )
        solutions.append(
            (
                sympy.acos(
                    sympy.cos(xi) * sympy.cos(theta1 + theta2) / sympy.cos(sphi + slam)
                ),
                sphi + sympy.pi / 2,
                slam - sympy.pi / 2,
            )
        )
        solutions.append(
            (
                sympy.acos(
                    sympy.cos(xi)
                    * sympy.cos(theta1 + theta2)
                    / sympy.cos(sphi + slam + sympy.pi)
                ),
                sphi + sympy.pi,
                slam,
            )
        )

    # Select the first solution with the required accuracy
    deltas = list(
        map(
            lambda x: test_trig_solution(x[0], x[1], x[2], xi, theta1, theta2),
            solutions,
        )
    )
    for delta_sol in zip(deltas, solutions):
        # TODO investigate when this can be .is_zero
        if delta_sol[0].evalf() < eps:
            return delta_sol[1]
    logger.debug("xi=%s", xi)
    logger.debug("theta1=%s", theta1)
    logger.debug("theta2=%s", theta2)
    logger.debug("solutions=%s", pprint.pformat(solutions))
    logger.debug("deltas=%s", pprint.pformat(deltas))
    assert False, "Error! No solution found. This should not happen."


# Traceback (AssertionError)
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-9-93ef2321f491> in <module>()
30 backend_coupling = backend_config['coupling_map']
31
---> 32 compiled_circuit = qp.compile([circuitName], backend=backend, coupling_map=backend_coupling)
33 compiled_qasm = qp.get_compiled_qasm(compiled_circuit, circuitName)
34 print("Number of gates at ", circuitName, " circuit is ", len(compiled_qasm.split("\n")) - 4)

~/miniconda3/envs/QISKitenv/lib/python3.6/site-packages/qiskit/_quantumprogram.py in compile(self, name_of_circuits, backend, config, basis_gates, coupling_map, initial_layout, shots, max_credits, seed, qobj_id, hpc, skip_translation)
972                                       config, basis_gates, coupling_map, initial_layout,
973                                       shots, max_credits, seed, qobj_id, hpc,
--> 974                                       skip_translation)
975         return qobj
976

~/miniconda3/envs/QISKitenv/lib/python3.6/site-packages/qiskit/wrapper/_wrapper.py in compile(circuits, backend, config, basis_gates, coupling_map, initial_layout, shots, max_credits, seed, qobj_id, hpc, skip_translation)
171                                     config, basis_gates, coupling_map, initial_layout,
172                                     shots, max_credits, seed, qobj_id, hpc,
--> 173                                     skip_translation)
174
175

~/miniconda3/envs/QISKitenv/lib/python3.6/site-packages/qiskit/_compiler.py in compile(circuits, backend, config, basis_gates, coupling_map, initial_layout, shots, max_credits, seed, qobj_id, hpc, skip_translation)
146                 coupling_map=coupling_map,
147                 initial_layout=initial_layout,
--> 148                 get_layout=True)
149             # Map the layout to a format that can be json encoded
150             list_layout = None

~/miniconda3/envs/QISKitenv/lib/python3.6/site-packages/qiskit/_compiler.py in compile_circuit(quantum_circuit, basis_gates, coupling_map, initial_layout, get_layout, format, seed)
237         cx_cancellation(compiled_dag_circuit)
238         # Simplify single qubit gates
--> 239         compiled_dag_circuit = optimize_1q_gates(compiled_dag_circuit)
240         logger.info("post-mapping properties: %s",
241                     compiled_dag_circuit.property_summary())

~/miniconda3/envs/QISKitenv/lib/python3.6/site-packages/qiskit/mapper/_mapping.py in optimize_1q_gates(circuit)
849                                               right_parameters[0],
850                                               right_parameters[1],
--> 851                                               right_parameters[2])
852                 # Why evalf()? This program:
853                 #   OPENQASM 2.0;

~/miniconda3/envs/QISKitenv/lib/python3.6/site-packages/qiskit/mapper/_mapping.py in compose_u3(theta1, phi1, lambda1, theta2, phi2, lambda2)
736     # Careful with the factor of two in yzy_to_zyz
737     thetap, phip, lambdap = yzy_to_zyz((lambda1 + phi2) / 2,
--> 738                                        theta1 / 2, theta2 / 2)
739     (theta, phi, lamb) = (2 * thetap, phi1 + 2 * phip, lambda2 + 2 * lambdap)
740     return (theta.simplify(), phi.simplify(), lamb.simplify())

~/miniconda3/envs/QISKitenv/lib/python3.6/site-packages/qiskit/mapper/_mapping.py in yzy_to_zyz(xi, theta1, theta2, eps)
720     logger.debug("solutions=%s", pprint.pformat(solutions))
721     logger.debug("deltas=%s", pprint.pformat(deltas))
--> 722     assert False, "Error! No solution found. This should not happen."
723
724

AssertionError: Error! No solution found. This should not happen.

# Fixed code
def yzy_to_zyz(xi, theta1, theta2, eps=1e-9):
    """Express a Y.Z.Y single qubit gate as a Z.Y.Z gate.

    Solve the equation

    .. math::

    Ry(theta1).Rz(xi).Ry(theta2) = Rz(phi).Ry(theta).Rz(lambda)

    for theta, phi, and lambda.

    Return a solution theta, phi, and lambda.
    """
    Q = quaternion_from_euler([theta1, xi, theta2], "yzy")
    euler = Q.to_zyz()
    P = quaternion_from_euler(euler, "zyz")
    # output order different than rotation order
    out_angles = (euler[1], euler[0], euler[2])
    abs_inner = abs(P.data.dot(Q.data))
    if not np.allclose(abs_inner, 1, eps):
        logger.debug("xi=%s", xi)
        logger.debug("theta1=%s", theta1)
        logger.debug("theta2=%s", theta2)
        logger.debug("solutions=%s", out_angles)
        logger.debug("abs_inner=%s", abs_inner)
        raise MapperError("YZY and ZYZ angles do not give same rotation matrix.")
    return out_angles