def _ml_defaults(hyperparams): """Uses hyperparameters or defaults to construct the components of the machine learning benchmark. Args: hyperparams (dict): hyperparameters provided by user """ # get hyperparameters or set default values n_features = hyperparams.pop("n_features", 4) n_samples = hyperparams.pop("n_samples", 20) interface = hyperparams.pop("interface", "autograd") diff_method = hyperparams.pop("diff_method", "best") device = hyperparams.pop("device", "default.qubit") # if device name is given, create device if isinstance(device, str): device = qml.device(device, wires=n_features) # data x0 = np.random.normal(loc=-1, scale=1, size=(n_samples // 2, n_features)) x1 = np.random.normal(loc=1, scale=1, size=(n_samples // 2, n_features)) x = np.concatenate([x0, x1], axis=0) y = np.concatenate([-np.ones(50), np.ones(50)], axis=0) data = list(zip(x, y)) return data, device, diff_method, interface
def test_wrong_dy_statevector(self, tol, dev): """Tests raise an exception when dy is incorrect""" x, y, z = [0.5, 0.3, -0.7] with qml.tape.QuantumTape() as tape: qml.RX(0.4, wires=[0]) qml.Rot(x, y, z, wires=[0]) qml.RY(-0.2, wires=[0]) qml.state() tape.trainable_params = {1, 2, 3} dy1 = np.ones(3, dtype=dev.C_DTYPE) with pytest.raises( ValueError, match= "Size of the provided vector dy must be the same as the size of" ): dev.vjp(tape.measurements, dy1) dy2 = np.ones(4, dtype=dev.R_DTYPE) with pytest.warns( UserWarning, match="The vjp method only works with complex-valued dy"): dev.vjp(tape.measurements, dy2)
def test_calculate_WAW(self): """Test that the calculate_WAW method calculates correctly""" const = 2 A = 0.1767767 * np.ones((4, 4)) params = const * np.ones(4) waw = StrawberryFieldsGBS.calculate_WAW(params, A) assert np.allclose(waw, const * A)
def test_caching_samples_at_input(self, mocker): """Test caching in non-analytic mode with pre-generated input samples. No call to the QNode should result in more samples being generated.""" dev = qml.device( "strawberryfields.gbs", wires=4, cutoff_dim=3, use_cache=True, shots=4, samples=samples, ) A = 0.1767767 * np.ones((4, 4), requires_grad=False) params = np.ones(4) @qml.qnode(dev) def vgbs(params): ParamGraphEmbed(params, A, 1, wires=range(4)) return qml.probs(wires=range(4)) spy = mocker.spy(sf.Engine, "run") p1 = vgbs(params) samps = dev.samples.copy() p2 = vgbs(0.5 * params) samps2 = dev.samples.copy() p2_expected = dev._reparametrize_probability(p1.reshape((3, 3, 3, 3))).ravel() assert np.allclose(samps, samples) assert np.allclose(samps2, samples) assert np.allclose(p2_expected, p2) spy.assert_not_called()
def test_apply_mask(self): size = 3 mp = DropoutMask((size, )) with pytest.raises(IndexError): mp.apply_mask(pnp.ones((size - 1, size))) mp.mask[1] = True result = mp.apply_mask(pnp.ones((size, ), dtype=bool)) assert pnp.sum(mp.mask) == 1 assert pnp.sum(result) == size - 1
def test_generate_hamiltonian(symbols, geometry, h_ref_data): r"""Test that generate_hamiltonian returns the correct Hamiltonian.""" mol = Molecule(symbols, geometry) args = [] h = generate_hamiltonian(mol)(*args) h_ref = qml.Hamiltonian(h_ref_data[0], h_ref_data[1]) assert np.allclose(h.terms[0], h_ref.terms[0]) assert qml.Hamiltonian(np.ones(len(h.terms[0])), h.terms[1]).compare( qml.Hamiltonian(np.ones(len(h_ref.terms[0])), h_ref.terms[1]))
def test_apply_mask(self): size = 3 mp = ValueMask((size, )) with pytest.raises(ValueError): mp.apply_mask(pnp.ones((size - 1, ))) mp.mask[1] = 1 result = mp.apply_mask(pnp.ones((size, ), dtype=float)) assert pnp.sum(mp.mask) == 1 assert pnp.sum(result) == size + 1 mp.mask[1] = -1 result = mp.apply_mask(pnp.ones((size, ), dtype=float)) assert pnp.sum(result) == size - 1
def test_apply_wrong_dim(self): """Test that the apply method raises a ValueError when the number of variable parameters does not match the number of modes""" dev = qml.device("strawberryfields.gbs", wires=4, cutoff_dim=3) op = "ParamGraphEmbed" wires = list(range(4)) A = 0.1767767 * np.ones((4, 4), requires_grad=False) params = np.ones(3) n_mean = 1 par = [params, A, n_mean] with pytest.raises(ValueError, match="The number of variable parameters must be"): dev.apply(op, wires, par)
def optimize(alpha, beta): """Define a function that optimizes theta_A0, theta_A1, theta_B0, theta_B1 to maximize the probability of winning the game Args: - alpha (float): real coefficient of |00> - beta (float): real coefficient of |11> Returns: - (float): Probability of winning """ def cost(params): """Define a cost function that only depends on params, given alpha and beta fixed""" return -winning_prob(params, alpha, beta) # QHACK # #Initialize parameters, choose an optimization method and number of steps init_params = np.ones(4) opt = qml.AdagradOptimizer() steps = 2000 # QHACK # # set the initial parameter values params = init_params for i in range(steps): # update the circuit parameters # QHACK # params = opt.step(cost, params) # QHACK # return winning_prob(params, alpha, beta)
def test_compile_autograd(self, diff_method): """Test QNode and gradient in autograd interface.""" original_qnode = qml.QNode(qfunc, dev, interface="autograd", diff_method=diff_method) transformed_qnode = qml.QNode(transformed_qfunc, dev, interface="autograd", diff_method=diff_method) x = np.array([0.1, 0.2, 0.3], requires_grad=False) params = np.ones((2, 3)) # Check that the numerical output is the same assert qml.math.allclose(original_qnode(x, params), transformed_qnode(x, params)) # Check that the gradient is the same assert qml.math.allclose( qml.grad(original_qnode)(x, params), qml.grad(transformed_qnode)(x, params)) # Check operation list ops = transformed_qnode.qtape.operations compare_operation_lists(ops, expected_op_list, expected_wires_list)
def test_with_qnode(self, qnode, params, ids, nums_frequency, spectra, shifts, exp_calls, mocker): """Run a full reconstruction on a QNode.""" qnode = qml.QNode(qnode, dev_1) with qml.Tracker(qnode.device) as tracker: recons = reconstruct(qnode, ids, nums_frequency, spectra, shifts)(*params) assert tracker.totals["executions"] == exp_calls arg_names = list(signature(qnode.func).parameters.keys()) for outer_key in recons: outer_key_num = arg_names.index(outer_key) for inner_key, rec in recons[outer_key].items(): x0 = params[outer_key_num] if not pnp.isscalar(x0): x0 = x0[inner_key] shift_vec = qml.math.zeros_like(params[outer_key_num]) shift_vec[inner_key] = 1.0 shift_vec = 1.0 if pnp.isscalar( params[outer_key_num]) else shift_vec mask = (0.0 if pnp.isscalar(params[outer_key_num]) else pnp.ones(qml.math.shape(params[outer_key_num])) - shift_vec) univariate = lambda x: qnode( *params[:outer_key_num], params[outer_key_num] * mask + x * shift_vec, *params[outer_key_num + 1:], ) assert np.isclose(rec(x0), qnode(*params)) assert np.isclose(rec(x0 + 0.1), univariate(x0 + 0.1)) assert fun_close(rec, univariate, 10)
def circuit_aux(cparams): diag = np.ones(2**num_wires) diag[0] *= -1 # Initialization init_circuit(cparams) # Non-Boolean Amplitude Amplification go brrrrr for k in range(1, K + 1): # Act the oracle during odd iterations, or its inverse during # the even iterations if k % 2 == 1: self.oracle(cparams, num_qparams) else: qml.inv(self.oracle(cparams, num_qparams)) # Diffusion operator qml.inv(init_circuit(cparams)) # Evan: This is incredibly painful to implement with a standard # gate decomposition, so we can't actually use Floq beyond this # point... qml.DiagonalQubitUnitary(diag, wires=range(num_wires)) init_circuit(cparams) # Measurement of the control registers post amplification return qml.probs(wires=range(self.num_qubits, num_wires))
def diffusion_matrix(): # DO NOT MODIFY anything in this code block psi_piece = (1 / 2**4) * np.ones(2**4) ident_piece = np.eye(2**4) return 2 * psi_piece - ident_piece
def test_compile_template(self): """Test that functions with templates are correctly expanded and compiled.""" # Push commuting gates to the right and merging rotations gives a circuit # with alternating RX and CNOT gates def qfunc(x, params): qml.templates.AngleEmbedding(x, wires=range(3)) qml.templates.BasicEntanglerLayers(params, wires=range(3)) return qml.expval(qml.PauliZ(wires=2)) dev = qml.device("default.qubit", wires=3) qnode = qml.QNode(qfunc, dev) pipeline = [commute_controlled, merge_rotations] transformed_qfunc = compile(pipeline=pipeline)(qfunc) transformed_qnode = qml.QNode(transformed_qfunc, dev) x = np.array([0.1, 0.2, 0.3]) params = np.ones((2, 3)) original_result = qnode(x, params) transformed_result = transformed_qnode(x, params) assert np.allclose(original_result, transformed_result) names_expected = ["RX", "CNOT"] * 6 wires_expected = [ Wires(0), Wires([0, 1]), Wires(1), Wires([1, 2]), Wires(2), Wires([2, 0]), ] * 2 compare_operation_lists(transformed_qnode.qtape.operations, names_expected, wires_expected)
def test_apply_mask(self): size = 3 mp = self._create_circuit(size) with pytest.raises(ValueError): mp.apply_mask(pnp.ones((size, size - 1))) mp.mask(Axis.WIRES)[:size - 1] = True result = mp.apply_mask(pnp.ones((size, size), dtype=bool)) assert pnp.sum(~mp.full_mask(DropoutMask)) == size assert pnp.sum(result) == size mp.mask(Axis.LAYERS)[:size - 1] = True result = mp.apply_mask(pnp.ones((size, size), dtype=bool)) assert pnp.sum(~mp.full_mask(DropoutMask)) == 1 assert pnp.sum(result) == 1 mp.mask(Axis.PARAMETERS)[(size - 1, size - 1)] = True result = mp.apply_mask(pnp.ones((size, size), dtype=bool)) assert pnp.sum(~mp.full_mask(DropoutMask)) == 0 assert pnp.sum(result) == 0
def test_reparametrize_probability(self): """Test the _reparametrize_probability method applied to a fixed 2-mode example""" dev = qml.device("strawberryfields.gbs", wires=2, cutoff_dim=3, shots=None) A = 0.35355339 * np.ones((2, 2)) dev._WAW = 0.9 * A dev.Z_inv = 1 / np.sqrt(2) dev._params = 0.9 * np.ones(2) p = np.array( [0.70710678, 0.0, 0.04419417, 0.0, 0.08838835, 0.0, 0.04419417, 0.0, 0.02485922] ).reshape((3, 3)) p_reparam = dev._reparametrize_probability(p) p_target = np.array( [0.77136243, 0.0, 0.03905022, 0.0, 0.07810045, 0.0, 0.03905022, 0.0, 0.01779226] ).reshape((3, 3)) assert np.allclose(p_reparam, p_target)
def test_jacobian_all_wires(self): """Test that the _jacobian_all_wires method returns the correct jacobian for a fixed input probability distribution""" dev = qml.device("strawberryfields.gbs", wires=4, cutoff_dim=3) dev._WAW = 0.1767767 * np.ones((4, 4)) params = np.array([1, 2, 3, 4]) n_mean = np.ones(4) / 4 dev._params = params indices = np.indices([3, 3, 3, 3]).reshape(4, -1).T probs = np.arange(3 ** 4) jac_expected = np.zeros((3 ** 4, 4)) for i, ind in enumerate(indices): jac_expected[i] = probs[i] * (ind - n_mean) / params jac = dev._jacobian_all_wires(probs) assert np.allclose(jac, jac_expected)
def test_apply_analytic(self): """Test that the apply method constructs the correct program""" dev = qml.device("strawberryfields.gbs", wires=4, cutoff_dim=3) op = "ParamGraphEmbed" wires = list(range(4)) A = 0.1767767 * np.ones((4, 4), requires_grad=False) params = 0.5 * np.ones(4) n_mean = 1 par = [params, A, n_mean] with dev.execution_context(): dev.apply(op, wires, par) circ = dev.prog.circuit assert len(circ) == 1 assert isinstance(circ[0].op, GraphEmbed) assert np.allclose(circ[0].op.p[0], 0.5 * A)
def oracle(self, cparams, num_qparams): diag = np.ones(2**self.num_qubits) diag[0] *= -1 qml.inv(self.rand_circuit(cparams, num_qparams)) qml.DiagonalQubitUnitary(diag, wires=range(self.num_qubits)) self.rand_circuit(cparams, num_qparams) qml.DiagonalQubitUnitary(diag, wires=range(self.num_qubits))
def test_pre_measure_eng(self, tol): """Test that the pre_measure method operates as expected by initializing the engine correctly""" dev = qml.device("strawberryfields.gbs", wires=4, cutoff_dim=3) prog = Program(4) op1 = GraphEmbed(0.1767767 * np.ones((4, 4)), mean_photon_per_mode=0.25) prog.append(op1, prog.register) dev.prog = prog dev.pre_measure() assert dev.eng.backend_name == "gaussian" assert dev.eng.backend_options == {"cutoff_dim": 3}
def test_shape(self, wires, cutoff_dim): """Test that the probabilities and jacobian are returned with the expected shape""" dev = qml.device("strawberryfields.gbs", wires=wires, cutoff_dim=cutoff_dim) a = np.ones((wires, wires), requires_grad=False) params = np.ones(wires) @qnode_decorator(dev) def vgbs(params): ParamGraphEmbed(params, a, 1, wires=range(wires)) return qml.probs(wires=range(wires)) d_vgbs = qml.jacobian(vgbs, argnum=0) p = vgbs(params) dp = d_vgbs(params) assert p.shape == (cutoff_dim ** wires,) assert dp.shape == (cutoff_dim ** wires, wires) assert (p >= 0).all() assert (p <= 1).all() assert np.sum(p) <= 1
def test_template_integration(self, strategy, tol): """Test that the metric tensor transform acts on QNodes correctly when the QNode contains a template""" dev = qml.device("default.qubit", wires=3) @qml.beta.qnode(dev, expansion_strategy=strategy) def circuit(weights): qml.templates.StronglyEntanglingLayers(weights, wires=[0, 1, 2]) return qml.probs(wires=[0, 1]) weights = np.ones([2, 3, 3], dtype=np.float64, requires_grad=True) res = qml.metric_tensor(circuit, approx="block-diag")(weights) assert res.shape == (2, 3, 3, 2, 3, 3)
def test_pre_measure_non_analytic_cache(self, mocker): """Test that the pre_measure method does not overwrite existing samples if present in non-analytic mode when use_cache is ``True``""" samples = -1 * np.ones((10, 4)) dev = qml.device( "strawberryfields.gbs", wires=4, cutoff_dim=3, shots=10, samples=samples, use_cache=True, ) prog = Program(4) op1 = GraphEmbed(0.1767767 * np.ones((4, 4)), mean_photon_per_mode=0.25) op2 = MeasureFock() prog.append(op1, prog.register) prog.append(op2, prog.register) dev.prog = prog dev.pre_measure() spy = mocker.spy(sf.Engine, "run") assert np.allclose(dev.samples, samples) spy.assert_not_called()
def test_pre_measure_state_and_samples(self, tol): """Test that the pre_measure method operates as expected in analytic mode by generating the correct output state and not generating samples""" dev = qml.device("strawberryfields.gbs", wires=4, cutoff_dim=3) prog = Program(4) op1 = GraphEmbed(0.1767767 * np.ones((4, 4)), mean_photon_per_mode=0.25) prog.append(op1, prog.register) dev.prog = prog dev.pre_measure() assert np.allclose(dev.state.displacement(), np.zeros(4)) assert np.allclose(dev.state.cov(), target_cov, atol=tol) assert dev.samples.size == 0
def test_shape_reduced_wires(self, wires, cutoff_dim): """Test that the probabilities and jacobian are returned with the expected shape when probabilities are measured on a subset of wires""" dev = qml.device("strawberryfields.gbs", wires=wires, cutoff_dim=cutoff_dim) a = np.ones((wires, wires)) params = np.ones(wires) @qml.qnode(dev) def vgbs(params): ParamGraphEmbed(params, a, 1, wires=range(wires)) return qml.probs(wires=[0, 1]) d_vgbs = qml.jacobian(vgbs, argnum=0) p = vgbs(params) dp = d_vgbs(params) assert p.shape == (cutoff_dim ** 2,) assert dp.shape == (cutoff_dim ** 2, wires) assert (p >= 0).all() assert (p <= 1).all() assert np.sum(p) <= 1
def test_custom_rotation(self, rotation): """Tests that non-default rotation gates are used correctly.""" n_layers = 2 n_wires = 4 weights = np.ones(shape=(n_layers, n_wires)) with pennylane._queuing.OperationRecorder() as rec: BasicEntanglerLayers(weights, wires=range(n_wires), rotation=rotation) # assert queue contains the custom rotations and CNOTs only gates = rec.queue for op in gates: if not isinstance(op, CNOT): assert isinstance(op, rotation)
def test_pre_measure_state_and_samples_non_analytic(self, tol): """Test that the pre_measure method operates as expected in non-analytic mode by generating the correct output state and samples of the right shape""" dev = qml.device("strawberryfields.gbs", wires=4, cutoff_dim=3, analytic=False, shots=2) prog = Program(4) op1 = GraphEmbed(0.1767767 * np.ones((4, 4)), mean_photon_per_mode=0.25) op2 = MeasureFock() prog.append(op1, prog.register) prog.append(op2, prog.register) dev.prog = prog dev.pre_measure() assert np.allclose(dev.state.displacement(), np.zeros(4)) assert np.allclose(dev.state.cov(), target_cov, atol=tol) assert dev.samples.shape == (2, 4)
def test_caching_samples(self, mocker): """Test caching in non-analytic mode. Samples should be generated upon first call and then not generated subsequently.""" dev = qml.device( "strawberryfields.gbs", wires=4, cutoff_dim=3, use_cache=True, shots=10 ) A = 0.1767767 * np.ones((4, 4), requires_grad=False) params = np.ones(4) @qml.qnode(dev) def vgbs(params): ParamGraphEmbed(params, A, 1, wires=range(4)) return qml.probs(wires=range(4)) vgbs(params) samps = dev.samples.copy() circ = dev.prog.circuit assert np.allclose(circ[0].op.p[0], A) spy = mocker.spy(sf.Engine, "run") vgbs(0.5 * params) samps2 = dev.samples.copy() assert np.allclose(samps, samps2) spy.assert_not_called()
def oracle(self, cparams, num_qparams): diag = np.ones(2**self.num_qubits) diag[0] *= -1 qml.inv(self.rand_circuit(cparams, num_qparams)) if self.floq: decomposed_oracle(self.num_qubits) else: qml.DiagonalQubitUnitary(diag, wires=range(self.num_qubits)) self.rand_circuit(cparams, num_qparams) if self.floq: decomposed_oracle(self.num_qubits) else: qml.DiagonalQubitUnitary(diag, wires=range(self.num_qubits))
def test_apply_non_analytic(self, use_cache): """Test that the apply method constructs the correct program when in non-analytic mode""" dev = qml.device( "strawberryfields.gbs", wires=4, cutoff_dim=3, shots=100, use_cache=use_cache ) op = "ParamGraphEmbed" wires = list(range(4)) A = 0.1767767 * np.ones((4, 4), requires_grad=False) params = 0.5 * np.ones(4) n_mean = 1 par = [params, A, n_mean] with dev.execution_context(): dev.apply(op, wires, par) circ = dev.prog.circuit assert len(circ) == 2 assert isinstance(circ[0].op, GraphEmbed) if use_cache: assert np.allclose(circ[0].op.p[0], A) else: assert np.allclose(circ[0].op.p[0], 0.5 * A) assert isinstance(circ[1].op, MeasureFock)