# Python List vs NumPy Array Input Compatibility in pybind11-rdp: A Complete Guide

> Understand Python list vs NumPy array compatibility in pybind11-rdp. Learn how pybind11-rdp converts inputs to NumPy ndarrays for efficient C++ Eigen integration.

- Repository: [cubao/pybind11-rdp](https://github.com/cubao/pybind11-rdp)
- Tags: deep-dive
- Published: 2026-02-28

---

**The pybind11-rdp library accepts both Python lists and NumPy arrays interchangeably by converting all inputs to NumPy `ndarrays` via `np.asarray` before passing them to the underlying C++ Eigen bindings.**

The cubao/pybind11-rdp package implements the Ramer-Douglas-Peucker (RDP) algorithm with a high-performance C++ backend wrapped for Python. Understanding Python list vs NumPy array input compatibility is essential for writing flexible, efficient coordinate simplification code. The library seamlessly handles both input types through a thin Python wrapper that normalizes data before it reaches the C++ layer.

## How the Python Wrapper Normalizes Input Types

The compatibility layer resides in **[`src/pybind11_rdp/__init__.py`](https://github.com/cubao/pybind11-rdp/blob/main/src/pybind11_rdp/__init__.py)**, where the public API functions `rdp()`, `rdp_rec()`, and `rdp_iter()` preprocess all inputs. Each function calls `np.asarray()` to convert user-provided sequences into contiguous double-precision arrays before invoking the C++ bindings.

Specifically:
- Lines 36-39 handle conversion for `rdp_rec()`
- Lines 60-64 handle conversion for `rdp_iter()`
- Lines 89-94 handle conversion for the unified `rdp()` entry point

This design means **any array-like object**—including native Python lists, tuples, or nested sequences—automatically becomes a NumPy `ndarray` with `dtype=np.float64`. The wrapper reshapes the data into the required `(N, 2)` or `(N, 3)` matrix format expected by the C++ implementation.

## The C++ Eigen Interface

On the C++ side in **[`src/main.cpp`](https://github.com/cubao/pybind11-rdp/blob/main/src/main.cpp)**, the bindings receive data as **Eigen matrix references** rather than raw Python objects. The implementation defines two overloads:
- Lines 15-23 accept 3-column matrices (`Eigen::Ref<const RowVectors>`)
- Lines 25-33 accept 2-column matrices (`Eigen::Ref<const RowVectorsNx2>`)

Because the Python wrapper always passes a NumPy `ndarray`, the C++ layer sees a contiguous block of memory compatible with Eigen's `Map` semantics. This **zero-copy mapping** ensures high performance regardless of whether the original input was a Python list or a NumPy array.

## Supported Input Types and Conversion Behavior

The following table details how different input types are processed before reaching the C++ algorithm:

| Input Type | Python Wrapper Action | C++ Receives |
|------------|----------------------|--------------|
| **Python list of lists/tuples** | `np.asarray` builds `float64` array, preserving nesting order | `Eigen::Ref<const RowVectors>` (or `RowVectorsNx2`) referencing contiguous data |
| **NumPy `ndarray`** | `np.asarray` returns original object unchanged | Same Eigen reference type as above |
| **Other array-like objects** (e.g., pandas DataFrame values) | `np.asarray` attempts conversion; succeeds if result is 2-D float array | Same as above (requires shape `(N,2)` or `(N,3)`) |

If the supplied data cannot be cast to a 2-D `float64` array—for example, if inner lists have mismatched lengths—NumPy raises a **`ValueError`** before the C++ layer executes.

## Practical Code Examples

The following examples demonstrate Python list vs NumPy array input compatibility using the `rdp()` function:

```python
import numpy as np
from pybind11_rdp import rdp

# Example 1 – plain Python list (2-D points)

points_list = [[0, 0], [1, 0.1], [2, -0.1], [3, 5]]
simplified = rdp(points_list, epsilon=0.5)
print("simplified (list input):", simplified)

```

```python

# Example 2 – NumPy ndarray (3-D points)

points_array = np.array([[0, 0, 0],
                         [1, 0.1, 0],
                         [2, -0.1, 0],
                         [3, 5, 0]], dtype=np.float64)
simplified = rdp(points_array, epsilon=0.5, algo="rec")
print("simplified (ndarray input):", simplified)

```

```python

# Example 3 – request the keep-mask instead of coordinates

mask = rdp(points_list, epsilon=0.5, return_mask=True)
print("mask:", mask)

```

All three calls succeed because the wrapper transparently converts inputs to NumPy arrays before invoking the C++ implementation.

## Error Handling and Validation

When working with heterogeneous input data, the library relies on NumPy's strict casting rules. **Malformed inputs**—such as jagged lists or non-numeric sequences—trigger a `ValueError` during the `np.asarray()` call in the Python wrapper. This prevents undefined behavior in the C++ layer and provides clear error messages at the Python level.

The wrapper requires inputs to resolve to either:
- Shape `(N, 2)` for 2-D coordinate simplification
- Shape `(N, 3)` for 3-D coordinate simplification

Any other dimensionality raises a standard NumPy reshape error before reaching the Eigen bindings in [`src/main.cpp`](https://github.com/cubao/pybind11-rdp/blob/main/src/main.cpp).

## Summary

- **Universal Input Support**: The `pybind11_rdp` API accepts Python lists, tuples, and NumPy arrays through automatic `np.asarray` conversion in [`src/pybind11_rdp/__init__.py`](https://github.com/cubao/pybind11-rdp/blob/main/src/pybind11_rdp/__init__.py).
- **Zero-Copy Performance**: C++ bindings use `Eigen::Ref` to map NumPy memory directly without copying, ensuring high performance regardless of input type.
- **Strict Validation**: Input arrays must convert to 2-D `float64` with shape `(N,2)` or `(N,3)`; otherwise, NumPy raises `ValueError` before C++ execution.
- **Implementation Files**: Key logic resides in [`src/pybind11_rdp/__init__.py`](https://github.com/cubao/pybind11-rdp/blob/main/src/pybind11_rdp/__init__.py) (Python wrapper) and [`src/main.cpp`](https://github.com/cubao/pybind11-rdp/blob/main/src/main.cpp) (C++ Eigen bindings).

## Frequently Asked Questions

### Does pybind11-rdp accept Python lists or only NumPy arrays?

**Both input types are fully supported.** The library uses `np.asarray()` in the Python wrapper to convert lists, tuples, and other sequences into NumPy `ndarrays` before passing them to the C++ implementation. This conversion happens automatically in the `rdp()`, `rdp_rec()`, and `rdp_iter()` functions.

### What data types does pybind11-rdp expect for coordinate inputs?

**The wrapper forces `dtype=np.float64` (double precision).** While the input can be any array-like object, the `np.asarray()` call without explicit dtype specification creates a `float64` array by default when given Python floats. The C++ Eigen bindings expect this specific memory layout for optimal performance.

### How does the library handle pandas DataFrame inputs?

**Pandas DataFrames work if converted to 2-D array values first.** Passing `df.values` or any attribute that yields a 2-D array-like structure allows `np.asarray` to create the required matrix. The wrapper treats these objects identically to standard NumPy arrays once converted.

### What happens if I pass a malformed list to the rdp function?

**NumPy raises a `ValueError` before the C++ code executes.** If inner lists have inconsistent lengths or contain non-numeric data, the `np.asarray()` call in [`src/pybind11_rdp/__init__.py`](https://github.com/cubao/pybind11-rdp/blob/main/src/pybind11_rdp/__init__.py) fails with a descriptive error message. This prevents crashes in the underlying C++ RDP algorithm.