STYLE: Use recursive FFT registration for N to 1#3065
Conversation
|
How does the approach template <typename InputPixelType, typename OutputPixelType, unsigned int ImageDimension>
void
OverrideFFTImageFilterType(const std::integral_constant<unsigned int, ImageDimension> &)
{
// ...
}
// Invoke with
OverrideFFTImageFilterType<InputPixelType, OutputPixelType>(std::integral_constant<unsigned int, D>());compare with template <typename InputPixelType, typename OutputPixelType, unsigned int ImageDimension>
void
OverrideFFTImageFilterType()
{
// ...
}
// Invoke with
OverrideFFTImageFilterType<InputPixelType, OutputPixelType, D>(); |
|
@Leengit The approach taker here also does the following to "specialized" the use when the dimension is 0: As you can not do partial template specialization for member function, the approach in this patch uses member function overload and depends on the C++ specification preferring the overloaded method that is more specific. ( Sorry know know the specific term. ). With the proposed alternative how is the template parameter recursion terminated? |
|
@blowekamp Interesting! I think it would be nice if |
Yes, I understand now. Although I venture that we could emulate the partial template specialization for the method, with |
@N-Dekker That looks "nifty". I'm not sure that the usage would be more compact, clearer or offer any benefit over using new C++/STL features. |
I have generally found std::enable_if give a little more clutter and complication to functions. The simpler overloaded approach is less code and is easier to understand. |
|
@blowekamp Thanks for working on this, very good idea to move from manually setting dimensions to a more configurable pattern. I'm wondering if there is room here to support class overrides not necessarily starting at I haven't tried compiling but I imagine something exposing override dimensions through the template <template <typename, typename> class TFFTImageFilter>
struct FFTImageFilterTraits
{
using DimensionList = std::make_index_sequence<4>;
};
template <template <typename, typename> class TFFTImageFilter>
class FFTImageFilterFactory : public itk::ObjectFactoryBase
{
...
FFTImageFilterFactory()
{
(OverrideFFTImageFilterType<typename FFTImageFilterTraits<TFFTImageFilter>::template InputPixelType<float>,
typename FFTImageFilterTraits<TFFTImageFilter>::template OutputPixelType<float>,
FFTImageFilterTraits<TFFTImageFilter>::DimensionList>(), ...);
...
}If pursuing this would pose an undue burden, though, I'm fine with moving ahead as-is and revisiting if a need arises at some point in the future. EDIT: I researched this a bit more and fold expressions were introduced in C++17. We are targeting C++14, which I believe would make the block suggested here in |
|
It looks like we are all in agreement: this is an improvement. Planning to merge later today, unless someone objects or beats me to it 😄 |
Instead of manually listing the FFT filter dimensions to regisiter, use a recursive function templated over an integer. This in the future can easily enable the maximum FFT dimension to be registered as some type of configuration parameter.
60d6f15 to
c6c61b5
Compare
|
Well I gave into peer pressure and updated to the std::integer_sequence thing... Please wait to the CI to finished. |
|
@blowekamp I think the advantage of |
|
Wasn't the purpose to allow skipping some numbers? |
I'm not sure what you had in mind then. You should give a go at implementing as you'd like 😉 |
|
I agree with @dzenanz, the implementation shouldn't matter so much as exposing functionality to external developers. @blowekamp 's implementation sets up a good structure to allow wrapping dimensions to be explicitly specified rather than always being in the range from 1 to N. Its recursive nature is not exposed to the developer and isn't too difficult to read here. I will point out that while the current changes alter the structure of template <template <typename, typename> class TFFTImageFilter>
struct FFTImageFilterTraits
{
using DimensionList = std::make_integer_sequence<unsigned int, 4>;
};
...
OverrideFFTImageFilterType<typename FFTImageFilterTraits<TFFTImageFilter>::template InputPixelType<float>,
typename FFTImageFilterTraits<TFFTImageFilter>::template OutputPixelType<double>>(
FFTImageFilterTraits<TFFTImageFilter>::DimensionList);@blowekamp it's up to you whether this is within the scope of this PR to investigate or not. |
I did give this a try, but since all the specialized With this proposed addition, it not clear how this could be configurable. For example ITK Python was configured with 5d could it be enabled some how? Or SimpleITK does not use 4D ffts, is there a way to disable that from being compiled. ( I think the 4D implementation may be in the libraries too, adding to the library bulk.... I should check. ) |
Ah good point, thanks for giving it a shot. I think these changes stand alone without it, I can investigate and submit a subsequent PR down the line.
You're right, I meant "configurable" as opposed to manually outlining a factory registration call for each distinct dimension. In my mind the optimal approach for Python-wrapped files would be to only register default factories against the image values outlined in |
|
Is this ready for merging now? |
|
Could |
|
It appears that Using the wonderful Unfortunately, VS2019 says:
|
|
Well, I guess you should report this instance of ICE-ing ... aaand give up on this rewrite, at least for the time being 😄 |
|
@N-Dekker Thanks for sharing and informing me about that usage of initializer lists and parameter packing. |
Just reported the compiler bug to Microsoft, please "up-vote": Minimal example to reproduce the compiler bug, at https://godbolt.org/z/PnGW5hcnj : Update from the Microsoft Feedback Bot, January 18, 2022:
|
Instead of manually listing the FFT filter dimensions to regisiter,
use a recursive function templated over an integer. This in the future
can easily enable the maximum FFT dimension to be registered as some
type of configuration parameter.
PR Checklist
Refer to the ITK Software Guide for
further development details if necessary.