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 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<Complex> 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<Complex> op = Complex::sqrt;
// These compose to Function
Function<Complex, Complex> op2 = op.andThen(Complex::conj);
Function<Complex, Complex> op3 = op.compose(Complex::conj);

// Invalid to assign back to UnaryOperator
op = op.andThen(Complex::conj);
// OK with a cast
op = (UnaryOperator<Complex>) op.andThen(Complex::conj);

// In use:
// op could be declared as a UnaryOperator<Complex> or Function<Complex,
Complex> 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<T> andThen(UnaryOperator<T> 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

Reply via email to