def random_fermionic_simulation_gate(order): exponent = random_real() if order == 2: weights = (random_complex(), random_real()) return openfermion.QuadraticFermionicSimulationGate(weights, exponent=exponent) weights = random_complex(3) if order == 3: return openfermion.CubicFermionicSimulationGate(weights, exponent=exponent) if order == 4: return openfermion.QuarticFermionicSimulationGate(weights, exponent=exponent)
def test_weights_and_exponent(weights): exponents = np.linspace(-1, 1, 8) gates = tuple( openfermion.QuarticFermionicSimulationGate( weights / exponent, exponent=exponent, absorb_exponent=True) for exponent in exponents) for g1, g2 in itertools.combinations(gates, 2): assert cirq.approx_eq(g1, g2, atol=1e-100) for i, (gate, exponent) in enumerate(zip(gates, exponents)): assert gate.exponent == 1 new_exponent = exponents[-i] new_gate = gate._with_exponent(new_exponent) assert new_gate.exponent == new_exponent
def test_quartic_fermionic_simulation_unitary(weights, exponent): generator = np.zeros((1 << 4,) * 2, dtype=np.complex128) # w0 |1001><0110| + h.c. generator[9, 6] = weights[0] generator[6, 9] = weights[0].conjugate() # w1 |1010><0101| + h.c. generator[10, 5] = weights[1] generator[5, 10] = weights[1].conjugate() # w2 |1100><0011| + h.c. generator[12, 3] = weights[2] generator[3, 12] = weights[2].conjugate() expected_unitary = la.expm(-1j * exponent * generator) gate = openfermion.QuarticFermionicSimulationGate(weights, exponent=exponent) actual_unitary = cirq.unitary(gate) assert np.allclose(expected_unitary, actual_unitary)
def test_quartic_fermionic_simulation_gate_text_diagram(): gate = openfermion.QuarticFermionicSimulationGate((1, 1, 1)) qubits = cirq.LineQubit.range(6) circuit = cirq.Circuit([gate(*qubits[:4]), gate(*qubits[-4:])]) assert super(type(gate), gate).wire_symbol(False) == type(gate).__name__ for G in (gate, gate._with_exponent('e')): assert (super(type(G), G)._diagram_exponent( cirq.CircuitDiagramInfoArgs.UNINFORMED_DEFAULT) == G._exponent) expected_text_diagram = """ 0: ───⇊⇈(1, 1, 1)───────────────── │ 1: ───⇊⇈────────────────────────── │ 2: ───⇊⇈────────────⇊⇈(1, 1, 1)─── │ │ 3: ───⇊⇈────────────⇊⇈──────────── │ 4: ─────────────────⇊⇈──────────── │ 5: ─────────────────⇊⇈──────────── """.strip() cirq.testing.assert_has_diagram(circuit, expected_text_diagram) expected_text_diagram = """ 0: ---a*a*aa(1, 1, 1)--------------------- | 1: ---a*a*aa------------------------------ | 2: ---a*a*aa------------a*a*aa(1, 1, 1)--- | | 3: ---a*a*aa------------a*a*aa------------ | 4: ---------------------a*a*aa------------ | 5: ---------------------a*a*aa------------ """.strip() cirq.testing.assert_has_diagram(circuit, expected_text_diagram, use_unicode_characters=False)
def test_quartic_fermionic_simulation_eq(): eq = cirq.testing.EqualsTester() eq.add_equality_group( openfermion.QuarticFermionicSimulationGate((1.2, 0.4, -0.4), exponent=0.5), openfermion.QuarticFermionicSimulationGate((0.3, 0.1, -0.1), exponent=2), openfermion.QuarticFermionicSimulationGate((-0.6, -0.2, 0.2), exponent=-1), openfermion.QuarticFermionicSimulationGate((0.6, 0.2, 2 * np.pi - 0.2)), ) eq.add_equality_group( openfermion.QuarticFermionicSimulationGate((-0.6, 0.0, 0.3), exponent=0.5)) eq.make_equality_group(lambda: openfermion.QuarticFermionicSimulationGate( (0.1, -0.3, 0.0), exponent=0.0)) eq.make_equality_group(lambda: openfermion.QuarticFermionicSimulationGate( (1., -1., 0.5), exponent=0.75))
def test_quartic_fermionic_simulation_apply_unitary(weights, exponent): gate = openfermion.QuarticFermionicSimulationGate(weights, exponent=exponent) cirq.testing.assert_has_consistent_apply_unitary(gate, atol=5e-6)
def test_quartic_fermionic_simulation_decompose(weights): cirq.testing.assert_decompose_is_consistent_with_unitary( openfermion.QuarticFermionicSimulationGate(weights))
def test_quartic_fermionic_simulation_consistency(): openfermion.testing.assert_implements_consistent_protocols( openfermion.QuarticFermionicSimulationGate())
other_interaction_op = super(type(gate), gate).interaction_operator_generator() other_interaction_op = openfermion.normal_ordered(interaction_op) assert interaction_op == other_interaction_op random_quadratic_gates = [random_fermionic_simulation_gate(2) for _ in range(5)] manual_quadratic_gates = [ openfermion.QuadraticFermionicSimulationGate(weights) for weights in [cast(Tuple[float, float], (1, 1)), (1, 0), (0, 1), (0, 0)] ] quadratic_gates = random_quadratic_gates + manual_quadratic_gates cubic_gates = ([openfermion.CubicFermionicSimulationGate()] + [random_fermionic_simulation_gate(3) for _ in range(5)]) quartic_gates = ([openfermion.QuarticFermionicSimulationGate()] + [random_fermionic_simulation_gate(4) for _ in range(5)]) gates = quadratic_gates + cubic_gates + quartic_gates @pytest.mark.parametrize('gate', gates) def test_fermionic_simulation_gate(gate): openfermion.testing.assert_implements_consistent_protocols(gate) generator = gate.qubit_generator_matrix expected_unitary = la.expm(-1j * gate.exponent * generator) actual_unitary = cirq.unitary(gate) assert np.allclose(expected_unitary, actual_unitary) assert_fswap_consistent(gate) assert_permute_consistent(gate)