You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mahout.apache.org by ra...@apache.org on 2024/04/29 13:39:28 UTC

(mahout) branch main updated: MAHOUT-2202 Testing Suite Template (plus MAHOUT-2207) (#442)

This is an automated email from the ASF dual-hosted git repository.

rawkintrevo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/mahout.git


The following commit(s) were added to refs/heads/main by this push:
     new b5b76c0d8 MAHOUT-2202 Testing Suite Template (plus MAHOUT-2207) (#442)
b5b76c0d8 is described below

commit b5b76c0d8d95c9758640c1c84cc1aa198b7d2e67
Author: Tommy Naugle <52...@users.noreply.github.com>
AuthorDate: Mon Apr 29 08:39:23 2024 -0500

    MAHOUT-2202 Testing Suite Template (plus MAHOUT-2207) (#442)
    
    * added testing folder
    
    * successful pytest
    
    * comparison test working
    
    * added testing folder
    
    * successful pytest
    
    * comparison test working
    
    * conform to cirq 1.3.0 python reqs
    
    * MAHOUT-2202 add license headers
    
    * Stable implementation of prototype method
    
    * support for arbitrary backends
    
    * fixes and tidying
    
    * tidying readme
    
    * another header
    
    * another header fix
---
 pyproject.toml                       |  2 ++
 qumat/qiskit_backend.py              |  9 +++++
 qumat/qumat.py                       |  4 +++
 testing/README.md                    | 33 +++++++++++++++++
 testing/qiskit_helpers.py            | 68 ++++++++++++++++++++++++++++++++++++
 testing/qumat_helpers.py             | 60 +++++++++++++++++++++++++++++++
 testing/test_final_quantum_states.py | 37 ++++++++++++++++++++
 7 files changed, 213 insertions(+)

diff --git a/pyproject.toml b/pyproject.toml
index 70c047356..929cab925 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -12,6 +12,8 @@ qiskit = "^0.45.1"
 qiskit-aer = "^0.13.2"
 cirq = "^1.3.0"
 
+[tool.poetry.dev-dependencies]
+pytest = "^8.1.1"
 
 [build-system]
 requires = ["poetry-core"]
diff --git a/qumat/qiskit_backend.py b/qumat/qiskit_backend.py
index adff8ac3e..ffa12ca0a 100644
--- a/qumat/qiskit_backend.py
+++ b/qumat/qiskit_backend.py
@@ -77,3 +77,12 @@ def execute_circuit(circuit, backend, backend_config):
     result = job.result()
     return result.get_counts(transpiled_circuit)
 
+# placeholder method for use in the testing suite
+def get_final_state_vector(circuit, backend, backend_config):
+    simulator = qiskit.Aer.get_backend('statevector_simulator')
+
+    # Simulate the circuit
+    job = qiskit.execute(circuit, simulator)
+    result = job.result()
+
+    return result.get_statevector()
diff --git a/qumat/qumat.py b/qumat/qumat.py
index f062612a8..5d6f7a25c 100644
--- a/qumat/qumat.py
+++ b/qumat/qumat.py
@@ -54,3 +54,7 @@ class QuMat:
 
     def execute_circuit(self):
         return self.backend_module.execute_circuit(self.circuit, self.backend, self.backend_config)
+
+    # placeholder method for use in the testing suite
+    def get_final_state_vector(self):
+        return self.backend_module.get_final_state_vector(self.circuit, self.backend, self.backend_config)
\ No newline at end of file
diff --git a/testing/README.md b/testing/README.md
new file mode 100644
index 000000000..1071e3bb4
--- /dev/null
+++ b/testing/README.md
@@ -0,0 +1,33 @@
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+Apache Mahout Testing Suite
+===========
+For each backend supported in Apache Mahout, the testing suite executes an example circuit using the qumat implementation of the backend, and then executes the same example circuit using the backend's native implementation. The test then checks that the resulting final state vectors are the same.
+
+The testing suite is run using pytest, which is installed by default using poetry. To run the tests, simply run
+```
+pytest
+```
+
+### How to add a test for a new backend
+In order to add *my-new-backend* to the testing suite:
+1.  Create a file `testing/my-new-backend_helpers.py`
+2. In `testing/my-new-backend_helpers.py`, create a function `get_qumat_backend_config` which returns the qumat backend config needed for the qumat implementation of my-new-backend
+3. In `testing/my-new-backend_helpers.py`, create a function `get_native_example_final_state_vector` which builds and executes the example circuit using the native implementation of my-new-backend
+4. In `testing/test_final_quantum_states.py`, add `"my-new-backend"` to `backends_to_test`
+
diff --git a/testing/qiskit_helpers.py b/testing/qiskit_helpers.py
new file mode 100644
index 000000000..1d8d64ac9
--- /dev/null
+++ b/testing/qiskit_helpers.py
@@ -0,0 +1,68 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Import necessary Qiskit libraries
+from qiskit import Aer, QuantumCircuit, execute
+from qiskit.quantum_info import Statevector
+
+def get_qumat_backend_config(test_type: str = "get_final_state_vector"):
+    if test_type == "get_final_state_vector":
+        print("success")
+        qumat_backend_config = {
+            'backend_name': 'qiskit',
+            'backend_options': {
+                'simulator_type': 'statevector_simulator',
+                'shots': 1
+            }
+        }
+    else:
+        pass
+
+    return qumat_backend_config
+
+
+def get_native_example_final_state_vector(initial_state_ket_str: str = "000") -> Statevector:
+    n_qubits = len(initial_state_ket_str)
+    assert n_qubits == 3, print("The current qiskit native testing example is strictly 3 qubits")
+
+    simulator = Aer.get_backend('statevector_simulator')
+
+    qc = QuantumCircuit(n_qubits)
+
+    initial_state = Statevector.from_label(initial_state_ket_str)
+    qc.initialize(initial_state, range(n_qubits))
+
+    # Create entanglement between qubits 1 and 2
+    qc.h(1)  # Apply Hadamard gate on qubit 1
+    qc.cx(1, 2)  # Apply CNOT gate with qubit 1 as control and qubit 2 as target
+
+    # Prepare the state to be teleported on qubit 0
+    qc.h(0)  # Apply Hadamard gate on qubit 0
+    qc.z(0)  # Apply Pauli-Z gate on qubit 0
+
+    # Perform Bell measurement on qubits 0 and 1
+    qc.cx(0, 1)  # Apply CNOT gate with qubit 0 as control and qubit 1 as target
+    qc.h(0)  # Apply Hadamard gate on qubit 0
+
+    # Simulate the circuit
+    job = execute(qc, simulator)
+    result = job.result()
+
+    # Get the state vector
+    state_vector = result.get_statevector()
+
+    return state_vector
diff --git a/testing/qumat_helpers.py b/testing/qumat_helpers.py
new file mode 100644
index 000000000..c11329e6d
--- /dev/null
+++ b/testing/qumat_helpers.py
@@ -0,0 +1,60 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+import numpy as np
+from functools import reduce
+from qumat.qumat import QuMat
+
+class BinaryString(str):
+    def __new__(cls, value):
+        if not all(char in ['0', '1'] for char in value):
+            raise ValueError("String contains characters other than '0' and '1'")
+        return str.__new__(cls, value)
+
+
+def create_np_computational_basis_state(ket_str: BinaryString,
+                                        np_dtype: str = "complex128") -> np.array:
+    single_qubit_state_dict = {
+                            "0": np.array([1, 0], dtype=np_dtype),
+                            "1": np.array([0, 1], dtype=np_dtype)
+                            }
+
+    single_qubit_vectors = map(single_qubit_state_dict.get, ket_str)
+    computational_basis_vector = reduce(np.kron, single_qubit_vectors)
+
+    return computational_basis_vector
+
+
+def get_qumat_example_final_state_vector(backend_config: dict, initial_state_ket_str: BinaryString = "000"):
+    n_qubits = len(initial_state_ket_str)
+    assert n_qubits == 3, print("The current qumat testing example is strictly 3 qubits")
+
+    qumat_instance = QuMat(backend_config)
+
+    qumat_instance.create_empty_circuit(num_qubits=3)
+    initial_state = create_np_computational_basis_state(initial_state_ket_str)
+    qumat_instance.circuit.initialize(initial_state, range(n_qubits))
+
+    qumat_instance.apply_hadamard_gate(qubit_index=1)
+    qumat_instance.apply_cnot_gate(control_qubit_index=1, target_qubit_index=2)
+    qumat_instance.apply_hadamard_gate(qubit_index=0)
+    qumat_instance.apply_pauli_z_gate(qubit_index=0)
+    qumat_instance.apply_cnot_gate(control_qubit_index=0, target_qubit_index=1)
+    qumat_instance.apply_hadamard_gate(qubit_index=0)
+
+    state_vector = qumat_instance.get_final_state_vector()
+
+    return state_vector
diff --git a/testing/test_final_quantum_states.py b/testing/test_final_quantum_states.py
new file mode 100644
index 000000000..af4daa9b0
--- /dev/null
+++ b/testing/test_final_quantum_states.py
@@ -0,0 +1,37 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+from qumat_helpers import get_qumat_example_final_state_vector
+import numpy as np
+from importlib import import_module
+
+def test_final_state_vector():
+    # Specify initial computational basis state vector
+    initial_ket_str = "001"
+
+    backends_to_test = ["qiskit"]
+    for backend_name in backends_to_test:
+        backend_module = import_module(f"{backend_name}_helpers", package="qumat")
+        # use native implementation
+        native_example_vector = backend_module.get_native_example_final_state_vector(initial_ket_str)
+
+        # use qumat implementation
+        qumat_backend_config = backend_module.get_qumat_backend_config("get_final_state_vector")
+        qumat_example_vector = get_qumat_example_final_state_vector(qumat_backend_config, initial_ket_str)
+
+        # Compare final state vectors from qumat vs. native implementation
+        np.testing.assert_array_equal(qumat_example_vector, native_example_vector)
+