Repository navigation
Add pdist compatible python function signature - #1
Merged
Merged
Conversation
…ture - pdist(X, metric='euclidean', *, out=None) dispatches to the existing distance functions by metric name - allocates the condensed distance matrix when out is None and validates shape, dtype and contiguity otherwise - document the new entry point in the readme Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012wqz9cM21KFZ7LP6MfZd9o
- decrement references to arrays produced by PyArray_FROM_OTF and PyArray_FROM_O on every return path - replace the explicit destructor call on the demeaned correlation array with Py_DECREF Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012wqz9cM21KFZ7LP6MfZd9o
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012wqz9cM21KFZ7LP6MfZd9o
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical memory-safety and exception-handling issues block approval.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds a SciPy-compatible Pairwise.pdist API for Euclidean and correlation distances, with optional output arrays and improved cleanup.
Changes:
- Adds and registers
pdist(X, metric, *, out). - Documents the new API and compatibility.
- Improves NumPy reference cleanup and validation.
File summaries
| File | Review summary |
|---|---|
Readme.md |
Documents pdist; the RandomForest example conflicts with the stated compatibility (nit, 1 vote). |
PairwiseDistances.h |
Declares and registers the new pdist entry point. |
PairwiseDistances.cpp |
Contains unresolved zero-row memory corruption (critical, 3 votes), unchecked conversion failures that can crash (critical, 2 votes), incorrect exception returns (moderate, 2 votes), leaked indexers in multiple paths (moderate, 3 votes each), and signed-char tolower undefined behavior (moderate, 1 vote). |
Review details
Suppressed comments (5)
PairwiseDistances.cpp:535
PyArray_FROM_Ocan fail and returnnullptr(for example when conversion or__array__raises), butPyArray_TYPE(probe)dereferences it immediately. Checkprobebefore reading its type and returnnullptrso invalid inputs raise their original Python exception instead of crashing the interpreter.
PyArrayObject* probe = (PyArrayObject*)PyArray_FROM_O(arg1);
int arrayType = PyArray_TYPE(probe);
Py_DECREF(probe);
PairwiseDistances.cpp:555
- This branch sets a Python exception and then returns
None. CPython treats a non-NULL return with an active exception as aSystemError, so invalid cluster types do not reach callers as the intendedValueError; returnnullptrafter setting the error.
Py_XDECREF(clusterDistances);
PyErr_SetString(PyExc_ValueError, "Cluster solutions need to be in uint8 or uint16");
Py_RETURN_NONE;
PairwiseDistances.cpp:515
- The new NumPy decrefs do not release the
itemIndexerandsolutionIndexerallocated at lines 487-488. Each successful AVX call therefore still leaks both lookup tables; delete both indexers before returning.
Py_DECREF(clusterSolutions);
Py_DECREF(clusterDistances);
PairwiseDistances.cpp:231
tolowerrequires eitherEOFor anunsigned charvalue, butmetric[i]may be a negativecharfor non-ASCII metric strings. An unsupported UTF-8 metric can therefore invoke undefined behavior before the intendedValueError; cast throughunsigned charbefore callingtolower.
metric[i] = (char)tolower(metric[i]);
Readme.md:22
- This newly added example includes
RandomForest, but the newpdistentry point only acceptseuclideanandcorrelation; the following statement thatoutcontains the same data aspdistis therefore false for the listed random-forest function. Qualify that statement or separate the random-forest legacy API from the pdist-compatible functions.
Pairwise.GetPairwise[Euclidean|Correlation|RandomForest]Distance(data, out)
- Files reviewed: 3/3 changed files
- Comments generated: 5
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| } | ||
| npy_intp m = PyArray_DIM(XArray, 0); | ||
| Py_DECREF(XArray); | ||
| npy_intp numCondensed = m * (m - 1) / 2; |
Comment on lines
+454
to
+456
| PyArrayObject* probe = (PyArrayObject*)PyArray_FROM_O(arg1); | ||
| int arrayType = PyArray_TYPE(probe); | ||
| Py_DECREF(probe); |
Comment on lines
+434
to
+435
| Py_DECREF(clusterSolutions); | ||
| Py_DECREF(clusterDistances); |
Comment on lines
+474
to
476
| Py_XDECREF(clusterDistances); | ||
| PyErr_SetString(PyExc_ValueError, "Cluster solutions need to be in uint8 or uint16"); | ||
| Py_RETURN_NONE; |
Comment on lines
+594
to
+595
| Py_DECREF(clusterSolutions); | ||
| Py_DECREF(clusterDistances); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Make API fully compatible with scipy's pdist, and squash memory leaks