Exemple #1
0
def wide_cv_qnode():
    """A wide unparametrized CV circuit."""
    def qfunc():
        qml.GaussianState(np.array([(2 * i + 2) // 2 for i in range(16)]),
                          2 * np.eye(16),
                          wires=list(range(8)))
        [qml.Beamsplitter(0.4, 0, wires=[2 * i, 2 * i + 1]) for i in range(4)]
        [
            qml.Beamsplitter(0.25475, 0.2312344, wires=[i, i + 4])
            for i in range(4)
        ]

        return [
            qml.expval(
                qml.FockStateProjector(np.array([1, 1]), wires=[i, i + 4]))
            for i in range(4)
        ]

    dev = qml.device("default.gaussian", wires=8)
    qnode = qml.QNode(qfunc, dev)
    qnode._construct((), {})
    qnode.evaluate((), {})

    return qnode
Exemple #2
0
    def sample_circuit(self, request):
        """Sample variational circuit fixture used in the
        next couple of tests"""
        dev = qml.device("default.qubit", wires=3)

        def non_parametrized_layer(a, b, c):
            qml.RX(a, wires=0)
            qml.RX(b, wires=1)
            qml.RX(c, wires=1)
            qml.CNOT(wires=[0, 1])
            qml.CNOT(wires=[1, 2])
            qml.RZ(a, wires=0)
            qml.Hadamard(wires=1)
            qml.CNOT(wires=[0, 1])
            qml.RZ(b, wires=1)
            qml.Hadamard(wires=0)

        a = 0.5
        b = 0.1
        c = 0.5

        def final(x, y, z, h, g, f):
            non_parametrized_layer(a, b, c)
            qml.RX(x, wires=0)
            qml.RY(y, wires=1)
            qml.RZ(z, wires=2)
            non_parametrized_layer(a, b, c)
            qml.RY(f, wires=1)
            qml.RZ(g, wires=2)
            qml.RX(h, wires=1)
            return qml.expval(qml.PauliX(0)), qml.expval(
                qml.PauliX(1)), qml.expval(qml.PauliX(2))

        final = qml.QNode(final, dev, diff_method=request.param)

        return dev, final, non_parametrized_layer, a, b, c
Exemple #3
0
def test_get_unitary_matrix_interface_jax():
    """Test with JAX interface"""

    jax = pytest.importorskip("jax")
    from jax import numpy as jnp
    from jax.config import config

    remember = config.read("jax_enable_x64")
    config.update("jax_enable_x64", True)

    dev = qml.device("default.qubit", wires=3)

    def circuit(theta):
        qml.RZ(theta[0], wires=0)
        qml.RZ(theta[1], wires=1)
        qml.CRY(theta[2], wires=[1, 2])
        return qml.expval(qml.PauliZ(1))

    # set qnode interface
    qnode = qml.QNode(circuit, dev, interface="jax")

    get_matrix = get_unitary_matrix(qnode)

    # input jax parameters
    theta = jnp.array([0.1, 0.2, 0.3], dtype=jnp.float64)

    matrix = get_matrix(theta)

    # expected matrix
    matrix1 = np.kron(
        qml.RZ(theta[0], wires=0).matrix, np.kron(qml.RZ(theta[1], wires=1).matrix, I)
    )
    matrix2 = np.kron(I, qml.CRY(theta[2], wires=[1, 2]).matrix)
    expected_matrix = matrix2 @ matrix1

    assert np.allclose(matrix, expected_matrix)
    def test_cv_gradient_fanout(self, gaussian_dev, tol):
        "Tests that qnodes can compute the correct gradient when the same parameter is used in multiple gates."
        par = [0.5, 1.3]

        def circuit(x, y):
            qml.Displacement(x, 0, wires=[0])
            qml.Rotation(y, wires=[0])
            qml.Displacement(0, x, wires=[0])
            return qml.expval(qml.X(0))

        q = qml.QNode(circuit, gaussian_dev)
        q(*par)
        grad_F = q.qtape.jacobian(gaussian_dev, method='numeric')
        grad_A = q.qtape.jacobian(gaussian_dev, method='analytic')
        grad_A2 = q.qtape.jacobian(gaussian_dev,
                                   method='analytic',
                                   force_order2=True)

        # analytic method works for every parameter
        assert {q.qtape._grad_method(i)
                for i in range(q.qtape.num_params)} == {"A"}
        # the different methods agree
        assert grad_A == pytest.approx(grad_F, abs=tol)
        assert grad_A2 == pytest.approx(grad_F, abs=tol)
Exemple #5
0
    def test_cvneuralnet_integration(self, gaussian_device_4modes, weights,
                                     depth, N):
        """integration test for the CVNeuralNetLayers template."""
        def circuit(weights):
            CVNeuralNetLayers(*weights, wires=range(N))
            return qml.expval(qml.X(wires=0))

        qnode = qml.QNode(circuit, gaussian_device_4modes)

        # execution test
        qnode(weights)
        queue = qnode.queue

        # Test that gates appear in the right order for each layer:
        # BS-R-S-BS-R-D-K
        for l in range(depth):
            gates = [
                qml.Beamsplitter, qml.Rotation, qml.Squeezing,
                qml.Beamsplitter, qml.Rotation, qml.Displacement
            ]

            # count the position of each group of gates in the layer
            num_gates_per_type = [0, 6, 4, 4, 6, 4, 4, 4]
            s = np.cumsum(num_gates_per_type)
            gc = l * sum(num_gates_per_type) + np.array(
                list(zip(s[:-1], s[1:])))

            # loop through expected gates
            for idx, g in enumerate(gates):
                # loop through where these gates should be in the queue
                for opidx, op in enumerate(queue[gc[idx, 0]:gc[idx, 1]]):
                    # check that op in queue is correct gate
                    assert isinstance(op, g)

                    # test that the parameters are correct
                    res_params = op.parameters

                    if idx == 0:
                        # first BS
                        exp_params = [
                            weights[0][l][opidx], weights[1][l][opidx]
                        ]
                    elif idx == 1:
                        # first rot
                        exp_params = [weights[2][l][opidx]]
                    elif idx == 2:
                        # squeezing
                        exp_params = [
                            weights[3][l][opidx], weights[4][l][opidx]
                        ]
                    elif idx == 3:
                        # second BS
                        exp_params = [
                            weights[5][l][opidx], weights[6][l][opidx]
                        ]
                    elif idx == 4:
                        # second rot
                        exp_params = [weights[7][l][opidx]]
                    elif idx == 5:
                        # displacement
                        exp_params = [
                            weights[8][l][opidx], weights[9][l][opidx]
                        ]

                    assert res_params == exp_params
Exemple #6
0
def test_batch_execution_of_gradient_torch(device, shots, mocker):
    """Test that the output of a parallelized execution of batch circuits to evaluate the
    gradient is correct in comparison to default.qubit when using the torch interface."""
    try:
        import torch
    except ImportError:
        pytest.skip("This test requires installation of torch")

    qubits = 2
    layers = 2

    dev_aws = device(qubits)

    if isinstance(dev_aws, BraketLocalQubitDevice):
        pytest.skip(
            "Parallelized batch execution is only supported on the remote AWS device"
        )

    dev_aws._parallel = True

    dev_default = qml.device("default.qubit", wires=qubits)

    def func(weights):
        qml.templates.StronglyEntanglingLayers(weights, wires=range(qubits))
        return qml.expval(qml.PauliZ(0))

    qnode_aws = qml.QNode(func, dev_aws, interface="torch")
    qnode_default = qml.QNode(func, dev_default, interface="torch")

    shape = qml.templates.StronglyEntanglingLayers.shape(layers, qubits)
    weights = np.random.random(shape)
    weights_aws = torch.tensor(weights, requires_grad=True)
    weights_default = torch.tensor(weights, requires_grad=True)

    spy1 = mocker.spy(BraketAwsQubitDevice, "execute")
    spy2 = mocker.spy(BraketAwsQubitDevice, "batch_execute")
    spy3 = mocker.spy(AwsDevice, "run_batch")

    out_aws = qnode_aws(weights_aws)
    out_default = qnode_default(weights_default)

    out_aws.backward()
    out_default.backward()

    res_aws = weights_aws.grad
    res_default = weights_default.grad

    if qml.version() >= "0.20.0":
        assert np.allclose(res_aws, res_default)
        spy1.assert_not_called()
        assert len(spy2.call_args_list) == 2
        assert len(spy3.call_args_list) == 2

        expected_circuits = qubits * layers * 3 * 2
        assert len(spy2.call_args_list[0][0]
                   [1]) == 1  # First batch_execute called for forward pass
        assert (len(spy2.call_args_list[1][0][1]) == expected_circuits
                )  # Then called for backward pass
    else:
        assert np.allclose(res_aws, res_default)
        spy1.assert_called_once()  # For a forward pass
        spy2.assert_called_once()
        spy3.assert_called_once()

        expected_circuits = qubits * layers * 3 * 2
        assert len(spy2.call_args_list[0][0][1]) == expected_circuits
Exemple #7
0
    def test_construct_subcircuit_layers(self):
        """Test correct subcircuits constructed
        when a layer structure exists"""
        dev = qml.device("default.qubit", wires=3)

        def circuit(params):
            # section 1
            qml.RX(params[0], wires=0)
            # section 2
            qml.RY(params[1], wires=0)
            qml.CNOT(wires=[0, 1])
            qml.CNOT(wires=[1, 2])
            # section 3
            qml.RX(params[2], wires=0)
            qml.RY(params[3], wires=1)
            qml.RZ(params[4], wires=2)
            qml.CNOT(wires=[0, 1])
            qml.CNOT(wires=[1, 2])
            # section 4
            qml.RX(params[5], wires=0)
            qml.RY(params[6], wires=1)
            qml.RZ(params[7], wires=2)
            qml.CNOT(wires=[0, 1])
            qml.CNOT(wires=[1, 2])
            return qml.expval(qml.PauliX(0)), qml.expval(
                qml.PauliX(1)), qml.expval(qml.PauliX(2))

        circuit = qml.QNode(circuit, dev)

        params = np.ones([8])
        tapes = circuit.metric_tensor(params, only_construct=True)

        # this circuit should split into 4 independent
        # sections or layers when constructing subcircuits
        assert len(tapes) == 4

        # first layer subcircuit
        assert len(tapes[0].operations) == 1
        assert isinstance(tapes[0].operations[0],
                          qml.Hadamard)  # PauliX decomp

        # second layer subcircuit
        assert len(tapes[1].operations) == 4
        assert isinstance(tapes[1].operations[0], qml.RX)
        # PauliY decomp
        assert isinstance(tapes[1].operations[1], qml.PauliZ)
        assert isinstance(tapes[1].operations[2], qml.S)
        assert isinstance(tapes[1].operations[3], qml.Hadamard)

        # # third layer subcircuit
        assert len(tapes[2].operations) == 8
        assert isinstance(tapes[2].operations[0], qml.RX)
        assert isinstance(tapes[2].operations[1], qml.RY)
        assert isinstance(tapes[2].operations[2], qml.CNOT)
        assert isinstance(tapes[2].operations[3], qml.CNOT)
        # PauliX decomp
        assert isinstance(tapes[2].operations[4], qml.Hadamard)
        # PauliY decomp
        assert isinstance(tapes[2].operations[5], qml.PauliZ)
        assert isinstance(tapes[2].operations[6], qml.S)
        assert isinstance(tapes[2].operations[7], qml.Hadamard)

        # # fourth layer subcircuit
        assert len(tapes[3].operations) == 13
        assert isinstance(tapes[3].operations[0], qml.RX)
        assert isinstance(tapes[3].operations[1], qml.RY)
        assert isinstance(tapes[3].operations[2], qml.CNOT)
        assert isinstance(tapes[3].operations[3], qml.CNOT)
        assert isinstance(tapes[3].operations[4], qml.RX)
        assert isinstance(tapes[3].operations[5], qml.RY)
        assert isinstance(tapes[3].operations[6], qml.RZ)
        assert isinstance(tapes[3].operations[7], qml.CNOT)
        assert isinstance(tapes[3].operations[8], qml.CNOT)
        # PauliX decomp
        assert isinstance(tapes[3].operations[9], qml.Hadamard)
        # PauliY decomp
        assert isinstance(tapes[3].operations[10], qml.PauliZ)
        assert isinstance(tapes[3].operations[11], qml.S)
        assert isinstance(tapes[3].operations[12], qml.Hadamard)
Exemple #8
0

def circuit(weights, feat=None):
    qml.templates.embeddings.AmplitudeEmbedding(feat,
                                                range(num_qubits),
                                                pad=0.0,
                                                normalize=True)
    for W in weights:
        layer(W)

    return qml.expval(qml.PauliZ(0))


qnodes = []
for iq in range(num_classes):
    qnode = qml.QNode(circuit, dev, interface="torch")
    qnodes.append(qnode)

#################################################################################
# The variational quantum circuit is parametrized by the weights. We use a
# classical bias term that is applied after processing the quantum circuit's
# output. Both variational circuit weights and classical bias term are optimized.


def variational_classifier(q_circuit, params, feat):
    weights = params[0]
    bias = params[1]
    return q_circuit(weights, feat=feat) + bias


##############################################################################
    def test_differentiability_torch(self, qnode, params, ids, nums_frequency,
                                     spectra, shifts, exp_calls, mocker):
        """Tests the reconstruction and differentiability with Torch."""
        torch = pytest.importorskip("torch")
        qnode = qml.QNode(qnode, dev_1, interface="torch")
        params = tuple(
            torch.tensor(par, requires_grad=True, dtype=torch.float64)
            for par in params)
        if spectra is not None:
            spectra = {
                outer_key: {
                    inner_key: torch.tensor(val, dtype=torch.float64)
                    for inner_key, val in outer_val.items()
                }
                for outer_key, outer_val in spectra.items()
            }
        if shifts is not None:
            shifts = {
                outer_key: {
                    inner_key: torch.tensor(val, dtype=torch.float64)
                    for inner_key, val in outer_val.items()
                }
                for outer_key, outer_val in shifts.items()
            }
        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 len(qml.math.shape(x0)) == 0:
                    x0 = x0[inner_key]
                    shift_vec = qml.math.zeros_like(params[outer_key_num])
                    shift_vec = qml.math.scatter_element_add(
                        shift_vec, inner_key, 1.0)
                    mask = torch.ones(qml.math.shape(
                        params[outer_key_num])) - shift_vec
                else:
                    shift_vec = 1.0
                    mask = 0.0
                univariate = lambda x: qnode(
                    *params[:outer_key_num],
                    params[outer_key_num] * mask + x * shift_vec,
                    *params[outer_key_num + 1:],
                )
                exp_qnode_grad = torch.autograd.functional.jacobian(
                    qnode, params)[outer_key_num]

                exp_grad = lambda x: torch.autograd.functional.jacobian(
                    univariate, x)
                grad = lambda x: torch.autograd.functional.jacobian(rec, x)

                assert np.isclose(grad(x0), exp_qnode_grad[inner_key])
                assert np.isclose(grad(x0 + 0.1), exp_grad(x0 + 0.1))
                assert fun_close(grad,
                                 exp_grad,
                                 zero=torch.tensor(0.0, requires_grad=True),
                                 samples=10)
 def SetThermalQNode(self):
     '''
     Set thermal QNode for computation
     of cost function
     '''
     self.ThermalQNode = qml.QNode(self.BasisQNN, self.device)
Exemple #11
0
def main():
    # config.
    reps = 10  # repetições
    steps = 200  # iterações
    lr = 0.1  # learning rate
    batch = 0.1  # batch set size
    val = 0.2  # validation set size
    test = 0.2  # test set size
    verbose = 1  # 0: just final results; 1: prints every iteration

    # template (select one).
    tplt = qubit_hqc  # qubit encoding              + hierarchical quantum classifier
    #tplt = amp_hqc                    # amplitude encoding          + hierarchical quantum classifier
    #tplt = dc_hqc                     # divide-and-conquer encoding + hierarchical quantum classifier

    # dataset (select one).
    X, Y = iris.load([0, 1])
    #X, Y = pima.load()
    #X, Y = banknote_authentication.load()
    #X, Y = haberman.load()

    # parameterized variational circuit.
    circuit = tplt.circuit

    # circuit properties.
    n, N, w, X = tplt.config(X)
    print("n={}, N={}, w={}, x={}".format(n, N, w, len(X)))

    # load a Pennylane plugin device and return the instance.
    dev1 = qml.device("default.qubit", wires=N)

    # splits the data, "reps" times.
    splitted = [
        manipulate.split_data(X, Y, validation_size=val, test_size=test)
        for i in range(reps)
    ]
    batch_size = int(batch * len(splitted[0][0]))
    print("train={}, val={}, test={}, batch={}".format(len(splitted[0][0]),
                                                       len(splitted[0][2]),
                                                       len(splitted[0][4]),
                                                       batch_size))

    # converts "circuit" it into a QNode instance.
    node = qml.QNode(circuit, dev1)

    # randomizes the init weights, "reps" times.
    vars = [
        np.array([*np.random.uniform(low=-np.pi, high=np.pi, size=w), 0.0])
        for i in range(reps)
    ]  # pylint: disable=no-member

    # learn and test, "reps" times.
    best_iters = [
        numpy_interface(node, vars[i], n, lr, steps, batch_size, split[0],
                        split[2], split[4], split[1], split[3], split[5],
                        verbose) for i, split in enumerate(splitted)
    ]

    # print best results.
    print('\nBest iters:')
    for best in best_iters:
        print(
            "Iter:{:5d} | Cost:{:0.7f} | Ac train:{:0.7f} | Ac val:{:0.7f} | Ac test:{:0.7f}"
            "".format(best[0], best[1], best[2], best[3], best[4]))

    print('\nBest bias:')
    for best in best_iters:
        print("Optimized bias: {}".format(best[5][-1]))

    print('\nBest rotation angles:')
    for best in best_iters:
        print("Optimized rotation angles: {}".format(best[5][:-1]))

    # print the quantum circuit (for some reason, it does not print the amplitude encoding).
    print('\n')
    print(node.draw(show_variable_names=True))
Exemple #12
0
 def draw(self):
     circuit = qml.QNode(self.circuit, self.dev)
     circuit(0, 0)
     return circuit.draw()
Exemple #13
0

def circuit(weights, feat=None):
    qml.templates.embeddings.AmplitudeEmbedding(feat,
                                                range(num_qubits),
                                                pad=0.0,
                                                normalize=True)
    for W in weights:
        layer(W)

    return qml.expval(qml.PauliZ(0))


qnodes = []
for iq in range(num_classes):
    qnodes.append(qml.QNode(circuit, dev).to_torch())

#################################################################################
# The variational quantum circuit is parametrized by the weights. We use a
# classical bias term that is applied after processing the quantum circuit's
# output. Both variational circuit weights and classical bias term are optimized.


def variational_classifier(q_circuit, params, feat):
    weights = params[0]
    bias = params[1]
    return q_circuit(weights, feat=feat) + bias


##############################################################################
# Loss Function
def classify_data(X_train, Y_train, X_test):
    """Develop and train your very own variational quantum classifier.

    Use the provided training data to train your classifier. The code you write
    for this challenge should be completely contained within this function
    between the # QHACK # comment markers. The number of qubits, choice of
    variational ansatz, cost function, and optimization method are all to be
    developed by you in this function.

    Args:
        X_train (np.ndarray): An array of floats of size (250, 3) to be used as training data.
        Y_train (np.ndarray): An array of size (250,) which are the categorical labels
            associated to the training data. The categories are labeled by -1, 0, and 1.
        X_test (np.ndarray): An array of floats of (50, 3) to serve as testing data.

    Returns:
        str: The predicted categories of X_test, converted from a list of ints to a
            comma-separated string.
    """

    # Use this array to make a prediction for the labels of the data in X_test
    predictions = []

    # QHACK #

    np.random.seed(0)

    num_classes = 3
    margin = 0.15
    feature_size = 3

    # the number of the required qubits is calculated from the number of features
    num_qubits = int(np.ceil(np.log2(feature_size)))
    num_layers = 2

    dev = qml.device("default.qubit", wires=num_qubits)

    def layer(W):
        for i in range(num_qubits):
            qml.Rot(W[i, 0], W[i, 1], W[i, 2], wires=i)
        for j in range(num_qubits - 1):
            qml.CNOT(wires=[j, j + 1])
        if num_qubits >= 2:
            # Apply additional CNOT to entangle the last with the first qubit
            qml.CNOT(wires=[num_qubits - 1, 0])

    def circuit(weights, feat=None):
        qml.templates.embeddings.AmplitudeEmbedding(feat,
                                                    range(num_qubits),
                                                    pad=0.0,
                                                    normalize=True)
        for W in weights:
            layer(W)

        return qml.expval(qml.PauliZ(0))

    qnodes = []
    for iq in range(num_classes):
        qnode = qml.QNode(circuit, dev)
        qnodes.append(qnode)

    def variational_classifier(q_circuit, params, feat):
        weights = params[0]
        bias = params[1]
        return q_circuit(weights, feat=feat) + bias

    def multiclass_svm_loss(q_circuits, all_params, feature_vecs, true_labels):
        loss = 0
        num_samples = len(true_labels)
        for i, feature_vec in enumerate(feature_vecs):
            # Compute the score given to this sample by the classifier corresponding to the
            # true label. So for a true label of 1, get the score computed by classifer 1,
            # which distinguishes between "class 1" or "not class 1".
            s_true = variational_classifier(
                q_circuits[int(true_labels[i])],
                (all_params[0][int(true_labels[i])], all_params[1][int(
                    true_labels[i])]),
                feature_vec,
            )
            s_true = s_true
            li = 0

            # Get the scores computed for this sample by the other classifiers
            for j in range(num_classes):
                if j != int(true_labels[i]):
                    s_j = variational_classifier(
                        q_circuits[j], (all_params[0][j], all_params[1][j]),
                        feature_vec)
                    s_j = s_j
                    li += max(0, s_j - s_true + margin)
            loss += li

        return loss / num_samples

    def classify(q_circuits, all_params, feature_vecs):
        predicted_labels = []
        for i, feature_vec in enumerate(feature_vecs):
            scores = np.zeros(num_classes)
            for c in range(num_classes):
                score = variational_classifier(
                    q_circuits[c], (all_params[0][c], all_params[1][c]),
                    feature_vec)
                scores[c] = float(score)
            pred_class = np.argmax(scores)
            predicted_labels.append(pred_class)
        return predicted_labels

    all_weights = [(0.1 * np.random.rand(num_layers, num_qubits, 3))
                   for i in range(num_classes)]
    all_bias = [(0.1 * np.ones(1)) for i in range(num_classes)]

    training_params = (all_weights, all_bias)
    q_circuits = qnodes

    opt = qml.AdamOptimizer(stepsize=0.18)

    steps = 12
    cost_tol = 0.008

    Y_train += 1  # To change labels to 0, 1, 2

    for i in range(steps):
        training_params, prev_cost = opt.step_and_cost(
            lambda v: multiclass_svm_loss(q_circuits, v, X_train, Y_train),
            training_params)

        if prev_cost <= cost_tol:
            break

    pred = classify(q_circuits, training_params, X_test)
    pred = [x - 1 for x in pred]  # To get original label

    predictions = pred

    # QHACK #

    return array_to_concatenated_string(predictions)
Exemple #15
0
def run(params, ibm_data=None, **kwargs):
    """Runs a single experiment with a given choice of the hyper-parameters."""

    same_seed = params.pop("same_seed", False)
    if same_seed:
        seed_store = params["seed"]

        if params["dev_ns"] != "ibmq":
            params["seed"] = 0
        else:
            params["seed"] = 17

        if params["circ"] == "hw_friendly":
            params["seed"] = 2

    init_time = time.time()
    params = params.copy()
    np.random.seed(params["seed"])

    ##############################################################################
    # Load devices

    dev = load_device(params, exact=False, ibm_data=ibm_data)
    dev_exact = load_device(params)

    ##############################################################################
    # Define ansatz and quantities of interest

    ansatz = load_ansatz(params)

    # symbolic evaluation of expectation values
    exp_exact = qml.QNode(ansatz, dev_exact, diff_method="parameter-shift")
    exp_sampled = qml.QNode(ansatz, dev, diff_method="parameter-shift")

    # symbolic evaluation of gradients
    # note: argnum=0 corresponds to the full "weights" array
    grad_exact = qml.grad(exp_exact, argnum=0)
    grad_shift = qml.grad(exp_sampled, argnum=0)

    if params["dev_ns"] == "ibmq":
        exp_sampled_old = exp_sampled

        def exp_sampled(*args, **kwargs):
            """Wrapped exp_sampled to try again when there are timeouts."""
            finished = False

            while not finished:
                try:
                    res = exp_sampled_old(*args, **kwargs)
                    finished = True
                except:
                    pass

            return res

    ##############################################################################
    # Evaluate quantities
    w = load_weights(params)
    result = {}

    np.random.seed()

    # expectation values
    if params.pop("log_exp", False):
        e_exact = exp_exact(w)
        e_sampled = exp_sampled(w)

        result["exp_e"] = e_exact
        result["exp_s"] = e_sampled

    if params.pop("log_g_ex", False):
        g_exact = grad_exact(w)
        result["g_ex"] = g_exact.tolist()

    if params.pop("log_g_sh", False):
        g_shift = grad_shift(w)
        result["g_sh"] = g_shift.tolist()

    eval_grads(params, w, exp_sampled, result)
    eval_hess(params, w, exp_sampled, result)

    ##############################################################################
    # Output results
    result["time"] = time.strftime("%Y%m%d-%H%M%S")
    result["rtime"] = time.time() - init_time

    if same_seed:
        params["seed"] = seed_store

    return {**params, **result}
    qml.CZ(wires=[0, 1])
    qml.CZ(wires=[1, 2])
    qml.CZ(wires=[1, 3])

    for i in range(n_wires):
        qml.Rot(*params[0, 1, i], wires=i)
    return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)), qml.expval(
        qml.PauliZ(2))


##############################################################################
# We finally combine the two devices into a :class:`~.pennylane.QNodeCollection` that uses the
# PyTorch interface:

qnodes = qml.QNodeCollection([
    qml.QNode(circuit0, dev0, interface="torch"),
    qml.QNode(circuit1, dev1, interface="torch")
])

##############################################################################
# Postprocessing into a prediction
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#
# The ``predict_point`` function below allows us to find the ensemble prediction, as well as keeping
# track of the individual predictions from each QPU.
#
# We include a ``parallel`` keyword argument for evaluating the :class:`~.pennylane.QNodeCollection`
# in a parallel asynchronous manner. This feature requires the ``dask`` library, which can be
# installed using ``pip install "dask[delayed]"``. When ``parallel=True``, we are able to make
# predictions faster because we do not need to wait for one QPU to output before running on the
# other.
Exemple #17
0
def global_cost_simple(rotations):
    for i in range(wires):
        qml.RX(rotations[0][i], wires=i)
        qml.RY(rotations[1][i], wires=i)
    return qml.probs(wires=range(wires))


def local_cost_simple(rotations):
    for i in range(wires):
        qml.RX(rotations[0][i], wires=i)
        qml.RY(rotations[1][i], wires=i)
    return [qml.probs(wires=i) for i in range(wires)]


global_circuit = qml.QNode(global_cost_simple, dev)

local_circuit = qml.QNode(local_cost_simple, dev)


def cost_local(rotations):
    return 1 - np.sum(local_circuit(rotations)[:, 0]) / wires


def cost_global(rotations):
    return 1 - global_circuit(rotations)[0]


######################################################################
# To analyze each of the circuits, we provide some random initial
# parameters for each rotation.

## ZZ connections, Single X, Single Z

layer_language = {'ZZ': zz_layer, 'X': x_layer, 'Y': y_layer}
depth = 4
nqubits = 3
num_y_labels = 3
assert nqubits >= num_y_labels, f"nqubits must be larger than {nqubits}, since num_y_labels = {num_y_labels}"
dev = qml.device("default.qubit", wires=nqubits)

n_architecures = 0
for architecture in it.product(('ZZ', 'X', 'Y'), repeat=depth):
    print(architecture)
    init_params = np.ones((nqubits, depth))
    if non_commuting_check(architecture):
        n_architecures += 1


    def circuit_from_architecture(params):
        for d, component in enumerate(architecture):
            layer_language[component](list(range(nqubits)), params[:, d])
        return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1)), qml.expval(qml.PauliZ(2))


    circuit = qml.QNode(circuit_from_architecture, dev)
    print(circuit(init_params))
print(n_architecures)
## Monte Carlo Tree Search this space of possible architectures
## Start with identity circuit
    def test_differentiability_tensorflow(self, qnode, params, ids,
                                          nums_frequency, spectra, shifts,
                                          exp_calls, mocker):
        """Tests the reconstruction and differentiability with TensorFlow."""
        if qnode == qnode_4:
            pytest.skip(
                "Gradients are empty in TensorFlow for independent functions.")
        tf = pytest.importorskip("tensorflow")
        qnode = qml.QNode(qnode, dev_1, interface="tf")
        params = tuple(tf.Variable(par, dtype=tf.float64) for par in params)
        if spectra is not None:
            spectra = {
                outer_key: {
                    inner_key: tf.constant(val, dtype=tf.float64)
                    for inner_key, val in outer_val.items()
                }
                for outer_key, outer_val in spectra.items()
            }
        if shifts is not None:
            shifts = {
                outer_key: {
                    inner_key: tf.constant(val, dtype=tf.float64)
                    for inner_key, val in outer_val.items()
                }
                for outer_key, outer_val in shifts.items()
            }
        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():
                if outer_key == "Z" and inner_key == (1, 3):
                    # This is a constant function dependence, which can
                    # not be properly resolved by this test.
                    continue
                x0 = params[outer_key_num]
                if not len(qml.math.shape(x0)) == 0:
                    x0 = x0[inner_key]
                    shift_vec = qml.math.zeros_like(params[outer_key_num])
                    shift_vec = qml.math.scatter_element_add(
                        shift_vec, inner_key, 1.0)
                    mask = pnp.ones(qml.math.shape(
                        params[outer_key_num])) - shift_vec
                else:
                    shift_vec = 1.0
                    mask = 0.0
                univariate = lambda x: qnode(
                    *params[:outer_key_num],
                    params[outer_key_num] * mask + x * shift_vec,
                    *params[outer_key_num + 1:],
                )
                with tf.GradientTape() as tape:
                    out = qnode(*params)
                exp_qnode_grad = tape.gradient(out, params[outer_key_num])

                def exp_grad(x):
                    x = tf.Variable(x, dtype=tf.float64)
                    with tf.GradientTape() as tape:
                        out = univariate(x)
                    return tape.gradient(out, x)

                def grad(x):
                    x = tf.Variable(x, dtype=tf.float64)
                    with tf.GradientTape() as tape:
                        out = rec(x)
                    return tape.gradient(out, x)

                if nums_frequency is None:
                    # Gradient evaluation at reconstruction point not supported for
                    # Dirichlet reconstruction
                    assert np.isclose(grad(x0), exp_qnode_grad[inner_key])
                assert np.isclose(grad(x0 + 0.1), exp_grad(x0 + 0.1))
                assert fun_close(grad, exp_grad, 10)
Exemple #20
0
    for dt in times_sampled:
        result = qgrnn_qnode(weight_params, bias_params, time=dt)
        total_cost += -1 * result

    return total_cost / N


######################################################################
# Next we set up for optimization.
#

# Defines the new device
qgrnn_dev = qml.device("default.qubit", wires=2 * qubit_number + 1)

# Defines the new QNode
qgrnn_qnode = qml.QNode(qgrnn, qgrnn_dev)

steps = 300

optimizer = qml.AdamOptimizer(stepsize=0.5)

weights = rng.random(size=len(new_ising_graph.edges)) - 0.5
bias = rng.random(size=qubit_number) - 0.5

initial_weights = copy.copy(weights)
initial_bias = copy.copy(bias)

######################################################################
# All that remains is executing the optimization loop.

for i in range(0, steps):
Exemple #21
0
forward_shift = []
gradient_shift = []
forward_backprop = []
gradient_backprop = []

for depth in range(0, 21):
    params = qml.init.strong_ent_layers_normal(n_wires=4, n_layers=depth)
    num_params = params.size
    params = tf.Variable(params)

    # forward pass timing
    # ===================

    qnode_shift = qml.QNode(circuit,
                            dev,
                            interface="tf",
                            diff_method="parameter-shift",
                            mutable=False)
    qnode_backprop = qml.QNode(circuit,
                               dev,
                               interface="tf",
                               diff_method="backprop",
                               mutable=False)

    # parameter-shift
    t = timeit.repeat("qnode_shift(params)",
                      globals=globals(),
                      number=num,
                      repeat=reps)
    forward_shift.append([num_params, min(t) / num])
Exemple #22
0
number = 3

forward_shift = []
gradient_shift = []
forward_backprop = []
gradient_backprop = []

for depth in range(0, 21):
    params = qml.init.strong_ent_layers_normal(n_wires=4, n_layers=depth)
    num_params = params.size
    params = tf.Variable(params)

    # forward pass timing
    # ===================

    qnode_shift = qml.QNode(circuit, dev_shift, interface="tf", mutable=False)
    qnode_backprop = qml.QNode(circuit, dev_backprop, interface="tf")

    # parameter-shift
    t = timeit.repeat("qnode_shift(params)",
                      globals=globals(),
                      number=number,
                      repeat=repeat)
    forward_shift.append([num_params, min(t) / number])

    # backprop
    t = timeit.repeat("qnode_backprop(params)",
                      globals=globals(),
                      number=number,
                      repeat=repeat)
    forward_backprop.append([num_params, min(t) / number])
Exemple #23
0
    def test_four_qubit_random_circuit(self, device, tol):
        """Test a four-qubit random circuit with the whole set of possible gates"""
        n_wires = 4
        dev = device(n_wires)
        dev_def = qml.device("default.qubit", wires=n_wires)

        if dev.name == dev_def.name:
            pytest.skip("Device is default.qubit.")

        if not dev.analytic:
            pytest.skip("Device is in non-analytical mode.")

        gates = [
            qml.PauliX,
            qml.PauliY,
            qml.PauliZ,
            qml.S,
            qml.T,
            qml.RX,
            qml.RY,
            qml.RZ,
            qml.Hadamard,
            qml.Rot,
            qml.CRot,
            qml.Toffoli,
            qml.SWAP,
            qml.CSWAP,
            qml.U1,
            qml.U2,
            qml.U3,
            qml.CRX,
            qml.CRY,
            qml.CRZ,
        ]

        layers = 3
        np.random.seed(1967)
        gates_per_layers = [
            np.random.permutation(gates).numpy() for _ in range(layers)
        ]

        def circuit():
            """4-qubit circuit with layers of randomly selected gates and random connections for
            multi-qubit gates."""
            np.random.seed(1967)
            for gates in gates_per_layers:
                for gate in gates:
                    params = list(np.pi * np.random.rand(gate.num_params))
                    rnd_wires = np.random.choice(range(n_wires),
                                                 size=gate.num_wires,
                                                 replace=False)
                    gate(
                        *params,
                        wires=[
                            int(w) for w in rnd_wires
                        ]  # make sure we do not address wires as 0-d arrays
                    )
            return qml.expval(qml.PauliZ(0))

        qnode_def = qml.QNode(circuit, dev_def)
        qnode = qml.QNode(circuit, dev)

        assert np.allclose(qnode(), qnode_def(), atol=tol(dev.analytic))
Exemple #24
0
    # Prepares the variational ansatz for the circuit
    for i in range(0, depth):
        single_rotation(rotation_params[i], range(nr_qubits))
        qml.broadcast(
            unitary=qml.CRX, 
            pattern="ring", 
            wires=range(nr_qubits), 
            parameters=coupling_params[i]
        )

    # Calculates the expectation value of the Hamiltonian with respect to the prepared states
    return qml.expval(qml.Hermitian(ham_matrix, wires=range(nr_qubits)))


# Constructs the QNode
qnode = qml.QNode(quantum_circuit, dev)


######################################################################
# We can get an idea of what this circuit looks like by printing out a
# test circuit:
#


rotation_params = [[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]] for i in range(0, depth)]
coupling_params = [[1, 1, 1, 1] for i in range(0, depth)]
results = qnode(rotation_params, coupling_params, sample=[1, 0, 1, 0])
print(qnode.draw())


######################################################################
Exemple #25
0
    def test_evaluate_diag_approx_metric_tensor(self, sample_circuit, tol):
        """Test that a metric tensor under the
        diagonal approximation evaluates correctly."""
        dev, circuit, non_parametrized_layer, a, b, c = sample_circuit
        params = [-0.282203, 0.145554, 0.331624, -0.163907, 0.57662, 0.081272]
        x, y, z, h, g, f = params

        G = circuit.metric_tensor(*params, diag_approx=True)

        # ============================================
        # Test block diag metric tensor of first layer is correct.
        # We do this by comparing against the known analytic result.
        # First layer includes the non_parametrized_layer,
        # followed by observables corresponding to generators of:
        #   qml.RX(x, wires=0)
        #   qml.RY(y, wires=1)
        #   qml.RZ(z, wires=2)

        G1 = np.zeros([3, 3])

        # diag elements
        G1[0, 0] = np.sin(a)**2 / 4
        G1[1,
           1] = (16 * np.cos(a)**2 * np.sin(b)**3 * np.cos(b) * np.sin(2 * c) +
                 np.cos(2 * b) *
                 (2 - 8 * np.cos(a)**2 * np.sin(b)**2 * np.cos(2 * c)) +
                 np.cos(2 * (a - b)) + np.cos(2 * (a + b)) -
                 2 * np.cos(2 * a) + 14) / 64
        G1[2,
           2] = (3 - np.cos(2 * a) - 2 * np.cos(a)**2 * np.cos(2 *
                                                               (b + c))) / 16

        assert np.allclose(G[:3, :3], G1, atol=tol, rtol=0)

        # =============================================
        # Test block diag metric tensor of second layer is correct.
        # We do this by computing the required expectation values
        # numerically using multiple circuits.
        # The second layer includes the non_parametrized_layer,
        # RX, RY, RZ gates (x, y, z params), and a 2nd non_parametrized_layer.
        #
        # Observables are the generators of:
        #   qml.RY(f, wires=1)
        #   qml.RZ(g, wires=2)
        G2 = np.zeros([2, 2])

        def layer2_diag(x, y, z, h, g, f):
            non_parametrized_layer(a, b, c)
            qml.RX(x, wires=0)
            qml.RY(y, wires=1)
            qml.RZ(z, wires=2)
            non_parametrized_layer(a, b, c)
            return qml.var(qml.PauliZ(2)), qml.var(qml.PauliY(1))

        layer2_diag = qml.QNode(layer2_diag, dev)

        # calculate the diagonal terms
        varK0, varK1 = layer2_diag(x, y, z, h, g, f)
        G2[0, 0] = varK0 / 4
        G2[1, 1] = varK1 / 4

        assert np.allclose(G[4:6, 4:6], G2, atol=tol, rtol=0)

        # =============================================
        # Test metric tensor of third layer is correct.
        # We do this by computing the required expectation values
        # numerically.
        # The third layer includes the non_parametrized_layer,
        # RX, RY, RZ gates (x, y, z params), a 2nd non_parametrized_layer,
        # followed by the qml.RY(f, wires=2) operation.
        #
        # Observable is simply generator of:
        #   qml.RY(f, wires=2)
        #
        # Note: since this layer only consists of a single parameter,
        # only need to compute a single diagonal element.

        def layer3_diag(x, y, z, h, g, f):
            non_parametrized_layer(a, b, c)
            qml.RX(x, wires=0)
            qml.RY(y, wires=1)
            qml.RZ(z, wires=2)
            non_parametrized_layer(a, b, c)
            qml.RY(f, wires=2)
            return qml.var(qml.PauliX(1))

        layer3_diag = qml.QNode(layer3_diag, dev)
        G3 = layer3_diag(x, y, z, h, g, f) / 4
        assert np.allclose(G[3:4, 3:4], G3, atol=tol, rtol=0)

        # ============================================
        # Finally, double check that the entire metric
        # tensor is as computed.

        G_expected = block_diag(G1, G3, G2)
        assert np.allclose(G, G_expected, atol=tol, rtol=0)
    for i in range(num_qubits - 1):
        qml.CZ(wires=[i, i + 1])

    H = np.zeros((2**num_qubits, 2**num_qubits))
    H[0, 0] = 1
    wirelist = [i for i in range(num_qubits)]
    return qml.expval(qml.Hermitian(H, wirelist))


############################################################
# Now we can compute the gradient and calculate the variance.
# While we only take 200 samples to allow the code to run in
# a reasonable amount of time, this can be increased
# for more accurate results.

qcircuit = qml.QNode(rand_circuit, dev)
grad = qml.grad(qcircuit, argnum=0)

num_samples = 200
grad_vals = []

for i in range(num_samples):
    params = np.random.uniform(0, 2 * np.pi, size=num_qubits)
    grad_vals.append(
        grad(params, random_gate_sequence=gate_sequence,
             num_qubits=num_qubits))

print("Variance of the gradient for {} samples: {}".format(
    num_samples, np.var(grad_vals)))

###########################################################
    for n in range(3, 0, -1):
        qml.Hadamard(wires=('wire' + str(n)))
        for k in range(n - 1, 0, -1):
            b = n - 1
            U = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0],
                          [0, 0, 0,
                           np.exp((np.pi / float(2**(n - k))) * 1j)]])
            qml.QubitUnitary(U,
                             wires=[('wire' + str(k)), ('wire' + str(b + 1))])

    qml.SWAP(wires=['wire1', 'wire3'])

    return qml.probs(wires=['wire3', 'wire2', 'wire1'])


circuit1 = qml.QNode(qft_3, dev1)
circuit1()

prob_dict = generate_prob_dict(circuit1())

print(prob_dict)

# In[363]:

print(circuit1.draw())

# In[364]:

# Part B.2

dev2 = qml.device('default.qubit',
#os.environ['KMP_DUPLICATE_LIB_OK']='True'

p = 1  # Number of QAOA REPETITIONS
path = path = "Graphs/"
graphs = graph_loader(path, 6)
G = new_G(graphs[-1])

n_random = 200  # number of random seeds

dev1 = qml.device('default.qubit.tf', wires=len(G.nodes))
dev2 = qml.device('default.qubit',
                  wires=len(G.nodes),
                  analytic=False,
                  shots=500)

qcircuit = qml.QNode(circuit, dev1, interface="tf", diff_method="backprop")
qcircuit_stat = qml.QNode(circuit_stat,
                          dev1,
                          interface="tf",
                          diff_method="backprop")

# ------------------------- RANDOM INITIALIZATIONS ----------------------------
gammas = 7 * np.random.rand(n_random, p)
betas = 7 * np.random.rand(n_random, p)
print(gammas, betas)
# We only have to do this once!
Energies, configs = get_energies_of_all_strings(gammas[0],
                                                betas[0],
                                                qcircuit,
                                                G=G,
                                                p=p)
Exemple #29
0
# We can use ``qml.Hermitian`` to directly specify that we want to measure
# the expectation value of the matrix :math:`H`:

H = np.array([[8, 4, 0, -6], [4, 0, 4, 0], [0, 4, 8, 0], [-6, 0, 0, 0]])


def circuit(params):
    StronglyEntanglingLayers(weights=params, wires=[0, 1])
    return expval(qml.Hermitian(H, wires=[0, 1]))


##############################################################################
# Now, we create three QNodes, each corresponding to a device above,
# and optimize them using gradient descent via the parameter-shift rule.

qnode_analytic = qml.QNode(circuit, dev_analytic)
qnode_stochastic = qml.QNode(circuit, dev_stochastic)

init_params = strong_ent_layers_uniform(num_layers, num_wires)

# Optimizing using exact gradient descent

cost_GD = []
params_GD = init_params
opt = qml.GradientDescentOptimizer(eta)

for _ in range(steps):
    cost_GD.append(qnode_analytic(params_GD))
    params_GD = opt.step(qnode_analytic, params_GD)

# Optimizing using stochastic gradient descent with shots=1
Exemple #30
0
#################################################################################
# We now define the quantum nodes that will be used. As we are implementing our
# multiclass classifier as multiple one-vs-all classifiers, we will use 3 QNodes,
# each representing one such classifier. That is, ``circuit1`` classifies if a
# sample belongs to class 1 or not, and so on. The circuit architecture for all
# 3 nodes are the same. We use the PyTorch interface for the QNodes.
# Data is embedded in each circuit using amplitude embedding:

def circuit(weights, feat=None):
    qml.templates.embeddings.AmplitudeEmbedding(feat, [0, 1], pad=0.0, normalize=True)
    for W in weights:
        layer(W)
    return qml.expval(qml.PauliZ(0))

qnode1 = qml.QNode(circuit, dev).to_torch()
qnode2 = qml.QNode(circuit, dev).to_torch()
qnode3 = qml.QNode(circuit, dev).to_torch()


#################################################################################
# The variational quantum circuit is parametrized by the weights. We use a
# classical bias term that is applied after processing the quantum circuit's
# output. Both variational circuit weights and classical bias term are optimized.

def variational_classifier(q_circuit, params, feat):
    weights = params[0]
    bias = params[1]
    return q_circuit(weights, feat=feat) + bias