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<Void> 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 <[email protected]> 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 <[email protected]
> >
> 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<Complex>) one returning the real part of result and
> other
> > for imaginary part
> >
> > interface ComplexFunction {
> > ToDoubleFunction<Complex> getReal() ;
> > ToDoubleFunction<Complex> 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<Complex> getReal() {
> > return complex -> complex.real();
> > }
> > @Override
> > public ToDoubleFunction<Complex> 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<Complex> realFunc = fun.getReal();
> > ToDoubleFunction<Complex> 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<R>?
> >
>
> 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
>