pyrauli 0.3.1__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. {pyrauli-0.3.1 → pyrauli-0.4.0}/CMakeLists.txt +2 -1
  2. {pyrauli-0.3.1 → pyrauli-0.4.0}/PKG-INFO +6 -2
  3. {pyrauli-0.3.1 → pyrauli-0.4.0}/README.md +1 -1
  4. pyrauli-0.4.0/benchmarks/test_benchmark_qaoa.py +43 -0
  5. {pyrauli-0.3.1 → pyrauli-0.4.0}/docs/guides/how_to_qiskit.rst +14 -0
  6. pyrauli-0.4.0/docs/guides/how_to_symbolic.rst +99 -0
  7. {pyrauli-0.3.1 → pyrauli-0.4.0}/docs/index.rst +1 -0
  8. {pyrauli-0.3.1 → pyrauli-0.4.0}/pyproject.toml +7 -2
  9. {pyrauli-0.3.1 → pyrauli-0.4.0}/src/pyrauli/__init__.py +17 -0
  10. {pyrauli-0.3.1 → pyrauli-0.4.0}/src/pyrauli/_core/bindings.cpp +333 -7
  11. {pyrauli-0.3.1 → pyrauli-0.4.0}/src/pyrauli/backend.py +2 -2
  12. {pyrauli-0.3.1 → pyrauli-0.4.0}/src/pyrauli/estimator.py +96 -32
  13. pyrauli-0.4.0/tests/snippets/test_symbolic_circuit_noise.py +22 -0
  14. pyrauli-0.4.0/tests/snippets/test_symbolic_circuit_snippet.py +19 -0
  15. pyrauli-0.4.0/tests/snippets/test_symbolic_coefficient_guide.py +53 -0
  16. pyrauli-0.4.0/tests/snippets/test_symbolic_observable_guide.py +46 -0
  17. pyrauli-0.4.0/tests/snippets/test_symbolic_sympy.py +24 -0
  18. {pyrauli-0.3.1 → pyrauli-0.4.0}/tests/test_backend.py +48 -2
  19. pyrauli-0.4.0/tests/test_symbolic.py +12 -0
  20. pyrauli-0.4.0/tests/test_symbolic_circuit.py +61 -0
  21. pyrauli-0.4.0/tests/test_symbolic_coefficient.py +76 -0
  22. pyrauli-0.4.0/tests/test_symbolic_observable.py +88 -0
  23. {pyrauli-0.3.1 → pyrauli-0.4.0}/.clang-format +0 -0
  24. {pyrauli-0.3.1 → pyrauli-0.4.0}/.github/workflows/benchmark.yml +0 -0
  25. {pyrauli-0.3.1 → pyrauli-0.4.0}/.github/workflows/ci.yml +0 -0
  26. {pyrauli-0.3.1 → pyrauli-0.4.0}/.github/workflows/doc.yml +0 -0
  27. {pyrauli-0.3.1 → pyrauli-0.4.0}/.github/workflows/pypi.yml +0 -0
  28. {pyrauli-0.3.1 → pyrauli-0.4.0}/.gitignore +0 -0
  29. {pyrauli-0.3.1 → pyrauli-0.4.0}/LICENSE +0 -0
  30. {pyrauli-0.3.1 → pyrauli-0.4.0}/benchmarks/test_benchmark_circuit.py +0 -0
  31. {pyrauli-0.3.1 → pyrauli-0.4.0}/benchmarks/test_benchmark_observable.py +0 -0
  32. {pyrauli-0.3.1 → pyrauli-0.4.0}/benchmarks/test_benchmark_qiskit.py +0 -0
  33. {pyrauli-0.3.1 → pyrauli-0.4.0}/docs/.gitignore +0 -0
  34. {pyrauli-0.3.1 → pyrauli-0.4.0}/docs/Makefile +0 -0
  35. {pyrauli-0.3.1 → pyrauli-0.4.0}/docs/_static/.gitkeep +0 -0
  36. {pyrauli-0.3.1 → pyrauli-0.4.0}/docs/_templates/.gitkeep +0 -0
  37. {pyrauli-0.3.1 → pyrauli-0.4.0}/docs/conf.py +0 -0
  38. {pyrauli-0.3.1 → pyrauli-0.4.0}/docs/explanation/theory.rst +0 -0
  39. {pyrauli-0.3.1 → pyrauli-0.4.0}/docs/guides/how_to_circuit.rst +0 -0
  40. {pyrauli-0.3.1 → pyrauli-0.4.0}/docs/guides/how_to_complexity.rst +0 -0
  41. {pyrauli-0.3.1 → pyrauli-0.4.0}/docs/guides/how_to_noise.rst +0 -0
  42. {pyrauli-0.3.1 → pyrauli-0.4.0}/docs/guides/how_to_observables.rst +0 -0
  43. {pyrauli-0.3.1 → pyrauli-0.4.0}/docs/make.bat +0 -0
  44. {pyrauli-0.3.1 → pyrauli-0.4.0}/docs/reference/api.rst +0 -0
  45. {pyrauli-0.3.1 → pyrauli-0.4.0}/docs/requirements.txt +0 -0
  46. {pyrauli-0.3.1 → pyrauli-0.4.0}/docs/tutorials/getting_started.rst +0 -0
  47. {pyrauli-0.3.1 → pyrauli-0.4.0}/examples/qiskit_backend.py +0 -0
  48. {pyrauli-0.3.1 → pyrauli-0.4.0}/src/pyrauli/converters.py +0 -0
  49. {pyrauli-0.3.1 → pyrauli-0.4.0}/tests/snippets/test_basic_circuit.py +0 -0
  50. {pyrauli-0.3.1 → pyrauli-0.4.0}/tests/snippets/test_observable_evolution.py +0 -0
  51. {pyrauli-0.3.1 → pyrauli-0.4.0}/tests/snippets/test_qiskit_backend_usage.py +0 -0
  52. {pyrauli-0.3.1 → pyrauli-0.4.0}/tests/snippets/test_readme.py +0 -0
  53. {pyrauli-0.3.1 → pyrauli-0.4.0}/tests/test_circuit.py +0 -0
  54. {pyrauli-0.3.1 → pyrauli-0.4.0}/tests/test_circuit_qiskit.py +0 -0
  55. {pyrauli-0.3.1 → pyrauli-0.4.0}/tests/test_noise_model.py +0 -0
  56. {pyrauli-0.3.1 → pyrauli-0.4.0}/tests/test_observable.py +0 -0
  57. {pyrauli-0.3.1 → pyrauli-0.4.0}/tests/test_observable_qiskit.py +0 -0
  58. {pyrauli-0.3.1 → pyrauli-0.4.0}/tests/test_pauli.py +0 -0
  59. {pyrauli-0.3.1 → pyrauli-0.4.0}/tests/test_policies.py +0 -0
  60. {pyrauli-0.3.1 → pyrauli-0.4.0}/tests/test_pyrauli.py +0 -0
  61. {pyrauli-0.3.1 → pyrauli-0.4.0}/tests/test_truncator.py +0 -0
@@ -15,7 +15,8 @@ FetchContent_Declare(
15
15
  FetchContent_Declare(
16
16
  propauli
17
17
  GIT_REPOSITORY https://github.com/zefresk/propauli.git
18
- GIT_TAG v2.1.0
18
+ #GIT_TAG v2.1.0
19
+ GIT_TAG symbolic
19
20
  )
20
21
 
21
22
  FetchContent_MakeAvailable(pybind11 propauli)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pyrauli
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: A very fast and easy to use Quantum circuit simulator relying on Pauli propagation. Compatible with qiskit.
5
5
  License: GNU GENERAL PUBLIC LICENSE
6
6
  Version 3, 29 June 2007
@@ -686,11 +686,15 @@ Project-URL: Homepage, https://github.com/zefresk/pyrauli
686
686
  Requires-Python: >=3.9
687
687
  Provides-Extra: qiskit
688
688
  Requires-Dist: qiskit>=2.0.0; extra == "qiskit"
689
+ Requires-Dist: numpy; extra == "qiskit"
690
+ Provides-Extra: symbolic
691
+ Requires-Dist: sympy; extra == "symbolic"
689
692
  Provides-Extra: test
690
693
  Requires-Dist: pytest>=8.0.0; extra == "test"
691
694
  Requires-Dist: pytest-cov>=5.0.0; extra == "test"
692
695
  Requires-Dist: pytest-benchmark; extra == "test"
693
696
  Requires-Dist: numpy; extra == "test"
697
+ Requires-Dist: sympy; extra == "test"
694
698
  Description-Content-Type: text/markdown
695
699
 
696
700
  # pyrauli: High-Performance Quantum Circuit Simulation
@@ -753,7 +757,7 @@ final_observable = circuit.run(observable)
753
757
 
754
758
  # 5. Retrieve the final expectation value
755
759
  # The expectation value is calculated with respect to the initial |00...0> state
756
- expectation_value = final_observable.get_expectation_value()
760
+ expectation_value = final_observable.expectation_value()
757
761
 
758
762
  print(f"Final observable: {final_observable}")
759
763
  print(f"Expectation value: {expectation_value}")
@@ -58,7 +58,7 @@ final_observable = circuit.run(observable)
58
58
 
59
59
  # 5. Retrieve the final expectation value
60
60
  # The expectation value is calculated with respect to the initial |00...0> state
61
- expectation_value = final_observable.get_expectation_value()
61
+ expectation_value = final_observable.expectation_value()
62
62
 
63
63
  print(f"Final observable: {final_observable}")
64
64
  print(f"Expectation value: {expectation_value}")
@@ -0,0 +1,43 @@
1
+ import pytest
2
+ from pyrauli import SymbolicObservable, SymbolicCircuit
3
+
4
+ def rzz(qc, q1, q2, v):
5
+ qc.add_operation("cx", q1, q2)
6
+ qc.add_operation("rz", q2, v)
7
+ qc.add_operation("cx", q1, q2)
8
+
9
+ def rx(qc, q, v):
10
+ qc.add_operation("h", q)
11
+ qc.add_operation("rz", q, v)
12
+ qc.add_operation("h", q)
13
+
14
+ @pytest.fixture(scope="module")
15
+ def maxcut_qaoa_N4P1():
16
+ """Fixture"""
17
+ obs = SymbolicObservable(["ZZII", "ZIZI", "IZZI", "ZIIZ", "IZIZ", "IIZZ"])
18
+ qc = SymbolicCircuit(4)
19
+
20
+ for i in range(4):
21
+ qc.add_operation("h", i)
22
+
23
+ rzz(qc, 0, 1, "tz")
24
+ rzz(qc, 0, 3, "tz")
25
+ rzz(qc, 0, 2, "tz")
26
+
27
+ rx(qc, 0, "tx")
28
+
29
+ rzz(qc, 1, 2, "tz")
30
+ rzz(qc, 1, 3, "tz")
31
+
32
+ rx(qc, 1, "tx")
33
+ rzz(qc, 2, 3, "tz")
34
+
35
+ rx(qc, 2, "tx")
36
+ rx(qc, 3, "tx")
37
+
38
+ return qc, obs
39
+
40
+ def test_qaoa_N4P1_run(maxcut_qaoa_N4P1, benchmark):
41
+ qc, obs = maxcut_qaoa_N4P1
42
+
43
+ benchmark(qc.run, obs)
@@ -60,6 +60,20 @@ the hood.
60
60
  :end-before: # [estimator_complex]
61
61
  :dedent: 4
62
62
 
63
+ Full PUBs support
64
+ -----------------
65
+
66
+ ``pyrauli`` intends to be fully compatible with Qiskit and the provided backends and estimators should be able to be swapped with any other qiskit backend. Therefore, :py:class:`~pyrauli.PyrauliEstimator` and :py:class:`~pyrauli.PBackend` `.run` methods allows for any PUB (see `Qiskit documentation on PUBs https://qiskit.qotlabs.org/docs/guides/primitive-input-output`).
67
+
68
+ Below is an example of what is possible:
69
+
70
+ .. literalinclude:: /../tests/test_backend.py
71
+ :language: python
72
+ :start-after: # [qiskit_multiparameters]
73
+ :end-before: # [qiskit_multiparameters]
74
+ :dedent: 4
75
+
76
+
63
77
  Qiskit and reverse qubit ordering
64
78
  ---------------------------------
65
79
 
@@ -0,0 +1,99 @@
1
+ .. _how_to_symbolic:
2
+
3
+ Symbolic Simulation
4
+ ===================
5
+
6
+ `pyrauli` offers a powerful symbolic simulation mode that allows you to work with parameterized quantum circuits. Instead of providing fixed numerical values for parameters like gate angles or noise strengths, you can use symbolic variables. This is particularly useful for tasks like variational algorithms, gradient calculations, and sensitivity analysis, where you need to explore a function's behavior over a range of parameter values.
7
+
8
+ The Symbolic Toolkit
9
+ --------------------
10
+
11
+ The symbolic mode is built on three core classes:
12
+
13
+ * :py:class:`~pyrauli.SymbolicCoefficient`: Represents a mathematical expression that can include variables, constants, and standard mathematical operations.
14
+ * :py:class:`~pyrauli.SymbolicObservable`: An observable whose terms have `SymbolicCoefficient` objects as coefficients.
15
+ * :py:class:`~pyrauli.SymbolicCircuit`: A circuit that can accept `SymbolicCoefficient` objects as parameters for its operations.
16
+
17
+ Working with `SymbolicCoefficient`
18
+ ------------------------------------
19
+
20
+ The :py:class:`~pyrauli.SymbolicCoefficient` is the fundamental building block. You can create one from a number or a string (which becomes a variable name).
21
+
22
+ .. literalinclude:: /../tests/snippets/test_symbolic_coefficient_guide.py
23
+ :language: python
24
+ :start-after: # [symbolic_init]
25
+ :end-before: # [symbolic_init]
26
+ :dedent: 4
27
+
28
+ These objects support standard mathematical operations, allowing you to build complex expressions.
29
+
30
+ .. literalinclude:: /../tests/snippets/test_symbolic_coefficient_guide.py
31
+ :language: python
32
+ :start-after: # [symbolic_ops]
33
+ :end-before: # [symbolic_ops]
34
+ :dedent: 4
35
+
36
+ Evaluating Expressions
37
+ ~~~~~~~~~~~~~~~~~~~~~~
38
+
39
+ A key feature is the ability to substitute variables with values. There are two ways to do this:
40
+
41
+ 1. **.evaluate()**: This method substitutes all variables and computes a final floating-point number. It will raise an error if any variables are left unbound.
42
+ 2. **.symbolic_evaluate()**: This method substitutes only the specified variables, returning a new, potentially simpler `SymbolicCoefficient`.
43
+
44
+ .. literalinclude:: /../tests/snippets/test_symbolic_coefficient_guide.py
45
+ :language: python
46
+ :start-after: # [symbolic_evaluate]
47
+ :end-before: # [symbolic_evaluate]
48
+ :dedent: 4
49
+
50
+ Simplifying Expressions
51
+ ~~~~~~~~~~~~~~~~~~~~~~~
52
+
53
+ The :py:meth:`~pyrauli.SymbolicCoefficient.simplified` method applies arithmetic rules (like `x*1=x` or `x+0=x`) to reduce the complexity of an expression.
54
+
55
+ .. literalinclude:: /../tests/snippets/test_symbolic_coefficient_guide.py
56
+ :language: python
57
+ :start-after: # [symbolic_simplify]
58
+ :end-before: # [symbolic_simplify]
59
+ :dedent: 4
60
+
61
+ Constructing a `SymbolicObservable`
62
+ -------------------------------------
63
+
64
+ A :py:class:`~pyrauli.SymbolicObservable` works just like a regular :py:class:`~pyrauli.Observable`, but its coefficients are symbolic.
65
+
66
+ .. literalinclude:: /../tests/snippets/test_symbolic_observable_guide.py
67
+ :language: python
68
+ :start-after: # [symbolic_obs_init]
69
+ :end-before: # [symbolic_obs_init]
70
+ :dedent: 4
71
+
72
+ The :py:meth:`~pyrauli.SymbolicObservable.simplify` method on an observable will simplify the symbolic coefficients of all its terms. You can also pass a dictionary of variable substitutions to this method.
73
+
74
+ .. literalinclude:: /../tests/snippets/test_symbolic_observable_guide.py
75
+ :language: python
76
+ :start-after: # [symbolic_obs_simplify]
77
+ :end-before: # [symbolic_obs_simplify]
78
+ :dedent: 4
79
+
80
+ Building and Running a `SymbolicCircuit`
81
+ ------------------------------------------
82
+
83
+ The end-to-end workflow is straightforward. You build a :py:class:`~pyrauli.SymbolicCircuit` using variable names for your parameters and then run it on a :py:class:`~pyrauli.SymbolicObservable`. The simulation propagates the symbolic expressions through the circuit according to the rules of quantum mechanics.
84
+
85
+ .. literalinclude:: /../tests/snippets/test_symbolic_circuit_snippet.py
86
+ :language: python
87
+ :start-after: # [symbolic_circuit]
88
+ :end-before: # [symbolic_circuit]
89
+ :dedent: 4
90
+
91
+ The final result is a new :py:class:`~pyrauli.SymbolicObservable`. To get the final expectation value, you call its :py:meth:`~pyrauli.SymbolicObservable.expectation_value` method, which returns a `SymbolicCoefficient`. You can then evaluate this coefficient for any set of concrete parameter values.
92
+
93
+ .. literalinclude:: /../tests/snippets/test_symbolic_circuit_snippet.py
94
+ :language: python
95
+ :start-after: # [symbolic_evaluation]
96
+ :end-before: # [symbolic_evaluation]
97
+ :dedent: 4
98
+
99
+ This workflow allows you to run the simulation once to get a general symbolic result and then analyze that result for many different parameter values without needing to re-run the simulation each time.
@@ -31,6 +31,7 @@ the library for the first time or need a specific technical detail.
31
31
  guides/how_to_complexity
32
32
  guides/how_to_qiskit
33
33
  guides/how_to_noise
34
+ guides/how_to_symbolic
34
35
 
35
36
  .. toctree::
36
37
  :maxdepth: 2
@@ -5,7 +5,7 @@ build-backend = "scikit_build_core.build"
5
5
 
6
6
  [project]
7
7
  name = "pyrauli"
8
- version = "0.3.1"
8
+ version = "0.4.0"
9
9
  description = "A very fast and easy to use Quantum circuit simulator relying on Pauli propagation. Compatible with qiskit."
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.9"
@@ -25,13 +25,18 @@ Homepage = "https://github.com/zefresk/pyrauli"
25
25
 
26
26
  [project.optional-dependencies]
27
27
  qiskit = [
28
- "qiskit>=2.0.0"
28
+ "qiskit>=2.0.0",
29
+ "numpy"
30
+ ]
31
+ symbolic = [
32
+ "sympy"
29
33
  ]
30
34
  test = [
31
35
  "pytest>=8.0.0",
32
36
  "pytest-cov>=5.0.0",
33
37
  "pytest-benchmark",
34
38
  "numpy",
39
+ "sympy"
35
40
  ]
36
41
 
37
42
  [tool.scikit-build.wheel]
@@ -12,6 +12,7 @@ from ._core import (
12
12
  SchedulingPolicy, NeverPolicy, AlwaysBeforeSplittingPolicy,
13
13
  AlwaysAfterSplittingPolicy, Circuit, OperationType, Timing,
14
14
  SimulationState, CompressionResult, LambdaPolicy,
15
+ SymbolicCoefficient, SymbolicPauliTerm, SymbolicObservable, SymbolicNoise, SymbolicNoiseModel, SymbolicTruncator, SymbolicWeightTruncator, SymbolicNeverTruncator, SymbolicMultiTruncator, SymbolicCircuit
15
16
  )
16
17
 
17
18
  __all__ = [
@@ -22,8 +23,24 @@ __all__ = [
22
23
  "AlwaysBeforeSplittingPolicy", "AlwaysAfterSplittingPolicy", "Circuit",
23
24
  "OperationType", "Timing", "SimulationState", "CompressionResult",
24
25
  "LambdaPolicy",
26
+ "SymbolicCoefficient", "SymbolicObservable", "SymbolicPauliTerm", "SymbolicNoise", "SymbolicNoiseModel", "SymbolicTruncator", "SymbolicWeightTruncator", "SymbolicNeverTruncator", "SymbolicMultiTruncator", "SymbolicCircuit"
27
+
25
28
  ]
26
29
 
30
+ try:
31
+ import sympy
32
+ def to_sympy(self):
33
+ """
34
+ Converts the SymbolicCoefficient to a SymPy expression.
35
+
36
+ Returns:
37
+ A SymPy expression equivalent to the SymbolicCoefficient.
38
+ """
39
+ return sympy.sympify(self.to_string())
40
+ SymbolicCoefficient.to_sympy = to_sympy
41
+ except ImportError:
42
+ pass
43
+
27
44
  # Conditionally import Qiskit-related functionality
28
45
  try:
29
46
  from .backend import PBackend