```
[1]:
```

```
%matplotlib inline
%config InlineBackend.figure_format = 'svg'
import numpy as np
import scqubits as qubit
from scqubits import HilbertSpace, InteractionTerm, ParameterSweep, Explorer
```

# Explorer¶

Sometimes, exploring the properties of coupled quantum systems benefits from visual aides, and the possibility to see how properties change when system parameters are changed. The `Explorer`

class in scqubits provides an interactive plot with multiple panels collecting an important set of information.

The idea behind the `Explorer`

class is simple: the user selects an external parameter that they wish to sweep, e.g., an external magnetic flux. The composite system is user-defined through the `HilbertSpace`

and `InteractionTerm`

classes, allowing flexibility to include different types and numbers of superconducting qubits and harmonic modes.

Once defined, the parameter sweep is computed by means of the `ParameterSweep`

class, and spectral data is stored in memory to allow efficient, interactive display of data.

## Example 1: fluxonium coupled to resonator¶

As a first example, we consider a system composed of a fluxonium qubit, coupled through its charge operator to the voltage inside a resonator.

### HilbertSpace setup¶

The initialization of the composite Hilbert space proceeds as usual; we first define the individual two subsystems that will make up the Hilbert space:

```
[2]:
```

```
qbt = qubit.Fluxonium(
EJ=2.55,
EC=0.72,
EL=0.12,
flux=0.0,
cutoff=110,
truncated_dim=9
)
osc = qubit.Oscillator(
E_osc=4.0,
truncated_dim=5
)
```

Here, the `truncated_dim`

parameters are important. For the fluxonium, with `cutoff`

set to 110, the internal Hilbert space dimension is 110. Once diagonalized, we will only keep a few eigenstates going forward - in the above example 9. Similarly, we keep 5 levels for the resonators, i.e., photon states n=0,1,…,4 are included in the following.

Next, the two subsystems are declared as the two components of a joint Hilbert space:

```
[3]:
```

```
hilbertspace = qubit.HilbertSpace([qbt, osc])
```

The interaction between fluxonium and resonator is of the form \(H_\text{int} = g n (a+a^\dagger)\), where \(n\) is the fluxonium’s charge operator: `qbt.n_operator()`

. This structure is captured by creating an `InteractionTerm`

object. Since this is the only interaction term, the `interaction_list`

contains only this one term. It is inserted into the `HilbertSpace`

object.

```
[4]:
```

```
interaction = InteractionTerm(
g_strength=0.2,
op1=qbt.n_operator(),
subsys1=qbt,
op2=osc.creation_operator() + osc.annihilation_operator(),
subsys2=osc
)
interaction_list = [interaction]
hilbertspace.interaction_list = interaction_list
```

### Parameter sweep setup¶

We consider sweeping the external flux through the fluxonium loop. To create the necessary `ParameterSweep`

object, we specify: 1. `param_name`

: the name of the sweep parameter (below expressed in LaTeX format as the flux in units of the flux quantum) 2. `param_vals`

: an array with the flux values used in the sweep 3. `subsys_update_list`

: a list containing all Hilbert space subsystems that change as the flux is varied 4. `update_hilbertspace(param_val)`

: a function that shows how a
change in the sweep parameter affects the Hilbert space; here only the `.flux`

attributed of the fluxonium qubit needs to be changed

These ingredients all make it into the initialization of the `ParameterSweep`

object. Once initialized, spectral data is generated and stored. Here, we additionally generate data for dispersive shifts and charge matrix elements.

```
[5]:
```

```
param_name = '$\Phi_{ext}/\Phi_0$'
param_vals = np.linspace(-0.5, 0.5, 100)
subsys_update_list = [qbt]
def update_hilbertspace(param_val):
qbt.flux = param_val
sweep = ParameterSweep(
param_name=param_name,
param_vals=param_vals,
evals_count=10,
hilbertspace=hilbertspace,
subsys_update_list=subsys_update_list,
update_hilbertspace=update_hilbertspace
)
```

```
```

```
```

### Starting the Explorer class¶

At this point, everything is prepared to start the interactive `Explorer`

and play with the interactive display!

```
[6]:
```

```
explorer = Explorer(
sweep=sweep,
evals_count=10
)
explorer.interact()
```

```
```

```
```

The `Explorer`

plots are currently fixed to:

Bare spectra of the individual qubits

Wave functions of the bare qubits

Dressed spectrum of the composite Hilbert space

Spectrum for n-photon qubit transitions, starting from a given initial state

AC Stark shift \(\chi_{01}\) for any of the qubits

Charge matrix elements for any of the qubits, using the same initial state as in point 4.

Note

The n-photon qubit transition plot gathers data from the full system spectrum by assessing maximum overlap with bare qubit states. Whenever qubit levels cross and hybridize with, e.g., a resonator, a discontinuity will show up in the spectrum. These discontinuities are correct representations, and not a bug.

## Example 2: two transmons coupled to a resonator¶

In the following second example, we consider a system composed of two flux-tunable transmons, capacitively coupled to one joint harmonic mode. (The flux is assumed to arise from a global field, and the SQUID-loop areas of the two transmons are different with an area ratio of 1.4)

### Hilbert space setup¶

```
[8]:
```

```
qbt1 = qubit.Transmon(
EJ=25.0,
EC=0.2,
ng=0,
ncut=30,
truncated_dim=3)
qbt2 = qubit.Transmon(
EJ=15.0,
EC=0.15,
ng=0,
ncut=30,
truncated_dim=3)
resonator = qubit.Oscillator(
E_osc=5.5,
truncated_dim=4)
hilbertspace = HilbertSpace([qbt1, qbt2, resonator])
g1 = 0.1 # coupling resonator-CPB1 (without charge matrix elements)
g2 = 0.2 # coupling resonator-CPB2 (without charge matrix elements)
interaction1 = InteractionTerm(
g_strength = g1,
op1 = qbt1.n_operator(),
subsys1 = qbt1,
op2 = resonator.creation_operator() + resonator.annihilation_operator(),
subsys2 =resonator
)
interaction2 = InteractionTerm(
g_strength = g2,
op1 = qbt2.n_operator(),
subsys1 = qbt2,
op2 = resonator.creation_operator() + resonator.annihilation_operator(),
subsys2 =resonator
)
interaction_list = [interaction1, interaction2]
hilbertspace.interaction_list = interaction_list
```

### Parameter sweep setup¶

```
[9]:
```

```
param_name = '$\Phi_{ext}/\Phi_0$'
param_vals = np.linspace(0.0, 1.0, 150)
subsys_update_list = [qbt1, qbt2]
def update_hilbertspace(param_val): # function that shows how Hilbert space components are updated
qbt1.EJ = 30*np.abs(np.cos(np.pi * param_val))
qbt2.EJ = 40*np.abs(np.cos(np.pi * param_val * 2))
sweep = ParameterSweep(
param_name=param_name,
param_vals=param_vals,
evals_count=15,
hilbertspace=hilbertspace,
subsys_update_list=subsys_update_list,
update_hilbertspace=update_hilbertspace,
)
```

```
```

```
```

### Start Explorer¶

```
[10]:
```

```
explorer = Explorer(
sweep=sweep,
evals_count=10
)
explorer.interact()
```

```
```

```
```

```
```

```
```

```
[ ]:
```

```
```