test: add conftest and first observable test
This commit is contained in:
66
tests/conftest.py
Normal file
66
tests/conftest.py
Normal file
@@ -0,0 +1,66 @@
|
||||
"""conftest.py.
|
||||
|
||||
Pytest fixtures.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
# backends to be tested
|
||||
# TODO: add cutensornet and quimb here as well
|
||||
BACKENDS = ["qmatchatea"]
|
||||
|
||||
|
||||
def get_backend(backend_name):
|
||||
|
||||
from qibotn.backends.qmatchatea import QMatchaTeaBackend
|
||||
|
||||
NAME2BACKEND = {
|
||||
"qmatchatea": QMatchaTeaBackend,
|
||||
}
|
||||
|
||||
return NAME2BACKEND[backend_name]()
|
||||
|
||||
|
||||
AVAILABLE_BACKENDS = []
|
||||
for backend_name in BACKENDS:
|
||||
try:
|
||||
_backend = get_backend(backend_name)
|
||||
AVAILABLE_BACKENDS.append(backend_name)
|
||||
except (ModuleNotFoundError, ImportError):
|
||||
pass
|
||||
|
||||
|
||||
def pytest_runtest_setup(item):
|
||||
ALL = {"darwin", "linux"}
|
||||
supported_platforms = ALL.intersection(mark.name for mark in item.iter_markers())
|
||||
plat = sys.platform
|
||||
if supported_platforms and plat not in supported_platforms: # pragma: no cover
|
||||
# case not covered by workflows
|
||||
pytest.skip(f"Cannot run test on platform {plat}.")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def backend(backend_name):
|
||||
yield get_backend(backend_name)
|
||||
|
||||
|
||||
def pytest_runtest_setup(item):
|
||||
ALL = {"darwin", "linux"}
|
||||
supported_platforms = ALL.intersection(mark.name for mark in item.iter_markers())
|
||||
plat = sys.platform
|
||||
if supported_platforms and plat not in supported_platforms: # pragma: no cover
|
||||
# case not covered by workflows
|
||||
pytest.skip(f"Cannot run test on platform {plat}.")
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
config.addinivalue_line("markers", "linux: mark test to run only on linux")
|
||||
|
||||
|
||||
def pytest_generate_tests(metafunc):
|
||||
module_name = metafunc.module.__name__
|
||||
|
||||
if "backend_name" in metafunc.fixturenames:
|
||||
metafunc.parametrize("backend_name", AVAILABLE_BACKENDS)
|
||||
47
tests/test_observables.py
Normal file
47
tests/test_observables.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import math
|
||||
import random
|
||||
|
||||
import pytest
|
||||
from qibo import Circuit, construct_backend, gates, hamiltonians
|
||||
from qibo.symbols import X, Z
|
||||
|
||||
|
||||
def build_observable(nqubits):
|
||||
"""Helper function to construct a target observable."""
|
||||
hamiltonian_form = 0
|
||||
for i in range(nqubits):
|
||||
hamiltonian_form += 0.5 * X(i % nqubits) * Z((i + 1) % nqubits)
|
||||
|
||||
hamiltonian = hamiltonians.SymbolicHamiltonian(form=hamiltonian_form)
|
||||
return hamiltonian, hamiltonian_form
|
||||
|
||||
|
||||
def build_circuit(nqubits, nlayers, seed=42):
|
||||
"""Helper function to construct a layered quantum circuit."""
|
||||
random.seed(seed)
|
||||
|
||||
circ = Circuit(nqubits)
|
||||
for _ in range(nlayers):
|
||||
for q in range(nqubits):
|
||||
circ.add(gates.RY(q=q, theta=random.uniform(-math.pi, math.pi)))
|
||||
circ.add(gates.RZ(q=q, theta=random.uniform(-math.pi, math.pi)))
|
||||
[circ.add(gates.CNOT(q % nqubits, (q + 1) % nqubits) for q in range(nqubits))]
|
||||
circ.add(gates.M(*range(nqubits)))
|
||||
return circ
|
||||
|
||||
|
||||
@pytest.mark.parametrize("nqubits", [2, 5, 10])
|
||||
def test_observable_expval(backend, nqubits):
|
||||
numpy_backend = construct_backend("numpy")
|
||||
ham, ham_form = build_observable(nqubits)
|
||||
circ = build_circuit(nqubits=nqubits, nlayers=1)
|
||||
|
||||
exact_expval = numpy_backend.calculate_expectation_state(
|
||||
hamiltonian=ham,
|
||||
state=circ().state(),
|
||||
normalize=False,
|
||||
)
|
||||
|
||||
tn_expval = backend.expectation(circuit=circ, observable=ham_form)
|
||||
|
||||
assert math.isclose(exact_expval, tn_expval, abs_tol=1e-7)
|
||||
Reference in New Issue
Block a user