Python library for simulating superconducting qubits with energy spectra, plotting, and QuTiP integration
—
Symbolic circuit analysis tools for custom superconducting circuits, enabling automated quantization and Hamiltonian generation from circuit descriptions. Supports YAML-based circuit specification and flexible node/branch analysis.
Main class for building and analyzing custom superconducting circuits from symbolic descriptions.
class Circuit:
def __init__(self, input_string: str, from_file: bool = False, ext_basis: str = None,
initiate_sym_calc: bool = True, truncated_dim: int = None):
"""
Custom circuit analysis from symbolic description.
Parameters:
- input_string (str): YAML circuit description or file path
- from_file (bool): Whether input_string is a file path
- ext_basis (str): External basis choice for quantization
- initiate_sym_calc (bool): Whether to immediately perform symbolic calculation
- truncated_dim (int): Truncated Hilbert space dimension
"""
def hamiltonian(self) -> np.ndarray:
"""Generate circuit Hamiltonian matrix."""
def eigenvals(self, evals_count: int = 6) -> np.ndarray:
"""Calculate circuit eigenvalues."""
def eigensys(self, evals_count: int = 6) -> tuple:
"""Calculate circuit eigenvalues and eigenvectors."""
def plot_evals_vs_paramvals(self, param_name: str, param_vals: np.ndarray,
evals_count: int = 6, **kwargs):
"""Plot energy levels vs circuit parameter."""
def wavefunction(self, esys: tuple = None, which: int = 0,
mode: str = 'abs_sqr') -> WaveFunction:
"""Return circuit wavefunction for specified eigenstate."""
def set_discretization(self, var_name: str, grid: Grid1d) -> None:
"""Set discretization grid for continuous circuit variable."""
def configure(self, **kwargs) -> None:
"""Configure circuit parameters."""
class SymbolicCircuit:
def __init__(self, nodes_dict: dict, branches_dict: dict, initiate: bool = True):
"""
Symbolic circuit representation from nodes and branches.
Parameters:
- nodes_dict (dict): Dictionary defining circuit nodes
- branches_dict (dict): Dictionary defining circuit branches
- initiate (bool): Whether to immediately build symbolic representation
"""
def configure(self, transformation: str = None, closure_branches: list = None) -> None:
"""Configure symbolic circuit transformation and closure."""
def generate_hamiltonian_symbolic(self) -> sympy.Expr:
"""Generate symbolic Hamiltonian expression."""Helper functions for circuit construction, parameter management, and example generation.
def truncation_template(system_hierarchy: list, individual_trunc_dim: int = 6, combined_trunc_dim: int = 30) -> list:
"""
Generate template for defining truncated dimensions for subsystems in hierarchical diagonalization.
Parameters:
- system_hierarchy (list): Hierarchy of system components
- individual_trunc_dim (int): Truncation dimension for individual subsystems
- combined_trunc_dim (int): Truncation dimension for combined systems
Returns:
- list: Truncation template structure
"""
def assemble_circuit(circuit_list: List[str], couplers: str, rename_parameters: bool = False) -> Tuple[str, List[Dict[int, int]]]:
"""
Assemble a large circuit from smaller sub-circuits and coupling elements.
Parameters:
- circuit_list (List[str]): List of sub-circuit YAML strings
- couplers (str): YAML string characterizing coupler branches
- rename_parameters (bool): Whether to rename conflicting parameters
Returns:
- Tuple[str, List[Dict[int, int]]]: Assembled circuit YAML and node mapping
"""
def assemble_transformation_matrix(transformation_name: str, **kwargs) -> np.ndarray:
"""
Create coordinate transformation matrix.
Parameters:
- transformation_name (str): Type of transformation
- **kwargs: Transformation parameters
Returns:
- np.ndarray: Transformation matrix
"""
def example_circuit(qubit_type: str) -> str:
"""
Get example circuit YAML description.
Parameters:
- qubit_type (str): Type of qubit circuit ('transmon', 'fluxonium', etc.)
Returns:
- str: YAML circuit description
"""Classes for discretizing continuous circuit variables and managing computational grids.
class Grid1d:
def __init__(self, min_val: float, max_val: float, pt_count: int):
"""
One-dimensional discretization grid.
Parameters:
- min_val (float): Minimum grid value
- max_val (float): Maximum grid value
- pt_count (int): Number of grid points
"""
@property
def grid_spacing(self) -> float:
"""Grid spacing between adjacent points."""
@property
def grid_points(self) -> np.ndarray:
"""Array of all grid points."""
def closest_index(self, value: float) -> int:
"""Find grid index closest to given value."""import scqubits as scq
# Get example transmon circuit description
transmon_yaml = scq.core.circuit_utils.example_circuit('transmon')
print("Transmon circuit YAML:")
print(transmon_yaml)
# Create circuit from description
circuit = scq.Circuit(transmon_yaml, from_file=False)
# Calculate spectrum
energies = circuit.eigenvals(evals_count=6)
print("Circuit energy levels:", energies)
# Compare to built-in Transmon class
transmon_builtin = scq.Transmon(EJ=25.0, EC=0.2, ng=0.0, ncut=30)
builtin_energies = transmon_builtin.eigenvals(evals_count=6)
print("Built-in Transmon energies:", builtin_energies)# Define custom circuit YAML
custom_circuit_yaml = """
branches:
- ["J", "JJ", 1, 2, EJ=25.0, EC=0.2]
- ["C", "C", 1, 0, C=1.0]
- ["L", "L", 2, 0, L=0.1]
nodes:
1: [0, 1]
2: [1, 0]
# Parameters for quantization
vars:
phi1: [0, 2*pi]
phi2: [0, 2*pi]
# Truncation settings
truncated_dim: 20
"""
# Create circuit
custom_circuit = scq.Circuit(custom_circuit_yaml, from_file=False)
# Set up discretization grids
phi_grid = scq.Grid1d(min_val=0, max_val=2*np.pi, pt_count=100)
custom_circuit.set_discretization('phi1', phi_grid)
custom_circuit.set_discretization('phi2', phi_grid)
# Calculate spectrum
spectrum = custom_circuit.eigenvals(evals_count=8)
print("Custom circuit spectrum:", spectrum)# Create fluxonium circuit
fluxonium_yaml = scq.core.circuit_utils.example_circuit('fluxonium')
fluxonium_circuit = scq.Circuit(fluxonium_yaml, from_file=False)
# Parameter sweep over external flux
flux_vals = np.linspace(0, 1, 51)
hilbert_space = scq.HilbertSpace([fluxonium_circuit])
def update_flux(system, flux_val):
"""Update circuit flux parameter."""
system.subsystem_list[0].configure(flux=flux_val)
sweep = scq.ParameterSweep(
hilbert_space=hilbert_space,
paramvals_by_name={'flux': flux_vals},
update_hilbert_space=update_flux,
evals_count=6
)
sweep.run()
sweep.plot_evals_vs_paramvals()# Define circuit using nodes and branches dictionaries
nodes_dict = {
1: [1, 0], # Node 1 at coordinates (1, 0)
2: [0, 1], # Node 2 at coordinates (0, 1)
3: [0, 0] # Ground node
}
branches_dict = {
'JJ1': {
'type': 'JJ',
'nodes': [1, 3],
'parameters': {'EJ': 20.0, 'EC': 0.15}
},
'JJ2': {
'type': 'JJ',
'nodes': [2, 3],
'parameters': {'EJ': 18.0, 'EC': 0.12}
},
'C12': {
'type': 'C',
'nodes': [1, 2],
'parameters': {'C': 5.0}
}
}
# Create symbolic circuit
symbolic_circuit = scq.SymbolicCircuit(
nodes_dict=nodes_dict,
branches_dict=branches_dict
)
# Generate symbolic Hamiltonian
H_symbolic = symbolic_circuit.generate_hamiltonian_symbolic()
print("Symbolic Hamiltonian:")
print(H_symbolic)# Create circuit with custom truncation
circuit_yaml = """
branches:
- ["JJ1", "JJ", 1, 0, EJ=25.0, EC=0.2]
- ["JJ2", "JJ", 2, 0, EJ=20.0, EC=0.18]
- ["C", "C", 1, 2, C=2.0]
nodes:
1: [0, 1]
2: [1, 0]
vars:
phi1: [-pi, pi]
phi2: [-pi, pi]
"""
# Create truncation template
truncation = scq.core.circuit_utils.truncation_template()
truncation.update({
'phi1_truncation': 15,
'phi2_truncation': 15,
'interaction_truncation': 10
})
# Create circuit with custom settings
circuit = scq.Circuit(circuit_yaml, from_file=False)
circuit.configure(
truncated_dim=50,
ext_basis='harmonic'
)
# Set up grid discretization
phi_grid_fine = scq.Grid1d(min_val=-np.pi, max_val=np.pi, pt_count=150)
circuit.set_discretization('phi1', phi_grid_fine)
circuit.set_discretization('phi2', phi_grid_fine)
# Calculate detailed spectrum
detailed_spectrum = circuit.eigenvals(evals_count=12)
print("Detailed circuit spectrum:", detailed_spectrum)# Create circuit and calculate wavefunctions
circuit = scq.Circuit(transmon_yaml, from_file=False)
evals, evecs = circuit.eigensys(evals_count=4)
# Analyze ground state wavefunction
ground_state_wf = circuit.wavefunction(esys=(evals, evecs), which=0)
ground_state_wf.plot(mode='abs_sqr')
# Analyze first excited state
excited_state_wf = circuit.wavefunction(esys=(evals, evecs), which=1)
excited_state_wf.plot(mode='abs_sqr')
# Calculate matrix elements for circuit operators
# Note: Circuit operators need to be defined based on circuit variables
print("Energy level differences:")
for i in range(1, len(evals)):
transition = evals[i] - evals[0]
print(f"0->{i} transition: {transition:.4f} GHz")# Three-junction flux qubit circuit
flux_qubit_yaml = """
branches:
- ["JJ1", "JJ", 1, 0, EJ=10.0, EC=0.1]
- ["JJ2", "JJ", 2, 0, EJ=10.0, EC=0.1]
- ["JJ3", "JJ", 1, 2, EJ=8.0, EC=0.08]
- ["L", "L", 1, 2, L=0.5]
nodes:
1: [0, 1]
2: [1, 0]
# External flux threading the loop
external_flux: 0.5
vars:
phi1: [-2*pi, 2*pi]
phi2: [-2*pi, 2*pi]
truncated_dim: 25
"""
# Create and analyze flux qubit circuit
flux_circuit = scq.Circuit(flux_qubit_yaml, from_file=False)
# Sweep external flux
flux_values = np.linspace(0, 1, 101)
def update_circuit_flux(system, flux_val):
system.subsystem_list[0].configure(external_flux=flux_val)
flux_sweep = scq.ParameterSweep(
hilbert_space=scq.HilbertSpace([flux_circuit]),
paramvals_by_name={'external_flux': flux_values},
update_hilbert_space=update_circuit_flux,
evals_count=8
)
flux_sweep.run()
flux_sweep.plot_evals_vs_paramvals()Install with Tessl CLI
npx tessl i tessl/pypi-scqubits