rydiqule.sensor_solution.Solution¶
- class rydiqule.sensor_solution.Solution[source]¶
Bases:
objectResults object that contains information from a solve.
Methods implement a number of standard analyses on the result based on the density matrix observable formalism and Maxwell’s equations for a plane wave in an optically-thin polarizable medium.
- __init__()¶
Methods
__init__()copy()coupling_coefficient_matrix(coupling)Matrix of coefficients representing coupling strength for a particular coupling.
coupling_coefficient_observable([coupling])Get the observable associated with the output of
coupling_coefficient_matrix().coupling_rabi(coupling)Rabi frequency, in Mrad/s, of a particular coupling or coupling group.
deepcopy()get_OD()Calculates the optical depth from the solution.
get_observable(matrix)Returns the trace of a matrix product of the density matrix with a provided matrix.
Extract the phase shift from a solution.
get_solution_element(idx)Return a slice of an n_dimensional matrix of solutions of shape (...,n^2-1), where n is the basis size of the quantum system.
Return the atomic susceptibility on the probe transition.
Extract the transmission term from a solution.
rho_ij(i, j)Gets the full complex density matrix element corresponding to a given pair of indices.
Attributes
Cross-sectional area of the probing beam, in square meters.
Optical path length of the medium, in meters.
Density-matrix solutions in complex basis.
Eta constant from the Cell.
Kappa constant from the Cell.
Probing transition frequency, in rad/s.
Base laser rabi frequency of the probing transition of the
Sensorused in a solve.Coupling edge corresponding to probing field.
Return a list of all states in the
Sensorused to produce solution.Copy of the
Sensor.couplingsgraph.Labels for the axes of scanned parameters.
Value corresponding to each axis.
Version of rydiqule that created the Solution.
The list of density matrix elements in the order they appear in the solution.
Output of the Sensor.variable_parameters() method for the Sensor used in a solve.
Doppler classes used to perform the doppler average.
Solutions returned by the solver.
Times the solution is returned at, when using the time solver.
Initial conditions, when using the time solver.
- _beam_area: float | None¶
Cross-sectional area of the probing beam, in square meters. Not generally defined when using a Sensor.
- _cell_length: float | None¶
Optical path length of the medium, in meters. Not generally defined when using a Sensor.
- _eta: float | None¶
Eta constant from the Cell. Not generally defined when using a Sensor.
- Type:
float, optional
- _kappa: float | None¶
Kappa constant from the Cell. Not generally defined when using a Sensor.
- Type:
float, optional
- _probe_freq: float | None¶
Probing transition frequency, in rad/s. Not generally defined when using a Sensor.
- _probe_tuple: Tuple[int | str | Tuple[float, ...] | List[int | str | Tuple[float, ...]] | Tuple[float | List[float], ...], int | str | Tuple[float, ...] | List[int | str | Tuple[float, ...]] | Tuple[float | List[float], ...]] | None¶
Coupling edge corresponding to probing field. Defined as the first added coupling when using a Sensor.
- axis_labels: list[str]¶
Labels for the axes of scanned parameters. If doppler averaging but not summing, doppler dimensions are prepended.
- axis_values: list¶
Value corresponding to each axis. If doppler averaging but not summing, doppler classes in internal units are added.
- Type:
- property beam_area: float¶
Cross-sectional area of the probing beam, in square meters. Not generally defined when using a Sensor.
- property cell_length: float¶
Optical path length of the medium, in meters. Not generally defined when using a Sensor.
- property complex_rho: ndarray¶
Density-matrix solutions in complex basis.
This function calls
sensor_utils.convert_dm_to_complex()onrho.- Returns:
Complex density matrix solutions, with ground state present.
- Return type:
- coupling_coefficient_matrix(coupling: Tuple[int | str | Tuple[float, ...] | List[int | str | Tuple[float, ...]] | Tuple[float | List[float], ...], int | str | Tuple[float, ...] | List[int | str | Tuple[float, ...]] | Tuple[float | List[float], ...]]) ndarray[source]¶
Matrix of coefficients representing coupling strength for a particular coupling.
- Returns:
Adjacency matrix of
couplingsattributes generated from the"coherent_cc"parameter on thecouplingedge.- Return type:
np.ndarray
Examples
>>> g = rq.ground_state(5, splitting="fs") >>> e = rq.D1_excited(5, splitting="fs") >>> my_cell = rq.Cell('Rb85', [g, e]) >>> my_cell.add_coupling(states=(g, e), rabi_frequency=1, detuning=1, label="probe") >>> sol = rq.solve_steady_state(my_cell) >>> for e in sol.couplings.edges(data="coherent_cc"): ... print(*e) (5, 0, 0.5, m_j=-0.5) (5, 0, 0.5, m_j=-0.5) None (5, 0, 0.5, m_j=-0.5) (5, 0, 0.5, m_j=0.5) None (5, 0, 0.5, m_j=-0.5) (5, 1, 0.5, m_j=-0.5) -0.816496580927726 (5, 0, 0.5, m_j=0.5) (5, 0, 0.5, m_j=-0.5) None (5, 0, 0.5, m_j=0.5) (5, 0, 0.5, m_j=0.5) None (5, 0, 0.5, m_j=0.5) (5, 1, 0.5, m_j=0.5) 0.816496580927726 (5, 1, 0.5, m_j=-0.5) (5, 0, 0.5, m_j=-0.5) None (5, 1, 0.5, m_j=-0.5) (5, 0, 0.5, m_j=0.5) None (5, 1, 0.5, m_j=0.5) (5, 0, 0.5, m_j=-0.5) None (5, 1, 0.5, m_j=0.5) (5, 0, 0.5, m_j=0.5) None >>> print(sol.coupling_coefficient_matrix(sol.probe_tuple)) [[ 0. 0. 0. 0. ] [ 0. 0. 0. 0. ] [-0.816497 0. 0. 0. ] [ 0. 0.816497 0. 0. ]]
- coupling_coefficient_observable(coupling: Tuple[int | str | Tuple[float, ...] | List[int | str | Tuple[float, ...]] | Tuple[float | List[float], ...], int | str | Tuple[float, ...] | List[int | str | Tuple[float, ...]] | Tuple[float | List[float], ...]] | None = None)[source]¶
Get the observable associated with the output of
coupling_coefficient_matrix().Calls the
get_observable()function with the output ofcoupling_coefficient_matrix(), with rows and columns limited those defined by the probe coupling. IfcouplingisNone, uses the tuple defined byprobe_tuple.This function is designed to get observable values associated with the probe laser in an experiment, such as transmission and absorption coefficients.
- Parameters:
coupling (tuple of int or string, optional) – The 2-length tuple of state specifications to use in the observable calculation. Each state can be either an
intor a regex string corresponding to a group of states. IfNone, uses theprobe_tupleattribute as defined in theSensorused to produce the solution. Defaults toNone.- Returns:
The observable or array of observables corresponding to the coupling coefficients.
- Return type:
np.ndarray
- coupling_rabi(coupling: Tuple[int | str | Tuple[float, ...] | List[int | str | Tuple[float, ...]] | Tuple[float | List[float], ...], int | str | Tuple[float, ...] | List[int | str | Tuple[float, ...]] | Tuple[float | List[float], ...]]) complex | ndarray[source]¶
Rabi frequency, in Mrad/s, of a particular coupling or coupling group.
Serves as a more general way of fetching a rabi frequency from the graph that supports couplings between manifolds. Throws an error if any of the couplings in the group specified by
couplingdo not have matchingrabi_frequency, either in values or shape.- Parameters:
coupling (tuple of states) – Pair of states or state manifolds specifying a coupling or coupling group respectively. If a group, all couplings in the group must have matching values and shapes for the
rabi_frequency. This is most easily accomplished by adding the coupling to the group usingadd_coupling()with manifolds, butzip_parameters()can also be used.- Returns:
The
rabi_frequencyof the coupling or of all couplings in the group specified bycoupling.- Return type:
float or np.ndarray
- Raises:
ValueError – If
couplingis a group with mismatched rabi frequencies, either in shape or value, or coupling has no defined rabi frequencies.
Examples
The basic functionality for couplings between single states mimics the functionality of just accessing the
rabi_frequencyattribute from the graph.>>> my_sensor = rq.Sensor(2) >>> my_sensor.add_coupling((0,1), rabi_frequency=1, detuning=1) >>> my_sensor.add_decoherence((1,0), 0.1) >>> sol = rq.solve_steady_state(my_sensor) >>> print(sol.couplings.edges[0,1]["rabi_frequency"]) 1 >>> print(sol.coupling_rabi((0,1))) 1
It can also get the
rabi_frequencyfor an entire coupling group. Therabi_frequencyis treated as a laser property. Coupling coefficients as individual coupling properties, and so are not accounted for.>>> g = (0,0) >>> e = (1, [-1,1]) >>> cc = { ... (g, (1,-1)): 0.5, ... (g, (1,1)): 0.5 ... } >>> my_sensor = rq.Sensor([g,e]) >>> my_sensor.add_coupling((g,e), rabi_frequency=5, detuning=1, label="probe") >>> my_sensor.add_decoherence((e,g), 0.1, label="foo") >>> sol = rq.solve_steady_state(my_sensor) >>> print(sol.couplings.edges.data("rabi_frequency")) [((0, 0), (1, -1), 5), ((0, 0), (1, 1), 5), ((1, -1), (0, 0), None), ((1, 1), (0, 0), None)] >>> print(sol.coupling_rabi((g,e))) 5
- dm_basis: ndarray¶
The list of density matrix elements in the order they appear in the solution. See
Sensor.basis()for details.
- doppler_classes: ndarray | None¶
Doppler classes used to perform the doppler average. Will be None if doppler averaging was not used.
- Type:
numpy.ndarray, optional
- get_OD() float | ndarray[source]¶
Calculates the optical depth from the solution. This equation comes from Steck’s Quantum Optics Notes Eq. 6.74.
Assumes the optically-thin approximation is valid. If a calculated OD for a solution exceeds 1, this approximation is likely invalid.
- Returns:
OD – Optical depth of the sample
- Return type:
- Warns:
UserWarning – If any OD exceeds 1, which indicates the optically-thin approximation is likely invalid.
Examples
>>> [g, e] = rq.D2_states('Rb85') >>> c = rq.Cell('Rb85', [g, e], cell_length = 0.0001) >>> c.add_coupling(states=(g, e), rabi_frequency=1, detuning=1) >>> sols = rq.solve_steady_state(c) >>> print(sols.rho.shape) (3,) >>> OD = sols.get_OD() >>> print(OD) 0.2964844
- get_observable(matrix: ndarray)[source]¶
Returns the trace of a matrix product of the density matrix with a provided matrix. This is the standard definition of an measurement of observable \(A\) taken on a density matrix \(\rho\) given by \(tr(\rho A)\). Note that this function first converts the density matrix into the standard complex basis rather than rydiqule’s real basis, leading to potential round-off errors for very small density matrix elements.
The provided observable wil respect
rydiqulestacking convention, and the labels for each axis can be recovered via theaxis_labelsattribute.- Parameters:
matrix (np.ndarray) – The matrix representing the observable to be computed.
- Returns:
Array of observables using rydiqule’s stacking convention.
- Return type:
np.ndarray
- get_phase_shift() float | ndarray[source]¶
Extract the phase shift from a solution.
Assumes the optically-thin approximation is valid.
- Returns:
Probe phase in radians.
- Return type:
Examples
>>> [g, e] = rq.D2_states('Rb85') >>> c = rq.Cell('Rb85', [g, e], cell_length = 0.00001) >>> c.add_coupling(states=(g, e), rabi_frequency=1, detuning=1) >>> sols = rq.solve_steady_state(c) >>> print(sols.rho.shape) (3,) >>> print(sols.get_phase_shift()) 80.5294887
- get_solution_element(idx: int) float | ndarray[source]¶
Return a slice of an n_dimensional matrix of solutions of shape (…,n^2-1), where n is the basis size of the quantum system.
- Parameters:
idx (int) – Solution index to slice.
- Returns:
Slice of solutions corresponding to index idx. For example, if sols has shape (…, n^2-1), sol_slice will have shape (…).
- Return type:
- Raises:
RydiquleError – If
idxin not within the shape determined by basis size.
Examples
>>> [g, e] = rq.D2_states("Rb85", expand=True) >>> c = rq.Cell('Rb85', [g, e]) >>> c.add_coupling(states=(g, e), rabi_frequency=1, detuning=1) >>> sols = rq.solve_steady_state(c) >>> print(sols.rho.shape) (3,) >>> rho_01_im = sols.get_solution_element(0) >>> print(rho_01_im) 0.00131399
- get_susceptibility() complex | ndarray[source]¶
Return the atomic susceptibility on the probe transition.
Experimental parameters must be defined manually for a
Sensor.- Returns:
Susceptibility of the density matrix solution.
- Return type:
Examples
>>> [g, e] = rq.D2_states(5, expand=True) >>> c = rq.Cell('Rb85', [g, e], cell_length = 0.0001) >>> c.add_coupling(states=(g,e), rabi_frequency=1, detuning=1) >>> sols = rq.solve_steady_state(c) >>> print(sols.rho.shape) (3,) >>> sus = sols.get_susceptibility() >>> print(sus) (1.891136e-05+0.00036817j)
- get_transmission_coef() float | ndarray[source]¶
Extract the transmission term from a solution.
Assumes the optically-thin approximation is valid.
- Returns:
Numerical value of the probe absorption in fractional units (P_out/P_in).
- Return type:
Examples
>>> [g, e] = rq.D2_states('Rb85') >>> c = rq.Cell('Rb85', [g, e], cell_length = 0.0001) >>> c.add_coupling(states=(g, e), rabi_frequency=1, detuning=1) >>> sols = rq.solve_steady_state(c) >>> print(sols.rho.shape) (3,) >>> t = sols.get_transmission_coef() >>> print(t) 0.743427
- property probe_freq: float¶
Probing transition frequency, in rad/s. Not generally defined when using a Sensor.
- property probe_rabi: complex | ndarray¶
Base laser rabi frequency of the probing transition of the
Sensorused in a solve.The return of this function will be the appropriate shape to be cast using rydiqule’s stacking convention. An error will be thrown if any of the base rabi frequencies of the probe coupling group do not match. (All rabi frequencies should match if added using
add_coupling_groupand not overwritten)- Returns:
The base rabi frequency of the transition defined as the rabi frequency of any of the
couplings in the group divided by the
coherent_ccon the corresponding edge (default 1).
- property probe_tuple: Tuple[int | str | Tuple[float, ...] | List[int | str | Tuple[float, ...]] | Tuple[float | List[float], ...], int | str | Tuple[float, ...] | List[int | str | Tuple[float, ...]] | Tuple[float | List[float], ...]]¶
Coupling edge corresponding to probing field. Defined as the first added coupling when using a Sensor.
- rho_ij(i: int | str | Tuple[float, ...], j: int | str | Tuple[float, ...]) complex | ndarray[source]¶
Gets the full complex density matrix element corresponding to a given pair of indices.
Returns the entire array of density matrix elements corresponding to every combination of parameters defined by the mesh of parameters in the system. The shape of the output array will match the
stack_shapeof the solution.Indices can be provided either as integers which number the states, or using state labels (integers, tuples, or strings). For the case of tuples, only individual states can be used, full state specifications are invalid
In the case of a state, it will be mapped to the corresponding integer, then the element itself is fetched using the
get_rho_ij()function.- Parameters:
- Returns:
[i,j]complex element(s) of the density matrix- Return type:
Examples
State labels and integer indices can be used interchangeably.
>>> rabis = np.linspace(1, 6, 5) >>> my_sensor = rq.Sensor(["g","e"]) >>> my_sensor.add_coupling(("g","e"), rabi_frequency=rabis, detuning=1) >>> my_sensor.add_decoherence(("e","g"), 0.1) >>> sol = rq.solve_steady_state(my_sensor) >>> print(sol.rho_ij("g","e")) [0.3328-0.0166j 0.3184-0.0159j 0.2455-0.0123j 0.1933-0.0097j 0.1579-0.0079j] >>> print(sol.rho_ij(0,1)) [0.3328-0.0166j 0.3184-0.0159j 0.2455-0.0123j 0.1933-0.0097j 0.1579-0.0079j]
- property states: List[int | str | Tuple[float, ...]]¶
Return a list of all states in the
Sensorused to produce solution.- Returns:
List of all states in the sensor used to produce solution. Order will match order in
Sensor.- Return type:
list of states