I am using Accord.NET in F# for the first time and I am having problems creating the function to calculate the distance for KNN.
Here is my code
static member RunKNN =
let inputs = MachineLearningEngine.TrainingInputClass
let outputs = MachineLearningEngine.TrainingOutputClass
let knn = new KNearestNeighbors<int*int*int*int>(1,inputs,outputs,null)
let input = 1,1,1,1
knn.Compute(input)
When I swap out the null for a function like this
let distanceFunction = fun (a:int,b:int,c:int,d:int)
(e:int,f:int,g:int,h:int)
(i:float) ->
0
I get an exception like this:
*Error 1 This expression was expected to have type
System.Func<(int * int * int * int),(int * int * int * int),float> but here has type
int * int * int * int -> int * int * int * int -> float -> int*
So far, the only article I found close to my problem is this one. Apparently, there is a problem with how F# and C# handle delegates?
I posted this same question on the Google group for Accord.NET here.
Thanks in advance
Declare the distance function like this:
let distanceFunction (a:int,b:int,c:int,d:int) (e:int,f:int,g:int,h:int) =
0.0
(it takes two tuples in input and returns a float), and then create a delegate from it:
let distanceDelegate =
System.Func<(int * int * int * int),(int * int * int * int),float>(distanceFunction)
Passing this delegate to Accord.NET should do the trick.
I would guess you should use the tuple form like so
let distanceFunction = fun ((a:int,b:int,c:int,d:int),
(e:int,f:int,g:int,h:int),
(i:float)) ->
Related
I have some code wrapping TA-Lib and a lot of the wrappers are very similar:
let sma (timePeriod: int) (data: float[]) =
let mutable outStartIndex = 0
let mutable outNbElement = 0
let mutable smaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)
let retCode = Core.Sma(0, (data.Length - 1), data, timePeriod, &outStartIndex, &outNbElement, smaData)
if retCode <> Core.RetCode.Success then
invalidOp (sprintf "AssertRetCodeSuccess")
let padding = Array.create (timePeriod - 1) System.Double.NaN
Array.append padding smaData
let ema (timePeriod: int) (data: float[]) =
let mutable outStartIndex = 0
let mutable outNbElement = 0
let mutable emaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)
let retCode = Core.Ema(0, (data.Length - 1), data, timePeriod, &outStartIndex, &outNbElement, emaData)
if retCode <> Core.RetCode.Success then
invalidOp (sprintf "AssertRetCodeSuccess")
let padding = Array.create (timePeriod - 1) System.Double.NaN
Array.append padding emaData
What I could like to do is create a generic function where I can just pass the TA-Lib function to call. Something like:
let myGenericFunction (timePeriod: int) (data: float[]) TALibFunc =
let mutable outStartIndex = 0
let mutable outNbElement = 0
let mutable smaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)
let retCode = TALibFunc(0, (data.Length - 1), data, timePeriod, &outStartIndex, &outNbElement, smaData)
if retCode <> Core.RetCode.Success then
invalidOp (sprintf "AssertRetCodeSuccess")
let padding = Array.create (timePeriod - 1) System.Double.NaN
Array.append padding smaData
but the error I am getting is:
[FS0412] A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
Is there a workaround for this? I am not familiar with this issue.
Short answer: replace your mutable parameters with ref.
TA-Lib has a very unfortunate API: those pesky out-parameters (known in F# as byref), they always make trouble. In this case, they cannot be part of a generic type instantiation.
Here's a much shorter example. Consider a good old list<T>. We can make an empty list<int>:
let noInts = [] : list<int>
But what if those ints are byref?
let noRefs = [] : list< byref<int> >
No can do - says the compiler. A type instantiation involves a byref type. This is not permitted by the rules of Common IL. Sorry.
In your case, the last parameter of myGenericFunction is an F# function. In F# functions are represented by the type FSharpFunc<T, R> (where T is argument and R is result). So the type of your last parameter is this:
FSharpFunc< int * int * float array * int * byref<int> * byref<int> * float array, int >
See those two byref<int>s in there? Those are &outStartIndex and &outNbElement. And they are forbidden in a generic instantiation. Tough luck.
But there is hope!
The mutable keyword is only one of two ways to make mutable cells in F#. The other way is ref:
let x = ref 0 // Initialization
printfn "%d" !x // Prints "0"
x := 42 // Mutation
printfn "%d" !x // Prints "42"
It's an old-school thing, predates mutable, is implemented as a library (as opposed to a language construct), and in most cases mutable is better. But this is not one of those cases!
It turns out that:
Unlike true .NET CIL out-parameters, ref cells can be part of generic instantiation just fine. Because, from .NET point of view, they're nothing special - just another class.
The F# compiler has special sauce for them: when the expected type is a ref, but you're trying to pass a function with an out-parameter in its place, the compiler will automatically generate some wrapping code for you.
So, armed with this knowledge, you can modify myGenericFunction like this:
let myGenericFunction (timePeriod: int) (data: float[]) TALibFunc =
let outStartIndex = ref 0
let outNbElement = ref 0
let mutable smaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)
let retCode = TALibFunc(0, (data.Length - 1), data, timePeriod, outStartIndex, outNbElement, smaData)
...
And then the consumers can call it like this:
myGenericFunction 42 [|1; 2; 3|] Core.Sma // Wrapping code gets generated here
I want to assign two variables to integer and decimal parts on double.
how to do it?
One way would be
int x = abc.toInt()
int y = int.tryParse(abc.toString().split('.')[1]);
final double abc = 1.4;
int a = int.parse(abc.toString().split(".")[0]);
int b = int.parse(abc.toString().split(".")[1]);
Try this out, it should work fine
The following function:
let twoInputs x y =
let sum = x + y
let product a = sum * a
product
Has the type:
val twoInputs : x:int -> y:int -> (int -> int)
That's perfectly reasonable, I see why it's coming. But why this function:
let oneInput = twoInputs 1
is of type val oneInput : (int -> int -> int) ?
Shouldn't it be int -> (int -> int) ?
Also, I think the functions above should comply with Associative property, so there should be no differences between int -> int -> (int -> int) and int -> int -> int -> int. If so, why not just specify the latter as the function type for twoInputs?
Parentheses mean "value of type FsharpFunc<_>", while the absence of parentheses means "true CLR method". In your example, twoInput is compiled to a true CLR method, but returns a value of type FSharpFunc<_>, hence its type. But your oneInput is compiled to a class field of type FSharpFunc<_>, and hence its type.
You can actually achieve same effect (i.e. turn true method into value) even without currying, very simply:
> let twoInputs x y =
> let sum = x + y
> let product a = sum * a
> product
> let twoInputsAgain = twoInputs
val twoInputs : x:int -> y:int -> (int -> int)
val twoInputsAgain : (int -> int -> int -> int)
This happens because CLR doesn't support the notion of "assigning a method", so F# has to compile this by declaring twoInputsAgain as a field of type FSharpFunc<_> and then assigning to it an instance of a class that inherits from FSharpFunc<_> and calls twoInputs when Invoked.
If you decompile it to C# (I use ILSpy), this is what you see:
static $Program()
{
$Program.twoInputsAgain#11 = new Program.twoInputsAgain#11();
}
internal class twoInputsAgain#11 : OptimizedClosures.FSharpFunc<int, int, FSharpFunc<int, int>>
{
public override FSharpFunc<int, int> Invoke(int x, int y)
{
return Program.twoInputs(x, y);
}
}
In conclusion, I want to note that this disctinction doesn't matter very much in practice, unless you practice some really dark magic, so you shouldn't worry about it.
I am running into some issues trying to use the Accelerate framework with vDSP API from Swift. Obviously I am doing something wrong although the compiler gives me all sorts of warnings
var srcAsFloat:CConstPointer<CFloat> = CFloat[](count: Int(width*height), repeatedValue: 0)
var dstAsFloat = CFloat[](count: Int(width*height), repeatedValue: 0)
if shouldClip {
var min:CFloat = 0.0
var max:CFloat = 255.0
var l:vDSP_Stride = Int(width*height)
vDSP_vclip(CConstPointer<CFloat>(&dstAsFloat), vDSP_Stride(1), CConstPointer<CFloat>(&min), CConstPointer<CFloat>(&max), CMutablePointer<CFloat>(&dstAsFloat), vDSP_Stride(1), l)
}
The error:
error: could not find an overload for 'init' that accepts the supplied arguments
vDSP_vclip(CConstPointer<CFloat>(&dstAsFloat),
vDSP_Stride(1),
CConstPointer<CFloat>(&min),
CConstPointer<CFloat>(&max),
CMutablePointer<CFloat>(&dstAsFloat),
vDSP_Stride(1),
l) –
I've tried to cast the heck out of it but so far, no luck.
Okay, I figured out a (probably sub-optimal) solution. I decided to bridge to Objective-C (and used a slightly different function).
main.swift
import Foundation
func abs(x: matrix) -> matrix{
let N = x.count
var arg1 = NSArray(array: x)
var yy = abs_objc(arg1, CInt(N))
var y = zeros(N)
for i in 0..N{
y[i] = Double(yy[i])
}
return y
abs_objc.m
#import <Accelerate/Accelerate.h>
double* abs_objc(NSArray * x, int N){
// converting input to double *
double * xx = (double *)malloc(sizeof(double) * N);
for (int i=0; i<[x count]; i++) {
xx[i] = [[x objectAtIndex:i] doubleValue];
}
// init'ing output
double * y = (double *)malloc(sizeof(double) * N);
for (int i=0; i<N; i++){
y[i] = 0;
}
vDSP_vabsD(xx,1,y,1,N);
return y;
}
swix-Bridging-Header.h
#import <Foundation/Foundation.h>
double* abs_objc(NSArray * x, int N);
I've been working with vDSP to just create a general matrix language.
I have found this way to be the easiest to get the correct pointer types.
Hopefully you find it useful (this might not be optimal either but a start).
import Accelerate
func myFunction(width:Float, height:Float) {
var dstAsFloat = CFloat[](count: Int(width*height), repeatedValue: 0)
var min:CFloat = 0.0
var max:CFloat = 255.0
func vclipPointerConversion(dstAsFloat:CMutablePointer<CFloat>) {
vDSP_vclip(CConstPointer<CFloat>(nil,dstAsFloat.value), vDSP_Stride(1),
&min, &max, dstAsFloat, vDSP_Stride(1), CUnsignedLong(width*height))
}
vclipPointerConversion(&dstAsFloat)
//...
// return whatever you wanted
}
I got it to work with a few tweaks. Notice the first param doesn't have an ampersand (CConstPointer). However the second one does (I use the same pointer for src & dst). I also replaced the casting (necessary) of values. You need to use CFloats for ceiling values. Here is the code:
let width: UInt = CGBitmapContextGetWidth(context)
let height: UInt = CGBitmapContextGetHeight(context)
var dstAsFloat = CFloat[](count: Int(width*height), repeatedValue: 0)
if shouldClip {
var min:CFloat = 0.0
var max:CFloat = 255.0
vDSP_vclip(dstAsFloat, CLong(1), &min, &max, &dstAsFloat, CLong(1), UInt(width*height))
}
How do I go about using the TryTake method on a BlockingCollection<'a> passing in a timeout period in milliseconds?
Heres the signature:
BlockingCollection.TryTake(item: byref, millisecondsTimeout: int) : bool
is it possible to use the Tuple method of avoiding passing a ref type like on the Dictionary.TryGet methods?
i.e.
let success, item = myDictionary.TryGetValue(client)
Im struggling with this particular signature, any suggestions would be great.
Cheers!
I believe that you can only use that technique for byref parameters which occur at the end of the parameter list (this is similar to the rule for optional parameters). So if BlockingCollection.TryTake were defined with signature int * 'T byref -> bool it would work, but since it's defined as 'T byref * int -> bool it won't.
For example:
open System.Runtime.InteropServices
type T =
static member Meth1(a:int, [<Out>]b:string byref, [<Out>]c:bool byref) : char =
b <- sprintf "%i" a
c <- a % 2 = 0
char a
static member Meth2([<Out>]b:string byref, [<Out>]c:bool byref, a:int) : char =
b <- sprintf "%i" a
c <- a % 2 = 0
char a
// ok
let (r,b,c) = T.Meth1(5)
// ok
let (r,c) = T.Meth1(5,ref "test")
// ok
let r = T.Meth1(5, ref "test", ref true)
// doesn't compile
let (r,b,c) = T.Meth2(5)
// doesn't compile
let (r,c) = T.Meth2(ref "test", 5)
// ok
let r = T.Meth2(ref "test", ref true, 5)