Exemple #1
0
def gc_decomp(U):
  """Group commutator decomposition."""

  def diagonalize(U):
    _, V = np.linalg.eig(U)
    return ops.Operator(V)

  # Get axis and theta for the operator.
  axis, theta = u_to_bloch(U)

  # The angle phi comes from eq 10 in 'The Solovay-Kitaev Algorithm' by
  # Dawson, Nielsen. It is fully derived in the book section on the
  # theorem and algorithm.
  phi = 2.0 * np.arcsin(np.sqrt(
      np.sqrt((0.5 - 0.5 * np.cos(theta / 2)))))

  V = ops.RotationX(phi)
  if axis[2] > 0:
    W = ops.RotationY(2 * np.pi - phi)
  else:
    W = ops.RotationY(phi)

  Ud = diagonalize(U)
  VWVdWdd = diagonalize(V @ W @ V.adjoint() @ W.adjoint())
  S = Ud @ VWVdWdd.adjoint()

  V_hat = S @ V @ S.adjoint()
  W_hat = S @ W @ S.adjoint()
  return V_hat, W_hat
Exemple #2
0
def gc_decomp(U):
  """Group Commutator Decomposition."""

  def diagonalize(U):
    _, V = np.linalg.eig(U)
    return ops.Operator(V)

  # Because of moderate numerical instability, it can happen
  # that the trace is just a tad over 2.000000. If this happens,
  # we tolerate it and set the trace to exactly 2.000000.
  tr = np.trace(U)
  if tr > 2.0:
    tr = 2.0

  # We know how to compute theta from u_to_bloch().
  theta = 2.0 * np.arccos(np.real(tr / 2))
  # The angle phi comes from eq 10 in 'The Solovay-Kitaev Algorithm' by
  # Dawson, Nielsen.
  phi = 2.0 * np.arcsin(np.sqrt(np.sqrt((0.5 - 0.5 * np.cos(theta / 2)))))

  axis, _ = u_to_bloch(U)
  V = ops.RotationX(phi)
  if axis[2] < 0:
    W = ops.RotationY(2 * np.pi - phi)
  else:
    W = ops.RotationY(phi)

  V1 = diagonalize(U)
  V2 = diagonalize(V @ W @ V.adjoint() @ W.adjoint())
  S = V1 @ V2.adjoint()
  V_tilde = S @ V @ S.adjoint()
  W_tilde = S @ W @ S.adjoint()
  return V_tilde, W_tilde
Exemple #3
0
def main(argv):
  if len(argv) > 1:
    raise app.UsageError('Too many command-line arguments.')

  num_experiments = 10
  depth = 8
  recursion = 4
  print('SK algorithm - depth: {}, recursion: {}, experiments: {}'.
        format(depth, recursion, num_experiments))

  base = [to_su2(ops.Hadamard()), to_su2(ops.Tgate())]
  gates = create_unitaries(base, depth)
  sum_dist = 0.0
  for i in range(num_experiments):
      U = (ops.RotationX(2.0 * np.pi * random.random()) @
           ops.RotationY(2.0 * np.pi * random.random()) @
           ops.RotationZ(2.0 * np.pi * random.random()))

      U_approx = sk_algo(U, gates, recursion)

      dist = trace_dist(U, U_approx)
      sum_dist += dist

      phi1 = U(state.zero)
      phi2 = U_approx(state.zero)
      print('[{:2d}]: Trace Dist: {:.4f} State: {:6.4f}%'.
            format(i, dist,
                   100.0 * (1.0 - np.real(np.dot(phi1, phi2.conj())))))

  print('Gates: {}, Mean Trace Dist:: {:.4f}'.
        format(len(gates), sum_dist / num_experiments))
Exemple #4
0
def random_gates(min_length, max_length, num_experiments):
  """Just create random sequences, find the best."""

  base = [to_su2(ops.Hadamard()), to_su2(ops.Tgate())]

  U = (ops.RotationX(2.0 * np.pi * random.random()) @
       ops.RotationY(2.0 * np.pi * random.random()) @
       ops.RotationZ(2.0 * np.pi * random.random()))

  min_dist = 1000
  for _ in range(num_experiments):
    seq_length = min_length + random.randint(0, max_length)
    U_approx = ops.Identity()

    for _ in range(seq_length):
      g = random.randint(0, 1)
      U_approx = U_approx @ base[g]

    dist = trace_dist(U, U_approx)
    min_dist = min(dist, min_dist)

  phi1 = U(state.zero)
  phi2 = U_approx(state.zero)
  print('Trace Dist: {:.4f} State: {:6.4f}%'.
        format(min_dist,
               100.0 * (1.0 - np.real(np.dot(phi1, phi2.conj())))))
Exemple #5
0
 def ry(self, idx: int, theta: float):
     self.apply1(ops.RotationY(theta), idx, 'ry', val=theta)
Exemple #6
0
def make_u(alpha, beta, gamma, delta):
    """Construct unitary from the 4 parameters."""

    return (
        (ops.RotationZ(beta) @ ops.RotationY(gamma) @ ops.RotationZ(delta)) *
        cmath.exp(1.0j * alpha))
Exemple #7
0
 def ry(self, idx, theta):
     self.apply1(ops.RotationY(theta), idx, 'ry', val=theta)