Skip to content

Conversation

@hemalvarambhia
Copy link
Contributor

@hemalvarambhia hemalvarambhia commented Apr 19, 2022

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.

@hemalvarambhia hemalvarambhia marked this pull request as ready for review April 19, 2022 16:50
@hemalvarambhia hemalvarambhia changed the title Refactor complex number tests Refactor: Clarify Complex Number Complex Conjugation Tests Apr 19, 2022
"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
Copy link
Contributor Author

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?

Copy link
Member

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

Copy link
Member

Choose a reason for hiding this comment

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

Issue #247

@hemalvarambhia hemalvarambhia changed the title Refactor: Clarify Complex Number Complex Conjugation Tests Refactor: Separate Out Conjugation Tests Apr 20, 2022
@hemalvarambhia hemalvarambhia changed the title Refactor: Separate Out Conjugation Tests Refactor: Separate Out Complex Conjugation Tests Apr 20, 2022
Copy link
Member

@olekscode olekscode left a 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
Copy link
Member

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 }
Copy link
Member

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 [
Copy link
Member

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

Copy link
Contributor Author

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.

Copy link
Contributor Author

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
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 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: -4

So the same logic should apply to complex numbers

Copy link
Member

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).

Copy link
Member

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).

Copy link
Member

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

Copy link
Member

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.
Copy link
Member

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:

  1. Remove this test, because for complex numbers, testing that self assert: (5 - 0i) complexConjugate equals (5 + 0i) is the same test as self assert: (3 + 2i) complexConjugate equals (3 - 2i). And we already have that test as testComplexConjugate
  2. Add complexConjugate to Number class (see my first comment to this review)
  3. 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)
Copy link
Member

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))
Copy link
Member

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

@hemalvarambhia hemalvarambhia deleted the refactor-complex-number-tests branch April 23, 2022 06:04
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.

3 participants