def test_ugates_cirq(): c1 = Circuit(3) c1.add(gates.RX(0, 0.1)) c1.add(gates.RZ(1, 0.4)) c1.add(gates.U2(2, 0.5, 0.6)) final_state_c1 = c1() c2 = circuit_from_qasm(c1.to_qasm()) c2depth = len(cirq.Circuit(c2.all_operations())) assert c1.depth == c2depth final_state_c2 = cirq.Simulator().simulate(c2).final_state np.testing.assert_allclose(final_state_c1, final_state_c2, atol=_atol) c3 = Circuit.from_qasm(c2.to_qasm()) assert c3.depth == c2depth final_state_c3 = c3() np.testing.assert_allclose(final_state_c3, final_state_c2, atol=_atol) c1 = Circuit(3) c1.add(gates.RX(0, 0.1)) c1.add(gates.RZ(1, 0.4)) c1.add(gates.U2(2, 0.5, 0.6)) c1.add(gates.CU3(2, 1, 0.2, 0.3, 0.4)) # catches unknown gate "cu3" with pytest.raises(exception.QasmException): c2 = circuit_from_qasm(c1.to_qasm())
def test_set_parameters_with_gate_fusion(backend, accelerators): """Check updating parameters of fused circuit.""" original_backend = qibo.get_backend() qibo.set_backend(backend) params = np.random.random(9) c = Circuit(5, accelerators) c.add(gates.RX(0, theta=params[0])) c.add(gates.RY(1, theta=params[1])) c.add(gates.CZ(0, 1)) c.add(gates.RX(2, theta=params[2])) c.add(gates.RY(3, theta=params[3])) c.add(gates.fSim(2, 3, theta=params[4], phi=params[5])) c.add(gates.RX(4, theta=params[6])) c.add(gates.RZ(0, theta=params[7])) c.add(gates.RZ(1, theta=params[8])) fused_c = c.fuse() np.testing.assert_allclose(c(), fused_c()) new_params = np.random.random(9) new_params_list = list(new_params[:4]) new_params_list.append((new_params[4], new_params[5])) new_params_list.extend(new_params[6:]) c.set_parameters(new_params_list) fused_c.set_parameters(new_params_list) np.testing.assert_allclose(c(), fused_c()) qibo.set_backend(original_backend)
def test_ugates_cirq(backend): import qibo original_backend = qibo.get_backend() qibo.set_backend(backend) c1 = Circuit(3) c1.add(gates.RX(0, 0.1)) c1.add(gates.RZ(1, 0.4)) c1.add(gates.U2(2, 0.5, 0.6)) final_state_c1 = c1() c2 = circuit_from_qasm(c1.to_qasm()) c2depth = len(cirq.Circuit(c2.all_operations())) assert c1.depth == c2depth final_state_c2 = cirq.Simulator().simulate(c2).final_state_vector # pylint: disable=no-member np.testing.assert_allclose(final_state_c1, final_state_c2, atol=_atol) c3 = Circuit.from_qasm(c2.to_qasm()) assert c3.depth == c2depth final_state_c3 = c3() np.testing.assert_allclose(final_state_c3, final_state_c2, atol=_atol) c1 = Circuit(3) c1.add(gates.RX(0, 0.1)) c1.add(gates.RZ(1, 0.4)) c1.add(gates.U2(2, 0.5, 0.6)) c1.add(gates.CU3(2, 1, 0.2, 0.3, 0.4)) # catches unknown gate "cu3" with pytest.raises(exception.QasmException): c2 = circuit_from_qasm(c1.to_qasm()) qibo.set_backend(original_backend)
def test_circuit_set_parameters_with_dictionary(backend, accelerators): """Check updating parameters of circuit with list.""" original_backend = qibo.get_backend() qibo.set_backend(backend) c = Circuit(3, accelerators) c.add(gates.X(0)) c.add(gates.X(2)) c.add(gates.U1(0, theta=0)) c.add(gates.RZ(1, theta=0)) c.add(gates.CZ(1, 2)) c.add(gates.CU1(0, 2, theta=0)) c.add(gates.H(2)) c.add(gates.Unitary(np.eye(2), 1)) final_state = c() params = [0.123, 0.456, 0.789, np.random.random((2, 2))] target_c = Circuit(3, accelerators) target_c.add(gates.X(0)) target_c.add(gates.X(2)) target_c.add(gates.U1(0, theta=params[0])) target_c.add(gates.RZ(1, theta=params[1])) target_c.add(gates.CZ(1, 2)) target_c.add(gates.CU1(0, 2, theta=params[2])) target_c.add(gates.H(2)) target_c.add(gates.Unitary(params[3], 1)) param_dict = {c.queue[i]: p for i, p in zip([2, 3, 5, 7], params)} c.set_parameters(param_dict) np.testing.assert_allclose(c(), target_c()) qibo.set_backend(original_backend)
def ansatz_Fourier_2D(layers, qubits=1): """ 3 parameters per layer: Ry(wx + a), Rz(b) """ circuit = models.Circuit(qubits) for _ in range(layers): circuit.add(gates.RY(0, theta=0)) circuit.add(gates.RZ(0, theta=0)) circuit.add(gates.RY(0, theta=0)) circuit.add(gates.RZ(0, theta=0)) def rotation(theta, x): p = circuit.get_parameters() i = 0 j = 0 for l in range(layers): p[i] = theta[j] p[i + 1] = theta[j + 1] + theta[j + 2:j + 4] @ x p[i + 2] = theta[j + 4] p[i + 3] = theta[j + 5] i += 4 j += 6 return p nparams = 6 * (layers) return circuit, rotation, nparams
def test_set_parameters_with_gate_fusion(backend, trainable): """Check updating parameters of fused circuit.""" params = np.random.random(9) c = Circuit(5) c.add(gates.RX(0, theta=params[0], trainable=trainable)) c.add(gates.RY(1, theta=params[1])) c.add(gates.CZ(0, 1)) c.add(gates.RX(2, theta=params[2])) c.add(gates.RY(3, theta=params[3], trainable=trainable)) c.add(gates.fSim(2, 3, theta=params[4], phi=params[5])) c.add(gates.RX(4, theta=params[6])) c.add(gates.RZ(0, theta=params[7], trainable=trainable)) c.add(gates.RZ(1, theta=params[8])) fused_c = c.fuse() final_state = fused_c() target_state = c() K.assert_allclose(final_state, target_state) if trainable: new_params = np.random.random(9) new_params_list = list(new_params[:4]) new_params_list.append((new_params[4], new_params[5])) new_params_list.extend(new_params[6:]) else: new_params = np.random.random(9) new_params_list = list(new_params[1:3]) new_params_list.append((new_params[4], new_params[5])) new_params_list.append(new_params[6]) new_params_list.append(new_params[8]) c.set_parameters(new_params_list) fused_c.set_parameters(new_params_list) K.assert_allclose(c(), fused_c())
def test_circuit_set_parameters_with_dictionary(backend, accelerators, trainable): """Check updating parameters of circuit with list.""" original_backend = qibo.get_backend() qibo.set_backend(backend) params = [0.123, 0.456, 0.789, np.random.random((2, 2))] c1 = Circuit(3, accelerators) c1.add(gates.X(0)) c1.add(gates.X(2)) if trainable: c1.add(gates.U1(0, theta=0, trainable=trainable)) else: c1.add(gates.U1(0, theta=params[0], trainable=trainable)) c2 = Circuit(3, accelerators) c2.add(gates.RZ(1, theta=0)) c2.add(gates.CZ(1, 2)) c2.add(gates.CU1(0, 2, theta=0)) c2.add(gates.H(2)) if trainable: c2.add(gates.Unitary(np.eye(2), 1, trainable=trainable)) else: c2.add(gates.Unitary(params[3], 1, trainable=trainable)) c = c1 + c2 final_state = c() target_c = Circuit(3, accelerators) target_c.add(gates.X(0)) target_c.add(gates.X(2)) target_c.add(gates.U1(0, theta=params[0])) target_c.add(gates.RZ(1, theta=params[1])) target_c.add(gates.CZ(1, 2)) target_c.add(gates.CU1(0, 2, theta=params[2])) target_c.add(gates.H(2)) target_c.add(gates.Unitary(params[3], 1)) if trainable: params_dict = {c.queue[i]: p for i, p in zip([2, 3, 5, 7], params)} else: params_dict = {c.queue[3]: params[1], c.queue[5]: params[2]} c.set_parameters(params_dict) np.testing.assert_allclose(c(), target_c()) # test not passing all parametrized gates target_c = Circuit(3, accelerators) target_c.add(gates.X(0)) target_c.add(gates.X(2)) target_c.add(gates.U1(0, theta=params[0])) target_c.add(gates.RZ(1, theta=params[1])) target_c.add(gates.CZ(1, 2)) target_c.add(gates.CU1(0, 2, theta=0.7891)) target_c.add(gates.H(2)) target_c.add(gates.Unitary(params[3], 1)) c.set_parameters({c.queue[5]: 0.7891}) np.testing.assert_allclose(c(), target_c()) qibo.set_backend(original_backend)
def _initialize_circuit(self): """Creates variational circuit.""" C = Circuit(1) for l in range(self.layers): C.add(gates.RY(0, theta=0)) C.add(gates.RZ(0, theta=0)) return C
def test_qgan_circuit_error(): if not K.check_availability("tensorflow"): # pragma: no cover pytest.skip("Skipping StyleQGAN test because tensorflow backend is not available.") original_backend = qibo.get_backend() qibo.set_backend("tensorflow") reference_distribution = generate_distribution(10) # use wrong number of qubits so that we capture the error nqubits = reference_distribution.shape[1] + 1 nlayers = 1 circuit = models.Circuit(nqubits) for l in range(nlayers): for q in range(nqubits): circuit.add(gates.RY(q, 0)) circuit.add(gates.RZ(q, 0)) for i in range(0, nqubits - 1): circuit.add(gates.CZ(i, i + 1)) circuit.add(gates.CZ(nqubits - 1, 0)) for q in range(nqubits): circuit.add(gates.RY(q, 0)) initial_params = np.random.uniform(-0.15, 0.15, 18) qgan = models.StyleQGAN( latent_dim=2, circuit=circuit, set_parameters=lambda x: x ) with pytest.raises(ValueError): qgan.fit(reference_distribution, initial_params=initial_params, n_epochs=1, save=False) qibo.set_backend(original_backend)
def test_variable_backpropagation(backend): if backend == "custom": pytest.skip("Custom gates do not support automatic differentiation.") original_backend = qibo.get_backend() qibo.set_backend(backend) if K.name != "tensorflow": qibo.set_backend(original_backend) pytest.skip("Backpropagation is not supported by {}.".format(K.name)) theta = K.optimization.Variable(0.1234, dtype=K.dtypes('DTYPE')) # TODO: Fix parametrized gates so that `Circuit` can be defined outside # of the gradient tape with K.optimization.GradientTape() as tape: c = Circuit(1) c.add(gates.X(0)) c.add(gates.RZ(0, theta)) loss = K.real(c()[-1]) grad = tape.gradient(loss, theta) target_loss = np.cos(theta / 2.0) np.testing.assert_allclose(loss, target_loss) target_grad = -np.sin(theta / 2.0) / 2.0 np.testing.assert_allclose(grad, target_grad) qibo.set_backend(original_backend)
def test_cu1_cirq(): c1 = Circuit(2) c1.add(gates.RX(0, 0.1234)) c1.add(gates.RZ(1, 0.4321)) c1.add(gates.CU1(0, 1, 0.567)) # catches unknown gate "cu1" with pytest.raises(exception.QasmException): c2 = circuit_from_qasm(c1.to_qasm())
def test_crotations_cirq(): c1 = Circuit(3) c1.add(gates.RX(0, 0.1)) c1.add(gates.RZ(1, 0.4)) c1.add(gates.CRX(0, 2, 0.5)) c1.add(gates.RY(1, 0.3).controlled_by(2)) # catches unknown gate "crx" with pytest.raises(exception.QasmException): c2 = circuit_from_qasm(c1.to_qasm())
def test_circuit_on_qubits_controlled_by_execution(backend, accelerators): smallc = Circuit(3) smallc.add(gates.RX(0, theta=0.1).controlled_by(1, 2)) smallc.add(gates.RY(1, theta=0.2).controlled_by(0)) smallc.add(gates.RX(2, theta=0.3).controlled_by(1, 0)) smallc.add(gates.RZ(1, theta=0.4).controlled_by(0, 2)) largec = Circuit(6, accelerators=accelerators) largec.add(gates.H(i) for i in range(6)) largec.add(smallc.on_qubits(1, 4, 3)) targetc = Circuit(6) targetc.add(gates.H(i) for i in range(6)) targetc.add(gates.RX(1, theta=0.1).controlled_by(3, 4)) targetc.add(gates.RY(4, theta=0.2).controlled_by(1)) targetc.add(gates.RX(3, theta=0.3).controlled_by(1, 4)) targetc.add(gates.RZ(4, theta=0.4).controlled_by(1, 3)) assert largec.depth == targetc.depth K.assert_allclose(largec(), targetc())
def test_rz(backend, applyx): theta = 0.1234 if applyx: gatelist = [gates.X(0)] else: gatelist = [] gatelist.append(gates.RZ(0, theta)) final_state = apply_gates(gatelist, nqubits=1) target_state = np.zeros_like(final_state) p = int(applyx) target_state[p] = np.exp((2 * p - 1) * 1j * theta / 2.0) K.assert_allclose(final_state, target_state)
def ansatz(p=0): """Ansatz for driving a random state into its up-tp-phases canonical form. Args: p (float): probability of occuring a single-qubit depolarizing error Returns: Qibo circuit implementing the variational ansatz. """ C = Circuit(3) for i in range(3): C.add(gates.RZ(i, theta=0)) C.add(gates.RY(i, theta=0)) C.add(gates.RZ(i, theta=0)) if p > 0: C.add(gates.NoiseChannel(i, px=p / 3, py=p / 3, pz=p / 3)) for i in range(3): if p > 0: C.add(gates.NoiseChannel(i, px=10 * p)) C.add(gates.M(i)) return C
def test_construct_unitary(backend): original_backend = qibo.get_backend() qibo.set_backend(backend) target_matrix = np.array([[1, 1], [1, -1]]) / np.sqrt(2) np.testing.assert_allclose(gates.H(0).unitary, target_matrix) target_matrix = np.array([[0, 1], [1, 0]]) np.testing.assert_allclose(gates.X(0).unitary, target_matrix) target_matrix = np.array([[0, -1j], [1j, 0]]) np.testing.assert_allclose(gates.Y(0).unitary, target_matrix) target_matrix = np.array([[1, 0], [0, -1]]) np.testing.assert_allclose(gates.Z(1).unitary, target_matrix) target_matrix = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) np.testing.assert_allclose(gates.CNOT(0, 1).unitary, target_matrix) target_matrix = np.diag([1, 1, 1, -1]) np.testing.assert_allclose(gates.CZ(1, 3).unitary, target_matrix) target_matrix = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) np.testing.assert_allclose(gates.SWAP(2, 4).unitary, target_matrix) target_matrix = np.array([[1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0]]) np.testing.assert_allclose(gates.TOFFOLI(1, 2, 3).unitary, target_matrix) theta = 0.1234 target_matrix = np.array([[np.cos(theta / 2.0), -1j * np.sin(theta / 2.0)], [-1j * np.sin(theta / 2.0), np.cos(theta / 2.0)]]) np.testing.assert_allclose(gates.RX(0, theta).unitary, target_matrix) target_matrix = np.array([[np.cos(theta / 2.0), -np.sin(theta / 2.0)], [np.sin(theta / 2.0), np.cos(theta / 2.0)]]) np.testing.assert_allclose(gates.RY(0, theta).unitary, target_matrix) target_matrix = np.diag( [np.exp(-1j * theta / 2.0), np.exp(1j * theta / 2.0)]) np.testing.assert_allclose(gates.RZ(0, theta).unitary, target_matrix) target_matrix = np.diag([1, np.exp(1j * theta)]) np.testing.assert_allclose(gates.U1(0, theta).unitary, target_matrix) target_matrix = np.diag([1, 1, 1, np.exp(1j * theta)]) np.testing.assert_allclose(gates.CU1(0, 1, theta).unitary, target_matrix) from qibo import matrices target_matrix = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) np.testing.assert_allclose(matrices.SWAP, target_matrix) qibo.set_backend(original_backend)
def test_czpow(): c = Circuit(2) c.add(gates.RX(0, 0.1234)) c.add(gates.RZ(1, 0.4321)) c.add(gates.CZPow(0, 1, 0.567)) target = f"""// Generated by QIBO {__version__} OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; rx(0.1234) q[0]; rz(0.4321) q[1]; crz(0.567) q[0],q[1];""" assert_strings_equal(c.to_qasm(), target)
def test_custom_qgan(): if not K.check_availability("tensorflow"): # pragma: no cover pytest.skip("Skipping StyleQGAN test because tensorflow backend is not available.") original_backend = qibo.get_backend() qibo.set_backend("tensorflow") def set_params(circuit, params, x_input, i): """Set the parameters for the quantum generator circuit.""" p = [] index = 0 noise = 0 for l in range(1): for q in range(3): p.append(params[index]*x_input[noise][i] + params[index+1]) index+=2 noise=(noise+1)%2 p.append(params[index]*x_input[noise][i] + params[index+1]) index+=2 noise=(noise+1)%2 for q in range(3): p.append(params[index]*x_input[noise][i] + params[index+1]) index+=2 noise=(noise+1)%2 circuit.set_parameters(p) nqubits = 3 nlayers = 1 reference_distribution = generate_distribution(10) circuit = models.Circuit(nqubits) for l in range(nlayers): for q in range(nqubits): circuit.add(gates.RY(q, 0)) circuit.add(gates.RZ(q, 0)) for i in range(0, nqubits - 1): circuit.add(gates.CZ(i, i + 1)) circuit.add(gates.CZ(nqubits - 1, 0)) for q in range(nqubits): circuit.add(gates.RY(q, 0)) initial_params = np.random.uniform(-0.15, 0.15, 18) qgan = models.StyleQGAN( latent_dim=2, circuit=circuit, set_parameters=set_params ) qgan.fit(reference_distribution, initial_params=initial_params, n_epochs=1, save=False) assert qgan.latent_dim == 2 assert qgan.batch_samples == 128 assert qgan.n_epochs == 1 assert qgan.lr == 0.5 qibo.set_backend(original_backend)
def test_rz_phase0(backend): """Check RZ gate is working properly when qubit is on |0>.""" original_backend = qibo.get_backend() qibo.set_backend(backend) theta = 0.1234 c = Circuit(2) c.add(gates.RZ(0, theta)) final_state = c.execute().numpy() target_state = np.zeros_like(final_state) target_state[0] = np.exp(-1j * theta / 2.0) np.testing.assert_allclose(final_state, target_state) qibo.set_backend(original_backend)
def test_from_qasm_parametrized_gates(): import numpy as np target = """OPENQASM 2.0; qreg q[2]; rx(0.1234) q[0]; rz(0.4321) q[1]; cu1(0.567) q[0],q[1];""" c = Circuit.from_qasm(target) assert c.depth == 2 assert isinstance(c.queue[0], gates.RX) assert isinstance(c.queue[1], gates.RZ) assert isinstance(c.queue[2], gates.CU1) c2 = Circuit(2) c2.add([gates.RX(0, 0.1234), gates.RZ(1, 0.4321), gates.CU1(0, 1, 0.567)]) np.testing.assert_allclose(c2().numpy(), c().numpy())
def test_variable_backpropagation(backend): if not K.supports_gradients: pytest.skip("Backpropagation is not supported by {}.".format(K.name)) theta = K.optimization.Variable(0.1234, dtype=K.dtypes('DTYPE')) # TODO: Fix parametrized gates so that `Circuit` can be defined outside # of the gradient tape with K.optimization.GradientTape() as tape: c = Circuit(1) c.add(gates.X(0)) c.add(gates.RZ(0, theta)) loss = K.real(c()[-1]) grad = tape.gradient(loss, theta) target_loss = np.cos(theta / 2.0) K.assert_allclose(loss, target_loss) target_grad = -np.sin(theta / 2.0) / 2.0 K.assert_allclose(grad, target_grad)
def test_crotations(): c = Circuit(3) c.add(gates.RX(0, 0.1)) c.add(gates.RZ(1, 0.4)) c.add(gates.CRX(0, 2, 0.5)) c.add(gates.RY(1, 0.3).controlled_by(2)) target = f"""// Generated by QIBO {__version__} OPENQASM 2.0; include "qelib1.inc"; qreg q[3]; rx(0.1) q[0]; rz(0.4) q[1]; crx(0.5) q[0],q[2]; cry(0.3) q[2],q[1];""" assert_strings_equal(c.to_qasm(), target) c = Circuit(2) c.add(gates.CU2(0, 1, 0.1, 0.2)) with pytest.raises(ValueError): target = c.to_qasm()
def test_ugates(): c = Circuit(3) c.add(gates.RX(0, 0.1)) c.add(gates.RZ(1, 0.4)) c.add(gates.U2(2, 0.5, 0.6)) c.add(gates.CU1(0, 1, 0.7)) c.add(gates.CU3(2, 1, 0.2, 0.3, 0.4)) target = f"""// Generated by QIBO {__version__} OPENQASM 2.0; include "qelib1.inc"; qreg q[3]; rx(0.1) q[0]; rz(0.4) q[1]; u2(0.5, 0.6) q[2]; cu1(0.7) q[0],q[1]; cu3(0.2, 0.3, 0.4) q[2],q[1];""" assert_strings_equal(c.to_qasm(), target) c = Circuit(2) c.add(gates.CU2(0, 1, 0.1, 0.2)) with pytest.raises(ValueError): target = c.to_qasm()
def test_variable_backpropagation(backend): """Check that backpropagation works when using `tf.Variable` parameters.""" original_backend = qibo.get_backend() qibo.set_backend(backend) import tensorflow as tf from qibo.config import DTYPES theta = tf.Variable(0.1234, dtype=DTYPES.get('DTYPE')) # TODO: Fix parametrized gates so that `Circuit` can be defined outside # of the gradient tape with tf.GradientTape() as tape: c = Circuit(1) c.add(gates.X(0)) c.add(gates.RZ(0, theta)) loss = tf.math.real(c()[-1]) grad = tape.gradient(loss, theta) target_loss = np.cos(theta.numpy() / 2.0) np.testing.assert_allclose(loss.numpy(), target_loss) target_grad = -np.sin(theta.numpy() / 2.0) / 2.0 np.testing.assert_allclose(grad.numpy(), target_grad) qibo.set_backend(original_backend)
def ansatz_Weighted_2D(layers, qubits=1): """ 3 parameters per layer: Ry(wx + a), Rz(b) """ circuit = models.Circuit(qubits) circuit.add(gates.H(0)) for _ in range(layers): circuit.add(gates.RZ(0, theta=0)) circuit.add(gates.RY(0, theta=0)) def rotation(theta, x): p = circuit.get_parameters() i = 0 j = 0 for l in range(layers): p[i] = theta[j] + theta[j + 1:j + 3] @ x p[i + 1] = theta[j + 3] i += 2 j += 4 return p nparams = 4 * layers return circuit, rotation, nparams
def ansatz_Weighted(layers, qubits=1): """Fourier Ansatz implementation. 4 parameters per layer and qubit: Ry(wx + a), Rz(v log(x) + b) Args: layers (int): number of layers. qubits (int): number of qubits. Returns: The circuit, the rotation function and the total number of parameters. """ circuit = models.Circuit(qubits) for _ in range(layers - 1): for q in range(qubits): circuit.add(gates.RY(q, theta=0)) circuit.add(gates.RZ(q, theta=0)) if qubits > 1: for q in range(0, qubits, 2): circuit.add(gates.CZPow(q, (q + 1) % qubits, theta=0)) if qubits > 2: for q in range(1, qubits + 1, 2): circuit.add(gates.CZPow(q, (q + 1) % qubits, theta=0)) for q in range(qubits): circuit.add(gates.RY(q, theta=0)) circuit.add(gates.RZ(q, theta=0)) def rotation(theta, x): p = circuit.get_parameters() i = 0 j = 0 for l in range(layers - 1): for q in range(qubits): p[i] = theta[j] + theta[j + 1] * map_to(x) p[i + 1] = theta[j + 2] + theta[j + 3] * maplog_to(x) i += 2 j += 4 if qubits > 1: for q in range(0, qubits, 2): p[i] = theta[j] i += 1 j += 1 if qubits > 2: for q in range(1, qubits + 1, 2): p[i] = theta[j] i += 1 j += 1 for q in range(qubits): p[i] = theta[j] + theta[j + 1] * map_to(x) p[i + 1] = theta[j + 2] + theta[j + 3] * maplog_to(x) i += 2 j += 4 return p nparams = 4 * layers * qubits + \ (layers - 1) * int(np.ceil(qubits / 2)) * \ (int(qubits > 1) + int(qubits > 2)) return circuit, rotation, nparams
def ansatz_Fourier(layers, qubits=1): """Fourier Ansatz implementation. It is composed by 3 parameters per layer and qubit: U3(a, b, c) Ry(x) || U3(a, b, c) Ry(log x). Args: layers (int): number of layers. qubits (int): number of qubits. Returns: The circuit, the rotation function and the total number of parameters. """ circuit = models.Circuit(qubits) for l in range(layers - 1): for q in range(qubits): for _ in range(2): circuit.add(gates.RY(q, theta=0)) circuit.add(gates.RZ(q, theta=0)) circuit.add(gates.RY(q, theta=0)) if qubits > 1: for q in range(0, qubits, 2): circuit.add(gates.CZPow(q, q + 1, theta=0)) if qubits > 2: for q in range(1, qubits + 1, 2): circuit.add(gates.CZPow(q, (q + 1) % qubits, theta=0)) for q in range(qubits): for _ in range(2): circuit.add(gates.RY(q, theta=0)) circuit.add(gates.RZ(q, theta=0)) circuit.add(gates.RY(q, theta=0)) def rotation(theta, x): p = circuit.get_parameters() i = 0 j = 0 for l in range(layers - 1): for q in range(qubits): p[i] = map_to(x) p[i + 1:i + 3] = theta[j:j + 2] i += 3 j += 2 p[i] = .5 * maplog_to(x) p[i + 1:i + 3] = theta[j:j + 2] i += 3 j += 2 if qubits > 1: for q in range(0, qubits, 2): p[i] = theta[j] i += 1 j += 1 if qubits > 2: for q in range(1, qubits + 1, 2): p[i] = theta[j] i += 1 j += 1 for q in range(qubits): p[i] = .5 * map_to(x) p[i + 1:i + 3] = theta[j:j + 2] i += 3 j += 2 p[i] = .5 * maplog_to(x) p[i + 1:i + 3] = theta[j:j + 2] i += 3 j += 2 return p nparams = 4 * layers * qubits + \ (layers - 1) * int(np.ceil(qubits / 2)) * \ (int(qubits > 1) + int(qubits > 2)) return circuit, rotation, nparams
def last_rotation(circuit, nqubits): for k in range(nqubits): circuit.add(gates.RZ(k, np.random.rand())) circuit.add(gates.RX(k, np.random.rand()))
def rotations(): for q in range(self.nqubits): yield gates.RX(q, theta=0) yield gates.RZ(q, theta=0) yield gates.RX(q, theta=0)
def fit(self, reference, initial_params=None, batch_samples=128, n_epochs=20000, lr=0.5, save=True): """Execute qGAN training. Args: reference (array): samples from the reference input distribution. initial_parameters (array): initial parameters for the quantum generator. If not provided, the default initial parameters will be used. discriminator (:class:`tensorflow.keras.models`): custom classical discriminator. If not provided, the default classical discriminator will be used. batch_samples (int): number of training examples utilized in one iteration. n_epochs (int): number of training iterations. lr (float): initial learning rate for the quantum generator. It controls how much to change the model each time the weights are updated. save (bool): If ``True`` the results of training (trained parameters and losses) will be saved on disk. Default is ``True``. """ if initial_params is None and self.circuit is not None: raise_error( ValueError, "Set the initial parameters for your custom quantum generator." ) elif initial_params is not None and self.circuit is None: raise_error( ValueError, "Define the custom quantum generator to use custom initial parameters." ) self.reference = reference self.nqubits = reference.shape[1] self.training_samples = reference.shape[0] self.initial_params = initial_params self.batch_samples = batch_samples self.n_epochs = n_epochs self.lr = lr # create classical discriminator if self.discriminator is None: discriminator = self.define_discriminator() else: discriminator = self.discriminator if discriminator.input_shape[1] is not self.nqubits: raise_error( ValueError, "The number of input neurons in the discriminator has to be equal to " "the number of qubits in the circuit (dimension of the input reference distribution)." ) # create quantum generator if self.circuit is None: circuit = models.Circuit(self.nqubits) for l in range(self.layers): for q in range(self.nqubits): circuit.add(gates.RY(q, 0)) circuit.add(gates.RZ(q, 0)) circuit.add(gates.RY(q, 0)) circuit.add(gates.RZ(q, 0)) for i in range(0, self.nqubits - 1): circuit.add(gates.CRY(i, i + 1, 0)) circuit.add(gates.CRY(self.nqubits - 1, 0, 0)) for q in range(self.nqubits): circuit.add(gates.RY(q, 0)) else: circuit = self.circuit if circuit.nqubits != self.nqubits: raise_error( ValueError, "The number of qubits in the circuit has to be equal to " "the number of dimensions in the reference distribution.") # define hamiltonian to generate fake samples def hamiltonian(nqubits, position): identity = [[1, 0], [0, 1]] m0 = hamiltonians.Z(1).matrix kron = [] for i in range(nqubits): if i == position: kron.append(m0) else: kron.append(identity) for i in range(nqubits - 1): if i == 0: ham = np.kron(kron[i + 1], kron[i]) else: ham = np.kron(kron[i + 1], ham) ham = hamiltonians.Hamiltonian(nqubits, ham) return ham hamiltonians_list = [] for i in range(self.nqubits): hamiltonians_list.append(hamiltonian(self.nqubits, i)) # train model self.train(discriminator, circuit, hamiltonians_list, save)