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

hcr 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 a74d5a2de MAHOUT-823: [QDP] test: add & refactor NumPy encoding tests 
for improved clarity and coverage (#824)
a74d5a2de is described below

commit a74d5a2de178093bd19cd74a41aa91f28a46b5d5
Author: Vic Wen <[email protected]>
AuthorDate: Thu Jan 15 16:30:44 2026 +0800

    MAHOUT-823: [QDP] test: add & refactor NumPy encoding tests for improved 
clarity and coverage (#824)
    
    * test: add & refactor NumPy encoding tests for improved clarity and 
coverage
    
    - Updated test descriptions to better reflect functionality.
    - Consolidated encoding tests into parameterized cases for basic, large, 
and single sample inputs.
    - Introduced helper function to verify tensor properties, enhancing code 
reuse.
    - Added tests for different encoding methods and precision settings.
    - Implemented error handling tests for invalid inputs and unsupported 
dimensions.
    
    * test: enhance and parameterize NumPy encoding tests
---
 qdp/qdp-python/tests/test_numpy.py | 200 +++++++++++++++++++++++--------------
 1 file changed, 123 insertions(+), 77 deletions(-)

diff --git a/qdp/qdp-python/tests/test_numpy.py 
b/qdp/qdp-python/tests/test_numpy.py
index 1616247bc..c5f53ecbd 100644
--- a/qdp/qdp-python/tests/test_numpy.py
+++ b/qdp/qdp-python/tests/test_numpy.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python3
 #
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
@@ -15,70 +14,51 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Test NumPy file format support in Mahout QDP Python bindings"""
+"""Test NumPy file format and array input support in Mahout QDP Python 
bindings"""
 
 import tempfile
 import os
+
 import numpy as np
+import pytest
 import torch
-from _qdp import QdpEngine
-
-
-def test_encode_from_numpy_basic():
-    """Test basic NumPy file encoding"""
-    engine = QdpEngine(device_id=0)
-
-    # Create test data
-    num_samples = 10
-    num_qubits = 3
-    sample_size = 2**num_qubits  # 8
-
-    # Generate normalized data
-    data = np.random.randn(num_samples, sample_size).astype(np.float64)
-    # Normalize each row
-    norms = np.linalg.norm(data, axis=1, keepdims=True)
-    data = data / norms
-
-    # Save to temporary .npy file
-    with tempfile.NamedTemporaryFile(suffix=".npy", delete=False) as f:
-        npy_path = f.name
-
-    try:
-        np.save(npy_path, data)
 
-        qtensor = engine.encode(npy_path, num_qubits)
-        tensor = torch.from_dlpack(qtensor)
+from _qdp import QdpEngine
 
-        # Verify shape
-        assert tensor.shape == (num_samples, sample_size), (
-            f"Expected shape {(num_samples, sample_size)}, got {tensor.shape}"
-        )
 
-        # Verify it's on GPU
-        assert tensor.is_cuda, "Tensor should be on CUDA device"
+def _verify_tensor(tensor, expected_shape, check_normalization=False):
+    """Helper function to verify tensor properties"""
+    assert tensor.shape == expected_shape, (
+        f"Expected shape {expected_shape}, got {tensor.shape}"
+    )
+    assert tensor.is_cuda, "Tensor should be on CUDA device"
 
-        # Verify normalization (amplitude encoding normalizes)
+    if check_normalization:
         norms = tensor.abs().pow(2).sum(dim=1).sqrt()
         assert torch.allclose(norms, torch.ones_like(norms), atol=1e-5), (
             "States should be normalized"
         )
 
-        print("āœ“ test_encode_from_numpy_basic passed")
-
-    finally:
-        if os.path.exists(npy_path):
-            os.remove(npy_path)
 
[email protected]
[email protected](
+    "num_samples,num_qubits,check_norm",
+    [
+        (10, 3, True),  # Basic: 10 samples, 3 qubits, check normalization
+        (100, 6, False),  # Large: 100 samples, 6 qubits
+        (1, 4, False),  # Single sample: 1 sample, 4 qubits
+    ],
+)
+def test_encode_from_numpy_file(num_samples, num_qubits, check_norm):
+    """Test NumPy file encoding"""
+    pytest.importorskip("torch")
+    if not torch.cuda.is_available():
+        pytest.skip("GPU required for QdpEngine")
 
-def test_encode_from_numpy_large():
-    """Test NumPy encoding with larger dataset"""
     engine = QdpEngine(device_id=0)
+    sample_size = 2**num_qubits
 
-    num_samples = 100
-    num_qubits = 6
-    sample_size = 2**num_qubits  # 64
-
-    # Generate test data
+    # Generate normalized data
     data = np.random.randn(num_samples, sample_size).astype(np.float64)
     norms = np.linalg.norm(data, axis=1, keepdims=True)
     data = data / norms
@@ -89,53 +69,119 @@ def test_encode_from_numpy_large():
 
     try:
         np.save(npy_path, data)
-
         qtensor = engine.encode(npy_path, num_qubits)
         tensor = torch.from_dlpack(qtensor)
 
-        # Verify
-        assert tensor.shape == (num_samples, sample_size)
-        assert tensor.is_cuda
-
-        print("āœ“ test_encode_from_numpy_large passed")
+        _verify_tensor(tensor, (num_samples, sample_size), check_norm)
 
     finally:
         if os.path.exists(npy_path):
             os.remove(npy_path)
 
 
-def test_encode_from_numpy_single_sample():
-    """Test NumPy encoding with single sample"""
[email protected]
[email protected]("num_qubits", [1, 2, 3, 4])
+def test_encode_numpy_array_1d(num_qubits):
+    """Test 1D NumPy array encoding (single sample)"""
+    pytest.importorskip("torch")
+    if not torch.cuda.is_available():
+        pytest.skip("GPU required for QdpEngine")
+
     engine = QdpEngine(device_id=0)
+    sample_size = 2**num_qubits
+    data = np.random.randn(sample_size).astype(np.float64)
+    data = data / np.linalg.norm(data)
 
-    num_qubits = 4
-    sample_size = 2**num_qubits  # 16
+    qtensor = engine.encode(data, num_qubits)
+    tensor = torch.from_dlpack(qtensor)
+    _verify_tensor(tensor, (1, sample_size), check_normalization=True)
 
-    # Single sample
-    data = np.random.randn(1, sample_size).astype(np.float64)
-    data = data / np.linalg.norm(data)
 
-    with tempfile.NamedTemporaryFile(suffix=".npy", delete=False) as f:
-        npy_path = f.name
[email protected]
[email protected]("num_samples,num_qubits", [(5, 2), (10, 3)])
+def test_encode_numpy_array_2d(num_samples, num_qubits):
+    """Test 2D NumPy array encoding (batch)"""
+    pytest.importorskip("torch")
+    if not torch.cuda.is_available():
+        pytest.skip("GPU required for QdpEngine")
 
-    try:
-        np.save(npy_path, data)
+    engine = QdpEngine(device_id=0)
+    sample_size = 2**num_qubits
+    data = np.random.randn(num_samples, sample_size).astype(np.float64)
+    norms = np.linalg.norm(data, axis=1, keepdims=True)
+    data = data / norms
 
-        qtensor = engine.encode(npy_path, num_qubits)
-        tensor = torch.from_dlpack(qtensor)
+    qtensor = engine.encode(data, num_qubits)
+    tensor = torch.from_dlpack(qtensor)
+    _verify_tensor(tensor, (num_samples, sample_size), 
check_normalization=True)
 
-        assert tensor.shape == (1, sample_size)
-        assert tensor.is_cuda
 
-        print("āœ“ test_encode_from_numpy_single_sample passed")
[email protected]
[email protected]("encoding_method", ["amplitude"])
+def test_encode_numpy_encoding_methods(encoding_method):
+    """Test different encoding methods"""
+    pytest.importorskip("torch")
+    if not torch.cuda.is_available():
+        pytest.skip("GPU required for QdpEngine")
 
-    finally:
-        if os.path.exists(npy_path):
-            os.remove(npy_path)
+    # TODO: Add angle and basis encoding tests when implemented
+    engine = QdpEngine(device_id=0)
+    num_qubits = 2
+    sample_size = 2**num_qubits
+    data = np.array([1.0, 2.0, 3.0, 4.0], dtype=np.float64)
+
+    qtensor = engine.encode(data, num_qubits, encoding_method=encoding_method)
+    tensor = torch.from_dlpack(qtensor)
+    _verify_tensor(tensor, (1, sample_size))
+
+
[email protected]
[email protected](
+    "precision,expected_dtype",
+    [
+        ("float32", torch.complex64),
+        ("float64", torch.complex128),
+    ],
+)
+def test_encode_numpy_precision(precision, expected_dtype):
+    """Test different precision settings"""
+    pytest.importorskip("torch")
+    if not torch.cuda.is_available():
+        pytest.skip("GPU required for QdpEngine")
+
+    engine = QdpEngine(device_id=0, precision=precision)
+    num_qubits = 2
+    data = np.array([1.0, 2.0, 3.0, 4.0], dtype=np.float64)
+
+    qtensor = engine.encode(data, num_qubits)
+    tensor = torch.from_dlpack(qtensor)
+    assert tensor.dtype == expected_dtype, (
+        f"Expected {expected_dtype}, got {tensor.dtype}"
+    )
+
+
[email protected]
[email protected](
+    "data,error_match",
+    [
+        (
+            np.array([1.0, 2.0, 3.0, 4.0], dtype=np.float32),
+            None,  # Wrong dtype - will raise RuntimeError or TypeError
+        ),
+        (
+            np.array([[[1.0, 2.0], [3.0, 4.0]]], dtype=np.float64),
+            None,  # 3D array - will raise RuntimeError or TypeError
+        ),
+    ],
+)
+def test_encode_numpy_errors(data, error_match):
+    """Test error handling for invalid inputs"""
+    pytest.importorskip("torch")
+    if not torch.cuda.is_available():
+        pytest.skip("GPU required for QdpEngine")
 
+    engine = QdpEngine(device_id=0)
+    num_qubits = 2 if data.ndim == 1 else 1
 
-if __name__ == "__main__":
-    test_encode_from_numpy_basic()
-    test_encode_from_numpy_large()
-    test_encode_from_numpy_single_sample()
-    print("\nāœ… All NumPy encoding tests passed!")
+    with pytest.raises((RuntimeError, TypeError)):
+        engine.encode(data, num_qubits)

Reply via email to