Hi.

>>> [...]
> >
> > public class ComplexArray {
> >      private final MultidimensionalCounter counter;
> >      // ...
> >
> >      public ComplexArray(int... dimensions) {
> >          counter = new MultidimensionalCounter(dimensions);
> >          data = new data[counter.getSize()];
> >      }
> >
> >      /**
> >       * @param indices Storage location.
> >       * @return the complex number stored at the given location.
> >       */
> >      public Complex get(int... indices) {
> >          return data[counter.getCount(indices)];
> >      }
> > }
> >
> > Or perhaps the data cube should be an additional abstraction on top of
> > "ComplexArray" (?).
> I think adding the abstraction on top is easier.
>
> Array can be renamed to Collection/List? Thus the count is the only
> thing that matters, and optionally a constant time access get(int index)
> method.

+1

>
> This can later be reshaped to a Matrix representation using the
> MultidimensionalCounter pattern.
>
> We have two use cases:
>
> 1. You know the final count of Complex objects
> 2. You do not know the count of Complex objects
>
> Use case 2 is used in streams where the ComplexList must be expandable
> for use as a collector. This can be satisfied with a constructor with an
> initial capacity. The ComplexList would thus offer a specialisation of
> ArrayList<Complex> by storing the Complex objects using primitive array(s).
>
> Use case 2 rules out the possibility of immutability. This is the type
> of functionality under discussion and could be served using an interface
> to allow different implementations:
>
> public interface ComplexList {
> [...]
> }

+1

> This could be separated to put the set and add methods in a
> sub-interface allowing the top level interface to be an immutable object.

Perhaps better to follow the JDK convention and provide a
    public static ComplexList unmodifiableList(ComplexList delegate)
method.

> However the apply functions currently are specified using Complex.
> Efficiency would be gained using primitive specialisations for operating
> on 1 or 2 complex numbers and outputting the results to a provided consumer:
>
>      public interface ComplexProvider {
>          /**
>           * Gets the real component of the complex number.
>           *
>           * @return the real component
>           */
>          double getReal();
>
>          /**
>           * Gets the imaginary component of the complex number.
>           *
>           * @return the imaginary component
>           */
>          double getImaginary();
>      }
>
>      public interface ComplexConsumer {
>          /**
>           * Accept the components of the complex number.
>           * Optionally return a new ComplexProvider with the components.
>           *
>           * @param real the real
>           * @param imaginary the imaginary
>           * @return the complex provider (or null)
>           */
>          ComplexProvider accept(double real, double imaginary);
>      }

What is gained wrt using "Complex" instances directly?

> [...]
>
> Unfortunately processing the stream as encountered may result in out of
> order elements if parallelisation occurs so the results may not be
> collected back in the same order.

IIUC, this would be a non-starter for the data cube abstraction.

> Here there are solutions to different problems. So which are we trying
> to solve:
>
> 1. Efficient storage of large amounts of complex numbers.
>
> 2. Efficient computation on large amounts of complex numbers.

Those two IMO.

>
> 3. Custom computation on complex numbers.

Not sure what you mean.

>
> 4. Computation on large amounts of complex numbers in-place.

This would assume very, very, large amounts of data.
For applications that would manage with data that fill at most half the
available memory, this could be emulated with
   ComplexList data = ...
   data = function.apply(data);

And, with a "data cube" abstraction with several underlying blocks
of data, the amount of needed "spare" RAM could be reduced at will:
Instead of storing one block of 1000 x 1000, one could store 4 of
500 x 500; process them sequentially would require four times less
spare RAM.

> For 1 we can use the abstraction to a collection (e.g. ComplexList).
>
> For 2 we can duplicate all methods in Complex to work directly on the
> underlying data.
>
> For 2/3 we can rewrite computation of Complex to work on input providers
> and output consumers and allow functions to be applied to the collection.
>
> For 4 we require different mutability of the collection.

I don't think that immutability is a very useful requirement when handling
very large amounts of data.  E.g. the data cube should probably allow this
kinf of usage:
   ComplexCube c = ...
   c.transformInPlace(function);

> I will continue to think about this as the solution to all issues is not
> straightforward.

I didn't want to push this too far.  The sole use-case I was aware of is an
"OutOfMemoryError" due to storing "Complex" instances in an array of
arrays of arrays of...

I think that an interesting example application would be how to compute
the FFT of the stored data (e.g. using "JTransforms").

Another nice example would be fractal computations.

Best,
Gilles

>
> Opinions are welcomed.
>
> > [...]

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
For additional commands, e-mail: dev-h...@commons.apache.org

Reply via email to