Masking Circuits

The concept of masking is fairly simple: When a position in a mask is set to True, the object referenced will not appear when the mask is applied. In our case referenced objects are gates in a quantum circuit that can be removed by applying masks.

When considering different ansätze from literature, e.g. when creating parameterised quantum circuits that often rely on repeating layers, it becomes clear that a single mask cannot be easily used while still maintaining comprehensability, usability, and maintainability. We use a composition of masks instead to create the concept of a MaskedCircuit.

A MaskedCircuit has a concept of wires, layers as well as entangling gates that make up the variational part of the circuit. Each of them is represented by a separate Mask. The final mask that is applied to the underlying parameters is the intersection of all masks.

You can change and adapt masks by different methods:

  • you can manually set specific positions in a mask,

  • you can perturb a mask on a random position, and

  • you can shrink a mask.

class maskit.masks.PerturbationAxis(value)

An enumeration.

LAYERS = 1

Perturbation affects whole layers

RANDOM = 2

Perturbation affects random locations in parameter mask

WIRES = 0

Perturbation affects whole wires

class maskit.masks.PerturbationMode(value)

An enumeration.

ADD = 0

Adding new holes to the mask

INVERT = 2

Invert current state of the mask

REMOVE = 1

Removing holes from the mask

class maskit.masks.MaskedCircuit(parameters: ndarray, layers: int, wires: int, dynamic_parameters: bool = True, default_value: Optional[float] = None, parameter_mask: Optional[ndarray] = None, layer_mask: Optional[ndarray] = None, wire_mask: Optional[ndarray] = None)

A MaskedCircuit supports masking of different components including wires, layers, and parameters. Masking naturally removes active parameters from a circuit. However, some optimisers expect the array of parameters to remain stable across iteration steps; use dynamic_parameters=False to force the mask to always yield the full set of parameters in such cases. The mask will still prevent modification of inactive parameters.

Parameters:
  • parameters – Initial parameter set for circuit

  • layers – Number of layers

  • wires – Number of wires

  • dynamic_parameters – Whether the array of differentiable parameters may change size/order

  • default_value – Default value for gates that are added back in. In case of None that is also the default, the last known value is assumed

  • parameter_mask – Initialization values of paramater mask, defaults to None

  • layer_mask – Initialization values of layer mask, defaults to None

  • wire_mask – Initialization values of wire mask, defaults to None

MaskedCircuit.perturb(axis: PerturbationAxis = PerturbationAxis.RANDOM, amount: Optional[Union[int, float]] = None, mode: PerturbationMode = PerturbationMode.INVERT)

Perturbs the MaskedCircuit for a given axis that is of type PerturbationAxis. The perturbation is applied amount times and depends on the given mode of type PerturbationMode. If no amount is given, that is amount=None, a random amount is determined given by the actual size of the py:attr:~.mask. The amount is automatically limited to the actual size of the py:attr:~.mask.

Parameters:
  • amount – Number of items to perturb, defaults to None

  • axis – Which mask to perturb

  • mode – How to perturb, defaults to PerturbationMode.INVERT

Raises:

NotImplementedError – Raised in case of an unknown mode

MaskedCircuit.shrink(axis: PerturbationAxis = PerturbationAxis.LAYERS, amount: int = 1)