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 |
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 |
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 |
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 |
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 |
--------------------------------------------------------------------------------