def objective_function_monte_carlo(self, u_params): U = U4(u_params) V = self.get_env(U) assert abs( full_tomography_env_objective_function(FullStateTensor(U), FullEnvironment(V))) < 1e-6 qbs = cirq.LineQubit.range(4) C = cirq.Circuit().from_ops( cirq.decompose( State(FullStateTensor(U), FullEnvironment(V), 2)(*qbs))) noise = cirq.ConstantQubitNoiseModel( cirq.depolarize(self.depolarizing_prob)) system_qubits = sorted(C.all_qubits()) noisy_circuit = cirq.Circuit() for moment in C: noisy_circuit.append(noise.noisy_moment(moment, system_qubits)) sim = cirq.Simulator() ψ = sim.simulate(noisy_circuit).final_state H = kron(kron(eye(2), self.H), eye(2)) f = real(ψ.conj().T @ H @ ψ) #sim = cirq.DensityMatrixSimulator(noise=noise) #ρ = sim.simulate(noisy_circuit).final_density_matrix #f = real(trace(ρ@H)) return f
def evolve_U1(): hh = HH(1) U1 = np.array([[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) STEPS = 100 init_params = np.random.rand(15) results = [] RE = RightEnvironment() def obj2(p, U1, h_): U1_ = U4(p).conj().T _, Mr = RE.exact_environment(r(U1), r(np.eye(4)), r(U1_), r(np.eye(4))) return -2 * np.abs( (U1_ @ h_ @ U1)[0, 0] * Mr[0, 0] * Mr[0, 0].conj())**2 U1 = U1.conj().T hh = expm(1j * hh * 0.01) for _ in tqdm(range(STEPS)): res = minimize(obj2, x0=init_params, args=(U1, hh), method="Nelder-Mead", tol=1e-8, options={ "maxiter": 40000, "disp": True, "adaptive": True }) init_params = res.x U1 = U4(res.x) results.append(res.x) return results
def test_U_parametrisation_effectiveness(reps=100): """ We want to test the effectiveness of this parametrisation of unitary matrices. We specify random unitaries and then use the parametrisation to find a U1' and U2' that give maximal overlap with the initial matrices. In every case the overlap with the 0s was within 1e-4 of 1.0. However U1' did not compile to U1. I suggest this might be because of the freedom to insert a resolution of the identity along the closed legs of the overlap circuit. """ results = [] U1s = [] U1_s = [] for _ in range(reps): U1, U2 = unitary_group.rvs(4), unitary_group.rvs(4) cost_func = partial(params_overlaps, U1=U1, U2=U2) grad = partial(approx_fprime, f=cost_func, epsilon=0.001) res = minimize(cost_func, x0=np.random.rand(18), method="BFGS", jac=grad) results.append(res.fun) U1s.append(U1) U1_s.append(U4(res.x[3:])) return results, U1s, U1_s
def parametrised_Us(params): a, b, c = params[:3] U1_params = params[3:] U1 = U4(U1_params) u2 = (Z(a) @ X(b) @ D1(c) @ X(-b) @ Z(-a)).reshape(4, 1) U2 = np.concatenate((u2, null_space(u2.conj().T)), axis=1) return U1, U2
def two_cost_functions(): p = np.random.rand(15) U1 = np.array([[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) h = HH(1) print(obj(p, U1, h)) U1_ = U4(p).conj().T LE, RE = LeftEnvironment(), RightEnvironment() _, Ml = LE.exact_environment(r(U1), r(np.eye(4)), r(U1_), r(np.eye(4))) _, Mr = RE.exact_environment(r(U1), r(np.eye(4)), r(U1_), r(np.eye(4))) print(Ml, "\n", Mr) print((U1_ @ expm(1j * h * 0.01) @ U1)[0, 0] * Mr[0, 0] * Ml[0, 0])
def evolve_and_plot_U1(): res = evolve_U1() states = [] for r_ in res: U2 = U4(r_) state = U2 @ np.array([1, 0, 0, 0]) states.append(state) plt.figure() plt.plot(np.abs(np.array(states)[:, 1])**2, label="|01>") plt.plot(np.abs(np.array(states)[:, 2])**2, label="|10>") plt.legend() plt.show()
def obj(p, U1, h_): LE = LeftEnvironment() RE = RightEnvironment() psi1 = bwMPS([np.eye(4), U1], 2).state() U1_ = U4(p) _, Ml = LE.exact_environment(r(U1), r(np.eye(4)), r(U1_.conj().T), r(np.eye(4))) _, Mr = RE.exact_environment(r(U1), r(np.eye(4)), r(U1_.conj().T), r(np.eye(4))) Ut = expm(1j * h_ * 0.01) Ut_m = tensor([Ml, Ut, Mr]) psi2 = bwMPS([np.eye(4), U1_], 2).state() return np.abs(psi2.conj().T @ Ut_m @ psi1)**2
def __init__(self, H, depolarizing_prob, D=2, get_env_function=get_env_exact, initial_guess=None, settings: Dict = None): self.get_env = get_env_function if D != 2: raise NotImplementedError('D>2 not implemented') self.H = H self.D = D self.d = 2 self.depolarizing_prob = depolarizing_prob initial_guess = (randn(15) if initial_guess is None else initial_guess) u_original = FullStateTensor(U4(initial_guess)) v_original = None super().__init__(u_original, v_original, initial_guess=initial_guess)
def paramU(params): """ Return unitaries U1 and U2 from 22 params (15 params for the fully parametrised U1 and 7 for the single column of the unitary U2) """ p1 = params[7:] p2 = params[:7] U1 = U4(p1) # find a unit norm column that is going to be accessed by the circuit # and embed this column into a larger unitary matrix. ################################## # u2 = (self.Z(a) @ self.X(b) @ self.D1(c) @ self.X(-b) @ self.Z(-a)).reshape(4,1) #U2 = np.concatenate((u2, null_space(u2.conj().T)), axis = 1) ################################## # Doesnt look like it works U2 = OO_unitary(p2) return U1, U2
def objective_function(self, params): target_u = FullStateTensor(U4(params).conj()) num_qubits = 2 * self.u.num_qubits() qubits = cirq.LineQubit.range(num_qubits) self.circuit.circuit = cirq.Circuit.from_ops([ cirq.H.on(qubits[0]), cirq.H.on(qubits[1]), cirq.CNOT.on(qubits[0], qubits[2]), cirq.CNOT.on(qubits[1], qubits[3]), self.u.on(*qubits[0:2]), target_u.on(*qubits[2:4]), cirq.CNOT.on(qubits[0], qubits[2]), cirq.CNOT.on(qubits[1], qubits[3]), cirq.H.on(qubits[0]), cirq.H.on(qubits[1]) ]) simulator = cirq.Simulator() results = simulator.simulate(self.circuit.circuit) final_state = results.final_simulator_state.state_vector[0] score = np.abs(final_state)**2 return 1 - score
def obj2(p, U1, h_): U1_ = U4(p).conj().T _, Mr = RE.exact_environment(r(U1), r(np.eye(4)), r(U1_), r(np.eye(4))) return -2 * np.abs( (U1_ @ h_ @ U1)[0, 0] * Mr[0, 0] * Mr[0, 0].conj())**2
def trace_distance_cost_function(params, U): ''' Circuit 1: Circuit 2: Circuit 3: Trace distance objective function: | | | | | |` | | | | | | | | | | | | |-V-| | | |` | |-V-| | |-V-| | | | | | |-U-| | |-V-| |` |-U-| | |-U-| | | |-V-| |-V-| @-----------X |` @-----------X | @-------X H |` H | H break1 | break2 | rho sigma ''' environment = FullStateTensor(U4(params)) state = State(U, environment, 1) state_qubits = state.num_qubits() env_qubits = environment.num_qubits() aux_qubits = int(env_qubits / 2) control_qubits = list(range(aux_qubits)) target_qubits1 = list(range(state_qubits, state_qubits + aux_qubits)) target_qubits2 = list(range(state_qubits, state_qubits + aux_qubits)) target_qubits3 = list(range(env_qubits, env_qubits + aux_qubits)) total_qubits = (2 * state_qubits) qubits = cirq.LineQubit.range(total_qubits) cnots1 = [ cirq.CNOT(qubits[i], qubits[j]) for i, j in zip(control_qubits, target_qubits1) ] cnots2 = [ cirq.CNOT(qubits[i], qubits[j]) for i, j in zip(control_qubits, target_qubits2) ] cnots3 = [ cirq.CNOT(qubits[i], qubits[j]) for i, j in zip(control_qubits, target_qubits3) ] hadamards = [cirq.H(qubits[i]) for i in control_qubits] circuit1 = cirq.Circuit.from_ops([ state(*qubits[:state_qubits]), environment(*qubits[state_qubits:state_qubits + env_qubits]) ] + cnots1 + hadamards) circuit2 = cirq.Circuit.from_ops([ state(*qubits[:state_qubits]), state(*qubits[state_qubits:total_qubits]) ] + cnots2 + hadamards) circuit3 = cirq.Circuit.from_ops([ environment(*qubits[:env_qubits]), environment(*qubits[env_qubits:2 * env_qubits]) ] + cnots3 + hadamards) simulator = cirq.Simulator() results1 = simulator.simulate(circuit1) results2 = simulator.simulate(circuit2) results3 = simulator.simulate(circuit3) circuit1qubits = [*qubits[:aux_qubits] ] + [*qubits[state_qubits:state_qubits + aux_qubits]] circuit3qubits = [*qubits[:aux_qubits] ] + [*qubits[env_qubits:env_qubits + aux_qubits]] r_s = 1 - 2 * results1.density_matrix_of(circuit1qubits)[-1, -1] r_squared = 1 - 2 * results2.density_matrix_of(circuit1qubits)[-1, -1] s_squared = 1 - 2 * results3.density_matrix_of(circuit3qubits)[-1, -1] score = (r_squared + s_squared - 2 * r_s).real return np.abs(score)
def update_state(self): self.U = U4(self.optimized_result.x)