├── docs ├── .gitignore ├── input │ ├── resources │ │ ├── logo.png │ │ └── logo.pspimage │ ├── files │ │ ├── img │ │ │ ├── github.png │ │ │ ├── fsalg-logo.png │ │ │ └── github-blue.png │ │ └── misc │ │ │ ├── tips.js │ │ │ ├── style_light.css │ │ │ └── style.css │ ├── templates │ │ ├── docpage.cshtml │ │ ├── reference │ │ │ ├── part-nested.cshtml │ │ │ ├── part-members.cshtml │ │ │ ├── namespaces.cshtml │ │ │ ├── type.cshtml │ │ │ └── module.cshtml │ │ ├── template.html │ │ └── template.cshtml │ ├── index.fsx │ ├── vector-operations.fsx │ └── matrix-operations.fsx └── BuildDocs.fsx ├── src └── FsAlg │ ├── Test.fsx │ ├── packages.config │ ├── app.config │ ├── Ops.fs │ ├── AssemblyInfo.fs │ ├── Util.fs │ ├── FsAlg.fsproj │ ├── Vector.fs │ └── Matrix.fs ├── README.md ├── LICENSE.txt ├── FsAlg.sln ├── .gitattributes └── .gitignore /docs/.gitignore: -------------------------------------------------------------------------------- 1 | output/ -------------------------------------------------------------------------------- /src/FsAlg/Test.fsx: -------------------------------------------------------------------------------- 1 | 2 | #r "bin/Debug/FsAlg.dll" 3 | -------------------------------------------------------------------------------- /docs/input/resources/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbaydin/FsAlg/HEAD/docs/input/resources/logo.png -------------------------------------------------------------------------------- /docs/input/files/img/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbaydin/FsAlg/HEAD/docs/input/files/img/github.png -------------------------------------------------------------------------------- /docs/input/resources/logo.pspimage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbaydin/FsAlg/HEAD/docs/input/resources/logo.pspimage -------------------------------------------------------------------------------- /docs/input/files/img/fsalg-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbaydin/FsAlg/HEAD/docs/input/files/img/fsalg-logo.png -------------------------------------------------------------------------------- /docs/input/files/img/github-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbaydin/FsAlg/HEAD/docs/input/files/img/github-blue.png -------------------------------------------------------------------------------- /docs/input/templates/docpage.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "template"; 3 | Title = Properties["page-title"]; 4 | Description = Properties["project-summary"]; 5 | } 6 | @Properties["document"] 7 | @Properties["tooltips"] -------------------------------------------------------------------------------- /src/FsAlg/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FsAlg: Generic Linear Algebra Library 2 | ===================================== 3 | 4 | Copyright (c) 2015, National University of Ireland Maynooth (Atilim Gunes Baydin, Barak A. Pearlmutter) 5 | 6 | All rights reserved. 7 | 8 | FsAlg is released under the BSD license. (See accompanying LICENSE file.) 9 | 10 | Written by: Atilim Gunes Baydin & Barak A. Pearlmutter 11 | 12 | Brain and Computation Lab 13 | Hamilton Institute & Department of Computer Science 14 | National University of Ireland Maynooth 15 | Maynooth, Co. Kildare 16 | Ireland 17 | 18 | www.bcl.hamilton.ie 19 | 20 | This work is supported by Science Foundation Ireland grant 09/IN.1/I2637. 21 | -------------------------------------------------------------------------------- /docs/input/templates/reference/part-nested.cshtml: -------------------------------------------------------------------------------- 1 | @if (Enumerable.Count(Model.Types) > 0) { 2 | 3 | 4 | 5 | 6 | 7 | @foreach (var it in Model.Types) 8 | { 9 | 10 | 13 | 14 | 15 | } 16 | 17 |
TypeDescription
11 | @it.Name 12 | @it.Comment.Blurb
18 | } 19 | @if (Enumerable.Count(Model.Modules) > 0) { 20 | 21 | 22 | 23 | 24 | 25 | @foreach (var it in Model.Modules) 26 | { 27 | 28 | 31 | 32 | 33 | } 34 | 35 |
ModuleDescription
29 | @it.Name 30 | @it.Comment.Blurb
36 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, National University of Ireland Maynooth (Atilim Gunes Baydin, Barak A. Pearlmutter) 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /src/FsAlg/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /FsAlg.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FsAlg", "src\FsAlg\FsAlg.fsproj", "{8715EA25-3B32-4CF5-A595-D4034442FE58}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{21FEAA04-EBA7-49C9-B0E6-0F244996DBAB}" 9 | ProjectSection(SolutionItems) = preProject 10 | docs\BuildDocs.fsx = docs\BuildDocs.fsx 11 | docs\input\index.fsx = docs\input\index.fsx 12 | docs\input\matrix-operations.fsx = docs\input\matrix-operations.fsx 13 | docs\input\vector-operations.fsx = docs\input\vector-operations.fsx 14 | EndProjectSection 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {8715EA25-3B32-4CF5-A595-D4034442FE58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {8715EA25-3B32-4CF5-A595-D4034442FE58}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {8715EA25-3B32-4CF5-A595-D4034442FE58}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {8715EA25-3B32-4CF5-A595-D4034442FE58}.Release|Any CPU.Build.0 = Release|Any CPU 26 | EndGlobalSection 27 | GlobalSection(SolutionProperties) = preSolution 28 | HideSolutionNode = FALSE 29 | EndGlobalSection 30 | EndGlobal 31 | -------------------------------------------------------------------------------- /docs/input/files/misc/tips.js: -------------------------------------------------------------------------------- 1 | var currentTip = null; 2 | var currentTipElement = null; 3 | 4 | function hideTip(evt, name, unique) { 5 | var el = document.getElementById(name); 6 | el.style.display = "none"; 7 | currentTip = null; 8 | } 9 | 10 | function findPos(obj) { 11 | // no idea why, but it behaves differently in webbrowser component 12 | if (window.location.search == "?inapp") 13 | return [obj.offsetLeft + 10, obj.offsetTop + 30]; 14 | 15 | var curleft = 0; 16 | var curtop = obj.offsetHeight; 17 | while (obj) { 18 | curleft += obj.offsetLeft; 19 | curtop += obj.offsetTop; 20 | obj = obj.offsetParent; 21 | }; 22 | return [curleft, curtop]; 23 | } 24 | 25 | function hideUsingEsc(e) { 26 | if (!e) { e = event; } 27 | hideTip(e, currentTipElement, currentTip); 28 | } 29 | 30 | function showTip(evt, name, unique, owner) { 31 | document.onkeydown = hideUsingEsc; 32 | if (currentTip == unique) return; 33 | currentTip = unique; 34 | currentTipElement = name; 35 | 36 | var pos = findPos(owner ? owner : (evt.srcElement ? evt.srcElement : evt.target)); 37 | var posx = pos[0]; 38 | var posy = pos[1]; 39 | 40 | var el = document.getElementById(name); 41 | var parent = (document.documentElement == null) ? document.body : document.documentElement; 42 | el.style.position = "absolute"; 43 | el.style.left = posx + "px"; 44 | el.style.top = posy + "px"; 45 | el.style.display = "block"; 46 | } -------------------------------------------------------------------------------- /src/FsAlg/Ops.fs: -------------------------------------------------------------------------------- 1 | // 2 | // This file is part of 3 | // FsAlg: Generic Linear Algebra Library 4 | // 5 | // Copyright (c) 2015, National University of Ireland Maynooth (Atilim Gunes Baydin, Barak A. Pearlmutter) 6 | // 7 | // FsAlg is released under the BSD license. 8 | // (See accompanying LICENSE file.) 9 | // 10 | // Written by: 11 | // 12 | // Atilim Gunes Baydin 13 | // atilimgunes.baydin@nuim.ie 14 | // 15 | // Barak A. Pearlmutter 16 | // barak@cs.nuim.ie 17 | // 18 | // Brain and Computation Lab 19 | // Hamilton Institute & Department of Computer Science 20 | // National University of Ireland Maynooth 21 | // Maynooth, Co. Kildare 22 | // Ireland 23 | // 24 | // www.bcl.hamilton.ie 25 | // 26 | 27 | namespace FsAlg.Generic 28 | 29 | /// Linear algebra operations module (automatically opened) 30 | [] 31 | module Ops = 32 | /// Converts array, list, or sequence `v` into a Vector 33 | let inline vector (v:seq<'T>):Vector<'T> = Vector.ofSeq v 34 | /// Converts array, list, or sequence `v` into a Vector, first passing the elements through a conversion function `f` 35 | let inline vectorBy (f:'T->'U) (v:seq<'T>):Vector<'U> = Vector.map f (Vector.ofSeq v) 36 | /// Converts 2d array `m` into a Matrix 37 | let inline matrix (m:seq>):Matrix<'T> = Matrix.ofSeqSeq m 38 | /// Converts 2d array `m` into a Matrix, first passing the elements through a conversion function `f` 39 | let inline matrixBy (f:'T->'U) (m:seq>):Matrix<'U> = Matrix.map f (Matrix.ofSeqSeq m) 40 | -------------------------------------------------------------------------------- /docs/input/templates/reference/part-members.cshtml: -------------------------------------------------------------------------------- 1 | @if (Enumerable.Count(Model.Members) > 0) { 2 |

@Model.Header

3 | 4 | 5 | 6 | 7 | 8 | @foreach (var it in Model.Members) 9 | { 10 | 11 | 26 | 36 | 37 | } 38 | 39 |
@Model.TableHeaderDescription
12 | @{ var id = Html.UniqueID().ToString(); } 13 | 14 | @Html.Encode(it.Details.FormatUsage(40)) 15 | 16 |
17 | Signature: @Html.Encode(it.Details.Signature)
18 | @if (!it.Details.Modifiers.IsEmpty) { 19 | Modifiers: @it.Details.FormatModifiers
20 | } 21 | @if (!it.Details.TypeArguments.IsEmpty) { 22 | Type parameters: @it.Details.FormatTypeArguments 23 | } 24 |
25 |
27 | @if (!String.IsNullOrEmpty(it.Details.FormatSourceLocation)) 28 | { 29 | 30 | 31 | 32 | 33 | } 34 | @it.Comment.FullText 35 |
40 | } -------------------------------------------------------------------------------- /docs/input/templates/reference/namespaces.cshtml: -------------------------------------------------------------------------------- 1 | @using FSharp.MetadataFormat 2 | @{ 3 | Layout = "template"; 4 | Title = "Namespaces - " + Properties["project-name"]; 5 | } 6 | 7 |

@Model.Name

8 | 9 | @{ var nsIndex = 0; } 10 | @foreach (var ns in Model.Namespaces) 11 | { 12 | nsIndex++; 13 | var typedNs = (Namespace)ns; 14 | var allCategories = 15 | typedNs.Types.Select(t => t.Category) 16 | .Concat(typedNs.Modules.Select(m => m.Category)) 17 | .Distinct() 18 | .OrderBy(s => String.IsNullOrEmpty(s) ? "ZZZ" : s); 19 | var allByCategory = 20 | allCategories 21 | .Select((c, i) => new { 22 | Name = String.IsNullOrEmpty(c) ? "Other namespace members" : c, 23 | Index = String.Format("{0}_{1}", nsIndex, i), 24 | Types = typedNs.Types.Where(t => t.Category == c).ToArray(), 25 | Modules = typedNs.Modules.Where(m => m.Category == c).ToArray() }) 26 | .Where(c => c.Types.Length + c.Modules.Length > 0).ToArray(); 27 | 28 |

@ns.Name Namespace

29 | if (allByCategory.Length > 1) 30 | { 31 | 32 |
    33 | @foreach (var g in allByCategory) 34 | { 35 |
  • @g.Name
  • 36 | } 37 |
38 | } 39 | foreach(var g in allByCategory) 40 | { 41 | if (allByCategory.Length > 1) 42 | { 43 |

@g.Name

44 | } 45 |
46 | @RenderPart("part-nested", new 47 | { 48 | Types = g.Types, 49 | Modules = g.Modules 50 | }) 51 |
52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/FsAlg/AssemblyInfo.fs: -------------------------------------------------------------------------------- 1 | #light 2 | 3 | namespace FsAlg 4 | 5 | open System.Reflection; 6 | open System.Runtime.CompilerServices; 7 | open System.Runtime.InteropServices; 8 | 9 | // General Information about an assembly is controlled through the following 10 | // set of attributes. Change these attribute values to modify the information 11 | // associated with an assembly. 12 | [] 13 | [] 14 | [] 15 | [] 16 | [] 17 | [] 18 | [] 19 | 20 | // Setting ComVisible to false makes the types in this assembly not visible 21 | // to COM components. If you need to access a type in this assembly from 22 | // COM, set the ComVisible attribute to true on that type. 23 | [] 24 | 25 | // The following GUID is for the ID of the typelib if this project is exposed to COM 26 | [] 27 | 28 | // Version information for an assembly consists of the following four values: 29 | // 30 | // Major Version 31 | // Minor Version 32 | // Build Number 33 | // Revision 34 | // 35 | // You can specify all the values or you can default the Build and Revision Numbers 36 | // by using the ‘*’ as shown below: 37 | // [assembly: AssemblyVersion("1.0.*")] 38 | [] 39 | [] 40 | [] 41 | 42 | () -------------------------------------------------------------------------------- /docs/input/index.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | #r "../../src/FsAlg/bin/Debug/FsAlg.dll" 3 | 4 | (** 5 | FsAlg: Generic Linear Algebra Library 6 | ===================================== 7 | 8 | FsAlg is a [linear algebra](http://en.wikipedia.org/wiki/Linear_algebra) library that supports [generic types](http://en.wikipedia.org/wiki/Generic_programming). It is implemented in the F# language. 9 | 10 | The library provides generic Vector and Matrix types that support most of the commonly used linear algebra operations, including matrix–vector operations, matrix inverse, determinants, eigenvalues, LU and QR decompositions. Its intended use is to enable writing generic linear algebra code with [custom numeric types](http://tomasp.net/blog/fsharp-custom-numeric.aspx/). It can also be used as a lightweight library for prototyping and scripting with [primitive floating point types](https://msdn.microsoft.com/en-us/library/dd233210.aspx). 11 | 12 | FsAlg is developed by [Atılım Güneş Baydin](http://www.cs.nuim.ie/~gunes/) and [Barak A. Pearlmutter](http://bcl.hamilton.ie/~barak/) as part of their work at the [Brain and Computation Lab](http://www.bcl.hamilton.ie/), Hamilton Institute, National University of Ireland Maynooth. 13 | 14 | How to Get 15 | ---------- 16 | 17 | You can install the library via NuGet. You can also download the source code or the binaries of the latest release on GitHub. 18 | 19 |
20 |
21 |
22 |
23 | The FsAlg library is available on NuGet. To install, run the following command in the Package Manager Console: 24 |
PM> Install-Package FsAlg
25 |
26 |
27 |
28 |
29 | 30 | Quick Usage Example 31 | ------------------- 32 | *) 33 | 34 | open FsAlg.Generic 35 | 36 | let A = matrix [[3.; 1.]; [2.; -1.]] 37 | let b = vector [5.; 0.] 38 | 39 | // Solve a matrix equation 40 | let x = Matrix.solve A b 41 | 42 | // Find inverse of A 43 | let Ainv = Matrix.inverse A 44 | 45 | // Initialize a vector 46 | let w = Vector.init 2 (fun i -> float (i * i)) 47 | 48 | // Map a function to a vector 49 | let y = Vector.map (fun x -> sin (exp x)) w 50 | 51 | // Matrix-vector operations 52 | let z = A * (x - y) -------------------------------------------------------------------------------- /src/FsAlg/Util.fs: -------------------------------------------------------------------------------- 1 | // 2 | // This file is part of 3 | // FsAlg: Generic Linear Algebra Library 4 | // 5 | // Copyright (c) 2015, National University of Ireland Maynooth (Atilim Gunes Baydin, Barak A. Pearlmutter) 6 | // 7 | // FsAlg is released under the BSD license. 8 | // (See accompanying LICENSE file.) 9 | // 10 | // Written by: 11 | // 12 | // Atilim Gunes Baydin 13 | // atilimgunes.baydin@nuim.ie 14 | // 15 | // Barak A. Pearlmutter 16 | // barak@cs.nuim.ie 17 | // 18 | // Brain and Computation Lab 19 | // Hamilton Institute & Department of Computer Science 20 | // National University of Ireland Maynooth 21 | // Maynooth, Co. Kildare 22 | // Ireland 23 | // 24 | // www.bcl.hamilton.ie 25 | // 26 | 27 | /// Various utility functions for internal use 28 | module FsAlg.Generic.Util 29 | 30 | /// Checks whether the 2d array `m` has the same number of elements in both dimensions 31 | let (|Square|) (m:_[,]) = 32 | match m with 33 | | m when m.GetLength 0 = m.GetLength 1 -> m 34 | | _ -> invalidArg "m" "Expecting a square 2d array" 35 | 36 | /// Gets the transpose of the 2d array `m` 37 | let inline transpose (m:_[,]) = Array2D.init (m.GetLength 1) (m.GetLength 0) (fun i j -> m.[j, i]) 38 | 39 | /// Gets an array containing the diagonal elements of the square 2d array `m` 40 | let inline diagonal (Square m:_[,]) = Array.init (m.GetLength 0) (fun i -> m.[i, i]) 41 | 42 | /// Gets the trace of the square matrix given in the 2d array `m` 43 | let inline trace (m:_[,]) = Array.sum (diagonal m) 44 | 45 | /// Copies the upper triangular elements of the square matrix given in the 2d array `m` to the lower triangular part 46 | let inline copyUpperToLower (Square m:_[,]) = 47 | let r = Array2D.copy m 48 | let rows = r.GetLength 0 49 | if rows > 1 then 50 | for i = 1 to rows - 1 do 51 | for j = 0 to i - 1 do 52 | r.[i, j] <- r.[j, i] 53 | r 54 | 55 | /// Finds an array that, when multiplied by an LU matrix `lu`, gives array `b` 56 | let inline matrixSolveHelper (lu:'a[,]) (b:'a[]) = 57 | let n = lu.GetLength 0 58 | let x = Array.copy b 59 | for i = 1 to n - 1 do 60 | let mutable sum = x.[i] 61 | for j = 0 to i - 1 do 62 | sum <- sum - lu.[i, j] * x.[j] 63 | x.[i] <- sum 64 | x.[n - 1] <- x.[n - 1] / lu.[n - 1, n - 1] 65 | for i in (n - 2) .. -1 .. 0 do 66 | let mutable sum = x.[i] 67 | for j = i + 1 to n - 1 do 68 | sum <- sum - lu.[i, j] * x.[j] 69 | x.[i] <- sum / lu.[i, i] 70 | x 71 | 72 | /// Checks whether a float contains an integer value 73 | let isInteger a = a = float (int a) -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /docs/BuildDocs.fsx: -------------------------------------------------------------------------------- 1 | 2 | 3 | #I "../packages/FSharp.Compiler.Service.0.0.86/lib/net40" 4 | #r "FSharp.Compiler.Service.dll" 5 | #I "../packages/FSharpVSPowerTools.Core.1.7.0/lib/net45" 6 | #r "FSharpVSPowerTools.Core.dll" 7 | #I "../packages/FSharp.Formatting.2.8.0/lib/net40" 8 | #r "CSharpFormat.dll" 9 | #r "FSharp.CodeFormat.dll" 10 | #r "FSharp.Literate.dll" 11 | #r "FSharp.MetadataFormat.dll" 12 | #r "FSharp.Markdown.dll" 13 | 14 | open System.IO 15 | open FSharp.Literate 16 | open FSharp.MetadataFormat 17 | 18 | // 19 | // Setup output directory structure and copy static files 20 | // 21 | 22 | let source = __SOURCE_DIRECTORY__ 23 | let docs = Path.Combine(source, "") 24 | let relative subdir = Path.Combine(docs, subdir) 25 | 26 | if not (Directory.Exists(relative "output")) then 27 | Directory.CreateDirectory(relative "output") |> ignore 28 | if not (Directory.Exists(relative "output/img")) then 29 | Directory.CreateDirectory (relative "output/img") |> ignore 30 | if not (Directory.Exists(relative "output/misc")) then 31 | Directory.CreateDirectory (relative "output/misc") |> ignore 32 | if not (Directory.Exists(relative "output/reference")) then 33 | Directory.CreateDirectory (relative "output/reference") |> ignore 34 | 35 | for fileInfo in DirectoryInfo(relative "input/files/misc").EnumerateFiles() do 36 | fileInfo.CopyTo(Path.Combine(relative "output/misc", fileInfo.Name), true) |> ignore 37 | 38 | for fileInfo in DirectoryInfo(relative "input/files/img").EnumerateFiles() do 39 | fileInfo.CopyTo(Path.Combine(relative "output/img", fileInfo.Name), true) |> ignore 40 | 41 | // 42 | // Generate documentation 43 | // 44 | 45 | let tags = ["project-name", "FsAlg"; "project-author", "Atılım Güneş Baydin"; "project-github", "http://github.com/gbaydin/FsAlg"; "project-nuget", "https://www.nuget.org/packages/fsalg"; "root", ""] 46 | 47 | Literate.ProcessScriptFile(relative "input/index.fsx", relative "input/templates/template.html", relative "output/index.html", replacements = tags, fsiEvaluator = FsiEvaluator()) 48 | Literate.ProcessScriptFile(relative "input/vector-operations.fsx", relative "input/templates/template.html", relative "output/vector-operations.html", replacements = tags, fsiEvaluator = FsiEvaluator()) 49 | Literate.ProcessScriptFile(relative "input/matrix-operations.fsx", relative "input/templates/template.html", relative "output/matrix-operations.html", replacements = tags, fsiEvaluator = FsiEvaluator()) 50 | 51 | 52 | // 53 | // Generate API reference 54 | // 55 | 56 | let library = relative "../src/FsAlg/bin/Debug/FsAlg.dll" 57 | let layoutRoots = [relative "input/templates"; relative "input/templates/reference" ] 58 | 59 | MetadataFormat.Generate(library, relative "output/reference", layoutRoots, tags, markDownComments = true) 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | 11 | [Dd]ebug/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | [Bb]in/ 16 | [Oo]bj/ 17 | 18 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 19 | !packages/*/build/ 20 | 21 | # MSTest test Results 22 | [Tt]est[Rr]esult*/ 23 | [Bb]uild[Ll]og.* 24 | 25 | *_i.c 26 | *_p.c 27 | *.ilk 28 | *.meta 29 | *.obj 30 | *.pch 31 | *.pdb 32 | *.pgc 33 | *.pgd 34 | *.rsp 35 | *.sbr 36 | *.tlb 37 | *.tli 38 | *.tlh 39 | *.tmp 40 | *.tmp_proj 41 | *.log 42 | *.vspscc 43 | *.vssscc 44 | .builds 45 | *.pidb 46 | *.log 47 | *.scc 48 | 49 | # Visual C++ cache files 50 | ipch/ 51 | *.aps 52 | *.ncb 53 | *.opensdf 54 | *.sdf 55 | *.cachefile 56 | 57 | # Visual Studio profiler 58 | *.psess 59 | *.vsp 60 | *.vspx 61 | 62 | # Guidance Automation Toolkit 63 | *.gpState 64 | 65 | # ReSharper is a .NET coding add-in 66 | _ReSharper*/ 67 | *.[Rr]e[Ss]harper 68 | 69 | # TeamCity is a build add-in 70 | _TeamCity* 71 | 72 | # DotCover is a Code Coverage Tool 73 | *.dotCover 74 | 75 | # NCrunch 76 | *.ncrunch* 77 | .*crunch*.local.xml 78 | 79 | # Installshield output folder 80 | [Ee]xpress/ 81 | 82 | # DocProject is a documentation generator add-in 83 | DocProject/buildhelp/ 84 | DocProject/Help/*.HxT 85 | DocProject/Help/*.HxC 86 | DocProject/Help/*.hhc 87 | DocProject/Help/*.hhk 88 | DocProject/Help/*.hhp 89 | DocProject/Help/Html2 90 | DocProject/Help/html 91 | 92 | # Click-Once directory 93 | publish/ 94 | 95 | # Publish Web Output 96 | *.Publish.xml 97 | 98 | # NuGet Packages Directory 99 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 100 | packages/ 101 | 102 | # Windows Azure Build Output 103 | csx 104 | *.build.csdef 105 | 106 | # Windows Store app package directory 107 | AppPackages/ 108 | 109 | # Others 110 | sql/ 111 | *.Cache 112 | ClientBin/ 113 | [Ss]tyle[Cc]op.* 114 | ~$* 115 | *~ 116 | *.dbmdl 117 | *.[Pp]ublish.xml 118 | *.pfx 119 | *.publishsettings 120 | 121 | # RIA/Silverlight projects 122 | Generated_Code/ 123 | 124 | # Backup & report files from converting an old project file to a newer 125 | # Visual Studio version. Backup files are not needed, because we have git ;-) 126 | _UpgradeReport_Files/ 127 | Backup*/ 128 | UpgradeLog*.XML 129 | UpgradeLog*.htm 130 | 131 | # SQL Server files 132 | App_Data/*.mdf 133 | App_Data/*.ldf 134 | 135 | 136 | #LightSwitch generated files 137 | GeneratedArtifacts/ 138 | _Pvt_Extensions/ 139 | ModelManifest.xml 140 | 141 | # ========================= 142 | # Windows detritus 143 | # ========================= 144 | 145 | # Windows image file caches 146 | Thumbs.db 147 | ehthumbs.db 148 | 149 | # Folder config file 150 | Desktop.ini 151 | 152 | # Recycle Bin used on file shares 153 | $RECYCLE.BIN/ 154 | 155 | # Mac desktop service store files 156 | .DS_Store 157 | -------------------------------------------------------------------------------- /docs/input/templates/reference/type.cshtml: -------------------------------------------------------------------------------- 1 | @using FSharp.MetadataFormat 2 | @{ 3 | Layout = "template"; 4 | Title = Model.Type.Name + " - " + Properties["project-name"]; 5 | } 6 | 7 | @{ 8 | // Get all the members & comment for the type 9 | var members = (IEnumerable)Model.Type.AllMembers; 10 | var comment = (Comment)Model.Type.Comment; 11 | 12 | // Group all members by their category which is an inline annotation 13 | // that can be added to members using special XML comment: 14 | // 15 | // /// [category:Something] 16 | // 17 | // ...and can be used to categorize members in large modules or types 18 | // (but if this is not used, then all members end up in just one category) 19 | var byCategory = members 20 | .GroupBy(m => m.Category) 21 | .OrderBy(g => String.IsNullOrEmpty(g.Key) ? "ZZZ" : g.Key) 22 | .Select((g, n) => new { 23 | Index = n, 24 | GroupKey = g.Key, 25 | Members = g.OrderBy(m => m.Kind == MemberKind.StaticParameter ? "" : m.Name), 26 | Name = String.IsNullOrEmpty(g.Key) ? "Other type members" : g.Key 27 | }); 28 | } 29 | 30 |

@Model.Type.Name

31 |
32 | @foreach (var sec in comment.Sections) { 33 | // XML comment for the type has multiple sections that can be labelled 34 | // with categories (to give comment for an individual category). Here, 35 | // we print only those that belong to the section. 36 | if (!byCategory.Any(g => g.GroupKey == sec.Key)) { 37 | if (sec.Key != "") { 38 |

@sec.Key

39 | } 40 | @sec.Value 41 | } 42 | } 43 |
44 | @if (byCategory.Count() > 1) 45 | { 46 | 47 |

Table of contents

48 |
    49 | @foreach (var g in byCategory) 50 | { 51 |
  • @g.Name
  • 52 | } 53 |
54 | } 55 | @foreach (var g in byCategory) { 56 | // Iterate over all the categories and print members. If there are more than one 57 | // categories, print the category heading (as

) and add XML comment from the type 58 | // that is related to this specific category. 59 | if (byCategory.Count() > 1) { 60 |

@g.Name 

61 | var info = comment.Sections.FirstOrDefault(kvp => kvp.Key == g.GroupKey); 62 | if (info.Key != null) { 63 |
64 | @info.Value 65 |
66 | } 67 | } 68 | 69 | @RenderPart("part-members", new { 70 | Header = "Union Cases", 71 | TableHeader = "Union Case", 72 | Members = g.Members.Where(m => m.Kind == MemberKind.UnionCase) 73 | }) 74 | 75 | @RenderPart("part-members", new { 76 | Header = "Record Fields", 77 | TableHeader = "Record Field", 78 | Members = g.Members.Where(m => m.Kind == MemberKind.RecordField) 79 | }) 80 | 81 | @RenderPart("part-members", new { 82 | Header = "Static parameters", 83 | TableHeader = "Static parameters", 84 | Members = g.Members.Where(m => m.Kind == MemberKind.StaticParameter) 85 | }) 86 | 87 | @RenderPart("part-members", new { 88 | Header = "Constructors", 89 | TableHeader = "Constructor", 90 | Members = g.Members.Where(m => m.Kind == MemberKind.Constructor) 91 | }) 92 | 93 | @RenderPart("part-members", new { 94 | Header = "Instance members", 95 | TableHeader = "Instance member", 96 | Members = g.Members.Where(m => m.Kind == MemberKind.InstanceMember) 97 | }) 98 | 99 | @RenderPart("part-members", new { 100 | Header = "Static members", 101 | TableHeader = "Static member", 102 | Members = g.Members.Where(m => m.Kind == MemberKind.StaticMember) 103 | }) 104 | } 105 | -------------------------------------------------------------------------------- /docs/input/templates/reference/module.cshtml: -------------------------------------------------------------------------------- 1 | @using FSharp.MetadataFormat 2 | @{ 3 | Layout = "template"; 4 | Title = Model.Module.Name + " - " + Properties["project-name"]; 5 | } 6 | 7 | @{ 8 | // Get all the members & comment for the type 9 | var members = (IEnumerable)Model.Module.AllMembers; 10 | var comment = (Comment)Model.Module.Comment; 11 | 12 | // Group all members by their category which is an inline annotation 13 | // that can be added to members using special XML comment: 14 | // 15 | // /// [category:Something] 16 | // 17 | // ...and can be used to categorize members in large modules or types 18 | // (but if this is not used, then all members end up in just one category) 19 | var byCategory = members 20 | .GroupBy(m => m.Category) 21 | .OrderBy(g => String.IsNullOrEmpty(g.Key) ? "ZZZ" : g.Key) 22 | .Select((g, n) => new { 23 | Index = n, 24 | GroupKey = g.Key, 25 | Members = g.OrderBy(m => m.Name), 26 | Name = String.IsNullOrEmpty(g.Key) ? "Other module members" : g.Key 27 | }); 28 | 29 | // Get nested modules and nested types as statically typed collections 30 | var nestModules = (IEnumerable)Model.Module.NestedModules; 31 | var nestTypes = (IEnumerable)Model.Module.NestedTypes; 32 | } 33 | 34 |

@Model.Module.Name

35 |
36 | @foreach (var sec in comment.Sections) { 37 | // XML comment for the type has multiple sections that can be labelled 38 | // with categories (to give comment for an individual category). Here, 39 | // we print only those that belong to the section. 40 | if (!byCategory.Any(g => g.GroupKey == sec.Key)) 41 | { 42 | if (sec.Key != "") { 43 |

@sec.Key

44 | } 45 | @sec.Value 46 | } 47 | } 48 |
49 | @if (byCategory.Count() > 1) 50 | { 51 | 52 |

Table of contents

53 |
    54 | @foreach (var g in byCategory) 55 | { 56 |
  • @g.Name
  • 57 | } 58 |
59 | } 60 | 61 | 62 | @if (nestTypes.Count() + nestModules.Count() > 0) 63 | { 64 |

Nested types and modules

65 |
66 | @RenderPart("part-nested", new { 67 | Types = nestTypes, 68 | Modules = nestModules 69 | }) 70 |
71 | } 72 | 73 | @foreach (var g in byCategory) 74 | { 75 | // Iterate over all the categories and print members. If there are more than one 76 | // categories, print the category heading (as

) and add XML comment from the type 77 | // that is related to this specific category. 78 | if (byCategory.Count() > 1) 79 | { 80 |

@g.Name 

81 | var info = comment.Sections.FirstOrDefault(kvp => kvp.Key == g.GroupKey); 82 | if (info.Key != null) 83 | { 84 |
85 | @info.Value 86 |
87 | } 88 | } 89 | 90 | @RenderPart("part-members", new { 91 | Header = "Functions and values", 92 | TableHeader = "Function or value", 93 | Members = g.Members.Where(m => m.Kind == MemberKind.ValueOrFunction) 94 | }) 95 | 96 | @RenderPart("part-members", new { 97 | Header = "Type extensions", 98 | TableHeader = "Type extension", 99 | Members = g.Members.Where(m => m.Kind == MemberKind.TypeExtension) 100 | }) 101 | 102 | @RenderPart("part-members", new { 103 | Header = "Active patterns", 104 | TableHeader = "Active pattern", 105 | Members = g.Members.Where(m => m.Kind == MemberKind.ActivePattern) 106 | }) 107 | } -------------------------------------------------------------------------------- /src/FsAlg/FsAlg.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 2.0 8 | 8715ea25-3b32-4cf5-a595-d4034442fe58 9 | Library 10 | FsAlg 11 | FsAlg 12 | v4.5 13 | 4.3.1.0 14 | FsAlg 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | 3 25 | bin\Debug\FsAlg.XML 26 | 27 | 28 | pdbonly 29 | true 30 | true 31 | bin\Release\ 32 | TRACE 33 | 3 34 | bin\Release\FsAlg.XML 35 | 36 | 37 | 11 38 | 39 | 40 | 41 | 42 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets 43 | 44 | 45 | 46 | 47 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | True 66 | 67 | 68 | 69 | 70 | 71 | 78 | -------------------------------------------------------------------------------- /docs/input/templates/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {page-title} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 30 | 31 | 32 |
33 |
34 | 38 |

{project-name}

39 |
40 |
41 |
42 |
43 | {document} 44 | {tooltips} 45 |
46 |
47 | 48 | 49 | 50 | 68 |
69 |
70 |
71 | 72 | 82 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /docs/input/templates/template.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | @Title 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 30 | 31 | 32 |
33 |
34 | 38 |

@Properties["project-name"]

39 |
40 |
41 |
42 |
43 | @RenderBody() 44 |
45 | 46 |
47 | 48 | 49 | 50 | 68 |
69 |
70 |
71 | 72 | 82 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /docs/input/files/misc/style_light.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans+Mono|Open+Sans:400,600,700); 2 | 3 | /*-------------------------------------------------------------------------- 4 | Formatting for F# code snippets 5 | /*--------------------------------------------------------------------------*/ 6 | 7 | /* identifier */ 8 | span.i { color:#000000; } 9 | /* string */ 10 | span.s { color:#a31515; } 11 | /* keywords */ 12 | span.k { color:#0000ff; } 13 | /* comment */ 14 | span.c { color:#008000; } 15 | /* operators */ 16 | span.o { color:#000000; } 17 | /* numbers */ 18 | span.n { color:#000000; } 19 | /* line number */ 20 | span.l { color:#96c2cd; } 21 | /* type or module */ 22 | span.t { color:#2b91af; } 23 | /* function */ 24 | span.f { color:#0000a0; } 25 | /* DU case or active pattern */ 26 | span.p { color:#800080; } 27 | /* mutable var or ref cell */ 28 | span.v { color:#000000; font-weight: bold; } 29 | /* printf formatters */ 30 | span.pf { color:#2b91af; } 31 | /* escaped chars */ 32 | span.e { color:#ff0080; } 33 | /* mutable var or ref cell */ 34 | 35 | 36 | /* inactive code */ 37 | span.inactive { color:#808080; } 38 | /* preprocessor */ 39 | span.prep { color:#0000ff; } 40 | /* fsi output */ 41 | span.fsi { color:#808080; } 42 | 43 | /* omitted */ 44 | span.omitted { 45 | background:#3c4e52; 46 | border-radius:5px; 47 | color:#808080; 48 | padding:0px 0px 1px 0px; 49 | } 50 | /* tool tip */ 51 | div.tip { 52 | background:#e5e5e5; 53 | border-radius:4px; 54 | font:9pt 'Droid Sans', arial, sans-serif; 55 | padding:6px 8px 6px 8px; 56 | display:none; 57 | color:#000000; 58 | } 59 | table.pre pre { 60 | padding:0px; 61 | margin:0px; 62 | border:none; 63 | } 64 | table.pre, pre.fssnip, pre { 65 | line-height:13pt; 66 | border:1px solid #d8d8d8; 67 | border-collapse:separate; 68 | white-space:pre; 69 | font: 10pt consolas,monospace; 70 | width:90%; 71 | margin:10px 20px 20px 20px; 72 | background-color:#fdfdfd; 73 | padding:10px; 74 | border-radius:5px; 75 | color:#000000; 76 | } 77 | table.pre pre { 78 | padding:0px; 79 | margin:0px; 80 | border-radius:0px; 81 | width: 100%; 82 | } 83 | table.pre td { 84 | padding:0px; 85 | white-space:normal; 86 | margin:0px; 87 | } 88 | table.pre td.lines { 89 | width:30px; 90 | } 91 | 92 | /*-------------------------------------------------------------------------- 93 | Formatting for page & standard document content 94 | /*--------------------------------------------------------------------------*/ 95 | 96 | body { 97 | font-family: 'Open Sans', serif; 98 | padding-top: 0px; 99 | padding-bottom: 40px; 100 | } 101 | 102 | pre { 103 | word-wrap: inherit; 104 | } 105 | 106 | /* Format the heading - nicer spacing etc. */ 107 | .masthead { 108 | overflow: hidden; 109 | } 110 | .masthead .muted a { 111 | text-decoration:none; 112 | color:#999999; 113 | } 114 | .masthead ul, .masthead li { 115 | margin-bottom:0px; 116 | } 117 | .masthead .nav li { 118 | margin-top: 15px; 119 | font-size:110%; 120 | } 121 | .masthead h3 { 122 | margin-bottom:5px; 123 | font-size:170%; 124 | } 125 | hr { 126 | margin:0px 0px 20px 0px; 127 | } 128 | 129 | /* Make table headings and td.title bold */ 130 | td.title, thead { 131 | font-weight:bold; 132 | } 133 | 134 | /* Format the right-side menu */ 135 | #menu { 136 | margin-top:50px; 137 | font-size:11pt; 138 | padding-left:20px; 139 | } 140 | 141 | #menu .nav-header { 142 | font-size:12pt; 143 | color:#606060; 144 | margin-top:20px; 145 | } 146 | 147 | #menu li { 148 | line-height:25px; 149 | } 150 | 151 | /* Change font sizes for headings etc. */ 152 | #main h1 { font-size: 26pt; margin:10px 0px 15px 0px; font-weight:400; } 153 | #main h2 { font-size: 20pt; margin:20px 0px 0px 0px; font-weight:400; } 154 | #main h3 { font-size: 14pt; margin:15px 0px 0px 0px; font-weight:600; } 155 | #main p { font-size: 11pt; margin:5px 0px 15px 0px; } 156 | #main ul { font-size: 11pt; margin-top:10px; } 157 | #main li { font-size: 11pt; margin: 5px 0px 5px 0px; } 158 | #main strong { font-weight:700; } 159 | 160 | /*-------------------------------------------------------------------------- 161 | Formatting for API reference 162 | /*--------------------------------------------------------------------------*/ 163 | 164 | .type-list .type-name, .module-list .module-name { 165 | width:25%; 166 | font-weight:bold; 167 | } 168 | .member-list .member-name { 169 | width:35%; 170 | } 171 | #main .xmldoc h2 { 172 | font-size:14pt; 173 | margin:10px 0px 0px 0px; 174 | } 175 | #main .xmldoc h3 { 176 | font-size:12pt; 177 | margin:10px 0px 0px 0px; 178 | } 179 | .github-link { 180 | float:right; 181 | text-decoration:none; 182 | } 183 | .github-link img { 184 | border-style:none; 185 | margin-left:10px; 186 | } 187 | .github-link .hover { display:none; } 188 | .github-link:hover .hover { display:block; } 189 | .github-link .normal { display: block; } 190 | .github-link:hover .normal { display: none; } 191 | 192 | /*-------------------------------------------------------------------------- 193 | Links 194 | /*--------------------------------------------------------------------------*/ 195 | 196 | h1 a, h1 a:hover, h1 a:focus, 197 | h2 a, h2 a:hover, h2 a:focus, 198 | h3 a, h3 a:hover, h3 a:focus, 199 | h4 a, h4 a:hover, h4 a:focus, 200 | h5 a, h5 a:hover, h5 a:focus, 201 | h6 a, h6 a:hover, h6 a:focus { color : inherit; text-decoration : inherit; outline:none } 202 | 203 | /*-------------------------------------------------------------------------- 204 | Additional formatting for the homepage 205 | /*--------------------------------------------------------------------------*/ 206 | 207 | #nuget { 208 | margin-top:20px; 209 | font-size: 11pt; 210 | padding:20px; 211 | } 212 | 213 | #nuget pre { 214 | font-size:11pt; 215 | -moz-border-radius: 0px; 216 | -webkit-border-radius: 0px; 217 | border-radius: 0px; 218 | background: #404040; 219 | border-style:none; 220 | color: #e0e0e0; 221 | margin-top:15px; 222 | } -------------------------------------------------------------------------------- /docs/input/files/misc/style.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans+Mono|Open+Sans:400,600,700); 2 | 3 | /*-------------------------------------------------------------------------- 4 | Formatting for F# code snippets 5 | /*--------------------------------------------------------------------------*/ 6 | 7 | /* strings --- and stlyes for other string related formats */ 8 | span.s { color:#E0E268; } 9 | /* printf formatters */ 10 | span.pf { color:#E0C57F; } 11 | /* escaped chars */ 12 | span.e { color:#EA8675; } 13 | 14 | /* identifiers --- and styles for more specific identifier types */ 15 | span.i { color:#d1d1d1; } 16 | /* type or module */ 17 | span.t { color:#43AEC6; } 18 | /* function */ 19 | span.f { color:#e1e1e1; } 20 | /* DU case or active pattern */ 21 | span.p { color:#4ec9b0; } 22 | 23 | /* keywords */ 24 | span.k { color:#FAB11D; } 25 | /* comment */ 26 | span.c { color:#808080; } 27 | /* operators */ 28 | span.o { color:#af75c1; } 29 | /* numbers */ 30 | span.n { color:#96C71D; } 31 | /* line number */ 32 | span.l { color:#80b0b0; } 33 | /* mutable var or ref cell */ 34 | span.v { color:#d1d1d1; font-weight: bold; } 35 | /* inactive code */ 36 | span.inactive { color:#808080; } 37 | /* preprocessor */ 38 | span.prep { color:#af75c1; } 39 | /* fsi output */ 40 | span.fsi { color:#808080; } 41 | 42 | /* omitted */ 43 | span.omitted { 44 | background:#3c4e52; 45 | border-radius:5px; 46 | color:#808080; 47 | padding:0px 0px 1px 0px; 48 | } 49 | /* tool tip */ 50 | div.tip { 51 | background:#475b5f; 52 | border-radius:4px; 53 | font:11pt 'Droid Sans', arial, sans-serif; 54 | padding:6px 8px 6px 8px; 55 | display:none; 56 | color:#d1d1d1; 57 | } 58 | table.pre pre { 59 | padding:0px; 60 | margin:0px; 61 | border:none; 62 | } 63 | table.pre, pre.fssnip, pre { 64 | line-height:13pt; 65 | border:1px solid #d8d8d8; 66 | border-collapse:separate; 67 | white-space:pre; 68 | font: 9pt 'Droid Sans Mono',consolas,monospace; 69 | width:90%; 70 | margin:10px 20px 20px 20px; 71 | background-color:#212d30; 72 | padding:10px; 73 | border-radius:5px; 74 | color:#d1d1d1; 75 | } 76 | table.pre pre { 77 | padding:0px; 78 | margin:0px; 79 | border-radius:0px; 80 | width: 100%; 81 | } 82 | table.pre td { 83 | padding:0px; 84 | white-space:normal; 85 | margin:0px; 86 | } 87 | table.pre td.lines { 88 | width:30px; 89 | } 90 | 91 | /*-------------------------------------------------------------------------- 92 | Formatting for page & standard document content 93 | /*--------------------------------------------------------------------------*/ 94 | 95 | body { 96 | font-family: 'Open Sans', serif; 97 | padding-top: 0px; 98 | padding-bottom: 40px; 99 | } 100 | 101 | pre { 102 | word-wrap: inherit; 103 | } 104 | 105 | /* Format the heading - nicer spacing etc. */ 106 | .masthead { 107 | overflow: hidden; 108 | } 109 | .masthead .muted a { 110 | text-decoration:none; 111 | color:#999999; 112 | } 113 | .masthead ul, .masthead li { 114 | margin-bottom:0px; 115 | } 116 | .masthead .nav li { 117 | margin-top: 15px; 118 | font-size:110%; 119 | } 120 | .masthead h3 { 121 | margin-bottom:5px; 122 | font-size:170%; 123 | } 124 | hr { 125 | margin:0px 0px 20px 0px; 126 | } 127 | 128 | /* Make table headings and td.title bold */ 129 | td.title, thead { 130 | font-weight:bold; 131 | } 132 | 133 | /* Format the right-side menu */ 134 | #menu { 135 | margin-top:50px; 136 | font-size:11pt; 137 | padding-left:20px; 138 | } 139 | 140 | #menu .nav-header { 141 | font-size:12pt; 142 | color:#606060; 143 | margin-top:20px; 144 | } 145 | 146 | #menu li { 147 | line-height:25px; 148 | } 149 | 150 | /* Change font sizes for headings etc. */ 151 | #main h1 { font-size: 26pt; margin:10px 0px 15px 0px; font-weight:400; } 152 | #main h2 { font-size: 20pt; margin:20px 0px 0px 0px; font-weight:400; } 153 | #main h3 { font-size: 14pt; margin:15px 0px 0px 0px; font-weight:600; } 154 | #main p { font-size: 11pt; margin:5px 0px 15px 0px; } 155 | #main ul { font-size: 11pt; margin-top:10px; } 156 | #main li { font-size: 11pt; margin: 5px 0px 5px 0px; } 157 | #main strong { font-weight:700; } 158 | 159 | /*-------------------------------------------------------------------------- 160 | Formatting for API reference 161 | /*--------------------------------------------------------------------------*/ 162 | 163 | .type-list .type-name, .module-list .module-name { 164 | width:25%; 165 | font-weight:bold; 166 | } 167 | .member-list .member-name { 168 | width:35%; 169 | } 170 | #main .xmldoc h2 { 171 | font-size:14pt; 172 | margin:10px 0px 0px 0px; 173 | } 174 | #main .xmldoc h3 { 175 | font-size:12pt; 176 | margin:10px 0px 0px 0px; 177 | } 178 | .github-link { 179 | float:right; 180 | text-decoration:none; 181 | } 182 | .github-link img { 183 | border-style:none; 184 | margin-left:10px; 185 | } 186 | .github-link .hover { display:none; } 187 | .github-link:hover .hover { display:block; } 188 | .github-link .normal { display: block; } 189 | .github-link:hover .normal { display: none; } 190 | 191 | /*-------------------------------------------------------------------------- 192 | Links 193 | /*--------------------------------------------------------------------------*/ 194 | 195 | h1 a, h1 a:hover, h1 a:focus, 196 | h2 a, h2 a:hover, h2 a:focus, 197 | h3 a, h3 a:hover, h3 a:focus, 198 | h4 a, h4 a:hover, h4 a:focus, 199 | h5 a, h5 a:hover, h5 a:focus, 200 | h6 a, h6 a:hover, h6 a:focus { color : inherit; text-decoration : inherit; outline:none } 201 | 202 | /*-------------------------------------------------------------------------- 203 | Additional formatting for the homepage 204 | /*--------------------------------------------------------------------------*/ 205 | 206 | #nuget { 207 | margin-top:20px; 208 | font-size: 11pt; 209 | padding:20px; 210 | } 211 | 212 | #nuget pre { 213 | font-size:11pt; 214 | -moz-border-radius: 0px; 215 | -webkit-border-radius: 0px; 216 | border-radius: 0px; 217 | background: #404040; 218 | border-style:none; 219 | color: #e0e0e0; 220 | margin-top:15px; 221 | } -------------------------------------------------------------------------------- /docs/input/vector-operations.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | #r "../../src/FsAlg/bin/Debug/FsAlg.dll" 3 | 4 | (** 5 | Vector Operations 6 | ================= 7 | 8 | This page lists only a selection of commonly used vector operations provided by FsAlg. 9 | 10 | Please refer to [API Reference](reference/index.html) for a full list of supported operations. 11 | 12 | The **FsAlg.Generic.Vector** module provides functionality similar to the F# [Collecitons.Array](https://msdn.microsoft.com/en-us/library/ee370273.aspx) module, for creating and manipulating vectors. 13 | 14 | Creating Vectors 15 | ---------------- 16 | *) 17 | 18 | open FsAlg.Generic 19 | 20 | let v1 = vector [1.; 2.; 3.] 21 | let v2 = Vector.create 3 1. 22 | let v3 = Vector.init 3 (fun i -> exp (float i)) 23 | 24 | (*** hide, define-output: o ***) 25 | printf "val v1 : Vector = Vector [|1.0; 2.0; 3.0|] 26 | val v2 : Vector = Vector [|1.0; 1.0; 1.0|] 27 | val v3 : Vector = Vector [|1.0; 2.718281828; 7.389056099|]" 28 | (*** include-output: o ***) 29 | 30 | (** 31 | Basic Operations 32 | ---------------- 33 | *) 34 | 35 | let v4 = v1 + v2 // Vector addition 36 | let v5 = v1 - v2 // Vector substraction 37 | let v6 = v1 * v2 // Vector inner product (dot / scalar product) 38 | let v7 = v1 %* v2 // Vector cross product 39 | let v8 = v1 .* v2 // Vector element-wise (Hadamard) product 40 | let v9 = v1 ./ v2 // Vector element-wise (Hadamard) division 41 | let v10 = v1 + 2. // Add scalar to vector 42 | let v11 = v1 - 2. // Subtract scalar from vector 43 | let v12 = 2. - v1 // Subtract each element of vector from scalar 44 | let v13 = v1 * 2. // Vector-scalar multiplication 45 | let v14 = v1 / 2. // Vector-scalar division 46 | let v15 = 2. / v1 // Divides each element of vector by scalar 47 | let v16 = -v1 // Unary negation 48 | 49 | (*** hide, define-output: o2 ***) 50 | printf "val v4 : Vector = Vector [|2.0; 3.0; 4.0|] 51 | val v5 : Vector = Vector [|0.0; 1.0; 2.0|] 52 | val v6 : float = 6.0 53 | val v7 : Vector = Vector [|-1.0; 2.0; -1.0|] 54 | val v8 : Vector = Vector [|1.0; 2.0; 3.0|] 55 | val v9 : Vector = Vector [|1.0; 2.0; 3.0|] 56 | val v10 : Vector = Vector [|3.0; 4.0; 5.0|] 57 | val v11 : Vector = Vector [|-1.0; 0.0; 1.0|] 58 | val v12 : Vector = Vector [|1.0; 0.0; -1.0|] 59 | val v13 : Vector = Vector [|2.0; 4.0; 6.0|] 60 | val v14 : Vector = Vector [|0.5; 1.0; 1.5|] 61 | val v15 : Vector = Vector [|2.0; 1.0; 0.6666666667|] 62 | val v16 : Vector = Vector [|-1.0; -2.0; -3.0|]" 63 | (*** include-output: o2 ***) 64 | 65 | (** 66 | Vector Norms 67 | ------------ 68 | *) 69 | 70 | let n1 = Vector.l1norm v1 // L1 norm 71 | let n2 = Vector.l2norm v1 // L2 norm 72 | let n3 = Vector.l2normSq v1 // Squared L2 norm 73 | let n4 = Vector.lpnorm 3. v1 // Lp norm 74 | 75 | (*** hide, define-output: o3 ***) 76 | printf "val n1 : float = 6.0 77 | val n2 : float = 3.741657387 78 | val n3 : float = 14.0 79 | val n4 : float = 3.301927249" 80 | (*** include-output: o3 ***) 81 | 82 | (** 83 | Accessing Elements & Conversions 84 | -------------------------------- 85 | *) 86 | 87 | let e1 = v1.[0] // 1st element of v1 88 | let e2 = Vector.get v1 1 // 2nd element of v1 89 | let e3 = v1.[..1] // Slice, until 2nd element 90 | let e4 = v1.[1..2] // Slice, between 2nd and 3rd elements 91 | let v20 = Vector.ofSeq [1.; 2.; 3.] // Convert sequence to vector 92 | let v21 = vector [1.; 2.; 3.] // Same with above, supports lists, 93 | let v22 = vector [|1.; 2.; 3.|] // arrays, 94 | let v23 = vector (seq {yield 1.}) // and sequences. 95 | let aa1 = Vector.toArray v1 // Convert vector to array 96 | let sq1 = Vector.toSeq v1 // Convert vector to sequence 97 | 98 | (*** hide, define-output: o4 ***) 99 | printf "val e1 : float = 1.0 100 | val e2 : float = 2.0 101 | val e3 : Vector = Vector [|1.0; 2.0|] 102 | val e4 : Vector = Vector [|2.0; 3.0|] 103 | val v20 : Vector = Vector [|1.0; 2.0; 3.0|] 104 | val v21 : Vector = Vector [|1.0; 2.0; 3.0|] 105 | val v22 : Vector = Vector [|1.0; 2.0; 3.0|] 106 | val v23 : Vector = Vector [|1.0|] 107 | val aa1 : float [] = [|1.0; 2.0; 3.0|] 108 | val sq1 : seq" 109 | (*** include-output: o4 ***) 110 | 111 | (** 112 | Mutating/Replacing Elements 113 | ------------------ 114 | *) 115 | v1.[0] <- 4. // Mutate an element 116 | Vector.replace (fun x -> x + 2.) v1 // Replace by mapping a function, mutating in place 117 | Vector.replacei (fun i x -> x + float i) v1 // Replace in place, with index 118 | Vector.replace2 (fun x y -> x - y) v1 v2 // Replace v1 in place, using a function of v1 and v2 119 | Vector.replacei2 (fun i x y -> x - y + float i) v1 v2 // Replace v1 in place, with index 120 | Vector.replaceWith v1 v2 // Replace elements of v1 with v2, mutating in place 121 | 122 | (** 123 | Splitting and Concatenating 124 | --------------------------- 125 | *) 126 | 127 | let ss1 = Vector.splitEqual 3 (vector [1.; 2.; 3.; 4.; 5.; 6.]) // Split into 3 vectors of equal length 128 | let ss2 = Vector.split [2; 4] (vector [1.; 2.; 3.; 4.; 5.; 6.]) // Split into vectors of given lengths 129 | let cc1 = Vector.concat ss1 // Concatenate vectors into one 130 | 131 | (*** hide, define-output: o5 ***) 132 | printf "val ss1 : seq> 133 | val ss2 : seq> 134 | val cc1 : Vector = Vector [|1.0; 2.0; 3.0; 4.0; 5.0; 6.0|]" 135 | (*** include-output: o5 ***) 136 | 137 | (** 138 | Mathematica and MATLAB Strings 139 | ------------------------------ 140 | 141 | You can generate string representations of vectors that you can copy and paste into Mathematica notebooks or MATLAB. 142 | *) 143 | 144 | let s1 = v1.ToMathematicaString() 145 | let s2 = v1.ToMatlabString() 146 | 147 | (*** hide, define-output: o6 ***) 148 | printf "val s1 : string = \"{1.00, 2.00, 3.00}\" 149 | val s2 : string = \"[1.00 2.00 3.00]\"" 150 | (*** include-output: o6 ***) 151 | 152 | (** 153 | Other Operations 154 | --------------------- 155 | The following are just a selection of other operations. Please refer to [API Reference](reference/index.html) for a full list of supported operations. 156 | *) 157 | 158 | let len = Vector.length v1 // Length of vector 159 | let min = Vector.min v1 // Minimum element of vector 160 | let max = Vector.max v1 // Maximum element of vector 161 | let sum = Vector.sum v1 // Sum elements of vector 162 | let v17 = Vector.unitVector v1 // Get unit vector codirectional with v1 163 | let v18 = Vector.map (fun x -> sin x) v1 // Map function to vector 164 | let v19 = Vector.fold (fun s x -> s + sin x) 0. v1 // Fold a vector 165 | 166 | (*** hide, define-output: o7 ***) 167 | printf "val len : int = 3 168 | val min : float = 1.0 169 | val max : float = 3.0 170 | val sum : float = 6.0 171 | val v17 : Vector = Vector [|0.2672612419; 0.5345224838; 0.8017837257|] 172 | val v18 : Vector = Vector [|0.8414709848; 0.9092974268; 0.1411200081|] 173 | val v19 : float = 1.89188842" 174 | (*** include-output: o7 ***) -------------------------------------------------------------------------------- /docs/input/matrix-operations.fsx: -------------------------------------------------------------------------------- 1 | (*** hide ***) 2 | #r "../../src/FsAlg/bin/Debug/FsAlg.dll" 3 | 4 | (** 5 | Matrix Operations 6 | ================= 7 | 8 | This page lists only a selection of commonly used matrix operations provided by FsAlg. 9 | 10 | Please refer to [API Reference](reference/index.html) for a full list of supported operations. 11 | 12 | The **FsAlg.Generic.Matrix** module provides functionality similar to the F# [Collecitons.Array2D](https://msdn.microsoft.com/en-us/library/ee353794.aspx) module, for creating and manipulating matrices. 13 | 14 | Creating Matrices 15 | ----------------- 16 | *) 17 | 18 | open FsAlg.Generic 19 | 20 | let m1 = matrix [[1.; 2.]; [3.; 4.]] 21 | let m2 = Matrix.create 2 2 1. 22 | let m3 = Matrix.init 2 2 (fun i j -> exp (float (i + j))) 23 | 24 | (*** hide, define-output: o ***) 25 | printf "val m1 : Matrix = Matrix [[1.0; 1.0] 26 | [1.0; 1.0]] 27 | val m2 : Matrix = Matrix [[1.0; 1.0] 28 | [1.0; 1.0]] 29 | val m3 : Matrix = Matrix [[1.0; 2.718281828] 30 | [2.718281828; 7.389056099]]" 31 | (*** include-output: o ***) 32 | 33 | (** 34 | Basic Operations 35 | ---------------- 36 | *) 37 | 38 | let m4 = m1 + m2 // Matrix addition 39 | let m5 = m1 - m2 // Matrix subtraction 40 | let m6 = m1 * m2 // Matrix product 41 | let m7 = m1 .* m2 // Matrix element-wise (Hadamard) product 42 | let m8 = m1 ./ m2 // Matrix element-wise (Hadamard) division 43 | 44 | let v = vector [1.; 2.] 45 | let m9 = m1 * v // Matrix-vector product 46 | let m10 = v * m1 // Vector-matrix product 47 | 48 | let m11 = m1 + 2. // Add scalar to matrix 49 | let m12 = m1 - 2. // Subtract scalar from matrix 50 | let m13 = 2. - m1 // Subtract each element of matrix from scalar 51 | let m14 = m1 * 2. // Matrix-scalar multiplication 52 | let m15 = m1 / 2. // Matrix-scalar division 53 | let m16 = 2. / m1 // Divides each element of matrix by scalar 54 | let m17 = -m1 // Unary negation 55 | 56 | (*** hide, define-output: o2 ***) 57 | printf "val m4 : Matrix = Matrix [[2.0; 3.0] 58 | [4.0; 5.0]] 59 | val m5 : Matrix = Matrix [[0.0; 1.0] 60 | [2.0; 3.0]] 61 | val m6 : Matrix = Matrix [[3.0; 3.0] 62 | [7.0; 7.0]] 63 | val m7 : Matrix = Matrix [[1.0; 2.0] 64 | [3.0; 4.0]] 65 | val m8 : Matrix = Matrix [[1.0; 2.0] 66 | [3.0; 4.0]] 67 | val v : Vector = Vector [|1.0; 2.0|] 68 | val m9 : Vector = Vector [|5.0; 11.0|] 69 | val m10 : Vector = Vector [|7.0; 10.0|] 70 | val m11 : Matrix = Matrix [[3.0; 4.0] 71 | [5.0; 6.0]] 72 | val m12 : Matrix = Matrix [[-1.0; 0.0] 73 | [1.0; 2.0]] 74 | val m13 : Matrix = Matrix [[1.0; 0.0] 75 | [-1.0; -2.0]] 76 | val m14 : Matrix = Matrix [[2.0; 4.0] 77 | [6.0; 8.0]] 78 | val m15 : Matrix = Matrix [[0.5; 1.0] 79 | [1.5; 2.0]] 80 | val m16 : Matrix = Matrix [[2.0; 1.0] 81 | [0.6666666667; 0.5]] 82 | val m17 : Matrix = Matrix [[-1.0; -2.0] 83 | [-3.0; -4.0]]" 84 | (*** include-output: o2 ***) 85 | 86 | (** 87 | Matrix Operations 88 | ----------------- 89 | *) 90 | 91 | let m1det = Matrix.det m1 // Determinant 92 | let m1inv = Matrix.inverse m1 // Inverse 93 | let m1eig = Matrix.eigenvalues m1 // Eigenvalues 94 | let m1t = Matrix.transpose m1 // Transpose 95 | let m1tr = Matrix.trace m1 // Trace 96 | let m1dia = Matrix.diagonal m1 // Diagonal 97 | 98 | (*** hide, define-output: o3 ***) 99 | printf "val m1det : float = -2.0 100 | val m1inv : Matrix = Matrix [[-2.0; 1.0] 101 | [1.5; -0.5]] 102 | val m1eig : Vector = Vector [|5.372281312; -0.3722813117|] 103 | val m1t : Matrix = Matrix [[1.0; 3.0] 104 | [2.0; 4.0]] 105 | val m1tr : float = 5.0 106 | val m1dia : Vector = Vector [|1.0; 4.0|]" 107 | (*** include-output: o3 ***) 108 | 109 | (** 110 | Solving Systems of Linear Equations 111 | ----------------------------------- 112 | We can solve a [system of linear equations](http://en.wikipedia.org/wiki/System_of_linear_equations) represented in matrix form $\mathbf{A} \mathbf{x} = \mathbf{b} \;,$ which has solution $\mathbf{x} = \mathbf{A}^{-1} \mathbf{b}\;$. 113 | 114 | For example, the system 115 | 116 | $$$ 117 | \begin{eqnarray*} 118 | 3x + 2y - z &=& 1\\ 119 | 2x - 2y +4z &=& -2\\ 120 | -x + 0.5y -z &=& 0\\ 121 | \end{eqnarray*} 122 | 123 | can be represented as 124 | 125 | $$$ 126 | \begin{bmatrix} 127 | 3 & 2 & -1\\ 128 | 2 & -2 & 4\\ 129 | -1& 0.5 &-1\\ 130 | \end{bmatrix} \begin{bmatrix} 131 | x\\ 132 | y\\ 133 | z\\ 134 | \end{bmatrix} = \begin{bmatrix} 135 | 1\\ 136 | -2\\ 137 | 0\\ 138 | \end{bmatrix} 139 | 140 | and has solution 141 | 142 | $$$ 143 | \begin{eqnarray*} 144 | x &=& 1\\ 145 | y &=& -2\\ 146 | z &=& -2\\ 147 | \end{eqnarray*}\; . 148 | *) 149 | 150 | let A = matrix [[3.; 2.; -1.]; [2.; -2.; 4.]; [-1.; 0.5; -1.]] 151 | let b = vector [1.; -2.; 0.] 152 | 153 | let x = Matrix.solve A b 154 | 155 | (*** hide, define-output: o4 ***) 156 | printf "val A : Matrix = Matrix [[3.0; 2.0; -1.0] 157 | [2.0; -2.0; 4.0] 158 | [-1.0; 0.5; -1.0]] 159 | val b : Vector = Vector [|1.0; -2.0; 0.0|] 160 | val x : Vector = Vector [|1.0; -2.0; -2.0|]" 161 | (*** include-output: o4 ***) 162 | 163 | (** 164 | Matrix Decompositions 165 | --------------------- 166 | *) 167 | 168 | let lu, piv, togg = Matrix.decomposeLU m1 // LU decomposition 169 | let q, r = Matrix.decomposeQR m1 // QR decomposition 170 | 171 | (*** hide, define-output: o5 ***) 172 | printf "val togg : float = -1.0 173 | val piv : int [] = [|1; 0|] 174 | val lu : Matrix = Matrix [[3.0; 4.0] 175 | [0.3333333333; 0.6666666667]] 176 | val r : Matrix = Matrix [[3.16227766; 4.427188724] 177 | [4.440892099e-16; 0.632455532]] 178 | val q : Matrix = Matrix [[0.316227766; 0.9486832981] 179 | [0.9486832981; -0.316227766]]" 180 | (*** include-output: o5 ***) 181 | 182 | (** 183 | Accessing Elements & Conversions 184 | -------------------------------- 185 | *) 186 | 187 | let el1 = m1.[0, 0] // Element at 0, 0 188 | let el2 = Matrix.get m1 1 1 // Element at 1, 1 189 | let sl1 = m1.[0..1, 1..] // Slice, between rows 0 and 1, columns 1 and beyond 190 | let sl2 = m1.[*, 0..1] // Slice, all rows, between columns 0 and 1 191 | let sl3 = m1.[0, *] // Return row 0 192 | let sl4 = Matrix.row 0 m1 // Return row 0 193 | let sl5 = m1.[*, 1] // Return column 1 194 | let sl6 = Matrix.col 1 m1 // Return column 1 195 | let sl7 = Matrix.toRows m1 // Return rows as a sequence 196 | let m18 = Matrix.ofRows [vector [1.;2.]; vector [3.;4.]] // Create matrix from row vectors 197 | let sl8 = Matrix.toCols m1 // Return columns as a sequence 198 | let m19 = Matrix.ofCols [vector [1.;2.]; vector [3.;4.]] // Create matrix from column vectors 199 | let m20 = Matrix.ofSeqSeq [[1.; 2.]; [3.; 4.]] // Convert sequence of sequences to matrix 200 | let m21 = matrix [[1.; 2.]; [3.; 4.]] // Same with above, supports lists, 201 | let m22 = matrix [|[|1.; 2.|]; [|3.; 4.|]|] // arrays, 202 | let m23 = matrix (seq {yield seq {yield 1.}}) // and sequences. 203 | let aa1 = Matrix.toArrayArray m1 // Convert matrix to jagged array 204 | let aa2 = Matrix.toArray2D m1 // Convert matrix to 2d array 205 | let aa3 = Matrix.toArray m1 // Convert matrix to 1d array, scanning left to right, top to bottom 206 | let ma3 = Matrix.ofArray 2 aa3 // Convert 1d array to matrix, populating two rows 207 | let vv1 = Matrix.toVector m1 // Convert matrix to vector, scanning left to right, top to bottom 208 | let mv1 = Matrix.ofVector 2 vv1 // Convert vector to matrix, populating two rows 209 | 210 | (*** hide, define-output: o6 ***) 211 | printf "val el1 : float = 1.0 212 | val el2 : float = 4.0 213 | val sl1 : Matrix = Matrix [[2.0] 214 | [4.0]] 215 | val sl2 : Matrix = Matrix [[1.0; 2.0] 216 | [3.0; 4.0]] 217 | val sl3 : Matrix = Matrix [[1.0; 2.0]] 218 | val sl4 : Matrix = Matrix [[1.0; 2.0]] 219 | val sl5 : Matrix = Matrix [[2.0] 220 | [4.0]] 221 | val sl6 : Matrix = Matrix [[2.0] 222 | [4.0]] 223 | val sl7 : seq> 224 | val m18 : Matrix = Matrix [[1.0; 2.0] 225 | [3.0; 4.0]] 226 | val sl8 : seq> 227 | val m19 : Matrix = Matrix [[1.0; 3.0] 228 | [2.0; 4.0]] 229 | val m20 : Matrix = Matrix [[1.0; 2.0] 230 | [3.0; 4.0]] 231 | val m21 : Matrix = Matrix [[1.0; 2.0] 232 | [3.0; 4.0]] 233 | val m22 : Matrix = Matrix [[1.0; 2.0] 234 | [3.0; 4.0]] 235 | val m23 : Matrix = Matrix [[1.0]] 236 | val aa1 : float [] [] = [|[|1.0; 2.0|]; [|3.0; 4.0|]|] 237 | val aa2 : float [,] = [[1.0; 1.0] 238 | [1.0; 1.0]] 239 | val aa3 : float [] = [|1.0; 2.0; 3.0; 4.0|] 240 | val ma3 : Matrix = Matrix [[1.0; 2.0] 241 | [3.0; 4.0]] 242 | val vv1 : Vector = Vector [|1.0; 2.0; 3.0; 4.0|] 243 | val mv1 : Matrix = Matrix [[1.0; 2.0] 244 | [3.0; 4.0]]" 245 | (*** include-output: o6 ***) 246 | 247 | 248 | (** 249 | Mutating/Replacing Elements 250 | ------------------ 251 | *) 252 | 253 | m1.[0, 0] <- 4. // Mutate an element 254 | Matrix.replace (fun x -> x + 2.) m1 // Replace by mapping a function, mutating in place 255 | Matrix.replacei (fun i j x -> x + float (i * j)) m1 // Replace in place, with index 256 | Matrix.replace2 (fun x y -> x - y) m1 m2 // Replace m1 in place, using a function of m1 and m2 257 | Matrix.replacei2 (fun i j x y -> x - y + float (i * j)) m1 m2 // Replace m1 in place, with index 258 | Matrix.replaceWith m1 m2 // Replace elements of m1 with m2, mutating in place 259 | Matrix.appendRow v m1 // Append a vector to a matrix as a new row 260 | Matrix.appendCol v m1 // Append a vector to a matrix as a new column 261 | Matrix.prependRow v m1 // Prepend a vector to a matrix as a new row 262 | Matrix.prependCol v m1 // Prepend a vector to a matrix as a new column 263 | 264 | (** 265 | Mathematica and MATLAB Strings 266 | ------------------------------ 267 | You can generate string representations of matrices that you can copy and paste into Mathematica notebooks or MATLAB. 268 | *) 269 | 270 | let s1 = m1.ToMathematicaString() 271 | let s2 = m2.ToMatlabString() 272 | 273 | (*** hide, define-output: o7 ***) 274 | printf "val s1 : string = \"{{1.00, 2.00}, {3.00, 4.00}}\" 275 | val s2 : string = \"[1.00 1.00; 1.00 1.00]\"" 276 | (*** include-output: o7 ***) 277 | 278 | (** 279 | Other Operations 280 | --------------------- 281 | The following are just a selection of other operations. Please refer to [API Reference](reference/index.html) for a full list of supported operations. 282 | *) 283 | 284 | let l1 = Matrix.rows m1 // Number of rows 285 | let l2 = Matrix.cols m1 // Number of columns 286 | let m24 = Matrix.map (fun x -> sin x) m1 // Map function to matrix 287 | 288 | (*** hide, define-output: o8 ***) 289 | printf "val l1 : int = 2 290 | val l2 : int = 2 291 | val m24 : Matrix = Matrix [[0.8414709848; 0.8414709848] 292 | [0.8414709848; 0.8414709848]]" 293 | (*** include-output: o8 ***) 294 | -------------------------------------------------------------------------------- /src/FsAlg/Vector.fs: -------------------------------------------------------------------------------- 1 | // 2 | // This file is part of 3 | // FsAlg: Generic Linear Algebra Library 4 | // 5 | // Copyright (c) 2015, National University of Ireland Maynooth (Atilim Gunes Baydin, Barak A. Pearlmutter) 6 | // 7 | // FsAlg is released under the BSD license. 8 | // (See accompanying LICENSE file.) 9 | // 10 | // Written by: 11 | // 12 | // Atilim Gunes Baydin 13 | // atilimgunes.baydin@nuim.ie 14 | // 15 | // Barak A. Pearlmutter 16 | // barak@cs.nuim.ie 17 | // 18 | // Brain and Computation Lab 19 | // Hamilton Institute & Department of Computer Science 20 | // National University of Ireland Maynooth 21 | // Maynooth, Co. Kildare 22 | // Ireland 23 | // 24 | // www.bcl.hamilton.ie 25 | // 26 | 27 | namespace FsAlg.Generic 28 | 29 | open FsAlg.Generic.Util 30 | 31 | /// Generic vector type 32 | [] 33 | type Vector<'T when 'T : (static member Zero : 'T) 34 | and 'T : (static member One : 'T) 35 | and 'T : (static member (+) : 'T * 'T -> 'T) 36 | and 'T : (static member (-) : 'T * 'T -> 'T) 37 | and 'T : (static member (*) : 'T * 'T -> 'T) 38 | and 'T : (static member (/) : 'T * 'T -> 'T) 39 | and 'T : (static member (~-) : 'T -> 'T) 40 | and 'T : (static member Abs : 'T -> 'T) 41 | and 'T : (static member Pow : 'T * 'T -> 'T) 42 | and 'T : (static member Sqrt : 'T -> 'T) 43 | and 'T : (static member op_Explicit : 'T -> float) 44 | and 'T : comparison> = 45 | | ZeroVector of 'T 46 | | Vector of 'T[] 47 | /// ZeroVector 48 | static member inline Zero = ZeroVector LanguagePrimitives.GenericZero<'T> 49 | /// Converts vector `v` to float[] 50 | static member inline op_Explicit(v:Vector<'T>) = 51 | match v with 52 | | Vector v -> Array.map float v 53 | | ZeroVector _ -> [||] 54 | /// The element of this vector at the given position `i` 55 | member inline v.Item 56 | with get i = 57 | match v with 58 | | Vector v -> v.[i] 59 | | ZeroVector z -> z 60 | and set i vv = 61 | match v with 62 | | Vector v -> v.[i] <- vv 63 | | ZeroVector _ -> () 64 | /// Gets a subvector between bounds `lower` and `upper` 65 | member inline v.GetSlice(lower, upper) = 66 | match v with 67 | | Vector v -> 68 | let l = defaultArg lower 0 69 | let u = defaultArg upper (v.Length - 1) 70 | if l > u then invalidArg "" "Given slice bounds are invalid." 71 | Vector v.[l..u] 72 | | ZeroVector _ -> invalidArg "" "Cannot get slice of a ZeroVector." 73 | /// Gets the first element of this vector 74 | member inline v.FirstItem = 75 | match v with 76 | | Vector v -> v.[0] 77 | | ZeroVector z -> z 78 | /// Gets the total number of elements of this vector 79 | member inline v.Length = 80 | match v with 81 | | Vector v -> v.Length 82 | | ZeroVector _ -> 0 83 | /// Gets the L1 (Manhattan) norm of this vector 84 | member inline v.GetL1Norm() = 85 | match v with 86 | | Vector v -> Array.sumBy abs v 87 | | ZeroVector z -> z 88 | /// Gets the L2 (Euclidean) norm of this vector 89 | member inline v.GetL2Norm() = 90 | match v with 91 | | Vector v -> sqrt (Array.sumBy (fun x -> x * x) v) 92 | | ZeroVector z -> z 93 | /// Gets the squared L2 (Euclidean) norm of this vector 94 | member inline v.GetL2NormSq() = 95 | match v with 96 | | Vector v -> Array.sumBy (fun x -> x * x) v 97 | | ZeroVector z -> z 98 | /// Gets the Lp norm (or p-norm) of this vector, with the given `p` 99 | member inline v.GetLPNorm(p:'T):'T = 100 | match v with 101 | | Vector v -> (Array.sumBy (fun x -> (abs x) ** p) v) ** (LanguagePrimitives.GenericOne<'T> / p) 102 | | ZeroVector z -> z 103 | /// Gets the minimum element of this vector 104 | member inline v.GetMin() = 105 | match v with 106 | | Vector v -> Array.min v 107 | | ZeroVector z -> z 108 | /// Gets the minimum element of this vector, compared by using Operators.min on the result of function `f` 109 | member inline v.GetMinBy(f) = 110 | match v with 111 | | Vector v -> Array.minBy f v 112 | | ZeroVector z -> z 113 | /// Gets the maximum element of this vector 114 | member inline v.GetMax() = 115 | match v with 116 | | Vector v -> Array.max v 117 | | ZeroVector z -> z 118 | /// Gets the maximum element of this vector, compared by using Operators.max on the result of function `f` 119 | member inline v.GetMaxBy(f) = 120 | match v with 121 | | Vector v -> Array.maxBy f v 122 | | ZeroVector z -> z 123 | /// Gets the unit vector codirectional with this vector 124 | member inline v.GetUnitVector() = 125 | match v with 126 | | Vector vv -> let n = v.GetL2Norm() in Vector (Array.map (fun x -> x / n) vv) 127 | | ZeroVector z -> ZeroVector z 128 | /// Returns a sequence of vectors that are obtained by splitting this vector into subvectors whose lengths are given in sequence `n` 129 | member inline v.Split(n:seq) = 130 | match v with 131 | | Vector v -> 132 | let i = ref 0 133 | seq {for j in n do 134 | yield Array.sub v !i j |> Vector 135 | i := !i + j} 136 | | ZeroVector _ -> seq {yield v} 137 | /// Returns a sequence of vectors that are obtained by splitting this vector into `n` subvectors of equal length. The length of this vector must be an integer multiple of `n`, otherwise ArgumentException is raised. 138 | member inline v.SplitEqual(n:int) = 139 | match v with 140 | | Vector v -> 141 | if n <= 0 then invalidArg "" "For splitting this vector, n should be a positive integer." 142 | let l = (float v.Length) / (float n) 143 | if not (isInteger l) then invalidArg "" "Cannot split vector into n equal pieces when length of vector is not an integer multiple of n." 144 | seq {for i in 0 .. (int l) .. (v.Length - 1) do yield Vector (Array.sub v i (int l))} 145 | | ZeroVector _ -> seq {yield v} 146 | /// Gets a string representation of this vector that can be pasted into a Mathematica notebook 147 | member inline v.ToMathematicaString() = 148 | let sb = System.Text.StringBuilder() 149 | sb.Append("{") |> ignore 150 | for i = 0 to v.Length - 1 do 151 | sb.Append(sprintf "%.2f" (float v.[i])) |> ignore 152 | if i < v.Length - 1 then sb.Append(", ") |> ignore 153 | sb.Append("}") |> ignore 154 | sb.ToString() 155 | /// Gets a string representation of this vector that can be pasted into MATLAB 156 | member inline v.ToMatlabString() = 157 | let sb = System.Text.StringBuilder() 158 | sb.Append("[") |> ignore 159 | for i = 0 to v.Length - 1 do 160 | sb.Append(sprintf "%.2f" (float v.[i])) |> ignore 161 | if i < v.Length - 1 then sb.Append(" ") |> ignore 162 | sb.Append("]") |> ignore 163 | sb.ToString() 164 | /// Converts the elements of this vector to another type, using the given conversion function `f` 165 | member inline v.Convert(f:'T->'a):Vector<'a> = 166 | match v with 167 | | Vector v -> Vector (Array.map f v) 168 | | ZeroVector _ -> ZeroVector LanguagePrimitives.GenericZero<'a> 169 | /// Creates a copy of this vector 170 | member inline v.Copy() = 171 | match v with 172 | | Vector v -> Vector (Array.copy v) 173 | | ZeroVector z -> ZeroVector z 174 | /// Converts this vector to an array 175 | member inline v.ToArray() = 176 | match v with 177 | | Vector v -> v 178 | | ZeroVector _ -> [||] 179 | /// Converts this vector to a sequence 180 | member inline v.ToSeq() = 181 | match v with 182 | | Vector v -> Array.toSeq v 183 | | ZeroVector _ -> Seq.empty 184 | /// Creates a new vector that contains the given subrange of elements, specified by start index `s` and count `c` 185 | member inline v.GetSubVector(s, c) = 186 | match v with 187 | | Vector v -> Vector (Array.sub v s c) 188 | | ZeroVector _ -> Vector.Zero 189 | /// Returns an enumerator that iterates through the elements of this vector 190 | member inline v.GetEnumerator() = 191 | v.ToSeq().GetEnumerator() 192 | /// Adds vector `a` to vector `b` 193 | static member inline (+) (a:Vector<'T>, b:Vector<'T>):Vector<'T> = 194 | match a, b with 195 | | Vector a, Vector b -> try Vector (Array.map2 (+) a b) with | _ -> invalidArg "" "Cannot add two vectors of different dimensions." 196 | | Vector _, ZeroVector _ -> a 197 | | ZeroVector _, Vector _ -> b 198 | | ZeroVector _, ZeroVector _ -> Vector.Zero 199 | /// Subtracts vector `b` from vector `a` 200 | static member inline (-) (a:Vector<'T>, b:Vector<'T>):Vector<'T> = 201 | match a, b with 202 | | Vector a, Vector b -> try Vector (Array.map2 (-) a b) with | _ -> invalidArg "" "Cannot subtract two vectors of different dimensions." 203 | | Vector _, ZeroVector _ -> a 204 | | ZeroVector _, Vector b -> Vector (Array.map (~-) b) 205 | | ZeroVector _, ZeroVector _ -> Vector.Zero 206 | /// Computes the inner product (dot / scalar product) of vector `a` and vector `b` 207 | static member inline (*) (a:Vector<'T>, b:Vector<'T>):'T = 208 | match a, b with 209 | | Vector a, Vector b -> try Array.map2 (*) a b |> Array.sum with | _ -> invalidArg "" "Cannot multiply two vectors of different dimensions." 210 | | Vector _, ZeroVector _ -> LanguagePrimitives.GenericZero<'T> 211 | | ZeroVector _, Vector _ -> LanguagePrimitives.GenericZero<'T> 212 | | ZeroVector _, ZeroVector _ -> LanguagePrimitives.GenericZero<'T> 213 | /// Computes the cross product of vector `a` and vector `b` (three-dimensional) 214 | static member inline (%*) (a:Vector<'T>, b:Vector<'T>):Vector<'T> = 215 | match a, b with 216 | | Vector va, Vector vb -> 217 | if (a.Length <> 3) || (b.Length <> 3) then invalidArg "" "The cross product is only defined for three-dimensional vectors." 218 | Vector [|va.[1] * vb.[2] - va.[2] * vb.[1]; va.[2] * vb.[0] - va.[0] * vb.[2]; va.[0] * vb.[1] - va.[1] * vb.[0]|] 219 | | Vector _, ZeroVector _ -> Vector.Zero 220 | | ZeroVector _, Vector _ -> Vector.Zero 221 | | ZeroVector _, ZeroVector _ -> Vector.Zero 222 | /// Multiplies vector `a` and vector `b` element-wise (Hadamard product) 223 | static member inline (.*) (a:Vector<'T>, b:Vector<'T>):Vector<'T> = 224 | match a, b with 225 | | Vector a, Vector b -> try Vector (Array.map2 (*) a b) with | _ -> invalidArg "" "Cannot multiply two vectors of different dimensions." 226 | | Vector _, ZeroVector _ -> Vector.Zero 227 | | ZeroVector _, Vector _ -> Vector.Zero 228 | | ZeroVector _, ZeroVector _ -> Vector.Zero 229 | /// Divides vector `a` by vector `b` element-wise (Hadamard division) 230 | static member inline (./) (a:Vector<'T>, b:Vector<'T>):Vector<'T> = 231 | match a, b with 232 | | Vector a, Vector b -> try Vector (Array.map2 (/) a b) with | _ -> invalidArg "" "Cannot divide two vectors of different dimensions." 233 | | Vector _, ZeroVector _-> raise (new System.DivideByZeroException("Attempted to divide a Vector by a ZeroVector.")) 234 | | ZeroVector _, Vector _ -> Vector.Zero 235 | | ZeroVector _, ZeroVector _ -> raise (new System.DivideByZeroException("Attempted to divide a ZeroVector by a ZeroVector.")) 236 | /// Adds scalar `b` to each element of vector `a` 237 | static member inline (+) (a:Vector<'T>, b:'T):Vector<'T> = 238 | match a with 239 | | Vector a -> Vector (Array.map ((+) b) a) 240 | | ZeroVector _ -> invalidArg "" "Unsupported operation. Cannot add a scalar to a ZeroVector." 241 | /// Adds scalar `a` to each element of vector `b` 242 | static member inline (+) (a:'T, b:Vector<'T>):Vector<'T> = 243 | match b with 244 | | Vector b -> Vector (Array.map ((+) a) b) 245 | | ZeroVector _ -> invalidArg "" "Unsupported operation. Cannot add a scalar to a ZeroVector." 246 | /// Subtracts scalar `b` from each element of vector `a` 247 | static member inline (-) (a:Vector<'T>, b:'T):Vector<'T> = 248 | match a with 249 | | Vector a -> Vector (Array.map (fun x -> x - b) a) 250 | | ZeroVector _ -> invalidArg "" "Unsupported operation. Cannot subtract a scalar from a ZeroVector." 251 | /// Subtracts each element of vector `b` from scalar `a` 252 | static member inline (-) (a:'T, b:Vector<'T>):Vector<'T> = 253 | match b with 254 | | Vector b -> Vector (Array.map ((-) a) b) 255 | | ZeroVector _ -> invalidArg "" "Unsupported operation. Cannot add subtract a ZeroVector from a scalar." 256 | /// Multiplies each element of vector `a` by scalar `b` 257 | static member inline (*) (a:Vector<'T>, b:'T):Vector<'T> = 258 | match a with 259 | | Vector a -> Vector (Array.map ((*) b) a) 260 | | ZeroVector _ -> Vector.Zero 261 | /// Multiplies each element of vector `b` by scalar `a` 262 | static member inline (*) (a:'T, b:Vector<'T>):Vector<'T> = 263 | match b with 264 | | Vector b -> Vector (Array.map ((*) a) b) 265 | | ZeroVector _ -> Vector.Zero 266 | /// Divides each element of vector `a` by scalar `b` 267 | static member inline (/) (a:Vector<'T>, b:'T):Vector<'T> = 268 | match a with 269 | | Vector a -> Vector (Array.map (fun x -> x / b) a) 270 | | ZeroVector _ -> Vector.Zero 271 | /// Divides scalar `a` by each element of vector `b` 272 | static member inline (/) (a:'T, b:Vector<'T>):Vector<'T> = 273 | match b with 274 | | Vector b -> Vector (Array.map ((/) a) b) 275 | | ZeroVector _ -> raise (new System.DivideByZeroException("Attempted division by a ZeroVector.")) 276 | /// Gets the negative of Vector `a` 277 | static member inline (~-) (a:Vector<'T>):Vector<'T> = 278 | match a with 279 | | Vector a -> Vector (Array.map (~-) a) 280 | | ZeroVector _ -> Vector.Zero 281 | 282 | 283 | /// Operations on Vector type. (Implementing functionality similar to Microsoft.FSharp.Collections.Array) 284 | [] 285 | module Vector = 286 | /// Createsa vector from array `v` 287 | let inline ofArray (v:'T[]) = Vector v 288 | /// Converts vector `v` to an array 289 | let inline toArray (v:Vector<'T>):'T[] = v.ToArray() 290 | /// Creates a vector from sequence `s` 291 | let inline ofSeq (s:seq<'T>):Vector<'T> = Vector (Array.ofSeq s) 292 | /// Returns vector `v` as a sequence 293 | let inline toSeq (v:Vector<'T>):seq<'T> = v.ToSeq() 294 | /// Creates a vector that contains the elements of vector `v1` followed by the elements of vector `v2` 295 | let inline append (v1:Vector<'T>) (v2:Vector<'T>):Vector<'T> = Array.append (v1 |> toArray) (v2 |> toArray) |> Vector 296 | /// Builds a new vector that contains the elements of each of the given sequence of vectors `v` 297 | let inline concat (v:seq>):Vector<'T> = Seq.map toArray v |> Array.concat |> ofSeq 298 | /// Creates a copy of vector `v` 299 | let inline copy (v:Vector<'T>):Vector<'T> = v.Copy() 300 | /// Creates a vector with `n` elements, all having value `v` 301 | let inline create (n:int) (v:'T):Vector<'T> = Vector (Array.create n v) 302 | /// Creates a vector with `n` elements, where the element with index `i` has value `v` and the rest of the elements have value 0 303 | let inline createBasis (n:int) (i:int) (v:'T):Vector<'T> = Vector (Array.init n (fun j -> if j = i then v else LanguagePrimitives.GenericZero)) 304 | /// Tests if any element of vector `v` satisfies predicate `p` 305 | let inline exists (p:'T->bool) (v:Vector<'T>):bool = v |> toArray |> Array.exists p 306 | /// Tests if any pair of corresponding elements of vectors `v1` and `v2` satisfies predicate `p` 307 | let inline exists2 (p:'T1->'T2->bool) (v1:Vector<'T1>) (v2:Vector<'T2>):bool = Array.exists2 p (v1 |> toArray) (v2 |> toArray) 308 | /// Fills a range of elements of vector `v` with value `a` starting with index `s` and counting `c` elements 309 | let inline fill (v:Vector<'T>) (s:int) (c:int) (a:'T):unit = Array.fill (v |> toArray) s c a 310 | /// Returns the first element of vector `v` for which predicate `p` is true 311 | let inline find (p:'T->bool) (v:Vector<'T>):'T = v |> toArray |> Array.find p 312 | /// Returns the index of the first element of vector `v` for which predicate `p` is true 313 | let inline findIndex (p:'T->bool) (v:Vector<'T>):int = v |> toArray |> Array.findIndex p 314 | /// Applies function `f` to each element of vector `v`, threading an accumulator (with initial state `s`) through the computation. If the input function is f and the elements are i0...iN then computes f (... (f s i0)...) iN. 315 | let inline fold (f:'S->'T->'S) (s:'S) (v:Vector<'T>):'S = v |> toArray |> Array.fold f s 316 | /// Applies function `f` to corresponding elements of vectors `v1` and `v2`, threading an accumulator (with initial state `s`) through the computation. The two input vectors must have the same lengths, otherwise ArgumentException is raised. 317 | let inline fold2 (f:'S->'T1->'T2->'S) (s:'S) (v1:Vector<'T1>) (v2:Vector<'T2>):'S = Array.fold2 f s (v1 |> toArray) (v2 |> toArray) 318 | /// Applies function `f` to each element of vector `v`, threading an accumulator (with initial state `s`) through the computation. If the input function is f and the elements are i0...iN then computes f i0 (...(f iN s)). 319 | let inline foldBack (f:'T->'S->'S) (v:Vector<'T>) (s:'S):'S = Array.foldBack f (v |> toArray) s 320 | /// Applies function `f` to corresponding elements of vectors `v1` and `v2`, threading an accumulator (with initial state `s`) through the computation. The two input vectors must have the same lengths, otherwise ArgumentException is raised. 321 | let inline foldBack2 (f:'T1->'T2->'S->'S) (v1:Vector<'T1>) (v2:Vector<'T2>) (s:'S):'S = Array.foldBack2 f (v1 |> toArray) (v2 |> toArray) s 322 | /// Tests if all elements of vector `v` satisfy predicate `p` 323 | let inline forall (p:'T->bool) (v:Vector<'T>):bool = v |> toArray |> Array.forall p 324 | /// Tests if all corresponding elements of vectors `v1` and `v2` satisfy predicate `p` pairwise 325 | let inline forall2 (p:'T1->'T2->bool) (v1:Vector<'T1>) (v2:Vector<'T2>):bool = Array.forall2 p (v1 |> toArray) (v2 |> toArray) 326 | /// Gets the element of vector `v` with index `i` 327 | let inline get (v:Vector<'T>) (i:int):'T = v.[i] 328 | /// Creates a vector with dimension `n` and a generator function `f` to compute the elements 329 | let inline init (n:int) (f:int->'T):Vector<'T> = Vector (Array.init n f) 330 | /// Applies function `f` to each element of vector `v` 331 | let inline iter (f:'T->unit) (v:Vector<'T>):unit = v |> toArray |> Array.iter f 332 | /// Applies function `f` to corresponding elements of vectors `v1` and `v2` pairwise. The two input vectors must have the same lengths, otherwise ArgumentException is raised. 333 | let inline iter2 (f:'T1->'T2->unit) (v1:Vector<'T1>) (v2:Vector<'T2>):unit = Array.iter2 f (v1 |> toArray) (v2 |> toArray) 334 | /// Applies function `f` to each element of vector `v`. The integer passed to function `f` indicates the index of element. 335 | let inline iteri (f:int->'T->unit) (v:Vector<'T>):unit = v |> toArray |> Array.iteri f 336 | /// Applies function `f` to corresponding elements of vectors `v1` and `v2` pairwise. The integer passed to function `f` indicates the index of element. The two input vectors must have the same lengths, otherwise ArgumentException is raised. 337 | let inline iteri2 (f:int->'T1->'T2->unit) (v1:Vector<'T1>) (v2:Vector<'T2>):unit = Array.iteri2 f (v1 |> toArray) (v2 |> toArray) 338 | /// Gets the L1 (Manhattan) norm of vector `v` 339 | let inline l1norm (v:Vector<'T>):'T = v.GetL1Norm() 340 | /// Gets the L2 (Euclidean) norm of vector `v`. This is the same with `Vector.norm`. 341 | let inline l2norm (v:Vector<'T>):'T = v.GetL2Norm() 342 | /// Gets the squared L2 (Euclidean) norm of vector `v`. This is the same with `Vector.normSq`. 343 | let inline l2normSq (v:Vector<'T>):'T = v.GetL2NormSq() 344 | /// Returns the length of vector `v` 345 | let inline length (v:Vector<'T>):int = v.Length 346 | /// Gets the Lp norm (or p-norm) of vector `v`, with the given `p` 347 | let inline lpnorm (p:'T) (v:Vector<'T>):'T = v.GetLPNorm(p) 348 | /// Creates a vector whose elements are the results of applying function `f` to each element of vector `v` 349 | let inline map (f:'T->'U) (v:Vector<'T>):Vector<'U> = v |> toArray |> Array.map f |> Vector 350 | /// Creates a vector whose elements are the results of applying function `f` to corresponding elements of vectors `v1` and `v2` pairwise. The two input vectors must have the same lengths, otherwise ArgumentException is raised. 351 | let inline map2 (f:'T1->'T2->'U) (v1:Vector<'T1>) (v2:Vector<'T2>):Vector<'U> = Array.map2 f (v1 |> toArray) (v2 |> toArray) |> Vector 352 | /// Creates a vector whose elements are the results of applying function `f` to each element of vector `v`. An element index is also supplied to function `f`. 353 | let inline mapi (f:int->'T->'U) (v:Vector<'T>):Vector<'U> = v |> toArray |> Array.mapi f |> Vector 354 | /// Creates a vector whose elements are the results of applying function `f` to corresponding elements of vectors `v1` and `v2` pairwise. The integer passed to function `f` indicates the index of element. The two input vectors must have the same lengths, otherwise ArgumentException is raised. 355 | let inline mapi2 (f:int->'T1->'T2->'U) (v1:Vector<'T1>) (v2:Vector<'T2>):Vector<'U> = Array.mapi2 f (v1 |> toArray) (v2 |> toArray) |> Vector 356 | /// Returns the maximum of all elements of vector `v` 357 | let inline max (v:Vector<'T>):'T = v.GetMax() 358 | /// Returns the maximum of all elements of vector `v`, compared by using Operators.max on the result of function `f` 359 | let inline maxBy (f:'T->'U) (v:Vector<'T>):'T = v.GetMaxBy(f) 360 | /// Returns the minimum of all elements of vector `v` 361 | let inline min (v:Vector<'T>):'T = v.GetMin() 362 | /// Returns the minimum of all elements of vector `v`, compared by using Operators.min on the result of function `f` 363 | let inline minBy (f:'T->'U) (v:Vector<'T>):'T = v.GetMinBy(f) 364 | /// Gets the L2 (Euclidean) norm of vector `v`. This is the same with `Vector.l2norm`. 365 | let inline norm (v:Vector<'T>):'T = l2norm v 366 | /// Gets the squared L2 (Euclidean) norm of vector `v`. This is the same with `Vector.l2normSq`. 367 | let inline normSq (v:Vector<'T>):'T = l2normSq v 368 | /// Applies function `f` to each element of vector `v`, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN, then computes f (... (f i0 i1)...) iN. 369 | let inline reduce (f:'T->'T->'T) (v:Vector<'T>):'T = v |> toArray |> Array.reduce f 370 | /// Applies function `f` to each element of vector `v`, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN then computes f i0 (...(f iN-1 iN)). 371 | let inline reduceBack (f:'T->'T->'T) (v:Vector<'T>):'T = v |> toArray |> Array.reduceBack f 372 | /// Replaces the elements of vector `v` by mutating them in place, passing them through function `f` 373 | let inline replace (f:'T->'T) (v:Vector<'T>):unit = for i in 0..(v.Length - 1) do v.[i] <- f v.[i] 374 | /// Replaces the elements of vector `v1` by mutating them in place. The new values are computed by applying function `f` to corresponding elements of vectors `v1` and `v2` pairwise. The two input vectors must have the same lengths, otherwie ArgumentException is raised. 375 | let inline replace2 (f:'T1->'T2->'T1) (v1:Vector<'T1>) (v2:Vector<'T2>):unit = 376 | if v1.Length <> v2.Length then invalidArg "" "The vectors should have the same length." 377 | for i in 0..(v1.Length - 1) do v1.[i] <- f v1.[i] v2.[i] 378 | /// Replaces the elements of vector `v` by mutating them in place, passing them through function `f`. An element index is also supplied to function `f`. 379 | let inline replacei (f:int->'T->'T) (v:Vector<'T>):unit = for i in 0..(v.Length - 1) do v.[i] <- f i v.[i] 380 | /// Replaces the elements of vector `v1` by mutating them in place. The new values are computed by applying function `f` to corresponding elements of vectors `v1` and `v2` pairwise. An element index is also supplied to function `f`. The two input vectors must have the same lengths, otherwise ArgumentException is raised. 381 | let inline replacei2 (f:int->'T1->'T2->'T1) (v1:Vector<'T1>) (v2:Vector<'T2>):unit = 382 | if v1.Length <> v2.Length then invalidArg "" "The vectors should have the same length." 383 | for i in 0..(v1.Length - 1) do v1.[i] <- f i v1.[i] v2.[i] 384 | /// Replaces the elements of vector `v1` with the elements of vector `v2`, by mutating them in place. The two input vectors must have the same lengths, otherwise ArgumentException is raised. 385 | let inline replaceWith (v1:Vector<'T>) (v2:Vector<'T>):unit = 386 | if v1.Length <> v2.Length then invalidArg "" "The vectors should have the same length." 387 | Array.blit (v2 |> toArray) 0 (v1 |> toArray) 0 v1.Length 388 | /// Like Vector.fold, but returns the intermediate and final results 389 | let inline scan (f:'S->'T->'S) (s:'S) (v:Vector<'T>):Vector<'S> = v |> toArray |> Array.scan f s |> ofSeq 390 | /// Like Vector.foldBack, but returns both the intermediate and final results 391 | let inline scanBack (f:'T->'S->'S) (s:'S) (v:Vector<'T>):Vector<'S> = Array.scanBack f (v |> toArray) s |> ofSeq 392 | /// Sets the element of vector`v` with index `i` to value `a` 393 | let inline set (v:Vector<'T>) (i:int) (a:'T):unit = v.[i] <- a 394 | /// Returns a sequence of vectors that are obtained by splitting vector `v` into subvectors whose lengths are given in the sequence `n` 395 | let inline split (n:seq) (v:Vector<'T>):seq> = v.Split(n) 396 | /// Returns a sequence of vectors that are obtained by splitting vector `v` into `n` subvectors of equal length. The length of vector `v` must be an integer multiple of `n`, otherwise ArgumentException is raised. 397 | let inline splitEqual (n:int) (v:Vector<'T>):seq> = v.SplitEqual(n) 398 | /// Creates a vector with `n` elements, where the `i`-th element is 1 and the rest of the elements are 0 399 | let inline standardBasis (n:int) (i:int):Vector<'T> = createBasis n i LanguagePrimitives.GenericOne 400 | /// Creates a new vector that contains the given subrange of vector `v`, specified by start index `s` and count `c` 401 | let inline sub (v:Vector<'T>) (s:int) (c:int):Vector<'T> = v.GetSubVector(s, c) 402 | /// Returns the sum of all the elements in vector `v` 403 | let inline sum (v:Vector<'T>):'T = v |> toArray |> Array.sum 404 | /// Returns the sum of the results generated by applying function `f` to each element of vector `v` 405 | let inline sumBy (f:'T->'U) (v:Vector<'T>):'U = v |> toArray |> Array.sumBy f 406 | /// Gets the unit vector codirectional with vector `v` 407 | let inline unitVector (v:Vector<'T>) = v.GetUnitVector() -------------------------------------------------------------------------------- /src/FsAlg/Matrix.fs: -------------------------------------------------------------------------------- 1 | // 2 | // This file is part of 3 | // FsAlg: Generic Linear Algebra Library 4 | // 5 | // Copyright (c) 2015, National University of Ireland Maynooth (Atilim Gunes Baydin, Barak A. Pearlmutter) 6 | // 7 | // FsAlg is released under the BSD license. 8 | // (See accompanying LICENSE file.) 9 | // 10 | // Written by: 11 | // 12 | // Atilim Gunes Baydin 13 | // atilimgunes.baydin@nuim.ie 14 | // 15 | // Barak A. Pearlmutter 16 | // barak@cs.nuim.ie 17 | // 18 | // Brain and Computation Lab 19 | // Hamilton Institute & Department of Computer Science 20 | // National University of Ireland Maynooth 21 | // Maynooth, Co. Kildare 22 | // Ireland 23 | // 24 | // www.bcl.hamilton.ie 25 | // 26 | 27 | namespace FsAlg.Generic 28 | 29 | open FsAlg.Generic.Util 30 | 31 | /// Generic matrix type 32 | [] 33 | type Matrix<'T when 'T : (static member Zero : 'T) 34 | and 'T : (static member One : 'T) 35 | and 'T : (static member (+) : 'T * 'T -> 'T) 36 | and 'T : (static member (-) : 'T * 'T -> 'T) 37 | and 'T : (static member (*) : 'T * 'T -> 'T) 38 | and 'T : (static member (/) : 'T * 'T -> 'T) 39 | and 'T : (static member (~-) : 'T -> 'T) 40 | and 'T : (static member Abs : 'T -> 'T) 41 | and 'T : (static member Pow : 'T * 'T -> 'T) 42 | and 'T : (static member Sqrt : 'T -> 'T) 43 | and 'T : (static member op_Explicit : 'T -> float) 44 | and 'T : comparison> = 45 | | ZeroMatrix of 'T 46 | | Matrix of 'T[,] 47 | /// ZeroMatrix 48 | static member inline Zero = ZeroMatrix LanguagePrimitives.GenericZero<'T> 49 | /// Converts Matrix `m` to float[,] 50 | static member inline op_Explicit(m:Matrix<'T>) = 51 | match m with 52 | | Matrix m -> Array2D.map float m 53 | | ZeroMatrix _ -> Array2D.zeroCreate 0 0 54 | /// Gets the number of rows of this matrix 55 | member inline m.Rows = 56 | match m with 57 | | Matrix m -> m.GetLength 0 58 | | ZeroMatrix _ -> 0 59 | /// Gets the number of columns of this matrix 60 | member inline m.Cols = 61 | match m with 62 | | Matrix m -> m.GetLength 1 63 | | ZeroMatrix _ -> 0 64 | /// The entry of this matrix at row `i` and column `j` 65 | member inline m.Item 66 | with get (i, j) = 67 | match m with 68 | | Matrix m -> m.[i, j] 69 | | ZeroMatrix z -> z 70 | and set (i, j) v = 71 | match m with 72 | | Matrix m -> m.[i, j] <- v 73 | | ZeroMatrix _ -> () 74 | /// Gets a submatrix of this matrix with the bounds given in `rowStart`, `rowFinish`, `colStart`, `colFinish` 75 | member inline m.GetSlice(rowStart, rowFinish, colStart, colFinish) = 76 | match m with 77 | | Matrix mm -> 78 | let rowStart = defaultArg rowStart 0 79 | let rowFinish = defaultArg rowFinish (m.Rows - 1) 80 | if rowStart > rowFinish then invalidArg "" "Given row slice bounds are invalid." 81 | let colStart = defaultArg colStart 0 82 | let colFinish = defaultArg colFinish (m.Cols - 1) 83 | if colStart > colFinish then invalidArg "" "Given column slice bounds are invalid." 84 | Matrix mm.[rowStart..rowFinish, colStart..colFinish] 85 | | ZeroMatrix _ -> invalidArg "" "Cannot get slice of a ZeroMatrix." 86 | /// Gets a row of this matrix with the given row index `row` and column bounds `colStart` and `colFinish` 87 | member inline m.GetSlice(row, colStart, colFinish) = 88 | match m with 89 | | Matrix mm -> 90 | let colStart = defaultArg colStart 0 91 | let colFinish = defaultArg colFinish (m.Cols - 1) 92 | if colStart > colFinish then invalidArg "" "Given column slice bounds are invalid." 93 | [mm.[row, colStart..colFinish]] |> array2D |> Matrix 94 | | ZeroMatrix _ -> invalidArg "" "Cannot get slice of a ZeroMatrix." 95 | /// Gets a column of this matrix with the given column index `col` and row bounds `rowStart` and `rowFinish` 96 | member inline m.GetSlice(rowStart, rowFinish, col) = 97 | match m with 98 | | Matrix mm -> 99 | let rowStart = defaultArg rowStart 0 100 | let rowFinish = defaultArg rowFinish (m.Rows - 1) 101 | if rowStart > rowFinish then invalidArg "" "Given row slice bounds are invalid." 102 | [mm.[rowStart..rowFinish, col]] |> array2D |> transpose |> Matrix 103 | | ZeroMatrix _ -> invalidArg "" "Cannot get slice of a ZeroMatrix." 104 | /// Gets a string representation of this matrix that can be pasted into a Mathematica notebook 105 | member inline m.ToMathematicaString() = 106 | let sb = System.Text.StringBuilder() 107 | sb.Append("{") |> ignore 108 | for i = 0 to m.Rows - 1 do 109 | sb.Append("{") |> ignore 110 | for j = 0 to m.Cols - 1 do 111 | sb.Append(sprintf "%.2f" (float m.[i, j])) |> ignore 112 | if j <> m.Cols - 1 then sb.Append(", ") |> ignore 113 | sb.Append("}") |> ignore 114 | if i <> m.Rows - 1 then sb.Append(", ") |> ignore 115 | sb.Append("}") |> ignore 116 | sb.ToString() 117 | /// Gets a string representation of this matrix that can be pasted into MATLAB 118 | member inline m.ToMatlabString() = 119 | let sb = System.Text.StringBuilder() 120 | sb.Append("[") |> ignore 121 | for i = 0 to m.Rows - 1 do 122 | for j = 0 to m.Cols - 1 do 123 | sb.Append(sprintf "%.2f" (float m.[i, j])) |> ignore 124 | if j < m.Cols - 1 then sb.Append(" ") |> ignore 125 | if i < m.Rows - 1 then sb.Append("; ") |> ignore 126 | sb.Append("]") |> ignore 127 | sb.ToString() 128 | /// Converts this matrix into a 2d array 129 | member inline m.ToArray2D() = 130 | match m with 131 | | Matrix m -> m 132 | | ZeroMatrix _ -> Array2D.zeroCreate 0 0 133 | /// Converts this matrix into a jagged array, e.g. from Matrix to float[][] 134 | member inline m.ToArray() = 135 | let a = m.ToArray2D() 136 | [|for i = 0 to m.Rows - 1 do yield [|for j = 0 to m.Cols - 1 do yield a.[i, j]|]|] 137 | /// Converts this matrix into a one dimensional sequence, scanning columns from left to right and rows from top to bottom 138 | member inline m.ToSeq() = 139 | let a = m.ToArray() 140 | seq {for aa in a do yield! Seq.ofArray aa} 141 | /// Returns an enumerator that iterates through this matrix 142 | member inline m.GetEnumerator() = 143 | m.ToSeq().GetEnumerator() 144 | /// Creates a copy of this matrix 145 | member inline m.Copy() = 146 | match m with 147 | | Matrix m -> Matrix (Array2D.copy m) 148 | | ZeroMatrix z -> ZeroMatrix z 149 | /// Gets the trace of this matrix 150 | member inline m.GetTrace() = 151 | match m with 152 | | Matrix m -> trace m 153 | | ZeroMatrix z -> z 154 | /// Gets the transpose of this matrix 155 | member inline m.GetTranspose() = 156 | match m with 157 | | Matrix m -> Matrix (transpose m) 158 | | ZeroMatrix z -> ZeroMatrix z 159 | /// Gets a vector of the diagonal elements of this matrix 160 | member inline m.GetDiagonal() = 161 | match m with 162 | | Matrix mm -> 163 | if m.Rows <> m.Cols then invalidArg "" "Cannot get the diagonal entries of a nonsquare matrix." 164 | Array.init m.Rows (fun i -> mm.[i, i]) 165 | | ZeroMatrix z -> [||] 166 | /// Returns the LU decomposition of this matrix. The return values are the LU matrix, pivot indices, and a toggle value indicating the number of row exchanges during the decomposition, which is +1 if the number of exchanges were even, -1 if odd. 167 | member inline m.GetLUDecomposition() = 168 | match m with 169 | | Matrix mm -> 170 | if (m.Rows <> m.Cols) then invalidArg "" "Cannot compute the LU decomposition of a nonsquare matrix." 171 | let res = Array2D.copy mm 172 | let perm = Array.init m.Rows (fun i -> i) 173 | let mutable toggle = LanguagePrimitives.GenericOne<'T> 174 | for j = 0 to m.Rows - 2 do 175 | let mutable colmax:'T = abs res.[j, j] 176 | let mutable prow = j 177 | for i = j + 1 to m.Rows - 1 do 178 | let absresij = abs res.[i, j] 179 | if absresij > colmax then 180 | colmax <- absresij 181 | prow <- i 182 | if prow <> j then 183 | let tmprow = res.[prow, 0..] 184 | res.[prow, 0..] <- res.[j, 0..] 185 | res.[j, 0..] <- tmprow 186 | let tmp = perm.[prow] 187 | perm.[prow] <- perm.[j] 188 | perm.[j] <- tmp 189 | toggle <- -toggle 190 | for i = j + 1 to m.Rows - 1 do 191 | res.[i, j] <- res.[i, j] / res.[j, j] 192 | for k = j + 1 to m.Rows - 1 do 193 | res.[i, k] <- res.[i, k] - res.[i, j] * res.[j, k] 194 | Matrix res, perm, toggle 195 | | ZeroMatrix z -> ZeroMatrix z, [||], LanguagePrimitives.GenericZero<'T> 196 | /// Gets the determinant of this matrix 197 | member inline m.GetDeterminant() = 198 | match m with 199 | | Matrix _ -> 200 | if (m.Rows <> m.Cols) then invalidArg "" "Cannot compute the determinant of a nonsquare matrix." 201 | let lu, _, toggle = m.GetLUDecomposition() 202 | toggle * Array.fold (fun s x -> s * x) LanguagePrimitives.GenericOne<'T> (lu.GetDiagonal()) 203 | | ZeroMatrix z -> z 204 | /// Gets the inverse of this matrix 205 | member inline m.GetInverse() = 206 | match m with 207 | | Matrix mm -> 208 | if (m.Rows <> m.Cols) then invalidArg "" "Cannot compute the inverse of a nonsquare matrix." 209 | let res = Array2D.copy mm 210 | let lu, perm, _ = m.GetLUDecomposition() 211 | let b:'T[] = Array.zeroCreate m.Rows 212 | for i = 0 to m.Rows - 1 do 213 | for j = 0 to m.Rows - 1 do 214 | if i = perm.[j] then 215 | b.[j] <- LanguagePrimitives.GenericOne<'T> 216 | else 217 | b.[j] <- LanguagePrimitives.GenericZero<'T> 218 | let x = matrixSolveHelper (lu.ToArray2D()) b 219 | res.[0.., i] <- x 220 | Matrix res 221 | | ZeroMatrix z -> ZeroMatrix z 222 | /// Adds matrix `a` to matrix `b` 223 | static member inline (+) (a:Matrix<'T>, b:Matrix<'T>):Matrix<'T> = 224 | match a, b with 225 | | Matrix ma, Matrix mb -> 226 | if (a.Rows <> b.Rows) || (a.Cols <> b.Cols) then invalidArg "" "Cannot add matrices of different sizes." 227 | Matrix (Array2D.init a.Rows a.Cols (fun i j -> ma.[i, j] + mb.[i, j])) 228 | | Matrix _, ZeroMatrix _ -> a 229 | | ZeroMatrix _, Matrix _ -> b 230 | | ZeroMatrix z, ZeroMatrix _ -> ZeroMatrix z 231 | /// Subtracts matrix `b` from matrix `a` 232 | static member inline (-) (a:Matrix<'T>, b:Matrix<'T>):Matrix<'T> = 233 | match a, b with 234 | | Matrix ma, Matrix mb -> 235 | if (a.Rows <> b.Rows) || (a.Cols <> b.Cols) then invalidArg "" "Cannot subtract matrices of different sizes." 236 | Matrix (Array2D.init a.Rows a.Cols (fun i j -> ma.[i, j] - mb.[i, j])) 237 | | Matrix _, ZeroMatrix _ -> a 238 | | ZeroMatrix _, Matrix b -> Matrix (Array2D.map (~-) b) 239 | | ZeroMatrix _, ZeroMatrix _ -> Matrix.Zero 240 | /// Multiplies matrix `a` and matrix `b` (matrix product) 241 | static member inline (*) (a:Matrix<'T>, b:Matrix<'T>):Matrix<'T> = 242 | match a, b with 243 | | Matrix ma, Matrix mb -> 244 | if (a.Cols <> b.Rows) then invalidArg "" "Cannot multiply two matrices of incompatible sizes." 245 | Matrix (Array2D.init a.Rows b.Cols (fun i j -> Array.sumBy (fun k -> ma.[i, k] * mb.[k, j]) [|0..(b.Rows - 1)|] )) 246 | | Matrix _, ZeroMatrix _ -> Matrix.Zero 247 | | ZeroMatrix _, Matrix _ -> Matrix.Zero 248 | | ZeroMatrix _, ZeroMatrix _ -> Matrix.Zero 249 | /// Multiplies matrix `a` and matrix `b` element-wise (Hadamard product) 250 | static member inline (.*) (a:Matrix<'T>, b:Matrix<'T>):Matrix<'T> = 251 | match a, b with 252 | | Matrix ma, Matrix mb -> 253 | if (a.Rows <> b.Rows) || (a.Cols <> b.Cols) then invalidArg "" "Cannot multiply matrices of different sizes." 254 | Matrix (Array2D.init a.Rows a.Cols (fun i j -> ma.[i, j] * mb.[i, j])) 255 | | Matrix _, ZeroMatrix _ -> Matrix.Zero 256 | | ZeroMatrix _, Matrix _ -> Matrix.Zero 257 | | ZeroMatrix _, ZeroMatrix _ -> Matrix.Zero 258 | /// Divides matrix `a` by matrix `b` element-wise (Hadamard division) 259 | static member inline (./) (a:Matrix<'T>, b:Matrix<'T>):Matrix<'T> = 260 | match a, b with 261 | | Matrix ma, Matrix mb -> 262 | if (a.Rows <> b.Rows) || (a.Cols <> b.Cols) then invalidArg "" "Cannot divide matrices of different sizes." 263 | Matrix (Array2D.init a.Rows a.Cols (fun i j -> ma.[i, j] / mb.[i, j])) 264 | | Matrix _, ZeroMatrix _ -> raise (new System.DivideByZeroException("Attempted division by a ZeroMatrix.")) 265 | | ZeroMatrix _, Matrix _ -> Matrix.Zero 266 | | ZeroMatrix _, ZeroMatrix _ -> raise (new System.DivideByZeroException("Attempted division by a ZeroMatrix.")) 267 | /// Computes the matrix-vector product of matrix `a` and vector `b` 268 | static member inline (*) (a:Matrix<'T>, b:Vector<'T>):Vector<'T> = 269 | match a, b with 270 | | Matrix ma, Vector vb -> 271 | if (a.Cols <> b.Length) then invalidArg "" "Cannot compute the matrix-vector product of a matrix and a vector of incompatible sizes." 272 | Vector (Array.init a.Rows (fun i -> Array.sumBy (fun j -> ma.[i, j] * vb.[j]) [|0..(b.Length - 1)|] )) 273 | | Matrix _, ZeroVector _ -> Vector.Zero 274 | | ZeroMatrix _, Vector _ -> Vector.Zero 275 | | ZeroMatrix _, ZeroVector _ -> Vector.Zero 276 | /// Computes the vector-matrix product of vector `a` and matrix `b` 277 | static member inline (*) (a:Vector<'T>, b:Matrix<'T>):Vector<'T> = 278 | match a, b with 279 | | Vector va, Matrix mb -> 280 | if (a.Length <> b.Rows) then invalidArg "" "Cannot compute the vector-matrix product of a vector and matrix of incompatible sizes." 281 | Vector (Array.init b.Cols (fun i -> Array.sumBy (fun j -> va.[j] * mb.[j, i]) [|0..(a.Length - 1)|])) 282 | | Vector _, ZeroMatrix _ -> Vector.Zero 283 | | ZeroVector _, Matrix _ -> Vector.Zero 284 | | ZeroVector _, ZeroMatrix _ -> Vector.Zero 285 | /// Adds scalar `b` to each element of matrix `a` 286 | static member inline (+) (a:Matrix<'T>, b:'T):Matrix<'T> = 287 | match a with 288 | | Matrix a -> Matrix (Array2D.map ((+) b) a) 289 | | ZeroMatrix z -> invalidArg "" "Unsupported operation. Cannot add a scalar to a ZeroMatrix." 290 | /// Adds scalar `a` to each element of matrix `b` 291 | static member inline (+) (a:'T, b:Matrix<'T>):Matrix<'T> = 292 | match b with 293 | | Matrix b -> Matrix (Array2D.map ((+) a) b) 294 | | ZeroMatrix z -> invalidArg "" "Unsupported operation. Cannot add a scalar to a ZeroMatrix." 295 | /// Subtracts scalar `b` from each element of matrix `a` 296 | static member inline (-) (a:Matrix<'T>, b:'T):Matrix<'T> = 297 | match a with 298 | | Matrix a -> Matrix (Array2D.map (fun x -> x - b) a) 299 | | ZeroMatrix z -> invalidArg "" "Unsupported operation. Cannot subtract a scalar from a ZeroMatrix." 300 | /// Subtracts each element of of matrix `b` from scalar `a` 301 | static member inline (-) (a:'T, b:Matrix<'T>):Matrix<'T> = 302 | match b with 303 | | Matrix b -> Matrix (Array2D.map ((-) a) b) 304 | | ZeroMatrix z -> invalidArg "" "Unsupported operation. Cannot subtract a ZeroMatrix from a scalar." 305 | /// Multiplies each element of matrix `a` by scalar `b` 306 | static member inline (*) (a:Matrix<'T>, b:'T):Matrix<'T> = 307 | match a with 308 | | Matrix a -> Matrix (Array2D.map ((*) b) a) 309 | | ZeroMatrix _ -> Matrix.Zero 310 | /// Multiplies each element of matrix `b` by scalar `a` 311 | static member inline (*) (a:'T, b:Matrix<'T>):Matrix<'T> = 312 | match b with 313 | | Matrix b -> Matrix (Array2D.map ((*) a) b) 314 | | ZeroMatrix _ -> Matrix.Zero 315 | /// Divides each element of matrix `a` by scalar `b` 316 | static member inline (/) (a:Matrix<'T>, b:'T):Matrix<'T> = 317 | match a with 318 | | Matrix a -> Matrix (Array2D.map (fun x -> x / b) a) 319 | | ZeroMatrix _ -> Matrix.Zero 320 | /// Creates a matrix whose elements are scalar `a` divided by each element of matrix `b` 321 | static member inline (/) (a:'T, b:Matrix<'T>):Matrix<'T> = 322 | match b with 323 | | Matrix b -> Matrix (Array2D.map ((/) a) b) 324 | | ZeroMatrix _ -> raise (new System.DivideByZeroException("Attempted division by a ZeroMatrix.")) 325 | /// Gets the negative of matrix `a` 326 | static member inline (~-) (a:Matrix<'T>) = 327 | match a with 328 | | Matrix a -> Matrix (Array2D.map (~-) a) 329 | | ZeroMatrix _ -> Matrix.Zero 330 | /// Returns the QR decomposition of this matrix 331 | member inline m.GetQRDecomposition() = 332 | match m with 333 | | ZeroMatrix z -> failwith "Cannot compute the QR decomposition of ZeroMatrix." 334 | | Matrix mm -> 335 | let minor (m:_[,]) (d) = 336 | let rows = Array2D.length1 m 337 | let cols = Array2D.length2 m 338 | let ret = Array2D.zeroCreate rows cols 339 | for i = 0 to d - 1 do 340 | ret.[i, i] <- LanguagePrimitives.GenericOne 341 | Array2D.blit m d d ret d d (rows - d) (cols - d) 342 | ret 343 | let identity d = Array2D.init d d (fun i j -> if i = j then LanguagePrimitives.GenericOne else LanguagePrimitives.GenericZero) 344 | // Householder 345 | let kmax = -1 + min (m.Rows - 1) m.Cols 346 | let mutable z = m.Copy() 347 | let q = Array.create m.Rows Matrix.Zero 348 | for k = 0 to kmax do 349 | z <- Matrix (minor (z.ToArray2D()) k) 350 | let x = z.[*, k].ToSeq() |> Array.ofSeq |> Vector 351 | let mutable a = x.GetL2Norm() 352 | if mm.[k, k] > LanguagePrimitives.GenericZero then a <- -a 353 | let e = (x + Vector.createBasis m.Rows k a).GetUnitVector() 354 | q.[k] <- Matrix (identity m.Rows) + Matrix (Array2D.init m.Rows m.Rows (fun i j -> -(e.[i] * e.[j] + e.[i] * e.[j]))) 355 | z <- q.[k] * z 356 | let mutable q' = q.[0] 357 | for i = 1 to kmax do 358 | q' <- q.[i] * q' 359 | q'.GetTranspose(), q' * m 360 | /// Returns the eigenvalues of this matrix. (Experimental code, complex eigenvalues are not supported.) 361 | member inline m.GetEigenvalues() = 362 | let mutable m' = m.Copy() 363 | for i = 0 to 20 do 364 | let q, r = m'.GetQRDecomposition() 365 | m' <- r * q 366 | m'.GetDiagonal() 367 | 368 | /// Operations on Matrix type. (Implementing functionality similar to Microsoft.FSharp.Collections.Array2D) 369 | [] 370 | module Matrix = 371 | /// Creates a matrix from 2d array `m` 372 | let inline ofArray2D (m:'T[,]):Matrix<'T> = Matrix m 373 | /// Converts matrix `m` to a 2d array, e.g. from Matrix to float[,] 374 | let inline toArray2D (m:Matrix<'T>):'T[,] = m.ToArray2D() 375 | /// Creates a matrix from a jagged array, e.g. from float[][] to Matrix 376 | let inline ofArrayArray (m:'T[][]):Matrix<'T> = m |> array2D |> Matrix 377 | /// Converts matrix `m` to a jagged array, e.g. from Matrix to float[][] 378 | let inline toArrayArray (m:Matrix<'T>):'T[][] = m.ToArray() 379 | /// Creates a matrix from sequence of sequences `s` 380 | let inline ofSeqSeq (s:seq>):Matrix<'T> = s |> array2D |> Matrix 381 | /// Converts matrix `m` to a sequence of sequences 382 | let inline toSeqSeq (m:Matrix<'T>):seq> = m.ToArray() |> Array.map Seq.ofArray |> Seq.ofArray 383 | /// Creates a matrix with `m` rows from the one dimensional sequence `s`, filling columns from left to right and rows from top to bottom. The number of columns will be deduced from `m` and the length of the sequence `s`. The length of `s` must be an integer multiple of `m`. 384 | let inline ofSeq (m:int) (s:seq<'T>):Matrix<'T> = 385 | let n = Seq.length s / m 386 | Array2D.init m n (fun i j -> Seq.nth (i * n + j) s) |> Matrix 387 | /// Converts matrix `m` to a one dimensional sequence, scanning columns from left to right and rows from top to bottom 388 | let inline toSeq (m:Matrix<'T>):seq<'T> = m.ToSeq() 389 | /// Creates a matrix with `m` rows from the one dimensional array `a`, filling columns from left to right and rows from top to bottom. The number of columns will be deduced from `m` and the length of the array `a`. The length of `a` must be an integer multiple of `m`. 390 | let inline ofArray (m:int) (a:'T[]):Matrix<'T> = ofSeq m a 391 | /// Converts matrix `m` to a one dimensional array, scanning columns from left to right and rows from top to bottom 392 | let inline toArray (m:Matrix<'T>):'T[] = m |> toSeq |> Array.ofSeq 393 | /// Creates a matrix with `m` rows from the vector `v`, filling columns from left to right and rows from top to bottom. The number of columns will be deduced from `m` and the length of the vector `v`. The length of `v` must be an integer multiple of `m`. 394 | let inline ofVector (m:int) (v:Vector<'T>):Matrix<'T> = v |> Vector.toSeq |> ofSeq m 395 | /// Converts matrix `m` to a vector, scanning columns from left to right and rows from top to bottom 396 | let inline toVector (m:Matrix<'T>):Vector<'T> = m |> toSeq |> Vector.ofSeq 397 | /// Returns the j-th column of matrix `m` 398 | let inline col (j:int) (m:Matrix<'T>):Matrix<'T> = m.[*,j] 399 | /// Returns the number of columns in matrix `m`. This is the same with `Matrix.length2`. 400 | let inline cols (m:Matrix<'T>):int = m.Cols 401 | /// Creates a copy of Matrix `m` 402 | let inline copy (m:Matrix<'T>):Matrix<'T> = m.Copy() 403 | /// Creates a matrix with `m` rows, `n` columns, and all entries having value `v` 404 | let inline create (m:int) (n:int) (v:'T):Matrix<'T> = Matrix (Array2D.create m n v) 405 | /// Creates a matrix with `m` rows and all rows equal to array `v` 406 | let inline createRows (m:int) (v:'T[]):Matrix<'T> = Matrix (array2D (Array.init m (fun _ -> v))) 407 | /// Gets the LU decomposition of matrix `m`. The return values are the LU matrix, pivot indices, and a toggle value indicating the number of row exchanges during the decomposition, which is +1 if the number of exchanges were even, -1 if odd. 408 | let inline decomposeLU (m:Matrix<'T>):(Matrix<'T>*int[]*'T) = m.GetLUDecomposition() 409 | /// Gets the QR decomposition of matrix `m` 410 | let inline decomposeQR (m:Matrix<'T>):(Matrix<'T>*Matrix<'T>) = m.GetQRDecomposition() 411 | /// Gets the determinant of matrix `m` 412 | let inline det (m:Matrix<'T>):'T = m.GetDeterminant() 413 | /// Gets the diagonal elements of matrix `m` 414 | let inline diagonal (m:Matrix<'T>):Vector<'T> = m.GetDiagonal() |> Vector.ofSeq 415 | /// Creates the identity matrix with `m` rows and columns 416 | let inline identity (m:int):Matrix<'T> = 417 | Matrix (Array2D.init m m (fun i j -> if i = j then LanguagePrimitives.GenericOne<'T> else LanguagePrimitives.GenericZero<'T>)) 418 | /// Gets the eigenvalues of matrix `m` 419 | let inline eigenvalues (m:Matrix<'T>):Vector<'T> = m.GetEigenvalues() |> Vector.ofSeq 420 | /// Gets the entry of matrix `m` with indices `i` and `j` 421 | let inline get (m:Matrix<'T>) (i:int) (j:int):'T = m.[i, j] 422 | /// Creates a matrix with `m` rows, `n` columns and a generator function `f` to compute the entries 423 | let inline init (m:int) (n:int) (f:int->int->'T):Matrix<'T> = Matrix (Array2D.init m n f) 424 | /// Creates a square matrix with `m` rows and columns and a generator function `f` to compute the elements. Function `f` is used only for populating the diagonal and the upper triangular part of the matrix, the lower triangular part will be the reflection. 425 | let inline initSymmetric (m:int) (f:int->int->'T):Matrix<'T> = 426 | if m = 0 then 427 | Matrix.Zero 428 | else 429 | let s = Array2D.zeroCreate<'T> m m 430 | for i = 0 to m - 1 do 431 | for j = i to m - 1 do 432 | s.[i, j] <- f i j 433 | Matrix (copyUpperToLower s) 434 | /// Gets the inverse of matrix `m` 435 | let inline inverse (m:Matrix<'T>):Matrix<'T> = m.GetInverse() 436 | /// Applies function `f` to each element of matrix `m` 437 | let inline iter (f:'T->unit) (m:Matrix<'T>):unit = m |> toArray2D |> Array2D.iter f 438 | /// Applies function `f` to each element of matrix `m`. Element indices are also supplied to function `f`. 439 | let inline iteri (f:int->int->'T->unit) (m:Matrix<'T>):unit = m |> toArray2D |> Array2D.iteri f 440 | /// Returns the number of rows in matrix `m`. This is the same with `Matrix.rows`. 441 | let inline length1 (m:Matrix<'T>):int = m.Rows 442 | /// Returns the number of columns in matrix `m`. This is the same with `Matrix.cols`. 443 | let inline length2 (m:Matrix<'T>):int = m.Cols 444 | /// Creates a matrix whose entries are the results of applying function `f` to each entry of matrix `m` 445 | let inline map (f:'T->'U) (m:Matrix<'T>):Matrix<'U> = m |> toArray2D |> Array2D.map f |> Matrix 446 | /// Creates a matrix whose entries are the results of applying function `f` to each entry of matrix `m`. Element indices are also supplied to function `f`. 447 | let inline mapi (f:int->int->'T->'U) (m:Matrix<'T>):Matrix<'U> = m |> toArray2D |> Array2D.mapi f |> Matrix 448 | /// Replaces the elements of matrix `m` by mutating them in place, passing them through function `f` 449 | let inline replace (f:'T->'T) (m:Matrix<'T>):unit = 450 | for i in 0..(m.Rows - 1) do 451 | for j in 0..(m.Cols - 1) do 452 | m.[i,j] <- f m.[i, j] 453 | /// Replaces the elements of matrix `m1` by mutating them in place. The new values are computed by applying function `f` to the corresponding elements of matrices `m1` and `m2` pairwise. The two input matrices should have the same dimensions, otherwise ArgumentException is raised. 454 | let inline replace2 (f:'T1->'T2->'T1) (m1:Matrix<'T1>) (m2:Matrix<'T2>):unit = 455 | if (m1.Rows <> m2.Rows) || (m1.Cols <> m2.Cols) then invalidArg "" "The matrices should have the same dimensions." 456 | for i in 0..(m1.Rows - 1) do 457 | for j in 0..(m1.Cols - 1) do 458 | m1.[i, j] <- f m1.[i, j] m2.[i, j] 459 | /// Replaces the elements of matrix `m` by mutating them in place, passing them through function` f`. Element indices are also supplied to function `f`. 460 | let inline replacei (f:int->int->'T->'T) (m:Matrix<'T>):unit = 461 | for i in 0..(m.Rows - 1) do 462 | for j in 0..(m.Cols - 1) do 463 | m.[i,j] <- f i j m.[i, j] 464 | /// Replaces the elements of matrix `m1` by mutating them in place. The new values are computed by applying function `f` to the corresponding elements of matrices `m1` and `m2` pairwise. Element indices are also supplied to function `f`. The two input matrices should have the same dimensions, otherwise ArgumentException is raised. 465 | let inline replacei2 (f:int->int->'T1->'T2->'T1) (m1:Matrix<'T1>) (m2:Matrix<'T2>):unit = 466 | if (m1.Rows <> m2.Rows) || (m1.Cols <> m2.Cols) then invalidArg "" "The matrices should have the same dimensions." 467 | for i in 0..(m1.Rows - 1) do 468 | for j in 0..(m1.Cols - 1) do 469 | m1.[i, j] <- f i j m1.[i, j] m2.[i, j] 470 | /// Replaces the elements of matrix `m1` with the elements of matrix `m2`, by mutating them in place. The two input matrices should have the same dimensions, otherwise ArgumentException is raised. 471 | let inline replaceWith (m1:Matrix<'T>) (m2:Matrix<'T>) = 472 | if (m1.Rows <> m2.Rows) || (m1.Cols <> m2.Cols) then invalidArg "" "The matrices should have the same dimensions." 473 | Array2D.blit (m2 |> toArray2D) 0 0 (m1 |> toArray2D) 0 0 m1.Rows m1.Cols 474 | /// Returns the i-th row of matrix `m` 475 | let inline row (i:int) (m:Matrix<'T>):Matrix<'T> = m.[i,*] 476 | /// Returns the number of rows in matrix `m`. This is the same with `Matrix.length1`. 477 | let inline rows (m:Matrix<'T>):int = m.Rows 478 | /// Sets the entry of matrix `m` with indices `i` and `j` to value `a` 479 | let inline set (m:Matrix<'T>) (i:int) (j:int) (a:'T) = m.[i, j] <- a 480 | /// Solves a system of linear equations ax = b, where the coefficients are given in matrix `a` and the result vector is vector `b`. The returned vector will correspond to x. 481 | let inline solve (a:Matrix<'T>) (b:Vector<'T>):Vector<'T> = 482 | if a.Cols <> b.Length then invalidArg "" "Cannot solve the system of equations using a matrix and a vector of incompatible sizes." 483 | let lu, perm, _ = a.GetLUDecomposition() 484 | let bp = Array.init a.Rows (fun i -> b.[perm.[i]]) 485 | Vector (matrixSolveHelper (lu.ToArray2D()) bp) 486 | /// Gets the trace of matrix `m` 487 | let inline trace (m:Matrix<'T>):'T = m.GetTrace() 488 | /// Gets the transpose of matrix `m` 489 | let inline transpose (m:Matrix<'T>):Matrix<'T> = m.GetTranspose() 490 | /// Constructs a matrix out of a sequence of row vectors `v`. The row vectors should be of equal length. 491 | let inline ofRows (v:seq>):Matrix<'T> = v |> Seq.map Vector.toSeq |> ofSeqSeq 492 | /// Returns the rows of matrix `m` as a sequence of matrices 493 | let inline toRows (m:Matrix<'T>):seq> = Seq.init m.Rows (fun i -> m.[i,*]) 494 | /// Constructs a matrix out of a sequence of column vectors `v`. The column vectors should be of equal length. 495 | let inline ofCols (v:seq>):Matrix<'T> = v |> ofRows |> transpose 496 | /// Returns the columns of matrix `m` as a sequence of matrices 497 | let inline toCols (m:Matrix<'T>):seq> = m |> transpose |> toRows 498 | /// Returns a matrix where vector `v` is appended as a new row to matrix `m` 499 | let inline appendRow (v:Vector<'T>) (m:Matrix<'T>):Matrix<'T> = 500 | if m.Cols <> v.Length then invalidArg "" "The length of the appended row should be the same with the number of the columns in the matrix." 501 | let mm = m |> toArray2D 502 | let ret = Array2D.zeroCreate (m.Rows + 1) m.Cols 503 | Array2D.blit mm 0 0 ret 0 0 m.Rows m.Cols 504 | for i = 0 to m.Cols - 1 do 505 | ret.[m.Rows, i] <- v.[i] 506 | Matrix ret 507 | /// Returns a matrix where vector `v` is appended as a new column to matrix `m` 508 | let inline appendCol (v:Vector<'T>) (m:Matrix<'T>):Matrix<'T> = 509 | if m.Rows <> v.Length then invalidArg "" "The length of the appended column should be the same with the number of rows in the matrix." 510 | let mm = m |> toArray2D 511 | let ret = Array2D.zeroCreate m.Rows (m.Cols + 1) 512 | Array2D.blit mm 0 0 ret 0 0 m.Rows m.Cols 513 | for i = 0 to m.Rows - 1 do 514 | ret.[i, m.Cols] <- v.[i] 515 | Matrix ret 516 | /// Returns a matrix where vector `v` is appended as a new row to matrix `m` 517 | let inline prependRow (v:Vector<'T>) (m:Matrix<'T>):Matrix<'T> = 518 | if m.Cols <> v.Length then invalidArg "" "The length of the prepended row should be the same with the number of the columns in the matrix." 519 | let mm = m |> toArray2D 520 | let ret = Array2D.zeroCreate (m.Rows + 1) m.Cols 521 | Array2D.blit mm 0 0 ret 1 0 m.Rows m.Cols 522 | for i = 0 to m.Cols - 1 do 523 | ret.[0, i] <- v.[i] 524 | Matrix ret 525 | /// Returns a matrix where vector `v` is prepended as a new column to matrix `m` 526 | let inline prependCol (v:Vector<'T>) (m:Matrix<'T>):Matrix<'T> = 527 | if m.Rows <> v.Length then invalidArg "" "The length of the prepended column should be the same with the number of rows in the matrix." 528 | let mm = m |> toArray2D 529 | let ret = Array2D.zeroCreate m.Rows (m.Cols + 1) 530 | Array2D.blit mm 0 0 ret 0 1 m.Rows m.Cols 531 | for i = 0 to m.Rows - 1 do 532 | ret.[i, 0] <- v.[i] 533 | Matrix ret 534 | /// Creates a matrix with `n` columns and a generator function `f` that gives each column as a vector 535 | let inline initCols (n:int) (f:int->Vector<'T>):Matrix<'T> = Matrix (array2D (Array.init n (f >> Vector.toArray))) |> transpose 536 | /// Creates a matrix with `m` rows and a generator function `f` that gives each row as a a vector 537 | let inline initRows (m:int) (f:int->Vector<'T>):Matrix<'T> = Matrix (array2D (Array.init m (f >> Vector.toArray))) 538 | --------------------------------------------------------------------------------