Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# write value in multidimensional array

Tags:

arrays

f#

I am trying to calculate covariance matrix

The operator 'expr.[idx]' has been used on an object of indeterminate type based on information prior to this program point. Consider adding further type constraints

CovMatrix.[a,b]

How to fix this and why it happens?

let FirstSeq = {1.0..10.0}
let SecondSeq = {20.0..30.0}

let All = seq {yield (0,FirstSeq); yield (1,SecondSeq)}

let cov(first:seq<float>)(second:seq<float>) =
    Seq.map2 (*) first second
    |> Seq.average
    |> fun x -> x - Seq.average first * Seq.average second

let CreateCovMatrix(strangeList:seq<int * seq<float>>) = 
    let Size = Seq.length strangeList
    let CovMatrix = Array2D.init Size Size
    let CalculateCovMatrix = 
        for (a, i) in strangeList do
            for (b, j) in strangeList do
                    CovMatrix.[a,b]=cov(i)(j)
    CalculateCovMatrix

let result = CreateCovMatrix(All)
printf "%A" result
like image 517
A191919 Avatar asked Sep 20 '26 09:09

A191919


2 Answers

The function Array2D.init takes 3 parameters, you're missing the last one, which is the initialization function.

You can quick-fix it by writing:

let CovMatrix = Array2D.init Size Size (fun _ _ -> 0.)

Then you'll discover the next problem: assignment for mutable references is the <- operator, not = which is for comparison and let bindings.

So your function will look like this:

let CreateCovMatrix(strangeList:seq<int * seq<float>>) = 
    let Size = Seq.length strangeList
    let CovMatrix = Array2D.init Size Size (fun _ _ -> 0.)
    let CalculateCovMatrix = 
        for (a, i) in strangeList do
            for (b, j) in strangeList do
                    CovMatrix.[a,b] <- cov(i)(j)
    CalculateCovMatrix

But instead of specifying a function that ignores the inputs and return always zero, you can use the function Array2D.zeroCreate :

let CovMatrix = Array2D.zeroCreate Size Size
like image 57
Gus Avatar answered Sep 22 '26 01:09

Gus


This kind of math is where functional programming excels, although you're currently residing in the imperative paradigm. Gustavo handled your warnings, but even so your function won't give the desired result. Mixing functional and imperative concepts CreateCovMatrix now returns unit.

Good imperative:

let createCovMatrix(strangeList:seq<int * seq<float>>) = 
    let size = Seq.length strangeList
    let covMatrix = Array2D.zeroCreate size size
    for (a, i) in strangeList do
        for (b, j) in strangeList do
            covMatrix.[a,b]<-cov(i)(j)
    covMatrix

Going functional:

let createCovMatrix strangeList = 
    strangeList 
    |> Seq.map (fun (a, i) -> Seq.map (fun (b, j) -> cov i j) strangeList)
    |> array2D

Multi functional:

let createCovMatrix strangeList = 
    let mapper f = Seq.map f strangeList
    mapper (fun (a, i) -> mapper (fun (b, j) -> cov i j))
    |> array2D
like image 22
Funk Avatar answered Sep 21 '26 23:09

Funk