Skip to content

Conversation

pchsu-hsupc
Copy link
Contributor

Completed Tasks

  • Make Python unittest for SimpleArray::argwhere() and SimpleArray::where()

  • Using mixin class SimpleArrayMixinConditional to collect methods SimpleArray::argwhere() and SimpleArray::where()

Abstraction

As mentioned in #519 , this PR implements argwhere() and where() methods without overloading operators.

numpy.argwhere(a): Find the indices of array elements that are non-zero by default, also could add condition as well.

numpy.where(condition, [x, y, ]/): Return elements chosen from x or y depending on condition.

Implement Method

Thanks to the std::function template, I could use lambdas as argument—letting the API mirror NumPy’s style in Python.

ret_np = np.argwhere(narr == 5)
ret_sa = sarr.argwhere(lambda x: x == 5)

}

template <typename A, typename T>
SimpleArray<uint64_t> detail::SimpleArrayMixinSearch<A, T>::argwhere(std::function<bool(value_type const &)> const & condition) const
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Use an std::vector to store the indices of elements that satisfy the condition.
  • Creating the output coordinates and filling the dimensions's information.

}

template <typename A, typename T>
A detail::SimpleArrayMixinSearch<A, T>::where(std::function<bool(value_type const &)> const & condition, A const & other) const
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Should output the same shape as input.
  • If the condition is met, fill with the original value; otherwise, use the alternative.

},
py::arg("condition") = py::none())
.def(
"where",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Numpy's where() says that when only condition is provided, nonzero() should be preferred. So I didn't give SimpleArray::where default operation.

@pchsu-hsupc
Copy link
Contributor Author

Thank you, @ThreeMonth03 and @KHLee529, for your valuable insights.
I would appreciate any additional feedback you might have.
@yungyuc, could you please take a look at this PR when you have a moment? Thanks!

@yungyuc yungyuc added the array Multi-dimensional array implementation label May 5, 2025
Copy link
Member

@yungyuc yungyuc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please profile the runtime performance of the searching functions like what issue #532 does? If the runtime is much worse than numpy, we may not use the implementation in this PR and need to find another approach.

@pchsu-hsupc
Copy link
Contributor Author

Sure, I will add it in.

@pchsu-hsupc
Copy link
Contributor Author

pchsu-hsupc commented May 14, 2025

Profiling

Use the built-in tools modmesh.call_profiler and modmesh.time_registry to profile the default behavior of SimpleArray::argwhere() from Python. This function is equivalent to SimpleArray::argwhere(lambda x: x != 0).

Numpy is abbreviated to np ,SimpleArray is abbreviated to sa.
And Nums is the abbreviation of number of elements.
Speedup achieved by SimpleArray is measured relative to NumPy.

np.argwhere() per call sa.argwhere() per call Speedup
Nums = 128, Data type = uint8 5.489 ms 1.849 ms 2.97x
Nums = 1K, Data type = uint16 3.150 ms 3.795 ms 0.83x
Nums = 8K, Data type = uint16 11.546 ms 24.759 ms 0.47x
Nums = 64K, Data type = uint32 80.181 ms 198.060 ms 0.40x
Nums = 512K, Data type = uint32 980.167 ms 2165.842 ms 0.45x
Nums = 4M, Data type = uint64 9604.355 ms 17401.239 ms 0.55x
Nums = 32M, Data type = uint64 102880.127 ms 160952.633 ms 0.64x

With iterations = 50, the test cases were generated using np.random.uniform().

@yungyuc
Copy link
Member

yungyuc commented May 16, 2025

Please include your profile script in the PR. @KHLee529 could you please help @pchsu-hsupc ?

The runtime is much less slower than I thought, but still too slow to be useful. We may not implement the interface by using a Python callable and/or lambda.

@yungyuc yungyuc requested a review from KHLee529 May 16, 2025 04:53
@KHLee529
Copy link
Collaborator

@pchsu-hsupc I think it 's worthy to first clarify whether it's the Python callable value that makes runtime slow or the C++ std::function. Maybe try to make the default argument condition a free function written in C++. If it is the Python callable object that slows down the whole process, we should implement this function in another way.

@yungyuc
Copy link
Member

yungyuc commented Jun 10, 2025

@pchsu-hsupc In the discussions in the meetup, we concluded that it should use Boolean array to select elements in the way that numpy employs. Please update your progress.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
array Multi-dimensional array implementation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants