예제 #1
0
 def __init__(self,
              env,
              qnode,
              params,
              alpha=0.1,
              gamma=0.9,
              epsilon_max=1.0,
              epsilon_min=0.2,
              epsilon_halflife=10,
              memory_size=100000,
              memory_sampling=10,
              update_freq=100):
     self.env = env
     self.learner = qnode
     self.params = np.array(params, requires_grad=True)
     self.actions = [0, 1, 2, 3]
     self.alpha = alpha
     self.gamma = gamma
     self.opt = qml.NesterovMomentumOptimizer(self.alpha)
     self.epsilon_max = epsilon_max
     self.epsilon_min = epsilon_min
     self.epsilon_halflife = epsilon_halflife
     self.visits = {}
     self.training = True
     self.memory_size = memory_size
     self.memory_sampling = memory_sampling
     self.memory_table = []
     self.update_freq = 100
     self.counter = 0
예제 #2
0
def QAOA(n_layers=1, verbose=False):
    """ Quantum Approximation Optimization Algorithm:
        Uses a Nesterov Momentum optimizer to variate the hyperparameters theta (one per gate Rx, Rz and layer)
        to minimize the cost 1 - F.
    """
    init_params = 2*np.pi * \
        np.random.rand(
            2, n_layers, n_wires)  # Possible improvement: limit params. to [0, 2pi) (due to periodicity)

    def cost(params):
        thetaEven_s = params[0]
        thetaOdd_s = params[1]
        return (1 -
                np.sqrt(circuit(thetaEven_s, thetaOdd_s, n_layers=n_layers)))

    # itialize optimizer: Nesterov with momentum chosen after trying various
    opt = qml.NesterovMomentumOptimizer(stepsize=0.02, momentum=0.9)

    losses = []

    # optimize parameters in cost
    params = init_params
    for i in range(steps):
        params = opt.step(cost, params)
        loss = cost(params)
        losses.append(loss)
        if verbose == True:
            if (i + 1) % 5 == 0:
                print("Objective after step {:5d}: {: .7f}".format(
                    i + 1, loss))
    print(f"Layer architecture {0} finished".format(n_layers))
    return losses
예제 #3
0
def find_max_independent_set(graph, params):
    """Find the maximum independent set of an input graph given some optimized QAOA parameters.

    The code you write for this challenge should be completely contained within this function
    between the # QHACK # comment markers. You should create a device, set up the QAOA ansatz circuit
    and measure the probabilities of that circuit using the given optimized parameters. Your next
    step will be to analyze the probabilities and determine the maximum independent set of the
    graph. Return the maximum independent set as an ordered list of nodes.

    Args:
        graph (nx.Graph): A NetworkX graph
        params (np.ndarray): Optimized QAOA parameters of shape (2, 10)

    Returns:
        list[int]: the maximum independent set, specified as a list of nodes in ascending order
    """
    cost_h, mixer_h = qaoa.max_independent_set(graph)

    def qaoa_layer(gamma, alpha):
        qaoa.cost_layer(gamma, cost_h)
        qaoa.mixer_layer(alpha, mixer_h)

    def circuit(params, **kwargs):
        for w in range(NODES):
            qml.Hadamard(wires=w)

        qml.layer(qaoa_layer, N_LAYERS, params[0], params[1])

    dev = qml.device('default.qubit', wires=NODES)
    cost_function = qml.ExpvalCost(circuit, cost_h, dev)

    optimizer = qml.NesterovMomentumOptimizer()

    for i in range(3):
        params = optimizer.step(cost_function, params)

    @qml.qnode(dev)
    def probability_circuit(gamma, alpha):
        circuit([gamma, alpha])
        return qml.probs(wires=[x for x in range(NODES)])

    probs = probability_circuit(params[0], params[1])
    most_freq_bit_string = np.argmax(probs)
    result = []
    for i in reversed(range(NODES)):
        if most_freq_bit_string & (1 << i) != 0:
            result.append(NODES - 1 - i)

    return result
예제 #4
0
def train(weights, wires, X, Y, steps, batch_size, k):
    #opt = qml.GradientDescentOptimizer(0.1)
    opt = qml.NesterovMomentumOptimizer(0.1)

    for _ in range(steps):
        batch_idx = np.random.randint(0, len(X), (batch_size,))

        X_batch = X[batch_idx]
        Y_batch = Y[batch_idx]

        weights, prev_cost = opt.step_and_cost(lambda weights: cost(weights, wires, X_batch, Y_batch, k), weights)
        print(prev_cost)
        #print(weights)

    opt_cost = cost(weights, wires, X, Y, k)
    print(opt_cost)

    return weights
예제 #5
0
def optimize_circuit(params):
    """Minimize the variational circuit and return its minimum value.

    The code you write for this challenge should be completely contained within this function
    between the # QHACK # comment markers. You should create a device and convert the
    variational_circuit function into an executable QNode. Next, you should minimize the variational
    circuit using gradient-based optimization to update the input params. Return the optimized value
    of the QNode as a single floating-point number.

    Args:
        params (np.ndarray): Input parameters to be optimized, of dimension 30

    Returns:
        float: the value of the optimized QNode
    """

    optimal_value = 0.0

    # QHACK #

    # Initialize the device
    # dev = ...

    # Instantiate the QNode
    dev = qml.device('default.qubit', wires=WIRES)

    circuit = qml.QNode(variational_circuit, dev)

    gd_cost = []
    opt = qml.NesterovMomentumOptimizer(stepsize=0.07)

    for _ in range(60):
        params = opt.step(circuit, params)
        gd_cost.append(circuit(params))

    # Minimize the circuit
    optimal_value = circuit(params)

    # QHACK #

    # Return the value of the minimized QNode
    return optimal_value
예제 #6
0
def train_circuit(num_vertices, H):
    """Trains a quantum circuit to learn the ground state of the UDMIS Hamiltonian.

    Args:
        - num_vertices (int): The number of vertices/wires in the graph
        - H (qml.Hamiltonian): The result of qml.Hamiltonian(coeffs, obs)

    Returns:
        - E / num_vertices (float): The ground state energy density.
    """

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

    @qml.qnode(dev)
    def cost(params):
        """The energy expectation value of a Hamiltonian"""
        variational_circuit(params, num_vertices)
        return qml.expval(H)

    # QHACK #

    # define your trainable parameters and optimizer here
    # change the number of training iterations, `epochs`, if you want to
    # just be aware of the 80s time limit!

    epochs = 500  # number of training iterations
    num_layers = 2  # number of layers is variational quantum circuit
    params = np.ones([num_layers, num_vertices, 3])  # initial guess
    opt = qml.NesterovMomentumOptimizer()  # optimiser

    # QHACK #

    for i in range(epochs):
        params, E = opt.step_and_cost(cost, params)

    return E / float(num_vertices)
예제 #7
0
def classify_ising_data(ising_configs, labels):
    """Learn the phases of the classical Ising model.

    Args:
        - ising_configs (np.ndarray): 250 rows of binary (0 and 1) Ising model configurations
        - labels (np.ndarray): 250 rows of labels (1 or -1)

    Returns:
        - predictions (list(int)): Your final model predictions

    Feel free to add any other functions than `cost` and `circuit` within the "# QHACK #" markers 
    that you might need.
    """

    # QHACK #

    num_wires = ising_configs.shape[1]
    dev = qml.device("default.qubit", wires=num_wires)

    # Define a variational circuit below with your needed arguments and return something meaningful
    @qml.qnode(dev)
    def circuit(params, ising_config):
        """ Variational quantum circuit """
        # data encoding
        qml.BasisState(ising_config, wires=range(num_wires))

        # variational quantum circuit
        for i in range(len(params)):
            for j in range(num_wires):
                qml.Rot(*params[i][j], wires=j)
            for j in range(num_wires - 1):
                qml.CNOT(wires=(j, j + 1))
            qml.CNOT(wires=(num_wires - 1, 0))

        # Return NN parity of entire spin chain
        # parity = [qml.PauliZ(i) for i in range(num_wires)]
        # parity = qml.operation.Tensor(*parity)
        # return qml.expval(parity)

        # return [qml.expval(qml.PauliZ(i) @ qml.PauliZ(i+1)) for i in range(num_wires-1)]
        return [qml.expval(qml.PauliZ(i)) for i in range(num_wires)]

    def variational_classifier(params, bias, ising_config):
        """ Decodes the quantum circuit output into a classification """
        magnetisation = np.sum(circuit(params, ising_config))
        return magnetisation + bias

    # Define a cost function below with your needed arguments
    def cost(params, bias, X, Y):

        # QHACK #

        # Insert an expression for your model predictions here
        predictions = [variational_classifier(params, bias, x) for x in X]

        # QHACK #

        return square_loss(Y, predictions)  # DO NOT MODIFY this line

    # optimize your circuit here
    opt = qml.NesterovMomentumOptimizer()
    batch_size = 5  # number of ising_configs to train on in each iter
    num_layers = 3  # number of mixing layers in variational quantum circuit
    params = np.ones([num_layers, num_wires, 3])  # initial guess
    bias = np.array(0.0)  # initial guess
    for i in range(100):  # iteratively optimise
        batch_index = np.random.randint(0, len(labels), (batch_size, ))
        X = ising_configs[batch_index]
        Y = labels[batch_index]
        params, bias, _, _ = opt.step(cost, params, bias, X, Y)

    # make predictions w/ optimised circuit
    predictions = []
    for ising_config in ising_configs:
        predict = variational_classifier(params, bias, ising_config)
        predictions.append(int(np.sign(predict)))

    # QHACK #

    return predictions