Open BrunoLiegiBastonLiegi opened 1 month ago
Just to complement on this, I would like to summarize here the list of methods that are called through the self.np.method
or backend.np.method
pattern and that, therefore, are candidate to be converted to explicit methods of the Backend
.
Right now we support several backends, some inside
qibo
and others outside of it:qibojit
,qibo-cloud
,qiboml
,qibolab
... However it is nowhere defined what exactly each backend should provide to be compatible with the rest of theqibo
API, for instance thequantum_info
module. At the moment we rely on theself.np
orbackend.np
trick to trigger the "engine" of each separate backend. However this is neither consistent across the backends,PyTorchBackend
hasself.np = torch
whereasTensorflowBackend
hasself.tf = tf
andself.np = tf.experimental.numpy
orCupyBackend
hasself.np = numpy
andself.cp = cupy
, nor is enough to cover all the needed cases. A quick search withgit grep "if backend"
shows several situations in which we need to explicitely check which backend is used and act accordingly:git grep "if backend"
``` src/qibo/backends/__init__.py: if backend == "numpy": src/qibo/backends/__init__.py: elif backend == "tensorflow": src/qibo/backends/__init__.py: elif backend == "pytorch": src/qibo/backends/__init__.py: elif backend == "clifford": src/qibo/backends/__init__.py: elif backend == "qulacs": src/qibo/backends/__init__.py: if backend: # pragma: no cover src/qibo/backends/__init__.py: if backend is None: src/qibo/backends/__init__.py: if backend in QIBO_NATIVE_BACKENDS + ("clifford",): src/qibo/backends/__init__.py: if backend.__class__.__name__ in [ src/qibo/backends/clifford.py: return backend.platform if backend.platform is not None else backend.name src/qibo/models/error_mitigation.py: if backend.name == "pytorch": src/qibo/models/error_mitigation.py: if backend.name == "pytorch": src/qibo/models/error_mitigation.py: if backend.name == "pytorch": src/qibo/models/error_mitigation.py: if backend is None: # pragma: no cover src/qibo/models/error_mitigation.py: elif backend.name == "qibolab": # pragma: no cover src/qibo/optimizers.py: if backend.name == "tensorflow": src/qibo/optimizers.py: if backend.name == "pytorch": src/qibo/quantum_info/metrics.py: if backend.np.real(eig) > PRECISION_TOL: src/qibo/quantum_info/quantum_networks.py: if backend is None: # pragma: no cover src/qibo/quantum_info/quantum_networks.py: if backend is None: # pragma: no cover src/qibo/quantum_info/quantum_networks.py: if backend is None: # pragma: no cover src/qibo/quantum_info/random_ensembles.py: if backend.name == "tensorflow": src/qibo/quantum_info/superoperator_transformations.py: if backend.np.abs(eig) > precision_tol: src/qibo/quantum_info/utils.py: if backend.np.abs(backend.np.sum(prob_dist_p) - 1.0) > PRECISION_TOL: src/qibo/quantum_info/utils.py: if backend.np.abs(backend.np.sum(prob_dist_q) - 1.0) > PRECISION_TOL: src/qibo/quantum_info/utils.py: if backend.np.abs(backend.np.sum(prob_dist_p) - 1.0) > PRECISION_TOL: src/qibo/quantum_info/utils.py: if backend.np.abs(backend.np.sum(prob_dist_q) - 1.0) > PRECISION_TOL: src/qibo/tomography/gate_set_tomography.py: if backend.name == "qibolab" and transpiler is None: # pragma: no cover src/qibo/transpiler/unitary_decompositions.py: if backend.__class__.__name__ in [ src/qibo/transpiler/unitary_decompositions.py: if backend.__class__.__name__ != "PyTorchBackend": src/qibo/transpiler/unitary_decompositions.py: if backend.__class__.__name__ == "TensorflowBackend": src/qibo/transpiler/unitary_decompositions.py: if backend.__class__.__name__ == "TensorflowBackend": tests/test_backends_clifford.py: GlobalBackend().name if backend.name == "numpy" else GlobalBackend().platform tests/test_hamiltonians.py: if backend.name == "tensorflow": tests/test_hamiltonians.py: elif backend.name == "pytorch": tests/test_hamiltonians.py: if backend.name == "tensorflow": tests/test_hamiltonians.py: elif backend.name == "pytorch": tests/test_hamiltonians.py: if backend.name == "pytorch": tests/test_hamiltonians.py: if backend.name == "tensorflow" and sparse_type is not None: tests/test_hamiltonians.py: if backend.name == "tensorflow": tests/test_hamiltonians.py: elif backend.name == "pytorch": tests/test_hamiltonians.py: if backend.name == "tensorflow": tests/test_hamiltonians.py: elif backend.name == "pytorch": tests/test_hamiltonians.py: if backend.name == "tensorflow": tests/test_hamiltonians.py: elif backend.name == "pytorch": tests/test_hamiltonians.py: if backend.name == "tensorflow": tests/test_hamiltonians.py: elif backend.name == "pytorch": tests/test_hamiltonians.py: if backend.name == "tensorflow": tests/test_hamiltonians.py: elif backend.name == "pytorch": tests/test_measurements_collapse.py: if backend.name == "tensorflow": tests/test_models_circuit_features.py: if backend.__class__.__name__ == "TensorflowBackend": tests/test_models_circuit_features.py: elif backend.__class__.__name__ == "PyTorchBackend": tests/test_models_error_mitigation.py: if backend.name == "tensorflow": tests/test_models_error_mitigation.py: if backend.name == "tensorflow": tests/test_models_error_mitigation.py: if backend.name == "tensorflow": tests/test_models_error_mitigation.py: if backend.name == "tensorflow": tests/test_models_error_mitigation.py: if backend.name == "tensorflow": tests/test_models_evolution.py: if backend.name != "tensorflow": tests/test_models_qft.py: if backend is not None: tests/test_models_variational.py: if backend.name == "pytorch": tests/test_models_variational.py: if backend.name == "pytorch": tests/test_quantum_info_clifford.py: if backend.__class__.__name__ == "TensorflowBackend": tests/test_quantum_info_clifford.py: elif backend.__class__.__name__ == "PyTorchBackend": tests/test_quantum_info_entropies.py: if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: tests/test_quantum_info_entropies.py: if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: tests/test_quantum_info_entropies.py: if backend.__class__.__name__ == "CupyBackend": tests/test_quantum_info_random.py: if backend.name == "pytorch" tests/test_transpiler_decompositions.py: if backend.np.allclose( tests/test_transpiler_unitary_decompositions.py: if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: tests/test_transpiler_unitary_decompositions.py: if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: tests/test_transpiler_unitary_decompositions.py: if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: tests/test_transpiler_unitary_decompositions.py: if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: tests/test_transpiler_unitary_decompositions.py: if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: tests/test_transpiler_unitary_decompositions.py: if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: tests/test_transpiler_unitary_decompositions.py: if backend.__class__.__name__ in ["CupyBackend", "CuQuantumBackend"]: tests/utils.py: if backend.name == "tensorflow": ```which is not a sustainable strategy with the inclusion of more and more backends. Especially, an external backend provider should be able to know which operations the backend has to support to have a reasonable "guarantee" of being compatible with
qibo
.I think, therefore, that we should compile a list of necessary functionalities, i.e. backend methods, that every backend has to expose to grant compatibility.