Skip to content

Commit

Permalink
added many tests
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesB-1qbit committed Dec 3, 2021
1 parent 104bd45 commit eedd108
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 17 deletions.
2 changes: 1 addition & 1 deletion tangelo/linq/gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def check_qubit_indices(qubit_list, label):
"""
errmsg = ""
for ind in qubit_list:
if (ind < 0) or (type(ind) != int):
if (type(ind) != int) or (ind < 0):
errmsg += f"\n {label} qubit index {ind} is not a non-negative integer"

if errmsg:
Expand Down
18 changes: 9 additions & 9 deletions tangelo/linq/tests/test_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,16 @@
circuit4 = Circuit([Gate("RZ", 0, parameter=2.)], n_qubits=2)
# Circuit that tests all gates that are supported on all simulators
init_gates = [Gate('H', 0), Gate('X', 1), Gate('H', 2)]
ONE_QUBIT_GATES = ["H", "X", "Y", "Z", "S", "T", "RX", "RY", "RZ", "PHASE"]
all_one_qubit_gates = [Gate(name, target=0) if name not in PARAMETERIZED_GATES else Gate(name, target=0, parameter=0.5)
for name in ONE_QUBIT_GATES]
all_one_qubit_gates += [Gate(name, target=1) if name not in PARAMETERIZED_GATES else Gate(name, target=1, parameter=0.2)
for name in ONE_QUBIT_GATES]
TWO_QUBIT_GATES = ["CNOT", "CH", "CX", "CY", "CZ", "CRX", "CRY", "CRZ", "CPHASE"]
all_two_qubit_gates = [Gate(name, target=1, control=0) if name not in PARAMETERIZED_GATES
else Gate(name, target=1, control=0, parameter=0.5) for name in TWO_QUBIT_GATES]
one_qubit_gate_names = ["H", "X", "Y", "Z", "S", "T", "RX", "RY", "RZ", "PHASE"]
one_qubit_gates = [Gate(name, target=0) if name not in PARAMETERIZED_GATES else Gate(name, target=0, parameter=0.5)
for name in one_qubit_gate_names]
one_qubit_gates += [Gate(name, target=1) if name not in PARAMETERIZED_GATES else Gate(name, target=1, parameter=0.2)
for name in one_qubit_gate_names]
two_qubit_gate_names = ["CNOT", "CH", "CX", "CY", "CZ", "CRX", "CRY", "CRZ", "CPHASE"]
two_qubit_gates = [Gate(name, target=1, control=0) if name not in PARAMETERIZED_GATES
else Gate(name, target=1, control=0, parameter=0.5) for name in two_qubit_gate_names]
swap_gates = [Gate('SWAP', target=[1, 0]), Gate('CSWAP', target=[1, 2], control=0)]
circuit5 = Circuit(init_gates + all_one_qubit_gates + all_two_qubit_gates + swap_gates)
circuit5 = Circuit(init_gates + one_qubit_gates + two_qubit_gates + swap_gates)
# Circuit preparing a mixed-state (e.g containing a MEASURE instruction in the middle of the circuit)
circuit_mixed = Circuit([Gate("RX", 0, parameter=2.), Gate("RY", 1, parameter=-1.), Gate("MEASURE", 0), Gate("X", 0)])

Expand Down
55 changes: 51 additions & 4 deletions tangelo/linq/tests/test_translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import numpy as np

from tangelo.linq import Gate, Circuit
from tangelo.linq.gate import PARAMETERIZED_GATES
import tangelo.linq.translator as translator
from tangelo.helpers.utils import installed_backends

Expand All @@ -31,8 +32,26 @@
abs_circ = Circuit(gates) + Circuit([Gate("RX", 1, parameter=2.)])
multi_controlled_gates = [Gate("X", 0), Gate("X", 1), Gate("CX", target=2, control=[0, 1])]
abs_multi_circ = Circuit(multi_controlled_gates)
init_gates = [Gate('H', 0), Gate('X', 1), Gate('H', 2)]
one_qubit_gate_names = ["H", "X", "Y", "Z", "S", "T", "RX", "RY", "RZ", "PHASE"]
one_qubit_gates = [Gate(name, target=0) if name not in PARAMETERIZED_GATES else Gate(name, target=0, parameter=0.5)
for name in one_qubit_gate_names]
one_qubit_gates += [Gate(name, target=1) if name not in PARAMETERIZED_GATES else Gate(name, target=1, parameter=0.2)
for name in one_qubit_gate_names]
two_qubit_gate_names = ["CNOT", "CX", "CY", "CZ", "CPHASE", "CRZ"]
two_qubit_gates = [Gate(name, target=1, control=0) if name not in PARAMETERIZED_GATES
else Gate(name, target=1, control=0, parameter=0.5) for name in two_qubit_gate_names]
swap_gates = [Gate('SWAP', target=[1, 0]), Gate('CSWAP', target=[1, 2], control=0)]
big_circuit = Circuit(init_gates + one_qubit_gates + two_qubit_gates + swap_gates + [Gate('XX', [0, 1], parameter=0.5)])

references = [0., 0.38205142 ** 2, 0., 0.59500984 ** 2, 0., 0.38205142 ** 2, 0., 0.59500984 ** 2]
references_multi = [0., 0., 0., 0., 0., 0., 0., 1.]
reference_big_lsq = [-0.29022980 + 0.20684454j, -0.34400320 + 0.12534970j, 0.21316957 + 0.23442923j,
0.15939614 + 0.15293439j, -0.36723378 + 0.29031223j, -0.04807413 + 0.0797184j,
-0.37427732 + 0.41885117j, -0.05511766 + 0.20825736j]
reference_big_msq = [-0.29022979 + 0.20684454j, -0.36723376 + 0.29031221j, 0.21316958 + 0.23442923j,
-0.37427729 + 0.41885117j, -0.34400321 + 0.12534970j, -0.04807414 + 0.07971841j,
0.15939615 + 0.15293440j, -0.05511766 + 0.20825737j]

abs_circ_mixed = Circuit(gates) + Circuit([Gate("RX", 1, parameter=1.5), Gate("MEASURE", 0)])

Expand Down Expand Up @@ -95,6 +114,14 @@ def test_qulacs(self):
# Assert that both simulations returned the same state vector
np.testing.assert_array_equal(state1.get_vector(), state2.get_vector())

# Test that the translated circuit reports the same result for all cross-supported gates
translated_circuit = translator.translate_qulacs(big_circuit)

# Run the simulation
state1 = qulacs.QuantumState(big_circuit.width)
translated_circuit.update_quantum_state(state1)
np.testing.assert_array_almost_equal(state1.get_vector(), reference_big_msq, decimal=6)

@unittest.skipIf("qiskit" not in installed_backends, "Test Skipped: Backend not available \n")
def test_qiskit(self):
"""
Expand All @@ -118,10 +145,10 @@ def test_qiskit(self):

# Simulate both circuits, assert state vectors are equal
qiskit_simulator = qiskit.Aer.get_backend("aer_simulator", method='statevector')
save_state_circuit = qiskit.QuantumCircuit(abs_circ.width, abs_circ.width)
save_state_circuit.save_statevector()
translated_circuit = translated_circuit.compose(save_state_circuit)
circ = circ.compose(save_state_circuit)
translated_circuit = qiskit.transpile(translated_circuit, qiskit_simulator)
circ = qiskit.transpile(circ, qiskit_simulator)
translated_circuit.save_statevector()
circ.save_statevector()

sim_results = qiskit_simulator.run(translated_circuit).result()
v1 = sim_results.get_statevector(translated_circuit)
Expand All @@ -134,6 +161,15 @@ def test_qiskit(self):
# Return error when attempting to use qiskit with multiple controls
self.assertRaises(ValueError, translator.translate_qiskit, abs_multi_circ)

# Generate the qiskit circuit by translating from the abstract one and print it
translated_circuit = translator.translate_qiskit(big_circuit)
# Simulate both circuits, assert state vectors are equal
qiskit_simulator = qiskit.Aer.get_backend("aer_simulator", method='statevector')
translated_circuit = qiskit.transpile(translated_circuit, qiskit_simulator)
translated_circuit.save_statevector()
sim_results = qiskit_simulator.run(translated_circuit).result()
np.testing.assert_array_almost_equal(sim_results.get_statevector(translated_circuit), reference_big_msq, decimal=6)

@unittest.skipIf("cirq" not in installed_backends, "Test Skipped: Backend not available \n")
def test_cirq(self):
"""
Expand Down Expand Up @@ -183,6 +219,11 @@ def test_cirq(self):

np.testing.assert_array_equal(v1, v2)

# Test that translated circuit is correct for all cross-supported gates
translated_circuit = translator.translate_cirq(big_circuit)
job_sim = cirq_simulator.simulate(translated_circuit)
np.testing.assert_array_almost_equal(job_sim.final_state_vector, reference_big_lsq, decimal=6)

@unittest.skipIf("qdk" not in installed_backends, "Test Skipped: Backend not available \n")
def test_qdk(self):
""" Compares the frequencies computed by the QDK/Q# shot-based simulator to the theoretical ones """
Expand Down Expand Up @@ -369,6 +410,12 @@ def test_braket(self):
# Return error when attempting to use braket with multiple controls
self.assertRaises(ValueError, translator.translate_braket, abs_multi_circ)

# Test that circuit is correct for all cross-supported gates
translated_circuit = translator.translate_braket(big_circuit)
translated_circuit.state_vector()
translated_result = device.run(translated_circuit, shots=0).result()
np.testing.assert_array_almost_equal(translated_result.values[0], reference_big_lsq, decimal=6)

@unittest.skipIf("qiskit" not in installed_backends, "Test Skipped: Backend not available \n")
def test_unsupported_gate(self):
""" Must return an error if a gate is not supported for the target backend """
Expand Down
4 changes: 2 additions & 2 deletions tangelo/linq/translator/translate_cirq.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ def translate_cirq(source_circuit, noise_model=None):
next_gate = GATE_CIRQ[gate.name](gate.parameter).controlled(num_controls)
target_circuit.append(next_gate(*control_list, qubit_list[gate.target[0]]))
elif gate.name in {"XX"}:
next_gate = GATE_CIRQ[gate.name](exponent=gate.parameter/pi)
target_circuit.append(next_gate(qubit_list[gate.target[0]], qubit_list[gate.target1[0]]))
next_gate = GATE_CIRQ[gate.name](exponent=gate.parameter/pi, global_shift=-0.5)
target_circuit.append(next_gate(qubit_list[gate.target[0]], qubit_list[gate.target[1]]))
elif gate.name in {"PHASE"}:
next_gate = GATE_CIRQ[gate.name](exponent=gate.parameter/pi)
target_circuit.append(next_gate(qubit_list[gate.target[0]]))
Expand Down
11 changes: 10 additions & 1 deletion tangelo/linq/translator/translate_qulacs.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
- how the order and conventions for some of the inputs to the gate operations
may also differ.
"""
from numpy import exp
from numpy import exp, cos, sin


def get_qulacs_gates():
Expand Down Expand Up @@ -51,6 +51,7 @@ def get_qulacs_gates():
GATE_QULACS["CRZ"] = qulacs.gate.RZ
GATE_QULACS["PHASE"] = qulacs.gate.DenseMatrix
GATE_QULACS["CPHASE"] = qulacs.gate.DenseMatrix
GATE_QULACS["XX"] = qulacs.gate.DenseMatrix
GATE_QULACS["SWAP"] = qulacs.QuantumCircuit.add_SWAP_gate
GATE_QULACS["CSWAP"] = qulacs.gate.SWAP
GATE_QULACS["MEASURE"] = qulacs.gate.Measurement
Expand Down Expand Up @@ -109,6 +110,14 @@ def translate_qulacs(source_circuit, noise_model=None):
for c in gate.control:
mat_gate.add_control_qubit(c, 1)
target_circuit.add_gate(mat_gate)
elif gate.name in {"XX"}:
c = cos(gate.parameter/2)
s = -1j * sin(gate.parameter/2)
mat_gate = GATE_QULACS[gate.name]([gate.target[0], gate.target[1]], [[c, 0, 0, s],
[0, c, s, 0],
[0, s, c, 0],
[s, 0, 0, c]])
target_circuit.add_gate(mat_gate)
elif gate.name in {"CNOT"}:
(GATE_QULACS[gate.name])(target_circuit, gate.control[0], gate.target[0])
elif gate.name in {"MEASURE"}:
Expand Down

0 comments on commit eedd108

Please sign in to comment.