def test_single_qubit_basis_transfrom(): ''' Testing whether transformations using the binary form and the transformation through direct computation agree ''' H, n_qubits, binary_sol, coeff_sol = prepare_test_hamiltonian() single_qub_H, old_basis, new_basis = BinaryHamiltonian.init_from_qubit_hamiltonian( H).single_qubit_form() H_brute_force = brute_force_transformation(H, old_basis, new_basis) assert (equal_qubit_hamiltonian(single_qub_H.to_qubit_hamiltonian(), H_brute_force)) H = -1.0 * paulis.X(0) * paulis.X(1) * paulis.X(2) + 2.0 * paulis.Y( 0) * paulis.Y(1) single_qub_H, old_basis, new_basis = BinaryHamiltonian.init_from_qubit_hamiltonian( H).single_qubit_form() H_brute_force = brute_force_transformation(H, old_basis, new_basis) assert (equal_qubit_hamiltonian(single_qub_H.to_qubit_hamiltonian(), H_brute_force))
def test_simple_arithmetic(): qubit = random.randint(0, 5) primitives = [paulis.X, paulis.Y, paulis.Z] assert (paulis.X(qubit).conjugate() == paulis.X(qubit)) assert (paulis.Y(qubit).conjugate() == -1 * paulis.Y(qubit)) assert (paulis.Z(qubit).conjugate() == paulis.Z(qubit)) assert (paulis.X(qubit).transpose() == paulis.X(qubit)) assert (paulis.Y(qubit).transpose() == -1 * paulis.Y(qubit)) assert (paulis.Z(qubit).transpose() == paulis.Z(qubit)) for P in primitives: assert (P(qubit) * P(qubit) == QubitHamiltonian(1.0)) n = random.randint(0, 10) nP = QubitHamiltonian.zero() for i in range(n): nP += P(qubit) assert (n * P(qubit) == nP) for i, Pi in enumerate(primitives): i1 = (i + 1) % 3 i2 = (i + 2) % 3 assert (Pi(qubit) * primitives[i1](qubit) == 1j * primitives[i2](qubit)) assert (primitives[i1](qubit) * Pi(qubit) == -1j * primitives[i2](qubit)) for qubit2 in random.randint(6, 10, 5): if qubit2 == qubit: continue P = primitives[random.randint(0, 2)] assert (Pi(qubit) * primitives[i1](qubit) * P(qubit2) == 1j * primitives[i2](qubit) * P(qubit2)) assert (P(qubit2) * primitives[i1](qubit) * Pi(qubit) == -1j * P(qubit2) * primitives[i2](qubit))
def test_paulistring_conversion(): X1 = QubitHamiltonian.from_string("X0", openfermion_format=True) X2 = paulis.X(0) keys = [i for i in X2.keys()] pwx = PauliString.from_openfermion(key=keys[0], coeff=X2[keys[0]]) X3 = QubitHamiltonian.from_paulistrings(pwx) assert (X1 == X2) assert (X2 == X3) H = paulis.X(0) * paulis.Y(1) * paulis.Z(2) + paulis.X(3) * paulis.Y( 4) * paulis.Z(5) PS = [] for key, value in H.items(): PS.append(PauliString.from_openfermion(key, value)) PS2 = H.paulistrings assert (PS == PS2) H = make_random_pauliword(complex=True) for i in range(5): H += make_random_pauliword(complex=True) PS = [] for key, value in H.items(): PS.append(PauliString.from_openfermion(key, value)) PS2 = H.paulistrings assert (PS == PS2)
def test_dagger(): assert (paulis.X(0).dagger() == paulis.X(0)) assert (paulis.Y(0).dagger() == paulis.Y(0)) assert (paulis.Z(0).dagger() == paulis.Z(0)) for repeat in range(10): string = make_random_pauliword(complex=False) assert (string.dagger() == string) assert ((1j * string).dagger() == -1j * string)
def prepare_test_hamiltonian(): ''' Return a test hamiltonian and its solution ''' H = -1.0 * paulis.Z(0) * paulis.Z(1) - 0.5 * paulis.Y(0) * paulis.Y( 1) + 0.1 * paulis.X(0) * paulis.X(1) + 0.2 * paulis.Z(2) coeff_sol = np.array([-1.0, -0.5, 0.1, 0.2]) binary_sol = np.array([[0, 0, 0, 1, 1, 0], [1, 1, 0, 1, 1, 0], [1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1]]) return H, H.n_qubits, binary_sol, coeff_sol
def test_qubit_wise_commuting(): ''' Testing whether method is_qubit_wise_commuting correctly recognizes qubit wise commuting parts. ''' not_qwc = -1.0 * paulis.Z(0) * paulis.Z(1) - 0.5 * paulis.Y(0) * paulis.Y(1) not_qwc = BinaryHamiltonian.init_from_qubit_hamiltonian(not_qwc) qwc = paulis.Z(0) * paulis.Z(1) + paulis.Z(1) * paulis.Y(2) qwc = BinaryHamiltonian.init_from_qubit_hamiltonian(qwc) assert not not_qwc.is_qubit_wise_commuting() assert qwc.is_qubit_wise_commuting()
def assign_generator(axis, qubits): if axis == 0: return sum(paulis.X(q) for q in qubits) if axis == 1: return sum(paulis.Y(q) for q in qubits) return sum(paulis.Z(q) for q in qubits)
def test_gradient_UX_HY_wfnsim(simulator, angle, controlled, silent=True): # same as before just with wavefunction simulation # case YX # U = cos(angle/2) + sin(-angle/2)*i*X # O = cos*sin*i*<0|YX|0> + sin*cos*(-i)<0|XY|0> # = 0.5*sin(-angle)*i <0|[YX,XY]|0> # = -sin(angle) angle_value = angle angle = Variable(name="angle") variables = {angle: angle_value} qubit = 0 H = paulis.Y(qubit=qubit) if controlled: control = 1 U = gates.X(target=control) + gates.Rx( target=qubit, control=control, angle=angle) else: U = gates.Rx(target=qubit, angle=angle) O = ExpectationValue(U=U, H=H) E = simulate(O, variables=variables, backend=simulator) dO = grad(objective=O, variable=angle) dE = simulate(dO, variables=variables) assert (numpy.isclose(E, -numpy.sin(angle(variables)), atol=0.0001)) assert (numpy.isclose(dE, -numpy.cos(angle(variables)), atol=0.0001)) if not silent: print("E =", E) print("-sin(angle)=", -numpy.sin(angle(variables))) print("dE =", dE) print("-cos(angle)=", -numpy.cos(angle(variables)))
def test_gradient_PHASE_HY(simulator, angle_value, controlled, silent=False): angle = Variable(name="angle") variables = {angle: angle_value} qubit = 0 H = paulis.Y(qubit=qubit) if controlled: control = 1 U = gates.X(target=control) + gates.H(target=qubit) + gates.Phase( target=qubit, control=control, phi=angle) + gates.H(target=qubit) else: U = gates.H(target=qubit) + gates.Phase( target=qubit, phi=angle) + gates.H(target=qubit) O = ExpectationValue(U=U, H=H) E = simulate(O, variables=variables, backend=simulator) dO = grad(objective=O, variable='angle') dE = simulate(dO, variables=variables) assert (numpy.isclose(E, -numpy.sin(angle(variables)), atol=1.e-4)) assert (numpy.isclose(dE, -numpy.cos(angle(variables)), atol=1.e-4)) if not silent: print("E =", E) print("-sin(angle)=", -numpy.sin(angle(variables))) print("dE =", dE) print("-cos(angle)=", -numpy.cos(angle(variables)))
def test_really_awfull_thing(simulator, value1=(numpy.random.randint(10, 1000) / 1000.0 * (numpy.pi / 2.0)), value2=(numpy.random.randint(10, 1000) / 1000.0 * (numpy.pi / 2.0))): angle1 = Variable(name="angle1") angle2 = Variable(name="angle2") variables = {angle1: value1, angle2: value2} prod = angle1 * angle2 qubit = 0 control = None H = paulis.Y(qubit=qubit) U = gates.Rx(target=qubit, control=control, angle=prod) Up = gates.Rx(target=qubit, control=control, angle=prod + np.pi / 2) Down = gates.Rx(target=qubit, control=control, angle=prod - np.pi / 2) e1 = ExpectationValue(U=U, H=H) en1 = simulate(e1, variables=variables, backend=simulator) uen = simulate(0.5 * ExpectationValue(Up, H), variables=variables, backend=simulator) den = simulate(-0.5 * ExpectationValue(Down, H), variables=variables, backend=simulator) an1 = -np.sin(prod(variables=variables)) anval = prod(variables=variables) an2 = angle2(variables=variables) added = angle1 * e1 raised = added.wrap(np.sin) dO = grad(raised, 'angle1') dE = grad(e1, 'angle1') dA = grad(added, 'angle1') val = simulate(added, variables=variables, backend=simulator) dave = simulate(dA, variables=variables, backend=simulator) deval = simulate(dE, variables=variables, backend=simulator) doval = simulate(dO, variables=variables, backend=simulator) dtrue = np.cos(val) * dave assert np.isclose(en1, an1, atol=1.e-4) assert np.isclose(deval, an2 * (uen + den), atol=1.e-4) assert np.isclose(doval, dtrue, atol=1.e-4)
def test_akward_expression( simulator, value1=(numpy.random.randint(0, 1000) / 1000.0 * (numpy.pi / 2.0)), value2=(numpy.random.randint(0, 1000) / 1000.0 * (numpy.pi / 2.0))): angle1 = Variable(name="angle1") angle2 = Variable(name="angle2") variables = {angle1: value1, angle2: value2} prod = angle1 * angle2 qubit = 0 control = None H = paulis.Y(qubit=qubit) U = gates.Rx(target=qubit, control=control, angle=prod) Up = gates.Rx(target=qubit, control=control, angle=prod + np.pi / 2) Down = gates.Rx(target=qubit, control=control, angle=prod - np.pi / 2) e1 = ExpectationValue(U=U, H=H) en1 = simulate(e1, variables=variables, backend=simulator) uen = simulate(0.5 * ExpectationValue(Up, H), variables=variables, backend=simulator) den = simulate(-0.5 * ExpectationValue(Down, H), variables=variables, backend=simulator) an1 = -np.sin(prod(variables=variables)) anval = prod(variables=variables) an2 = angle2(variables=variables) added = angle1 * e1 dO = grad(added, 'angle1') dE = grad(e1, 'angle1') deval = simulate(dE, variables=variables, backend=simulator) doval = simulate(dO, variables=variables, backend=simulator) dtrue = angle1(variables=variables) * deval + en1 assert np.isclose(en1, an1) assert np.isclose(deval, an2 * (uen + den), atol=1.e-4) assert np.isclose(doval, dtrue, atol=1.e-4)
def test_mixed_power( simulator, value1=(numpy.random.randint(0, 1000) / 1000.0 * (numpy.pi / 2.0)), value2=(numpy.random.randint(0, 1000) / 1000.0 * (numpy.pi / 2.0))): angle1 = Variable(name="angle1") angle2 = Variable(name="angle2") variables = {angle1: value1, angle2: value2} qubit = 0 control = 1 H1 = paulis.X(qubit=qubit) U1 = gates.X(target=control) + gates.Ry( target=qubit, control=control, angle=angle1) e1 = ExpectationValue(U=U1, H=H1) H2 = paulis.Y(qubit=qubit) U2 = gates.X(target=control) + gates.Rx( target=qubit, control=control, angle=angle2) e2 = ExpectationValue(U=U2, H=H2) added = e1**e2 val = simulate(added, variables=variables, backend=simulator) en1 = simulate(e1, variables=variables, backend=simulator) en2 = simulate(e2, variables=variables, backend=simulator) an1 = np.sin(angle1(variables=variables)) an2 = -np.sin(angle2(variables=variables)) assert np.isclose(val, en1**en2, atol=1.e-4) assert np.isclose(val, an1**an2, atol=1.e-4)
def get_generator(gate) -> paulis.QubitHamiltonian: """ get the generator of a gaussian gate as a Qubit hamiltonian. Relies on the name of the gate. Parameters ---------- gate: QGateImpl: QGateImpl object or inheritor thereof, with name corresponding to its generator in some fashion. Returns ------- QubitHamiltonian: the generator of the gate acting, on the gate's target. """ if gate.name.lower() == 'rx': gen = paulis.X(gate.target[0]) elif gate.name.lower() == 'ry': gen = paulis.Y(gate.target[0]) elif gate.name.lower() == 'rz': gen = paulis.Z(gate.target[0]) elif gate.name.lower() == 'phase': gen = paulis.Qm(gate.target[0]) else: print(gate.name.lower()) raise TequilaException( 'cant get the generator of a non Gaussian gate, you fool!') return gen
def test_rz_phase_flip_0(simulator, p, angle): qubit = 0 H = paulis.Y(qubit) U = gates.H(target=qubit) + gates.Rz(angle=Variable('a'), target=qubit) + gates.H(target=qubit) O = ExpectationValue(U=U, H=H) NM = PhaseFlip(p, 1) E = simulate(O, backend=simulator, variables={'a': angle}, samples=1000, noise=NM) assert (numpy.isclose(E, ((-1. + 2 * p) ** 3) * numpy.sin(angle), atol=1.e-1))
def test_initialization(): H = paulis.I() for i in range(10): H += paulis.pauli(qubit=numpy.random.randint(0,5,3), type=numpy.random.choice(["X", "Y", "Z"],1)) for H1 in [H, paulis.I(), paulis.Zero(), paulis.X(0), paulis.Y(1), 1.234*paulis.Z(2)]: string = str(H1) ofstring = str(H1.to_openfermion()) H2 = QubitHamiltonian.from_string(string=string) assert H1 == H2 H3 = QubitHamiltonian.from_string(string=ofstring, openfermion_format=True) assert H1 == H3
def test_commuting_groups(): ''' Testing whether the partitioning gives commuting parts ''' H, _, _, _ = prepare_test_hamiltonian() H = H + paulis.X(0) + paulis.Y(0) H = BinaryHamiltonian.init_from_qubit_hamiltonian(H) commuting_parts = H.commuting_groups() for part in commuting_parts: assert part.is_commuting()
def test_rz_phase_flip_0(simulator, p, angle): qubit = 0 H = paulis.Y(qubit) U = gates.H(target=qubit) + gates.Rz(angle=Variable('a'), target=qubit) + gates.H(target=qubit) O = ExpectationValue(U=U, H=H) NM = PhaseFlip(p, 1) E = simulate(O, backend=simulator, variables={'a': angle}, samples=1, noise=NM) print(E)
def get_generator(gate): if gate.name.lower() == 'rx': gen = paulis.X(gate.target[0]) elif gate.name.lower() == 'ry': gen = paulis.Y(gate.target[0]) elif gate.name.lower() == 'rz': gen = paulis.Z(gate.target[0]) elif gate.name.lower() == 'phase': gen = paulis.Qm(gate.target[0]) else: print(gate.name.lower()) raise TequilaException( 'cant get the generator of a non Gaussian gate, you fool!') return gen
def test_transposition(): primitives = [paulis.X, paulis.Y, paulis.Z] factors = [1, -1, 1j, -1j, 0.5 + 1j] assert ((paulis.X(0) * paulis.X(1) * paulis.Y(2)).transpose() == -1 * paulis.X(0) * paulis.X(1) * paulis.Y(2)) assert ((paulis.X(0) * paulis.X(1) * paulis.Z(2)).transpose() == paulis.X(0) * paulis.X(1) * paulis.Z(2)) for repeat in range(10): string = QubitHamiltonian.unit() tstring = QubitHamiltonian.unit() for q in range(5): ri = random.randint(0, 2) P = primitives[ri] sign = 1 if ri == 1: sign = -1 factor = factors[random.randint(0, len(factors) - 1)] string *= factor * P(qubit=q) tstring *= factor * sign * P(qubit=q) assert (string.transpose() == tstring)
def test_gradient_deep_controlled_X(simulator, power, controls): if controls > 2 and simulator == "qiskit": # does not work yet return qubit = 0 control = [i for i in range(1, controls + 1)] angle = Variable(name="angle") U = gates.X(target=control) + gates.X(target=qubit, power=angle, control=control) angle = Variable(name="angle") variables = {angle: power} H = paulis.Y(qubit=qubit) O = ExpectationValue(U=U, H=H) E = simulate(O, variables=variables, backend=simulator) dO = grad(objective=O, variable=angle) dE = simulate(dO, variables=variables, backend=simulator) assert (numpy.isclose(E, -numpy.sin(angle(variables) * (numpy.pi)), atol=1.e-4)) assert (numpy.isclose(dE, -numpy.pi * numpy.cos(angle(variables) * (numpy.pi)), atol=1.e-4))
def test_gradient_X(simulator, power, controlled): qubit = 0 control = 1 angle = Variable(name="angle") if controlled: U = gates.X(target=control) + gates.X(target=qubit, power=angle, control=control) else: U = gates.X(target=qubit, power=angle) angle = Variable(name="angle") variables = {angle: power} H = paulis.Y(qubit=qubit) O = ExpectationValue(U=U, H=H) E = simulate(O, variables=variables, backend=simulator) dO = grad(objective=O, variable=angle) dE = simulate(dO, variables=variables, backend=simulator) assert (numpy.isclose(E, -numpy.sin(angle(variables) * (numpy.pi)), atol=1.e-4)) assert (numpy.isclose(dE, -numpy.pi * numpy.cos(angle(variables) * (numpy.pi)), atol=1.e-4))
def test_heterogeneous_operations_r(simulator, op, value1=(numpy.random.randint(1, 999) / 1000.0 * (numpy.pi / 2.0)), value2=(numpy.random.randint(1, 999) / 1000.0 * (numpy.pi / 2.0))): angle1 = Variable(name="angle1") angle2 = Variable(name="angle2") variables = {angle1: value1, angle2: value2} qubit = 0 control = 1 H1 = paulis.Y(qubit=qubit) U1 = gates.X(target=control) + gates.Rx(target=qubit, control=control, angle=angle1) e1 = ExpectationValue(U=U1, H=H1) added = Objective(args=[e1.args[0], angle2], transformation=op) val = simulate(added, variables=variables, backend=simulator) en1 = simulate(e1, variables=variables, backend=simulator) an1 = -np.sin(angle1(variables=variables)) an2 = angle2(variables=variables) assert np.isclose(val, float(op(en1, an2)), atol=1.e-4) assert np.isclose(en1, an1, atol=1.e-4)
def SWAP(first: int, second: int, control: typing.Union[int, list] = None, power: float = None, *args, **kwargs) -> QCircuit: """ Notes ---------- SWAP gate, order of targets does not matter Parameters ---------- first: int target qubit second: int target qubit control int or list of ints power numeric type (fixed exponent) or hashable type (parametrized exponent) Returns ------- QCircuit """ target = [first, second] generator = 0.5 * (paulis.X(target) + paulis.Y(target) + paulis.Z(target) - paulis.I(target)) if power is None or power in [1, 1.0]: return QGate(name="SWAP", target=target, control=control, generator=generator) else: return GeneralizedRotation(angle=power * np.pi, control=control, generator=generator, eigenvalues_magnitude=0.25)
def Y(target: typing.Union[list, int], control: typing.Union[list, int] = None, power=None, angle=None, *args, **kwargs) -> QCircuit: """ Notes ---------- Pauli Y Gate Parameters ---------- target: int or list of int control int or list of int power numeric type (fixed exponent) or hashable type (parametrized exponent) angle similar to power, but will be interpreted as .. math:: U(\\text{angle})=e^{-i\\frac{angle}{2} (1-Y)} the default is angle=pi .. math:: U(\\pi) = Y If angle and power are given both, tequila will combine them Returns ------- QCircuit object """ generator = lambda q: paulis.Y(q) - paulis.I(q) return _initialize_power_gate(name="Y", power=power, angle=angle, target=target, control=control, generator=generator)
def test_heterogeneous_gradient_r_div(simulator): ### the reason we don't test float power here is that it keeps coming up NAN, because the argument is too small angle1 = Variable(name="angle1") value = (numpy.random.randint(100, 1000) / 1000.0 * (numpy.pi / 2.0)) variables = {angle1: value} qubit = 0 control = 1 H1 = paulis.Y(qubit=qubit) U1 = gates.X(target=control) + gates.Rx(target=qubit, control=control, angle=angle1) e1 = ExpectationValue(U=U1, H=H1) added = Objective(args=[e1.args[0], angle1], transformation=np.true_divide) val = simulate(added, variables=variables, backend=simulator) en1 = simulate(e1, variables=variables, backend=simulator) an1 = -np.sin(angle1(variables=variables)) anval = angle1(variables=variables) dO = grad(added, 'angle1') dE = grad(e1, 'angle1') deval = simulate(dE, variables=variables, backend=simulator) doval = simulate(dO, variables=variables, backend=simulator) dtrue = deval / anval - en1 / (anval ** 2) assert np.isclose(float(val), float(np.true_divide(en1, anval))) assert np.isclose(en1, an1, atol=1.e-4) assert np.isclose(doval, dtrue, atol=1.e-4)
def test_convenience(): i = numpy.random.randint(0, 10, 1)[0] assert paulis.X(i) + paulis.I(i) == paulis.X(i) + 1.0 assert paulis.Qp(i) == 0.5 * (1.0 + paulis.Z(i)) assert paulis.Qm(i) == 0.5 * (1.0 - paulis.Z(i)) assert paulis.Sp(i) == 0.5 * (paulis.X(i) + 1.j * paulis.Y(i)) assert paulis.Sm(i) == 0.5 * (paulis.X(i) - 1.j * paulis.Y(i)) i = numpy.random.randint(0, 10, 1)[0] assert paulis.Qp(i) == (0.5 + 0.5 * paulis.Z(i)) assert paulis.Qm(i) == (0.5 - 0.5 * paulis.Z(i)) assert paulis.Sp(i) == (0.5 * paulis.X(i) + 0.5j * paulis.Y(i)) assert paulis.Sm(i) == (0.5 * paulis.X(i) - 0.5j * paulis.Y(i)) assert -1.0 * paulis.Y(i) == -paulis.Y(i) test = paulis.Z(i) test *= -1.0 assert test == -paulis.Z(i) test = paulis.Z(i) test += 1.0 assert test == paulis.Z(i) + 1.0 test = paulis.X(i) test += paulis.Y(i + 1) assert test == paulis.X(i) + paulis.Y(i + 1) test = paulis.X(i) test -= paulis.Y(i) test += 3.0 test = -test assert test == -1.0 * (paulis.X(i) - paulis.Y(i) + 3.0) test = paulis.X([0, 1, 2, 3]) assert test == QubitHamiltonian.from_string("X(0)X(1)X(2)X(3)", False) test = paulis.Y([0, 1, 2, 3]) assert test == QubitHamiltonian.from_string("Y(0)Y(1)Y(2)Y(3)", False) test = paulis.Z([0, 1, 2, 3]) assert test == QubitHamiltonian.from_string("Z(0)Z(1)Z(2)Z(3)", False)