def test_parallel_circuit_evaluation(backend, skip_parallel): # pragma: no cover """Evaluate circuit for multiple input states.""" device = qibo.get_device() backend_name = qibo.get_backend() if skip_parallel: pytest.skip("Skipping parallel test.") if not is_parallel_supported(backend_name): pytest.skip("Skipping parallel test due to unsupported configuration.") original_threads = qibo.get_threads() qibo.set_threads(1) nqubits = 10 np.random.seed(0) c = QFT(nqubits) states = [np.random.random(2**nqubits) for i in range(5)] r1 = [] for state in states: r1.append(c(state)) r2 = parallel_execution(c, states=states, processes=2) np.testing.assert_allclose(r1, r2) qibo.set_threads(original_threads)
def test_parallel_parametrized_circuit(): """Evaluate circuit for multiple parameters.""" if 'GPU' in get_device(): # pragma: no cover pytest.skip("unsupported configuration") original_threads = get_threads() set_threads(1) nqubits = 5 nlayers = 10 c = Circuit(nqubits) for l in range(nlayers): c.add((gates.RY(q, theta=0) for q in range(nqubits))) c.add((gates.CZ(q, q + 1) for q in range(0, nqubits - 1, 2))) c.add((gates.RY(q, theta=0) for q in range(nqubits))) c.add((gates.CZ(q, q + 1) for q in range(1, nqubits - 2, 2))) c.add(gates.CZ(0, nqubits - 1)) c.add((gates.RY(q, theta=0) for q in range(nqubits))) size = len(c.get_parameters()) np.random.seed(0) parameters = [np.random.uniform(0, 2 * np.pi, size) for i in range(10)] state = None r1 = [] for params in parameters: c.set_parameters(params) r1.append(c(state)) r2 = parallel_parametrized_execution(c, parameters=parameters, initial_state=state, processes=2) np.testing.assert_allclose(r1, r2) set_threads(original_threads)
def __init__(self): """ Attributes: unitary: Unitary matrix representation of the gate in the computational basis. is_prepared: ``True`` if the gate is prepared for action to states. A gate is prepared when its matrix and/or other tensors required in the computation are calculated. See :meth:`qibo.abstractions.abstract_gates.BackendGate.prepare` for more details. Note that gate preparation is triggered automatically when a gate is added to a circuit or when it acts on a state. device: Hardware device to use in order to simulate this gate. density_matrix: ``True`` if the gate will act on density matrices, ``False`` if the gate will act on state vectors. """ Gate.__init__(self) self._matrix = None self._cache = None # Cast gate matrices to the proper device self.device = get_device() # Reference to copies of this gate that are casted in devices when # a distributed circuit is used self.device_gates = set() self.original_gate = None
def main(nqubits, nlayers, backend, varlayer=False, method="Powell", maxiter=None, filename=None): """Performs a VQE circuit minimization test.""" qibo.set_backend(backend) logs = BenchmarkLogger(filename) logs.append({ "nqubits": nqubits, "nlayers": nlayers, "varlayer": varlayer, "backend": qibo.get_backend(), "precision": qibo.get_precision(), "device": qibo.get_device(), "threads": qibo.get_threads(), "method": method, "maxiter": maxiter }) print("Number of qubits:", nqubits) print("Number of layers:", nlayers) print("Backend:", logs[-1]["backend"]) start_time = time.time() if varlayer: circuit = varlayer_circuit(nqubits, nlayers) else: circuit = standard_circuit(nqubits, nlayers) hamiltonian = hamiltonians.XXZ(nqubits=nqubits) vqe = models.VQE(circuit, hamiltonian) logs[-1]["creation_time"] = time.time() - start_time target = np.real(np.min(K.to_numpy(hamiltonian.eigenvalues()))) print("\nTarget state =", target) np.random.seed(0) nparams = 2 * nqubits * nlayers + nqubits initial_parameters = np.random.uniform(0, 2 * np.pi, nparams) start_time = time.time() options = {'disp': False, 'maxiter': maxiter} best, params, _ = vqe.minimize(initial_parameters, method=method, options=options, compile=False) logs[-1]["minimization_time"] = time.time() - start_time epsilon = np.log10(1 / np.abs(best - target)) print("Found state =", best) print("Final eps =", epsilon) logs[-1]["best_energy"] = float(best) logs[-1]["epsilon_energy"] = float(epsilon) print("\nCreation time =", logs[-1]["creation_time"]) print("Minimization time =", logs[-1]["minimization_time"]) print("Total time =", logs[-1]["minimization_time"] + logs[-1]["creation_time"]) logs.dump()
def is_parallel_supported(backend_name): # pragma: no cover if "GPU" in qibo.get_device(): return False if backend_name in ("tensorflow", "qibojit"): return False if sys.platform in ("darwin", "win32"): return False return True
def __init__(self): Gate.__init__(self) self._unitary = None # Cast gate matrices to the proper device self.device = get_device() # Reference to copies of this gate that are casted in devices when # a distributed circuit is used self.device_gates = set() self.original_gate = None
def main(nqubits, nangles, dense=True, solver="exp", method="Powell", maxiter=None, filename=None): """Performs a QAOA minimization test.""" print("Number of qubits:", nqubits) print("Number of angles:", nangles) logs = BenchmarkLogger(filename) logs.append({ "nqubits": nqubits, "nangles": nangles, "dense": dense, "solver": solver, "backend": qibo.get_backend(), "precision": qibo.get_precision(), "device": qibo.get_device(), "threads": qibo.get_threads(), "method": method, "maxiter": maxiter }) hamiltonian = hamiltonians.XXZ(nqubits=nqubits, dense=dense) start_time = time.time() qaoa = models.QAOA(hamiltonian, solver=solver) logs[-1]["creation_time"] = time.time() - start_time target = np.real(np.min(K.to_numpy(hamiltonian.eigenvalues()))) print("\nTarget state =", target) np.random.seed(0) initial_parameters = np.random.uniform(0, 0.1, nangles) start_time = time.time() options = {'disp': True, 'maxiter': maxiter} best, params, _ = qaoa.minimize(initial_parameters, method=method, options=options) logs[-1]["minimization_time"] = time.time() - start_time logs[-1]["best_energy"] = float(best) logs[-1]["target_energy"] = float(target) logs[-1]["epsilon"] = np.log10(1 / np.abs(best - target)) print("Found state =", best) print("Final eps =", logs[-1]["epsilon"]) print("\nCreation time =", logs[-1]["creation_time"]) print("Minimization time =", logs[-1]["minimization_time"]) print("Total time =", logs[-1]["creation_time"] + logs[-1]["minimization_time"]) logs.dump()
def main(nqubits, dt, solver, backend, dense=False, accelerators=None, filename=None): """Performs adiabatic evolution with critical TFIM as the "hard" Hamiltonian.""" qibo.set_backend(backend) if accelerators is not None: dense = False solver = "exp" logs = BenchmarkLogger(filename) logs.append({ "nqubits": nqubits, "dt": dt, "solver": solver, "dense": dense, "backend": qibo.get_backend(), "precision": qibo.get_precision(), "device": qibo.get_device(), "threads": qibo.get_threads(), "accelerators": accelerators }) print(f"Using {solver} solver and dt = {dt}.") print(f"Accelerators: {accelerators}") print("Backend:", logs[-1]["backend"]) start_time = time.time() h0 = hamiltonians.X(nqubits, dense=dense) h1 = hamiltonians.TFIM(nqubits, h=1.0, dense=dense) logs[-1]["hamiltonian_creation_time"] = time.time() - start_time print(f"\nnqubits = {nqubits}, solver = {solver}") print(f"dense = {dense}, accelerators = {accelerators}") print("Hamiltonians created in:", logs[-1]["hamiltonian_creation_time"]) start_time = time.time() evolution = models.AdiabaticEvolution(h0, h1, lambda t: t, dt=dt, solver=solver, accelerators=accelerators) logs[-1]["creation_time"] = time.time() - start_time print("Evolution model created in:", logs[-1]["creation_time"]) start_time = time.time() final_psi = evolution(final_time=1.0) logs[-1]["simulation_time"] = time.time() - start_time print("Simulation time:", logs[-1]["simulation_time"]) logs.dump()
def test_set_device(): """Check device switcher and errors in device name.""" import qibo original_device = qibo.get_device() qibo.set_device("/CPU:0") with pytest.raises(ValueError): qibo.set_device("test") with pytest.raises(ValueError): qibo.set_device("/TPU:0") with pytest.raises(ValueError): qibo.set_device("/gpu:10") with pytest.raises(ValueError): qibo.set_device("/GPU:10") qibo.set_device(original_device)
def test_parallel_circuit_evaluation(backend): """Evaluate circuit for multiple input states.""" device = qibo.get_device() backend = qibo.get_backend() if 'GPU' in qibo.get_device( ) or sys.platform == "win32" or sys.platform == "darwin" or backend == "tensorflow" or backend == "qibojit": # pragma: no cover pytest.skip("unsupported configuration") original_threads = qibo.get_threads() qibo.set_threads(1) nqubits = 10 np.random.seed(0) c = QFT(nqubits) states = [np.random.random(2**nqubits) for i in range(5)] r1 = [] for state in states: r1.append(c(state)) r2 = parallel_execution(c, states=states, processes=2) np.testing.assert_allclose(r1, r2) qibo.set_threads(original_threads)
def test_vqe(backend, method, options, compile, filename): """Performs a VQE circuit minimization test.""" original_backend = qibo.get_backend() original_threads = qibo.get_threads() if (method == "sgd" or compile) and backend != "matmuleinsum": pytest.skip("Skipping SGD test for unsupported backend.") qibo.set_backend(backend) if method == 'parallel_L-BFGS-B': device = qibo.get_device() if device is not None and "GPU" in device: # pragma: no cover pytest.skip("unsupported configuration") import os if os.name == 'nt': # pragma: no cover pytest.skip("Parallel L-BFGS-B not supported on Windows.") qibo.set_threads(1) nqubits = 6 layers = 4 circuit = models.Circuit(nqubits) for l in range(layers): for q in range(nqubits): circuit.add(gates.RY(q, theta=1.0)) for q in range(0, nqubits - 1, 2): circuit.add(gates.CZ(q, q + 1)) for q in range(nqubits): circuit.add(gates.RY(q, theta=1.0)) for q in range(1, nqubits - 2, 2): circuit.add(gates.CZ(q, q + 1)) circuit.add(gates.CZ(0, nqubits - 1)) for q in range(nqubits): circuit.add(gates.RY(q, theta=1.0)) hamiltonian = hamiltonians.XXZ(nqubits=nqubits) np.random.seed(0) initial_parameters = np.random.uniform(0, 2 * np.pi, 2 * nqubits * layers + nqubits) v = models.VQE(circuit, hamiltonian) best, params, _ = v.minimize(initial_parameters, method=method, options=options, compile=compile) if method == "cma": # remove `outcmaes` folder import shutil shutil.rmtree("outcmaes") if filename is not None: assert_regression_fixture(params, filename) qibo.set_backend(original_backend) qibo.set_threads(original_threads)
def test_vqe(method, options, compile, filename): """Performs a VQE circuit minimization test.""" import qibo original_backend = qibo.get_backend() if method == "sgd" or compile: qibo.set_backend("matmuleinsum") else: qibo.set_backend("custom") original_threads = get_threads() if method == 'parallel_L-BFGS-B': if 'GPU' in qibo.get_device(): # pragma: no cover pytest.skip("unsupported configuration") qibo.set_threads(1) nqubits = 6 layers = 4 circuit = Circuit(nqubits) for l in range(layers): for q in range(nqubits): circuit.add(gates.RY(q, theta=1.0)) for q in range(0, nqubits - 1, 2): circuit.add(gates.CZ(q, q + 1)) for q in range(nqubits): circuit.add(gates.RY(q, theta=1.0)) for q in range(1, nqubits - 2, 2): circuit.add(gates.CZ(q, q + 1)) circuit.add(gates.CZ(0, nqubits - 1)) for q in range(nqubits): circuit.add(gates.RY(q, theta=1.0)) hamiltonian = XXZ(nqubits=nqubits) np.random.seed(0) initial_parameters = np.random.uniform(0, 2 * np.pi, 2 * nqubits * layers + nqubits) v = VQE(circuit, hamiltonian) best, params = v.minimize(initial_parameters, method=method, options=options, compile=compile) if method == "cma": # remove `outcmaes` folder import shutil shutil.rmtree("outcmaes") if filename is not None: utils.assert_regression_fixture(params, filename) qibo.set_backend(original_backend) qibo.set_threads(original_threads)
def _check_parallel_configuration(processes): """Check if configuration is suitable for efficient parallel execution.""" import psutil from qibo import get_device from qibo.config import raise_error, get_threads, log device = get_device() if device is not None and "GPU" in device: # pragma: no cover raise_error(RuntimeError, "Parallel evaluations cannot be used with GPU.") if ((processes is not None and processes * get_threads() > psutil.cpu_count()) or (processes is None and get_threads() != 1)): # pragma: no cover log.warning( 'Please consider using a lower number of threads per process,' ' or reduce the number of processes for better performance')
def test_parallel_circuit_evaluation(): """Evaluate circuit for multiple input states.""" if 'GPU' in get_device(): # pragma: no cover pytest.skip("unsupported configuration") original_threads = get_threads() set_threads(1) nqubits = 10 np.random.seed(0) c = QFT(nqubits) states = [np.random.random(2**nqubits) for i in range(5)] r1 = [] for state in states: r1.append(c(state)) r2 = parallel_execution(c, states=states, processes=2) np.testing.assert_allclose(r1, r2) set_threads(original_threads)
def _check_parallel_configuration(processes): # pragma: no cover """Check if configuration is suitable for efficient parallel execution.""" import sys, psutil from qibo import get_device, get_backend, get_threads from qibo.config import raise_error, log device = get_device() if sys.platform == "win32" or sys.platform == 'darwin': # pragma: no cover raise_error(RuntimeError, "Parallel evaluations supported only on linux.") if get_backend() == "tensorflow": # pragma: no cover raise_error( RuntimeError, f"{get_backend()} backend does not support parallel evaluations.") if device is not None and "GPU" in device: # pragma: no cover raise_error(RuntimeError, "Parallel evaluations cannot be used with GPU.") if ((processes is not None and processes * get_threads() > psutil.cpu_count()) or (processes is None and get_threads() != 1)): # pragma: no cover log.warning( 'Please consider using a lower number of threads per process,' ' or reduce the number of processes for better performance')
def main(nqubits, type, backend="custom", precision="double", device=None, accelerators=None, nshots=None, fuse=False, compile=False, nlayers=None, gate_type=None, params={}, filename=None): """Runs benchmarks for different circuit types. Args: nqubits (int): Number of qubits in the circuit. type (str): Type of Circuit to use. See ``benchmark_models.py`` for available types. device (str): Tensorflow logical device to use for the benchmark. If ``None`` the first available device is used. accelerators (dict): Dictionary that specifies the accelarator devices for multi-GPU setups. nshots (int): Number of measurement shots. Logs the time required to sample frequencies (no samples). If ``None`` no measurements are performed. fuse (bool): If ``True`` gate fusion is used for faster circuit execution. compile: If ``True`` then the Tensorflow graph is compiled using ``circuit.compile()``. Compilation time is logged in this case. nlayers (int): Number of layers for supremacy-like or gate circuits. If a different circuit is used ``nlayers`` is ignored. gate_type (str): Type of gate for gate circuits. If a different circuit is used ``gate_type`` is ignored. params (dict): Gate parameter for gate circuits. If a non-parametrized circuit is used then ``params`` is ignored. filename (str): Name of file to write logs. If ``None`` logs will not be saved. """ qibo.set_backend(backend) qibo.set_precision(precision) if device is not None: qibo.set_device(device) if filename is not None: if os.path.isfile(filename): with open(filename, "r") as file: logs = json.load(file) print("Extending existing logs from {}.".format(filename)) else: print("Creating new logs in {}.".format(filename)) logs = [] else: logs = [] # Create log dict logs.append({ "nqubits": nqubits, "circuit_type": type, "backend": qibo.get_backend(), "precision": qibo.get_precision(), "device": qibo.get_device(), "accelerators": accelerators, "nshots": nshots, "fuse": fuse, "compile": compile }) params = {k: v for k, v in params.items() if v is not None} kwargs = {"nqubits": nqubits, "circuit_type": type} if params: kwargs["params"] = params if nlayers is not None: kwargs["nlayers"] = nlayers if gate_type is not None: kwargs["gate_type"] = gate_type if accelerators is not None: kwargs["accelerators"] = accelerators kwargs["device"] = device logs[-1].update(kwargs) start_time = time.time() circuit = circuits.CircuitFactory(**kwargs) if nshots is not None: # add measurement gates circuit.add(qibo.gates.M(*range(nqubits))) if fuse: circuit = circuit.fuse() logs[-1]["creation_time"] = time.time() - start_time if compile: start_time = time.time() circuit.compile() # Try executing here so that compile time is not included # in the simulation time result = circuit(nshots=nshots) logs[-1]["compile_time"] = time.time() - start_time start_time = time.time() result = circuit(nshots=nshots) logs[-1]["simulation_time"] = time.time() - start_time logs[-1]["dtype"] = str(result.dtype) if nshots is not None: start_time = time.time() freqs = result.frequencies() logs[-1]["measurement_time"] = time.time() - start_time print() for k, v in logs[-1].items(): print("{}: {}".format(k, v)) if filename is not None: with open(filename, "w") as file: json.dump(logs, file)
def main(nqubits, circuit_name, backend="custom", precision="double", nreps=1, nshots=None, transfer=False, fuse=False, device=None, accelerators=None, threadsafe=False, compile=False, get_branch=True, nlayers=None, gate_type=None, params={}, filename=None): """Runs circuit simulation benchmarks for different circuits. See benchmark documentation for a description of arguments. """ qibo.set_backend(backend) qibo.set_precision(precision) if device is not None: qibo.set_device(device) logs = BenchmarkLogger(filename) # Create log dict logs.append({ "nqubits": nqubits, "circuit_name": circuit_name, "threading": "", "backend": qibo.get_backend(), "precision": qibo.get_precision(), "device": qibo.get_device(), "accelerators": accelerators, "nshots": nshots, "transfer": transfer, "fuse": fuse, "compile": compile, }) if get_branch: logs[-1]["branch"] = get_active_branch_name() params = {k: v for k, v in params.items() if v is not None} kwargs = {"nqubits": nqubits, "circuit_name": circuit_name} if params: kwargs["params"] = params if nlayers is not None: kwargs["nlayers"] = nlayers if gate_type is not None: kwargs["gate_type"] = gate_type if accelerators is not None: kwargs["accelerators"] = accelerators logs[-1].update(kwargs) start_time = time.time() circuit = circuits.CircuitFactory(**kwargs) if nshots is not None: # add measurement gates circuit.add(qibo.gates.M(*range(nqubits))) if fuse: circuit = circuit.fuse() logs[-1]["creation_time"] = time.time() - start_time start_time = time.time() if compile: circuit.compile() # Try executing here so that compile time is not included # in the simulation time result = circuit(nshots=nshots) del (result) logs[-1]["compile_time"] = time.time() - start_time start_time = time.time() result = circuit(nshots=nshots) logs[-1]["dry_run_time"] = time.time() - start_time start_time = time.time() if transfer: result = result.numpy() logs[-1]["dry_run_transfer_time"] = time.time() - start_time del (result) simulation_times, transfer_times = [], [] for _ in range(nreps): start_time = time.time() result = circuit(nshots=nshots) simulation_times.append(time.time() - start_time) start_time = time.time() if transfer: result = result.numpy() transfer_times.append(time.time() - start_time) logs[-1]["dtype"] = str(result.dtype) if nshots is None: del (result) logs[-1]["simulation_times"] = simulation_times logs[-1]["transfer_times"] = transfer_times logs[-1]["simulation_times_mean"] = np.mean(simulation_times) logs[-1]["simulation_times_std"] = np.std(simulation_times) logs[-1]["transfer_times_mean"] = np.mean(transfer_times) logs[-1]["transfer_times_std"] = np.std(transfer_times) start_time = time.time() if nshots is not None: freqs = result.frequencies() logs[-1]["measurement_time"] = time.time() - start_time if logs[-1]["backend"] == "qibojit" and qibo.K.get_platform() == "numba": from numba import threading_layer logs[-1]["threading"] = threading_layer() print() print(logs) print() logs.dump()