This page was generated from docs/examples/Parameters/Complex_Parameters.ipynb. Interactive online version: Binder badge.

Complex Numbers

QCoDeS natively supports complex numbers via the complex datatypes of numpy.

[1]:
import numpy as np

Complex-valued parameters

QCoDeS parameters can take complex values. There are two types of complex-valued parameters: scalar-valued parameters and array-valued parameters.

Scalar-valued parameters

Let us create a complex-valued parameter and set and get values for it. An example that one might encounter in physics is the complex impedance.

For any QCoDeS parameter, it holds that adding input validation is a good idea. Complex parameters are no exception. We therefore use the ComplexNumbers validator with our complex parameter.

[2]:
from qcodes.parameters import Parameter
from qcodes.validators import ComplexNumbers
Logging hadn't been started.
Activating auto-logging. Current session state plus future input saved.
Filename       : /home/runner/.qcodes/logs/command_history.log
Mode           : append
Output logging : True
Raw input log  : False
Timestamping   : True
State          : active
Qcodes Logfile : /home/runner/.qcodes/logs/241122-19724-qcodes.log
[3]:
imp = Parameter(
    name="imp",
    label="Impedance",
    unit="Ohm",
    initial_value=50 + 0j,
    set_cmd=None,
    get_cmd=None,
    vals=ComplexNumbers(),
)

The ComplexNumbers validator requires explicitly complex values. floats and ints will not pass.

[4]:
for value in np.array([1, -1, 8.2, np.pi]):
    try:
        imp(value)
        print(f"Succesfully set the parameter to {value}")
    except TypeError:
        print(f"Sorry, but {value} is not complex")
Sorry, but 1.0 is not complex
Sorry, but -1.0 is not complex
Sorry, but 8.2 is not complex
Sorry, but 3.141592653589793 is not complex

The easiest way to make a scalar value complex is probably by adding 0j to it.

[5]:
for value in np.array([1, -1, 8.2, np.pi]) + 0j:
    try:
        imp(value)
        print(f"Succesfully set the parameter to {value}")
    except TypeError:
        print(f"Sorry, but {value} is not complex")
Succesfully set the parameter to (1+0j)
Succesfully set the parameter to (-1+0j)
Succesfully set the parameter to (8.2+0j)
Succesfully set the parameter to (3.141592653589793+0j)

Array-valued parameters

There is no separate complex-valued array validator, since the Arrays validator can be customized to cover any real or complex valued case.

Let’s make a little array to hold some quantum state amplitudes. Let’s pretend to be in a 5-dimensional Hilbert space. Our state parameter should thus hold 5 complex numbers (the state expansion coefficients in some implicit basis).

[6]:
from qcodes.validators import Arrays

The proper validator should accept complex numbers and should reject anything of the wrong shape. Note that we get to decide whether we want to accept “non-strictly complex” data.

[7]:
amps_val_strict = Arrays(shape=(5,), valid_types=(np.complexfloating,))
amps_val_lax = Arrays(
    shape=(5,), valid_types=(np.complexfloating, np.floating, np.integer)
)

The strict validator is strict:

[8]:
try:
    amps_val_strict.validate(np.array([1, 2, 3, 4, 5]))
except TypeError:
    print("Sorry, but integers are not strictly complex")

try:
    amps_val_strict.validate(np.array([1.0, 2.0, 3.0, 4.0, 5.0]))
except TypeError:
    print("Sorry, but floats are not strictly complex")
Sorry, but integers are not strictly complex
Sorry, but floats are not strictly complex

But note, that the presence of a single imaginary part will cast the whole array as complex:

[9]:
my_array = np.array([1.0 + 0j, 2.0, 3.0, 4.0, 5.0])
print(my_array)
print(my_array.dtype)
amps_val_strict.validate(np.array([1.0 + 0j, 2.0, 3.0, 4.0, 5.0]))
print("Yeah, those are complex numbers")
[1.+0.j 2.+0.j 3.+0.j 4.+0.j 5.+0.j]
complex128
Yeah, those are complex numbers

The lax validator let’s everything through:

[10]:
amps_val_lax.validate(np.array([1, 2, 3, 4, 5]))
amps_val_lax.validate(np.array([1.0, 2.0, 3.0, 4.0, 5.0]))
amps_val_lax.validate(np.array([1.0 + 0j, 2, 3, 4, 5]))

We can use either validator for the parameter.

[11]:
amplitudes = Parameter(
    name="amplitudes",
    label="Amplitudes",
    unit="",
    set_cmd=None,
    get_cmd=None,
    vals=amps_val_strict,
    initial_value=(1 / np.sqrt(2) * np.array([1 + 1j, 0, 0, 0, 0])),
)
[12]:
amplitudes()
[12]:
array([0.70710678+0.70710678j, 0.        +0.j        ,
       0.        +0.j        , 0.        +0.j        ,
       0.        +0.j        ])
[13]:
amplitudes(1 / np.sqrt(2) * np.array([0, 1 + 1j, 0, 0, 0]))
[ ]: