{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Complex Numbers\n", "\n", "QCoDeS natively supports complex numbers via the complex datatypes of `numpy`." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Complex-valued parameters\n", "\n", "QCoDeS parameters can take complex values. There are two types of complex-valued parameters: scalar-valued parameters and array-valued parameters." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Scalar-valued parameters\n", "\n", "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.\n", "\n", "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." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from qcodes.parameters import Parameter\n", "from qcodes.validators import ComplexNumbers" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "imp = Parameter(\n", " name=\"imp\",\n", " label=\"Impedance\",\n", " unit=\"Ohm\",\n", " initial_value=50 + 0j,\n", " set_cmd=None,\n", " get_cmd=None,\n", " vals=ComplexNumbers(),\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `ComplexNumbers` validator requires explicitly complex values. `float`s and `int`s will *not* pass." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Sorry, but 1.0 is not complex\n", "Sorry, but -1.0 is not complex\n", "Sorry, but 8.2 is not complex\n", "Sorry, but 3.141592653589793 is not complex\n" ] } ], "source": [ "for value in np.array([1, -1, 8.2, np.pi]):\n", " try:\n", " imp(value)\n", " print(f\"Succesfully set the parameter to {value}\")\n", " except TypeError:\n", " print(f\"Sorry, but {value} is not complex\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The easiest way to make a scalar value complex is probably by adding `0j` to it." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Succesfully set the parameter to (1+0j)\n", "Succesfully set the parameter to (-1+0j)\n", "Succesfully set the parameter to (8.2+0j)\n", "Succesfully set the parameter to (3.141592653589793+0j)\n" ] } ], "source": [ "for value in np.array([1, -1, 8.2, np.pi]) + 0j:\n", " try:\n", " imp(value)\n", " print(f\"Succesfully set the parameter to {value}\")\n", " except TypeError:\n", " print(f\"Sorry, but {value} is not complex\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Array-valued parameters\n", "\n", "There is no separate complex-valued array validator, since the `Arrays` validator can be customized to cover any real or complex valued case.\n", "\n", "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)." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "from qcodes.validators import Arrays" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "amps_val_strict = Arrays(shape=(5,), valid_types=(np.complexfloating,))\n", "amps_val_lax = Arrays(\n", " shape=(5,), valid_types=(np.complexfloating, np.floating, np.integer)\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The strict validator is strict:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Sorry, but integers are not strictly complex\n", "Sorry, but floats are not strictly complex\n" ] } ], "source": [ "try:\n", " amps_val_strict.validate(np.array([1, 2, 3, 4, 5]))\n", "except TypeError:\n", " print(\"Sorry, but integers are not strictly complex\")\n", "\n", "try:\n", " amps_val_strict.validate(np.array([1.0, 2.0, 3.0, 4.0, 5.0]))\n", "except TypeError:\n", " print(\"Sorry, but floats are not strictly complex\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But note, that the presence of a single imaginary part will cast the whole array as complex:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1.+0.j 2.+0.j 3.+0.j 4.+0.j 5.+0.j]\n", "complex128\n", "Yeah, those are complex numbers\n" ] } ], "source": [ "my_array = np.array([1.0 + 0j, 2.0, 3.0, 4.0, 5.0])\n", "print(my_array)\n", "print(my_array.dtype)\n", "amps_val_strict.validate(np.array([1.0 + 0j, 2.0, 3.0, 4.0, 5.0]))\n", "print(\"Yeah, those are complex numbers\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The lax validator let's everything through:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "amps_val_lax.validate(np.array([1, 2, 3, 4, 5]))\n", "amps_val_lax.validate(np.array([1.0, 2.0, 3.0, 4.0, 5.0]))\n", "amps_val_lax.validate(np.array([1.0 + 0j, 2, 3, 4, 5]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use either validator for the parameter." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "amplitudes = Parameter(\n", " name=\"amplitudes\",\n", " label=\"Amplitudes\",\n", " unit=\"\",\n", " set_cmd=None,\n", " get_cmd=None,\n", " vals=amps_val_strict,\n", " initial_value=(1 / np.sqrt(2) * np.array([1 + 1j, 0, 0, 0, 0])),\n", ")" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([0.70710678+0.70710678j, 0. +0.j ,\n", " 0. +0.j , 0. +0.j ,\n", " 0. +0.j ])" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "amplitudes()" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "amplitudes(1 / np.sqrt(2) * np.array([0, 1 + 1j, 0, 0, 0]))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 2 }