Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed dace::math::pow for Integer case #1748

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

philip-paul-mueller
Copy link
Collaborator

Added a pow specialization for dace::math::pow.

The new specialization works for integers if all arguments are integer the return value is guaranteed to be integer as well.
This should also solve the issue with the fft test mentioned by Tal (https://github.com/spcl/dace/pull/1742/files#diff-a81c4594b19da98f6516283a50f6958b04976ae2913f097358141b2681868f3eR158).
However, to work we need #1747.

The new specialization works for integers.
So if all arguments are integer the return value is guaranteed to be integer as well.
This should also solve the issue with the fft test mentioned by Tal.

https://github.com/spcl/dace/pull/1742/files#diff-a81c4594b19da98f6516283a50f6958b04976ae2913f097358141b2681868f3eR158
However, to work we need spcl#1747.
@philip-paul-mueller philip-paul-mueller changed the title Better pow Fixed dace::math::pow for Integer case Nov 11, 2024
@tbennun
Copy link
Collaborator

tbennun commented Nov 12, 2024

@philip-paul-mueller That's a lot of modern C++. Can you verify that it conforms to C++14?

@philip-paul-mueller
Copy link
Collaborator Author

Yes everything is C++14, actually it looks a bit strange because for example std::is_integral_v is in C++17.
We should consider switching to C++17.

I spotted a small error in the current implementation and also one in ipow which I fixed.

@philip-paul-mueller
Copy link
Collaborator Author

Actually If I have time I want to go through the runtime and fix some things there (for example the range class in pyinterop.h is wrong if (end - begin) % skip != 0 holds.

The original signature of `ipow` only accepted an unsigned integer as exponent.
However, it seems that it was called using integers as exponents.
Thus there is now a specialization for this case.

For the sake of argument let's consider the following situation `ipow(a, b)`:
- If `b` was zero then the previous implementation would return `a`, the new implementation returns 1.
- If `b` was negative then it would perform a lot of iterations, because a signed integer was converted to an unsigned one.
	In the new implementation, the function would return 0, which is in agreement with what `pow` does.
I now combined both versions into one, this makes it similar to what `pow` is.
However another version would be to put the enable if on the arguments, but I thought it would be too ugly.
@tbennun
Copy link
Collaborator

tbennun commented Nov 12, 2024

Yes everything is C++14, actually it looks a bit strange because for example std::is_integral_v is in C++17. We should consider switching to C++17.

I spotted a small error in the current implementation and also one in ipow which I fixed.

We cannot do so yet, definitely not before 1.0. As far as I understand some of our target platforms do not support it and it will change our compiler requirements.

@philip-paul-mueller
Copy link
Collaborator Author

I currently have a strange error with template instantiation.
I am looking into it as soon as I can.

After some digging I found out that `ipow` is only called for positive integers that are known at compile time.
And I know now whym because the `half` vectors do not play nice.
@philip-paul-mueller
Copy link
Collaborator Author

@tbennun On the note about C++17, in HIP mode C++17 is used.

default: '-std=c++17 -fPIC -O3 -ffast-math -Wno-unused-parameter'

Copy link
Contributor

@alexnick83 alexnick83 left a comment

Choose a reason for hiding this comment

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

The code is OK, but I am unsure if this is the behavior we want or what the user would expect. I understand there is an issue with StockhamFFT, but this is probably due to erroneous type inference from np.result_type, sympy, etc.

template<
typename T1,
typename T2,
typename = std::enable_if_t<std::is_integral<T1>::value && std::is_integral<T2>::value>
Copy link
Contributor

Choose a reason for hiding this comment

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

So, if both a and b are integers (signed or unsigned), this path will be followed? In other words, if we want to compute, e.g., 3^-5, we need to convert one of them to float. Are we sure this is the behavior we want?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is correct.
But we kind of need this behaviour, to enable the FFT test this commit enables.
There the problem is that a size of an array is given as a = np.ones(2**3).
Which the code generator translates to

double* a;
a = new double[pow(2, 3)];

If pow would return a double, then it is a compilation error.

There are technically three things we can do:

  • Leave it as it is.
  • Adding the specialization that if the exponent is an unsigned int then we return a double and hope that expressions such as above are never called where the exponent is unsigned, i.e.
unsigned int b = 4;
//...
double* a;
a = new double[pow(2, b)];
  • Patch the code generator that sizes in new[] expressions are always casted to std::size_t.
    However, this would be another PR.

What is your opinion on this @tbennun ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree with @alexnick83. The reason we didn't have these pow implementations in the first place was because of negative exponents. I think we should use ipow when we know something or the equivalent version only in the case of an unsigned exponent and integer base.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I looked it up in the code generator, ipow is only used if the exponent is known at code generation time.
This is not the case in the FFT test, there the exponent is not known and thus pow is selected.

The reason why it lead to the compilation error in the FFT test was because the arguments of pow where int64 and since there is only an overload for int and unsigned int, the template was selected.
However, even before the expression 5^-3 would have resulted in the value 0, given that both were integer.

For the reasons outlined above, I do not think that this PR changes anything big.
But how should I proceed @alexnick83 @tbennun

PS: I also tried to implement ipow for negative exponents and that failed with some compilation bug related to half, which I did not understood.

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

Successfully merging this pull request may close these issues.

3 participants