

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

# Hello AHS: esegui la tua prima simulazione hamiltoniana analogica
<a name="braket-get-started-hello-ahs"></a>

Questa sezione fornisce informazioni sull'esecuzione della prima simulazione hamiltoniana analogica.

**Topics**
+ [Catena di rotazione interagente](#braket-get-started-interacting-spin-chain)
+ [Disposizione](#braket-get-started-arrangement)
+ [Interazione](#braket-get-started-interaction)
+ [Campo di guida](#braket-get-started-driving-field)
+ [Programma AHS](#braket-get-started-ahs-program)
+ [In esecuzione su un simulatore locale](#braket-get-started-running-local-simulator)
+ [Analisi dei risultati del simulatore](#braket-get-started-analyzing-simulator-results)
+ [È in esecuzione la QPU Aquila QuEra](#braket-get-started-running-aquila-qpu)
+ [Analisi dei risultati della QPU](#braket-get-started-analyzing-qpu-results)
+ [Fasi successive](#braket-get-started-ahs-next)

## Catena di rotazione interagente
<a name="braket-get-started-interacting-spin-chain"></a>

Per un esempio canonico di un sistema di molte particelle interagenti, consideriamo un anello di otto spin (ognuno dei quali può trovarsi negli stati «su» ↑⟩ e «giù» ↓ ⟩). Sebbene piccolo, questo sistema modello mostra già una manciata di interessanti fenomeni legati ai materiali magnetici presenti in natura. In questo esempio, mostreremo come preparare un cosiddetto ordine antiferromagnetico, in cui gli spin consecutivi puntano in direzioni opposte.

![Diagramma che collega 8 nodi circolari che contengono frecce invertite su e giù.](http://docs.aws.amazon.com/it_it/braket/latest/developerguide/images/AntiFerromagnetic.png)


## Disposizione
<a name="braket-get-started-arrangement"></a>

Useremo un atomo neutro per rappresentare ogni spin, e gli stati di spin «su» e «giù» saranno codificati rispettivamente nello stato eccitato di Rydberg e nello stato fondamentale degli atomi. Per prima cosa, creiamo la disposizione bidimensionale. Possiamo programmare il suddetto anello di giri con il seguente codice.

 **Prerequisiti**: è necessario installare pip l'SDK [Braket](https://github.com/aws/amazon-braket-sdk-python#installing-the-amazon-braket-python-sdk). (Se si utilizza un'istanza di notebook ospitata da Braket, questo SDK viene preinstallato con i notebook.) Per riprodurre i grafici, è inoltre necessario installare separatamente matplotlib con il comando shell. `pip install matplotlib`

```
from braket.ahs.atom_arrangement import AtomArrangement
import numpy as np
import matplotlib.pyplot as plt  # Required for plotting

a = 5.7e-6  # Nearest-neighbor separation (in meters)

register = AtomArrangement()
register.add(np.array([0.5, 0.5 + 1/np.sqrt(2)]) * a)
register.add(np.array([0.5 + 1/np.sqrt(2), 0.5]) * a)
register.add(np.array([0.5 + 1/np.sqrt(2), - 0.5]) * a)
register.add(np.array([0.5, - 0.5 - 1/np.sqrt(2)]) * a)
register.add(np.array([-0.5, - 0.5 - 1/np.sqrt(2)]) * a)
register.add(np.array([-0.5 - 1/np.sqrt(2), - 0.5]) * a)
register.add(np.array([-0.5 - 1/np.sqrt(2), 0.5]) * a)
register.add(np.array([-0.5, 0.5 + 1/np.sqrt(2)]) * a)
```

con cui possiamo anche tracciare

```
fig, ax = plt.subplots(1, 1, figsize=(7, 7))
xs, ys = [register.coordinate_list(dim) for dim in (0, 1)]
ax.plot(xs, ys, 'r.', ms=15)

for idx, (x, y) in enumerate(zip(xs, ys)):
    ax.text(x, y, f" {idx}", fontsize=12)

plt.show()  # This will show the plot below in an ipython or jupyter session
```

![Grafico a dispersione che mostra i punti distribuiti tra valori positivi e negativi su entrambi gli assi.](http://docs.aws.amazon.com/it_it/braket/latest/developerguide/images/PlotNeutralAtoms.png)


## Interazione
<a name="braket-get-started-interaction"></a>

Per preparare la fase antiferromagnetica, dobbiamo indurre interazioni tra spin adiacenti. A tale scopo utilizziamo l'[interazione di van der Waals](https://en.wikipedia.org/wiki/Van_der_Waals_force), che viene implementata nativamente da dispositivi ad atomi neutri (come il dispositivo from). Aquila QuEra Utilizzando la rappresentazione dello spin, il termine hamiltoniano per questa interazione può essere espresso come somma di tutte le coppie di spin (j, k).

![Equazione di interazione hamiltoniana che mostra questa interazione espressa come somma di tutte le coppie di spin (j, k).](http://docs.aws.amazon.com/it_it/braket/latest/developerguide/images/HInteraction.png)


In questo caso, nj=^ ↑ è un operatore che assume j il valore di 1 solo se lo spin j è nello stato j «alto», e 0 in caso contrario. La forza è V j,k =C6/(dj,k​) 6, dove C 6 è il coefficiente fisso e d è la distanza euclidea tra gli spin j e j,k k. L'effetto immediato di questo termine di interazione è che ogni stato in cui sia lo spin j che lo spin k sono «verso l'alto» ha un'energia elevata (della quantità V). j,k Progettando attentamente il resto del programma AHS, questa interazione eviterà che entrambi gli spin adiacenti si trovino nello stato «attivo», un effetto comunemente noto come «blocco di Rydberg».

## Campo di guida
<a name="braket-get-started-driving-field"></a>

All'inizio del programma AHS, tutti gli spin (per impostazione predefinita) iniziano nel loro stato «inattivo», si trovano in una cosiddetta fase ferromagnetica. Tenendo d'occhio il nostro obiettivo di preparare la fase antiferromagnetica, specifichiamo un campo guida coerente dipendente dal tempo che trasferisce agevolmente gli spin da questo stato a uno stato a molti corpi in cui sono preferiti gli stati «alti». L'hamiltoniano corrispondente può essere scritto come

![Equazione matematica che descrive il calcolo di una funzione di azionamento hamiltoniana.](http://docs.aws.amazon.com/it_it/braket/latest/developerguide/images/HDrive.png)


dove Ω (t), 4444t (t), Δ (t) sono l'ampiezza globale (nota anche come [frequenza Rabi](https://en.wikipedia.org/wiki/Rabi_frequency)), la fase e la desintonizzazione del campo di pilotaggio dipendenti dal tempo che influiscono uniformemente su tutti gli spin. Qui S −,k =↓ k​ †↑ k e S \+,k =( S−,k) † =↑ ↑ k​ ↓ k sono rispettivamente gli operatori di abbassamento e innalzamento dello spin k, e k n k =↑ ↑ ≤ k è lo stesso operatore di prima. La parte Ω del campo di pilotaggio accoppia in modo coerente gli stati «giù» e «su» di tutti gli spin contemporaneamente, mentre la parte Δ controlla la ricompensa energetica per gli stati «su».

Per programmare una transizione graduale dalla fase ferromagnetica alla fase antiferromagnetica, specifichiamo il campo di pilotaggio con il seguente codice.

```
from braket.timings.time_series import TimeSeries
from braket.ahs.driving_field import DrivingField

# Smooth transition from "down" to "up" state
time_max = 4e-6  # seconds
time_ramp = 1e-7  # seconds
omega_max = 6300000.0  # rad / sec
delta_start = -5 * omega_max
delta_end = 5 * omega_max

omega = TimeSeries()
omega.put(0.0, 0.0)
omega.put(time_ramp, omega_max)
omega.put(time_max - time_ramp, omega_max)
omega.put(time_max, 0.0)

delta = TimeSeries()
delta.put(0.0, delta_start)
delta.put(time_ramp, delta_start)
delta.put(time_max - time_ramp, delta_end)
delta.put(time_max, delta_end)

phi = TimeSeries().put(0.0, 0.0).put(time_max, 0.0)

drive = DrivingField(
   amplitude=omega,
   phase=phi,
   detuning=delta
)
```

Possiamo visualizzare le serie temporali del campo di guida con il seguente script.

```
fig, axes = plt.subplots(3, 1, figsize=(12, 7), sharex=True)

ax = axes[0]
time_series = drive.amplitude.time_series
ax.plot(time_series.times(), time_series.values(), '.-')
ax.grid()
ax.set_ylabel('Omega [rad/s]')

ax = axes[1]
time_series = drive.detuning.time_series
ax.plot(time_series.times(), time_series.values(), '.-')
ax.grid()
ax.set_ylabel('Delta [rad/s]')

ax = axes[2]
time_series = drive.phase.time_series
# Note: time series of phase is understood as a piecewise constant function
ax.step(time_series.times(), time_series.values(), '.-', where='post')
ax.set_ylabel('phi [rad]')
ax.grid()
ax.set_xlabel('time [s]')

plt.show()  # This will show the plot below in an ipython or jupyter session
```

![Tre grafici che mostrano phi, delta e omega nel tempo. La sottotrama in alto mostra la crescita fino a poco sopra 6, rads/s dove rimane per 4 secondi fino a quando non torna a 0. La sottotrama centrale mostra la crescita lineare associata della derivata e la sottotrama inferiore illustra una linea piatta vicina allo zero.](http://docs.aws.amazon.com/it_it/braket/latest/developerguide/images/DrivingTimeSeries.png)


## Programma AHS
<a name="braket-get-started-ahs-program"></a>

Il registro, il campo di guida (e le interazioni implicite di van der Waals) costituiscono il programma di simulazione hamiltoniana analogica. `ahs_program`

```
from braket.ahs.analog_hamiltonian_simulation import AnalogHamiltonianSimulation

ahs_program = AnalogHamiltonianSimulation(
   register=register,
   hamiltonian=drive
)
```

## In esecuzione su un simulatore locale
<a name="braket-get-started-running-local-simulator"></a>

Poiché questo esempio è piccolo (meno di 15 giri), prima di eseguirlo su una QPU compatibile con AHS, possiamo eseguirlo sul simulatore AHS locale fornito con l'SDK Braket. Poiché il simulatore locale è disponibile gratuitamente con Braket SDK, questa è la migliore pratica per garantire che il nostro codice possa essere eseguito correttamente.

Qui, possiamo impostare il numero di scatti su un valore elevato (ad esempio, 1 milione) perché il simulatore locale traccia l'evoluzione temporale dello stato quantistico e preleva campioni dallo stato finale, aumentando quindi il numero di scatti e aumentando la durata totale solo marginalmente.

```
from braket.devices import LocalSimulator

device = LocalSimulator("braket_ahs")

result_simulator = device.run(
   ahs_program,
   shots=1_000_000
).result()  # Takes about 5 seconds
```

## Analisi dei risultati del simulatore
<a name="braket-get-started-analyzing-simulator-results"></a>

Possiamo aggregare i risultati dei colpi con la seguente funzione che deduce lo stato di ogni rotazione (che può essere «d» per «giù», «u» per «su» o «e» per il sito vuoto) e conta quante volte ogni configurazione si è verificata tra i colpi.

```
from collections import Counter


def get_counts(result):
    """Aggregate state counts from AHS shot results

    A count of strings (of length = # of spins) are returned, where
    each character denotes the state of a spin (site):
      e: empty site
      u: up state spin
      d: down state spin

    Args:
      result (braket.tasks.analog_hamiltonian_simulation_quantum_task_result.AnalogHamiltonianSimulationQuantumTaskResult)

    Returns
       dict: number of times each state configuration is measured

    """
    state_counts = Counter()
    states = ['e', 'u', 'd']
    for shot in result.measurements:
        pre = shot.pre_sequence
        post = shot.post_sequence
        state_idx = np.array(pre) * (1 + np.array(post))
        state = "".join(map(lambda s_idx: states[s_idx], state_idx))
        state_counts.update((state,))
    return dict(state_counts)


counts_simulator = get_counts(result_simulator)  # Takes about 5 seconds
print(counts_simulator)
```

```
*[Output]*
{'dddddddd': 5, 'dddddddu': 12, 'ddddddud': 15, ...}
```

`counts`Ecco un dizionario che conta il numero di volte in cui ogni configurazione di stato viene osservata tra le riprese. Possiamo anche visualizzarli con il codice seguente.

```
from collections import Counter


def has_neighboring_up_states(state):
    if 'uu' in state:
        return True
    if state[0] == 'u' and state[-1] == 'u':
        return True
    return False


def number_of_up_states(state):
    return Counter(state)['u']


def plot_counts(counts):
    non_blockaded = []
    blockaded = []
    for state, count in counts.items():
        if not has_neighboring_up_states(state):
            collection = non_blockaded
        else:
            collection = blockaded
        collection.append((state, count, number_of_up_states(state)))

    blockaded.sort(key=lambda _: _[1], reverse=True)
    non_blockaded.sort(key=lambda _: _[1], reverse=True)

    for configurations, name in zip((non_blockaded,
                                     blockaded),
                                    ('no neighboring "up" states',
                                     'some neighboring "up" states')):
        plt.figure(figsize=(14, 3))
        plt.bar(range(len(configurations)), [item[1] for item in configurations])
        plt.xticks(range(len(configurations)))
        plt.gca().set_xticklabels([item[0] for item in configurations], rotation=90)
        plt.ylabel('shots')
        plt.grid(axis='y')
        plt.title(f'{name} configurations')
        plt.show()


plot_counts(counts_simulator)
```

![Grafico a barre che mostra un gran numero di scatti senza configurazioni di stati «superiori» adiacenti.](http://docs.aws.amazon.com/it_it/braket/latest/developerguide/images/AHSCounts1.png)


![Grafico a barre che mostra immagini di alcune configurazioni di stati «superiori» adiacenti, con 4 stati a 1,0 scatti.](http://docs.aws.amazon.com/it_it/braket/latest/developerguide/images/AHSCounts2.png)


Dai grafici, possiamo leggere le seguenti osservazioni per verificare di aver preparato con successo la fase antiferromagnetica.

1. In genere, gli stati non bloccati (in cui non ci sono due spin adiacenti nello stato «attivo») sono più comuni degli stati in cui almeno una coppia di spin adiacenti si trova entrambi nello stato «positivo».

1. In genere, sono preferiti gli stati con più eccitazioni «in alto», a meno che la configurazione non sia bloccata.

1. Gli stati più comuni sono infatti gli stati antiferromagnetici perfetti e. `"dudududu"` `"udududud"`

1. I secondi stati più comuni sono quelli in cui ci sono solo 3 eccitazioni «verso l'alto» con separazioni consecutive di 1, 2, 2. Ciò dimostra che l'interazione di van der Waals ha un effetto (anche se molto minore) anche sui vicini più prossimi.

## È in esecuzione la QPU Aquila QuEra
<a name="braket-get-started-running-aquila-qpu"></a>

 **Prerequisiti**[: oltre all'installazione pip dell'[SDK](https://github.com/aws/amazon-braket-sdk-python#installing-the-amazon-braket-python-sdk) Braket, se non utilizzi Amazon Braket, assicurati di aver completato i passaggi introduttivi necessari.](https://docs.aws.amazon.com/braket/latest/developerguide/braket-get-started.html)

**Nota**  
Se utilizzi un'istanza di notebook ospitata da Braket, l'SDK Braket viene preinstallato con l'istanza.

Con tutte le dipendenze installate, possiamo connetterci alla QPU. Aquila

```
from braket.aws import AwsDevice

aquila_qpu = AwsDevice("arn:aws:braket:us-east-1::device/qpu/quera/Aquila")
```

Per rendere il nostro programma AHS adatto alla QuEra macchina, dobbiamo arrotondare tutti i valori per rispettare i livelli di precisione consentiti dalla Aquila QPU. (Questi requisiti sono regolati dai parametri del dispositivo con «Risoluzione» nel nome. Possiamo vederli `aquila_qpu.properties.dict()` eseguendoli su un notebook. Per ulteriori dettagli sulle funzionalità e sui requisiti di Aquila, vedere il notebook [Introduzione ad Aquila](https://github.com/aws/amazon-braket-examples/blob/main/examples/analog_hamiltonian_simulation/01_Introduction_to_Aquila.ipynb).) Possiamo farlo chiamando il `discretize` metodo.

```
discretized_ahs_program = ahs_program.discretize(aquila_qpu)
```

Ora possiamo eseguire il programma (per ora eseguendo solo 100 scatti) sulla Aquila QPU.

**Nota**  
L'esecuzione di questo programma sul Aquila processore comporterà un costo. L'SDK Amazon Braket include un [Cost Tracker](https://aws.amazon.com/blogs/quantum-computing/managing-the-cost-of-your-experiments-in-amazon-braket/) che consente ai clienti di impostare limiti di costo e di tenere traccia dei costi quasi in tempo reale.

```
task = aquila_qpu.run(discretized_ahs_program, shots=100)

metadata = task.metadata()
task_arn = metadata['quantumTaskArn']
task_status = metadata['status']

print(f"ARN: {task_arn}")
print(f"status: {task_status}")
```

```
*[Output]*
ARN: arn:aws:braket:us-east-1:123456789012:quantum-task/12345678-90ab-cdef-1234-567890abcdef
status: CREATED
```

A causa della grande differenza tra il tempo di esecuzione di un'attività quantistica (a seconda delle finestre di disponibilità e dell'utilizzo della QPU), è una buona idea annotare l'ARN dell'attività quantistica, in modo da poterne controllare lo stato in un secondo momento con il seguente frammento di codice.

```
# Optionally, in a new python session
from braket.aws import AwsQuantumTask

SAVED_TASK_ARN = "arn:aws:braket:us-east-1:123456789012:quantum-task/12345678-90ab-cdef-1234-567890abcdef"

task = AwsQuantumTask(arn=SAVED_TASK_ARN)
metadata = task.metadata()
task_arn = metadata['quantumTaskArn']
task_status = metadata['status']

print(f"ARN: {task_arn}")
print(f"status: {task_status}")
```

```
*[Output]*
ARN: arn:aws:braket:us-east-1:123456789012:quantum-task/12345678-90ab-cdef-1234-567890abcdef
status: COMPLETED
```

Una volta che lo stato è COMPLETATO (che può essere verificato anche dalla pagina delle attività quantistiche della console Amazon [Braket](https://us-east-1.console.aws.amazon.com/braket/home?region=us-east-1#/tasks)), possiamo interrogare i risultati con:

```
result_aquila = task.result()
```

## Analisi dei risultati della QPU
<a name="braket-get-started-analyzing-qpu-results"></a>

Usando le stesse `get_counts` funzioni di prima, possiamo calcolare i conteggi:

```
counts_aquila = get_counts(result_aquila)
   print(counts_aquila)
```

```
*[Output]*
{'dddududd': 2, 'dudududu': 18, 'ddududud': 4, ...}
```

e tracciali con`plot_counts`:

```
plot_counts(counts_aquila)
```

![Grafico a barre che mostra un gran numero di scatti senza configurazioni di stati «superiori» adiacenti.](http://docs.aws.amazon.com/it_it/braket/latest/developerguide/images/QPUPlotCounts1.png)


![Grafico a barre che mostra immagini di alcune configurazioni di stati «superiori» adiacenti, con 4 stati a 1,0 scatti.](http://docs.aws.amazon.com/it_it/braket/latest/developerguide/images/QPUPlotCounts2.png)


Si noti che una piccola parte delle riprese presenta aree vuote (contrassegnate con «e»). Ciò è dovuto a imperfezioni della QPU nella preparazione dell'1-2% per atomo. Aquila Inoltre, i risultati corrispondono alla simulazione nell'ambito della fluttuazione statistica prevista a causa del numero ridotto di scatti.

## Fasi successive
<a name="braket-get-started-ahs-next"></a>

Congratulazioni, ora hai eseguito il tuo primo carico di lavoro AHS su Amazon Braket utilizzando il simulatore AHS locale e la QPU. Aquila

[Per ulteriori informazioni sulla fisica di Rydberg, sulla simulazione hamiltoniana analogica e sul dispositivo, consulta i nostri taccuini di esempio. Aquila](https://github.com/aws/amazon-braket-examples/tree/main/examples/analog_hamiltonian_simulation)