Computer Science Experimentation

Thursday, December 15, 2011

Silverlight and F#

The following example is a Silverlight application using F#.

The server and client are written in F# (except for a standard one line code in C# to register the event handlers). So, basically, only one language is used for all parts.

The UI is separated from the logic and it is developed using Visual Studio XAML editor (WYSIWYG).

The application is a simple Hello-World using a Button and a TextBlock.

But, the example is quite generic because it allows cross-domain network access. It means that the web-page and the web-service can be hosted by multiple and different servers.

The client solution is composed by three projects, one Silverlight Application (C#), one Silverlight Class Library (C#) and one F# Library, as follow.

An F# script is used to define programmatically a self-hosted server. Check the full article at:

https://skydrive.live.com/#!/view.aspx?cid=BDC87EF39B001785&resid=BDC87EF39B001785%21285

Thursday, June 9, 2011

WCF Excel Client using F#/Excel Automation

 
These previous posts presented examples of a data/historian server using WCF and F#:
This post extends these examples with a WCF Excel client using F#/Excel Automation.

 
Check the following link for documentation and script code:
http://cid-bdc87ef39b001785.office.live.com/view.aspx/Fsharp/WCF%5E_Excel%5E_Client%5E_1.docx

Monday, May 23, 2011

Data and Historian Service using WCF and F# interactive - rev 2

This blog presents the revision 2 from the material from the blog:
WCF with F# interactive – Data Server example - Dec/25/2010
http://caxelrud.blogspot.com/2010/12/wcf-with-f-interactive-data-server.html
These are the improvements:
- The data value is of type Object. The examples show how to work with basic types as float, integer, strings and other types as dateTime. It can also use array of the basic types.
- The data server also stores status and time-stamp.
- The data server optionally can operate as a historian using an in-memory circular buffer storing values (objects), status and time-stamps.

Check the code and examples at:
http://cid-bdc87ef39b001785.office.live.com/view.aspx/Fsharp/DataServer%5E_doc%5E_1%5E_0.docx

Thursday, May 5, 2011

F# interactive - how to hide/show the console

The F# interactive allows great object visibility and interactive capabilities even in running applications like server processes. So, it is a good idea to keep the F# interactive console available even in production versions of the code. But, it is not acceptable to leave several consoles open in the computer screen. The idea of this document is to show that consoles can be hidden and be shown as needed.
The following code shows how to manage application (start) and hide/show the F# interactive console applications.

//module ApplMgm

open System
open System.Diagnostics
open System.Collections.Generic
open System.Runtime.InteropServices;

System.Console.Title<-"AppMgm"

[< dllimport("user32.dll")>]
extern IntPtr FindWindow(string lpClassName,string lpWindowName);
[<dllimport("user32.dll")>]
extern bool ShowWindow(IntPtr hWnd, int nCmdShow)

let fsharpPath= @"C:\Program Files (x86)\Microsoft F#\v4.0\fsi.exe"

type Process={Path:string;ExecName:string;ConsoleName:string}

type AppMgm()=
    let mutable applications= new Dictionary()
    let fsharpPath= @"C:\Program Files (x86)\Microsoft F#\v4.0\fsi.exe"

    member this.Apps with get() = applications and set a = applications <- a
    member this.fsharpFullPath= @"C:\Program Files (x86)\Microsoft F#\v4.0\fsi.exe"
    member this.start(keyName:string) =
        let procPath=applications.[keyName].Path
        let procName=applications.[keyName].ExecName
        Process.Start(fsharpPath,@"--readline+ --load:"+"\""+procPath+procName+"\"") |>ignore
        ()
    member this.hide(keyName:string) =
        let consName=applications.[keyName].ConsoleName
        let hWnd = FindWindow(null, consName) 
        if (hWnd <> 0n) then
            let b1=ShowWindow(hWnd, 0); // 0 = SW_HIDE
            ()        
    member this.show(keyName:string) =
        let consName=applications.[keyName].ConsoleName
        let hWnd = FindWindow(null, consName) 
        if (hWnd <> 0n) then
            let b1=ShowWindow(hWnd, 1); // 1 = SW_SHOWNORMA
            ()        
//--------------------------------------------------------------------------------------------------
//Configuration
let A= new AppMgm()
let d= new Dictionary()
let projPath= @"C:\Users\caxelrud\Documents\Visual Studio 2010\Projects\Utilities\"

d.Add("ap1",{Path=projPath;ExecName="app_1.fsx";ConsoleName="Application1"})
d.Add("ap2",{Path=projPath;ExecName="app_2.fsx";ConsoleName="Application2"})
//d.["ap2"]
A.Apps<-d
//A.Apps

A.start("ap1")
A.hide("ap1")
A.show("ap1")

Friday, February 18, 2011

F# Linear Algebra with Blas and Lapack

I am testing the F# MathProvider library (http://mathprovider.codeplex.com/).
Mathprovider site has a very interesting section called "About the Performance" that I recommend.


For now, I tried the following sample code with no problems.
// reference F# PowerPack & MathProvider
#r @"FSharp.PowerPack.dll"
//#r @"D:\FSharp\math-provider\MathProvider\MathProvider\bin\Release\MathProvider.dll"
#r @"C:\cs\Others\MathProvider\Net 4.0\MathProvider.dll"
#time

// rename the module name
module L = MathProvider.LinearAlgebra

// set the directory of the Lapack runtime (blas.dll & lapack.dll)
System.Environment.CurrentDirectory <- @"C:\cs\Others\MathProvider\LapackRuntime"
//System.Environment.CurrentDirectory <- @"D:\FSharp\math-provider\LapackRuntime\Netlib" 
//System.Environment.CurrentDirectory <- @"D:\FSharp\math-provider\LapackRuntime\MKL"

// start the native provider, otherwise (implementent) F# implementation will be used
L.startProvider()

// create two 3x3 matrices
let A = matrix [ [12.; -51.; 4.; ]; [6.; 167.; -68.;]; [-4.; 24.; -41.; ] ]
let B = matrix [ [ 2.; 1.; 1.;] ; [ 1.; 2.; 1.;]; [ 1.; 1.; 2.;] ]

// determinant 
let det = L.det A
// inverse
let inv = L.inv A
// qr decomposition
let q, r  = L.qr  A
// lu decomposition
let p, l, u  = L.lu  A
// cholesky decomposition
let ch  = L.chol B
// svd decomposition
let v, s, ut = L.svd A
// eigen decomposition for symetric matrix
let a, b = L.cov A A  |> L.eigenSym 

(* result *)

(*
val A : matrix = matrix [[12.0; -51.0; 4.0]
                         [6.0; 167.0; -68.0]
                         [-4.0; 24.0; -41.0]]
val B : matrix = matrix [[2.0; 1.0; 1.0]
                         [1.0; 2.0; 1.0]
                         [1.0; 1.0; 2.0]]
val det : float = -85750.0
val inv : matrix = matrix [[0.06081632653; 0.02326530612; -0.03265306122]
                           [-0.006040816327; 0.005551020408; -0.009795918367]
                           [-0.009469387755; 0.0009795918367; -0.02693877551]]
val r : matrix = matrix [[-14.0; -21.0; 14.0]
                         [0.0; -175.0; 70.0]
                         [0.0; 0.0; -35.0]]
val q : matrix = matrix [[-0.8571428571; 0.3942857143; 0.3314285714]
                         [-0.4285714286; -0.9028571429; -0.03428571429]
                         [0.2857142857; -0.1714285714; 0.9428571429]]
val u : matrix = matrix [[12.0; -51.0; 4.0]
                         [0.0; 192.5; -70.0]
                         [0.0; 0.0; -37.12121212]]
val p : (int -> int)
val l : matrix = matrix [[1.0; 0.0; 0.0]
                         [0.5; 1.0; 0.0]
                         [-0.3333333333; 0.03636363636; 1.0]]
val ch : matrix = matrix [[1.414213562; 0.7071067812; 0.7071067812]
                          [0.0; 1.224744871; 0.4082482905]
                          [0.0; 0.0; 1.154700538]]
val v : matrix = matrix [[-0.2543778627; -0.5139835724; -0.81921474]
                         [0.9464104305; 0.0419982359; -0.3202240549]
                         [0.1989954776; -0.8567712854; 0.4757559925]]
val ut : matrix = matrix [[0.00960262784; 0.922507462; -0.385859783]
                          [-0.07574450365; 0.3854399898; 0.9196188256]
                          [-0.9970810196; -0.0203960004; -0.0735761066]]
val s : Vector = vector [|190.5672437; 32.85688323; 13.69492038|]
val b : Matrix = matrix [[0.9970810196; -0.07574450365; -0.00960262784]
                                [0.0203960004; 0.3854399898; -0.922507462]
                                [0.0735761066; 0.9196188256; 0.385859783]]
val a : vector = vector [|187.5508443; 1079.574776; 36315.87438|]
*)

Thursday, February 17, 2011

Dynamic Compilation and Execution using F#


Dynamic Compilation and Execution using F#
Celso Axelrud
Feb/17/2011

The following example shows how to compile a module from a string inside an executable and make it available to be used by the same executable.
For better understanding of the steps, the example uses F# interactive.

Here is the code:
#r "FSharp.Compiler.dll" 
#r "FSharp.Compiler.CodeDom.dll" 
#I @"C:\Users\caxelrud\Documents\Visual Studio 2010\Projects\NLMPC" 
open System 
open System.IO 
open System.CodeDom.Compiler 
open Microsoft.FSharp.Compiler.CodeDom 

(* For this example, copy Fsharp.Core.* from C:\Program Files (x86)\Reference Assemblies\Microsoft\FSharp\2.0\Runtime\v4.0 and FSharp.Powerpack.dll to the local directory*)

let CompileFSharpString(str, assemblies, output) = 
        use pro = new FSharpCodeProvider() 
        let opt = CompilerParameters(assemblies, output) 
        let res = pro.CompileAssemblyFromSource( opt, [|str|] ) 
        printfn "%A" res.Errors
        if res.Errors.Count = 0 then  
             Some(FileInfo(res.PathToAssembly))  
        else None ;;
 
let (++) v1 v2   = Path.Combine(v1, v2)
let path= @"C:\Users\caxelrud\My Documents\Visual Studio 2010\Projects\NLMPC"    
let defaultAsms  = [|path++"System.dll"; path++"FSharp.Core.dll"; path++"FSharp.Powerpack.dll"|]  
let randomFile() = path ++ Path.GetRandomFileName() + ".dll";;    
//let randomFile() = __SOURCE_DIRECTORY__ ++ Path.GetRandomFileName() + ".dll"    
 
type System.CodeDom.Compiler.CodeCompiler with  
    static member CompileFSharpString (str, ?assemblies, ?output) = 
        let assemblies  = defaultArg assemblies defaultAsms 
        let output      = defaultArg output (randomFile())
        printfn "%A %s" assemblies output  
        CompileFSharpString(str, assemblies, output);;      
 
// Module definition 
let library = "  
module Temp.Main 
let f(x,y) = sin x + cos y 
" ;;

// Create the assembly 
let fileinfo = CodeCompiler.CompileFSharpString(library);; 
 
// Just testing in the interactive env. 
#r "zmm30vu5.eqq.dll" 

let a = Temp.Main.f(0.5 * Math.PI, 0.0);;     // val a : float = 2.0 
 
// Purely reflective invocation of the function. 
let asm = Reflection.Assembly.LoadFrom(fileinfo.Value.FullName) 
let mth  = asm.GetType("Temp.Main").GetMethod("f") 
 
// Wrap weakly typed function with strong typing. 
let f(x,y) = mth.Invoke(null, [|box (x:float); box (y:float)|]) :?> float;; 

// Call the function 
let b = f (0.5 * Math.PI, 0.0);;              // val b : float = 2.0 

Sunday, January 30, 2011

Linear Programming in F#

Linear Programming in F#


Celso Axelrud
Jan/30/2011



Introduction

This document presents a Linear Programming function developed in F# and executed in the interactive environment.
I am targeting small LP programs on very fast computers.
I selected the simplest and shortest code from all references. It means that has no linear algebra operation and not subroutine calls.

The F# code presented here is based on the subroutine Linpro.
Fortran version at:
http://www.sie.arizona.edu/faculty/addenda/yak/SIE270/for/linpro
Pascal version at:
http://www.sie.arizona.edu/faculty/addenda/yak/SIE270/pas/linpro.pas

There are other references to a subroutine Linpro but it is not the same code.
Fortran version at:
http://www.slac.stanford.edu/accel/ilc/codes/lcopt/source/linpro.f
Python version at:
http://adorio-research.org/wordpress/?p=194

Source Code and Results
(*
 Linpro - this function computes the solution of a linear programming     
           problem by using the Simplex method.  The Objective function    
           is maximized.  Parameters a,b, and c are presumed transmitted   
           as  global variables  declared in the calling program           
  Usage:                                                                   
           Linpro n m1 m2 m3                                

  Parmeters:                                                               
           a = matrix of coefficients (global)                             
           b = right hand side vector (global)                             
           c = coefficients of the objective function(global)              
           Input:                                                          
                 n = number of variables                                   
                 m1 = number of constraints of the Le type                 
                 m2 = number of constraints of the Eq type                 
                 m3 = number of constraints of the Ge type                 
           Output:                                                         
                 x.[i] = i-th component of the optimal solution             
                        for i = 1, ... ,N                                  
                 x.[n+1] = optimal value of the objective function          
                 Kod = key showing the category of the Lp problem          
                       if Kod = 1 then an optimal exists                   
                       if Kod = 2 then no feasible solution exists         
                       if Kod = 3 then the objective function is not       
                                bounded                                    
  Remarks:                                                                 
           matrix a needs to be re-assign before calling the function again    
  Conditions:                                                              
           M1+M2+M3 must be less then or equal to 50                       
           N must not be larger then 50 unless the subroutine is           
           redimenstion                                                    
  Example:
    Maximize Z = f(x,y) = 3x + 2y 
    subject to: 2x + y ≤ 18 
        2x + 3y ≤ 42 
        3x + y ≤ 24 
        x ≥ 0 , y ≥ 0 
  result:
    (x,y) = (3,12)
    Z=33
*)


let a:float[,]= Array2D.zeroCreate 52 151
let b:float[]= Array.zeroCreate 50
let c:float[]= Array.zeroCreate 50



//Linpro
let Linpro n m1 m2 m3  =
    let x:float array = Array.zeroCreate 50
    let mutable i,i0,i1,i2=0,0,0,0
    let mutable j,j0,j1,j2,L=0,0,0,0,0
    let mutable L1,L2,L3,Kod=0,0,0,0
    let mutable m4,m5,mm,n1,n5,nm,nn=0,0,0,0,0,0,0
    let mutable key=0
    let mutable ifirst=0 
    let mutable u=0.0
    let mutable Key=0
    let eps=1.0e-3
    let kk:int array = Array.zeroCreate 150
    //Load up the initial tableau with slack and artificial
    //variables, original and secondary objective functions
    L1<- n + 1
    L2<- m1+m2+m3+1
    n1<- n + 1
    //set the size of the appended matrix
    mm<- m1+m2+m3+2
    nn<- n+m1+m2+(2*m3)+1
    //initialize both objectives to zero 
    for i= L2 to mm do
        for j= 1 to nn do
            a.[i,j]<- 0.0
    L3<- m1+m2+m3
    // initialize all slack and artificial coefficients to zero
    for i= 1 to L3 do
        for j= L1 to nn do
              a.[i,j]<- 0.0
    L<-n
    if m1 > 0 then
        // Fix slack coefficients for Le constraints
        for i= 1 to m1 do
            a.[i,L+i]<- 1.0
        L<- L + m1
    if m3 > 0 then 
        // Fix slack coefficients for Ge constraints
        for i= 1 to m3 do 
            i1<-m1+m2+i
            a.[i1,L+i]<- -1.0
        L<- L + m3
    m4<- m2 + m3
    if (m4 > 0) then
       // Fix artificial coefficient for for Eq and Ge constraints 
        for i= 1 to m4 do
            a.[m1+i,L+i]<- 1.0
    m5<- mm - 1
    // Place the objective function 
    for j= 1 to n do
        a.[m5,j]<- c.[j]
    i2<- m1+m2+m3;
    if (m4 > 0) then
        i1<- m1 + 1
        //construct the secondary objective function 
        for j= 1 to n do
            for i= i1 to i2 do
                a.[mm,j]<- a.[mm,j] + a.[i,j]
            j1<- n+m1+1
            j2<- n+m1+m3
            if (m3 > 0) then
                for j= j1 to j2 do
                    a.[mm,j]<- -1.0
            for i= i1 to i2 do
                a.[mm,nn]<- a.[mm,nn] + b.[i]
    for i= 1 to i2 do
        a.[i,nn]<- b.[i]
    a.[m5,nn]<- 0.0
    // Load up the initial basic solution 
    if (m1 > 0) then
        for i= 1 to m1 do
            kk.[i]<- i + n
    if (m4 > 0) then 
        i1<- m1 + 1
        for i= i1 to i2 do
            kk.[i]<- n+m1+m3+i-i1+1
    else
        //If no constraint of Eq and Gt type, then no secondary
        //  objective function is needed 
        mm<- mm - 1
    ifirst<- 0
    u<- 0.0
    while (ifirst = 0) || (u > eps) do 
        ifirst<- 1
        n5<- nn - 1;
        // Check for the pivot element find the largest
        // coefficient of the objective 
        u<-a.[mm,1]
        j0<- 1
        for j= 1 to n5 do
            if (a.[mm,j] > u) then
                u<- a.[mm,j]
                j0<- j
        if (u > eps) then 
            Key<- 0
            i0<- 0
            while (Key = 0) && (i0 <= i2) do
                i0<- i0 + 1
                if (a.[i0,j0] >= eps) then Key<- 1
            // Test if there is a positive a[i,j] in this column
            // if not then the objective function is bounded
            if (Key = 0) then
                Kod<- 3
                //goto 10;
            else
                if (i0 < i2) then
                    i1<- i0 + 1
                    u<- a.[i0,nn]/a.[i0,j0]
                    for i= i1 to i2 do
                        if (a.[i,j0] >= eps) then
                            if ((a.[i,nn]/a.[i,j0]) < u) then
                                i0<- i
                                u<- a.[i,nn]/a.[i,j0]
                //Perform the elimination step 
                u<- a.[i0,j0]
                for j= 1 to nn do
                    a.[i0,j]<- a.[i0,j]/u
                for i= 1 to mm do
                    if (i <> i0) then
                        for j= 1 to nn do
                            if (j <> j0) then
                                a.[i,j]<- a.[i,j]-a.[i0,j]*a.[i,j0]
                for i= 1 to mm do
                    if (i <> i0) then
                        a.[i,j0]<- 0.0;
                //Register the newest basis vector and go back to
                //perform the next step of elimination 
                kk.[i0]<- j0
        else if (m4 > 0) then
                L<- n+m1+m3;
                // Check for feasible solution from the secondary
                //objective 
                for i= 1 to i2 do
                    if (kk.[i] > L) then
                        Kod<- 2
                        //goto 10;
                if Kod<>2 then     
                    mm<- mm - 1
                    // Remove artificail variables and the secondary
                    //objective function
                    m4<- 0
                    nm<- nn-m2-m3
                    for i= 1 to mm do
                        a.[i,nm]<- a.[i,nn]
                    nn<- nm
                    ifirst<- 0
                //From here we go back to continue elimination 
    if Kod<>2 || Kod<>3 then Kod<- 1
        // Set up the optimal solution 
    for i= 1 to n do
        x.[i]<- 0.0
    for i= 1 to i2 do
        j<- kk.[i];
        x.[j]<- a.[i,nn]
    x.[n+1]<- -a.[mm,nn]
    x,Kod
    
(*
//Example 1
let n=2
let m1=3
let m2,m3=0,0

c.[1..2]<-[|3.0;2.0|]
b.[1..3]<-[|18.0;42.0;24.0|]

a.[1..3,1..2]<-array2D [[2.0;1.0];[2.0;3.0];[3.0;1.0]]

let r=Linpro n m1 m2 m3

printfn "LP category: %i" (snd r)
printfn "LP Objective Function: %A" ((fst r).[3])
printfn "LP Varaibles: %A" ((fst r).[1..2])

(*
> 
LP category: 0
LP Objective Function: 33.0
LP Varaibles: [|3.0; 12.0|]
*)
*)

//Example 2
(*
R = –2x + 5y, subject to:  
x <= 200
y <= 170
x >= 100
y >= 80  
y + x >= 200 
Solution: x=100,y=170
*)
let n=2
let m1=2
let m2=0
let m3=3

c.[1..2]<-[|-2.0;5.0|]
b.[1..3]<-[|200.0;170.0;100.0;80.0;200.0|]

a.Initialize()
a.[1..5,1..2]<-array2D [[1.0;0.0];[0.0;1.0];[1.0;0.0];[0.0;1.0];[1.0;1.0]]

let r=Linpro n m1 m2 m3

printfn "LP category: %i" (snd r)
printfn "LP Objective Function: %A" ((fst r).[3])
printfn "LP Varaibles: %A" ((fst r).[1..2])