0

Let's say I have 3 functions, something like y_1(x) = x^2, y_2(x) = x+1 and y_3(x) = x/5. How do I apply these functions to any multidimensional float array in an element wise fashion?

Now given that I have the functions y_1, y_2 and y_3, what is a function that applies an arbitrary function to a float array of any size and shape?

I tried creating a function applier that takes in any function and then applying it to every element in a double loop for the 2 dimensional case but I cannot even get the function applier to take another function as input.

I tried doing the following

public float[][] elemen_wise_function(  float[][] x,
                                        int Size_axis_0,
                                        int Size_axis_1,
                                        Callable<> myFunc) {

    float[][] Constructed_array = new float[Size_axis_0][Size_axis_1];
    for (int i=0; i<Size_axis_0; i++) {
        for (int j = 0; j < Size_axis_1; j++) {
            Constructed_array[i][j] = (float) myFunc(x[i][j]) ;
        }
    }
    return Constructed_array;
}

But this fails because I cannot find a way to pass myFunc to elemen_wise_function.

student
  • 5
  • 1
  • 7
  • 2
    `map` is the typical function to do this, although you'll need to use streams for that in Java. You could also just loop over the array using a standard `for` loop, and produce a new array using the loop. – Carcigenicate Jan 15 '19 at 20:44
  • do you want something like `Arrays.map`? possible duplicate of https://stackoverflow.com/a/3907448/10625458 – elbraulio Jan 15 '19 at 20:45
  • Show what you've tried. – Boris the Spider Jan 15 '19 at 20:45
  • And to take a function as an argument, look into the `Function` type. This question is a little broad though, as there's many ways to do what you're asking. – Carcigenicate Jan 15 '19 at 20:46
  • Do you know of any examples online? – student Jan 15 '19 at 20:46
  • Although the question is slightly vague, the simplest way I could see it is to iterate through your multi-dimensional array and use each element as your 'X'. Use Random to determine which function shall be applied to your float and call it, if that's what you want it to do. You could always create an object that has a float field and a String to hold a function if you do not want to do the math directly to your elements. – davedno Jan 15 '19 at 20:50
  • @BoristheSpider I updated my question to show what I tried in the 2D case. Because I won't be working with more than 5D I could just define a function for every dimensions, even though it's ugly. It's just that I cannot get it to work even if the dimension is set. – student Jan 15 '19 at 20:56
  • So that's just a [`UnaryOperator`](https://docs.oracle.com/javase/8/docs/api/java/util/function/UnaryOperator.html) then? – Boris the Spider Jan 15 '19 at 21:00
  • @BoristheSpider Do you have an example of how to use that? You seem to think it's trivial but I just don't get what I should do with that. Where would you insert that in what I tried to make it work? – student Jan 15 '19 at 21:06

3 Answers3

2

One solution would be to declare myFunc as UnaryOperator<Float>.

public float[][] elemen_wise_function(float[][] x, int Size_axis_0, int Size_axis_1,
                                      UnaryOperator<Float> myFunc) {

Unfortunately that will autobox the float back and forth.

If performance is a concern you can define a custom interface that is hard-coded to operate on primitive floats:

interface FloatOperator {
    float apply(float x);
}

public float[][] elemen_wise_function(float[][] x, int Size_axis_0, int Size_axis_1,
                                      FloatOperator myFunc) {

In both cases use as:

    for (int i = 0; i < Size_axis_0; i++) {
        for (int j = 0; j < Size_axis_1; j++) {
            Constructed_array[i][j] = myFunc.apply(x[i][j]);
        }
    }

Invoke as (example):

    elemen_wise_function(array, size0, size1, a -> 1/a);
rustyx
  • 80,671
  • 25
  • 200
  • 267
0

Quite cool, you can pass a lambda (since java 8):

public float[][] elemen_wise_function(float[][] x,
                                      Function<Float, Float> f) {

    float[][] Constructed_array = new float[x.length][x[0].length];
    for (int i=0; i<x.length; i++) {
        for (int j = 0; j < x[0].length; j++) {
            Constructed_array[i][j] = f.apply(x[i][j]);
        }
    }
    return Constructed_array;
}

Then you can pass any function defined as lambda, for example:

Function<Float, Float> fun = x -> 2 * x;

Also one note - use camelCase in java for method names;)

Andronicus
  • 25,419
  • 17
  • 47
  • 88
0

If you are trying to do this with Java 6, you can do something like.

    import java.util.Arrays;
    import java.util.function.Function;

    public interface MapFunction {
        public float map(float value);
    }

    public static float[][] map2DArray(float[][] floatArrays, MapFunction mapper) {
        final float[][] retval = new float[floatArrays.length][];
        for (int i = 0; i < floatArrays.length; i++) {
            float [] floats = floatArrays[i];
            retval[i] = new float[floats.length];
            for (int j = 0; j < floats.length; j++) {
                retval[i][j] = mapper.map(floats[j]);
            }
        }
        return retval;
    }

Or in Java 8 and you don't mind using Float

    import java.util.Arrays;
    import java.util.function.Function;

    public static Float[][] map2DArray(Float[][] floatArrays, Function<Float, Float> mapper) {
        return Arrays.stream(floatArrays).map((Float[] floats) -> 
                Arrays.stream(floats).map(mapper).toArray(Float[]::new)
        ).toArray(Float[][]::new);
    }
user104729
  • 58
  • 5