Skip to content

Commit

Permalink
[Feature] Analog feature maps (#234)
Browse files Browse the repository at this point in the history
Co-authored-by: João P. Moutinho <[email protected]>
  • Loading branch information
madagra and jpmoutinho authored Dec 11, 2023
1 parent d8c2cf1 commit 4ba3a9c
Show file tree
Hide file tree
Showing 7 changed files with 337 additions and 188 deletions.
116 changes: 0 additions & 116 deletions docs/digital_analog_qc/rydberg-hea.md

This file was deleted.

94 changes: 86 additions & 8 deletions docs/digital_analog_qc/semi-local-addressing.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,108 @@ $$

as is described in detail in the [analog interface basics](analog-basics.md) documentation.

The driving Hamiltonian term in priciple can model any local single-qubit rotation by addressing each qubit individually. However, on the current generation of neutral-atom devices full local addressing is not yet achievable. Fortunatelly, using devices called spatial light modulators (SLMs) it is possible to implement semi-local addressing where the pattern of targeted qubits is fixed during the execution of the quantum circuit. More formally, the addressing pattern appears as an additional term in the neutral-atom Hamiltonian:
The driving Hamiltonian term in priciple can model any local single-qubit rotation by addressing each qubit individually. However, some neutral-atom devices offer restricted local addressability using devices called spatial light modulators (SLMs).

We refer to this regime as *semi-local addressability*. In this regime, the individual qubit addressing is restricted to a pattern of targeted
qubits which is kept fixed during the execution of the quantum circuit. More formally, the addressing pattern appears as an additional
term in the neutral-atom Hamiltonian:

$$
\mathcal{H} = \mathcal{H}_{\rm drive} + \mathcal{H}_{\rm int} + \mathcal{H}_{\rm pattern},
\mathcal{H} = \mathcal{H}_{\rm drive} + \mathcal{H}_{\rm int} + \mathcal{H}_{\rm local}
$$

where $\mathcal{H}_{\rm pattern}$ is given by

$$
\mathcal{H}_{\rm pattern} = \sum_{i=0}^{n-1}\left(-\Delta w_i^{\rm det} N_i + \Gamma w_i^{\rm drive} X_i\right).
\mathcal{H}_{\rm local} = \sum_{i=0}^{n-1}\left(-\Delta w_i^{\rm det} \hat{n}_i + \Gamma w_i^{\rm drive} \hat{\sigma}^x_i\right).
$$

Here $\Delta$ specifies the maximal **negative** detuning that each qubit in the register can be exposed to. The weight $w_i^{\rm det}\in [0, 1]$ determines the actual value of detuning that $i$-th qubit feels and this way the detuning pattern is emulated. Similarly, for the amplitude pattern $\Gamma$ determines the maximal additional **positive** drive that acts on qubits. In this case the corresponding weights $w_i^{\rm drive}$ can vary in the interval $[0, 1]$.

Using the detuning and amplitude patterns described above one can modify the behavior of a selected set of qubits, thus achieving semi-local addressing.

## Creating semi-local addressing patterns
Qadence implements semi-local addressing in two different
flavors of increasing complexity: either as a circuit
constructor or directly as a pattern added to the general
evolution Hamiltonian described by the circuit.

## Using circuit constructors

The `rydberg_hea` constructor routine allows to
build a circuit instance implementing a basic version of the Hamiltonian
evolution described above where both $\Delta$ and $\tilde{\Omega}$ coefficients
are considered constants. Furthemore, **no global drive and detuning** are explicitly added
to the Hamiltonian. Therefore, the final Hamiltonian generator of the circuit reads as follows:

$$
\mathcal{H} = \mathcal{H}_{\rm local}(w^{\rm drive}, w^{\rm det}) + \mathcal{H}_{\textrm{int}}
$$

This implementation does not perform any checks on the weights normalization, thus
making it not realistic. This implies that global drive and detuning can be retrieved
by appropriately choosing the weights.

You can easily create a Rydberg hardware efficient ansatz implementing multiple layers
of the evolution generated by the local addressing Hamiltonian:

$$
\mathcal{H}_{\rm evo} = \sum_j \mathcal{H}_{\textrm{local}}(w_{j}^{\rm drive}, w_{j}^{\rm det})
$$

Notice that in real-device implementation, one layer only is usually achievable.

```python exec="on" source="material-block" result="json" session="addr"
import qadence as qd
from qadence import rydberg_hea, rydberg_hea_layer

n_qubits = 4
n_layers = 2
register = qd.Register.line(n_qubits)

# ansatz constructor
# the evolution time is parametrized for each layer of the evolution
ansatz = rydberg_hea(
register,
n_layers=n_layers, # number of subsequent layers of Hamiltonian evolution
addressable_detuning=True, # make the local detuning weights w_i^{det} as variational parameters
addressable_drive=True, # make the local drive weights w_i^{drv} as variational parameters
tunable_phase=True, # make the phase \phi as a variational parameter
)

# alternatively, a single ansatz layer can also be created for
# better flexibility

# these can be variational parameters
tevo_drive = 1.0 # evolution time for the locally addressed drive term
tevo_det = 1.0 # evolution time for the locally addressed detuning term
tevo_int = 1.0 # evolution time for the interaction term

# these can be list of variational parameters
weights_drive = [0.0, 0.25, 0.5, 0.25]
weights_det = [0.0, 0.0, 0.5, 0.5]

ansatz_layer = rydberg_hea_layer(
register,
tevo_det,
tevo_drive,
tevo_int,
detunings=weights_det,
drives=weights_drive,
)
```

This circuit constructor is meant to be used with fully differentiable backends such as
`pyqtorch` and mainly for quick experimentation with neutral atom compatible ansatze.

## Using addressing patterns

In Qadence semi-local addressing patterns can be created by either specifying fixed values for the weights of the qubits being addressed or defining them as trainable parameters that can be optimized later in some training loop. Semi-local addressing patterns can be defined with the `AddressingPattern` dataclass.

### Fixed weights

With fixed weights, detuning/amplitude addressing patterns can be defined in the following way:

```python exec="on" source="material-block" session="emu"
```python exec="on" source="material-block" session="addr"
import torch
from qadence.analog import AddressingPattern

Expand All @@ -58,7 +135,8 @@ If only detuning or amplitude pattern is needed - the corresponding weights for
The created addressing pattern can now be passed as an argument to any Qadence device class, or to the
`IdealDevice` or `RealisticDevice` to make use of the pre-defined options in those devices,

```python exec="on" source="material-block" session="emu"
```python exec="on" source="material-block" session="addr"
import torch
from qadence import (
AnalogRX,
AnalogRY,
Expand Down Expand Up @@ -102,7 +180,7 @@ print(f"Expectation value on PyQ: \n{expval_pyq.flatten().detach()}\n") # markd

The same configuration can also be seamlessly used to create a model with the Pulser backend.

```python exec="on" source="material-block" session="emu"
```python exec="on" source="material-block" session="addr"
model_pulser = QuantumModel(
circuit=circ,
observable=obs,
Expand Down Expand Up @@ -130,7 +208,7 @@ it will be added to all the blocks.
Since both the maximum detuning/amplitude value of the addressing pattern and the corresponding weights can be
user specified, they can be variationally used in some QML setting. This can be achieved by defining pattern weights as trainable `Parameter` instances or strings specifying weight names.

```python exec="on" source="material-block" session="emu"
```python exec="on" source="material-block" session="addr"
n_qubits = 3
reg = Register.line(n_qubits, spacing=8.0)

Expand Down
4 changes: 1 addition & 3 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@ nav:
- digital_analog_qc/index.md
- Basic operations on neutral-atoms: digital_analog_qc/analog-basics.md
- Fitting a simple function: digital_analog_qc/analog-qcl.md
- Semi-local addressing pattern: digital_analog_qc/semi-local-addressing.md
- Hardware efficient ansatz with restricted addressability: digital_analog_qc/rydberg-hea.md
- Restricted local addressability: digital_analog_qc/semi-local-addressing.md
- Pulse-level programming with Pulser: digital_analog_qc/pulser-basic.md
- Solve a QUBO problem: digital_analog_qc/analog-qubo.md
- Pulse-level programming with Pulser: digital_analog_qc/pulser-basic.md
- CNOT with interacting qubits: digital_analog_qc/daqc-cnot.md

- Variational quantum algorithms:
Expand Down
4 changes: 4 additions & 0 deletions qadence/constructors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
)

from .rydberg_hea import rydberg_hea, rydberg_hea_layer
from .rydberg_feature_maps import rydberg_feature_map, analog_feature_map, rydberg_tower_feature_map

from .qft import qft

Expand All @@ -45,4 +46,7 @@
"daqc_transform",
"rydberg_hea",
"rydberg_hea_layer",
"rydberg_feature_map",
"analog_feature_map",
"rydberg_tower_feature_map",
]
Loading

0 comments on commit 4ba3a9c

Please sign in to comment.