![](/img/logo.png)
<p align="center">
<img title="license" src="https://img.shields.io/badge/license-Apache_2.0-blue.svg">
<img title="python" src="https://img.shields.io/badge/python-≥3.9-blue.svg">
<a href="https://qiskit.org/ecosystem/" alt="Ecosystem">
<img src="https://img.shields.io/badge/Qiskit-Ecosystem-blueviolet.svg" /></a>
</p>
<p align="center">
<img title="build" src='https://github.com/SimoneGasperini/qiskit-symb/actions/workflows/python-package.yml/badge.svg?branch=master'>
<img title="coverage" src='https://coveralls.io/repos/github/SimoneGasperini/qiskit-symb/badge.svg?branch=master'>
</p>
***
[Qiskit DemoDays](https://github.com/Qiskit/feedback/wiki/Qiskit-DemoDays) presentation $\rightarrow$ :link:[link](https://ibm.webex.com/recordingservice/sites/ibm/recording/playback/c6d96f25edba103bb7d600505681044d),
password: `Demoday20230615` (15th June 2023)
Jupyter notebook demo $\rightarrow$ :link:[link](https://github.com/Qiskit/feedback/blob/main/demo-day-notebooks/2023-06-15/1_qiskit_symb_demo.ipynb) (15th June 2023)
Qiskit Medium blog $\rightarrow$ :link:[link](https://medium.com/p/b6b4407fa705) (28th June 2023)
***
# Table of contents
- [Introduction](#introduction)
- [Installation](#installation)
- [User-mode](#user-mode)
- [Dev-mode](#dev-mode)
- [Usage examples](#usage-examples)
- [_Sympify_ a Qiskit circuit](#sympify-a-qiskit-circuit)
- [_Lambdify_ a Qiskit circuit](#lambdify-a-qiskit-circuit)
- [Contributors](#contributors)
# Introduction
The `qiskit-symb` package is meant to be a Python tool to enable the symbolic evaluation of parametric quantum states and operators defined in [Qiskit](https://github.com/Qiskit/qiskit) by parameterized quantum circuits.
A Parameterized Quantum Circuit (PQC) is a quantum circuit where we have at least one free parameter (e.g. a rotation angle $\theta$). PQCs are particularly relevant in Quantum Machine Learning (QML) models, where the values of these parameters can be learned during training to reach the desired output.
In particular, `qiskit-symb` can be used to create a symbolic representation of a parametric quantum statevector, density matrix, or unitary operator directly from the Qiskit quantum circuit. This has been achieved through the re-implementation of some basic classes defined in the [`qiskit/quantum_info/`](https://github.com/Qiskit/qiskit/tree/main/qiskit/quantum_info) module by using [sympy](https://github.com/sympy/sympy) as a backend for symbolic expressions manipulation.
# Installation
## User-mode
```
pip install qiskit-symb
```
:warning: The package requires `qiskit>=1`. See the official [Migration guides](https://docs.quantum.ibm.com/api/migration-guides) if you are used to a prevoius Qiskit version.
## Dev-mode
```
git clone https://github.com/SimoneGasperini/qiskit-symb.git
cd qiskit-symb
pip install -e .
```
# Usage examples
### _Sympify_ a Qiskit circuit
Let's get started on how to use `qiskit-symb` to get the symbolic representation of a given Qiskit circuit. In particular, in this first basic example, we consider the following quantum circuit:
```python
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter, ParameterVector
y = Parameter('y')
p = ParameterVector('p', length=2)
pqc = QuantumCircuit(2)
pqc.ry(y, 0)
pqc.cx(0, 1)
pqc.u(0, *p, 1)
pqc.draw('mpl')
```
![](/img/example_circuit.png)
To get the *sympy* representation of the unitary matrix corresponding to the parameterized circuit, we just have to create the symbolic `Operator` instance and call the `to_sympy()` method:
```python
from qiskit_symb.quantum_info import Operator
op = Operator(pqc)
op.to_sympy()
```
```math
\left[\begin{matrix}\cos{\left(\frac{y}{2} \right)} & - \sin{\left(\frac{y}{2} \right)} & 0 & 0\\0 & 0 & \sin{\left(\frac{y}{2} \right)} & \cos{\left(\frac{y}{2} \right)}\\0 & 0 & e^{i \left(p[0] + p[1]\right)} \cos{\left(\frac{y}{2} \right)} & - e^{i \left(p[0] + p[1]\right)} \sin{\left(\frac{y}{2} \right)}\\e^{i \left(p[0] + p[1]\right)} \sin{\left(\frac{y}{2} \right)} & e^{i \left(p[0] + p[1]\right)} \cos{\left(\frac{y}{2} \right)} & 0 & 0\end{matrix}\right]
```
If you want then to assign a value to some specific parameter, you can use the `subs(<dict>)` method passing a dictionary that maps each parameter to the desired corresponding value:
```python
new_op = op.subs({p: [-1, 2]})
new_op.to_sympy()
```
```math
\left[\begin{matrix}\cos{\left(\frac{y}{2} \right)} & - \sin{\left(\frac{y}{2} \right)} & 0 & 0\\0 & 0 & \sin{\left(\frac{y}{2} \right)} & \cos{\left(\frac{y}{2} \right)}\\0 & 0 & e^{i} \cos{\left(\frac{y}{2} \right)} & - e^{i} \sin{\left(\frac{y}{2} \right)}\\e^{i} \sin{\left(\frac{y}{2} \right)} & e^{i} \cos{\left(\frac{y}{2} \right)} & 0 & 0\end{matrix}\right]
```
### _Lambdify_ a Qiskit circuit
Given a Qiskit circuit, `qiskit-symb` also allows to generate a Python lambda function with actual arguments matching the Qiskit unbound parameters.
Let's consider the following example starting from a `ZZFeatureMap` circuit, commonly used as a data embedding ansatz in QML applications:
```python
from qiskit.circuit.library import ZZFeatureMap
pqc = ZZFeatureMap(feature_dimension=3, reps=1)
pqc.draw('mpl')
```
![](/img/zzfeaturemap_circuit.png)
To get the Python function representing the final parameteric statevector, we just have to create the symbolic `Statevector` instance and call the `to_lambda()` method:
```python
from qiskit_symb.quantum_info import Statevector
pqc = pqc.decompose()
statevec = Statevector(pqc).to_lambda()
```
We can now call the lambda-generated function `statevec` passing the `x` values we want to assign to each parameter. The returned object will be a *numpy* 2D-array (with `shape=(8,1)` in this case) representing the final output statevector `psi`.
```python
x = [1.24, 2.27, 0.29]
psi = statevec(*x)
```
This feature can be useful when, given a Qiskit PQC, we want to run it multiple times with different parameters values. Indeed, we can perform a single symbolic evalutation and then call the lambda generated function as many times as needed, passing different values of the parameters at each iteration.
# Contributors
<table>
<tr>
<td align="center"><a href="https://github.com/SimoneGasperini"><img src="https://avatars2.githubusercontent.com/u/71086758?s=400&v=4" width="120px;"/><br/><b>Simone Gasperini</b></a></td>
</tr>
</table>
Raw data
{
"_id": null,
"home_page": null,
"name": "qiskit-symb",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "quantum-computing, symbolic-computation, qiskit, sympy",
"author": null,
"author_email": "Simone Gasperini <simone.gasperini4@unibo.it>",
"download_url": "https://files.pythonhosted.org/packages/34/f3/d7a9882de6bed7e9b9a652044c0bfa448265c03d74789a28963c12d2a3c7/qiskit_symb-0.2.1.tar.gz",
"platform": null,
"description": "![](/img/logo.png)\n\n<p align=\"center\">\n <img title=\"license\" src=\"https://img.shields.io/badge/license-Apache_2.0-blue.svg\">\n <img title=\"python\" src=\"https://img.shields.io/badge/python-\u22653.9-blue.svg\">\n <a href=\"https://qiskit.org/ecosystem/\" alt=\"Ecosystem\">\n <img src=\"https://img.shields.io/badge/Qiskit-Ecosystem-blueviolet.svg\" /></a>\n</p>\n\n<p align=\"center\">\n <img title=\"build\" src='https://github.com/SimoneGasperini/qiskit-symb/actions/workflows/python-package.yml/badge.svg?branch=master'>\n <img title=\"coverage\" src='https://coveralls.io/repos/github/SimoneGasperini/qiskit-symb/badge.svg?branch=master'>\n</p>\n\n***\n[Qiskit DemoDays](https://github.com/Qiskit/feedback/wiki/Qiskit-DemoDays) presentation $\\rightarrow$ :link:[link](https://ibm.webex.com/recordingservice/sites/ibm/recording/playback/c6d96f25edba103bb7d600505681044d),\npassword: `Demoday20230615` (15th June 2023)\n\nJupyter notebook demo $\\rightarrow$ :link:[link](https://github.com/Qiskit/feedback/blob/main/demo-day-notebooks/2023-06-15/1_qiskit_symb_demo.ipynb) (15th June 2023)\n\nQiskit Medium blog $\\rightarrow$ :link:[link](https://medium.com/p/b6b4407fa705) (28th June 2023)\n***\n\n# Table of contents\n- [Introduction](#introduction)\n- [Installation](#installation)\n - [User-mode](#user-mode)\n - [Dev-mode](#dev-mode)\n- [Usage examples](#usage-examples)\n - [_Sympify_ a Qiskit circuit](#sympify-a-qiskit-circuit)\n - [_Lambdify_ a Qiskit circuit](#lambdify-a-qiskit-circuit)\n- [Contributors](#contributors)\n\n\n# Introduction\nThe `qiskit-symb` package is meant to be a Python tool to enable the symbolic evaluation of parametric quantum states and operators defined in [Qiskit](https://github.com/Qiskit/qiskit) by parameterized quantum circuits.\n\nA Parameterized Quantum Circuit (PQC) is a quantum circuit where we have at least one free parameter (e.g. a rotation angle $\\theta$). PQCs are particularly relevant in Quantum Machine Learning (QML) models, where the values of these parameters can be learned during training to reach the desired output.\n\nIn particular, `qiskit-symb` can be used to create a symbolic representation of a parametric quantum statevector, density matrix, or unitary operator directly from the Qiskit quantum circuit. This has been achieved through the re-implementation of some basic classes defined in the [`qiskit/quantum_info/`](https://github.com/Qiskit/qiskit/tree/main/qiskit/quantum_info) module by using [sympy](https://github.com/sympy/sympy) as a backend for symbolic expressions manipulation.\n\n\n# Installation\n\n## User-mode\n```\npip install qiskit-symb\n```\n\n:warning: The package requires `qiskit>=1`. See the official [Migration guides](https://docs.quantum.ibm.com/api/migration-guides) if you are used to a prevoius Qiskit version.\n\n## Dev-mode\n```\ngit clone https://github.com/SimoneGasperini/qiskit-symb.git\ncd qiskit-symb\npip install -e .\n```\n\n\n# Usage examples\n\n### _Sympify_ a Qiskit circuit\nLet's get started on how to use `qiskit-symb` to get the symbolic representation of a given Qiskit circuit. In particular, in this first basic example, we consider the following quantum circuit:\n```python\nfrom qiskit import QuantumCircuit\nfrom qiskit.circuit import Parameter, ParameterVector\n\ny = Parameter('y')\np = ParameterVector('p', length=2)\n\npqc = QuantumCircuit(2)\npqc.ry(y, 0)\npqc.cx(0, 1)\npqc.u(0, *p, 1)\n\npqc.draw('mpl')\n```\n![](/img/example_circuit.png)\n\nTo get the *sympy* representation of the unitary matrix corresponding to the parameterized circuit, we just have to create the symbolic `Operator` instance and call the `to_sympy()` method:\n```python\nfrom qiskit_symb.quantum_info import Operator\n\nop = Operator(pqc)\nop.to_sympy()\n```\n```math\n\\left[\\begin{matrix}\\cos{\\left(\\frac{y}{2} \\right)} & - \\sin{\\left(\\frac{y}{2} \\right)} & 0 & 0\\\\0 & 0 & \\sin{\\left(\\frac{y}{2} \\right)} & \\cos{\\left(\\frac{y}{2} \\right)}\\\\0 & 0 & e^{i \\left(p[0] + p[1]\\right)} \\cos{\\left(\\frac{y}{2} \\right)} & - e^{i \\left(p[0] + p[1]\\right)} \\sin{\\left(\\frac{y}{2} \\right)}\\\\e^{i \\left(p[0] + p[1]\\right)} \\sin{\\left(\\frac{y}{2} \\right)} & e^{i \\left(p[0] + p[1]\\right)} \\cos{\\left(\\frac{y}{2} \\right)} & 0 & 0\\end{matrix}\\right]\n```\n\nIf you want then to assign a value to some specific parameter, you can use the `subs(<dict>)` method passing a dictionary that maps each parameter to the desired corresponding value:\n```python\nnew_op = op.subs({p: [-1, 2]})\nnew_op.to_sympy()\n```\n```math\n\\left[\\begin{matrix}\\cos{\\left(\\frac{y}{2} \\right)} & - \\sin{\\left(\\frac{y}{2} \\right)} & 0 & 0\\\\0 & 0 & \\sin{\\left(\\frac{y}{2} \\right)} & \\cos{\\left(\\frac{y}{2} \\right)}\\\\0 & 0 & e^{i} \\cos{\\left(\\frac{y}{2} \\right)} & - e^{i} \\sin{\\left(\\frac{y}{2} \\right)}\\\\e^{i} \\sin{\\left(\\frac{y}{2} \\right)} & e^{i} \\cos{\\left(\\frac{y}{2} \\right)} & 0 & 0\\end{matrix}\\right]\n```\n\n### _Lambdify_ a Qiskit circuit\nGiven a Qiskit circuit, `qiskit-symb` also allows to generate a Python lambda function with actual arguments matching the Qiskit unbound parameters.\nLet's consider the following example starting from a `ZZFeatureMap` circuit, commonly used as a data embedding ansatz in QML applications:\n```python\nfrom qiskit.circuit.library import ZZFeatureMap\n\npqc = ZZFeatureMap(feature_dimension=3, reps=1)\npqc.draw('mpl')\n```\n![](/img/zzfeaturemap_circuit.png)\n\nTo get the Python function representing the final parameteric statevector, we just have to create the symbolic `Statevector` instance and call the `to_lambda()` method:\n```python\nfrom qiskit_symb.quantum_info import Statevector\n\npqc = pqc.decompose()\nstatevec = Statevector(pqc).to_lambda()\n```\n\nWe can now call the lambda-generated function `statevec` passing the `x` values we want to assign to each parameter. The returned object will be a *numpy* 2D-array (with `shape=(8,1)` in this case) representing the final output statevector `psi`.\n```python\nx = [1.24, 2.27, 0.29]\npsi = statevec(*x)\n```\n\nThis feature can be useful when, given a Qiskit PQC, we want to run it multiple times with different parameters values. Indeed, we can perform a single symbolic evalutation and then call the lambda generated function as many times as needed, passing different values of the parameters at each iteration.\n\n# Contributors\n\n<table>\n <tr>\n <td align=\"center\"><a href=\"https://github.com/SimoneGasperini\"><img src=\"https://avatars2.githubusercontent.com/u/71086758?s=400&v=4\" width=\"120px;\"/><br/><b>Simone Gasperini</b></a></td>\n </tr>\n</table>\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "Symbolic evaluation of parameterized quantum circuits in Qiskit",
"version": "0.2.1",
"project_urls": null,
"split_keywords": [
"quantum-computing",
" symbolic-computation",
" qiskit",
" sympy"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "2bbb2c4f903765c190e508857809a9b06b2abae63f99f92f3e4ed6c6ddfb6589",
"md5": "ef04eef010b8dc73f3145417e8c1874d",
"sha256": "5df538c7cf27b71d104659470af9f474125036bc0062b5e5b56a35b130056235"
},
"downloads": -1,
"filename": "qiskit_symb-0.2.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "ef04eef010b8dc73f3145417e8c1874d",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 30663,
"upload_time": "2024-10-02T22:05:48",
"upload_time_iso_8601": "2024-10-02T22:05:48.179135Z",
"url": "https://files.pythonhosted.org/packages/2b/bb/2c4f903765c190e508857809a9b06b2abae63f99f92f3e4ed6c6ddfb6589/qiskit_symb-0.2.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "34f3d7a9882de6bed7e9b9a652044c0bfa448265c03d74789a28963c12d2a3c7",
"md5": "42535b955d0df1e83cca455d821c2472",
"sha256": "0ec94747e6d35b52d888f54ffa712104d4f82921085826b8b4eed0acedb86705"
},
"downloads": -1,
"filename": "qiskit_symb-0.2.1.tar.gz",
"has_sig": false,
"md5_digest": "42535b955d0df1e83cca455d821c2472",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 20625,
"upload_time": "2024-10-02T22:05:49",
"upload_time_iso_8601": "2024-10-02T22:05:49.526861Z",
"url": "https://files.pythonhosted.org/packages/34/f3/d7a9882de6bed7e9b9a652044c0bfa448265c03d74789a28963c12d2a3c7/qiskit_symb-0.2.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-02 22:05:49",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "qiskit-symb"
}