From c818f441bbb508ce4b4306421361d5339c46fe8f Mon Sep 17 00:00:00 2001 From: Jurgen Van Gael Date: Sat, 15 Aug 2009 16:59:22 +0800 Subject: [PATCH] Added initial F# interface. Signed-off-by: jvangael --- src/FSharp/DenseVector.fs | 48 +++++ src/FSharp/FSharp.fsproj | 59 ++++++ src/FSharp/Main.fs | 37 ++++ src/FSharpExamples/DenseVector.fs | 11 + src/FSharpExamples/FSharpExamples.fsproj | 63 ++++++ src/FSharpUnitTests/FSharpUnitTests.fsproj | 64 ++++++ src/FSharpUnitTests/FsUnit.fs | 222 +++++++++++++++++++++ src/FSharpUnitTests/Program.fs | 19 ++ src/MathNet.Numerics.sln | 18 ++ 9 files changed, 541 insertions(+) create mode 100644 src/FSharp/DenseVector.fs create mode 100644 src/FSharp/FSharp.fsproj create mode 100644 src/FSharp/Main.fs create mode 100644 src/FSharpExamples/DenseVector.fs create mode 100644 src/FSharpExamples/FSharpExamples.fsproj create mode 100644 src/FSharpUnitTests/FSharpUnitTests.fsproj create mode 100644 src/FSharpUnitTests/FsUnit.fs create mode 100644 src/FSharpUnitTests/Program.fs diff --git a/src/FSharp/DenseVector.fs b/src/FSharp/DenseVector.fs new file mode 100644 index 00000000..5126d7f0 --- /dev/null +++ b/src/FSharp/DenseVector.fs @@ -0,0 +1,48 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// +// Copyright (c) 2009 Math.NET +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics + +open MathNet.Numerics.LinearAlgebra + +/// A module which implements functional dense vector operations. +module DenseVector = + + /// Initialize a vector by calling a construction function for every element. + let inline init (n: int) f = + let v = new Double.DenseVector(n) + for i=0 to n-1 do + v.[i] <- f i + v + + /// Create a vector from a float list. + let inline of_list (fl: float list) = + let n = List.length fl + let v = Double.DenseVector(n) + fl |> List.iteri (fun i f -> v.[i] <- f) + v \ No newline at end of file diff --git a/src/FSharp/FSharp.fsproj b/src/FSharp/FSharp.fsproj new file mode 100644 index 00000000..69c3e408 --- /dev/null +++ b/src/FSharp/FSharp.fsproj @@ -0,0 +1,59 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {37e8e802-a354-4114-bfc1-6e1357da605b} + Library + FSharp + MathNet.Numerics.FSharp + v3.5 + FSharp + + + true + full + false + false + bin\Debug\ + DEBUG;TRACE + 3 + + + pdbonly + true + true + bin\Release\ + TRACE + 3 + + + + + + + 3.5 + + + + + Numerics + {b7cae5f4-a23f-4438-b5be-41226618b695} + True + + + + + + + + + \ No newline at end of file diff --git a/src/FSharp/Main.fs b/src/FSharp/Main.fs new file mode 100644 index 00000000..2a6bfe62 --- /dev/null +++ b/src/FSharp/Main.fs @@ -0,0 +1,37 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// +// Copyright (c) 2009 Math.NET +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics + +open MathNet.Numerics.LinearAlgebra.Double + +/// A module which implements some F# utility functions. +module FSharp = + + /// Construct a dense vector from a list of floating point numbers. + let inline vector (lst: list) = DenseVector.of_list lst :> Vector \ No newline at end of file diff --git a/src/FSharpExamples/DenseVector.fs b/src/FSharpExamples/DenseVector.fs new file mode 100644 index 00000000..bd2a1280 --- /dev/null +++ b/src/FSharpExamples/DenseVector.fs @@ -0,0 +1,11 @@ +open MathNet.Numerics.FSharp +open MathNet.Numerics.LinearAlgebra + +/// Create a new 100 dimensional dense vector. +let v = DenseVector.init 100 (fun i -> float i / 100.0) + +/// Another way to create a 100 dimensional dense vector is as follows. +let w = vector (List.init 100 (fun i -> float i ** 2.0)) + +/// Perform some binary arithmetic on vectors. +let x = v + w \ No newline at end of file diff --git a/src/FSharpExamples/FSharpExamples.fsproj b/src/FSharpExamples/FSharpExamples.fsproj new file mode 100644 index 00000000..e264d823 --- /dev/null +++ b/src/FSharpExamples/FSharpExamples.fsproj @@ -0,0 +1,63 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {bc81ea37-8ee6-4bf9-b8a9-b30497aef8b1} + Library + FSharpExamples + FSharpExamples + v3.5 + FSharpExamples + + + true + full + false + false + bin\Debug\ + DEBUG;TRACE + 3 + + + pdbonly + true + true + bin\Release\ + TRACE + 3 + + + + + + + 3.5 + + + + + FSharp + {37e8e802-a354-4114-bfc1-6e1357da605b} + True + + + Numerics + {b7cae5f4-a23f-4438-b5be-41226618b695} + True + + + + + + + + \ No newline at end of file diff --git a/src/FSharpUnitTests/FSharpUnitTests.fsproj b/src/FSharpUnitTests/FSharpUnitTests.fsproj new file mode 100644 index 00000000..d73c1d8f --- /dev/null +++ b/src/FSharpUnitTests/FSharpUnitTests.fsproj @@ -0,0 +1,64 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {f2f8032b-a31d-4e33-a05e-f2cdcbfaa75d} + Library + FSharpUnitTests + FSharpUnitTests + v3.5 + FSharpUnitTests + + + true + full + false + false + bin\Debug\ + DEBUG;TRACE + 3 + + + pdbonly + true + true + bin\Release\ + TRACE + 3 + + + + + + + 3.5 + + + + + + + + + FSharp + {37e8e802-a354-4114-bfc1-6e1357da605b} + True + + + Numerics + {b7cae5f4-a23f-4438-b5be-41226618b695} + True + + + + + \ No newline at end of file diff --git a/src/FSharpUnitTests/FsUnit.fs b/src/FSharpUnitTests/FsUnit.fs new file mode 100644 index 00000000..e6da2926 --- /dev/null +++ b/src/FSharpUnitTests/FsUnit.fs @@ -0,0 +1,222 @@ +(* +Copyright (c) 2008, Raymond W. Vernagus (R.Vernagus@gmail.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of Raymond W. Vernagus nor the names of FsUnit's + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*) +namespace FsUnit + +open MathNet.Numerics +open MathNet.Numerics.LinearAlgebra.Double + +type Result = + | Pass + | Fail of string + | Error of string + +type Expectation = + | True + | False + | Empty + | NullOrEmpty + | Null + | SameAs of obj + +type Spec = + abstract Check : unit -> Result + abstract NegatedMessage : string + +[] +module SpecOps = + let internal safeCheck f = + try + f() + with ex -> Error (ex.ToString()) + + let make f nmsg = + { new Spec with + member this.Check() = safeCheck f + member this.NegatedMessage = nmsg } + + let check (s: Spec) = s.Check() + + let not' f x = + let s = f x + match check s with + | Pass -> make (fun () -> Fail s.NegatedMessage) "" + | Fail msg -> make (fun () -> Pass) msg + | Error msg -> make (fun () -> Error msg) msg + + let equal expected actual = + make (fun () -> + if actual = expected + then Pass + else Fail (sprintf "Expected: %A\nActual: %A" expected actual)) + (sprintf "NOT Expected: %A\nActual: %A" expected actual) + + let have n lbl s = + make (fun() -> + let len = Seq.length s + if len = n + then Pass + else Fail (sprintf "Expected: %d %s\nActual: %d %s" n lbl len lbl)) + (sprintf "NOT Expected: %d %s\nActual: %d %s" n lbl n lbl) + + let contain x s = + make (fun () -> + let exists = s |> Seq.exists (fun x' -> x' = x) + if exists + then Pass + else Fail (sprintf "Expected %A to contain %A" s x)) + (sprintf "Did NOT expect %A to contain %A" s x) + + let raise'<'a when 'a :> System.Exception> f = + let expType = typeof<'a> + make (fun () -> + try + f() + Fail (sprintf "Expected %s but no exception was raised" expType.FullName) + with ex -> + let actualExType = ex.GetType() + if expType = actualExType + then Pass + else Fail (sprintf "Expected: %s\nActual: %s" expType.FullName actualExType.FullName)) + (sprintf "Did NOT expect %s to be raised" expType.FullName) + + let be expectation x = + let x = box x + let msg = sprintf "Expected: %A\nActual: %A" expectation x + let negmsg = sprintf "NOT Expected: %A\nActual: %A" expectation x + match expectation with + | True -> + make (fun () -> + if x = box true + then Pass + else Fail msg) + negmsg + | False -> + make (fun () -> + if x = box false + then Pass + else Fail msg) + negmsg + | Empty -> + make (fun () -> + if x = box System.String.Empty + then Pass + else Fail msg) + negmsg + | NullOrEmpty -> + make (fun () -> + if System.String.IsNullOrEmpty(x :?> string) + then Pass + else Fail msg) + negmsg + | Null -> + make (fun () -> + if x = null + then Pass + else Fail msg) + negmsg + | SameAs other -> + make (fun () -> + if System.Object.ReferenceEquals(x, other) + then Pass + else Fail (sprintf "Expected actual to be same reference as expected %A" other)) + (sprintf "Expected %A to have different reference than %A" x other) + + let approximately_equal (expected: float) (actual: float) = + make (fun () -> + if Precision.AlmostEqualInDecimalPlaces(actual, expected, 5) + then Pass + else Fail (sprintf "Expected: %A\nActual: %A" expected actual)) + (sprintf "NOT Expected: %A\nActual: %A" expected actual) + + let approximately_vector_equal (expected: #Vector) (actual: #Vector) = + make (fun () -> + let mutable f = true + for i=0 to expected.Count-1 do + f <- f && Precision.AlmostEqualInDecimalPlaces(expected.[i], actual.[i], 5) + if f + then Pass + else Fail (sprintf "Expected: %A\nActual: %A" expected actual)) + (sprintf "NOT Expected: %A\nActual: %A" expected actual) + + let approximately_matrix_equal (expected: #Matrix) (actual: #Matrix) = + make (fun () -> + let mutable f = true + for i=0 to expected.RowCount-1 do + for j=0 to expected.ColumnCount-1 do + f <- f && Precision.AlmostEqualInDecimalPlaces(expected.[i,j], actual.[i,j], 5) + if f + then Pass + else Fail (sprintf "Expected: %A\nActual: %A" expected actual)) + (sprintf "NOT Expected: %A\nActual: %A" expected actual) + +module Results = + open Microsoft.FSharp.Text.Printf + + let internal currentResults = new ResizeArray() + + let add = currentResults.Add + + let passedCount () = + currentResults + |> Seq.filter (function _,Pass -> true | _ -> false) + |> Seq.length + + let failed () = + currentResults + |> Seq.filter (function _,Fail _ -> true | _ -> false) + + let failedCount () = + failed() + |> Seq.length + + let erred () = + currentResults + |> Seq.filter (function _,Error _ -> true | _ -> false) + + let erredCount () = + erred() + |> Seq.length + + let summary () = + let buff = new System.Text.StringBuilder() + bprintf buff "%d passed.\n%d failed.\n%d erred." (passedCount()) (failedCount()) (erredCount()) + failed() + |> Seq.iter (function (lbl,Fail msg) -> bprintf buff "\n----\nFailed: %s\n%s" lbl msg | _ -> ()) + erred() + |> Seq.iter (function (lbl,Error msg) -> bprintf buff "\n----\nErred: %s\n%s" lbl msg | _ -> ()) + buff.ToString() + + +[] +module SpecHelpers = + let spec lbl s = (lbl, check s) + + let should f x = f x + + let specs lbl (results: seq) = + results |> Seq.iter (fun x -> Results.add x) diff --git a/src/FSharpUnitTests/Program.fs b/src/FSharpUnitTests/Program.fs new file mode 100644 index 00000000..2445077d --- /dev/null +++ b/src/FSharpUnitTests/Program.fs @@ -0,0 +1,19 @@ +open FsUnit +open MathNet.Numerics.FSharp +open MathNet.Numerics.LinearAlgebra + +/// Unit tests for the dense vector type. +let DenseVectorTests = + + /// A small uniform vector. + let smallv = new Double.DenseVector( [|0.3;0.3;0.3;0.3;0.3|] ) + + /// A large vector with increasingly large entries + let largev = new Double.DenseVector( Array.init 100 (fun i -> float i / 100.0) ) + + specs "DenseVector" [ + spec "DenseVector.init" + (DenseVector.init 100 (fun i -> float i / 100.0) |> should equal largev) + spec "DenseVector.of_list" + (DenseVector.of_list [ for i in 0 .. 99 -> float i / 100.0 ] |> should equal largev) + ] \ No newline at end of file diff --git a/src/MathNet.Numerics.sln b/src/MathNet.Numerics.sln index b0cc8130..f22f09ff 100644 --- a/src/MathNet.Numerics.sln +++ b/src/MathNet.Numerics.sln @@ -7,6 +7,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Numerics", "Numerics\Numeri EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{8C9A5D3F-A20C-4D24-A09C-98E187A8D720}" EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharp", "FSharp\FSharp.fsproj", "{37E8E802-A354-4114-BFC1-6E1357DA605B}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharpExamples", "FSharpExamples\FSharpExamples.fsproj", "{BC81EA37-8EE6-4BF9-B8A9-B30497AEF8B1}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharpUnitTests", "FSharpUnitTests\FSharpUnitTests.fsproj", "{F2F8032B-A31D-4E33-A05E-F2CDCBFAA75D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -25,6 +31,18 @@ Global {8C9A5D3F-A20C-4D24-A09C-98E187A8D720}.Debug|Any CPU.Build.0 = Debug|Any CPU {8C9A5D3F-A20C-4D24-A09C-98E187A8D720}.Release|Any CPU.ActiveCfg = Release|Any CPU {8C9A5D3F-A20C-4D24-A09C-98E187A8D720}.Release|Any CPU.Build.0 = Release|Any CPU + {37E8E802-A354-4114-BFC1-6E1357DA605B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {37E8E802-A354-4114-BFC1-6E1357DA605B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {37E8E802-A354-4114-BFC1-6E1357DA605B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {37E8E802-A354-4114-BFC1-6E1357DA605B}.Release|Any CPU.Build.0 = Release|Any CPU + {BC81EA37-8EE6-4BF9-B8A9-B30497AEF8B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC81EA37-8EE6-4BF9-B8A9-B30497AEF8B1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC81EA37-8EE6-4BF9-B8A9-B30497AEF8B1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC81EA37-8EE6-4BF9-B8A9-B30497AEF8B1}.Release|Any CPU.Build.0 = Release|Any CPU + {F2F8032B-A31D-4E33-A05E-F2CDCBFAA75D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2F8032B-A31D-4E33-A05E-F2CDCBFAA75D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F2F8032B-A31D-4E33-A05E-F2CDCBFAA75D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2F8032B-A31D-4E33-A05E-F2CDCBFAA75D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE