Skip to content

Conversation

endolith
Copy link
Contributor

Some arrays should produce real output but don't:

In [144]: poly([1j, -1j])
Out[144]: array([ 1.,  0.,  1.])

In [145]: poly([1j, -1j, 2j, -2j])
Out[145]: array([ 1.+0.j,  0.+0.j,  5.+0.j,  0.+0.j,  4.+0.j])

In [146]: _.imag == 0
Out[146]: array([ True,  True,  True,  True,  True], dtype=bool)

I think the check was meant to be sort_complex(conjugate(... rather than conjugate(sort_complex(..., which would work, but checking that the imaginary parts are exactly zero is equivalent and simpler anyway.

@endolith
Copy link
Contributor Author

oh wait now it doesn't work for poly([+1.082j, +2.613j, -2.613j, -1.082j]). So maybe make it neg_roots = sort_complex(NX.conjugate( instead. I'll do more tests

@charris
Copy link
Member

charris commented Nov 25, 2013

It might be better to have a real keywordarg as the user is likely to have a better sense of whether the result should be real or not. Otherwise, one relies on a certain degree of numerical precision which may not be available depending on where the roots come from.

@endolith
Copy link
Contributor Author

That would be equivalent to real(poly()), right?

Regardless, if the output is exactly real, or input are exact conjugates, it should automatically not use a complex type for output.

@endolith endolith closed this Nov 27, 2013
@endolith endolith deleted the patch-2 branch November 27, 2013 05:33
@endolith endolith reopened this Nov 27, 2013
@endolith
Copy link
Contributor Author

Ok I changed it back to the conjugate then sort method, and added a bunch of tests. Does this look good?

Is there a reason it's for k in range(len(seq_of_zeros)): instead of for x in seq_of_zeros:?

endolith added a commit to endolith/scipy that referenced this pull request Jan 19, 2014
…ry parts

Fixed in numpy/numpy#4073, but we can't depend on a specific numpy version, so copying it here, too.
if (len(pos_roots) == len(neg_roots) and
NX.alltrue(neg_roots == pos_roots)):
a = a.real.copy()
pos_roots = NX.compress(roots.imag > 0, roots)
Copy link
Member

Choose a reason for hiding this comment

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

I think you could just check np.all(roots.sort() == roots.conjugate().sort()).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, .sort() is in-place sorting and doesn't return anything, so anything.sort() == anythingelse.sort() is always true.

np.all(np.sort(roots) == np.sort(roots.conjugate()))?

np.sort_complex() just calls np.sort() internally but always outputs a complex type? Not sure if it's necessary, but just kept what was in the original code.

Copy link
Member

Choose a reason for hiding this comment

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

You're right about the sort method.

Both the polynomial and sort_complex code date back to 2002 with later refactoring, so I expect not using sort directly is just historical accident.

Copy link
Member

Choose a reason for hiding this comment

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

And since only complex types are checked, the return will be complex anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I assume checking the size first is to speed up rejections for huge arrays?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Though I guess polynomials are always going to be short 1d arrays?

Copy link
Member

Choose a reason for hiding this comment

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

I'd guess that going much over 20 is going to be a problem in general. I've gone up to 60 equally spaced roots in the polynomial package, which does better than this, but the results can be sensitive to root placement.

@jaimefrio
Copy link
Member

You need to rebase on master, some changes were made to the type handling a while back.

On a separate note regarding the actual object of this PR, wouldn't it make sense to detect the conjugate roots before multiplying? That way you could collapse every two conjugate roots into a strictly real second degree binomial and avoid roundoff errors creeping into the imaginary part of the result.

@charris
Copy link
Member

charris commented Jan 25, 2015

@jaimefrio Yes, and for power series that is pretty easy to do, although the convolution here would need modification. For other polynomial basis it gets a bit more involved.

Change to a deterministic test instead of using rand
@endolith
Copy link
Contributor Author

Ok, I rebased it and fixed an import error. Should I definitely change to np.all(np.sort(roots) == np.sort(roots.conjugate()))?

@charris
Copy link
Member

charris commented Jan 25, 2015

@endolith I think it would be cleaner. I don't think speed is of much importance here, but it might even be faster.

@endolith
Copy link
Contributor Author

Ok I changed it.

@rgommers
Copy link
Member

rgommers commented Mar 8, 2015

@charris this seems about ready to merge. ignore the test failure, that's unrelated (couldn't download Cython)

@endolith
Copy link
Contributor Author

endolith commented Mar 8, 2015

Actually instead of that long string of numbers in the test, it could just set the numpy random seed for determinism and go back to

a = rand(100) + 1j* rand(100)
assert_(np.isrealobj(np.poly(np.concatenate((a, np.conjugate(a))))))

also fixed some PEP8 issues
@endolith
Copy link
Contributor Author

Was there anything else that needed to be done on this?

@endolith
Copy link
Contributor Author

Is there anything wrong with this change?

@charris charris merged commit e26738a into numpy:master Jun 15, 2016
@charris
Copy link
Member

charris commented Jun 15, 2016

No, LGTM ;) Thanks @endolith .

@endolith endolith changed the title BUG: change real output checking to test if all imaginary parts are zero BUG: change poly() real output checking to test if all imaginary parts are zero Apr 22, 2022
roryyorke added a commit to roryyorke/scipy that referenced this pull request Dec 30, 2024
Removed code defending against old Numpy: [1] was included in Numpy
1.12.0, and minimum Numpy now is 1.23.5.  See [2] for context.

[1] numpy/numpy#4073
[2] scipy#3085 (comment)
roryyorke added a commit to roryyorke/scipy that referenced this pull request Dec 30, 2024
Removed code defending against old Numpy: [1] was included in Numpy
1.12.0, and minimum Numpy now is 1.23.5.  See [2] for context.

[1] numpy/numpy#4073
[2] scipy#3085 (comment)
j-bowhay pushed a commit to scipy/scipy that referenced this pull request Dec 30, 2024
…test for complex k, real p, z (#22213)

Removed code defending against old Numpy: [1] was included in Numpy
1.12.0, and minimum Numpy now is 1.23.5.  See [2] for context.

[1] numpy/numpy#4073
[2] #3085 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants