Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# to F#: Creating and using a float[][] in F#

I have this simple method for a neural network in C#:

  private void InitNeurons()
    {
        //Neuron Initilization
        List<float[]> neuronsList = new List<float[]>();

        for (int i = 0; i < _layers.Length; i++) //run through all layers
        {
            neuronsList.Add(new float[_layers[i]]); //add layer to neuron list
        }

        _neurons = neuronsList.ToArray(); //convert list to array
    }

How do I do this in F#? I was thinking it could be simpler. Perhaps something like this?

namespace NeuralNetwork

type NeuralNetworkF(layers : int[]) = 
    member this.Layers = layers
    member this.Neurons : float[][] = [| for layer in layers do new float[]|]

This causes a compiler error in F#. I want to take the size of the int array "_layers" and for each value iterate over and add that value to the Neurons member in F#.

like image 532
Chris Evans Avatar asked Jan 04 '23 16:01

Chris Evans


2 Answers

The way you're trying to create an array new float[] is not valid syntax in F#. The correct syntax for an array is [| 1; 2; 3 |], or for empty array it would be just [| |]. The type of elements does not need to be specified, the compiler will infer it from the context. But if you really want to be explicit, you can still specify the type via a colon, like you can with any expression: [| |] : float[].

However, that is all useless to you anyway, because what you're trying to do is not create an array with known elements, but create an array of a known length. For that, there are a few functions, and the one that would be useful to you here is Array.create. It takes two arguments - the size and the value, - and it returns an array of that size, where every element is that value.

type NeuralNetworkF(layers : int[]) = 
    member this.Layers = layers
    member this.Neurons : float[][] = [| for layer in layers -> Array.create layer 0.0 |]

Note that in the code above I've also replaced do with ->. This is the second problem you had. You see, do performs an "action", which does not necessarily result in an item, e.g.:

let xs = [ for n in 1..10 do 
             if n > 5 then yield n ]

This will produce a list of numbers 6 to 10 - not 1 to 10 - because it only produces an element when n > 5. The yield keyword is what produces an element. So, if you wanted to produce an array for every layer in your code, you'd have to yield that array:

[| for layer in layers do yield Array.create layer 0.0 |]

This works, but there is a shortcut: the arrow -> stands for do yield, so you can use it instead.

[| for layer in layers -> Array.create layer 0.0 |]

Finally, a question to you: do you really need a class? Classes are wibbly-wobbly-timey-whimey, so unless you have a good reason, I recommend going with a record.

like image 159
Fyodor Soikin Avatar answered Jan 20 '23 15:01

Fyodor Soikin


Nice explanation there, @FyodorSoikin, but the following is probably even nicer:

let newNeuralNetwork (layers : _ []) =
    fun i -> Array.zeroCreate<float> layers.[i]
    |> Array.init layers.Length
like image 28
dumetrulo Avatar answered Jan 20 '23 14:01

dumetrulo