-
-
Notifications
You must be signed in to change notification settings - Fork 40
Refactor: Separate Out Complex Conjugation Tests #245
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
Conversation
| "Answer true if self and aComplexNumber are complex conjugates of each other. The complex conjugate of a complex number is the number with an equal real part and an imaginary part equal in magnitude but opposite in sign." | ||
| ^ (aComplexNumber real = real) and: [ aComplexNumber imaginary = (-1 * imaginary) ] | ||
|
|
||
| ^ self = aComplexNumber complexConjugate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to a method? It's only used by a Matrix to check it is Hermitian. I don't feel it's needed. Is there evidence to the contrary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this method is needed for double dispatch.
I added it in this commit: 7d77acf
The idea is that both Number and PMComplex should answer to the message isComplexConjugateOf:
Because we need to apply it to matrices where we do not know if the values are real or complex
That being said, perhaps, we could simply define a complexConjugate method for the Number class
It would always return self
Then instead of isComplexConjugateOf: inside PMMatrix >> isHermitian, we could write number = otherNumber complexConjugate
I will open a separate issue for that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issue #247
olekscode
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I propose to reject this PR. Please see my comments
| "Answer true if self and aComplexNumber are complex conjugates of each other. The complex conjugate of a complex number is the number with an equal real part and an imaginary part equal in magnitude but opposite in sign." | ||
| ^ (aComplexNumber real = real) and: [ aComplexNumber imaginary = (-1 * imaginary) ] | ||
|
|
||
| ^ self = aComplexNumber complexConjugate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this method is needed for double dispatch.
I added it in this commit: 7d77acf
The idea is that both Number and PMComplex should answer to the message isComplexConjugateOf:
Because we need to apply it to matrices where we do not know if the values are real or complex
That being said, perhaps, we could simply define a complexConjugate method for the Number class
It would always return self
Then instead of isComplexConjugateOf: inside PMMatrix >> isHermitian, we could write number = otherNumber complexConjugate
I will open a separate issue for that
| self assert: aComplex copy hash equals: aComplex hash | ||
| ] | ||
|
|
||
| { #category : #tests } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem like refactoring.
Those tests are completely different from the ones that you added
| ] | ||
|
|
||
| { #category : #'testing - complex conjugation' } | ||
| PMComplexTest >> testThatComplexConjugateHasEqualRealPartAndAnImaginaryPartWithEqualMagnitudeButOppositeSign [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those long test names are very hard to read even if I can see all of it (and System Browser will hide most of the name because of the window size).
testThatComplexConjugateHasEqualRealPartAndAnImaginaryPartWithEqualMagnitudeButOppositeSign
I really prefer this name:
testComplexConjugate
Why?
Because we are testing if complexConjugate method returns the correct complex conjugate.
That's it.
Saying that "it must have equal real part and an imaginary part with equal magnitude but opposite sign" is just the definition of a complex conjugate. This sentence should be in a documentation comment of the complexConjugate method but not in the test name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a bit more to complex conjugation e.g. it is distributive over the binary operations for example hence:
I would say testWeCanComputeTheComplexConjugate
but if you insist I'm happy to go with what you suggest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, there is the value or idea of Tests as documentation c.f. XUnit Test Patterns by Géerard Mezsaros
| | z | | ||
| z := 3 + 2 i. | ||
|
|
||
| self assert: z complexConjugate equals: 3 - 2 i |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the code would be more readable if we don't create a variable here:
self assert: (3 + 2i) complexConjugate equals: (3 - 2i).Complex numbers are native to Pharo, they should be used like any other numbers.
And personally, I wouldn't write this:
| a b |
a := 4.
b := -4.
self assert: a negated equals: b.I would just write
self assert: 4 negated equals: -4So the same logic should apply to complex numbers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To sum up, I propose the following:
testComplexConjugate
self assert: (3 + 2i) complexConjugate equals: (3 - 2i).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The method with that name already exists but it is not good...
testComplexConjugate
| z complexConjugateOfZ expected |
z := 5 - 6 i.
complexConjugateOfZ := z complexConjugate .
expected := 5 + 6 i.
self assert: complexConjugateOfZ equals: expected.I propose to replace it with a more readable one-line version:
testComplexConjugate
self assert: (5 - 6i) complexConjugate equals: (5 + 6i).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will open a separate issue for that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Issue #246
| | z | | ||
| z := 5 + 0 i. | ||
|
|
||
| self assert: z complexConjugate equals: 5. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is not good.
First, the same comment about test name as above.
I would use a shorter name: testComplexConjugateOfRealNumber
The fact that it's itself is a definition of complex conjugate and should be in the method comment and not the test name
Second, about the temporary variable, same comment as above - I would not use it because it is unnecessary and make the code harder to read (of course, this is subjective).
Third (!), this test is misleading.
(5 + 0i) complexConjugate does not return 5 (a real number)
It returns (5 + 0i) (a complex number)
The reason why this test passes is because (5 + 0i) = 5
I would do the following:
- Remove this test, because for complex numbers, testing that
self assert: (5 - 0i) complexConjugate equals (5 + 0i)is the same test asself assert: (3 + 2i) complexConjugate equals (3 - 2i). And we already have that test astestComplexConjugate - Add
complexConjugatetoNumberclass (see my first comment to this review) - Write the following test for
Number:
NumberTest >> testComplexConjugate
self assert: 5 complexConjugate equals: 5| | z | | ||
| z := -0.5 - 1 i. | ||
|
|
||
| self deny: z complexConjugate equals: (3 - 2i) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would remove ALL those tests.
They pass by definition if testComplexConjugate passes
There is no need to pollute the code with 6 tests that can not possibly fail
The only way this can fail is either:
(a) if testComplexConjugate fails
(b) if complex numbers don't behave as expected, but this should be (an it is) reflected in the tests of complex numbers. It has nothing to do with complex conjugates specifically
| | z | | ||
| z := 3 - 2 i. | ||
|
|
||
| self assert: (z isComplexConjugateOf: (3 + 2 i)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the same reasons as discussed above, I would name this test testIsComplexConjugateOf and I would not create a temporary variable. So the code would be:
testIsComplexConjugateOf
self assert: ((3 - 2i) isComplexConjugateOf: (3 + 2i)).But this was already in the tests that you propose to remove.
Also, look at those tests that you propose to remove... they cover many important scenario:
- is complex conjugate of complex and real
- is complex conjugate of real and complex (different receiver)
- is complex conjugate of complex and complex
- is complex conjugate of complex and complex when they are not complex conjugate of each other
...
If we keep the isComplexConjugateOf: method, we must keep all those tests.
But if we remove it, and add complexConjugate to Number as I proposed above (will be a separate issue), then we can remove them and simply add testComplexConjugate to both Number and PMComplex
Clarified test naming and grouped the tests into a intention-revealing category.
Added new tests that demonstrates the properties of complex conjugation e.g. involution, distributive.