-
Notifications
You must be signed in to change notification settings - Fork 46
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
Complex py wrap #452
Complex py wrap #452
Conversation
cpp/modmesh/math.hpp
Outdated
template <typename T, typename = std::enable_if_t<std::is_arithmetic<T>::value>> | ||
struct ComplexImpl | ||
{ | ||
T real_v; | ||
T imag_v; | ||
|
||
explicit ComplexImpl() | ||
: ComplexImpl(0.0, 0.0) | ||
{ | ||
} | ||
|
||
explicit ComplexImpl(T r, T i) | ||
: real_v(r) | ||
, imag_v(i) | ||
{ | ||
} | ||
|
||
explicit ComplexImpl(const ComplexImpl & other) | ||
: real_v(other.real_v) | ||
, imag_v(other.imag_v) | ||
{ | ||
} | ||
|
||
ComplexImpl operator+(const ComplexImpl & other) const | ||
{ | ||
return ComplexImpl(real_v + other.real_v, imag_v + other.imag_v); | ||
} | ||
|
||
ComplexImpl operator-(const ComplexImpl & other) const | ||
{ | ||
return ComplexImpl(real_v - other.real_v, imag_v - other.imag_v); | ||
} | ||
|
||
ComplexImpl operator*(const ComplexImpl & other) const | ||
{ | ||
return ComplexImpl(real_v * other.real_v - imag_v * other.imag_v, real_v * other.imag_v + imag_v * other.real_v); | ||
} | ||
|
||
ComplexImpl operator/(const T & other) const | ||
{ | ||
return ComplexImpl(real_v / other, imag_v / other); | ||
} | ||
|
||
ComplexImpl & operator=(const ComplexImpl & other) | ||
{ | ||
if (this != &other) // Check for self-assignment | ||
{ | ||
real_v = other.real_v; | ||
imag_v = other.imag_v; | ||
} | ||
return *this; | ||
} | ||
|
||
ComplexImpl & operator+=(const ComplexImpl & other) | ||
{ | ||
real_v += other.real_v; | ||
imag_v += other.imag_v; | ||
return *this; | ||
} | ||
|
||
ComplexImpl & operator-=(const ComplexImpl & other) | ||
{ | ||
real_v -= other.real_v; | ||
imag_v -= other.imag_v; | ||
return *this; | ||
} | ||
|
||
T real() const { return real_v; } | ||
T imag() const { return imag_v; } | ||
T norm() const { return real_v * real_v + imag_v * imag_v; } | ||
}; /* end class ComplexImpl */ | ||
|
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.
Move ComplexImpl
into mathtype
folder for creating python wrapper.
cpp/modmesh/mathtype/Complex.hpp
Outdated
template <typename T, typename = std::enable_if_t<std::is_arithmetic<T>::value>> | ||
struct ComplexImpl | ||
{ | ||
T real_v; | ||
T imag_v; | ||
|
||
explicit ComplexImpl() | ||
: ComplexImpl(0.0, 0.0) | ||
{ | ||
} | ||
|
||
explicit ComplexImpl(T r, T i) | ||
: real_v(r) | ||
, imag_v(i) | ||
{ | ||
} | ||
|
||
explicit ComplexImpl(const ComplexImpl & other) | ||
: real_v(other.real_v) | ||
, imag_v(other.imag_v) | ||
{ | ||
} | ||
|
||
ComplexImpl operator+(const ComplexImpl & other) const | ||
{ | ||
return ComplexImpl(real_v + other.real_v, imag_v + other.imag_v); | ||
} | ||
|
||
ComplexImpl operator-(const ComplexImpl & other) const | ||
{ | ||
return ComplexImpl(real_v - other.real_v, imag_v - other.imag_v); | ||
} | ||
|
||
ComplexImpl operator*(const ComplexImpl & other) const | ||
{ | ||
return ComplexImpl(real_v * other.real_v - imag_v * other.imag_v, real_v * other.imag_v + imag_v * other.real_v); | ||
} | ||
|
||
ComplexImpl operator/(const T & other) const | ||
{ | ||
return ComplexImpl(real_v / other, imag_v / other); | ||
} | ||
|
||
ComplexImpl & operator=(const ComplexImpl & other) | ||
{ | ||
if (this != &other) // Check for self-assignment | ||
{ | ||
real_v = other.real_v; | ||
imag_v = other.imag_v; | ||
} | ||
return *this; | ||
} | ||
|
||
ComplexImpl & operator+=(const ComplexImpl & other) | ||
{ | ||
real_v += other.real_v; | ||
imag_v += other.imag_v; | ||
return *this; | ||
} | ||
|
||
ComplexImpl & operator-=(const ComplexImpl & other) | ||
{ | ||
real_v -= other.real_v; | ||
imag_v -= other.imag_v; | ||
return *this; | ||
} | ||
|
||
T real() const { return real_v; } | ||
T imag() const { return imag_v; } | ||
T norm() const { return real_v * real_v + imag_v * imag_v; } | ||
}; /* end class ComplexImpl */ |
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.
Meanwhile, I'm trying to integrate with SimpleArray and create an array type Python wrapper and make it compatible with the NumPy buffer protocol, but I got a static assert
modmesh/cpp/modmesh/python/common.hpp
Line 63 in c9594da
return pybind11::detail::npy_format_descriptor<T>::dtype().is(arr.dtype()); |
Which is that
ComplexImpl<T>
is not a POD type. Currently, I don't have a firm plan to move forward.
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 ending mark should be /* end structure ComplexImpl */
.
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.
ComplexImpl<T>
looks like POD. What does it mean to say t is not a POD type?
.def("__complex__", | ||
[](wrapped_type const & self) | ||
{ return std::complex<T>(self.real(), self.imag()); }); |
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.
Making it compatible with python built-in complex
type and cmath
function.
@yungyuc This PR is ready for review! |
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.
Good move. I would like to have tightened structure of the code:
-
cpp/modmesh/math.hpp
: Usecpp/modmesh/math/
to conform to the existing namecpp/modmesh/math.hpp
. Do not create another directory name (mathtype
). -
test_mathtype.py
: Random number is not necessary. Don't use it.
tests/test_mathtype.py
Outdated
|
||
import modmesh as mm | ||
|
||
from random import random |
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 is in stdlib and should be grouped with import unittest
at L27
.
tests/test_mathtype.py
Outdated
class ComplexTC(unittest.TestCase): | ||
|
||
def setUp(self): | ||
self.real1_32 = np.float32(random()) |
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.
Please avoid random number in unit tests unless there is not another way. Using random number introduces a hidden dependency. If random number goes wrong, the tests here will issue false alarm. The false alarm is noise that burdens maintenance.
The random number is not printed in code and maintainers need to print it themselves when troubleshooting. This is another burden.
In this case, there are ways other than generating random number here, so random number should not be used.
You can randomly generate fixture and print the number here.
cpp/modmesh/math.hpp
Outdated
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.
You should move cpp/modmesh/math.hpp
to cpp/modmesh/math/math.hpp
. The directory should be named as cpp/modmesh/math/
, not cpp/modmesh/mathtype/
.
tests/test_mathtype.py
Outdated
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.
After changing the new directory to be cpp/modmesh/math/
, this should be renamed as test_math.py
.
modmesh/core.py
Outdated
@@ -97,6 +97,8 @@ | |||
'WorldFp32', | |||
'WorldFp64', | |||
'testhelper', | |||
'ComplexFloat32', |
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 two lines should be placed before SimpleArray
because they are more fundamental.
cpp/modmesh/mathtype/mathtype.hpp
Outdated
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 should be replaced by moving cpp/modmesh/math.hpp
here.
cpp/modmesh/mathtype/Complex.hpp
Outdated
template <typename T, typename = std::enable_if_t<std::is_arithmetic<T>::value>> | ||
struct ComplexImpl | ||
{ | ||
T real_v; | ||
T imag_v; | ||
|
||
explicit ComplexImpl() | ||
: ComplexImpl(0.0, 0.0) | ||
{ | ||
} | ||
|
||
explicit ComplexImpl(T r, T i) | ||
: real_v(r) | ||
, imag_v(i) | ||
{ | ||
} | ||
|
||
explicit ComplexImpl(const ComplexImpl & other) | ||
: real_v(other.real_v) | ||
, imag_v(other.imag_v) | ||
{ | ||
} | ||
|
||
ComplexImpl operator+(const ComplexImpl & other) const | ||
{ | ||
return ComplexImpl(real_v + other.real_v, imag_v + other.imag_v); | ||
} | ||
|
||
ComplexImpl operator-(const ComplexImpl & other) const | ||
{ | ||
return ComplexImpl(real_v - other.real_v, imag_v - other.imag_v); | ||
} | ||
|
||
ComplexImpl operator*(const ComplexImpl & other) const | ||
{ | ||
return ComplexImpl(real_v * other.real_v - imag_v * other.imag_v, real_v * other.imag_v + imag_v * other.real_v); | ||
} | ||
|
||
ComplexImpl operator/(const T & other) const | ||
{ | ||
return ComplexImpl(real_v / other, imag_v / other); | ||
} | ||
|
||
ComplexImpl & operator=(const ComplexImpl & other) | ||
{ | ||
if (this != &other) // Check for self-assignment | ||
{ | ||
real_v = other.real_v; | ||
imag_v = other.imag_v; | ||
} | ||
return *this; | ||
} | ||
|
||
ComplexImpl & operator+=(const ComplexImpl & other) | ||
{ | ||
real_v += other.real_v; | ||
imag_v += other.imag_v; | ||
return *this; | ||
} | ||
|
||
ComplexImpl & operator-=(const ComplexImpl & other) | ||
{ | ||
real_v -= other.real_v; | ||
imag_v -= other.imag_v; | ||
return *this; | ||
} | ||
|
||
T real() const { return real_v; } | ||
T imag() const { return imag_v; } | ||
T norm() const { return real_v * real_v + imag_v * imag_v; } | ||
}; /* end class ComplexImpl */ |
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 ending mark should be /* end structure ComplexImpl */
.
cpp/modmesh/mathtype/Complex.hpp
Outdated
template <typename T, typename = std::enable_if_t<std::is_arithmetic<T>::value>> | ||
struct ComplexImpl | ||
{ | ||
T real_v; | ||
T imag_v; | ||
|
||
explicit ComplexImpl() | ||
: ComplexImpl(0.0, 0.0) | ||
{ | ||
} | ||
|
||
explicit ComplexImpl(T r, T i) | ||
: real_v(r) | ||
, imag_v(i) | ||
{ | ||
} | ||
|
||
explicit ComplexImpl(const ComplexImpl & other) | ||
: real_v(other.real_v) | ||
, imag_v(other.imag_v) | ||
{ | ||
} | ||
|
||
ComplexImpl operator+(const ComplexImpl & other) const | ||
{ | ||
return ComplexImpl(real_v + other.real_v, imag_v + other.imag_v); | ||
} | ||
|
||
ComplexImpl operator-(const ComplexImpl & other) const | ||
{ | ||
return ComplexImpl(real_v - other.real_v, imag_v - other.imag_v); | ||
} | ||
|
||
ComplexImpl operator*(const ComplexImpl & other) const | ||
{ | ||
return ComplexImpl(real_v * other.real_v - imag_v * other.imag_v, real_v * other.imag_v + imag_v * other.real_v); | ||
} | ||
|
||
ComplexImpl operator/(const T & other) const | ||
{ | ||
return ComplexImpl(real_v / other, imag_v / other); | ||
} | ||
|
||
ComplexImpl & operator=(const ComplexImpl & other) | ||
{ | ||
if (this != &other) // Check for self-assignment | ||
{ | ||
real_v = other.real_v; | ||
imag_v = other.imag_v; | ||
} | ||
return *this; | ||
} | ||
|
||
ComplexImpl & operator+=(const ComplexImpl & other) | ||
{ | ||
real_v += other.real_v; | ||
imag_v += other.imag_v; | ||
return *this; | ||
} | ||
|
||
ComplexImpl & operator-=(const ComplexImpl & other) | ||
{ | ||
real_v -= other.real_v; | ||
imag_v -= other.imag_v; | ||
return *this; | ||
} | ||
|
||
T real() const { return real_v; } | ||
T imag() const { return imag_v; } | ||
T norm() const { return real_v * real_v + imag_v * imag_v; } | ||
}; /* end class ComplexImpl */ |
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.
ComplexImpl<T>
looks like POD. What does it mean to say t is not a POD type?
@yungyuc This PR is ready for the next review. I have made the following change:
For the array type of complex number, I plan to use another PR. |
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 array type of complex number, I plan to use another PR.
Sounds like a plan. Still having issues to be worked out:
-
cpp/modmesh/python/module.cpp:33
: Formatting: missing blank lines after inclusion. -
tests/test_math.py:39
: Fixture should not use duplicate value. - Please squash. This PR does not need so many commits.
@@ -30,6 +30,7 @@ | |||
#include <modmesh/spacetime/pymod/spacetime_pymod.hpp> | |||
#include <modmesh/toggle/pymod/toggle_pymod.hpp> | |||
#include <modmesh/universe/pymod/universe_pymod.hpp> | |||
#include <modmesh/math/pymod/math_pymod.hpp> |
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.
Need a blank line. (This issue appears at multiple locations. Please fix them all.)
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 also found that some include order do not follow the LLVM include style, for example
modmesh/cpp/modmesh/spacetime/io.hpp
Line 8 in c9594da
#include <iostream> |
should I fix them ?
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.
Thanks for spotting the inclusion order. It should not be done with the enhancement PR.
We are not strictly following inclusion order. It's not important atm, but we should optimize the inclusion at some point. If anyone cares about it, it can be done in a standalone PR.
tests/test_math.py
Outdated
def setUp(self): | ||
self.real1_32 = np.float32(1.0) | ||
self.imag1_32 = np.float32(1.0) | ||
self.real2_32 = np.float32(1.0) |
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.
real/imag 1/2 are both 1+i. Please use use different value.
20a98f0
to
f97e2aa
Compare
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.
@yungyuc This PR is ready for the next review.
I have squashed commits, fixed missing blank lines after inclusion and using different number for test fixtures.
self.real1_32 = np.float32(0.7) | ||
self.imag1_32 = np.float32(1.6) | ||
self.real2_32 = np.float32(2.5) | ||
self.imag2_32 = np.float32(3.4) | ||
|
||
self.real1_64 = np.float64(4.3) | ||
self.imag1_64 = np.float64(5.2) | ||
self.real2_64 = np.float64(6.1) | ||
self.imag2_64 = np.float64(7.0) |
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.
Using different number for fixtures.
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 is good.
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.
- Do not change blank lines in unrelated files.
Please revert all unnecessary style changes and squash.
@@ -29,6 +29,7 @@ | |||
#include <modmesh/buffer/pymod/buffer_pymod.hpp> // Must be the first include. | |||
|
|||
#include <modmesh/buffer/pymod/array_common.hpp> | |||
|
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.
Do not change formatting in unrelated files. Adding/removing blank lines is refactoring. Refactoring change should not be included in the same PR as feature development.
self.real1_32 = np.float32(0.7) | ||
self.imag1_32 = np.float32(1.6) | ||
self.real2_32 = np.float32(2.5) | ||
self.imag2_32 = np.float32(3.4) | ||
|
||
self.real1_64 = np.float64(4.3) | ||
self.imag1_64 = np.float64(5.2) | ||
self.real2_64 = np.float64(6.1) | ||
self.imag2_64 = np.float64(7.0) |
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 is good.
Do you have any plan to support complex array? |
It has been discussed and the conclusion is to handle it in another PR.
|
f97e2aa
to
b6042a6
Compare
@yungyuc This PR is ready for the next review, I have reverted all unnecessary style changes and only applied style change within related files. |
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.
It now looks good. Thanks for the work.
@@ -96,7 +98,7 @@ | |||
'Bezier3dFp64', | |||
'WorldFp32', | |||
'WorldFp64', | |||
'testhelper', | |||
'testhelper' |
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 should be a comma after each line in a Python list. Please be careful about it next time.
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.
Thanks, I will be careful about this next time.
In this I have added modmesh
complex
implementation python wrapper, and containing python unit test code.And it is in preparation for further fft GUI related development.