Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hi, I have made a preliminary complex list implementation class which is backed by a single double array in interleaved format. I made some test cases for the forEach methods as well. This can be viewed here [1]. Please let me know what you think and if I'm on the right track. Thanks, Sumanth [1] https://github.com/sumanth-rajkumar/commons-numbers/tree/NUMBERS-186.complex_list_support/commons-numbers-complex/src On Tue, 2 Aug 2022 at 13:26, Sumanth Rajkumar wrote: > Thanks Alex for the feedback, > > I'll work on a ComplexList class that implements the List interface and is > backed by a single double array in interleaved format. > I'll have something ready to look at by tomorrow. > > Thanks, > > Sumanth > > On Tue, 2 Aug 2022 at 03:52, Alex Herbert > wrote: > >> On Mon, 1 Aug 2022 at 17:38, Sumanth Rajkumar > > >> wrote: >> >> > Hi, >> > >> > > I think that Alex's suggestion still holds: Better focus on one >> > > task at a time. Are the "list" and "matrix" features related? >> > >> > OK, Will focus on list features first and focus on extending all >> existing >> > methods on the Complex class to Lists. >> > >> > UnaryOperators will apply the operation (using refactored static >> methods) >> > to each element. >> > BinaryOperators for lists will have two variants. >> > For the first variant, the second operand is a single complex number >> that >> > is applied as second operand for all elements on List >> > The second variant operates on two Lists. Can we look at this later? >> > >> >> For an operand that is a single complex number then this should be >> satisfied by passing a lambda function to the unary forEach. The same >> would >> be the same for a single double factor. So these seem redundant and can be >> covered by documentation. >> >> I would suggest you create a List implementation that only >> satisfies the list interface in an optimal manner. If you extend >> java.util.AbstractList the minimal implementation is often not optimal for >> the storage (for example the spliterator and the forEach constructs). >> >> The support for a JDK Collection may not have to add any additional >> methods >> for processing. It would merely replace using ArrayList. >> Numerical >> processing of complex numbers could be added instead to a more focussed >> data structure that does not support the entire Collection API, i.e. the >> vector and matrix concepts previously proposed. >> >> >> > >> > > Do we have one use case for the "list" feature? >> > > I see there a lot factory methods that seem to defeat the >> > > intended purpose (AFAIU Matt's remark) of letting the caller >> > > decide on the input format. >> > > Similarly, the "parse" feature should be left to the code that >> > > handles the input. IOW shouldn't we separate the concerns >> > > of converting the input (array, stream, list of strings, ...) from >> > > what can be done with a "list" instance? >> > >> > Since the lists can have different underlying data storage >> implementations >> > such as >> > a) single double primitive array or DoubleBuffer in interleaved format >> > b) single double primitive array or DoubleBuffer in sub array format >> > c) separate arrays/DoubleBuffers for real and imaginary parts >> > >> > Based on earlier discussions, Alex wanted the iteration logic over the >> list >> > to apply the operators to be within the List implementation >> > So each implementation will have its own implementation of operators >> that >> > is optimal for its data storage >> > >> > For now, should we focus on more than 1 implementation? If it is just 1 >> > implementation, which one can I pick up first? >> > >> >> 1 implementation is the best start point to build the API. >> >> >> > Should we have a common interface (minimum methods/operations that all >> > implementations should support)? >> > >> >> That makes sense. However a known backing format for the data will allow >> optimal computation. So once the API is established for a single data >> structure format we can test speed of computation when mixing backing data >> structures. >> >> >> > >> > If so, I can first focus on finalizing the List interface and then look >> at >> > implementations >> > >> > I was also looking at the EJML api's [1]. >> > They support three API styles a) Procedural b) SimpleMatrix and c) >> > Equations (Matlab style) >> > >> > It looks like we will be implementing the SimpleMatrix style. Should we >> > also consider other approaches? >> > >> >> Equations requires parsing text input. I would put that out-of-scope. I >> would say an OO style is the most natural from a Java perspective. The API >> could be similar to the matrix functionality in Commons Math. >> >> Alex >> >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Thanks Alex for the feedback, I'll work on a ComplexList class that implements the List interface and is backed by a single double array in interleaved format. I'll have something ready to look at by tomorrow. Thanks, Sumanth On Tue, 2 Aug 2022 at 03:52, Alex Herbert wrote: > On Mon, 1 Aug 2022 at 17:38, Sumanth Rajkumar > wrote: > > > Hi, > > > > > I think that Alex's suggestion still holds: Better focus on one > > > task at a time. Are the "list" and "matrix" features related? > > > > OK, Will focus on list features first and focus on extending all existing > > methods on the Complex class to Lists. > > > > UnaryOperators will apply the operation (using refactored static methods) > > to each element. > > BinaryOperators for lists will have two variants. > > For the first variant, the second operand is a single complex number that > > is applied as second operand for all elements on List > > The second variant operates on two Lists. Can we look at this later? > > > > For an operand that is a single complex number then this should be > satisfied by passing a lambda function to the unary forEach. The same would > be the same for a single double factor. So these seem redundant and can be > covered by documentation. > > I would suggest you create a List implementation that only > satisfies the list interface in an optimal manner. If you extend > java.util.AbstractList the minimal implementation is often not optimal for > the storage (for example the spliterator and the forEach constructs). > > The support for a JDK Collection may not have to add any additional methods > for processing. It would merely replace using ArrayList. Numerical > processing of complex numbers could be added instead to a more focussed > data structure that does not support the entire Collection API, i.e. the > vector and matrix concepts previously proposed. > > > > > > > Do we have one use case for the "list" feature? > > > I see there a lot factory methods that seem to defeat the > > > intended purpose (AFAIU Matt's remark) of letting the caller > > > decide on the input format. > > > Similarly, the "parse" feature should be left to the code that > > > handles the input. IOW shouldn't we separate the concerns > > > of converting the input (array, stream, list of strings, ...) from > > > what can be done with a "list" instance? > > > > Since the lists can have different underlying data storage > implementations > > such as > > a) single double primitive array or DoubleBuffer in interleaved format > > b) single double primitive array or DoubleBuffer in sub array format > > c) separate arrays/DoubleBuffers for real and imaginary parts > > > > Based on earlier discussions, Alex wanted the iteration logic over the > list > > to apply the operators to be within the List implementation > > So each implementation will have its own implementation of operators that > > is optimal for its data storage > > > > For now, should we focus on more than 1 implementation? If it is just 1 > > implementation, which one can I pick up first? > > > > 1 implementation is the best start point to build the API. > > > > Should we have a common interface (minimum methods/operations that all > > implementations should support)? > > > > That makes sense. However a known backing format for the data will allow > optimal computation. So once the API is established for a single data > structure format we can test speed of computation when mixing backing data > structures. > > > > > > If so, I can first focus on finalizing the List interface and then look > at > > implementations > > > > I was also looking at the EJML api's [1]. > > They support three API styles a) Procedural b) SimpleMatrix and c) > > Equations (Matlab style) > > > > It looks like we will be implementing the SimpleMatrix style. Should we > > also consider other approaches? > > > > Equations requires parsing text input. I would put that out-of-scope. I > would say an OO style is the most natural from a Java perspective. The API > could be similar to the matrix functionality in Commons Math. > > Alex >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Mon, 1 Aug 2022 at 17:38, Sumanth Rajkumar wrote: > Hi, > > > I think that Alex's suggestion still holds: Better focus on one > > task at a time. Are the "list" and "matrix" features related? > > OK, Will focus on list features first and focus on extending all existing > methods on the Complex class to Lists. > > UnaryOperators will apply the operation (using refactored static methods) > to each element. > BinaryOperators for lists will have two variants. > For the first variant, the second operand is a single complex number that > is applied as second operand for all elements on List > The second variant operates on two Lists. Can we look at this later? > For an operand that is a single complex number then this should be satisfied by passing a lambda function to the unary forEach. The same would be the same for a single double factor. So these seem redundant and can be covered by documentation. I would suggest you create a List implementation that only satisfies the list interface in an optimal manner. If you extend java.util.AbstractList the minimal implementation is often not optimal for the storage (for example the spliterator and the forEach constructs). The support for a JDK Collection may not have to add any additional methods for processing. It would merely replace using ArrayList. Numerical processing of complex numbers could be added instead to a more focussed data structure that does not support the entire Collection API, i.e. the vector and matrix concepts previously proposed. > > > Do we have one use case for the "list" feature? > > I see there a lot factory methods that seem to defeat the > > intended purpose (AFAIU Matt's remark) of letting the caller > > decide on the input format. > > Similarly, the "parse" feature should be left to the code that > > handles the input. IOW shouldn't we separate the concerns > > of converting the input (array, stream, list of strings, ...) from > > what can be done with a "list" instance? > > Since the lists can have different underlying data storage implementations > such as > a) single double primitive array or DoubleBuffer in interleaved format > b) single double primitive array or DoubleBuffer in sub array format > c) separate arrays/DoubleBuffers for real and imaginary parts > > Based on earlier discussions, Alex wanted the iteration logic over the list > to apply the operators to be within the List implementation > So each implementation will have its own implementation of operators that > is optimal for its data storage > > For now, should we focus on more than 1 implementation? If it is just 1 > implementation, which one can I pick up first? > 1 implementation is the best start point to build the API. > Should we have a common interface (minimum methods/operations that all > implementations should support)? > That makes sense. However a known backing format for the data will allow optimal computation. So once the API is established for a single data structure format we can test speed of computation when mixing backing data structures. > > If so, I can first focus on finalizing the List interface and then look at > implementations > > I was also looking at the EJML api's [1]. > They support three API styles a) Procedural b) SimpleMatrix and c) > Equations (Matlab style) > > It looks like we will be implementing the SimpleMatrix style. Should we > also consider other approaches? > Equations requires parsing text input. I would put that out-of-scope. I would say an OO style is the most natural from a Java perspective. The API could be similar to the matrix functionality in Commons Math. Alex
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hi, > I think that Alex's suggestion still holds: Better focus on one > task at a time. Are the "list" and "matrix" features related? OK, Will focus on list features first and focus on extending all existing methods on the Complex class to Lists. UnaryOperators will apply the operation (using refactored static methods) to each element. BinaryOperators for lists will have two variants. For the first variant, the second operand is a single complex number that is applied as second operand for all elements on List The second variant operates on two Lists. Can we look at this later? > Do we have one use case for the "list" feature? > I see there a lot factory methods that seem to defeat the > intended purpose (AFAIU Matt's remark) of letting the caller > decide on the input format. > Similarly, the "parse" feature should be left to the code that > handles the input. IOW shouldn't we separate the concerns > of converting the input (array, stream, list of strings, ...) from > what can be done with a "list" instance? Since the lists can have different underlying data storage implementations such as a) single double primitive array or DoubleBuffer in interleaved format b) single double primitive array or DoubleBuffer in sub array format c) separate arrays/DoubleBuffers for real and imaginary parts Based on earlier discussions, Alex wanted the iteration logic over the list to apply the operators to be within the List implementation So each implementation will have its own implementation of operators that is optimal for its data storage For now, should we focus on more than 1 implementation? If it is just 1 implementation, which one can I pick up first? Should we have a common interface (minimum methods/operations that all implementations should support)? If so, I can first focus on finalizing the List interface and then look at implementations I was also looking at the EJML api's [1]. They support three API styles a) Procedural b) SimpleMatrix and c) Equations (Matlab style) It looks like we will be implementing the SimpleMatrix style. Should we also consider other approaches? Thanks, Sumanth [1] http://ejml.org/wiki/index.php?title=Main_Page#:~:text=EJML%20has%20three,of%20writing%20equations On Fri, 29 Jul 2022 at 10:41, Gilles Sadowski wrote: > Hello. > > Le jeu. 28 juil. 2022 à 22:28, Sumanth Rajkumar > a écrit : > > > > Hi, > > > > I've completed the task of refactoring all complex operations to static > > functions and it has been merged to the complex-gsoc-2022 branch. Thank > you > > for all the help to make this happen. > > > > I wanted to talk about the next task and get some inputs from all of you > on > > how to start. > > > > Now, I'm going to be working on complex list and matrix support. I have > > already begun working on this which can be seen in my github branch [1]. > > > > Right now, my work is based on the idea of a mutable list representation > of > > a set of complex numbers (List) using a backing double[] for > > storage. > > > > I know Matt mentioned using Buffers as well and so I was hoping if you > can > > give a little more detail about this. If there are any other suggestions, > > please let me know. > > > > Thanks, > > > > Sumanth > > > > [1] > > > https://github.com/sumanth-rajkumar/commons-numbers/tree/NUMBERS-186.complex_list_and_matrix_support > > I think that Alex's suggestion still holds: Better focus on one > task at a time. Are the "list" and "matrix" features related? > > Do we have one use case for the "list" feature? > I see there a lot factory methods that seem to defeat the > intended purpose (AFAIU Matt's remark) of letting the caller > decide on the input format. > Similarly, the "parse" feature should be left to the code that > handles the input. IOW shouldn't we separate the concerns > of converting the input (array, stream, list of strings, ...) from > what can be done with a "list" instance? > > Do we target linear algebra for complex numbers? > What use-cases for the "ComplexMatrix" and "ComplexVector" > interfaces? > > Regards, > Gilles > > - > To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org > For additional commands, e-mail: dev-h...@commons.apache.org > >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hello. Le jeu. 28 juil. 2022 à 22:28, Sumanth Rajkumar a écrit : > > Hi, > > I've completed the task of refactoring all complex operations to static > functions and it has been merged to the complex-gsoc-2022 branch. Thank you > for all the help to make this happen. > > I wanted to talk about the next task and get some inputs from all of you on > how to start. > > Now, I'm going to be working on complex list and matrix support. I have > already begun working on this which can be seen in my github branch [1]. > > Right now, my work is based on the idea of a mutable list representation of > a set of complex numbers (List) using a backing double[] for > storage. > > I know Matt mentioned using Buffers as well and so I was hoping if you can > give a little more detail about this. If there are any other suggestions, > please let me know. > > Thanks, > > Sumanth > > [1] > https://github.com/sumanth-rajkumar/commons-numbers/tree/NUMBERS-186.complex_list_and_matrix_support I think that Alex's suggestion still holds: Better focus on one task at a time. Are the "list" and "matrix" features related? Do we have one use case for the "list" feature? I see there a lot factory methods that seem to defeat the intended purpose (AFAIU Matt's remark) of letting the caller decide on the input format. Similarly, the "parse" feature should be left to the code that handles the input. IOW shouldn't we separate the concerns of converting the input (array, stream, list of strings, ...) from what can be done with a "list" instance? Do we target linear algebra for complex numbers? What use-cases for the "ComplexMatrix" and "ComplexVector" interfaces? Regards, Gilles - To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hi, I've completed the task of refactoring all complex operations to static functions and it has been merged to the complex-gsoc-2022 branch. Thank you for all the help to make this happen. I wanted to talk about the next task and get some inputs from all of you on how to start. Now, I'm going to be working on complex list and matrix support. I have already begun working on this which can be seen in my github branch [1]. Right now, my work is based on the idea of a mutable list representation of a set of complex numbers (List) using a backing double[] for storage. I know Matt mentioned using Buffers as well and so I was hoping if you can give a little more detail about this. If there are any other suggestions, please let me know. Thanks, Sumanth [1] https://github.com/sumanth-rajkumar/commons-numbers/tree/NUMBERS-186.complex_list_and_matrix_support On Tue, 12 Jul 2022 at 10:03, Sumanth Rajkumar wrote: > Hi, > > I committed my changes to the test classes into the opened PR and I think > it ran the checks by itself without needing your approval. > > Please let me know if there's anything else I need to change. > > Thanks, > > Sumanth > > On Mon, Jul 11, 2022, 7:45 PM Alex Herbert > wrote: > >> On Mon, 11 Jul 2022 at 22:56, Gilles Sadowski >> wrote: >> >> > Le lun. 11 juil. 2022 à 20:03, Sumanth Rajkumar >> > a écrit : >> > > >> > > Hi, >> > > >> > > I have finished updating the test classes, but I am encountering a >> > problem >> > > in the ComplexEdgeCaseTest class. >> > > >> > > private static void assertComplex(double a, double b, >> > > String name, >> UnaryOperator >> > > operation, >> > > >> ComplexUnaryOperator >> > > operation2, >> > > double x, double y, long >> maxUlps) { >> > > } >> > > >> > > >> > > I added my ComplexUnaryOperator as a parameter and am getting the >> error >> > of >> > > having more than 7 parameters in this method. >> > > Is there anything I can do? >> > >> > Assuming that the error is raised by "CheckStyle" (?), this check can >> > be disabled >> > on a class by class basis in this configuration file: >> > src/main/resources/checkstyle/checkstyle-suppressions.xml >> > >> >> It may be a PMD error too [1]. The PMD error can be suppressed using the >> file: >> >> src/main/resources/pmd/pmd-ruleset.xml >> >> However in Numbers there is a checkstyle suppression for ParameterNumber >> but no suppressions for PMD for ExcessiveParameterList, so you may not >> need >> this. >> >> Alex >> >> [1] >> >> https://pmd.github.io/latest/pmd_rules_apex_design.html#excessiveparameterlist >> >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hi, I committed my changes to the test classes into the opened PR and I think it ran the checks by itself without needing your approval. Please let me know if there's anything else I need to change. Thanks, Sumanth On Mon, Jul 11, 2022, 7:45 PM Alex Herbert wrote: > On Mon, 11 Jul 2022 at 22:56, Gilles Sadowski > wrote: > > > Le lun. 11 juil. 2022 à 20:03, Sumanth Rajkumar > > a écrit : > > > > > > Hi, > > > > > > I have finished updating the test classes, but I am encountering a > > problem > > > in the ComplexEdgeCaseTest class. > > > > > > private static void assertComplex(double a, double b, > > > String name, > UnaryOperator > > > operation, > > > > ComplexUnaryOperator > > > operation2, > > > double x, double y, long > maxUlps) { > > > } > > > > > > > > > I added my ComplexUnaryOperator as a parameter and am getting the error > > of > > > having more than 7 parameters in this method. > > > Is there anything I can do? > > > > Assuming that the error is raised by "CheckStyle" (?), this check can > > be disabled > > on a class by class basis in this configuration file: > > src/main/resources/checkstyle/checkstyle-suppressions.xml > > > > It may be a PMD error too [1]. The PMD error can be suppressed using the > file: > > src/main/resources/pmd/pmd-ruleset.xml > > However in Numbers there is a checkstyle suppression for ParameterNumber > but no suppressions for PMD for ExcessiveParameterList, so you may not need > this. > > Alex > > [1] > > https://pmd.github.io/latest/pmd_rules_apex_design.html#excessiveparameterlist >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Mon, 11 Jul 2022 at 22:56, Gilles Sadowski wrote: > Le lun. 11 juil. 2022 à 20:03, Sumanth Rajkumar > a écrit : > > > > Hi, > > > > I have finished updating the test classes, but I am encountering a > problem > > in the ComplexEdgeCaseTest class. > > > > private static void assertComplex(double a, double b, > > String name, UnaryOperator > > operation, > > ComplexUnaryOperator > > operation2, > > double x, double y, long maxUlps) { > > } > > > > > > I added my ComplexUnaryOperator as a parameter and am getting the error > of > > having more than 7 parameters in this method. > > Is there anything I can do? > > Assuming that the error is raised by "CheckStyle" (?), this check can > be disabled > on a class by class basis in this configuration file: > src/main/resources/checkstyle/checkstyle-suppressions.xml > It may be a PMD error too [1]. The PMD error can be suppressed using the file: src/main/resources/pmd/pmd-ruleset.xml However in Numbers there is a checkstyle suppression for ParameterNumber but no suppressions for PMD for ExcessiveParameterList, so you may not need this. Alex [1] https://pmd.github.io/latest/pmd_rules_apex_design.html#excessiveparameterlist
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Le lun. 11 juil. 2022 à 20:03, Sumanth Rajkumar a écrit : > > Hi, > > I have finished updating the test classes, but I am encountering a problem > in the ComplexEdgeCaseTest class. > > private static void assertComplex(double a, double b, > String name, UnaryOperator > operation, > ComplexUnaryOperator > operation2, > double x, double y, long maxUlps) { > } > > > I added my ComplexUnaryOperator as a parameter and am getting the error of > having more than 7 parameters in this method. > Is there anything I can do? Assuming that the error is raised by "CheckStyle" (?), this check can be disabled on a class by class basis in this configuration file: src/main/resources/checkstyle/checkstyle-suppressions.xml Regards, Gilles > > [...] - To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hi, I have finished updating the test classes, but I am encountering a problem in the ComplexEdgeCaseTest class. private static void assertComplex(double a, double b, String name, UnaryOperator operation, ComplexUnaryOperator operation2, double x, double y, long maxUlps) { } I added my ComplexUnaryOperator as a parameter and am getting the error of having more than 7 parameters in this method. Is there anything I can do? Thanks, Sumanth On Tue, 5 Jul 2022 at 15:50, Sumanth Rajkumar wrote: > Thanks for the feedback Alex, > > > Not a problem. Just write a dedicated method for Complex and a generic > > method in ComplexFunctions. This small level of code duplication is > > acceptable where the efficiency of the method is greatly improved by > > rewriting it, as has been done for the scalar functions. > > For proj(), I had to take it out of ComplexFunctions for now to pass the > coverage checks, > but I have left the original code for proj() in the Complex class. > > > Why should I have to return a ComplexDouble? Since the ComplexConstructor > > is typed it makes more sense to have the methods that use it to also be > > typed. These methods should perform an operation that generates a real > and > > imaginary part. This is passed to the provided constructor. It should be > up > > to the provider of the constructor (i.e. the caller) to decide what to do > > with the result. By typing to ComplexDouble you are removing that > > flexibility. > > > However there is no requirement to specify what R is, allowing it to be > > Void. This also decouples the interface from Complex and ComplexDouble. > > Note that this may make ComplexDouble obsolete which would simplify the > > current changes. > > > I've not applied this change to your entire current diff so there may be > > some issues, for example with the scalar functions. I am interested to > see > > if this would work. > > So, I have made all interfaces typed and updated the method signatures > accordingly. > Please let me know if there are any problems with these changes. > > As for updating the test suite, I am currently working on that right now > and will let you know as soon as I am done. > > Thanks, > > Sumanth > > >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Thanks for the feedback Alex, > Not a problem. Just write a dedicated method for Complex and a generic > method in ComplexFunctions. This small level of code duplication is > acceptable where the efficiency of the method is greatly improved by > rewriting it, as has been done for the scalar functions. For proj(), I had to take it out of ComplexFunctions for now to pass the coverage checks, but I have left the original code for proj() in the Complex class. > Why should I have to return a ComplexDouble? Since the ComplexConstructor > is typed it makes more sense to have the methods that use it to also be > typed. These methods should perform an operation that generates a real and > imaginary part. This is passed to the provided constructor. It should be up > to the provider of the constructor (i.e. the caller) to decide what to do > with the result. By typing to ComplexDouble you are removing that > flexibility. > However there is no requirement to specify what R is, allowing it to be > Void. This also decouples the interface from Complex and ComplexDouble. > Note that this may make ComplexDouble obsolete which would simplify the > current changes. > I've not applied this change to your entire current diff so there may be > some issues, for example with the scalar functions. I am interested to see > if this would work. So, I have made all interfaces typed and updated the method signatures accordingly. Please let me know if there are any problems with these changes. As for updating the test suite, I am currently working on that right now and will let you know as soon as I am done. Thanks, Sumanth
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Mon, 4 Jul 2022 at 23:00, Sumanth Rajkumar wrote: > Thanks Alex for PR feedback. > I have incorporated the majority of the requested changes to the PR. > > I would like to discuss the remaining points here. > > > In > > commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexUnaryOperator.java: > > Note that by making this a default that creates an instance of Complex > you impose memory allocation overhead to any call site that just has the > real and imaginary parts (e.g. a structure storing a list of complex > numbers using primitive arrays). > > The ComplexDouble apply(ComplexDouble in, > ComplexConstructor out) method should be a default that > calls this function using the real and imaginary parts. > > The existing unit test for Complex Projection (proj) is expecting the > returned result to be the same as the passed input Complex instance except > for the isInfinite edge case. > This was the main reason for making the functional interface accept a > ComplexDouble instead of primitive real and imaginary parts. > Passing an existing unit test should not govern a design decision. The proj method will return the same number if it is not an infinite complex number. That is all that is required to pass the test, the input and output should have the exact same real and imaginary parts. Note that the Complex class is immutable so it can return itself. The test for object identity can be dropped in a generic case where the output is passed to the ComplexConstructor. > > The additional memory allocation for the input can be eliminated (for the > example of primitive array backed lists), by combining it with the > constructed result object. > We had decided to incur the overhead for the complex Constructor > result object in the context of functional compositions and thread safety > discussion before. > So, passing in a cursor iterator item (that captures the index) as both > ComplexDouble input and ComplexResult constructor should avoid any > additional overhead? > In this case yes. But in the case of usage outside of the complex package, for example if the raw real and imaginary arrays are created by a 2D FFT. At present I do not see a downside to the functional method being the separate arguments of real and imaginary primitives, other than it decouples the values and so is not encapsulated. Let's see what others think. > > If we decide to use primitive types for the functional interface, then we > cannot use it for the projection method. > Not a problem. Just write a dedicated method for Complex and a generic method in ComplexFunctions. This small level of code duplication is acceptable where the efficiency of the method is greatly improved by rewriting it, as has been done for the scalar functions. > > > > @FunctionalInterface > > public interface ComplexScalarFunction { > > > > ComplexDouble apply(ComplexDouble c, double f, > ComplexConstructor result); > > > > } > > This interface should be typed: the result is accepted by the > ComplexConstructor and this can be typed. > > > By typed, did you mean to make this a generic interface > ComplexScalarFunction > ? > ComplexUnaryOperator and ComplexBinaryOperator are not generic and > constrained to ComplexDouble types > Why should I have to return a ComplexDouble? Since the ComplexConstructor is typed it makes more sense to have the methods that use it to also be typed. These methods should perform an operation that generates a real and imaginary part. This is passed to the provided constructor. It should be up to the provider of the constructor (i.e. the caller) to decide what to do with the result. By typing to ComplexDouble you are removing that flexibility. ComplexUnaryOperator extends UnaryOperator I do not see what extending UnaryOperator provides. It constrains the interface to having to support composition imposed by Function. Note that composition can avoid the Complex constructor by directly chaining the output to the next input. Consider this simplification: public interface ComplexUnaryOperator { R apply(double r, double i, ComplexConstructor out); default ComplexUnaryOperator andThen(ComplexUnaryOperator after) { Objects.requireNonNull(after); return (r, i, out) -> apply(r, i, (x, y) -> after.apply(x, y, out)); } } public interface ComplexBinaryOperator { R apply(double r1, double i1, double r2, double i2, ComplexConstructor out); default ComplexBinaryOperator andThen(ComplexUnaryOperator after) { Objects.requireNonNull(after); return (r1, i1, r2, i2, out) -> apply(r1, i1, r2, i2, (x, y) -> after.apply(x, y, out)); } } Note that this has some differences from java.util.function during composition. In the generic case of java.util.function an object is returned. This is passed to the next function and may be changed to an object of a different type. So a composition of Function and Function becomes Function (via T -> R -> V). In the complex
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Thanks Alex for PR feedback. I have incorporated the majority of the requested changes to the PR. I would like to discuss the remaining points here. > In commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexUnaryOperator.java: > Note that by making this a default that creates an instance of Complex you impose memory allocation overhead to any call site that just has the real and imaginary parts (e.g. a structure storing a list of complex numbers using primitive arrays). > The ComplexDouble apply(ComplexDouble in, ComplexConstructor out) method should be a default that calls this function using the real and imaginary parts. The existing unit test for Complex Projection (proj) is expecting the returned result to be the same as the passed input Complex instance except for the isInfinite edge case. This was the main reason for making the functional interface accept a ComplexDouble instead of primitive real and imaginary parts. The additional memory allocation for the input can be eliminated (for the example of primitive array backed lists), by combining it with the constructed result object. We had decided to incur the overhead for the complex Constructor result object in the context of functional compositions and thread safety discussion before. So, passing in a cursor iterator item (that captures the index) as both ComplexDouble input and ComplexResult constructor should avoid any additional overhead? If we decide to use primitive types for the functional interface, then we cannot use it for the projection method. > @FunctionalInterface > public interface ComplexScalarFunction { > > ComplexDouble apply(ComplexDouble c, double f, ComplexConstructor result); > > } > This interface should be typed: the result is accepted by the ComplexConstructor and this can be typed. By typed, did you mean to make this a generic interface ComplexScalarFunction ? ComplexUnaryOperator and ComplexBinaryOperator are not generic and constrained to ComplexDouble types > It may be wise to update the test suite to ensure that all tests currently applied to Complex are applied to ComplexFunctions using a ComplexConstructor other than Complex, for example using a dummy implementation: > > class ComplexNumber implements ComplexConstructor { >// (r, i) members > >@Override >public ComplexNumber apply(double r, double i) { >// store (r, i) ... >return this; >} > } > >This will detect the edge cases all pass through to the input constructor to create the result. The test should assert the ComplexConstructor received the expected values. For now, shall I copy all the tests from the CStandardTest, CReferenceTest and ComplexEdgeCaseTest to ComplexFunctionsTest and modify it to use a dummy constructor? Also please note as mentioned above for the complex.proj method, currently we are not invoking the complex constructor for normal cases.
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hello. > > [...] > > I have raised PR #113 after rebasing to the master branch with Alex's > > checkstyle changes > > > > As per feedback, I have made the following changes > > a) Added javadoc comments > > b) Ensured test coverage > > c) Renamed accessors on the interface > > > > [...] > > > > > > > > In "DComplex", I propose that the accessors be named "real()" and > > > "imag()" (or just > > > "re()" and "im()"). ["DComplex" is not a very satisfying name either...] > > > > For the interface name, shall I change it to Complex64 from DComplex? > > > > In c the 'complex' keyword is a suffix: > > double complex c1; > float complex c2; > long double complex c3; > > In c++ the type is generic (and read as a suffix): > > complex c1; > complex c2; > > Either of these would be my preference over DComplex or Complex64. Just to be sure: Are we discussing this because "Complex" is already taken? > > > Are we sure that all this code needs to be part of the public API? > > > If not, I'd suggest limiting accessibility to "package-private". > > > > Are you referring to the static methods in ComplexFunctions and > > ComplexBiFunctions classes? > > I think they would need to be public for developers to be able to compose > > multiple operations... > > > > The static helper functions have been extracted to support all the ISO c99 > operations on the list structure of complex numbers. > > A list will ideally implement a generic foreach operation. So to apply a > single function only requires making the static functions public. The > alternative is to make the list expose all the ISO c99 operations in its > public API. > > To create a composite function that eventually writes back to the list can > be implemented by writing intermediate values to a result which is then > passed to the next operation. This can be satisfied by using the Complex > class. This already exposes all the ISO c99 functions. So perhaps it is not > required to make all the helper functions public for the purpose of > composing multiple operations. But it would be helpful for all the single > operations. > I may be one or more steps behind, sorry, but I still cannot figure out how the API is supposed to be applied (IOW, the "use cases"). I'm still at "provide functions that operate on a list of complex numbers". But the subsequent question: For what purpose? Some weeks ago (IIRC), I asked the same and whether the only use case was FFT... Regards, Gilles - To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Sun, 26 Jun 2022 at 20:52, Sumanth Rajkumar wrote: > Hi, > I have raised PR #113 after rebasing to the master branch with Alex's > checkstyle changes > > As per feedback, I have made the following changes > a) Added javadoc comments > b) Ensured test coverage > c) Renamed accessors on the interface > Thanks for the changes. Note that a new PR is not required. You can simply force push changes to the previous PR. It is covering the same subject. I've not yet fully read the PR. However the level of abstraction on some of the simple functions seems excessive. Many of the scalar operations using applyScalarFunction are one liners that have been abstracted to multiple layers of function references. Simple operations such as add, subtract, conjugate, negate, arg (defined as Math.atan2) may be better left alone. They can be duplicated into the complex functions class if the API is for public consumption but performance may be impacted by the abstraction. The code is definitely made less readable. Also note that you have some double empty lines which should be a single empty line and then some functions ending with } and no empty line after. These can be simply fixed using a regular expression to search for them. I note that some javadoc is missing for private methods. I have not set checkstyle to enforce this and the default scope is public. It should at least be protected, but my preference would be package. I will see if the rest of the project is OK for this and then update the rule. > > > > Gilles Sadowski wrote: > > In "DComplex", I propose that the accessors be named "real()" and > > "imag()" (or just > > "re()" and "im()"). ["DComplex" is not a very satisfying name either...] > > For the interface name, shall I change it to Complex64 from DComplex? > In c the 'complex' keyword is a suffix: double complex c1; float complex c2; long double complex c3; In c++ the type is generic (and read as a suffix): complex c1; complex c2; Either of these would be my preference over DComplex or Complex64. > > Are we sure that all this code needs to be part of the public API? > > If not, I'd suggest limiting accessibility to "package-private". > > Are you referring to the static methods in ComplexFunctions and > ComplexBiFunctions classes? > I think they would need to be public for developers to be able to compose > multiple operations... > The static helper functions have been extracted to support all the ISO c99 operations on the list structure of complex numbers. A list will ideally implement a generic foreach operation. So to apply a single function only requires making the static functions public. The alternative is to make the list expose all the ISO c99 operations in its public API. To create a composite function that eventually writes back to the list can be implemented by writing intermediate values to a result which is then passed to the next operation. This can be satisfied by using the Complex class. This already exposes all the ISO c99 functions. So perhaps it is not required to make all the helper functions public for the purpose of composing multiple operations. But it would be helpful for all the single operations. > > Thanks, > Sumanth > > PS: Noticed master branch unit test failures in numbers-fraction module > This has been fixed. Sorry for the mistake. Alex
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hi, I have raised PR #113 after rebasing to the master branch with Alex's checkstyle changes As per feedback, I have made the following changes a) Added javadoc comments b) Ensured test coverage c) Renamed accessors on the interface > Gilles Sadowski wrote: > In "DComplex", I propose that the accessors be named "real()" and > "imag()" (or just > "re()" and "im()"). ["DComplex" is not a very satisfying name either...] For the interface name, shall I change it to Complex64 from DComplex? > Are we sure that all this code needs to be part of the public API? > If not, I'd suggest limiting accessibility to "package-private". Are you referring to the static methods in ComplexFunctions and ComplexBiFunctions classes? I think they would need to be public for developers to be able to compose multiple operations... Thanks, Sumanth PS: Noticed master branch unit test failures in numbers-fraction module On Fri, 24 Jun 2022 at 19:43, Gilles Sadowski wrote: > Hello. > > Le ven. 24 juin 2022 à 16:59, Sumanth Rajkumar > a écrit : > > > > Hi Alex, Gilles, and Matt, > > > > I have raised a PR to the complex-gsoc-22 branch and it has been linked > to > > the NUMBERS-188 jira. > > One tenet of a project such as "Commons" is that everything must be > documented.[1] > For the Javadoc comments, please apply the same style as in other source > files. > > Formatting should also be taken care of (to help review, and future > maintenance).[2] > > Are we sure that all this code needs to be part of the public API? If > not, I'd suggest > limiting accessibility to "package-private". > > In "DComplex", I propose that the accessors be named "real()" and > "imag()" (or just > "re()" and "im()"). ["DComplex" is not a very satisfying name either...] > > Thanks, > Gilles > > [1] I'm a bit surprised that the build succeeds despite the missing > comments. > [2] E.g. one argument per line improves readability (IMHO). > > > > > [...] > > - > To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org > For additional commands, e-mail: dev-h...@commons.apache.org > >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Sat, 25 Jun 2022 at 10:07, Alex Herbert wrote: > > > Checkstyle: > Checkstyle plugin is configured to failOnViolation. So it is not > complaining about lack of comments. We are using the following rules: > > InvalidJavadocPosition,JavadocMethod,JavadocType,JavadocVariable,JavadocStyle > > So the failure of checkstyle to fail is strange. If I take an existing > file and make some formatting changes it fails the build. If I delete a tag > from the javadoc it fails the build. If I delete the entire javadoc then > this passes. So checkstyle checks the existing javadoc but does not fail > when javadoc is missing. This requires further investigation. > This requires extra checks: MissingJavadocMethod MissingJavadocPackage MissingJavadocType I will add these to our checkstyle configs and fix any failures (since these are scoped to private by default there may be some missing javadoc). See: http://checkstyle.sourceforge.net/config_javadoc.html
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Sat, 25 Jun 2022 at 00:43, Gilles Sadowski wrote: > > [1] I'm a bit surprised that the build succeeds despite the missing > comments. > So am I. There are a lot of warnings: Compilation has 2 warnings each about unchecked casts and unchecked method invocation. PMD: 115 warnings. This plugin is not set to fail on violation due to problems throughout the numbers build. But it does spot all the missing javadoc comments. Javadoc: 2 warnings for incorrect tags. This plugin could be configured to fail on warning. The default is failOnError=true and failOnWarning=false. I checked the rest of the project and there are no warnings. So I changed this to failOnWarning. Jacoco: Rule violations for classes covered and methods covered. But it does not fail the build. I checked the old travis profile and it did not set the build to fail when coverage is not met. The travis profile just submitted the report to coveralls. There is a note in the pom: false I have set this to true since we have met coverage goals across the rest of the numbers project. Note: The coverage report from codecov is not yet complete so has not been posted to the PR. It does show the drop in coverage: https://codecov.io/github/apache/commons-numbers/commit/203cbc6a505a1d004297115414b2188e21427219 Checkstyle: Checkstyle plugin is configured to failOnViolation. So it is not complaining about lack of comments. We are using the following rules: InvalidJavadocPosition,JavadocMethod,JavadocType,JavadocVariable,JavadocStyle So the failure of checkstyle to fail is strange. If I take an existing file and make some formatting changes it fails the build. If I delete a tag from the javadoc it fails the build. If I delete the entire javadoc then this passes. So checkstyle checks the existing javadoc but does not fail when javadoc is missing. This requires further investigation. You will have to rebase the PR on master to pick up the pom changes. Then run the default maven goal (in the complex module) and fix the issues. Alex
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hello. Le ven. 24 juin 2022 à 16:59, Sumanth Rajkumar a écrit : > > Hi Alex, Gilles, and Matt, > > I have raised a PR to the complex-gsoc-22 branch and it has been linked to > the NUMBERS-188 jira. One tenet of a project such as "Commons" is that everything must be documented.[1] For the Javadoc comments, please apply the same style as in other source files. Formatting should also be taken care of (to help review, and future maintenance).[2] Are we sure that all this code needs to be part of the public API? If not, I'd suggest limiting accessibility to "package-private". In "DComplex", I propose that the accessors be named "real()" and "imag()" (or just "re()" and "im()"). ["DComplex" is not a very satisfying name either...] Thanks, Gilles [1] I'm a bit surprised that the build succeeds despite the missing comments. [2] E.g. one argument per line improves readability (IMHO). > > [...] - To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
OK. I have approved the CI build to run on the PR. I will review when I have some more time. Alex On Fri, 24 Jun 2022 at 15:59, Sumanth Rajkumar wrote: > Hi Alex, Gilles, and Matt, > > I have raised a PR to the complex-gsoc-22 branch and it has been linked to > the NUMBERS-188 jira. > > While the PR is being reviewed, I will start working on NUMBERS-186 (adding > support for list and matrix of Complex numbers). > > Thanks, > Sumanth > > On Mon, 20 Jun 2022 at 09:43, Sumanth Rajkumar > > wrote: > > > Hello Gilles, > > Thanks! I will start a new thread for float support. > > > > Thanks > > Sumanth > > > > > > On Mon, Jun 20, 2022, 18:41 Gilles Sadowski wrote > > > >> > >> > Also, should we add support for float data type for complex numbers? > >> > >> In the "dev" ML, we customarily aim at focussing each discussion, > > > > > >> Thus could you please start a new thread with this question? > >> > > > > > > >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hi Alex, Gilles, and Matt, I have raised a PR to the complex-gsoc-22 branch and it has been linked to the NUMBERS-188 jira. While the PR is being reviewed, I will start working on NUMBERS-186 (adding support for list and matrix of Complex numbers). Thanks, Sumanth On Mon, 20 Jun 2022 at 09:43, Sumanth Rajkumar wrote: > Hello Gilles, > Thanks! I will start a new thread for float support. > > Thanks > Sumanth > > > On Mon, Jun 20, 2022, 18:41 Gilles Sadowski wrote > >> >> > Also, should we add support for float data type for complex numbers? >> >> In the "dev" ML, we customarily aim at focussing each discussion, > > >> Thus could you please start a new thread with this question? >> > > >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hello Gilles, Thanks! I will start a new thread for float support. Thanks Sumanth On Mon, Jun 20, 2022, 18:41 Gilles Sadowski wrote > > > Also, should we add support for float data type for complex numbers? > > In the "dev" ML, we customarily aim at focussing each discussion, > Thus could you please start a new thread with this question? >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hello Sumanth. Le lun. 20 juin 2022 à 07:05, Sumanth Rajkumar a écrit : > > [...] > > Also, should we add support for float data type for complex numbers? In the "dev" ML, we customarily aim at focussing each discussion, so that people can easily decide (ideally, from the "Subject:" line) if they want to voice some opinion. [This also improves searches in the ML archive.] Thus could you please start a new thread with this question? [Note that the relationships between all technical issues related to the extension of the functionalities around "Complex" is better managed through links between JIRA issues than by lengthy threads here.] Thanks, Gilles > > [...] - To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hi Alex, Matt, and Gilles, As discussed on the other thread, I have made NUMBERS-186 (for complex lists work) the child of a parent ticket (NUMBERS-187) I have created NUMBERS-188 for the functional interfaces and static method refactoring of the existing instance methods of Complex class. I hurt my shoulders over the weekend and have been advised few days rest. I expect to have the PR for NUMBERS-188 ready for review by Thursday. Also, should we add support for float data type for complex numbers? If yes, should we reuse static functions that operate on double types and use Java float-double widening and narrowing conversions? https://docs.oracle.com/javase/specs/jls/se10/html/jls-5.html#jls-5.1.2 If no, should we have separate static complex functions for float types? I can raise a ticket for supporting float types based on feedback. Thanks, Sumanth On Thu, 16 Jun 2022 at 08:11, Sumanth Rajkumar wrote: > > EjML functional interface looks like this > > > > void apply(ComplexDouble in, MutableComplexDouble out) > > > Similar to the mutable cursor idea we have been discussing. The Mutable > object could be an interface? > > Ok > > We may need to have more than one implementation of the underlying storage. > Using interleaved real and imaginary will be more efficient for computation > on a single number due to cache reads from memory. But the separate arrays > are going to be useful when writing code with the vector API that requires > extracting blocks of real or imaginary components. > > Ok > > > > > > > > I am still wondering how these functions can be composed. Here are a few > > ideas > > > > This may need more work.. > > > > ComplexResultInterceptor class > > It does require a lot of code that may have a far bigger overhead impact > than just creating a complex result. > > > > > I think the overhead of creating the Complex objects for the intermediates > may be lower than a solution that tries to avoid allocation overhead with > complexity of ThreadLocal. A performance benchmark would be able to > determine this so we can look at that in the future. > > > Ok. Will extend java functions and create complex objects for > intermediate results > > > It may be useful here to create a branch in the numbers repository for all > the changes. To keep it simple perhaps a 'develop' branch can be used that > you can make your changes against. > > > Ok. > I can raise a PR to develop with the above changes. I will follow Alex's > latest update to the Developer Guide for pull requests. > > > Thanks, > > Sumanth > > > On Wed, 15 Jun 2022 at 13:58, Alex Herbert > wrote: > >> On Wed, 15 Jun 2022 at 17:38, Sumanth Rajkumar < >> rajkumar.suma...@gmail.com> >> wrote: >> >> > Hi Alex, >> > >> > What do you intend to support as a "Matrix"? Is it for 2D or ND? What >> > functionality already exists for complex matrix operations such as add >> and >> > multiply in for example EJML? >> > >> > This may require some expansion. >> > >> > a) I reviewed EJML data naming conventions, this is what they follow: >> > >> > >> > >> https://github.com/lessthanoptimal/ejml#procedural-api-matrix-and-class-names >> > Should we follow this approach as well? >> >I wasn't thinking about implementing ND right now, maybe I can during >> > Phase 2? >> > >> >> OK. >> >> >> > >> > b) EJML only supports 2D matrices with vector (1XN) being a special >> case, >> > should I do that too? >> > >> >> OK. >> >> >> > >> > c) EJML uses a mutable ComplexResult, they use a single mutable class >> for >> > both input and output and return void >> > >> > Here is the link to their implementation: >> > >> > >> > >> https://github.com/lessthanoptimal/ejml/blob/SNAPSHOT/main/ejml-core/src/org/ejml/ops/ComplexMath_F64.java >> > >> > Their functional interface looks like this >> > >> > void apply(ComplexDouble in, MutableComplexDouble out) >> > >> >> Similar to the mutable cursor idea we have been discussing. The Mutable >> object could be an interface? >> >> >> > >> > d) For dense Matrix internal storage, I'm planning on using separate >> arrays >> > (or a single array where the first half of the array will be real and >> the >> > second half will be imaginary) instead of alternating real and imaginary >> > because it allows us to optimize space for pure imaginary or real >> matrices. >> > >> > Is that ok? >> > >> >> We may need to have more than one implementation of the underlying >> storage. >> Using interleaved real and imaginary will be more efficient for >> computation >> on a single number due to cache reads from memory. But the separate arrays >> are going to be useful when writing code with the vector API that requires >> extracting blocks of real or imaginary components. >> >> >> > >> > >> > I am still wondering how these functions can be composed. Here are a few >> > ideas >> > >> > >> > This may need more work.. >> > >> > >> > I have provided an approach below using an intermediate >> > ComplexResultInterceptor
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
> EjML functional interface looks like this > > void apply(ComplexDouble in, MutableComplexDouble out) > Similar to the mutable cursor idea we have been discussing. The Mutable object could be an interface? Ok We may need to have more than one implementation of the underlying storage. Using interleaved real and imaginary will be more efficient for computation on a single number due to cache reads from memory. But the separate arrays are going to be useful when writing code with the vector API that requires extracting blocks of real or imaginary components. Ok > > > I am still wondering how these functions can be composed. Here are a few > ideas > > This may need more work.. > ComplexResultInterceptor class It does require a lot of code that may have a far bigger overhead impact than just creating a complex result. I think the overhead of creating the Complex objects for the intermediates may be lower than a solution that tries to avoid allocation overhead with complexity of ThreadLocal. A performance benchmark would be able to determine this so we can look at that in the future. Ok. Will extend java functions and create complex objects for intermediate results It may be useful here to create a branch in the numbers repository for all the changes. To keep it simple perhaps a 'develop' branch can be used that you can make your changes against. Ok. I can raise a PR to develop with the above changes. I will follow Alex's latest update to the Developer Guide for pull requests. Thanks, Sumanth On Wed, 15 Jun 2022 at 13:58, Alex Herbert wrote: > On Wed, 15 Jun 2022 at 17:38, Sumanth Rajkumar > > wrote: > > > Hi Alex, > > > > What do you intend to support as a "Matrix"? Is it for 2D or ND? What > > functionality already exists for complex matrix operations such as add > and > > multiply in for example EJML? > > > > This may require some expansion. > > > > a) I reviewed EJML data naming conventions, this is what they follow: > > > > > > > https://github.com/lessthanoptimal/ejml#procedural-api-matrix-and-class-names > > Should we follow this approach as well? > >I wasn't thinking about implementing ND right now, maybe I can during > > Phase 2? > > > > OK. > > > > > > b) EJML only supports 2D matrices with vector (1XN) being a special case, > > should I do that too? > > > > OK. > > > > > > c) EJML uses a mutable ComplexResult, they use a single mutable class for > > both input and output and return void > > > > Here is the link to their implementation: > > > > > > > https://github.com/lessthanoptimal/ejml/blob/SNAPSHOT/main/ejml-core/src/org/ejml/ops/ComplexMath_F64.java > > > > Their functional interface looks like this > > > > void apply(ComplexDouble in, MutableComplexDouble out) > > > > Similar to the mutable cursor idea we have been discussing. The Mutable > object could be an interface? > > > > > > d) For dense Matrix internal storage, I'm planning on using separate > arrays > > (or a single array where the first half of the array will be real and the > > second half will be imaginary) instead of alternating real and imaginary > > because it allows us to optimize space for pure imaginary or real > matrices. > > > > Is that ok? > > > > We may need to have more than one implementation of the underlying storage. > Using interleaved real and imaginary will be more efficient for computation > on a single number due to cache reads from memory. But the separate arrays > are going to be useful when writing code with the vector API that requires > extracting blocks of real or imaginary components. > > > > > > > > I am still wondering how these functions can be composed. Here are a few > > ideas > > > > > > This may need more work.. > > > > > > I have provided an approach below using an intermediate > > ComplexResultInterceptor class that is thread-safe and minimizes object > > creation using thread local and stacks. It also doesn't require > > ComplexDouble constraint for the generic R result type. > > > > It does require a lot of code that may have a far bigger overhead impact > than just creating a complex result. > > Since thread safety requires an intermediate be stored then it may make > more sense to expand the API to allow operations on a list using a unary > operator of complex: > > UnaryOperator op; > > You can then create your function to work on a complex number and chain > them together using the standard java 8 functions. This could be supported > for the ISO c99 functions by just using Complex. Unfortunately this does > not work as the UnaryOperator has not overridden andThen and compose for > the single argument. This is valid: > > UnaryOperator op = Complex::sqrt; > // These compose to Function > Function op2 = op.andThen(Complex::conj); > Function op3 = op.compose(Complex::conj); > > // Invalid to assign back to UnaryOperator > op = op.andThen(Complex::conj); > // OK with a cast > op = (UnaryOperator) op.andThen(Complex::conj); > > // In use: >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Wed, 15 Jun 2022 at 17:38, Sumanth Rajkumar wrote: > Hi Alex, > > What do you intend to support as a "Matrix"? Is it for 2D or ND? What > functionality already exists for complex matrix operations such as add and > multiply in for example EJML? > > This may require some expansion. > > a) I reviewed EJML data naming conventions, this is what they follow: > > > https://github.com/lessthanoptimal/ejml#procedural-api-matrix-and-class-names > Should we follow this approach as well? >I wasn't thinking about implementing ND right now, maybe I can during > Phase 2? > OK. > > b) EJML only supports 2D matrices with vector (1XN) being a special case, > should I do that too? > OK. > > c) EJML uses a mutable ComplexResult, they use a single mutable class for > both input and output and return void > > Here is the link to their implementation: > > > https://github.com/lessthanoptimal/ejml/blob/SNAPSHOT/main/ejml-core/src/org/ejml/ops/ComplexMath_F64.java > > Their functional interface looks like this > > void apply(ComplexDouble in, MutableComplexDouble out) > Similar to the mutable cursor idea we have been discussing. The Mutable object could be an interface? > > d) For dense Matrix internal storage, I'm planning on using separate arrays > (or a single array where the first half of the array will be real and the > second half will be imaginary) instead of alternating real and imaginary > because it allows us to optimize space for pure imaginary or real matrices. > > Is that ok? > We may need to have more than one implementation of the underlying storage. Using interleaved real and imaginary will be more efficient for computation on a single number due to cache reads from memory. But the separate arrays are going to be useful when writing code with the vector API that requires extracting blocks of real or imaginary components. > > > I am still wondering how these functions can be composed. Here are a few > ideas > > > This may need more work.. > > > I have provided an approach below using an intermediate > ComplexResultInterceptor class that is thread-safe and minimizes object > creation using thread local and stacks. It also doesn't require > ComplexDouble constraint for the generic R result type. > It does require a lot of code that may have a far bigger overhead impact than just creating a complex result. Since thread safety requires an intermediate be stored then it may make more sense to expand the API to allow operations on a list using a unary operator of complex: UnaryOperator op; You can then create your function to work on a complex number and chain them together using the standard java 8 functions. This could be supported for the ISO c99 functions by just using Complex. Unfortunately this does not work as the UnaryOperator has not overridden andThen and compose for the single argument. This is valid: UnaryOperator op = Complex::sqrt; // These compose to Function Function op2 = op.andThen(Complex::conj); Function op3 = op.compose(Complex::conj); // Invalid to assign back to UnaryOperator op = op.andThen(Complex::conj); // OK with a cast op = (UnaryOperator) op.andThen(Complex::conj); // In use: // op could be declared as a UnaryOperator or Function to just use the JDK functions as is with full support for chaining. list.forEach(op); To avoid the cast you can extend Function to add e.g. default UnaryOperator andThen(UnaryOperator after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } I do not know why the JDK has not done this. It seems to compile on my machine but I've not tested it. I think the overhead of creating the Complex objects for the intermediates may be lower than a solution that tries to avoid allocation overhead with complexity of ThreadLocal. A performance benchmark would be able to determine this so we can look at that in the future. > I'm working on this right now, I've refactored most of the existing > instance methods and I should be done by tomorrow > OK. It may be useful here to create a branch in the numbers repository for all the changes. To keep it simple perhaps a 'develop' branch can be used that you can make your changes against. Alex
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hi Alex, What do you intend to support as a "Matrix"? Is it for 2D or ND? What functionality already exists for complex matrix operations such as add and multiply in for example EJML? This may require some expansion. a) I reviewed EJML data naming conventions, this is what they follow: https://github.com/lessthanoptimal/ejml#procedural-api-matrix-and-class-names Should we follow this approach as well? I wasn't thinking about implementing ND right now, maybe I can during Phase 2? b) EJML only supports 2D matrices with vector (1XN) being a special case, should I do that too? c) EJML uses a mutable ComplexResult, they use a single mutable class for both input and output and return void Here is the link to their implementation: https://github.com/lessthanoptimal/ejml/blob/SNAPSHOT/main/ejml-core/src/org/ejml/ops/ComplexMath_F64.java Their functional interface looks like this void apply(ComplexDouble in, MutableComplexDouble out) d) For dense Matrix internal storage, I'm planning on using separate arrays (or a single array where the first half of the array will be real and the second half will be imaginary) instead of alternating real and imaginary because it allows us to optimize space for pure imaginary or real matrices. Is that ok? I am still wondering how these functions can be composed. Here are a few ideas This may need more work.. I have provided an approach below using an intermediate ComplexResultInterceptor class that is thread-safe and minimizes object creation using thread local and stacks. It also doesn't require ComplexDouble constraint for the generic R result type. @FunctionalInterface public interface ComplexFunction { default R apply(Complex c, ComplexResult result) { return apply(c.real(), c.imag(), result); } R apply(double r, double i, ComplexResult result); default ComplexFunction thenApply(ComplexFunction afterFunction) { return (x, y, afterResult) -> { ComplexResultInterceptor interceptor = ComplexResultInterceptor.TLOCAL_ResultInterceptor.get(); interceptor.pushResultProvider(afterFunction, afterResult); apply(x, y, interceptor); return interceptor.popResult(); }; } } public class ComplexResultInterceptor implements ComplexResult { private Stack> afterResultProviderStack = new Stack<>(); private Stack> afterFunctionStack= new Stack<>(); private Stack afterResult = new Stack<>(); public static final ThreadLocal TLOCAL_ResultInterceptor = ThreadLocal.withInitial(() -> new ComplexResultInterceptor()); private static final AtomicLong counter = new AtomicLong(); private ComplexResultInterceptor() { System.out.println("Allocating ComplexResultInterceptor # " + counter.incrementAndGet()); } public void pushResultProvider(ComplexFunction func, ComplexResult provider) { afterFunctionStack.push(func); afterResultProviderStack.push(provider); } @Override public R apply(double r, double i) { ComplexFunction after = afterFunctionStack.pop(); ComplexResult resultProvider = afterResultProviderStack.pop(); afterResult.push(after.apply(r, i, resultProvider)); return null; } public U popResult() { return (U) afterResult.pop(); } } Here is a link to the unit test class that ran successfully and the ComplexResultInterceptor class: https://github.com/sumanth-rajkumar/commons-numbers/blob/sumanth-gsoc-22-array_refactor/commons-numbers-complex/src/test/java/org/apache/commons/numbers/complex/ComplexComposeTest.java https://github.com/sumanth-rajkumar/commons-numbers/blob/sumanth-gsoc-22-array_refactor/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexResultInterceptor.java > 4) Refactor existing instance methods in Complex class as static functions > in ComplexDoubleFunctions class using functional interface signatures > I would start with this. It can always be updated if the functional interface is later modified. I'm working on this right now, I've refactored most of the existing instance methods and I should be done by tomorrow Thanks, Sumanth On Mon, 13 Jun 2022 at 06:26, Alex Herbert wrote: > On Mon, 13 Jun 2022 at 07:47, Sumanth Rajkumar > > wrote: > > > > > > > For Phase 1, I propose to do the following > > > > > > 1) Introduce ComplexDouble, ComplexDoubleVector and ComplexDoubleMatrix > > interfaces > > > > What do you intend to support as a "Matrix"? Is it for 2D or ND? What > functionality already exists for complex matrix operations such as add and > multiply in for example EJML? > > This may require some expansion. > > > > The interfaces to have methods for applying below unary and binary > > double functions > > The interfaces to have methods to convert to/from primitive double > > arrays (both separate arrays for real/imaginary and single interleaved > > array) > > The interfaces to
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Mon, 13 Jun 2022 at 07:47, Sumanth Rajkumar wrote: > > > For Phase 1, I propose to do the following > > > 1) Introduce ComplexDouble, ComplexDoubleVector and ComplexDoubleMatrix > interfaces > What do you intend to support as a "Matrix"? Is it for 2D or ND? What functionality already exists for complex matrix operations such as add and multiply in for example EJML? This may require some expansion. > The interfaces to have methods for applying below unary and binary > double functions > The interfaces to have methods to convert to/from primitive double > arrays (both separate arrays for real/imaginary and single interleaved > array) > The interfaces to have methods to convert to/from DoubleBuffer (both > separate arrays for real/imaginary and single interleaved buffer) > > 2) Introduce generic (item based) functional interfaces for unary and > binary double functions > > @FunctionalInterface > public interface ComplexDoubleFunction { > > R apply(double real, double imaginary, ComplexDoubleResult result); > } > > @FunctionalInterface > public interface ComplexDoubleBiFunction { > > R apply(double real1, double imaginary1, double real2, double imaginary2, > ComplexDoubleResult result); > } > > @FunctionalInterface > public interface ComplexDoubleResult { > > R apply(double r, double i); > > } > > I am still wondering how these functions can be composed. Here are a few ideas based on requiring that the functional interface generic type is a ComplexDouble. This allows the result single item R to be decomposed again into real and imaginary parts to pass to the next method. public static R conj(double r, double i, ComplexResult result) { return result.apply(r, -i); } public static R multiplyImaginary(double r, double i, ComplexResult result) { return result.apply(-i, r); } @FunctionalInterface public interface ComplexDoubleFunction { default R apply(ComplexDouble c, ComplexResult result) { return apply(c.real(), c.imag(), result); } R apply(double r, double i, ComplexResult result); default ComplexDoubleFunction andThen(ComplexDoubleFunction after, ComplexResult intermediateResult) { Objects.requireNonNull(after); // Requires the intermediate which would be the terminal result if the function is not composed. return (r, i, result) -> after.apply(apply(r, i, intermediateResult), result); } default ComplexDoubleFunction andThen2(ComplexDoubleFunction after) { Objects.requireNonNull(after); return (re, im, result) -> { // Fabricate the intermediate. Function is not thread safe. double[] parts = {0, 0}; ComplexResult intermediateResult = (x, y) -> { parts[0] = x; parts[1] = y; return null; }; R t = apply(re, im, intermediateResult); return after.apply(t, result); }; } default ComplexDoubleFunction andThen(ComplexDoubleFunction after) { Objects.requireNonNull(after); // Thread safe. The intermediate is also the terminal result. This is not optimal if the intermediate/terminal is a list with inefficient read/write to the current position. return (r, i, result) -> after.apply(apply(r, i, result), result); } } public static void example() { ComplexDoubleFunction fun = ComplexDoubleFunctions::conj; ComplexDoubleFunction fun2 = ComplexDoubleFunctions::multiplyImaginary; ComplexDoubleFunction fun3 = ComplexDoubleFunctions::multiplyImaginary; // Not allowed as Void does not extend ComplexDouble //ComplexDoubleFunction fun4 = ComplexDoubleFunctions::multiplyImaginary; ComplexDoubleFunction funA = fun.andThen(fun2); // Not allowed //ComplexDoubleFunction funA2 = fun.andThen(fun2); ComplexDoubleFunction funB = fun.andThen2(fun3); ComplexDoubleFunction funC = fun.andThen(fun3, Complex::ofCartesian); } However you cannot create a ComplexDoubleFunction which will not return a result as the interface is typed to ComplexDouble. Not returning a final result is the usage required by list operations that do not return results but write back to storage in ComplexResult. Composite function requires an intermediate to hold the result to pass to the next function. If this is the same object then the function will not be thread-safe. This may need more work... > 4) Refactor existing instance methods in Complex class as static functions > in ComplexDoubleFunctions class using functional interface signatures > I would start with this. It can always be updated if the functional interface is later modified. Alex
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Thanks Alex for the detailed feedback. As GSOC Phase 1 has started, for the existing C99 complex functions in Complex class, I will refactor using the item based functional interface approach. I can look at a Range based approach later if I have time. As you mentioned the C99 functions cannot take advantage of the limited Java 16 Vector API features. However, it may be possible to speed up C99 functions using GPUs based on quick look at documentation here https://aparapi.com/introduction/getting-started.html https://aparapi.com/documentation/kernel-guidelines.html https://aparapi.com/documentation/aparapi-patterns.html https://git.qoto.org/aparapi/aparapi-examples/-/blob/master/examples/movie/src/com/amd/aparapi/examples/movie/AparapiSolution.java For Phase 1, I propose to do the following 1) Introduce ComplexDouble, ComplexDoubleVector and ComplexDoubleMatrix interfaces The interfaces to have methods for applying below unary and binary double functions The interfaces to have methods to convert to/from primitive double arrays (both separate arrays for real/imaginary and single interleaved array) The interfaces to have methods to convert to/from DoubleBuffer (both separate arrays for real/imaginary and single interleaved buffer) 2) Introduce generic (item based) functional interfaces for unary and binary double functions @FunctionalInterface public interface ComplexDoubleFunction { R apply(double real, double imaginary, ComplexDoubleResult result); } @FunctionalInterface public interface ComplexDoubleBiFunction { R apply(double real1, double imaginary1, double real2, double imaginary2, ComplexDoubleResult result); } @FunctionalInterface public interface ComplexDoubleResult { R apply(double r, double i); } 3) Add ComplexDouble interface to Complex class. Add ComplexDoubleVectorImpl (primitive double array backing) implementation for ComplexDoubleVector interface Add ComplexDoubleMatrixImpl (primitive double array backing) implementation for ComplexDoubleMatrix interface 4) Refactor existing instance methods in Complex class as static functions in ComplexDoubleFunctions class using functional interface signatures 5) Add concurrency support for operations on Vector and Matrix objects interface ComplexDoubleVector { default ComplexDoubleVector apply(ComplexDoubleFunction function) { return apply(function, 0, size(), 1); } default ComplexDoubleVector apply(ComplexDoubleFunction function, int concurrency) { return apply(function, 0, size(), 1); } ComplexDoubleVector apply(ComplexDoubleFunction function, int start, int length, int concurrency) } ComplexDoubleMatrixImpl and ComplexDoubleVectorImpl implement concurrency (if concurrency > 1) by partitioning the data and execute using fork join thread pool (No use of streams) 6) Unit tests for Vector and Matrix implementations Let me know if you need anything else or reduce the scope for phase 1 Thanks Sumanth On Sun, 12 Jun 2022 at 20:08, Alex Herbert wrote: > On Sun, 12 Jun 2022 at 16:55, Sumanth Rajkumar > > wrote: > > > > > > > I have provided both approaches. Functional interfaces that operate on > > single complex and on Arrays > > > > Thanks for the examples. > > > > <-- SNIP --> > > > > Here the implementation including iteration/cursors has moved to the > > array based Lambda. > > For Complex arrays, I think it is beneficial to move the iteration > logic > > from data storage (ComplexList) to the Lambda (ComplexFunctions::conj) > > > > Possible mix up between lambda and method reference? I certainly would not > want to write a lambda function (anonymous method) that is responsible for > iteration; I would stick to providing a simple unary operator that can be > passed to a list to act on each member. > > Re: Iteration logic in the array method. I am not sure about this. If the > underlying data is not linear (e.g. a 2D double[][]) then performing a > range based method on it may not be optimal. It should be up to the > implementation to decide the optimal iteration over the underlying data, > possibly specialising a spliterator to split based on stripes of the > underlying data. > > Anyway, this set of examples for item-based or range-based approaches > confers no benefit to the range based approach. It just does a potentially > sub-optimal iteration of a unary operator on each item. But this is due to > the example not being a true range based operation. I think the range based > API should be based around operations that require access to more than one > element in the range in order to function. For example this would be > transform operations. > > All the other examples we have act on single complex numbers. In this case > an operator is provided to act on the complex and create a complex result. > This can be passed to the container which will optimally iterate over the > data, or sub-range of, and apply the operation. > > One issue is parallelisation using a stream. By
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Sun, 12 Jun 2022 at 16:55, Sumanth Rajkumar wrote: > > > I have provided both approaches. Functional interfaces that operate on > single complex and on Arrays > Thanks for the examples. > <-- SNIP --> > > Here the implementation including iteration/cursors has moved to the > array based Lambda. > For Complex arrays, I think it is beneficial to move the iteration logic > from data storage (ComplexList) to the Lambda (ComplexFunctions::conj) > Possible mix up between lambda and method reference? I certainly would not want to write a lambda function (anonymous method) that is responsible for iteration; I would stick to providing a simple unary operator that can be passed to a list to act on each member. Re: Iteration logic in the array method. I am not sure about this. If the underlying data is not linear (e.g. a 2D double[][]) then performing a range based method on it may not be optimal. It should be up to the implementation to decide the optimal iteration over the underlying data, possibly specialising a spliterator to split based on stripes of the underlying data. Anyway, this set of examples for item-based or range-based approaches confers no benefit to the range based approach. It just does a potentially sub-optimal iteration of a unary operator on each item. But this is due to the example not being a true range based operation. I think the range based API should be based around operations that require access to more than one element in the range in order to function. For example this would be transform operations. All the other examples we have act on single complex numbers. In this case an operator is provided to act on the complex and create a complex result. This can be passed to the container which will optimally iterate over the data, or sub-range of, and apply the operation. One issue is parallelisation using a stream. By its nature the stream acts on single items; the results are then collated at the end. The stream does not hold indices for each item. So you cannot use a terminal foreach() method on each sub-range created by splitting and write back to the original storage. The stream would have to be declared as ordered to maintain the original order for the output and this can be collated at the end to new storage. To use the stream API with a parallel implementation and zero-allocation for the terminal operation would require the stream contains an item that allows read and write. So you can use ComplexDoubleArray: Stream s; Consumer op; s.forEach(op); Here the operator has to have an array that knows its start and length. This would be more like a buffer. Each terminal forEach would require a different instance of ComplexDoubleArray that holds its own start and length. These may be accessed directly or via an iterator that provides read and write to each element in the range. The ComplexDoubleArray can wrap the same underlying data so the only allocation is the object in the stream wrapping the data and a range to act on. This would be N objects allocated equal to the number of threads. Then you write a function that accepts a ComplexDoubleArray and writes back to the same array. I do not see how this is any better than streaming a mutable complex: Stream s; Consumer op; s.forEach(op); ComplexNumber simply has read/write for real and imaginary parts and your operator can do what it requires. Here ComplexNumber is some object allocated once in the forEach method that acts as a cursor over the underlying data. However the stream examples can be misused. The ultimate method can accept the stream objects and use them for something else. For example the ComplexDoubleArray covering part of the range can then be added to (assuming the ComplexDoubleArray is also a List). So the sub-range should be a correct subList implementation. The ComplexNumber cursor could be added to a List which would have many entries but ultimately only N actual numbers (N=parallel threads) if the ComplexNumber was a recycled cursor object. So the specialised stream methods should not be public. Instead you could create your operators using factory methods. Here are examples for single-thread and parallel implementation. The parallel implementation uses the stream API to efficiently divide the range. public class ComplexFunctions { public static ComplexDoubleUnaryOperator create(ComplexFunction operator) { return new ComplexDoubleUnaryOperator() { @Override public ComplexDoubleArray apply(ComplexDoubleArray input, ComplexDoubleArray result) { for (int i = 0; i < input.size(); i++) { final int index = i; ComplexDouble c = input.get(i); operator.apply(c.real(), c.imag(), (re, im) -> { result.setValue(index, re, im); return null; }); } return result; } }; }
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
> > > Some thoughts: > > - an array should be mutable by default. It would be made immutable using a > Collections.immutableX(...) type wrapper. > - an array should have get and set methods for complex, real and imaginary > using an index within the array size. > Ok The last two requirements bring us back to the requirement for a generic > way to write the result of a complex number computation (i.e. a single > [real, imaginary] pair). > I have provided both approaches. Functional interfaces that operate on single complex and on Arrays Source available here https://github.com/sumanth-rajkumar/commons-numbers/tree/98fbedeb7ed3e99597f461d88856b4d94c53343d/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex I have summarized the approaches below 1) Functional interfaces Single Pair Approach @FunctionalInterface public interface ComplexFunction { R apply(double r, double i, ComplexResult result); } @FunctionalInterface public interface ComplexResult { R apply(double r, double i); } Array Approach @FunctionalInterface public interface ComplexDoubleUnaryOperator { ComplexDoubleArray apply(ComplexDoubleArray input, ComplexDoubleArray result); } @FunctionalInterface public interface ComplexArrayResult { R set(int index, double r, double i); } interface ComplexDoubleArray extends Iterable, ComplexArrayResult { ... } 2) Implementation for conjugate example in ComplexFunctions https://github.com/sumanth-rajkumar/commons-numbers/blob/98fbedeb7ed3e99597f461d88856b4d94c53343d/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexFunctions.java#L779 Single Pair Approach public static R conj(double r, double i, ComplexResult result) { return result.apply(r, -i); } Array Approach (the implementation below can be different in ComplexParallelFunctions for example) public static ComplexDoubleArray conj(ComplexDoubleArray input, ComplexDoubleArray out) { final int len = input.size(); for (int i = 0; i < len; i++) { ComplexDouble c = input.get(i); out = arrayConj(c.real(), c.imag(), out, i); } return out; } public static ComplexDoubleArray arrayConj(double r, double i, ComplexArrayResult resultConsumer, int index) { return resultConsumer.set(index, r, -i); } 3) Usage of conj in Complex class https://github.com/sumanth-rajkumar/commons-numbers/blob/98fbedeb7ed3e99597f461d88856b4d94c53343d/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java#L1127 Single Pair Approach Complex implements Serializable, ComplexDouble { public Complex conj() { return this.applyUnaryOperator(ComplexFunctions::conj); } public Complex applyUnaryOperator(ComplexFunction operator) { return operator.apply(this.real, this.imaginary, Complex::ofCartesian); } } Array Approach Complex implements Serializable, ComplexDoubleArray, ComplexDouble { public Complex conj() { return this.apply(ComplexFunctions::conj); } } 4) Usage of conj in ComplexList (implements ComplexDoubleArray) Single Pair Approach ComplexList { public ComplexList conj() { return this.forEach(ComplexFunctions::conj); } public ComplexList forEach(ComplexFunction operator) { . . . Cursor cursor = new Cursor(..); for (int i = 0; i < len; i++) { cursor.setIndex(i); operator.apply(cursor.getReal(), cursor.getImginary(), cursor); } } private final class Cursor implements ComplexDouble, ComplexResult { . . . } } Array Approach ComplexList implements ComplexDoubleArray { public ComplexList conj() { return this.apply(ComplexFunctions::conj); } } Here the implementation including iteration/cursors has moved to the array based Lambda. For Complex arrays, I think it is beneficial to move the iteration logic from data storage (ComplexList) to the Lambda (ComplexFunctions::conj) This would allow developers to use different Lambdas for the same operation/on the same list What are you streaming? ComplexDoubleArray sub-arrays? Would the > ComplexParrallelStreamFunctions class be responsible for creating the > Spliterator for this to control sub-ranges? > Yes. The parallelization details would be abstracted by ComplexParrallelFunctions ComplexFunctions could provide the sequential cursor implementation as you had suggested before The different implementations abstracted by functional interface would only be possible with Array based approach The developer could choose explicitly to call list.apply(ComplexFunctions::conj) or list.apply(ComplexParallelFunctions::conj) ComplexList.conj() could choose to apply sequential or parallel etc based on some config.
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Sun, 12 Jun 2022 at 04:37, Sumanth Rajkumar wrote: > On Sat, Jun 11, 2022, 18:02 Gilles Sadowski wrote: > > > I have a hard time figuring out whether these bits of code are > > intended to become the application developer API... > > What data-structure(s) will be visible (from the application)? > > What will be hidden ("implementation details")? > > > > Developer API will look something like this > > //1) Static methods to initialize array from external forms > > ComplexDoubleArray a = ComplexDoubleArray.fromBuffer(Double Buffer); > ComplexDoubleArray b = ComplexDoubleArray.fromArray(double[]); > > ComplexDoubleArray c = ComplexDoubleArray.parseFile(File); > > > //2) Methods on Array interface for complex operations. One for each > functional interface type.. unary, binary, scalar operations > > @FunctionalInterface > interface ComplexDoubleUnaryOperator { > > ComplexDoubleArray apply(ComplexDoubleArray input, ComplexDoubleArray > result); > } > > interface ComplexDoubleArray { > > int size(); > > //MutableComplexDoubleArray extends ComplexDoubleArray with setter, > mutation and static methods to allocate capacity > > MutableComplexDoubleArray asMutable(); > > ComplexDoubleArray asImmutable(); > > default boolean isImmutable() { return true;} > > > default ComplexDoubleArray apply(ComplexDoubleUnaryOperator op){ > > return op.apply(this, result); > > } > > . . . > > } > Some thoughts: - an array should be mutable by default. It would be made immutable using a Collections.immutableX(...) type wrapper. - an array should have get and set methods for complex, real and imaginary using an index within the array size. - a functional interface should be created that allows generic specification of the operation to perform on each atomic unit (i.e. a single complex number) as a lambda function. - two arrays (a and b) should be able to be paired for an operation on all pairs of (a, b), specified by a functional interface that can be written as a lambda function. This method will write in-place to a or an optional output array c. This could be preallocated, supplied dynamically using a T[]::new lambda function or some other variant. The last two requirements bring us back to the requirement for a generic way to write the result of a complex number computation (i.e. a single [real, imaginary] pair). > > //Function interfaces behavior - If output array is immutable, operations > return a copy, else result is applied in place on the passed in output and > returned > > //3 Developer API usage of complex operations on complex arrays > > ComplexDoubleArray a = init(); > a = a.asImmutable(); > > ComplexDoubleArray r1 = a.apply(ComplexFunctions::exp); > > ComplexDoubleArray r2 = a.apply(ComplexParrallelStreamFunctions::exp); > What are you streaming? ComplexDoubleArray sub-arrays? Would the ComplexParrallelStreamFunctions class be responsible for creating the Spliterator for this to control sub-ranges? > > ComplexDoubleArray r3 = a.apply(ComplexVectorFunctions::exp); > > ComplexDoubleArray r4 = a.apply(ComplexJTransformFunctions::forward_fft); > > > // 4 ComplexFunctions can provide commons C99 reference implementations > for supported complex operations as static methods that match the > functional interfaces. ( Refactored methods from existing Complex class). > Third parties can provide alternate implementations such as parallel stream > or vector based implementations and used by developers as above. > > > //5 the above functions also reused with existing Complex class? > > Complex implements ComplexDouble, ComplexDoubleArray { > > @Override > public int size() {return 1;} > > @Override > double [] toDoubleArray() { . . . } > > . . . > > //Refactored instance methods of Complex class > public Complex exp() { > return apply(ComplexFunctions::exp); > > } > . . . > > } > > Complex c = Complex.ofCartesian(r,i); > > //Backward compatible C99 implementation > Complex expc = c.exp(); > > Complex thirdparty_exp = c.apply(SomeThirdPartyFunctions::exp); > My concern with this approach is that if we store the minimum of a final real and imaginary part then any operation will have to: - create a ComplexDoubleArray for the result - Write to the ComplexDoubleArray - Convert the result ComplexDoubleArray back to a Complex If you look at how this can be used then there is a lot of excess object overhead here when you wish to write code for complex number computation in an OO way: See org.apache.commons.math4.legacy.analysis.solvers.LaguerreSolver IIUC the reason to have ComplexFunctions operate on arrays is to allow Vector optimisations. In this case the data would have to be extracted into a Vector species from a double[]. This would be more easily served by allowing the ComplexBuffer to be written to a double[]: DoubleComplexBuffer { // May be a reference to underlying data, or new allocation double[] getReal(); // Copied to the provided array double[] getReal(double[] b); } By providing a
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Sat, Jun 11, 2022, 18:02 Gilles Sadowski wrote: > I have a hard time figuring out whether these bits of code are > intended to become the application developer API... > What data-structure(s) will be visible (from the application)? > What will be hidden ("implementation details")? > Developer API will look something like this //1) Static methods to initialize array from external forms ComplexDoubleArray a = ComplexDoubleArray.fromBuffer(Double Buffer); ComplexDoubleArray b = ComplexDoubleArray.fromArray(double[]); ComplexDoubleArray c = ComplexDoubleArray.parseFile(File); //2) Methods on Array interface for complex operations. One for each functional interface type.. unary, binary, scalar operations @FunctionalInterface interface ComplexDoubleUnaryOperator { ComplexDoubleArray apply(ComplexDoubleArray input, ComplexDoubleArray result); } interface ComplexDoubleArray { int size(); //MutableComplexDoubleArray extends ComplexDoubleArray with setter, mutation and static methods to allocate capacity MutableComplexDoubleArray asMutable(); ComplexDoubleArray asImmutable(); default boolean isImmutable() { return true;} default ComplexDoubleArray apply(ComplexDoubleUnaryOperator op){ return op.apply(this, result); } . . . } //Function interfaces behavior - If output array is immutable, operations return a copy, else result is applied in place on the passed in output and returned //3 Developer API usage of complex operations on complex arrays ComplexDoubleArray a = init(); a = a.asImmutable(); ComplexDoubleArray r1 = a.apply(ComplexFunctions::exp); ComplexDoubleArray r2 = a.apply(ComplexParrallelStreamFunctions::exp); ComplexDoubleArray r3 = a.apply(ComplexVectorFunctions::exp); ComplexDoubleArray r4 = a.apply(ComplexJTransformFunctions::forward_fft); // 4 ComplexFunctions can provide commons C99 reference implementations for supported complex operations as static methods that match the functional interfaces. ( Refactored methods from existing Complex class). Third parties can provide alternate implementations such as parallel stream or vector based implementations and used by developers as above. //5 the above functions also reused with existing Complex class? Complex implements ComplexDouble, ComplexDoubleArray { @Override public int size() {return 1;} @Override double [] toDoubleArray() { . . . } . . . //Refactored instance methods of Complex class public Complex exp() { return apply(ComplexFunctions::exp); } . . . } Complex c = Complex.ofCartesian(r,i); //Backward compatible C99 implementation Complex expc = c.exp(); Complex thirdparty_exp = c.apply(SomeThirdPartyFunctions::exp); //Require Java16+ Complex vectorexp = c.apply(Complex VectorFunctions::exp) Thanks, Sumanth
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hello, Good discussion here! This is great! I lost track of what the overall goal here is while reading through the conversation. The goal of NUMBERS-186 is to "allow operations to be performed on lists of complex numbers". My first thought when looking at this is "how are we going to represent lists of complex numbers?" I don't think there is a single answer to this since the correct format for a list of complex numbers is whatever format the user already has them in. They could be in a file, in separate double arrays, in a single double array (alternating real and imaginary), in a float array, in a java.nio.Buffer, etc. So far, I haven't seen an API that can accomodate all of these. What I would like to see us create is an interface or abstract class like java.util.Buffer that allows us to wrap an underlying storage mechanism with complex number semantics. For example, if you have real and imaginary parts in two separate arrays, you could do something like ComplexBuffer buf = ComplexBuffer.fromRealAndImaginaryArrays(realArr, imArr); Similarly, with a DoubleBuffer: ComplexBuffer buf = ComplexBuffer.fromDoubleBuffer(buf); We can completely hide the classes implementing the wrappings here from the public API so that things are straightforward for the user. If we can first create a simple public API like this, then we can safely focus on performance improvements within the private code. Regards, Matt J On Sat, Jun 11, 2022 at 8:32 AM Gilles Sadowski wrote: > > Hello. > > > [...] > > > > interface ComplexDoubleArray { > > Stream stream(int start, int length); > > } > > > > ComplexDoubleArray a; > > // Will use the Java 8 ForkJoinPool.commonPool() for parallel execution > > a.stream(start, length).parallel().forEach(x -> ComplexFunctions.conj(x, > > x)); > > > > class ComplexFunctions { > > static void conj(ComplexDoubleArray in, ComplexDoubleArray out); > > } > > > > [...] > > I have a hard time figuring out whether these bits of code are > intended to become the application developer API... > What data-structure(s) will be visible (from the application)? > What will be hidden ("implementation details")? > Do we have use-cases of non-trivial processing of N-dimensional > cubes of complex numbers? [I imagine that the same API should > be able to also process cubes of real numbers (without storing the > "0" imaginary parts).] > > Gilles > > - > To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org > For additional commands, e-mail: dev-h...@commons.apache.org > - To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hello. > [...] > > interface ComplexDoubleArray { > Stream stream(int start, int length); > } > > ComplexDoubleArray a; > // Will use the Java 8 ForkJoinPool.commonPool() for parallel execution > a.stream(start, length).parallel().forEach(x -> ComplexFunctions.conj(x, > x)); > > class ComplexFunctions { > static void conj(ComplexDoubleArray in, ComplexDoubleArray out); > } > > [...] I have a hard time figuring out whether these bits of code are intended to become the application developer API... What data-structure(s) will be visible (from the application)? What will be hidden ("implementation details")? Do we have use-cases of non-trivial processing of N-dimensional cubes of complex numbers? [I imagine that the same API should be able to also process cubes of real numbers (without storing the "0" imaginary parts).] Gilles - To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Sat, 11 Jun 2022 at 07:09, Sumanth Rajkumar wrote: > Hi Alex and Gilles, > > For the complex functional interfaces, we have so far been working on > different options but all operate on single complex numbers one at a > time... > > Instead can we design around Functional Interfaces that work on List/Arrays > instead? > An interesting approach. IIUC this approach is to allow parallel optimisation. So the question is what computations would be performed in parallel on a large set of numbers? I am wondering if all the ISO c99 functions would ever be used in this way. And if they are, how well they would optimise given the high number of branch statements in many of the functions to handle edge cases. The optimisation is performing: for i in range: x(i) = f(x(i)) So you have to provide a function to operate on a number to obtain another number. How is this coded in the Java Vector API for simd support? Would a single layer of abstraction mapping a double[] (in the list) to ComplexNumber (for the function input) and back (from the function output) impact performance? <-- SNIP --> > > Interface ComplexDoubleArray{ > > DoubleStream realAndImgPairs (int index, int length) > > <-- SNIP --> A stream would have to have the pair of [real, imag] as the unit that the stream operates on. It cannot be a (possibly interleaved) stream of each part otherwise no function can operate on the whole complex number. Any API would require: Stream stream(int index, int length) with T the type of the complex number. ... > > } > > @FunctionalInterface > Interface ComplexDoubleUnaryOperator{ > > void apply(ComplexDoubleArray input, ComplexDoubleArray output, int > inputoffset, int outputoffset, int length); > > } > > This has following advantages > > 1) iterating implementations over lists will now be in the complex function > instead of ComplexList data structures allowing for different > implementations. For example we could have multi threaded java.util.stream > based operation on lists and single threaded cursor while loop based > implementation as suggested before by Alex. > Thinking about streams... For multi-threaded stream based operation this would: - Create the stream with a start and end point - Create a custom Spliterator holding the range limits - Allow division of the Spliterator which handles dividing the range until no more divisions are required (max threads reached) Thus the final unit to operate on is an unknown range (this is known to the Spliterator) of numbers. The unit for the functional interface is then ComplexDoubleArray: interface ComplexDoubleArray { Stream stream(int start, int length); } ComplexDoubleArray a; // Will use the Java 8 ForkJoinPool.commonPool() for parallel execution a.stream(start, length).parallel().forEach(x -> ComplexFunctions.conj(x, x)); class ComplexFunctions { static void conj(ComplexDoubleArray in, ComplexDoubleArray out); } So for streams the operations are required to operate on a range that is unknown. Internally the method must then have a way to access each entry of the ComplexDoubleArray, which is effectively a List.subList(...). Did you envision a different implementation? > 2) it will be required to take advantage of simd parallelism as discussed > before. For example conjugate operation on Complex list (double[] of real > and imaginary pairs) would be vector multiplication with array [ > 1,-1,1-1,..] > > If functional interface enforce operation on one complex number at a time, > we might not be able take advantage of simd optimizations? > IIUC the Java vector API is for multiplications, additions, and other arithmetic on primitives. The API is not finalised but it appears to have support for pow and sqrt elementary functions. So this would not allow full support for the ISO c99 elementary functions in Complex. Also the API requires a primitive array to be converted to a Vector species and operated on. So perhaps to support this only requires that any list of complex numbers can return the real and imaginary parts: interface ComplexList { void getReal(int start, int length, double[] dest); void getImaginary(int start, int length, double[] dest); // set methods } Then the functions can be written to extract the parts from the list, operate on them using the Java vector API and return them to the list. These functions would have an advantage on simple primitive operations. But any functions that require conditional logic may not be optimised (this is not clear from the examples I found). So for instance the multiplication of two complex numbers performed using: (a + i b)(c + i d) = (ac - bd) + i (ad + bc) final double ac = a * c; final double bd = b * d; final double ad = a * d; final double bc = b * c; double x = ac - bd; double y = ad + bc; The result x and y are then checked for NaN and suitable infinities recovered which requires a lot of logic. This logic may have to be moved out of the vector optimised loop and
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Sat, 11 Jun 2022 at 06:30, Sumanth Rajkumar wrote: > On Fri, Jun 10, 2022, 19:30 Gilles Sadowski wrote: > > > The current implementation of "Complex" encapsulates two "double" fields > > (not > > a "double[]"). > > Should we make two, at first separate, discussions: One for the > > implementation > > of the "complex number" concept, and another for (n-dimensional) lists of > > them? > > > > Yes. We could also change existing Complex type from two double fields to > double[] and even make it implement new ComplexNumber interface? This > should maintain runtime compatibility? > True. It does have the following disadvantages: - No longer immutable. Immutability would have to be enforced by encapsulation. - Increases memory consumption. Note this would compound the original issue with representing Complex in a List with inefficient memory consumption. So any application that does not update to the new implementation would suffer. > > I was thinking this would allow efficient reuse of functions processing > lists also to be used on single numbers (Complex) which is also a list of > size 1 > But we have also discussed other ways to share code between a single number and a list of them that are more safe, i.e. those that represent each entry of the list as a type to pass to the computation method which stores the result in the provided computation result. > > Jtransform has support for large arrays (size greater than integer.max with > array index of type long. > > Do we need to support that now or add that support later if needed? > No. You have to have a very good reason to use the undocumented sun.misc.Unsafe in code. I do not think we currently have that. Note that ~2^31 is a lot of numbers and to exceed this would be a specialist application for example using JTransforms 3D FFT on very large 3D data represented as a 1D array.
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Sat, 11 Jun 2022 at 06:08, Sumanth Rajkumar wrote: > > The type change would have been source compatible where existing > applications would have to recompile (without any code changes) to run > with the new version? > Yes. > > So yes, we cannot change Complex type to interface to maintain binary > runtime compatibility > > I assume, binary compatibility would be maintained if we add additional > interfaces with new methods to Complex class? > Yes. To use new methods another application would have to recompile source. Those applications that do now recompile source are ignorant of any new methods.
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hi Alex and Gilles, For the complex functional interfaces, we have so far been working on different options but all operate on single complex numbers one at a time... Instead can we design around Functional Interfaces that work on List/Arrays instead? Interface ComplexDoubleArray{ /* Methods for set/get by index as well as set/get array ranges on primitive double arrays*/ void set(int index, int sourceIndex, int len, double[] realAndImgPairs) void get(int index, int destIndex, int len, double[] realAndImgPairs) void set(int index, ComplexDouble c) ComplexDouble get(int index) Iterator iterator( int index, int length) DoubleStream realAndImgPairs (int index, int length) ... } @FunctionalInterface Interface ComplexDoubleUnaryOperator{ void apply(ComplexDoubleArray input, ComplexDoubleArray output, int inputoffset, int outputoffset, int length); } This has following advantages 1) iterating implementations over lists will now be in the complex function instead of ComplexList data structures allowing for different implementations. For example we could have multi threaded java.util.stream based operation on lists and single threaded cursor while loop based implementation as suggested before by Alex. 2) it will be required to take advantage of simd parallelism as discussed before. For example conjugate operation on Complex list (double[] of real and imaginary pairs) would be vector multiplication with array [ 1,-1,1-1,..] If functional interface enforce operation on one complex number at a time, we might not be able take advantage of simd optimizations? 3) operation on single complex number is now just operation on list/array of size 1. We can make existing Complex class implement ComplexDoubleArray interface Thanks Sumanth On Sat, Jun 11, 2022, 11:00 Sumanth Rajkumar wrote: > > > On Fri, Jun 10, 2022, 19:30 Gilles Sadowski wrote: > >> The current implementation of "Complex" encapsulates two "double" fields >> (not >> a "double[]"). >> Should we make two, at first separate, discussions: One for the >> implementation >> of the "complex number" concept, and another for (n-dimensional) lists of >> them? >> > > Yes. We could also change existing Complex type from two double fields to > double[] and even make it implement new ComplexNumber interface? This > should maintain runtime compatibility? > > For the interface, I suggest ComplexDouble (and ComplexFloat) intead of > ComplexNumber? > > > > A) ComplexCartesianImpl data structure will change to double[] >> > realAndImgPair >> >> What gain do you expect from involving an array here? >> > > We can make Complex class implement new ComplexList and ComplexNumber > interface.. > > I was thinking this would allow efficient reuse of functions processing > lists also to be used on single numbers (Complex) which is also a list of > size 1 > > > B) ComplexList can use single double[] for realAndImg parts (similar to >> all >> > external implementations such as jtransform) >> >> Yes (because of the gain in RAM usage). >> But AFAICT, the goal would be to make the "double[]" an "implementation >> detail" of "ComplexList" and have all operators handle "ComplexList" (or >> any n-dimensional "cube") as their input/output (?). >> >> > Yes. Also looking at jtransform naming, I suggest ComplexDoubleArray (and > ComplexFloatArray) instead of ComplexList? > > Jtransform has support for large arrays (size greater than integer.max > with array index of type long. > > Do we need to support that now or add that support later if needed? > > Thanks > Sumanth > >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Fri, Jun 10, 2022, 19:30 Gilles Sadowski wrote: > The current implementation of "Complex" encapsulates two "double" fields > (not > a "double[]"). > Should we make two, at first separate, discussions: One for the > implementation > of the "complex number" concept, and another for (n-dimensional) lists of > them? > Yes. We could also change existing Complex type from two double fields to double[] and even make it implement new ComplexNumber interface? This should maintain runtime compatibility? For the interface, I suggest ComplexDouble (and ComplexFloat) intead of ComplexNumber? > A) ComplexCartesianImpl data structure will change to double[] > > realAndImgPair > > What gain do you expect from involving an array here? > We can make Complex class implement new ComplexList and ComplexNumber interface.. I was thinking this would allow efficient reuse of functions processing lists also to be used on single numbers (Complex) which is also a list of size 1 > B) ComplexList can use single double[] for realAndImg parts (similar to > all > > external implementations such as jtransform) > > Yes (because of the gain in RAM usage). > But AFAICT, the goal would be to make the "double[]" an "implementation > detail" of "ComplexList" and have all operators handle "ComplexList" (or > any n-dimensional "cube") as their input/output (?). > > Yes. Also looking at jtransform naming, I suggest ComplexDoubleArray (and ComplexFloatArray) instead of ComplexList? Jtransform has support for large arrays (size greater than integer.max with array index of type long. Do we need to support that now or add that support later if needed? Thanks Sumanth
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Thanks for the detailed explanation with example. Now I understand the difference between binary vs source backward compatibility. The type change would have been source compatible where existing applications would have to recompile (without any code changes) to run with the new version? So yes, we cannot change Complex type to interface to maintain binary runtime compatibility I assume, binary compatibility would be maintained if we add additional interfaces with new methods to Complex class? For example, we should be ok if we add a new ComplexDouble interface with possibly new methods to Complex class? On Fri, Jun 10, 2022, 20:45 Alex Herbert wrote: > > > These are expected changes... Is there a compatibility issue here? > > > > Yes. These are reported as errors. > > This is the main issue: > > https://revapi.org/revapi-java/differences.html#java.class.kindChanged > > Changing a class to an interface. In this case methods on the object are > invoked using a different instruction. > So if you change class A to an interface then Test will have a runtime > linkage error as it cannot find the method > Thus we have to keep Complex as a class. >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Fri, 10 Jun 2022 at 14:10, Sumanth Rajkumar wrote: > For 1) I ran mvn verify and found the following errors > > > org.apache.commons.numbers.complex.Complex.getImaginary():METHOD_NOW_ABSTRACT, > org.apache.commons.numbers.complex.Complex.getReal():METHOD_NOW_ABSTRACT, > org.apache.commons.numbers.complex.Complex:CLASS_NOW_ABSTRACT, > org.apache.commons.numbers.complex.Complex:CLASS_TYPE_CHANGED, > > org.apache.commons.numbers.complex.ComplexCartesianImpl:METHOD_ABSTRACT_ADDED_IN_IMPLEMENTED_INTERFACE, > > org.apache.commons.numbers.complex.ComplexList:METHOD_ABSTRACT_ADDED_IN_IMPLEMENTED_INTERFACE, > > org.apache.commons.numbers.complex.ImmutableComplexList:METHOD_ABSTRACT_ADDED_IN_IMPLEMENTED_INTERFACE > > These are expected changes... Is there a compatibility issue here? > Yes. These are reported as errors. One point here is that Complex is a final class. So some of the errors regarding inheritance are non-issues. However binary compatibility requires that a class compiled against the old version can run against the new one. The main issue is changing a class to an interface (type change). The japicmp plugin does not have a lot of documentation. You can try revapi instead. Put this in the plugins section of the pom.xml: org.revapi revapi-maven-plugin 0.14.6 org.revapi revapi-java 0.26.1 Then run: mvn revapi:check (if you have the jar package) mvn package revapi:check -DskipTests -Djavadoc.skip (if you don't) This will output some similar compatibility errors and link to online documentation that explains why it is a problem. This is the main issue: https://revapi.org/revapi-java/differences.html#java.class.kindChanged Changing a class to an interface. In this case methods on the object are invoked using a different instruction. Save this as Test.java: public class Test { static class A { public int getAnswer() { return 42; } } interface B { int getAnswer(); } static class Bimp implements B { public int getAnswer() { return 13; } } public static void main(String[] args) { A a = new A(); System.out.println(a.getAnswer()); B b = new Bimp(); System.out.println(b.getAnswer()); } } > javac Test.java > java Test 42 13 > javap -c Test ... 12: invokevirtual #16 // Method Test$A.getAnswer:()I ... 30: invokeinterface #29, 1 // InterfaceMethod Test$B.getAnswer:()I ... Here we see the interface method uses 'invokeinterface' and the class method uses 'invokevirtual'. So if you change class A to an interface then Test will have a runtime linkage error as it cannot find the method (this is all assuming that A, B and Bimp are in their own class files which I didn't do here for simplicity). Basically if a class thinks the object with a method is a class and it is changed on the classpath at runtime to an interface this will not work. Thus we have to keep Complex as a class. However it does not mean the methods cannot be moved to e.g. public final class ComplexFunctions { interface ComplexResult { R accept(double real, double imag); } public static R conj(double real, double imaginary, ComplexResult result) { return result.accept(real, -imaginary); } } And Complex changed to e.g: ComplexFunctions conj() { return ComplexMath.conj(real(), imag(), Complex::ofCartesian); }
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hello. Le ven. 10 juin 2022 à 15:10, Sumanth Rajkumar a écrit : > > For 1) I ran mvn verify and found the following errors > > org.apache.commons.numbers.complex.Complex.getImaginary():METHOD_NOW_ABSTRACT, > org.apache.commons.numbers.complex.Complex.getReal():METHOD_NOW_ABSTRACT, > org.apache.commons.numbers.complex.Complex:CLASS_NOW_ABSTRACT, > org.apache.commons.numbers.complex.Complex:CLASS_TYPE_CHANGED, > org.apache.commons.numbers.complex.ComplexCartesianImpl:METHOD_ABSTRACT_ADDED_IN_IMPLEMENTED_INTERFACE, > org.apache.commons.numbers.complex.ComplexList:METHOD_ABSTRACT_ADDED_IN_IMPLEMENTED_INTERFACE, > org.apache.commons.numbers.complex.ImmutableComplexList:METHOD_ABSTRACT_ADDED_IN_IMPLEMENTED_INTERFACE > > These are expected changes... Is there a compatibility issue here? > > 2) Regarding usage of arrays in functional interfaces > @FunctionalInterface > public interface ComplexFunction3 { > void apply(Complex input, int offset, double[] result); > } > > The underlying implementations of Complex and ComplexList all use arrays > and there would be no additional array instantiation /RAM allocation just > to apply the functional interface functions The current implementation of "Complex" encapsulates two "double" fields (not a "double[]"). Should we make two, at first separate, discussions: One for the implementation of the "complex number" concept, and another for (n-dimensional) lists of them? > A) ComplexCartesianImpl data structure will change to double[] > realAndImgPair What gain do you expect from involving an array here? > B) ComplexList can use single double[] for realAndImg parts (similar to all > external implementations such as jtransform) Yes (because of the gain in RAM usage). But AFAICT, the goal would be to make the "double[]" an "implementation detail" of "ComplexList" and have all operators handle "ComplexList" (or any n-dimensional "cube") as their input/output (?). Regards, Gilles > > Thanks > Sumanth > > On Fri, 10 Jun 2022 at 08:58, Gilles Sadowski wrote: > > > Hello. > > > > Le ven. 10 juin 2022 à 14:43, Sumanth Rajkumar > > a écrit : > > > > > > Thanks for the quick response > > > > > > 1) I will run the mvn checks as suggested and get back to you > > > > > > 2) Yes, I realized the inefficiency and would not work.. I was following > > up > > > on another alternative but the email got sent prematurely > > > > > > Please ignore my previous email and consider this approach or some > > > variation of it? > > > > > > @FunctionalInterface > > > public interface ComplexFunction { > > > void apply(Complex input, int offset, double[] result); > > > } > > > > > > Example Conjugate implementation > > > > > > public static void conj(Complex in, int offset, double[] result) { > > > result[offset] = in.getReal(); > > > result[offset+1] = in.getImaginary(); > > > } > > > > My first feeling would be to steer away from (ab)using array as a pair. > > We may have to use arrays for interfacing with external tools (or perhaps > > internally too, e.g. to minimize RAM usage when processing a large list > > of complex numbers) but from a OO point of view, we should come up > > with an encapsulation that ensures robustness (e.g. featuring > > immutability). > > Also the type(s) should be easily usable in functional programming style. > > > > Gilles > > > > > > > > [...] - To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
For 1) I ran mvn verify and found the following errors org.apache.commons.numbers.complex.Complex.getImaginary():METHOD_NOW_ABSTRACT, org.apache.commons.numbers.complex.Complex.getReal():METHOD_NOW_ABSTRACT, org.apache.commons.numbers.complex.Complex:CLASS_NOW_ABSTRACT, org.apache.commons.numbers.complex.Complex:CLASS_TYPE_CHANGED, org.apache.commons.numbers.complex.ComplexCartesianImpl:METHOD_ABSTRACT_ADDED_IN_IMPLEMENTED_INTERFACE, org.apache.commons.numbers.complex.ComplexList:METHOD_ABSTRACT_ADDED_IN_IMPLEMENTED_INTERFACE, org.apache.commons.numbers.complex.ImmutableComplexList:METHOD_ABSTRACT_ADDED_IN_IMPLEMENTED_INTERFACE These are expected changes... Is there a compatibility issue here? 2) Regarding usage of arrays in functional interfaces @FunctionalInterface public interface ComplexFunction3 { void apply(Complex input, int offset, double[] result); } The underlying implementations of Complex and ComplexList all use arrays and there would be no additional array instantiation /RAM allocation just to apply the functional interface functions A) ComplexCartesianImpl data structure will change to double[] realAndImgPair B) ComplexList can use single double[] for realAndImg parts (similar to all external implementations such as jtransform) Thanks Sumanth On Fri, 10 Jun 2022 at 08:58, Gilles Sadowski wrote: > Hello. > > Le ven. 10 juin 2022 à 14:43, Sumanth Rajkumar > a écrit : > > > > Thanks for the quick response > > > > 1) I will run the mvn checks as suggested and get back to you > > > > 2) Yes, I realized the inefficiency and would not work.. I was following > up > > on another alternative but the email got sent prematurely > > > > Please ignore my previous email and consider this approach or some > > variation of it? > > > > @FunctionalInterface > > public interface ComplexFunction { > > void apply(Complex input, int offset, double[] result); > > } > > > > Example Conjugate implementation > > > > public static void conj(Complex in, int offset, double[] result) { > > result[offset] = in.getReal(); > > result[offset+1] = in.getImaginary(); > > } > > My first feeling would be to steer away from (ab)using array as a pair. > We may have to use arrays for interfacing with external tools (or perhaps > internally too, e.g. to minimize RAM usage when processing a large list > of complex numbers) but from a OO point of view, we should come up > with an encapsulation that ensures robustness (e.g. featuring > immutability). > Also the type(s) should be easily usable in functional programming style. > > Gilles > > > > > [...] > > - > To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org > For additional commands, e-mail: dev-h...@commons.apache.org > >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hello. Le ven. 10 juin 2022 à 14:43, Sumanth Rajkumar a écrit : > > Thanks for the quick response > > 1) I will run the mvn checks as suggested and get back to you > > 2) Yes, I realized the inefficiency and would not work.. I was following up > on another alternative but the email got sent prematurely > > Please ignore my previous email and consider this approach or some > variation of it? > > @FunctionalInterface > public interface ComplexFunction { > void apply(Complex input, int offset, double[] result); > } > > Example Conjugate implementation > > public static void conj(Complex in, int offset, double[] result) { > result[offset] = in.getReal(); > result[offset+1] = in.getImaginary(); > } My first feeling would be to steer away from (ab)using array as a pair. We may have to use arrays for interfacing with external tools (or perhaps internally too, e.g. to minimize RAM usage when processing a large list of complex numbers) but from a OO point of view, we should come up with an encapsulation that ensures robustness (e.g. featuring immutability). Also the type(s) should be easily usable in functional programming style. Gilles > > [...] - To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hello. > [...] > > > > > We could split complex unary operators into two primitive functions ( > > ToDoubleFunction) one returning the real part of result and other > > for imaginary part > > > > interface ComplexFunction { > > ToDoubleFunction getReal() ; > > ToDoubleFunction getImaginary() ; > > } > > > > > This has concerns for efficiency. First thought that came to my mind, being confirmed when looking at the "conj" example (where "applyAsDouble" is called twice)... Gilles > [...] - To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Thanks for the quick response 1) I will run the mvn checks as suggested and get back to you 2) Yes, I realized the inefficiency and would not work.. I was following up on another alternative but the email got sent prematurely Please ignore my previous email and consider this approach or some variation of it? @FunctionalInterface public interface ComplexFunction { void apply(Complex input, int offset, double[] result); } Example Conjugate implementation public static void conj(Complex in, int offset, double[] result) { result[offset] = in.getReal(); result[offset+1] = in.getImaginary(); } ComplexCartesianImpl data structure will change to double[] realAndImgPair with static factory method as below Complex { static Complex ofCartesian(double[] realAndImgPair); } And the complex functions used like below in Complex and ComplexList Complex { // default implementation are immutable always returning new instance to maintain b/w compatibility default Complex applyFunction(ComplexFunction function) { double[] result = new double[2]; return Complex.ofCartesian(function.apply(this,0,result); } } } ComplexList data structure will change to single double[] realAndImgPair ComplexList { .. private double[] realAndImaginaryPairs; // applies changes in place void forEach(ComplexFunction fun) { for(int i=0; i < realAndImaginaryPairs.length; i++){ fun.apply(cursor, i,realAndImaginaryPairs); } } Also, all the external list implementations I have reviewed, are using single double[] with real/imag parts interleaved or stored in the first and second half of the array. Thanks Sumanth On Fri, 10 Jun 2022 at 08:31, Alex Herbert wrote: > Hi, > > Thanks for the design update. I will review and get back to you with more > detailed feedback. Here are some quick thoughts: > > On Fri, 10 Jun 2022 at 12:55, Sumanth Rajkumar > > wrote: > > > Hi Alex and Giles, > > > > Thanks for the feedback. > > > > 1) Backward Compatibility and Complex Interface > > Yes. I understand the backward compatibility requirement and my goal is > to > > be fully backward compatible. > > > > Fortunately, the existing Complex class has private constructors and so > it > > is possible to refactor it as an interface. > > I was able to make the change along with a ComplexCartesianImpl class and > > run all unit tests successfully. I did not have to make any changes to > unit > > tests. > > "mvn test" runs successfully on my local machine after the changes > > > > 'mvn test' will not run binary compatibility checks. You should try > building with the default goal: 'mvn'. This will run a binary > compatibility check japicmp:cmp in the 'verify' phase as it requires the > packaged jar file. > > > > > > We could split complex unary operators into two primitive functions ( > > ToDoubleFunction) one returning the real part of result and > other > > for imaginary part > > > > interface ComplexFunction { > > ToDoubleFunction getReal() ; > > ToDoubleFunction getImaginary() ; > > } > > > > > This has concerns for efficiency. Look at some of the more involved > functions and you will see that there will be a lot of repeat computation > if you pass in the same complex number twice. > > And for example the Conjugate implementation would look like this > > ComplexFunction conj = new ComplexFunction2() { > > @Override > > public ToDoubleFunction getReal() { > > return complex -> complex.real(); > > } > > @Override > > public ToDoubleFunction getImaginary() { > > return complex -> -complex.imag(); > > } > > > > }; > >}; > > > > Quite verbose. However, can you even use a lambda function here? > > > > > > And the functions used like below in Complex and ComplexList > > > > Complex { > > // default implementation are immutable always returning new instance > > to maintain b/w compatibility > > default Complex applyFunction(ComplexFunction function) { > > return > > > > > Complex.ofCartesian(function.getReal().applyAsDouble(this),function.getImaginary().applyAsDouble(this)); > > } > > } > > } > > > > ComplexList { > > .. > > // applies changes in place > > void forEach(ComplexFunction fun) { > > ToDoubleFunction realFunc = fun.getReal(); > > ToDoubleFunction imgFunc = fun.getImaginary(); > > ComplexCursor cursor = new ComplexCursor(); > > while (cursor.index < r.length) { > > cursor.apply(realFunc.applyAsDouble(cursor), > > imgFunc .applyAsDouble(cursor)); > > cursor.index++; > > } > > } > > ... > > } > > > > Does this make sense or we just stick to the original interface that > > includes ComplexResult? > > > > I think a function for a complex number requires a real and imaginary input > and somewhere to put the real and imaginary answer. How to express this in > an interface that allows chaining is the tricky part. > > Alex >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hi, Thanks for the design update. I will review and get back to you with more detailed feedback. Here are some quick thoughts: On Fri, 10 Jun 2022 at 12:55, Sumanth Rajkumar wrote: > Hi Alex and Giles, > > Thanks for the feedback. > > 1) Backward Compatibility and Complex Interface > Yes. I understand the backward compatibility requirement and my goal is to > be fully backward compatible. > > Fortunately, the existing Complex class has private constructors and so it > is possible to refactor it as an interface. > I was able to make the change along with a ComplexCartesianImpl class and > run all unit tests successfully. I did not have to make any changes to unit > tests. > "mvn test" runs successfully on my local machine after the changes > 'mvn test' will not run binary compatibility checks. You should try building with the default goal: 'mvn'. This will run a binary compatibility check japicmp:cmp in the 'verify' phase as it requires the packaged jar file. > > We could split complex unary operators into two primitive functions ( > ToDoubleFunction) one returning the real part of result and other > for imaginary part > > interface ComplexFunction { > ToDoubleFunction getReal() ; > ToDoubleFunction getImaginary() ; > } > > This has concerns for efficiency. Look at some of the more involved functions and you will see that there will be a lot of repeat computation if you pass in the same complex number twice. And for example the Conjugate implementation would look like this > ComplexFunction conj = new ComplexFunction2() { > @Override > public ToDoubleFunction getReal() { > return complex -> complex.real(); > } > @Override > public ToDoubleFunction getImaginary() { > return complex -> -complex.imag(); > } > > }; >}; > Quite verbose. However, can you even use a lambda function here? > > And the functions used like below in Complex and ComplexList > > Complex { > // default implementation are immutable always returning new instance > to maintain b/w compatibility > default Complex applyFunction(ComplexFunction function) { > return > > Complex.ofCartesian(function.getReal().applyAsDouble(this),function.getImaginary().applyAsDouble(this)); > } > } > } > > ComplexList { > .. > // applies changes in place > void forEach(ComplexFunction fun) { > ToDoubleFunction realFunc = fun.getReal(); > ToDoubleFunction imgFunc = fun.getImaginary(); > ComplexCursor cursor = new ComplexCursor(); > while (cursor.index < r.length) { > cursor.apply(realFunc.applyAsDouble(cursor), > imgFunc .applyAsDouble(cursor)); > cursor.index++; > } > } > ... > } > > Does this make sense or we just stick to the original interface that > includes ComplexResult? > I think a function for a complex number requires a real and imaginary input and somewhere to put the real and imaginary answer. How to express this in an interface that allows chaining is the tricky part. Alex
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
2) ComplexFunction and ComplexResult functional interfaces Following up on my previous email, another alternative for ComplexFunction without using generic ComplexResult is as follows @FunctionalInterface public interface ComplexFunction3 { void apply(Complex input, int offset, double[] result); } Example Conjugate implementation public static void conj(Complex in, int offset, double[] result) { result[offset] = in.getReal(); result[offset+1] = in.getImaginary(); } ComplexCartesianImpl data structure will change to double[] realAndImgPair with static factory method as below Complex { static Complex ofCartesian(double[] realAndImgPair); } And the complex functions used like below in Complex and ComplexList Complex { // default implementation are immutable always returning new instance to maintain b/w compatibility default Complex applyFunction(ComplexFunction function) { double[] result = new double[2]; return Complex.ofCartesian(function.apply(this,0,result); } } } ComplexList { .. // applies changes in place void forEach(ComplexFunction fun) { ComplexCursor cursor = new ComplexCursor(); while (cursor.index < r.length) { cursor.apply(realFunc.applyAsDouble(cursor), imgFunc .applyAsDouble(cursor)); cursor.index++; } } ... } On Fri, 10 Jun 2022 at 07:55, Sumanth Rajkumar wrote: > Hi Alex and Giles, > > Thanks for the feedback. > > 1) Backward Compatibility and Complex Interface > Yes. I understand the backward compatibility requirement and my goal is to > be fully backward compatible. > > Fortunately, the existing Complex class has private constructors and so it > is possible to refactor it as an interface. > I was able to make the change along with a ComplexCartesianImpl class and > run all unit tests successfully. I did not have to make any changes to unit > tests. > "mvn test" runs successfully on my local machine after the changes > > > https://github.com/sumanth-rajkumar/commons-numbers/blob/sumanth-gsoc-22/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java > > https://github.com/sumanth-rajkumar/commons-numbers/blob/sumanth-gsoc-22/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexCartesianImpl.java > > This I assume should meet the backward compatibility requirements? > > The proposed functional interface changes introduces a new interface > ComplexNumber. > I think we could reuse the refactored Complex interface instead of a new > ComplexNumber interface and still maintain full backward compatibility. > > This would provide flexibility to older applications to work with new > implementations of Complex such as MutableComplexImpl or ComplexPolarImpl > or even ComplexStructImpl in the future whenever Java supports value types. > > Please let me know what you think. > > 2) ComplexFunction and ComplexResult functional interfaces > Yes the generic type introduces noise and can be solved as you > suggested. > > I was also thinking about an alternative that avoids the ComplexResult and > the generic type . > > We could split complex unary operators into two primitive functions ( > ToDoubleFunction) one returning the real part of result and other > for imaginary part > > interface ComplexFunction { > ToDoubleFunction getReal() ; > ToDoubleFunction getImaginary() ; > } > > And for example the Conjugate implementation would look like this > ComplexFunction conj = new ComplexFunction2() { > @Override > public ToDoubleFunction getReal() { > return complex -> complex.real(); > } > @Override > public ToDoubleFunction getImaginary() { > return complex -> -complex.imag(); > } > > }; >}; > > And the functions used like below in Complex and ComplexList > > Complex { > // default implementation are immutable always returning new instance > to maintain b/w compatibility > default Complex applyFunction(ComplexFunction function) { > return > Complex.ofCartesian(function.getReal().applyAsDouble(this),function.getImaginary().applyAsDouble(this)); > } > } > } > > ComplexList { > .. > // applies changes in place > void forEach(ComplexFunction fun) { > ToDoubleFunction realFunc = fun.getReal(); > ToDoubleFunction imgFunc = fun.getImaginary(); > ComplexCursor cursor = new ComplexCursor(); > while (cursor.index < r.length) { > cursor.apply(realFunc.applyAsDouble(cursor), > imgFunc .applyAsDouble(cursor)); > cursor.index++; > } > } > ... > } > > Does this make sense or we just stick to the original interface that > includes ComplexResult? > > > 3) Naming convention for the Functional Interfaces > > On reviewing the functions in java.util.functions package, the convention > is > "Function" name is used for interfaces that can accept inputs of > different types and return result of different type > "Operator" are
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hi Alex and Giles, Thanks for the feedback. 1) Backward Compatibility and Complex Interface Yes. I understand the backward compatibility requirement and my goal is to be fully backward compatible. Fortunately, the existing Complex class has private constructors and so it is possible to refactor it as an interface. I was able to make the change along with a ComplexCartesianImpl class and run all unit tests successfully. I did not have to make any changes to unit tests. "mvn test" runs successfully on my local machine after the changes https://github.com/sumanth-rajkumar/commons-numbers/blob/sumanth-gsoc-22/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/Complex.java https://github.com/sumanth-rajkumar/commons-numbers/blob/sumanth-gsoc-22/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexCartesianImpl.java This I assume should meet the backward compatibility requirements? The proposed functional interface changes introduces a new interface ComplexNumber. I think we could reuse the refactored Complex interface instead of a new ComplexNumber interface and still maintain full backward compatibility. This would provide flexibility to older applications to work with new implementations of Complex such as MutableComplexImpl or ComplexPolarImpl or even ComplexStructImpl in the future whenever Java supports value types. Please let me know what you think. 2) ComplexFunction and ComplexResult functional interfaces Yes the generic type introduces noise and can be solved as you suggested. I was also thinking about an alternative that avoids the ComplexResult and the generic type . We could split complex unary operators into two primitive functions ( ToDoubleFunction) one returning the real part of result and other for imaginary part interface ComplexFunction { ToDoubleFunction getReal() ; ToDoubleFunction getImaginary() ; } And for example the Conjugate implementation would look like this ComplexFunction conj = new ComplexFunction2() { @Override public ToDoubleFunction getReal() { return complex -> complex.real(); } @Override public ToDoubleFunction getImaginary() { return complex -> -complex.imag(); } }; }; And the functions used like below in Complex and ComplexList Complex { // default implementation are immutable always returning new instance to maintain b/w compatibility default Complex applyFunction(ComplexFunction function) { return Complex.ofCartesian(function.getReal().applyAsDouble(this),function.getImaginary().applyAsDouble(this)); } } } ComplexList { .. // applies changes in place void forEach(ComplexFunction fun) { ToDoubleFunction realFunc = fun.getReal(); ToDoubleFunction imgFunc = fun.getImaginary(); ComplexCursor cursor = new ComplexCursor(); while (cursor.index < r.length) { cursor.apply(realFunc.applyAsDouble(cursor), imgFunc .applyAsDouble(cursor)); cursor.index++; } } ... } Does this make sense or we just stick to the original interface that includes ComplexResult? 3) Naming convention for the Functional Interfaces On reviewing the functions in java.util.functions package, the convention is "Function" name is used for interfaces that can accept inputs of different types and return result of different type "Operator" are specialization of "Function" that take same type for all inputs and result Should we follow a similar naming convention for Complex functional interfaces? Thanks On Fri, 27 May 2022 at 21:34, Alex Herbert wrote: > On Thu, 26 May 2022 at 15:04, Gilles Sadowski > wrote: > > > > > > Next, I wanted to mention how I plan to start this project and was > hoping > > > to get some feedback. > > > > > > As per my proposal, the first thing I wanted to start with was the API > > > design which would have interfaces to represent complex numbers, > methods > > to > > > convert to/from linear primitive arrays, Java 8 functional interfaces > for > > > unary/binary operators and for functions for complex operations and > > > transforms involving: complex number and real numbers, complex vectors > > and > > > scalars, complex matrix, vectors and scalars. > > > > There are many items here. I would suggest breaking it down. Perhaps: > > 1. > interfaces to represent complex numbers > unary/binary operators and for functions for complex operations > > 2. > methods to convert to/from linear primitive arrays > > 3. > complex vectors and scalars, complex matrix, vectors and scalars. > > > Although not completely independant, we could discuss each in turn and see > what functionality is required. > > I will start with topic 1. Currently we have a single object, Complex, that > represents a complex number in cartesian form. It has a full set of > operations specified in ISO C99. I would suggest you have a look at the > specification as it has a lot of information
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Thu, 26 May 2022 at 15:04, Gilles Sadowski wrote: > > > Next, I wanted to mention how I plan to start this project and was hoping > > to get some feedback. > > > > As per my proposal, the first thing I wanted to start with was the API > > design which would have interfaces to represent complex numbers, methods > to > > convert to/from linear primitive arrays, Java 8 functional interfaces for > > unary/binary operators and for functions for complex operations and > > transforms involving: complex number and real numbers, complex vectors > and > > scalars, complex matrix, vectors and scalars. > There are many items here. I would suggest breaking it down. Perhaps: 1. interfaces to represent complex numbers unary/binary operators and for functions for complex operations 2. methods to convert to/from linear primitive arrays 3. complex vectors and scalars, complex matrix, vectors and scalars. Although not completely independant, we could discuss each in turn and see what functionality is required. I will start with topic 1. Currently we have a single object, Complex, that represents a complex number in cartesian form. It has a full set of operations specified in ISO C99. I would suggest you have a look at the specification as it has a lot of information about this [1]. There is a benchmark for these operations in the examples JMH module: org.apache.commons.numbers.examples.jmh.complex.ComplexPerformance Ideally any changes to extract all the methods into a static class should not impact performance. Many of the methods are quite involved and therefore slow. However some methods such as those for add/subtract/multiply/divide with real or imaginary scalars will be fast. It would be interesting to see if abstraction to a static class impacts their performance. These operations are not in the JMH benchmark so this could be added to provide a reference point for these. >From your GH code you have the following interface: public interface ComplexFunction { R apply(double r, double i, ComplexResult result); } I cannot create a lambda function for this as the method has a generic type parameter. This fails to compile. ComplexFunction f = (r, i, result) -> { // conjugate return result.apply(r, -i); }; This can be solved by moving to the interface declaration: public interface ComplexFunction { R apply(double r, double i, ComplexResult result); } But then all use of ComplexFunction has to be typed which can get noisy. It is however explicit in what the function output will be (and we assume the input is a complex number of some sort). Q. Do we wish to support effectively duplication of operations by accepting primitives and also a ComplexNumber type in the static methods: interface ComplexNumber { double real(); double imag(); } class ComplexFunctions { R sin(ComplexNumber c, ComplexResult r) { return sin(c.real(), c.imag(), r); } R sin(double r, double i, ComplexResult) { // ... } } There are various options for chaining methods together for sequential operations on the same complex. Should this avoid repeat object allocation by providing a MutableComplex holder: class MutableComplex implements ComplexNumber, ComplexResult { // allows read, write from/to real, imaginary parts } Q. How to manipulate ComplexList: class ComplexList implements List { private double[] r; private double[] i; } You have forEach methods (note this is without the type parameter): void forEach(ComplexFunction fun); So how do I declare a function to pass to the list, that accepts the real and imaginary parts and saves them back to the list. Currently you have the ComplexFunction accept the real and imaginary parts. But what if it accepted a ComplexNumber: public interface ComplexFunction { R apply(ComplexNumber c, ComplexResult result); } The ComplexList need only provide a single object that acts as a read/write cursor over the data by implementing both interfaces ComplexNumber and ComplexResult: // Internal class class ComplexCursor implements ComplexNumber, ComplexResult { // Directly manipulated by the enclosing list int index; @Override public Void apply(double r, double i) { ComplexList.this.r[index] = r; ComplexList.this.i[index] = i; return null; } @Override public double real() { return ComplexList.this.r[index]; } @Override public double imag() { return ComplexList.this.i[index]; } } I can write the method: void forEach(ComplexFunction fun) { ComplexCursor cursor = new ComplexCursor(); while (cursor.index < r.length) { fun.apply(cursor, cursor); cursor.index++; } } And call it like this: class ComplexFunctions { static R conj(ComplexNumber c, ComplexResult r) { return r.apply(c.real(), -c.imag()); } } ComplexList l; l.forEach(ComplexFunctions::conj); // Using a lambda l.forEach((c,
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hello. Le jeu. 26 mai 2022 à 07:04, Sumanth Rajkumar a écrit : > > Hi, > > My proposal was accepted into GSoC 2022 to work on the Numbers-186 [1] Jira > of the Commons Numbers project. > > I first want to ask if I can be assigned to this Jira Done. > since my GSoC > proposal was accepted. > > Next, I wanted to mention how I plan to start this project and was hoping > to get some feedback. > > As per my proposal, the first thing I wanted to start with was the API > design which would have interfaces to represent complex numbers, methods to > convert to/from linear primitive arrays, Java 8 functional interfaces for > unary/binary operators and for functions for complex operations and > transforms involving: complex number and real numbers, complex vectors and > scalars, complex matrix, vectors and scalars. For each of the mentioned functionalities, types and operations, please provide a concrete example of what you propose, indicating whether it is a new feature or a change and whethe it is backwards comptable (BC) or not. [These details can be further discussed on the JIRA page.] Whenever possible, please ensure that the proposed changes do not break the build. [You can test this by opening a PR, which should trigger an automated build.] > > Working on the API, am I on the right track to start with refactoring all > the existing methods in the Complex class as static functions for use as > lambdas? > > I already refactored some methods which can be viewed here [2] Renaming is typically something to be first discussed here and/or on JIRA. Unless other non BC changes are foreseen for the next release, such "cosmetic" changes must be avoided. Thanks, Gilles > > Thanks, > > Sumanth > > [1] https://issues.apache.org/jira/browse/NUMBERS-186 > > [2] > https://github.com/sumanth-rajkumar/commons-numbers/tree/sumanth-gsoc-22/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex > > On Mon, Mar 28, 2022, 7:01 PM Gilles Sadowski wrote: > > > Hello. > > > > Le lun. 28 mars 2022 à 00:32, Sumanth Rajkumar > > a écrit : > > > > > > Thanks Alex and Gilles for your feedback > > > > > > So currently Commons Math transform depends on Common complex numbers, > > and > > > the API involves usage of Complex Object Arrays instead of primitive > > array > > > data structures > > > > > > I also briefly looked into other library implementations besides > > Jtransform > > > and EJML that are not pure java but have java bindings such as JBLAS[1] > > and > > > NAG[2] > > > All of the implementation use single array data structures to represent > > > Complex Lists and higher dimensional matrices > > > > > > Since these involve parallel data pipelines I looked into libraries that > > > use SIMD [3] operations that use GP GPU (jcuda [4][5] /aparapi [6]) and > > CPU > > > (Java 17 Vector API [7]) > > > > Thanks for the investigation! > > > > > > > > Given all the alternative implementations, I agree it does not make sense > > > to re implement transforms here. > > > > Some transforms are (already) implemented here. > > Of course, it makes sense to wonder whether to keep maintaining those > > codes, or rely on external dependencies. The decision would depend on > > performance comparisons and whether users are able (or allowed) to > > interface with native libraries. [I know of one project where "pure Java" > > was a requirement...] > > > > > > > > So instead would it be useful to provide users with > > > 1) a complex numbers Linear Algebra and transforms API to compile against > > > and run with any of existing providers (apache commons, jtransform, EJML, > > > jblas) > > > AND > > > 2) a service provider interface to allow adapter implementations to > > > integrate existing and future providers such as jcudas/aparapi/vector > > APIs > > > > > > Do the commons library modularization dependency requirements apply to > > > compile time dependencies only or runtime also? > > > > Which "dependency requirements" are you referring to? > > > > > To minimize bloat, the runtime dependencies could be made optional and > > need > > > not be transitively included by default > > > > Flexibility would be ideal, indeed. > > > > > > > > Providing a Complex linear algebra and transforms API that can run with > > > different runtime providers would allow users to take advantage of > > hardware > > > capabilities and gracefully fallback to reference implementations > > > It could allow users to take advantage of Java 17 Vector APIs when > > > available without refactoring their existing libraries > > > > That looks great. > > > > > > > > Also do the Apache projects/ license allow for integration with non > > Apache > > > software (jtransform /jblas do not use Apache license, jcuda uses MIT > > > license) ? > > > > Licence issues are detailed here: > > https://www.apache.org/legal/resolved.html > > > > Best regards, > > Gilles > > > > > > > > Thanks > > > Sumanth > > > > > > [1] http://jblas.org/ > > > > > > [2] > >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hi, My proposal was accepted into GSoC 2022 to work on the Numbers-186 [1] Jira of the Commons Numbers project. I first want to ask if I can be assigned to this Jira since my GSoC proposal was accepted. Next, I wanted to mention how I plan to start this project and was hoping to get some feedback. As per my proposal, the first thing I wanted to start with was the API design which would have interfaces to represent complex numbers, methods to convert to/from linear primitive arrays, Java 8 functional interfaces for unary/binary operators and for functions for complex operations and transforms involving: complex number and real numbers, complex vectors and scalars, complex matrix, vectors and scalars. Working on the API, am I on the right track to start with refactoring all the existing methods in the Complex class as static functions for use as lambdas? I already refactored some methods which can be viewed here [2] Thanks, Sumanth [1] https://issues.apache.org/jira/browse/NUMBERS-186 [2] https://github.com/sumanth-rajkumar/commons-numbers/tree/sumanth-gsoc-22/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex On Mon, Mar 28, 2022, 7:01 PM Gilles Sadowski wrote: > Hello. > > Le lun. 28 mars 2022 à 00:32, Sumanth Rajkumar > a écrit : > > > > Thanks Alex and Gilles for your feedback > > > > So currently Commons Math transform depends on Common complex numbers, > and > > the API involves usage of Complex Object Arrays instead of primitive > array > > data structures > > > > I also briefly looked into other library implementations besides > Jtransform > > and EJML that are not pure java but have java bindings such as JBLAS[1] > and > > NAG[2] > > All of the implementation use single array data structures to represent > > Complex Lists and higher dimensional matrices > > > > Since these involve parallel data pipelines I looked into libraries that > > use SIMD [3] operations that use GP GPU (jcuda [4][5] /aparapi [6]) and > CPU > > (Java 17 Vector API [7]) > > Thanks for the investigation! > > > > > Given all the alternative implementations, I agree it does not make sense > > to re implement transforms here. > > Some transforms are (already) implemented here. > Of course, it makes sense to wonder whether to keep maintaining those > codes, or rely on external dependencies. The decision would depend on > performance comparisons and whether users are able (or allowed) to > interface with native libraries. [I know of one project where "pure Java" > was a requirement...] > > > > > So instead would it be useful to provide users with > > 1) a complex numbers Linear Algebra and transforms API to compile against > > and run with any of existing providers (apache commons, jtransform, EJML, > > jblas) > > AND > > 2) a service provider interface to allow adapter implementations to > > integrate existing and future providers such as jcudas/aparapi/vector > APIs > > > > Do the commons library modularization dependency requirements apply to > > compile time dependencies only or runtime also? > > Which "dependency requirements" are you referring to? > > > To minimize bloat, the runtime dependencies could be made optional and > need > > not be transitively included by default > > Flexibility would be ideal, indeed. > > > > > Providing a Complex linear algebra and transforms API that can run with > > different runtime providers would allow users to take advantage of > hardware > > capabilities and gracefully fallback to reference implementations > > It could allow users to take advantage of Java 17 Vector APIs when > > available without refactoring their existing libraries > > That looks great. > > > > > Also do the Apache projects/ license allow for integration with non > Apache > > software (jtransform /jblas do not use Apache license, jcuda uses MIT > > license) ? > > Licence issues are detailed here: > https://www.apache.org/legal/resolved.html > > Best regards, > Gilles > > > > > Thanks > > Sumanth > > > > [1] http://jblas.org/ > > > > [2] > https://www.nag.com/numeric/nl/nagdoc_latest/clhtml/c06/c06conts.html > > > > [3] > https://blogs.oracle.com/javamagazine/post/programming-the-gpu-in-java > > > > [4] http://jcuda.org/jcuda/jcufft/JCufft.html > > > > [5] > > > https://github.com/jcuda/jcuda-samples/tree/master/JCudaSamples/src/main/java/jcuda/jcufft/samples > > > > [6] http://aparapi.github.io/ > > > > [7] https://openjdk.java.net/jeps/414 > > > > > > On Tue, 22 Mar 2022 at 10:07, Gilles Sadowski > wrote: > > > > > Hello. > > > > > > > [...] > > > > > > > > > > Are we expecting complex-numbers to be an efficient pure java > library > > > that > > > > > could be used by other java libraries such as commons-imaging for > data > > > > > compression (DCT /JPEG lossy compression)? > > > > > > > > > > > > > Numbers should be seen as a toolbox to be used by other Java > > > applications. > > > > The best location for routines is something to discuss on the mailing > > > list. > > > > In
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hello. Le lun. 28 mars 2022 à 00:32, Sumanth Rajkumar a écrit : > > Thanks Alex and Gilles for your feedback > > So currently Commons Math transform depends on Common complex numbers, and > the API involves usage of Complex Object Arrays instead of primitive array > data structures > > I also briefly looked into other library implementations besides Jtransform > and EJML that are not pure java but have java bindings such as JBLAS[1] and > NAG[2] > All of the implementation use single array data structures to represent > Complex Lists and higher dimensional matrices > > Since these involve parallel data pipelines I looked into libraries that > use SIMD [3] operations that use GP GPU (jcuda [4][5] /aparapi [6]) and CPU > (Java 17 Vector API [7]) Thanks for the investigation! > > Given all the alternative implementations, I agree it does not make sense > to re implement transforms here. Some transforms are (already) implemented here. Of course, it makes sense to wonder whether to keep maintaining those codes, or rely on external dependencies. The decision would depend on performance comparisons and whether users are able (or allowed) to interface with native libraries. [I know of one project where "pure Java" was a requirement...] > > So instead would it be useful to provide users with > 1) a complex numbers Linear Algebra and transforms API to compile against > and run with any of existing providers (apache commons, jtransform, EJML, > jblas) > AND > 2) a service provider interface to allow adapter implementations to > integrate existing and future providers such as jcudas/aparapi/vector APIs > > Do the commons library modularization dependency requirements apply to > compile time dependencies only or runtime also? Which "dependency requirements" are you referring to? > To minimize bloat, the runtime dependencies could be made optional and need > not be transitively included by default Flexibility would be ideal, indeed. > > Providing a Complex linear algebra and transforms API that can run with > different runtime providers would allow users to take advantage of hardware > capabilities and gracefully fallback to reference implementations > It could allow users to take advantage of Java 17 Vector APIs when > available without refactoring their existing libraries That looks great. > > Also do the Apache projects/ license allow for integration with non Apache > software (jtransform /jblas do not use Apache license, jcuda uses MIT > license) ? Licence issues are detailed here: https://www.apache.org/legal/resolved.html Best regards, Gilles > > Thanks > Sumanth > > [1] http://jblas.org/ > > [2] https://www.nag.com/numeric/nl/nagdoc_latest/clhtml/c06/c06conts.html > > [3] https://blogs.oracle.com/javamagazine/post/programming-the-gpu-in-java > > [4] http://jcuda.org/jcuda/jcufft/JCufft.html > > [5] > https://github.com/jcuda/jcuda-samples/tree/master/JCudaSamples/src/main/java/jcuda/jcufft/samples > > [6] http://aparapi.github.io/ > > [7] https://openjdk.java.net/jeps/414 > > > On Tue, 22 Mar 2022 at 10:07, Gilles Sadowski wrote: > > > Hello. > > > > > [...] > > > > > > > > Are we expecting complex-numbers to be an efficient pure java library > > that > > > > could be used by other java libraries such as commons-imaging for data > > > > compression (DCT /JPEG lossy compression)? > > > > > > > > > > Numbers should be seen as a toolbox to be used by other Java > > applications. > > > The best location for routines is something to discuss on the mailing > > list. > > > In the example of DCT, I am not aware if imaging currently has an encoder > > > implementation for this. There is a decoder: > > > org/apache/commons/imaging/formats/jpeg/decoder/Dct.jav > > > > Also: > > > > https://gitbox.apache.org/repos/asf?p=commons-math.git;a=blob;f=commons-math-transform/src/main/java/org/apache/commons/math4/transform/FastCosineTransform.java > > > > It would be a maintenance boon if "Commons" could come up with > > a consensus about which components must be dependency-free and > > which could depend on other (lower-level) "Commons" components. > > > > [Imaging] is clearly higher-level than [Math] and that such non-obvious > > algorithms should be maintained in a single place. Through the process > > of modularizing [Math], we have "commons-math-transform" module, > > with zero dependency, so it would bring zero bloat to [Imaging] users if > > we consolidate usage. > > > > Of course, that would imply testing and benchmarking all current > > implementations, and retain the best (taking various axes into account: > > performance, robustness, flexibility). > > > > Regards, > > Gilles > > > > > [...] - To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Thanks Alex and Gilles for your feedback So currently Commons Math transform depends on Common complex numbers, and the API involves usage of Complex Object Arrays instead of primitive array data structures I also briefly looked into other library implementations besides Jtransform and EJML that are not pure java but have java bindings such as JBLAS[1] and NAG[2] All of the implementation use single array data structures to represent Complex Lists and higher dimensional matrices Since these involve parallel data pipelines I looked into libraries that use SIMD [3] operations that use GP GPU (jcuda [4][5] /aparapi [6]) and CPU (Java 17 Vector API [7]) Given all the alternative implementations, I agree it does not make sense to re implement transforms here. So instead would it be useful to provide users with 1) a complex numbers Linear Algebra and transforms API to compile against and run with any of existing providers (apache commons, jtransform, EJML, jblas) AND 2) a service provider interface to allow adapter implementations to integrate existing and future providers such as jcudas/aparapi/vector APIs Do the commons library modularization dependency requirements apply to compile time dependencies only or runtime also? To minimize bloat, the runtime dependencies could be made optional and need not be transitively included by default Providing a Complex linear algebra and transforms API that can run with different runtime providers would allow users to take advantage of hardware capabilities and gracefully fallback to reference implementations It could allow users to take advantage of Java 17 Vector APIs when available without refactoring their existing libraries Also do the Apache projects/ license allow for integration with non Apache software (jtransform /jblas do not use Apache license, jcuda uses MIT license) ? Thanks Sumanth [1] http://jblas.org/ [2] https://www.nag.com/numeric/nl/nagdoc_latest/clhtml/c06/c06conts.html [3] https://blogs.oracle.com/javamagazine/post/programming-the-gpu-in-java [4] http://jcuda.org/jcuda/jcufft/JCufft.html [5] https://github.com/jcuda/jcuda-samples/tree/master/JCudaSamples/src/main/java/jcuda/jcufft/samples [6] http://aparapi.github.io/ [7] https://openjdk.java.net/jeps/414 On Tue, 22 Mar 2022 at 10:07, Gilles Sadowski wrote: > Hello. > > > [...] > > > > > > Are we expecting complex-numbers to be an efficient pure java library > that > > > could be used by other java libraries such as commons-imaging for data > > > compression (DCT /JPEG lossy compression)? > > > > > > > Numbers should be seen as a toolbox to be used by other Java > applications. > > The best location for routines is something to discuss on the mailing > list. > > In the example of DCT, I am not aware if imaging currently has an encoder > > implementation for this. There is a decoder: > > org/apache/commons/imaging/formats/jpeg/decoder/Dct.jav > > Also: > > https://gitbox.apache.org/repos/asf?p=commons-math.git;a=blob;f=commons-math-transform/src/main/java/org/apache/commons/math4/transform/FastCosineTransform.java > > It would be a maintenance boon if "Commons" could come up with > a consensus about which components must be dependency-free and > which could depend on other (lower-level) "Commons" components. > > [Imaging] is clearly higher-level than [Math] and that such non-obvious > algorithms should be maintained in a single place. Through the process > of modularizing [Math], we have "commons-math-transform" module, > with zero dependency, so it would bring zero bloat to [Imaging] users if > we consolidate usage. > > Of course, that would imply testing and benchmarking all current > implementations, and retain the best (taking various axes into account: > performance, robustness, flexibility). > > Regards, > Gilles > > > [...] > > - > To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org > For additional commands, e-mail: dev-h...@commons.apache.org > >
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hello. > [...] > > > > Are we expecting complex-numbers to be an efficient pure java library that > > could be used by other java libraries such as commons-imaging for data > > compression (DCT /JPEG lossy compression)? > > > > Numbers should be seen as a toolbox to be used by other Java applications. > The best location for routines is something to discuss on the mailing list. > In the example of DCT, I am not aware if imaging currently has an encoder > implementation for this. There is a decoder: > org/apache/commons/imaging/formats/jpeg/decoder/Dct.jav Also: https://gitbox.apache.org/repos/asf?p=commons-math.git;a=blob;f=commons-math-transform/src/main/java/org/apache/commons/math4/transform/FastCosineTransform.java It would be a maintenance boon if "Commons" could come up with a consensus about which components must be dependency-free and which could depend on other (lower-level) "Commons" components. [Imaging] is clearly higher-level than [Math] and that such non-obvious algorithms should be maintained in a single place. Through the process of modularizing [Math], we have "commons-math-transform" module, with zero dependency, so it would bring zero bloat to [Imaging] users if we consolidate usage. Of course, that would imply testing and benchmarking all current implementations, and retain the best (taking various axes into account: performance, robustness, flexibility). Regards, Gilles > [...] - To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
On Sun, 20 Mar 2022 at 16:49, Sumanth Rajkumar wrote: > Thanks for the feedback Alex! > > As suggested, I reviewed the JTransforms and ComplexUtils class in the > complex streams package. > > The existing complex utils class has methods to convert to and from Array > data structures (the forms used in JTransform) to Complex class. > > I can come up with a Java 8/Streams based API for implementing complex > FFT algorithms of the types in JTransforms and support various methods in > ComplexUtils > The streams based complex operations API should allow for decoupling the > backing data structures. > This should make it possible to use single API to create an unit test > suite to benchmark/compare different backing data structures such as single > arrays, floats or even polar representations > Support for the output of Jtransforms ideally should not copy any data. This would be a wrapper to accept the array in place and allow further operations on the set of array complex data. At the end the same array can then be transformed back by JTransforms. However accepting a stream of Complex objects and performing a collect operation as a Stream termination operation to different backing data structures would be something to investigate: Complex[] c = ... ComplexList list = Arrays.stream(c).collect(ComplexCollectors.toList()); double[] data = list.flatten(); Ideally the ComplexCollectors would create a collector to generate data in a suitable format for any other library, e.g. JTransforms, so that the flatten operation simply returns the underlying data. Both methods would require arguments to allow the user to specify the organisation of the underlying data structure. The flatten method would then have to support transformation if necessary. The types of structure could be for a 1D example: double[] real double[] imag // Packed as real = i*2, imag = i*2+1 double[] data // Packed as real = i, imag = len/2 + i double[] data Then support for 2, 3, ND equivalents. In this case the class Gilles mentioned is useful: org.apache.commons.numbers.arrays.MultidimensionCounter Data transformation this way via streams may not be the optimal way to perform this with regard to memory usage. A transform utility class may be better suited as it can validate the dimensions of the input size before any allocation is made for the output data structure. For example you cannot create a 512*512 2D array if you do not have the correct size input. > > As part of the project, I could implement a subset of the FFT operations > in JTransform using the new streams based Complex Numbers API and > benchmark it against JTransform implementation > This would be repeating a lot of work from JTransforms which already implements support for parallel processing during the transform. I am not sure what the gain would be. Note that a FFT operation must operate on a vector of data, typically a power of size 2. So that would limit the use in a stream to stripes of data. Is this your intention? If so how would it differ from a parallel striped implementation in JTransforms? > > > I understand that we are in the GSOC discussion phase. I am trying to > understand the background of this project and the requirements in order to > come up with my GSOC proposal > > Can you provide with more information on the envisaged usage of > Commons-Numbers (especially Complex Numbers), its current usage/users and > the vision/roadmap for future enhancements > I do not have metrics for the usage of numbers. This is something that requires an analysis of the dependencies of a large number of projects to create a histogram of the frequency for library usage. I am not aware of a recent meta analysis where we can obtain such data for Numbers which had its first release in July 2021. Typically there is no roadmap for Commons beyond accepting contributions that add functionality that has general applicability. Future additions to Numbers could be further refactoring of existing functionality in Commons Math. There are already many parts of Commons Math that now depend on Commons Numbers. Since this is a community supported project the direction is really depicted by the input efforts of the community. > > Are we expecting complex-numbers to be an efficient pure java library that > could be used by other java libraries such as commons-imaging for data > compression (DCT /JPEG lossy compression)? > Numbers should be seen as a toolbox to be used by other Java applications. The best location for routines is something to discuss on the mailing list. In the example of DCT, I am not aware if imaging currently has an encoder implementation for this. There is a decoder: org/apache/commons/imaging/formats/jpeg/decoder/Dct.jav > > Are there other Java/Non-Java (C/Python) libraries that provide similar > features that I can look into for design inspiration and also benchmark > Complex Numbers with? > Complex numbers are a requirement for a C library that conforms to
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Le lun. 21 mars 2022 à 23:12, Alex Herbert a écrit : > > Hi, > > This lost the dev@commons in the to address. I am forwarding to the list to > include the history. >From a quick read of the quoted messages below, I believe I must point out that there is an FFT implementation in Commons Math.[1] It could be construed as a (high priority) use case. Thus, it should be included in benchmarks and possibly adapted to work with the proposed data-structure(s). Regards, Gilles [1] https://gitbox.apache.org/repos/asf?p=commons-math.git;a=blob;f=commons-math-transform/src/main/java/org/apache/commons/math4/transform/FastFourierTransform.java > > On Sun, 20 Mar 2022 at 16:49, Sumanth Rajkumar > wrote: > > > Thanks for the feedback Alex! > > > > As suggested, I reviewed the JTransforms and ComplexUtils class in the > > complex streams package. > > > > The existing complex utils class has methods to convert to and from Array > > data structures (the forms used in JTransform) to Complex class. > > > > I can come up with a Java 8/Streams based API for implementing complex > > FFT algorithms of the types in JTransforms and support various methods in > > ComplexUtils > > The streams based complex operations API should allow for decoupling the > > backing data structures. > > This should make it possible to use single API to create an unit test > > suite to benchmark/compare different backing data structures such as single > > arrays, floats or even polar representations > > > > As part of the project, I could implement a subset of the FFT operations > > in JTransform using the new streams based Complex Numbers API and > > benchmark it against JTransform implementation > > > > > > I understand that we are in the GSOC discussion phase. I am trying to > > understand the background of this project and the requirements in order to > > come up with my GSOC proposal > > > > Can you provide with more information on the envisaged usage of > > Commons-Numbers (especially Complex Numbers), its current usage/users and > > the vision/roadmap for future enhancements > > > > Are we expecting complex-numbers to be an efficient pure java library that > > could be used by other java libraries such as commons-imaging for data > > compression (DCT /JPEG lossy compression)? > > > > Are there other Java/Non-Java (C/Python) libraries that provide similar > > features that I can look into for design inspiration and also benchmark > > Complex Numbers with? > > > > Thanks > > Sumanth > > > > > > On Tue, 15 Mar 2022 at 20:50, Alex Herbert > > wrote: > > > >> Hi Sumanth, > >> > >> These changes to use static methods with functional interfaces is an > >> improvement. However I would advise that we consider the use cases for this > >> functionality to ensure that any design does not prevent extension and also > >> allows full flexibility to achieve various tasks. > >> > >> For example: > >> > >> - multiply all the complex numbers in one list with another > >> - wrap an existing complex number data structure, for example the FFT > >> result produced by JTransforms [1] > >> > >> This project originates from a previous enhancement request that was made > >> to store a large set of complex numbers efficiently. The argument was that > >> the 16 bytes to store 2 doubles is inflated by the object allocation to > >> store a Complex, perhaps by even double the 16 bytes. The natural storage > >> would be two arrays of doubles, but what about 1 linear array packed as > >> real/imag for each number. This will be able to store half as many numbers > >> but access to each will take advantage of efficient caching when > >> reading/writing memory. The JTransforms library (and others) may have ideas > >> for useful data structures. > >> > >> Unfortunately I cannot find if there was a Jira ticket for this or it is > >> only in the mailing archives. I've added links to the GSoC ticket for the > >> other tickets that mention complex number array utils and streams. However > >> these do not have a use case. Perhaps an investigation of the functionality > >> in the unreleased commons-number-complex-streams package would be the place > >> to start. The original author of that package is not actively involved in > >> the development any more. > >> > >> I should also point out the process for GSoC. It is outlined here [2]. In > >> short the initial period is about understanding what a project may involve. > >> Then you create a proposal for the project that is ranked with all the > >> other potential coders. Some projects are selected. It is only then that > >> the formal coding process begins and you have 12 weeks to create some code. > >> Previous years have had a timeline but this year the only date on the info > >> page is April 4 - 19 for when applications open. So right now we are in the > >> discussion phase. Any code developed now technically cannot be part of > >> GSoC, although this is not strictly enforced. > >> > >> Regards, > >> > >> Alex > >> > >> [1]
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hi, This lost the dev@commons in the to address. I am forwarding to the list to include the history. On Sun, 20 Mar 2022 at 16:49, Sumanth Rajkumar wrote: > Thanks for the feedback Alex! > > As suggested, I reviewed the JTransforms and ComplexUtils class in the > complex streams package. > > The existing complex utils class has methods to convert to and from Array > data structures (the forms used in JTransform) to Complex class. > > I can come up with a Java 8/Streams based API for implementing complex > FFT algorithms of the types in JTransforms and support various methods in > ComplexUtils > The streams based complex operations API should allow for decoupling the > backing data structures. > This should make it possible to use single API to create an unit test > suite to benchmark/compare different backing data structures such as single > arrays, floats or even polar representations > > As part of the project, I could implement a subset of the FFT operations > in JTransform using the new streams based Complex Numbers API and > benchmark it against JTransform implementation > > > I understand that we are in the GSOC discussion phase. I am trying to > understand the background of this project and the requirements in order to > come up with my GSOC proposal > > Can you provide with more information on the envisaged usage of > Commons-Numbers (especially Complex Numbers), its current usage/users and > the vision/roadmap for future enhancements > > Are we expecting complex-numbers to be an efficient pure java library that > could be used by other java libraries such as commons-imaging for data > compression (DCT /JPEG lossy compression)? > > Are there other Java/Non-Java (C/Python) libraries that provide similar > features that I can look into for design inspiration and also benchmark > Complex Numbers with? > > Thanks > Sumanth > > > On Tue, 15 Mar 2022 at 20:50, Alex Herbert > wrote: > >> Hi Sumanth, >> >> These changes to use static methods with functional interfaces is an >> improvement. However I would advise that we consider the use cases for this >> functionality to ensure that any design does not prevent extension and also >> allows full flexibility to achieve various tasks. >> >> For example: >> >> - multiply all the complex numbers in one list with another >> - wrap an existing complex number data structure, for example the FFT >> result produced by JTransforms [1] >> >> This project originates from a previous enhancement request that was made >> to store a large set of complex numbers efficiently. The argument was that >> the 16 bytes to store 2 doubles is inflated by the object allocation to >> store a Complex, perhaps by even double the 16 bytes. The natural storage >> would be two arrays of doubles, but what about 1 linear array packed as >> real/imag for each number. This will be able to store half as many numbers >> but access to each will take advantage of efficient caching when >> reading/writing memory. The JTransforms library (and others) may have ideas >> for useful data structures. >> >> Unfortunately I cannot find if there was a Jira ticket for this or it is >> only in the mailing archives. I've added links to the GSoC ticket for the >> other tickets that mention complex number array utils and streams. However >> these do not have a use case. Perhaps an investigation of the functionality >> in the unreleased commons-number-complex-streams package would be the place >> to start. The original author of that package is not actively involved in >> the development any more. >> >> I should also point out the process for GSoC. It is outlined here [2]. In >> short the initial period is about understanding what a project may involve. >> Then you create a proposal for the project that is ranked with all the >> other potential coders. Some projects are selected. It is only then that >> the formal coding process begins and you have 12 weeks to create some code. >> Previous years have had a timeline but this year the only date on the info >> page is April 4 - 19 for when applications open. So right now we are in the >> discussion phase. Any code developed now technically cannot be part of >> GSoC, although this is not strictly enforced. >> >> Regards, >> >> Alex >> >> [1] https://github.com/wendykierp/JTransforms >> [2] https://summerofcode.withgoogle.com/how-it-works >> >> >> On Tue, 15 Mar 2022 at 02:23, Sumanth Rajkumar < >> rajkumar.suma...@gmail.com> wrote: >> >>> Hi Alex/Gilles >>> >>> Thank you both for the detailed review. I think I have a better >>> understanding now. >>> >>> 1) Refactor using Functional Interfaces and move current instance >>> methods to static methods >>> >>> As suggested, I have attempted to refactor the Complex class to extract >>> the functions out to static methods and use Functional interfaces >>> >>> I have added following Complex Functional interfaces similar to >>> Functions and Operators defined in java.util.function but only using >>> primitive doubles
Re: [numbers][gsoc] GSoC 2022 - NUMBERS-186 Proposal
Hi, Thanks for your interest in Commons Numbers. On Mon, 14 Mar 2022 at 00:09, Gilles Sadowski wrote: > > > > My partial implementation (with TODOs for many operations) is available > > here. > > > https://github.com/sumanth-rajkumar/commons-numbers/blob/sumanth-gsoc-22/commons-numbers-complex/src/main/java/org/apache/commons/numbers/complex/ComplexList.java Thanks for the implementation idea. This is a literal implementation of a List. I think we should take a step back and find use cases for a large set of complex numbers. That should drive the API design. For example a common operation with complex numbers is to conjugate multiply the fast fourier transform of two data arrays. The conjugate multiply in the frequency domain is equivalent to the correlation in the spatial domain. So I would require: ComplexList a; ComplexList b; a.conj().multiply(b); But what is the most appropriate method to do this? I do not think we want to implement full matrix functionality for multiplication of arrays. But we should allow an API that makes this type of work efficient in terms of memory usage, i.e. zero object allocation during computation (avoid creating Complex instances) and ideally no intermediate array allocation. So in the above I do not want to create an entire list of conjugates before multiplying by another complex number. I also want the option to write to a new array or back to the original one. So should we have some type of generic interface for an operation on a Complex: interface ComplexFunction { interface ComplexResult { void complex(double real, double imag); } void apply(double re, double im, ComplexResult); } Then a list to allow operations on elements in place. For example to compute the conjugate: ComplexList a; a.forEach((re, im, result) -> result.complex(re, -im)); All operations in the Complex class can be rewritten as static methods using a minimal set of functional interfaces. static void conj(double re, double im, ComplexResult result) { result.complex(re, -im); } The operation then becomes: ComplexList a; a.forEach(Complex::conj); Which is a bit less cumbersome to write. Operations could be chained using a 'andThen' method in the interface: ComplexList a; a.forEach(((ComplexFunction) Complex::conj).andThen(Complex::sin)); I've not considered exactly how this will work in practice. Functions that convert to a real number (such as abs()) could write 0 to the imaginary. The specifics will depend on all the operations in Complex. So a start point may be to refactor the class to expose all the instance methods as static methods that take input and write the result to a destination. These can be used by (all) the Complex instance methods. I say (all) as some may be more efficient to leave as is, namely the simple methods like negate or conjugate, and the operations with real numbers. Re: Your code implementation I notice that the implementation for the expandable array backed list and hash code generation are "heavily reliant" on the JDK (11?) source for ArrayList and Arrays. It is good practice to be aware of the license terms of any open source code project you may wish to use. The Oracle Open JDK license terms are here [1]. This is under the GNU GPL v2 license which is not permissible to be used in an ASF project [2]. In general it is fine to look at the JDK source code to see how the function works or find bugs. However any new code reimplementing the functionality should be done as if blind to the code and only using a contractual specification of what the code is meant to do. The modern javadoc effort by the JDK tries to provide a very good specification of each method contract. So it is often possible to write the same function from the javadoc description. An ideal javadoc should have this as its goal. Effectively this would be someone telling you what the code does but not showing you how: 1. A default array size of 10 2. Backing array will grow using a factor of 50% up to the maximum array size 3. Overflow of the maximum array size will result in OutOfMemoryError 4. Index operations outside of the current list size [0, size) will throw ArrayIndexOutOfBoundException 5. etc Alex [1] http://openjdk.java.net/legal/gplv2+ce.html [2] https://www.apache.org/legal/resolved.html#category-x