How to execute specific functions with input pattern in F# language - f#

I'm kinda new to F# and trying out a simple calculator app. I take input from the user, and I want to the specific functions to be executed as per the input.
Right now, whenever I take any input from user, the program executes top to bottom. I want it to execute only specific functions matching with the input. Like if input is 6 then body of scientificFun() should be executed. Right now it executes all functions. Please help, I'm kinda stuck on this one!
The code is
open System
let mutable ok = true
while ok do
Console.WriteLine("Choose a operation:\n1.Addition\n2.Substraction\n3.Multiplication\n4.Division\n5.Modulo\n6.Scientific")
let input= Console.ReadLine()
let add =
Console.WriteLine("Ok, how many numbers?")
let mutable count = int32(Console.ReadLine())
let numberArray = Array.create count 0.0
for i in 0 .. numberArray.Length - 1 do
let no = float(Console.ReadLine())
Array.set numberArray i no
Array.sum numberArray
let sub x y = x - y
let mul x y = x * y
let div x y = x / y
let MOD x y = x % y
let scientificFun() =
printfn("1. Exponential")
match input with
| "1" -> printfn("The Result is: %f") (add)
| "6" -> (scientificFun())
| _-> printfn("Choose between 1 and 6")
Console.WriteLine("Would you like to use the calculator again? y/n")
let ans = Console.ReadLine()
if ans = "n" then
ok <- false
else Console.Clear()

You should define add as function: let add() = or let add inputNumbers =
Otherwise this simplified version below only executes the functions corresponding to the input number:
open System
[<EntryPoint>]
let main argv =
// define your functions
let hellofun() =
printfn "%A" "hello"
let worldfun() =
printfn "%A" "world"
let mutable cont = true
let run() = // set up the while loop
while cont do
printfn "%A" "\nChoose an operation:\n 1 hellofunc\n 2 worldfunc\n 3 exit"
let input = Console.ReadLine() // get the input
match input with // pattern match on the input to call the correct function
| "1" -> hellofun()
| "2" -> worldfun()
| "3" -> cont <- false;()
| _ -> failwith "Unknown input"
run() // kick-off the loop
0
The [<EntryPoint>] let main argv = is only necessary if you compile it. Otherwise just execute run().

Related

How can I interpret property based test code?

How can I interpret property based test code?
I'm struggling to translate the instructions on the following snippet:
let myProperty = Prop.forAll fiveAndThrees <| fun number ->
let actual = transform number
let expected = "jbdhjsdhjdsjhsdglsdjlljh"
expected = actual
Check.QuickThrowOnFailure myProperty
Specifically, I'm struggling with the backwards pipeline operator (i.e. "<|").
Here's the test:
[<Fact>]
let ``FizzBuzz.transform returns FizzBuzz`` () =
let fiveAndThrees = Arb.generate<int> |> Gen.map ((*) (3 * 5))
|> Arb.fromGen
let myProperty = Prop.forAll fiveAndThrees <| fun number ->
let actual = transform number
let expected = "jbdhjsdhjdsjhsdglsdjlljh"
expected = actual
Check.QuickThrowOnFailure myProperty
Can someone please guide me step by step on how this code works?
Could this be rewritten using the forward pipe operator (i.e. "|>")?
This answer only covers why <| is used instead of |>.
Here are 5 examples that work toward making use of <| with a large function. The 6th example is to show how the code looks using |> instead of <|. The point is that with the 6th example using |> you have to look into the code to find the primary function funThatNeedsListAndFunc but with <| the primary function funThatNeedsListAndFunc is obvious. So you typically see <| when the last parameter is a function and you want to pass in the function after the primary function for easier comprehension. That's all; don't read more into than that.
After reading the Mark's blog I also learned that <| is useful to remove ( ) around fun. An example using ( ) is given as example 7.
let funThatNeedsListAndFunc list func =
func list
let func = List.sum
let list = Seq.toList { 0 .. 5}
let result1 = funThatNeedsListAndFunc list func
printfn "result1: %A" result1
let result2 = funThatNeedsListAndFunc list <| func
printfn "result2: %A" result2
let result3 = funThatNeedsListAndFunc list <| List.sum
printfn "result3: %A" result3
let result4 = funThatNeedsListAndFunc list <|
fun (list : 'a list) -> List.sum list
printfn "result4: %A" result4
let result5 = funThatNeedsListAndFunc list <|
fun (list : 'a list) ->
// This will be a long function
let a = 1
let b = 2
let c = a * b
let result = List.sum list
let d = "more useless lines"
let (e,f,g) = ("a", 15, 3.0)
result
printfn "result5: %A" result5
.
let result6 =
fun (list : 'a list) ->
// This will be a long function
let a = 1
let b = 2
let c = a * b
let result = List.sum list
let d = "more useless lines"
let (e,f,g) = ("a", 15, 3.0)
result
|> funThatNeedsListAndFunc list
printfn "result6: %A" result6
.
let result7 =
funThatNeedsListAndFunc list (fun (list : 'a list) ->
// This will be a long function
let a = 1
let b = 2
let c = a * b
let result = List.sum list
let d = "more useless lines"
let (e,f,g) = ("a", 15, 3.0)
result)
printfn "result7: %A" result7

Second Taxicab Number Generator

I am attempting to generate a series of guesses for the second Taxicab number. What I want to do is is call the Attempt function on a series of integers in a finite sequence. I have my two questions about implementation in the comments.
A taxi cab number, in case your wondering, is the least number that satisfied the sum of 2 unique cubes in for n unique sets of 2 unique cubes. Ta(2) is 1729.
[<EntryPoint>]
let main argv =
let Attempt (start : int) =
let stop = start+20
let integerList = [start..stop]
let list = List.init 3 (fun x -> integerList.[x])
//Is there a simple way to make initialize the list with random indices of integerList?
let Cube x = x*x*x
let newlist = list |> List.map (fun x -> Cube x)
let partitionList (x : List<int>) (y : int) = List.sum [x.[y];x.[y+1]]
let intLIST = [0..2]
let partitionList' = [for i in intLIST do yield partitionList newlist i]
let x = Set.ofList partitionList'
let y = Set.ofList partitionList'
//I was going to try to use some kind of equality operator to determine whether the two sets were equal, which could tell me whether we had actually found a Taxicab number by the weakened definition.
System.Console.Write(list)
System.Console.Write(newlist)
let rnd = System.Random()
//My primary question is how can I convert a random to an integer to use in start for the function Attempt?
System.Console.ReadKey() |> ignore
printfn("%A") argv
0
Dirty way to initialize list with random indexes of another list:
let randomIndexes count myList =
let rand = System.Random()
seq {
for n = 1 to count do
yield rand.Next(List.length myList) }
|> Seq.distinct
//|> Seq.sort // if you need them sorted
|> List.ofSeq
let result = randomIndexes 5 [3;2;4;5]
printfn "%A" result

Parallel exists function in F#

Motivation
I have a long-running boolean function which should be executed in an array and I want to return immediately if an element in the array satisfies the condition. I would like to do the search in parallel and terminate other threads when the first complete thread returns an correct answer.
Question
What is a good way to implement parallel exists function in F#? Since my goal is performance, an efficient solution is preferred to an easy or idiomatic one.
Test case
Suppose that I want to find whether one value exists in an array or not. And the comparison function (equals) is simulated as a computation-expensive one:
open System.Diagnostics
open System.Threading
// Source at http://parallelpatterns.codeplex.com/releases/view/50473
let doCpuIntensiveOperation seconds (token:CancellationToken) throwOnCancel =
if (token.IsCancellationRequested) then
if (throwOnCancel) then token.ThrowIfCancellationRequested()
false
else
let ms = int64 (seconds * 1000.0)
let sw = new Stopwatch()
sw.Start()
let checkInterval = Math.Min(20000000, int (20000000.0 * seconds))
// Loop to simulate a computationally intensive operation
let rec loop i =
// Periodically check to see if the user has requested
// cancellation or if the time limit has passed
let check = seconds = 0.0 || i % checkInterval = 0
if check && token.IsCancellationRequested then
if throwOnCancel then token.ThrowIfCancellationRequested()
false
elif check && sw.ElapsedMilliseconds > ms then
true
else
loop (i + 1)
// Start the loop with 0 as the first value
loop 0
let inline equals x y =
doCpuIntensiveOperation 0.01 CancellationToken.None false |> ignore
x = y
The array consists of 1000 randomly generated elements and the searching value is guaranteed in the 2nd half of the array (so sequential search has to go through at least a half of the array):
let rand = new System.Random()
let m = 1000
let N = 1000000
let xs = [|for _ in 1..m -> rand.Next(N)|]
let i = rand.Next((m-1)/2, m-1);;
#time "on";;
let b1 = parallelExists (equals xs.[i]) xs;; // Parallel
let b2 = Array.exists (equals xs.[i]) xs;; // Sequential
I think you can take the following steps:
Spawn a number of workers (threads or async computations), and pass each an equal slice of the array and a cancellation token which will be shared by all workers
When a worker finds the searched item, it calls Cancel on the token (each worker should check the cancel state of the token on each iteration and bail if needed)
I don't have time at the moment to write the code, so there could be some detail I'm omitting.
This answer, and related question, may be helpful.
UPDATE
This is an example of what I'm thinking
open System
open System.Collections.Generic
open System.Threading
open System.Threading.Tasks
let getChunks size array =
let rec loop s n =
seq {
if n > 0 then
let r = n - size
if r > 0 then yield (s, size); yield! loop (s + size) r
else yield (s, size + r)
}
loop 0 (Array.length array)
[<Literal>]
let CHUNK_SIZE = 3
let parallelExists f (array:_[]) =
use cts = new CancellationTokenSource()
let rec checkSlice i n =
if n > 0 && not cts.IsCancellationRequested then
if f array.[i] then cts.Cancel()
else checkSlice (i + 1) (n - 1)
let workers =
array
|> getChunks CHUNK_SIZE
|> Seq.map (fun (s, c) -> Task.Factory.StartNew(fun () -> checkSlice s c))
|> Seq.toArray
try
Task.WaitAll(workers, cts.Token)
false
with :? OperationCanceledException -> true
Usage
let array = Array.init 10 id
let exists =
array |> parallelExists (fun i ->
Thread.Sleep(500)
i = 9)
printfn "%b" exists //true
The F# Powerpack has PSeq.exists which maps to PLINQ's ParallelEnumerable.Any which is part of the BCL. There's also ParallelEnumerable.First
I tried to decompile but wouldn't understand right away what was going on. So instead I went and executed the following side-effecting code to confirm that it's using some sort of cancellation once it found the element:
let elems = seq {
for x = 0 to 1000000 do
printfn "test"
yield x }
open System
open System.Linq;;
ParallelEnumerable.First (ParallelEnumerable.AsParallel(elems), Func<_,_>(fun x -> x = 1))

How do you create an F# workflow that enables something like single-stepping?

I'd like to create a builder that builds expressions that returns something like a continuation after each step.
Something like this:
module TwoSteps =
let x = stepwise {
let! y = "foo"
printfn "got: %A" y
let! z = y + "bar"
printfn "got: %A" z
return z
}
printfn "two steps"
let a = x()
printfn "something inbetween"
let b = a()
Where the 'let a' line returns something containing the rest of the expressions to be evaluated later on.
Doing this with a separate type for each number of steps is straightforward but of course not particularly useful:
type Stepwise() =
let bnd (v: 'a) rest = fun () -> rest v
let rtn v = fun () -> Some v
member x.Bind(v, rest) =
bnd v rest
member x.Return v = rtn v
let stepwise = Stepwise()
module TwoSteps =
let x = stepwise {
let! y = "foo"
printfn "got: %A" y
let! z = y + "bar"
printfn "got: %A" z
return z
}
printfn "two steps"
let a = x()
printfn "something inbetween"
let b = a()
module ThreeSteps =
let x = stepwise {
let! y = "foo"
printfn "got: %A" y
let! z = y + "bar"
printfn "got: %A" z
let! z' = z + "third"
printfn "got: %A" z'
return z
}
printfn "three steps"
let a = x()
printfn "something inbetween"
let b = a()
printfn "something inbetween"
let c = b()
And the results are what I'm looking for:
two steps
got: "foo"
something inbetween
got: "foobar"
three steps
got: "foo"
something inbetween
got: "foobar"
something inbetween
got: "foobarthird"
But I can't figure out what the general case of this would be.
What I'd like is to be able to feed events into this workflow, so you could write something like:
let someHandler = Stepwise<someMergedEventStream>() {
let! touchLocation = swallowEverythingUntilYouGetATouch()
startSomeSound()
let! nextTouchLocation = swallowEverythingUntilYouGetATouch()
stopSomeSound()
}
And have events trigger a move to the next step in the workflow. (In particular, I want to play with this sort of thing in MonoTouch - F# on the iPhone. Passing around objc selectors drives me insane.)
the problem with your implementation is that it returns "unit -> 'a" for each call to Bind, so you'll get a different type of result for different number of steps (in general, this is a suspicious definition of monad/computation expression).
A correct solution should be to use some other type, which can represent a computation with arbitrary number of steps. You'll also need to distinguish between two types of steps - some steps just evaluate next step of the computation and some steps return a result (via the return keyword). I'll use a type seq<option<'a>>. This is a lazy sequence, so reading the next element will evaluate the next step of the computation. The sequence will contain None values with the exception of the last value, which will be Some(value), representing the result returned using return.
Another suspicious thing in your implementation is a non-standard type of Bind member. The fact that your bind takes a value as the first parameter means that your code looks a bit simpler (you can write let! a = 1) however, you cannot compose stepwise computation. You may want to be able to write:
let foo() = stepwise {
return 1; }
let bar() = stepwise {
let! a = foo()
return a + 10 }
The type I described above will allow you to write this as well. Once you have the type, you just need to follow the type signature of Bind and Return in the implementation and you'll get this:
type Stepwise() =
member x.Bind(v:seq<option<_>>, rest:(_ -> seq<option<_>>)) = seq {
let en = v.GetEnumerator()
let nextVal() =
if en.MoveNext() then en.Current
else failwith "Unexpected end!"
let last = ref (nextVal())
while Option.isNone !last do
// yield None for each step of the source 'stepwise' computation
yield None
last := next()
// yield one more None for this step
yield None
// run the rest of the computation
yield! rest (Option.get !last) }
member x.Return v = seq {
// single-step computation that yields the result
yield Some(v) }
let stepwise = Stepwise()
// simple function for creating single-step computations
let one v = stepwise.Return(v)
Now, let's look at using the type:
let oneStep = stepwise {
// NOTE: we need to explicitly create single-step
// computations when we call the let! binder
let! y = one( "foo" )
printfn "got: %A" y
return y + "bar" }
let threeSteps = stepwise {
let! x = oneStep // compose computations :-)
printfn "got: %A" x
let! y = one( x + "third" )
printfn "got: %A" y
return "returning " + y }
If you want to run the computation step-by-step, you can simply iterate over the returned sequence, for example using the F# for keyword. The following also prints the index of the step:
for step, idx in Seq.zip threeSteps [ 1 .. 10] do
printf "STEP %d: " idx
match step with
| None _ -> ()
| Some(v) -> printfn "Final result: %s" v
Hope this helps!
PS: I found this problem very interesting! Would you mind if I addapted my answer into a blog post for my blog (http://tomasp.net/blog)? Thanks!
Monads and computation builders confuse the hell out of me, but I've adapted something I've made in an earlier SO post. Maybe some bits and pieces can be of use.
The code below contains an action queue, and a form where the Click event listens to the next action available in the action queue. The code below is an example with 4 actions in succession. Execute it in FSI and start clicking the form.
open System.Collections.Generic
open System.Windows.Forms
type ActionQueue(actions: (System.EventArgs -> unit) list) =
let actions = new Queue<System.EventArgs -> unit>(actions) //'a contains event properties
with
member hq.Add(action: System.EventArgs -> unit) =
actions.Enqueue(action)
member hq.NextAction =
if actions.Count=0
then fun _ -> ()
else actions.Dequeue()
//test code
let frm = new System.Windows.Forms.Form()
let myActions = [
fun (e:System.EventArgs) -> printfn "You clicked with %A" (e :?> MouseEventArgs).Button
fun _ -> printfn "Stop clicking me!!"
fun _ -> printfn "I mean it!"
fun _ -> printfn "I'll stop talking to you now."
]
let aq = new ActionQueue(myActions)
frm.Click.Add(fun e -> aq.NextAction e)
//frm.Click now executes the 4 actions in myActions in order and then does nothing on further clicks
frm.Show()
You can click the form 4 times and then nothing happens with further clicks.
Now execute the following code, and the form will respond two more times:
let moreActions = [
fun _ -> printfn "Ok, I'll talk to you again. Just don't click anymore, ever!"
fun _ -> printfn "That's it. I'm done with you."
]
moreActions |> List.iter (aq.Add)

Help Needed Creating a Binary Tree Given Truth Table

First, in order to provide full disclosure, I want to point out that this is related to homework in a Machine Learning class. This question is not the homework question and instead is something I need to figure out in order to complete the bigger problem of creating an ID3 Decision Tree Algorithm.
I need to generate tree similar to the following when given a truth table
let learnedTree = Node(0,"A0", Node(2,"A2", Leaf(0), Leaf(1)), Node(1,"A1", Node(2,"A2", Leaf(0), Leaf(1)), Leaf(0)))
learnedTree is of type BinaryTree which I've defined as follows:
type BinaryTree =
| Leaf of int
| Node of int * string * BinaryTree * BinaryTree
ID3 algorithms take into account various equations to determine where to split the tree, and I've got all that figured out, I'm just having trouble creating the learned tree from my truth table. For example if I have the following table
A1 | A2 | A3 | Class
1 0 0 1
0 1 0 1
0 0 0 0
1 0 1 0
0 0 0 0
1 1 0 1
0 1 1 0
And I decide to split on attribute A1 I would end up with the following:
(A1 = 1) A1 (A1 = 0)
A2 | A3 | Class A2 | A3 | Class
0 0 1 1 0 1
0 1 0 0 0 0
1 0 1 0 0 0
0 1 1
Then I would split the left side and split the right side, and continue the recursive pattern until the leaf nodes are pure and I end up with a tree similar to the following based on the splitting.
let learnedTree = Node(0,"A0", Node(2,"A2", Leaf(0), Leaf(1)), Node(1,"A1", Node(2,"A2", Leaf(0), Leaf(1)), Leaf(0)))
Here is what I've kind of "hacked" together thus far, but I think I might be way off:
let rec createTree (listToSplit : list<list<float>>) index =
let leftSideSplit =
listToSplit |> List.choose (fun x -> if x.Item(index) = 1. then Some(x) else None)
let rightSideSplit =
listToSplit |> List.choose (fun x -> if x.Item(index) = 0. then Some(x) else None)
if leftSideSplit.Length > 0 then
let pureCheck = isListPure leftSideSplit
if pureCheck = 0 then
printfn "%s" "Pure left node class 0"
createTree leftSideSplit (index + 1)
else if pureCheck = 1 then
printfn "%s" "Pure left node class 1"
createTree leftSideSplit (index + 1)
else
printfn "%s - %A" "Recursing Left" leftSideSplit
createTree leftSideSplit (index + 1)
else printfn "%s" "Pure left node class 0"
Should I be using pattern matching instead? Any tips/ideas/help? Thanks a bunch!
Edit: I've since posted an implementation of ID3 on my blog at:
http://blogs.msdn.com/chrsmith
Hey Jim, I've been wanting to write a blog post implementing ID3 in F# for a while - thanks for giving me an execute. While this code doesn't implement the algorithm full (or correctly), it should be sufficient for getting you started.
In general you have the right approach - representing each branch as a discriminated union case is good. And like Brian said, List.partition is definitely a handy function. The trick to making this work correctly is all in determining the optimal attribute/value pair to split on - and to do that you'll need to calculate information gain via entropy, etc.
type Attribute = string
type Value = string
type Record =
{
Weather : string
Temperature : string
PlayTennis : bool
}
override this.ToString() =
sprintf
"{Weather = %s, Temp = %s, PlayTennis = %b}"
this.Weather
this.Temperature
this.PlayTennis
type Decision = Attribute * Value
type DecisionTreeNode =
| Branch of Decision * DecisionTreeNode * DecisionTreeNode
| Leaf of Record list
// ------------------------------------
// Splits a record list into an optimal split and the left / right branches.
// (This is where you use the entropy function to maxamize information gain.)
// Record list -> Decision * Record list * Record list
let bestSplit data =
// Just group by weather, then by temperature
let uniqueWeathers =
List.fold
(fun acc item -> Set.add item.Weather acc)
Set.empty
data
let uniqueTemperatures =
List.fold
(fun acc item -> Set.add item.Temperature acc)
Set.empty
data
if uniqueWeathers.Count = 1 then
let bestSplit = ("Temperature", uniqueTemperatures.MinimumElement)
let left, right =
List.partition
(fun item -> item.Temperature = uniqueTemperatures.MinimumElement)
data
(bestSplit, left, right)
else
let bestSplit = ("Weather", uniqueWeathers.MinimumElement)
let left, right =
List.partition
(fun item -> item.Weather = uniqueWeathers.MinimumElement)
data
(bestSplit, left, right)
let rec determineBranch data =
if List.length data < 4 then
Leaf(data)
else
// Use the entropy function to break the dataset on
// the category / value that best splits the data
let bestDecision, leftBranch, rightBranch = bestSplit data
Branch(
bestDecision,
determineBranch leftBranch,
determineBranch rightBranch)
// ------------------------------------
let rec printID3Result indent branch =
let padding = new System.String(' ', indent)
match branch with
| Leaf(data) ->
data |> List.iter (fun item -> printfn "%s%s" padding <| item.ToString())
| Branch(decision, lhs, rhs) ->
printfn "%sBranch predicate [%A]" padding decision
printfn "%sWhere predicate is true:" padding
printID3Result (indent + 4) lhs
printfn "%sWhere predicate is false:" padding
printID3Result (indent + 4) rhs
// ------------------------------------
let dataset =
[
{ Weather = "windy"; Temperature = "hot"; PlayTennis = false }
{ Weather = "windy"; Temperature = "cool"; PlayTennis = false }
{ Weather = "nice"; Temperature = "cool"; PlayTennis = true }
{ Weather = "nice"; Temperature = "cold"; PlayTennis = true }
{ Weather = "humid"; Temperature = "hot"; PlayTennis = false }
]
printfn "Given input list:"
dataset |> List.iter (printfn "%A")
printfn "ID3 split resulted in:"
let id3Result = determineBranch dataset
printID3Result 0 id3Result
You can use List.partition instead of your two List.choose calls.
http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/FSharp.Core/Microsoft.FSharp.Collections.List.html
(or now http://msdn.microsoft.com/en-us/library/ee353738(VS.100).aspx )
It isn't clear to me that pattern matching will buy you much here; the input type (list of lists) and processing (partitioning and 'pureness' check) doesn't really lend itself to that.
And of course when you finally get the 'end' (a pure list) you need to create a tree, and then presumably this function will create a Leaf when the input only has one 'side' and it's 'pure', but create a Node out of the left-side and right-side results for every other input. Maybe. I didn't quite grok the algorithm completely.
Hopefully that will help steer you a little bit. May be useful to draw up a few smaller sample inputs and outputs to help work out the various cases of the function body.
Thanks Brian & Chris! I was actually able to figure this out and I ended up with the following. This calculates the information gain for determining the best place to split. I'm sure there are probably better ways for me to arrive at this solution especially around the chosen data structures, but this is a start. I plan to refine things later.
#light
open System
let trainList =
[
[1.;0.;0.;1.;];
[0.;1.;0.;1.;];
[0.;0.;0.;0.;];
[1.;0.;1.;0.;];
[0.;0.;0.;0.;];
[1.;1.;0.;1.;];
[0.;1.;1.;0.;];
[1.;0.;0.;1.;];
[0.;0.;0.;0.;];
[1.;0.;0.;1.;];
]
type BinaryTree =
| Leaf of int
| Node of int * string * BinaryTree * BinaryTree
let entropyList nums =
let sumOfnums =
nums
|> Seq.sum
nums
|> Seq.map (fun x -> if x=0.00 then x else (-((x/sumOfnums) * Math.Log(x/sumOfnums, 2.))))
|> Seq.sum
let entropyBinaryList (dataListOfLists:list<list<float>>) =
let classList =
dataListOfLists
|> List.map (fun x -> x.Item(x.Length - 1))
let ListOfNo =
classList
|> List.choose (fun x -> if x = 0. then Some(x) else None)
let ListOfYes =
classList
|> List.choose (fun x -> if x = 1. then Some(x) else None)
let numberOfYes : float = float ListOfYes.Length
let numberOfNo : float = float ListOfNo.Length
let ListOfNumYesAndSumNo = [numberOfYes; numberOfNo]
entropyList ListOfNumYesAndSumNo
let conditionalEntropy (dataListOfLists:list<list<float>>) attributeNumber =
let NoAttributeList =
dataListOfLists
|> List.choose (fun x -> if x.Item(attributeNumber) = 0. then Some(x) else None)
let YesAttributeList =
dataListOfLists
|> List.choose (fun x -> if x.Item(attributeNumber) = 1. then Some(x) else None)
let numberOfYes : float = float YesAttributeList.Length
let numberOfNo : float = float NoAttributeList.Length
let noConditionalEntropy = (entropyBinaryList NoAttributeList) * (numberOfNo/(numberOfNo + numberOfYes))
let yesConditionalEntropy = (entropyBinaryList YesAttributeList) * (numberOfYes/(numberOfNo + numberOfYes))
[noConditionalEntropy; yesConditionalEntropy]
let findBestSplitIndex(listOfInstances : list<list<float>>) =
let IGList =
[0..(listOfInstances.Item(0).Length - 2)]
|> List.mapi (fun i x -> (i, (entropyBinaryList listOfInstances) - (List.sum (conditionalEntropy listOfInstances x))))
IGList
|> List.maxBy snd
|> fst
let isListPure (listToCheck : list<list<float>>) =
let splitList = listToCheck |> List.choose (fun x -> if x.Item(x.Length - 1) = 1. then Some(x) else None)
if splitList.Length = listToCheck.Length then 1
else if splitList.Length = 0 then 0
else -1
let rec createTree (listToSplit : list<list<float>>) =
let pureCheck = isListPure listToSplit
if pureCheck = 0 then
printfn "%s" "Pure - Leaf(0)"
else if pureCheck = 1 then
printfn "%s" "Pure - Leaf(1)"
else
printfn "%A - is not pure" listToSplit
if listToSplit.Length > 1 then // There are attributes we can split on
// Chose best place to split list
let splitIndex = findBestSplitIndex(listToSplit)
printfn "spliting at index %A" splitIndex
let leftSideSplit =
listToSplit |> List.choose (fun x -> if x.Item(splitIndex) = 1. then Some(x) else None)
let rightSideSplit =
listToSplit |> List.choose (fun x -> if x.Item(splitIndex) = 0. then Some(x) else None)
createTree leftSideSplit
createTree rightSideSplit
else
printfn "%s" "Not Pure, but can't split choose based on heuristics - Leaf(0 or 1)"

Resources