Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ DDSIM version of Estimator primitive #327

Merged
merged 10 commits into from
Dec 22, 2023
222 changes: 216 additions & 6 deletions docs/source/Primitives.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,7 @@
"\n",
"The two currently available primitives are the `Sampler` and the `Estimator`. The first one computes quasi-probability distributions from circuit measurements, while the second one calculates and interprets expectation values of quantum operators that are required for many near-term quantum algorithms.\n",
"\n",
"DDSIM provides its own version of these Qiskit Primitives:\n",
"\n",
"- `Sampler` leverages the default circuit simulator based on decision diagrams, while preserving the methods and functionality of the original Qiskit's sampler.\n",
"\n",
"- `Estimator` is currently in development and will be available soon.\n"
"DDSIM provides its own version of these Qiskit Primitives that leverage the default circuit simulator based on decision diagrams, while preserving the methods and functionality of the original Qiskit primitives."
]
},
{
Expand Down Expand Up @@ -262,11 +258,225 @@
"dist = sampler.run(qc, shots=int(1e4)).result().quasi_dists[0]\n",
"plot_distribution(dist.binary_probabilities())"
]
},
{
"cell_type": "markdown",
"id": "9e706eec",
"metadata": {},
"source": [
"## Estimator"
]
},
{
"cell_type": "markdown",
"id": "42304e06",
"metadata": {},
"source": [
"The `Estimator` calculates the expectation value of an observable with respect to a certain quantum state (described by a quantum circuit). In contrast to Qiskit's estimator, the DDSIM version exactly computes the expectation value using its simulator based on decision diagrams instead of sampling.\n",
"\n",
"The `Estimator` also handles parameter binding when dealing with parametrized circuits.\n",
"\n",
"Here we show an example on how to use it:"
]
},
{
"cell_type": "markdown",
"id": "7068a1b9",
"metadata": {},
"source": [
"First, we build the observable and the quantum state. The observable is given as a `SparsePauliOp` object, while the quantum state is described by a `QuantumCircuit`.\n",
"\n",
"In this example, our observable is the Pauli matrix $\\sigma_{x}$ and the quantum state is $\\frac{1}{\\sqrt{2}}(|0\\rangle + |1\\rangle)$."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ce1f92d8",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"from qiskit import QuantumCircuit\n",
"from qiskit.circuit import Parameter\n",
"from qiskit.quantum_info import Pauli\n",
"\n",
"from mqt.ddsim.primitives.estimator import Estimator\n",
"\n",
"# Build quantum state\n",
"circ = QuantumCircuit(1)\n",
"circ.ry(np.pi / 2, 0)\n",
"circ.measure_all()\n",
"\n",
"# Build observable\n",
"pauli_x = Pauli(\"X\")\n",
"\n",
"# Show circuit\n",
"circ.draw(\"mpl\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e6a0403a",
"metadata": {},
"outputs": [],
"source": [
"# Initialize estimator\n",
"\n",
"estimator = Estimator()"
]
},
{
"cell_type": "markdown",
"id": "4681e409",
"metadata": {},
"source": [
"The next step involves running the estimation using the `run()` method. This method requires three arguments: a sequence of `QuantumCircuit` objects representing quantum states, a sequence of `SparsePauliOp` objects representing observables, and optionally, a parameter sequence if we are dealing with parametrized circuits.\n",
"\n",
"The user has to ensure that the number of circuits matches the number of observables, as the estimator pairs corresponding elements from both lists sequentially."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3a8a27a6",
"metadata": {},
"outputs": [],
"source": [
"# Enter observable and circuit as a sequence\n",
"\n",
"job = estimator.run([circ], [pauli_x])\n",
"result = job.result()"
]
},
{
"cell_type": "markdown",
"id": "38f41050",
"metadata": {},
"source": [
"The `result()` method of the job returns a `EstimatorResult` object, which contains the computed expectation values."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "88316971",
"metadata": {},
"outputs": [],
"source": [
"print(f\">>> {result}\")\n",
"print(f\" > Expectation values: {result.values}\")"
]
},
{
"cell_type": "markdown",
"id": "c5b267cb",
"metadata": {},
"source": [
"Now we explore how the `Estimator` works with multiple circuits and observables. For this example, we will calculate the expectation value of $\\sigma_{x}$ and $\\sigma_{y}$ with respect to the quantum state $|1\\rangle$. Since our observable list has a length of 2, we need to enter two copies of the `QuantumCircuit` object representing $|1\\rangle$ as a sequence:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8d732634",
"metadata": {},
"outputs": [],
"source": [
"# Build quantum state\n",
"circ = QuantumCircuit(1)\n",
"circ.ry(np.pi, 0)\n",
"circ.measure_all()\n",
"\n",
"# Build observables\n",
"pauli_x = Pauli(\"X\")\n",
"pauli_y = Pauli(\"Y\")\n",
"\n",
"# Construct input arguments\n",
"observables = [pauli_x, pauli_y]\n",
"quantum_states = [circ, circ]\n",
"\n",
"# Run estimator\n",
"job = estimator.run(quantum_states, observables)\n",
"result = job.result()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5cc6e1dc",
"metadata": {},
"outputs": [],
"source": [
"print(f\">>> {result}\")\n",
"print(f\" > Expectation values: {result.values}\")"
]
},
{
"cell_type": "markdown",
"id": "9d4caecc",
"metadata": {},
"source": [
"The first and second entries of the list of values are the expectation value of $\\sigma_{x}$ and $\\sigma_{y}$ respectively."
]
},
{
"cell_type": "markdown",
"id": "251487b1",
"metadata": {},
"source": [
"Let's now calculate the expectation values of $\\sigma_{x}$ with respect to $\\frac{1}{\\sqrt{2}}(|0\\rangle + |1\\rangle)$ and $\\frac{1}{\\sqrt{2}}(|0\\rangle - |1\\rangle)$. For this example we will use parametrized circuits to build the quantum state."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ee3f93bb",
"metadata": {},
"outputs": [],
"source": [
"theta = Parameter(\"theta\")\n",
"circ_2 = QuantumCircuit(1)\n",
"circ_2.ry(theta, 0)\n",
"circ_2.measure_all()\n",
"\n",
"# Show circuit\n",
"circ_2.draw(\"mpl\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5610c6fa",
"metadata": {},
"outputs": [],
"source": [
"# Construct input arguments\n",
"observables = [pauli_x, pauli_x]\n",
"quantum_states = [circ_2, circ_2]\n",
"parameters = [[np.pi / 2], [-np.pi / 2]]\n",
"\n",
"# Run estimator\n",
"job = estimator.run(quantum_states, observables, parameters)\n",
"result = job.result()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9262c988",
"metadata": {},
"outputs": [],
"source": [
"print(f\">>> {result}\")\n",
"print(f\" > Expectation values: {result.values}\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"display_name": "My Virtual Environment",
"language": "python",
"name": "venv"
},
Expand Down
Loading