Module qose.circuit_utils

Expand source code
import pennylane as qml
from pennylane import numpy as np
from qose.featuremaps import *


def cycle_CNOT_layer(wires):
    """

    Args:
      wires: 

    Returns:

    """
    nq = len(wires)
    for n in range(nq - 1):
        qml.CNOT(wires=[n, n + 1])
    qml.CNOT(wires=[nq - 1, 0])


def path_CNOT_layer(wires):
    """

    Args:
      wires: 

    Returns:

    """
    nq = len(wires)
    for n in range(nq - 1):
        qml.CNOT(wires=[n, n + 1])


def zz_layer(wires, params):
    """

    Args:
      wires: 
      params: 

    Returns:

    """
    nq = len(wires)
    for n in range(nq - 1):
        zz_gate([n, n + 1], params[n])
    zz_gate([nq - 1, 0], params[nq - 1])


def zz_gate(wires, gamma):
    """

    Args:
      wires: 
      gamma: 

    Returns:

    """
    qml.CNOT(wires=wires)
    qml.RZ(gamma, wires=wires[1])
    qml.CNOT(wires=wires)


def x_layer(wires, params):
    """

    Args:
      wires: 
      params: 

    Returns:

    """
    nqubits = len(wires)
    for n in range(nqubits):
        qml.RX(params[n], wires=[n, ])


def z_layer(wires, params):
    """

    Args:
      wires: 
      params: 

    Returns:

    """
    nqubits = len(wires)
    for n in range(nqubits):
        qml.RZ(params[n], wires=[n, ])


def y_layer(wires, params):
    """

    Args:
      wires: 
      params: 

    Returns:

    """
    nqubits = len(wires)
    for n in range(nqubits):
        qml.RY(params[n], wires=[n, ])


def embedding_1(X, wires, fill='redundant'):
    """

    Args:
      X: 
      wires: 
      fill:  (Default value = 'redundant')

    Returns:

    """
    if len(X) < len(wires):
        r_ = len(wires) // len(X)
        if fill == 'redundant':
            large_features = np.tile(X, r_)
        elif fill == 'pad':
            large_features = np.pad(X, (0, len(wires)), 'constant', constant_values=0)
        qml.templates.embeddings.AngleEmbedding(large_features, wires=wires, rotation='Y')
    else:
        qml.templates.embeddings.AngleEmbedding(X, wires=wires, rotation='Y')


def embedding_2(X, wires):
    """

    Args:
      X: 
      wires: 

    Returns:

    """
    qml.templates.embeddings.AmplitudeEmbedding(X, wires=wires, pad=0, normalize=True)

def construct_circuit_from_leaf(leaf: str, nqubits: int, nclasses: int, dev: qml.Device, config: dict):
    """Construct a Qnode specified by the architecture in the leaf. This includes an embedding layer as first layer.

    Args:
      leaf: String that corresponds to a leaf in the tree.
      nqubits: The number of qubits in the circuit.
      nclasses: The number of classes in the circuit.
      dev: PennyLane Device.

    Returns:
      QNode corresponding to the circuit.

    """
    architecture = leaf.split(':')

    # The first layer must be an embedding layer
    embedding_circuit = architecture.pop(0)

    def circuit_from_architecture(params, features):
        """

        Args:
          params: 
          features: 

        Returns:

        """
        # lookup the function in the embedding dict, call with features being passed.
        string_to_embedding_mapping[embedding_circuit](features, dev.wires)
        # for each layer, lookup the function in the layer dict, call with parameters being passed.
        for d, component in enumerate(architecture):
            if component == 'hw_CNOT':
                string_to_layer_mapping[component](list(range(nqubits)))
            else:
                string_to_layer_mapping[component](list(range(nqubits)), params[:, d])
        # return an expectation value for each class so we can compare with one hot encoded labels.
        return [qml.expval(qml.PauliZ(nc)) for nc in range(nclasses)]

    # Return the shape of the parameters so we can initialize them correctly later on.
    if config['circuit_type'] == 'schuld':
        params_shape = (nqubits, len(architecture))
        numcnots = architecture.count('ZZ') * 2 * nqubits  # count the number of cnots
    elif config['circuit_type'] == 'hardware':
        param_gates = [x for x in architecture if x != 'CNOT']
        params_shape = (nqubits, len(param_gates))
        params_shape = (nqubits, len(architecture))
        numcnots = architecture.count('CNOT') * (nqubits - 1)  # Each CNOT layer has (n-1) CNOT gates
    # create and return a QNode
    return qml.QNode(circuit_from_architecture, dev), params_shape, numcnots  # give back the number of cnots

string_to_layer_mapping = {'ZZ': zz_layer, \
                           'X': x_layer, 'Y': y_layer, 'Z': z_layer, \
                           'hw_CNOT': path_CNOT_layer}
string_to_embedding_mapping = {'E1': embedding_1, 'E2': embedding_2, 'E3': qaoa, 'E4': XXZ, 'E5': aspuru,
                               'E6': random_embed}

Functions

def construct_circuit_from_leaf(leaf: str, nqubits: int, nclasses: int, dev: pennylane._device.Device, config: dict)

Construct a Qnode specified by the architecture in the leaf. This includes an embedding layer as first layer.

Args

leaf
String that corresponds to a leaf in the tree.
nqubits
The number of qubits in the circuit.
nclasses
The number of classes in the circuit.
dev
PennyLane Device.

Returns

QNode corresponding to the circuit.

Expand source code
def construct_circuit_from_leaf(leaf: str, nqubits: int, nclasses: int, dev: qml.Device, config: dict):
    """Construct a Qnode specified by the architecture in the leaf. This includes an embedding layer as first layer.

    Args:
      leaf: String that corresponds to a leaf in the tree.
      nqubits: The number of qubits in the circuit.
      nclasses: The number of classes in the circuit.
      dev: PennyLane Device.

    Returns:
      QNode corresponding to the circuit.

    """
    architecture = leaf.split(':')

    # The first layer must be an embedding layer
    embedding_circuit = architecture.pop(0)

    def circuit_from_architecture(params, features):
        """

        Args:
          params: 
          features: 

        Returns:

        """
        # lookup the function in the embedding dict, call with features being passed.
        string_to_embedding_mapping[embedding_circuit](features, dev.wires)
        # for each layer, lookup the function in the layer dict, call with parameters being passed.
        for d, component in enumerate(architecture):
            if component == 'hw_CNOT':
                string_to_layer_mapping[component](list(range(nqubits)))
            else:
                string_to_layer_mapping[component](list(range(nqubits)), params[:, d])
        # return an expectation value for each class so we can compare with one hot encoded labels.
        return [qml.expval(qml.PauliZ(nc)) for nc in range(nclasses)]

    # Return the shape of the parameters so we can initialize them correctly later on.
    if config['circuit_type'] == 'schuld':
        params_shape = (nqubits, len(architecture))
        numcnots = architecture.count('ZZ') * 2 * nqubits  # count the number of cnots
    elif config['circuit_type'] == 'hardware':
        param_gates = [x for x in architecture if x != 'CNOT']
        params_shape = (nqubits, len(param_gates))
        params_shape = (nqubits, len(architecture))
        numcnots = architecture.count('CNOT') * (nqubits - 1)  # Each CNOT layer has (n-1) CNOT gates
    # create and return a QNode
    return qml.QNode(circuit_from_architecture, dev), params_shape, numcnots  # give back the number of cnots
def cycle_CNOT_layer(wires)

Args

wires
 

Returns:

Expand source code
def cycle_CNOT_layer(wires):
    """

    Args:
      wires: 

    Returns:

    """
    nq = len(wires)
    for n in range(nq - 1):
        qml.CNOT(wires=[n, n + 1])
    qml.CNOT(wires=[nq - 1, 0])
def embedding_1(X, wires, fill='redundant')

Args

X
 
wires
 
fill
(Default value = 'redundant')

Returns:

Expand source code
def embedding_1(X, wires, fill='redundant'):
    """

    Args:
      X: 
      wires: 
      fill:  (Default value = 'redundant')

    Returns:

    """
    if len(X) < len(wires):
        r_ = len(wires) // len(X)
        if fill == 'redundant':
            large_features = np.tile(X, r_)
        elif fill == 'pad':
            large_features = np.pad(X, (0, len(wires)), 'constant', constant_values=0)
        qml.templates.embeddings.AngleEmbedding(large_features, wires=wires, rotation='Y')
    else:
        qml.templates.embeddings.AngleEmbedding(X, wires=wires, rotation='Y')
def embedding_2(X, wires)

Args

X
 
wires
 

Returns:

Expand source code
def embedding_2(X, wires):
    """

    Args:
      X: 
      wires: 

    Returns:

    """
    qml.templates.embeddings.AmplitudeEmbedding(X, wires=wires, pad=0, normalize=True)
def path_CNOT_layer(wires)

Args

wires
 

Returns:

Expand source code
def path_CNOT_layer(wires):
    """

    Args:
      wires: 

    Returns:

    """
    nq = len(wires)
    for n in range(nq - 1):
        qml.CNOT(wires=[n, n + 1])
def x_layer(wires, params)

Args

wires
 
params
 

Returns:

Expand source code
def x_layer(wires, params):
    """

    Args:
      wires: 
      params: 

    Returns:

    """
    nqubits = len(wires)
    for n in range(nqubits):
        qml.RX(params[n], wires=[n, ])
def y_layer(wires, params)

Args

wires
 
params
 

Returns:

Expand source code
def y_layer(wires, params):
    """

    Args:
      wires: 
      params: 

    Returns:

    """
    nqubits = len(wires)
    for n in range(nqubits):
        qml.RY(params[n], wires=[n, ])
def z_layer(wires, params)

Args

wires
 
params
 

Returns:

Expand source code
def z_layer(wires, params):
    """

    Args:
      wires: 
      params: 

    Returns:

    """
    nqubits = len(wires)
    for n in range(nqubits):
        qml.RZ(params[n], wires=[n, ])
def zz_gate(wires, gamma)

Args

wires
 
gamma
 

Returns:

Expand source code
def zz_gate(wires, gamma):
    """

    Args:
      wires: 
      gamma: 

    Returns:

    """
    qml.CNOT(wires=wires)
    qml.RZ(gamma, wires=wires[1])
    qml.CNOT(wires=wires)
def zz_layer(wires, params)

Args

wires
 
params
 

Returns:

Expand source code
def zz_layer(wires, params):
    """

    Args:
      wires: 
      params: 

    Returns:

    """
    nq = len(wires)
    for n in range(nq - 1):
        zz_gate([n, n + 1], params[n])
    zz_gate([nq - 1, 0], params[nq - 1])