Browse Source

Docs: Turn F# Sample project into documentation (using FSharp.Literate/Formatting)

pull/167/head
Christoph Ruegg 13 years ago
parent
commit
728dc322ec
  1. 3
      MathNet.Numerics.sln
  2. 42
      build/FSharp.Formatting/build.fsx
  3. 243
      build/FSharp.Formatting/content/style.css
  4. 46
      build/FSharp.Formatting/content/tips.js
  5. 56
      build/FSharp.Formatting/template.html
  6. BIN
      packages/FSharp.Formatting.1.0.15/FSharp.Formatting.1.0.15.nupkg
  7. 19
      packages/FSharp.Formatting.1.0.15/FSharp.Formatting.1.0.15.nuspec
  8. BIN
      packages/FSharp.Formatting.1.0.15/lib/net40/FSharp.CodeFormat.dll
  9. BIN
      packages/FSharp.Formatting.1.0.15/lib/net40/FSharp.CodeFormat.pdb
  10. BIN
      packages/FSharp.Formatting.1.0.15/lib/net40/FSharp.CompilerBinding.dll
  11. BIN
      packages/FSharp.Formatting.1.0.15/lib/net40/FSharp.CompilerBinding.pdb
  12. BIN
      packages/FSharp.Formatting.1.0.15/lib/net40/FSharp.Markdown.dll
  13. BIN
      packages/FSharp.Formatting.1.0.15/lib/net40/FSharp.Markdown.pdb
  14. 160
      packages/FSharp.Formatting.1.0.15/literate/StringParsing.fs
  15. 152
      packages/FSharp.Formatting.1.0.15/literate/content/style.css
  16. 47
      packages/FSharp.Formatting.1.0.15/literate/content/tips.js
  17. 41
      packages/FSharp.Formatting.1.0.15/literate/demo.fsx
  18. 717
      packages/FSharp.Formatting.1.0.15/literate/literate.fsx
  19. 35
      packages/FSharp.Formatting.1.0.15/literate/templates/template-file.html
  20. 62
      packages/FSharp.Formatting.1.0.15/literate/templates/template-project.html
  21. 1
      packages/repositories.config
  22. 12
      src/FSharp/Distributions.fs
  23. 13
      src/FSharpExamples/FSharpExamples.fsproj
  24. 6
      src/FSharpExamples/Matrices.fsx
  25. 269
      src/FSharpExamples/RandomAndDistributions.fsx
  26. 6
      src/FSharpExamples/Vectors.fsx
  27. 4
      src/FSharpExamples/packages.config

3
MathNet.Numerics.sln

@ -4,6 +4,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{4D50FB34-10BC-495A-8B2F-482E34B4D771}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{49EE74BD-301F-4C3B-B76A-07F90CC88CE7}"
ProjectSection(SolutionItems) = preProject
build\FSharp.Formatting\build.fsx = build\FSharp.Formatting\build.fsx
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Readme", "Readme", "{C2F37492-38AE-4186-8A7F-17B0B080942C}"
ProjectSection(SolutionItems) = preProject

42
build/FSharp.Formatting/build.fsx

@ -0,0 +1,42 @@
#I "../../packages/FSharp.Formatting.1.0.15/lib/net40"
#load "../../packages/FSharp.Formatting.1.0.15/literate/literate.fsx"
open System
open System.IO
open FSharp.Literate
let (+/) l r = Path.GetFullPath(Path.Combine(l,r))
let source = __SOURCE_DIRECTORY__
let toolDir = source +/ "../../packages/FSharp.Formatting.1.0.15/lib/net40"
let libDir = source +/ "../../out/lib/Net40"
let templateDir = source
let inputDir = source +/ "../../src/FSharpExamples"
let outputDir = source +/ "../../out/docs"
let templateFile = "template.html"
let templateContent = ["content/style.css"; "content/tips.js"]
// Additional strings to be replaced in the HTML template
let projInfo =
[ "page-description", ""
"page-author", "Math.NET Team & Contributors; Christoph Ruegg"
"project-name", "Math.NET Numerics" ]
let compilerReferences =
[ toolDir +/ "FSharp.CompilerBinding.dll"
toolDir +/ "FSharp.CodeFormat.dll"
toolDir +/ "FSharp.Markdown.dll"
"System.Web.dll"
libDir +/ "MathNet.Numerics.dll"
libDir +/ "MathNet.Numerics.FSharp.dll" ]
// Compiler options (reference the two dll files and System.Web.dll)
let compilerOptions = (List.fold (fun s p -> s + sprintf """--reference:"%s" """ p) "" compilerReferences).Trim()
// Copy template content files (scripts, styles, images, ..)
List.iter (fun tc -> File.Copy(templateDir +/ tc, outputDir +/ tc, true)) templateContent
// Now we can process the samples directory (with some additional references)
// and then we clean up the files & directories we had to create earlier
Literate.ProcessDirectory(inputDir, templateDir +/ templateFile, outputDir, OutputKind.Html, replacements=projInfo, compilerOptions=compilerOptions)

243
build/FSharp.Formatting/content/style.css

@ -0,0 +1,243 @@
@import url(http://fonts.googleapis.com/css?family=Ovo);
@import url(http://fonts.googleapis.com/css?family=Droid+Sans+Mono);
/*--------------------------------------------------------------------------
Formatting for F# code snippets
/*--------------------------------------------------------------------------*/
/* identifier */
span.i { color:#000000; }
/* string */
span.s { color:#ce4415; }
/* keywords */
span.k { color:#0000fe; }
/* comment */
span.c { color:#008000; }
/* operators */
span.o { color:#800080; }
/* numbers */
span.n { color:#cd8300; }
/* line number */
span.l { color:#80b0b0; }
/* inactive code */
span.inactive { color:#808080; }
/* preprocessor */
span.prep { color:#800080; }
/* fsi output */
span.fsi { font-style:italic; color:#808080; }
/* omitted */
span.omitted {
color: #808080;
background: #fafafa;
border: solid 1px #d8d8d8;
border-radius: 5px;
padding: 0px 0px 1px 0px;
}
/* tool tip */
div.tip {
display: none;
font: 10pt Consolas, Calibri, sans-serif;
color: #d1d1d1;
background: #475b5f;
border: 1px solid #606060;
border-radius: 4px;
padding: 3px;
}
/* Optionally, also configure how the PRE element and TABLE.PRE look */
table.pre pre {
padding: 0;
margin: 0;
border-style: none;
border-radius:0;
width: 100%;
}
pre {
margin:10px 20px 20px 10px;
white-space:pre;
}
code {
font: 9pt "Droid Sans Mono", Consolas, sans-serif;
color: #7d0a26;
background-color: inherit;
border: 1px solid #e8e8e8;
padding: 1px 3px;
}
pre code {
width: 95%;
}
table.pre {
width: 95%;
margin:10px 20px 20px 10px;
padding: 10px;
}
table.pre, pre.fssnip, pre {
font: 9pt "Droid Sans Mono", Consolas, sans-serif;
color:#404040;
background: #f5f5f5;
border:1px solid #e0e0e0;
border-radius:5px;
border-collapse:separate;
line-height: 13pt;
margin:10px 20px 20px 10px;
padding:10px;
}
/*pre, table.pre td {
padding: 9.5px;
background: #f5f5f5;
border: solid 1px black;
border-radius: 4px;
border-color: rgba(0,0,0,0.15);
margin: 0 0 10px 0;
}*/
table.pre td {
padding: 0;
white-space: normal;
margin: 0;
}
table.pre td.lines {
width: 30px;
}
/*table.pre td.lines {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-right-style: none;
padding-right: 0;
}
table.pre td.snippet {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-left-style: none;
padding-left: 4px;
}*/
/*--------------------------------------------------------------------------
Formatting for page & standard document content
/*--------------------------------------------------------------------------*/
body {
font-family: Ovo, serif;
padding-top: 0;
padding-bottom: 40px;
}
a, a:visited {
color: #1BA1E2;
text-decoration: none;
}
a:hover {
color: white;
background: #1BA1E2;
}
.nav {
font-family: "Segoe UI", "Segoe WP", "Helvetica Neue", 'RobotoRegular', "Trebuchet MS", sans-serif;
}
.nav li a:hover {
color: white;
background: #1BA1E2;
}
/* Format the heading - nicer spacing etc. */
.masthead {
overflow: hidden;
}
.masthead ul, .masthead li {
margin-bottom: 0;
}
.masthead .nav li {
margin-top: 15px;
font-size: 110%;
}
.masthead h3 {
font-family: "Segoe UI", "Segoe WP", "Helvetica Neue", 'RobotoRegular', "Trebuchet MS", sans-serif;
font-weight: normal;
color: #1BA1E2;
margin-bottom: 5px;
font-size: 170%;
}
hr {
margin: 0 0 20px 0;
}
/* Format the right-side menu */
#menu {
margin-top: 50px;
font-size: 11pt;
padding-left: 20px;
}
#menu .nav-header {
font-size: 12pt;
color: #606060;
margin-top: 20px;
}
#menu li {
line-height: 25px;
}
/* Change font sizes for headings etc. */
#main h1 { font-size: 26pt; margin:10px 0 15px 0; }
#main h2 { font-size: 20pt; margin:20px 0 0 0; }
#main h3 { font-size: 14pt; margin:15px 0 0 0; }
#main p { font-size: 12pt; margin:5px 0 15px 0; }
#main ul { font-size: 12pt; margin-top:10px; }
#main li { font-size: 12pt; margin: 5px 0 5px 0; }
/*--------------------------------------------------------------------------
Additional formatting for the homepage
/*--------------------------------------------------------------------------*/
#nuget {
margin-top: 20px;
font-size: 11pt;
padding: 20px;
}
#nuget pre {
font-size: 11pt;
-moz-border-radius: 0;
-webkit-border-radius: 0;
border-radius: 0;
background: #404040;
border-style: none;
color: #e0e0e0;
margin-top: 15px;
}
#hp-snippet td.lines {
display: none;
}
#hp-snippet .table {
width: 80%;
margin-left: 30px;
}
#hp-snippet thead, #hp-snippet .title {
font-weight: bold;
}
#menu li.generatedBy {
margin-top: 40px;
font-size: 0.8em;
line-height: normal;
color: #808080;
}

46
build/FSharp.Formatting/content/tips.js

@ -0,0 +1,46 @@
var currentTip = null;
var currentTipElement = null;
function hideTip(evt, name, unique) {
var el = document.getElementById(name);
el.style.display = "none";
currentTip = null;
}
function findPos(obj) {
// no idea why, but it behaves differently in webbrowser component
if (window.location.search == "?inapp")
return [obj.offsetLeft + 10, obj.offsetTop + 30];
var curleft = 0;
var curtop = obj.offsetHeight;
while (obj) {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
obj = obj.offsetParent;
};
return [curleft, curtop];
}
function hideUsingEsc(e) {
if (!e) { e = event; }
hideTip(e, currentTipElement, currentTip);
}
function showTip(evt, name, unique, owner) {
document.onkeydown = hideUsingEsc;
if (currentTip == unique) return;
currentTip = unique;
currentTipElement = name;
var pos = findPos(owner ? owner : (evt.srcElement ? evt.srcElement : evt.target));
var posx = pos[0];
var posy = pos[1];
var el = document.getElementById(name);
var parent = (document.documentElement == null) ? document.body : document.documentElement;
el.style.position = "absolute";
el.style.left = posx + "px";
el.style.top = posy + "px";
el.style.display = "block";
}

56
build/FSharp.Formatting/template.html

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{page-title}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{page-description}">
<meta name="author" content="{page-author}">
<script src="http://code.jquery.com/jquery-1.8.0.js"></script>
<script src="http://code.jquery.com/ui/1.8.23/jquery-ui.js"></script>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/js/bootstrap.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/css/bootstrap-combined.min.css" rel="stylesheet">
<link type="text/css" rel="stylesheet" href="content/style.css" />
<script src="content/tips.js" type="text/javascript"></script>
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<div class="masthead">
<ul class="nav nav-pills pull-right">
<li><a href="http://www.mathdotnet.com">Math.NET Project</a></li>
<li><a href="http://numerics.mathdotnet.com">Math.NET Numerics</a></li>
<li><a href="https://github.com/mathnet/mathnet-numerics">GitHub</a></li>
<li><a href="https://mathnetnumerics.codeplex.com/">CodePlex</a></li>
</ul>
<h3>Math.NET Numerics</h3>
</div>
<hr />
<div class="row">
<div class="span9" id="main">
{document}
{tooltips}
</div>
<div class="span3">
<ul class="nav nav-list" id="menu">
<li class="nav-header">Math.NET Numerics</li>
<li><a href="http://numerics.mathdotnet.com">Home page</a></li>
<li><a href="http://numerics.mathdotnet.com/api/">API Reference</a></li>
<li class="nav-header">User Guide</li>
<li><a href="index.html">Random & Distributions</a></li>
<li class="generatedBy"><span>
<em>You</em> can edit this page <a href="https://github.com/mathnet/mathnet-numerics/tree/master/src/FSharpExamples">here</a>.<br />
Generated using <a href="http://tpetricek.github.io/FSharp.Formatting/">FSharp.Literate</a>.
</span></li>
</ul>
</div>
</div>
</div>
</body>
</html>

BIN
packages/FSharp.Formatting.1.0.15/FSharp.Formatting.1.0.15.nupkg

Binary file not shown.

19
packages/FSharp.Formatting.1.0.15/FSharp.Formatting.1.0.15.nuspec

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>FSharp.Formatting</id>
<version>1.0.15</version>
<title>FSharp.Formatting</title>
<authors>Tomas Petricek, Oleg Pestov, Anh-Dung Phan</authors>
<owners>Tomas Petricek, Oleg Pestov, Anh-Dung Phan</owners>
<licenseUrl>http://github.com/tpetricek/FSharp.Formatting/blob/master/LICENSE.md</licenseUrl>
<projectUrl>http://github.com/tpetricek/FSharp.Formatting</projectUrl>
<iconUrl>https://raw.github.com/tpetricek/FSharp.Formatting/master/docs/misc/logo.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Provides an F# implementation of Markdown parser and F# code formatter that can used to tokenize F# code and obtain information about tokens including tool tips with type information. The package comes with a sample that implements literate programming for F#.</description>
<releaseNotes>Added latex support, tables and better formatting with line numbers</releaseNotes>
<copyright>Copyright 2013</copyright>
<language />
<tags>F# fsharp formatting markdown code fssnip literate programming</tags>
</metadata>
</package>

BIN
packages/FSharp.Formatting.1.0.15/lib/net40/FSharp.CodeFormat.dll

Binary file not shown.

BIN
packages/FSharp.Formatting.1.0.15/lib/net40/FSharp.CodeFormat.pdb

Binary file not shown.

BIN
packages/FSharp.Formatting.1.0.15/lib/net40/FSharp.CompilerBinding.dll

Binary file not shown.

BIN
packages/FSharp.Formatting.1.0.15/lib/net40/FSharp.CompilerBinding.pdb

Binary file not shown.

BIN
packages/FSharp.Formatting.1.0.15/lib/net40/FSharp.Markdown.dll

Binary file not shown.

BIN
packages/FSharp.Formatting.1.0.15/lib/net40/FSharp.Markdown.pdb

Binary file not shown.

160
packages/FSharp.Formatting.1.0.15/literate/StringParsing.fs

@ -0,0 +1,160 @@
// --------------------------------------------------------------------------------------
// F# Markdown (StringParsing.fs)
// (c) Tomas Petricek, 2012, Available under Apache 2.0 license.
// --------------------------------------------------------------------------------------
module FSharp.Patterns
open System
open FSharp.Collections
// --------------------------------------------------------------------------------------
// Active patterns that simplify parsing of strings and lists of strings (lines)
// --------------------------------------------------------------------------------------
module String =
/// Matches when a string is a whitespace or null
let (|WhiteSpace|_|) s =
if String.IsNullOrWhiteSpace(s) then Some() else None
/// Matches when a string does starts with non-whitespace
let (|Unindented|_|) (s:string) =
if not (String.IsNullOrWhiteSpace(s)) && s.TrimStart() = s then Some() else None
/// Returns a string trimmed from both start and end
let (|TrimBoth|) (text:string) = text.Trim()
/// Returns a string trimmed from the end
let (|TrimEnd|) (text:string) = text.TrimEnd()
/// Returns a string trimmed from the start
let (|TrimStart|) (text:string) = text.TrimStart()
/// Retrusn a string trimmed from the end using characters given as a parameter
let (|TrimEndUsing|) chars (text:string) = text.TrimEnd(Array.ofSeq chars)
/// Returns a string trimmed from the start together with
/// the number of skipped whitespace characters
let (|TrimStartAndCount|) (text:string) =
let trimmed = text.TrimStart()
text.Length - trimmed.Length, trimmed
/// Matches when a string starts with any of the specified sub-strings
let (|StartsWithAny|_|) (starts:seq<string>) (text:string) =
if starts |> Seq.exists (text.StartsWith) then Some() else None
/// Matches when a string starts with the specified sub-string
let (|StartsWith|_|) (start:string) (text:string) =
if text.StartsWith(start) then Some(text.Substring(start.Length)) else None
/// Matches when a string starts with the specified sub-string
/// The matched string is trimmed from all whitespace.
let (|StartsWithTrim|_|) (start:string) (text:string) =
if text.StartsWith(start) then Some(text.Substring(start.Length).Trim()) else None
/// Matches when a string starts with the given value and ends
/// with a given value (and returns the rest of it)
let (|StartsAndEndsWith|_|) (starts, ends) (s:string) =
if s.StartsWith(starts) && s.EndsWith(ends) &&
s.Length >= starts.Length + ends.Length then
Some(s.Substring(starts.Length, s.Length - starts.Length - ends.Length))
else None
/// Matches when a string starts with the given value and ends
/// with a given value (and returns trimmed body)
let (|StartsAndEndsWithTrim|_|) args = function
| StartsAndEndsWith args (TrimBoth res) -> Some res
| _ -> None
/// Matches when a string starts with a non-zero number of complete
/// repetitions of the specified parameter (and returns the number
/// of repetitions, together with the rest of the string)
///
/// let (StartsWithRepeated "/\" (2, " abc")) = "/\/\ abc"
///
let (|StartsWithRepeated|_|) (repeated:string) (text:string) =
let rec loop i =
if i = text.Length then i
elif text.[i] <> repeated.[i % repeated.Length] then i
else loop (i + 1)
let n = loop 0
if n = 0 || n % repeated.Length <> 0 then None
else Some(n/repeated.Length, text.Substring(n, text.Length - n))
/// Matches when a string starts with a sub-string wrapped using the
/// opening and closing sub-string specified in the parameter.
/// For example "[aa]bc" is wrapped in [ and ] pair. Returns the wrapped
/// text together with the rest.
let (|StartsWithWrapped|_|) (starts:string, ends:string) (text:string) =
if text.StartsWith(starts) then
let id = text.IndexOf(ends, starts.Length)
if id >= 0 then
let wrapped = text.Substring(starts.Length, id - starts.Length)
let rest = text.Substring(id + ends.Length, text.Length - id - ends.Length)
Some(wrapped, rest)
else None
else None
/// Matches when a string consists of some number of
/// complete repetitions of a specified sub-string.
let (|EqualsRepeated|_|) repeated = function
| StartsWithRepeated repeated (n, "") -> Some()
| _ -> None
module List =
/// Matches a list if it starts with a sub-list that is delimited
/// using the specified delimiters. Returns a wrapped list and the rest.
let inline (|DelimitedWith|_|) startl endl input =
if List.startsWith startl input then
match List.partitionUntilEquals endl (List.skip startl.Length input) with
| Some(pre, post) -> Some(pre, List.skip endl.Length post)
| None -> None
else None
/// Matches a list if it starts with a sub-list that is delimited
/// using the specified delimiter. Returns a wrapped list and the rest.
let inline (|Delimited|_|) str = (|DelimitedWith|_|) str str
/// Matches a list if it starts with a bracketed list. Nested brackets
/// are skipped (by counting opening and closing brackets) and can be
/// escaped using the '\' symbol.
let (|BracketDelimited|_|) startc endc input =
let rec loop acc count = function
| '\\'::x::xs when x = endc -> loop (x::acc) count xs
| x::xs when x = endc && count = 0 -> Some(List.rev acc, xs)
| x::xs when x = endc -> loop (x::acc) (count - 1) xs
| x::xs when x = startc -> loop (x::acc) (count + 1) xs
| x::xs -> loop (x::acc) count xs
| [] -> None
match input with
| x::xs when x = startc -> loop [] 0 xs
| _ -> None
/// Retruns a list of characters as a string.
let (|AsString|) chars = String(Array.ofList chars)
module Lines =
/// Removes blank lines from the start and the end of a list
let (|TrimBlank|) lines =
lines
|> List.skipWhile String.IsNullOrWhiteSpace |> List.rev
|> List.skipWhile String.IsNullOrWhiteSpace |> List.rev
/// Matches when there are some lines at the beginning that are
/// either empty (or whitespace) or start with the specified string.
/// Returns all such lines from the beginning until a different line.
let (|TakeStartingWithOrBlank|_|) start input =
match List.partitionWhile (fun s ->
String.IsNullOrWhiteSpace s || s.StartsWith(start)) input with
| matching, rest when matching <> [] -> Some(matching, rest)
| _ -> None
/// Removes whitespace lines from the beginning of the list
let (|TrimBlankStart|) = List.skipWhile (String.IsNullOrWhiteSpace)
/// Parameterized pattern that assigns the specified value to the
/// first component of a tuple. Usage:
///
/// match str with
/// | Let 1 (n, "one") | Let 2 (n, "two") -> n
///
let (|Let|) a b = (a, b)

152
packages/FSharp.Formatting.1.0.15/literate/content/style.css

@ -0,0 +1,152 @@
@import url(http://fonts.googleapis.com/css?family=Ovo);
@import url(http://fonts.googleapis.com/css?family=Droid+Sans+Mono);
/*********************** TOOL TIP STYLES **********************/
/* The following CSS classes are used by the F# formatter and */
/* so you should include them whenever you want to display */
/* HTML code generated by FSharp.CodeFormat.dll */
/**************************************************************/
/* identifier */
span.i { color:#000000; }
/* comment */
span.c { color:#008000; }
/* inactive code */
span.inactive { color:#808080; }
/* keywords */
span.k { color:#000080; }
/* numbers */
span.n { color:#008000; }
/* operators */
span.o { color:#800080; }
/* preprocessor */
span.prep { color:#800080; }
/* string */
span.s { color:#808000; }
/* line number */
span.l { color:#80b0b0; }
/* fsi output */
span.fsi { font-style:italic; color:#606060; }
/* omitted */
span.omitted {
border:solid 1px #d8d8d8;
color:#808080;
padding:0px 0px 1px 0px;
background:#fafafa;
}
/* tool tip */
div.tip
{
font: 10pt calibri, sans-serif;
padding:3px;
border:1px solid #606060;
background:#ffffd0;
display:none;
}
/* Optionally, also configure how the PRE element and TABLE.PRE look */
table.pre pre {
padding:0px;
margin:0px;
border-style:none;
}
pre, table.pre td {
padding:9.5px;
background:#f5f5f5;
border:solid 1px black;
border-radius:4px;
border-color:rgba(0,0,0,0.15);
margin:0px 0px 10px 0px;
}
table.pre td.lines {
border-top-right-radius:0px;
border-bottom-right-radius:0px;
border-right-style: none;
padding-right:0px;
}
table.pre td.snippet {
border-top-left-radius:0px;
border-bottom-left-radius:0px;
border-left-style: none;
padding-left:4px;
}
code, pre, pre code {
font-family:9pt "Droid Sans Mono", sans-serif;
line-height:13pt;
}
/********************* ADDITIONAL STYLES **********************/
/* These styles are not necessary - they just provide a nice */
/* Bootstrap template that can be freely used by F# libraries */
/**************************************************************/
body {
font-family: Ovo, serif;
padding-top: 0px;
padding-bottom: 40px;
}
/* Format the heading - nicer spacing etc. */
.masthead {
overflow: hidden;
}
.masthead ul, .masthead li {
margin-bottom:0px;
}
.masthead .nav li {
margin-top: 15px;
font-size:110%;
}
.masthead h3 {
margin-bottom:5px;
font-size:170%;
}
hr {
margin:0px 0px 20px 0px;
}
/* Format the right-side menu */
#menu {
margin-top:50px;
font-size:11pt;
padding-left:20px;
}
#menu .nav-header {
font-size:12pt;
color:#606060;
margin-top:20px;
}
#menu li {
line-height:25px;
}
/* Change font sizes for headings etc. */
#main h1 { font-size: 26pt; margin:10px 0px 15px 0px; }
#main h2 { font-size: 20pt; margin:20px 0px 0px 0px; }
#main h3 { font-size: 14pt; margin:15px 0px 0px 0px; }
#main p { font-size: 12pt; margin:5px 0px 15px 0px; }
#main ul { font-size: 12pt; margin-top:10px; }
#main li { font-size: 12pt; margin: 5px 0px 5px 0px; }
/* Additional formatting for the homepage */
#nuget {
margin-top:20px;
font-size: 11pt;
padding:20px;
}
#nuget pre {
font-size:11pt;
-moz-border-radius: 0px;
-webkit-border-radius: 0px;
border-radius: 0px;
background: #404040;
border-style:none;
color: #e0e0e0;
margin-top:15px;
}

47
packages/FSharp.Formatting.1.0.15/literate/content/tips.js

@ -0,0 +1,47 @@
var currentTip = null;
var currentTipElement = null;
function hideTip(evt, name, unique)
{
var el = document.getElementById(name);
el.style.display = "none";
currentTip = null;
}
function findPos(obj)
{
var curleft = 0;
var curtop = obj.offsetHeight;
while (obj)
{
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
obj = obj.offsetParent;
};
return [curleft, curtop];
}
function hideUsingEsc(e)
{
if (!e) { e = event; }
hideTip(e, currentTipElement, currentTip);
}
function showTip(evt, name, unique, owner)
{
document.onkeydown = hideUsingEsc;
if (currentTip == unique) return;
currentTip = unique;
currentTipElement = name;
var pos = findPos(owner ? owner : (evt.srcElement ? evt.srcElement : evt.target));
var posx = pos[0];
var posy = pos[1];
var el = document.getElementById(name);
var parent = (document.documentElement == null) ? document.body : document.documentElement;
el.style.position = "absolute";
el.style.left = posx + "px";
el.style.top = posy + "px";
el.style.display = "block";
}

41
packages/FSharp.Formatting.1.0.15/literate/demo.fsx

@ -0,0 +1,41 @@
// Given a typical setup (with 'FSharp.Formatting' referenced using NuGet),
// the following will include binaries and load the literate script
#I "../bin"
#load "literate.fsx"
open FSharp.Literate
/// This functions processes a single F# Script file
let processScript templateFile outputKind =
let file = __SOURCE_DIRECTORY__ + "\\test.fsx"
let output = __SOURCE_DIRECTORY__ + "\\outputs\\test." + (outputKind.ToString())
let template = __SOURCE_DIRECTORY__ + templateFile
Literate.ProcessScriptFile(file, template, output, format = outputKind)
/// This functions processes a single Markdown document
let processDocument templateFile outputKind =
let file = __SOURCE_DIRECTORY__ + "\\demo.md"
let output = __SOURCE_DIRECTORY__ + "\\outputs\\demo." + (outputKind.ToString())
let template = __SOURCE_DIRECTORY__ + templateFile
Literate.ProcessMarkdown(file, template, output, format = outputKind)
/// This functions processes an entire directory containing
/// multiple script files (*.fsx) and Markdown documents (*.md)
/// and it specifies additional replacements for the template file
let processDirectory() =
let dir = __SOURCE_DIRECTORY__
let template = __SOURCE_DIRECTORY__ + "\\templates\\template-project.html"
let projInfo =
[ "page-description", "F# Literate Programming"
"page-author", "Tomas Petricek"
"github-link", "https://github.com/tpetricek/FSharp.Formatting"
"project-name", "F# Formatting" ]
Literate.ProcessDirectory
( dir, template, dir + "\\output", OutputKind.Html,
replacements = projInfo)
// Generate output for sample scripts & documents in both HTML & Latex
processScript "\\templates\\template-file.html" OutputKind.Html
processDocument "\\templates\\template-file.html" OutputKind.Html
processScript "\\templates\\template-color.tex" OutputKind.Latex
processDocument "\\templates\\template-color.tex" OutputKind.Latex

717
packages/FSharp.Formatting.1.0.15/literate/literate.fsx

@ -0,0 +1,717 @@
(**
Literate programming for F#
===========================
Implementation
--------------
This document is written as a literate F# script file, so the remaining text
is an overview of the implementation. The implementation uses `FSharp.Markdown.dll`
and `FSharp.CodeFormat.dll` to colorize F# source & parse Markdown:
*)
(*** hide ***)
namespace FSharp.Literate
#if INTERACTIVE
#I "../bin/"
#r "System.Web.dll"
#r "FSharp.Markdown.dll"
#r "FSharp.CodeFormat.dll"
#load "StringParsing.fs"
#endif
open System
open System.IO
open System.Web
open System.Reflection
open System.Collections.Generic
open FSharp.Patterns
open FSharp.CodeFormat
open FSharp.Markdown
(**
### OutputKind type
The following type defines the two possible output types from literate script:
HTML and LaTeX.
*)
[<RequireQualifiedAccess>]
type OutputKind =
| Html
| Latex
(*[omit:(members omitted)]*)
/// Name of the format (used as a file extension)
override x.ToString() =
match x with
| Html -> "html"
| Latex -> "tex"
/// Format a given document as HTML or LaTeX depending on the current kind
member x.Format(doc) =
match x with
| OutputKind.Html -> Markdown.WriteHtml(doc)
| OutputKind.Latex -> Markdown.WriteLatex(doc)
/// The name of the {tag} that is used for pasting content into a template file
/// (the default is {document}, but that collides in LaTeX)
member x.ContentTag =
match x with
| OutputKind.Html -> "document"
| OutputKind.Latex -> "contents"
(*[/omit]*)
(**
### CommandUtils module
Utilities for parsing commands. Commands can be used in different places. We
recognize `key1=value, key2=value` and also `key1:value, key2:value`
*)
module internal CommandUtils =
(*[omit:(Implementation omitted)]*)
let (|ParseCommands|_|) (str:string) =
let kvs =
[ for cmd in str.Split(',') do
let kv = cmd.Split([| '='; ':' |])
if kv.Length = 2 then yield kv.[0].Trim(), kv.[1].Trim()
elif kv.Length = 1 then yield kv.[0].Trim(), "" ]
if kvs <> [] then Some(dict kvs) else None
let (|Command|_|) k (d:IDictionary<_, _>) =
match d.TryGetValue(k) with
| true, v -> Some v
| _ -> None
(*[/omit]*)
(**
### LiterateUtils module
Utilities for processing Markdown documents - extract links for references,
add links to references, extract code blocks for colorization and replace them
with formatted HTML (after running F# code formatter)
*)
module internal LiterateUtils =
(*[omit:(Implementation omitted)]*)
open CommandUtils
/// Given Markdown document, get the keys of all IndirectLinks
/// (to be used when generating paragraph with all references)
let rec collectReferences =
// Collect IndirectLinks in a span
let rec collectSpanReferences span = seq {
match span with
| IndirectLink(_, _, key) -> yield key
| Matching.SpanLeaf _ -> ()
| Matching.SpanNode(_, spans) ->
for s in spans do yield! collectSpanReferences s }
// Collect IndirectLinks in a paragraph
let rec loop par = seq {
match par with
| Matching.ParagraphLeaf _ -> ()
| Matching.ParagraphNested(_, pars) ->
for ps in pars do
for p in ps do yield! loop p
| Matching.ParagraphSpans(_, spans) ->
for s in spans do yield! collectSpanReferences s }
loop
/// Given Markdown document, add a number using the given index to all indirect
/// references. For example, [article][ref] becomes [article][ref] [1](#rfxyz)
let replaceReferences (refIndex:IDictionary<string, int>) =
// Replace IndirectLinks with a nice link given a single span element
let rec replaceSpans = function
| IndirectLink(body, original, key) ->
[ yield IndirectLink(body, original, key)
match refIndex.TryGetValue(key) with
| true, i ->
yield Literal "&#160;["
yield DirectLink([Literal (string i)], ("#rf" + DateTime.Now.ToString("yyMMddhh"), None))
yield Literal "]"
| _ -> () ]
| Matching.SpanLeaf(sl) -> [Matching.SpanLeaf(sl)]
| Matching.SpanNode(nd, spans) ->
[ Matching.SpanNode(nd, List.collect replaceSpans spans) ]
// Given a paragraph, process it recursively and transform all spans
let rec loop = function
| Matching.ParagraphNested(pn, nested) ->
Matching.ParagraphNested(pn, List.map (List.choose loop) nested) |> Some
| Matching.ParagraphSpans(ps, spans) ->
Matching.ParagraphSpans(ps, List.collect replaceSpans spans) |> Some
| Matching.ParagraphLeaf(pl) -> Matching.ParagraphLeaf(pl) |> Some
loop
/// Iterate over Markdown document and extract all F# code snippets that we want
/// to colorize. We skip snippets that specify non-fsharp langauge e.g. [lang=csharp].
let rec collectCodeSnippets par = seq {
match par with
| CodeBlock(String.StartsWithWrapped ("[", "]") (ParseCommands cmds, String.TrimStart code))
when cmds.ContainsKey("lang") && cmds.["lang"] <> "fsharp" -> ()
| CodeBlock(String.StartsWithWrapped ("[", "]") (ParseCommands cmds, String.TrimStart code))
| CodeBlock(Let (dict []) (cmds, code)) ->
let modul =
match cmds.TryGetValue("module") with
| true, v -> Some v | _ -> None
yield modul, code
| Matching.ParagraphLeaf _ -> ()
| Matching.ParagraphNested(_, pars) ->
for ps in pars do
for p in ps do yield! collectCodeSnippets p
| Matching.ParagraphSpans(_, spans) -> () }
/// Replace CodeBlock elements with formatted HTML that was processed by the F# snippets tool
/// (The dictionary argument is a map from original code snippets to formatted HTML snippets.)
let rec replaceCodeSnippets outputKind (codeLookup:IDictionary<_, _>) = function
| CodeBlock(String.StartsWithWrapped ("[", "]") (ParseCommands cmds, String.TrimStart code))
when cmds.ContainsKey("hide") -> None
| CodeBlock(String.StartsWithWrapped ("[", "]") (ParseCommands cmds, String.TrimStart code))
| CodeBlock(Let (dict []) (cmds, code)) ->
if (cmds.ContainsKey("lang")) && cmds.["lang"] <> "fsharp" then
let content =
if outputKind = OutputKind.Html then
"<pre lang=\"" + cmds.["lang"] + "\">" + HttpUtility.HtmlEncode(code) + "</pre>"
else sprintf "\\begin{lstlisting}\n%s\n\\end{lstlisting}" <| HttpUtility.HtmlDecode(code)
HtmlBlock(content) |> Some
else
let content : string = codeLookup.[code]
HtmlBlock(content) |> Some
// Recursively process nested paragraphs, other nodes return without change
| Matching.ParagraphNested(pn, nested) ->
let pars = List.map (List.choose (replaceCodeSnippets outputKind codeLookup)) nested
Matching.ParagraphNested(pn, pars) |> Some
| other -> Some other
/// Try find first-level heading in the paragraph collection
let findHeadings paragraphs (outputKind:OutputKind) =
paragraphs |> Seq.tryPick (function
| (Heading(1, text)) ->
let doc = MarkdownDocument([Span(text)], dict [])
Some(outputKind.Format(doc))
| _ -> None)
(*[/omit]*)
(**
### CodeBlockUtils module
Parsing of F# Script files with Markdown commands. Given a parsed script file, we
split it into a sequence of comments, snippets and commands (comment starts with
`(**` and ending with `*)` are translated to Markdown, snippet is all other F# code
and command looks like `(*** key1:value, key2:value ***)` (and should be single line).
*)
module internal CodeBlockUtils =
(*[omit:(Implementation omitted)]*)
open CommandUtils
type Block =
| BlockComment of string
| BlockSnippet of Line list
| BlockCommand of IDictionary<string, string>
/// Trim blank lines from both ends of a lines list & reverse it (we accumulate
/// lines & we want to remove all blanks before returning BlockSnippet)
let private trimBlanksAndReverse lines =
lines
|> Seq.skipWhile (function Line[] -> true | _ -> false)
|> List.ofSeq |> List.rev
|> Seq.skipWhile (function Line[] -> true | _ -> false)
|> List.ofSeq
/// Succeeds when a line (list of tokens) contains only Comment
/// tokens and returns the text from the comment as a string
let private (|ConcatenatedComments|_|) (Line tokens) =
let comments =
tokens |> List.choose (function
| Token(TokenKind.Comment, text, _) -> Some text
| _ -> None)
if comments.Length <> tokens.Length then None
else Some (String.concat "" comments)
// Process lines of an F# script file. Simple state machine with two states
// * collectComment - we're parsing a comment and waiting for the end
// * collectSnippet - we're in a normal F# code and we're waiting for a comment
// (in both states, we also need to recognize (*** commands ***)
/// Waiting for the end of a comment
let rec private collectComment (comment:string) lines = seq {
match lines with
| (ConcatenatedComments(String.StartsAndEndsWith ("(***", "***)") (ParseCommands cmds)))::lines ->
// Ended with a command, yield comment, command & parse the next as a snippet
let cend = comment.LastIndexOf("*)")
yield BlockComment (comment.Substring(0, cend))
yield BlockCommand cmds
yield! collectSnippet [] lines
| (ConcatenatedComments text)::_ when
comment.LastIndexOf("*)") <> -1 && text.Trim().StartsWith("//") ->
// Comment ended, but we found a code snippet starting with // comment
let cend = comment.LastIndexOf("*)")
yield BlockComment (comment.Substring(0, cend))
yield! collectSnippet [] lines
| (Line[Token(TokenKind.Comment, String.StartsWith "(**" text, _)])::lines ->
// Another block of Markdown comment starting...
// Yield the previous snippet block and continue parsing more comments
let cend = comment.LastIndexOf("*)")
yield BlockComment (comment.Substring(0, cend))
if lines <> [] then yield! collectComment text lines
| (ConcatenatedComments text)::lines ->
// Continue parsing comment
yield! collectComment (comment + "\n" + text) lines
| lines ->
// Ended - yield comment & continue parsing snippet
let cend = comment.LastIndexOf("*)")
yield BlockComment (comment.Substring(0, cend))
if lines <> [] then yield! collectSnippet [] lines }
/// Collecting a block of F# snippet
and private collectSnippet acc lines = seq {
match lines with
| (ConcatenatedComments(String.StartsAndEndsWith ("(***", "***)") (ParseCommands cmds)))::lines ->
// Found a special command, yield snippet, command and parse another snippet
if acc <> [] then yield BlockSnippet (trimBlanksAndReverse acc)
yield BlockCommand cmds
yield! collectSnippet [] lines
| (Line[Token(TokenKind.Comment, String.StartsWith "(**" text, _)])::lines ->
// Found a comment - yield snippet & switch to parsing comment state
if acc <> [] then yield BlockSnippet (trimBlanksAndReverse acc)
yield! collectComment text lines
| x::xs -> yield! collectSnippet (x::acc) xs
| [] -> yield BlockSnippet (trimBlanksAndReverse acc) }
/// Parse F# script file into a sequence of snippets, comments and commands
let parseScriptFile = collectSnippet []
/// Given a parsed script file, extract "definitions". A definition is a part of
/// the file that we want to include elsewhere (and hide in the original location):
///
/// (*** define:key ***)
/// let foo = 1 + 2
///
/// This function returns 'string * Block' list containing all definitions
/// together with all a list of all remaining blocks that were not extracted.
let extractDefinitions defns =
let rec loop defns normal = function
| [] -> defns, normal |> List.rev
| BlockCommand(Command "hide" _)::(BlockSnippet _)::rest ->
loop defns normal rest
| BlockCommand(Command "define" key)::(BlockSnippet lines)::rest ->
// If we have command with 'define' in it, then pick the following
// snippet (it should be a snippet) and return it as a definition
loop ((key, lines)::defns) normal rest
| current::rest ->
loop defns (current::normal) rest
defns |> List.ofSeq |> loop [] []
(*[/omit]*)
(**
### SourceProcessors module
Functions that process `*.fsx` and `*.md` files. The function `processScriptFile`
assumes that the file is an F# script file (with text hidden in comments) while
`processMarkdown` assumes that all F# code is included as code snippets.
*)
module internal SourceProcessors =
/// Specifies a context that is passed to the
/// code/document processing functions
type ProcessingContext =
{ // An instance of the F# code formatting agent
FormatAgent : CodeFormatAgent
// Source code of a HTML template file
Template : string option
// Short prefix code added to all HTML 'id' elements
Prefix : string
// Should the processing add 'References' section?
GenerateReferences : bool
// Additional replacements to be made in the template file
Replacements : list<string * string>
// Generate line numbers for F# snippets?
GenerateLineNumbers : bool
// Include the source file in the generated output as '{source}'
IncludeSource : bool
// Command line options for the F# compiler
Options : string
// The output format
OutputKind : OutputKind
// Custom function for reporting errors
ErrorHandler : option<string * SourceError -> unit> }
(*[omit:(Implementation omitted)]*)
open CommandUtils
open CodeBlockUtils
open LiterateUtils
/// Print information about all errors during the processing
let private reportErrors ctx file (errors:seq<SourceError>) =
match ctx.ErrorHandler with
| Some eh -> for e in errors do eh(file, e)
| _ ->
for (SourceError((sl, sc), (el, ec), kind, msg)) in errors do
printfn " * (%d:%d)-(%d:%d) (%A): %s" sl sc el ec kind msg
if Seq.length errors > 0 then printfn ""
/// Given all links defined in the Markdown document and a list of all links
/// that are accessed somewhere from the document, generate References paragraph
let generateReferences (definedLinks:IDictionary<_, string * string option>) refs outputKind =
// For all unique references in the document,
// get the link & title from definitions
let refs =
refs |> set |> Seq.choose (fun ref ->
match definedLinks.TryGetValue(ref) with
| true, (link, Some title) -> Some (ref, link, title)
| _ -> None)
|> Seq.sort |> Seq.mapi (fun i v -> i+1, v)
// Generate dictionary with a number for all references
let refLookup = dict [ for (i, (r, _, _)) in refs -> r, i ]
// Generate Markdown blocks paragraphs representing Reference <li> items
let refList =
[ for i, (ref, link, title) in refs do
let colon = title.IndexOf(":")
if colon > 0 then
let auth = title.Substring(0, colon)
let name = title.Substring(colon + 1, title.Length - 1 - colon)
yield [Span [ Literal (sprintf "[%d] " i)
DirectLink([Literal name], (link, Some title))
Literal (" - " + auth)] ]
else
yield [Span [ Literal (sprintf "[%d] " i)
DirectLink([Literal title], (link, Some title))]] ]
// Return the document together with dictionary for looking up indices
let literal =
match outputKind with
| OutputKind.Html ->
// Return the document together with dictionary for looking up indices
let id = DateTime.Now.ToString("yyMMddhh")
Literal ("<a name=\"rf" + id + "\">&#160;</a>References")
| OutputKind.Latex ->
// Add formatting later
Literal ("References")
[ Heading(3, [literal])
ListBlock(MarkdownListKind.Unordered, refList) ], refLookup
/// Replace {parameter} in the input string with
/// values defined in the specified list
let replaceParameters parameters input =
match input with
| None ->
// If there is no template, return just document + tooltips
let lookup = parameters |> dict
lookup.["document"] + "\n\n" + lookup.["tooltips"]
| Some input ->
// First replace keys with some uglier keys and then replace them with values
// (in case one of the keys appears in some other value)
let id = System.Guid.NewGuid().ToString("d")
let input = parameters |> Seq.fold (fun (html:string) (key, value) ->
html.Replace("{" + key + "}", "{" + key + id + "}")) input
let result = parameters |> Seq.fold (fun (html:string) (key, value) ->
html.Replace("{" + key + id + "}", value)) input
result
/// Write formatted blocks to a specified string builder
/// and return first-level heading if there is some
let outputBlocks (sb:Text.StringBuilder)
// Original blocks of the input document
blocks
// Sequence with just formatted BlockSnippet elements
(snippets:seq<FormattedSnippet>)
// Sequence with just formatted BlockComment elements
(comments:seq<MarkdownDocument>)
(definitions:IDictionary<_, string>) refLookup outputKind =
// We traverse sequences using enumerators as we need them
let heading = ref None
use snippetsEn = snippets.GetEnumerator()
use commentsEn = comments.GetEnumerator()
let nextSnippet () = snippetsEn.MoveNext() |> ignore; snippetsEn.Current
let nextComment () = commentsEn.MoveNext() |> ignore; commentsEn.Current
for block in blocks do
match block with
// Skip known commands and comments ('hide' is removed in earlier step)
| BlockCommand (Command "include" key) -> sb.Append(definitions.[key]) |> ignore
| BlockCommand (Command "define" _) -> ()
| BlockCommand cmds when cmds.Count = 1 && cmds.Keys |> Seq.head |> Seq.forall ((=) '*') -> ()
| BlockCommand cmds ->
failwithf "Unsupported command: %s" (String.concat ", " [ for (KeyValue(k,v)) in cmds -> k + ":" + v ])
// Emit next comment, but search for headings
| BlockComment s ->
let mdoc = nextComment()
let paragraphs = mdoc.Paragraphs |> List.choose (replaceReferences refLookup)
findHeadings paragraphs outputKind |> Option.iter (fun v -> heading := Some v)
let doc = MarkdownDocument(paragraphs, mdoc.DefinedLinks)
sb.Append(outputKind.Format(doc)) |> ignore
// Emit next snippet (if it is not just empty list)
| BlockSnippet lines ->
let snip = nextSnippet()
if lines <> [] then sb.Append(snip.Content) |> ignore
!heading
// ------------------------------------------------------------------------------------
/// Process F# Script file
let processScriptFile ctx file output =
let name = Path.GetFileNameWithoutExtension(file)
// Parse the entire file as an F# script file,
// get sequence of blocks & extract definitions
let sourceSnippets, errors = ctx.FormatAgent.ParseSource(file, File.ReadAllText(file), ctx.Options)
reportErrors ctx file errors
let (Snippet(_, lines)) = match sourceSnippets with [| it |] -> it | _ -> failwith "multiple snippets"
let definitions, blocks = parseScriptFile lines |> extractDefinitions
// Process all definitions & build a dictionary with HTML for each definition
let snippets = [| for name, lines in definitions -> Snippet(name, lines) |]
let formattedDefns =
match ctx.OutputKind with
| OutputKind.Html -> CodeFormat.FormatHtml(snippets, ctx.Prefix + "d", ctx.GenerateLineNumbers, false)
| OutputKind.Latex -> CodeFormat.FormatLatex(snippets, ctx.GenerateLineNumbers)
let definitions = dict [ for snip in formattedDefns.Snippets -> snip.Title, snip.Content ]
// Process all snippet blocks in the script file (using F# formatter)
let snippets = blocks |> List.choose (function
| BlockSnippet(lines) -> Some(Snippet("Untitled", lines))
| _ -> None) |> Array.ofList
let formatted =
match ctx.OutputKind with
| OutputKind.Html -> CodeFormat.FormatHtml(snippets, ctx.Prefix, ctx.GenerateLineNumbers, false)
| OutputKind.Latex -> CodeFormat.FormatLatex(snippets, ctx.GenerateLineNumbers)
// Parse all comment blocks in the script file (as Markdown)
let parsedBlocks = blocks |> Array.ofSeq |> Seq.choose (function
| BlockComment(text) -> Some(Markdown.Parse(text))
| _ -> None)
// Turn all indirect links into a references & add paragraph to the document
let refParagraph, refLookup =
if ctx.GenerateReferences then
// Union link definitions & collect all indirect links
let definedLinks = parsedBlocks |> Seq.collect (fun mdoc ->
[ for (KeyValue(k, v)) in mdoc.DefinedLinks -> k, v]) |> dict
let refs = parsedBlocks |> Seq.collect (fun mdoc ->
Seq.collect collectReferences mdoc.Paragraphs)
let pars, refLookup = generateReferences definedLinks refs ctx.OutputKind
Some pars, refLookup
else None, dict []
// Write all HTML content to a string builder & add References
let sb = Text.StringBuilder()
let heading = outputBlocks sb blocks formatted.Snippets parsedBlocks definitions refLookup ctx.OutputKind
refParagraph |> Option.iter (fun p ->
let output = ctx.OutputKind.Format(MarkdownDocument(p, dict []))
sb.Append(output) |> ignore)
// If we want to include the source code of the script, then process
// the entire source and generate replacement {source} => ...some html...
let sourceReplacement, sourceTips =
match ctx.OutputKind with
| OutputKind.Html ->
if ctx.IncludeSource then
let formatted = CodeFormat.FormatHtml(sourceSnippets, ctx.Prefix + "s")
let content =
match formatted.Snippets with
| [| snip |] -> snip.Content
| snips -> [ for s in snips -> sprintf "<h3>%s</h3>\n%s" s.Title s.Content ] |> String.concat ""
[ "source", content ], formatted.ToolTip
else [], ""
| OutputKind.Latex ->
if ctx.IncludeSource then
let formatted = CodeFormat.FormatLatex(sourceSnippets)
let content =
match formatted.Snippets with
| [| snip |] -> snip.Content
| snips -> [ for s in snips -> sprintf "\subsubsection{%s}\n%s" s.Title s.Content ] |> String.concat ""
[ "source", content ], formatted.ToolTip
else [], ""
// Replace all parameters in the template & write to output
let parameters =
ctx.Replacements @ sourceReplacement @
[ "page-title", defaultArg heading name
ctx.OutputKind.ContentTag, sb.ToString()
"tooltips", formatted.ToolTip + formattedDefns.ToolTip + sourceTips ]
File.WriteAllText(output, replaceParameters parameters ctx.Template)
// ------------------------------------------------------------------------------------
/// Process Markdown document
let processMarkdown ctx file output =
// Read file & parse Markdown document
let name = Path.GetFileNameWithoutExtension(file)
let originalSource = File.ReadAllText(file)
let doc = Markdown.Parse(originalSource)
// Turn all indirect links into a references & add paragraph to the document
let refParagraph, refLookup =
if ctx.GenerateReferences then
// Union link definitions & collect all indirect links
let refs = Seq.collect collectReferences doc.Paragraphs
let pars, refLookup = generateReferences doc.DefinedLinks refs ctx.OutputKind
Some pars, refLookup
else None, dict []
// Extract all CodeBlocks and pass them to F# snippets
let codes = doc.Paragraphs |> Seq.collect collectCodeSnippets |> Array.ofSeq
let codeLookup, tipsHtml =
if codes.Length = 0 then dict [], ""
else
// If there are some F# snippets, we build an F# source file
let blocks = codes |> Seq.mapi (fun index (modul, code) ->
match modul with
| Some modul ->
// generate module & add indentation
"module " + modul + " =\n" +
"// [snippet:" + (string index) + "]\n" +
" " + code.Replace("\n", "\n ") + "\n" +
"// [/snippet]"
| None ->
"// [snippet:" + (string index) + "]\n" +
code + "\n" +
"// [/snippet]" )
// Process F# script file, report errors & build lookup table for replacement
let modul = "module " + (new String(name |> Seq.filter Char.IsLetter |> Seq.toArray))
let source = modul + "\r\n" + (String.concat "\n\n" blocks)
let snippets, errors = ctx.FormatAgent.ParseSource(output + ".fs", source, ctx.Options)
reportErrors ctx file errors
let formatted =
match ctx.OutputKind with
| OutputKind.Html -> CodeFormat.FormatHtml(snippets, ctx.Prefix, ctx.GenerateLineNumbers, false)
| OutputKind.Latex -> CodeFormat.FormatLatex(snippets, ctx.GenerateLineNumbers)
let snippetLookup =
[ for (_, code), fs in Array.zip codes formatted.Snippets -> code, fs.Content ]
dict snippetLookup, formatted.ToolTip
// Process all paragraphs in two steps (replace F# snippets & references)
let paragraphs =
doc.Paragraphs |> List.choose (fun par ->
par |> replaceCodeSnippets ctx.OutputKind codeLookup
|> Option.bind (replaceReferences refLookup))
// If we want to include the source code of the script, then process
// the entire source and generate replacement {source} => ...some html...
let sourceReplacements =
if ctx.IncludeSource then
let doc = MarkdownDocument([CodeBlock originalSource], dict [])
let content = ctx.OutputKind.Format(doc)
[ "source", content ]
else []
// Construct new Markdown document and write it
let parameters =
ctx.Replacements @ sourceReplacements @
[ "page-title", defaultArg (findHeadings paragraphs ctx.OutputKind) name
ctx.OutputKind.ContentTag, ctx.OutputKind.Format(MarkdownDocument(paragraphs, doc.DefinedLinks))
"tooltips", tipsHtml ]
File.WriteAllText(output, replaceParameters parameters ctx.Template)
(*[/omit]*)
(**
## Public API
The following type provides three simple methods for calling the literate programming tool.
The `ProcessMarkdown` and `ProcessScriptFile` methods process a single Markdown document
and F# script, respectively. The `ProcessDirectory` method handles an entire directory tree
(looking for `*.fsx` and `*.md` files).
*)
open SourceProcessors
type Literate =
(*[omit:(Helper methdods omitted)]*)
/// Provides default values for all optional parameters
static member private DefaultArguments
( input, templateFile, output,format, fsharpCompiler, prefix, compilerOptions,
lineNumbers, references, replacements, includeSource, errorHandler) =
let defaultArg v f = match v with Some v -> v | _ -> f()
let outputKind = defaultArg format (fun _ -> OutputKind.Html)
let output = defaultArg output (fun () ->
let dir = Path.GetDirectoryName(input)
let file = Path.GetFileNameWithoutExtension(input)
Path.Combine(dir, sprintf "%s.%O" file outputKind))
let fsharpCompiler = defaultArg fsharpCompiler (fun () ->
Assembly.Load("FSharp.Compiler"))
// Build & return processing context
let ctx =
{ FormatAgent = CodeFormat.CreateAgent(fsharpCompiler)
Template = templateFile |> Option.map (fun file -> File.ReadAllText(file))
Prefix = defaultArg prefix (fun () -> "fs")
Options = defaultArg compilerOptions (fun () -> "")
GenerateLineNumbers = defaultArg lineNumbers (fun () -> true)
GenerateReferences = defaultArg references (fun () -> false)
Replacements = defaultArg replacements (fun () -> [])
IncludeSource = defaultArg includeSource (fun () -> false)
OutputKind = outputKind
ErrorHandler = errorHandler }
output, ctx(*[/omit]*)
/// Process Markdown document
static member ProcessMarkdown
( input, ?templateFile, ?output, ?format, ?fsharpCompiler, ?prefix, ?compilerOptions,
?lineNumbers, ?references, ?replacements, ?includeSource, ?errorHandler ) = (*[omit:(...)]*)
let output, ctx =
Literate.DefaultArguments
( input, templateFile, output, format, fsharpCompiler, prefix, compilerOptions,
lineNumbers, references, replacements, includeSource, errorHandler )
processMarkdown ctx input output (*[/omit]*)
/// Process F# Script file
static member ProcessScriptFile
( input, ?templateFile, ?output, ?format, ?fsharpCompiler, ?prefix, ?compilerOptions,
?lineNumbers, ?references, ?replacements, ?includeSource, ?errorHandler ) = (*[omit:(...)]*)
let output, ctx =
Literate.DefaultArguments
( input, templateFile, output, format, fsharpCompiler, prefix, compilerOptions,
lineNumbers, references, replacements, includeSource, errorHandler )
processScriptFile ctx input output (*[/omit]*)
/// Process directory containing a mix of Markdown documents and F# Script files
static member ProcessDirectory
( inputDirectory, ?templateFile, ?outputDirectory, ?format, ?fsharpCompiler, ?prefix, ?compilerOptions,
?lineNumbers, ?references, ?replacements, ?includeSource, ?errorHandler ) = (*[omit:(...)]*)
let _, ctx =
Literate.DefaultArguments
( "", templateFile, Some "", format, fsharpCompiler, prefix, compilerOptions,
lineNumbers, references, replacements, includeSource, errorHandler )
/// Recursively process all files in the directory tree
let rec processDirectory indir outdir =
// Create output directory if it does not exist
if Directory.Exists(outdir) |> not then
try Directory.CreateDirectory(outdir) |> ignore
with _ -> failwithf "Cannot create directory '%s'" outdir
let fsx = [ for f in Directory.GetFiles(indir, "*.fsx") -> processScriptFile, f ]
let mds = [ for f in Directory.GetFiles(indir, "*.md") -> processMarkdown, f ]
for func, file in fsx @ mds do
let name = Path.GetFileNameWithoutExtension(file)
let output = Path.Combine(outdir, sprintf "%s.%O" name ctx.OutputKind)
// Update only when needed
let changeTime = File.GetLastWriteTime(file)
let generateTime = File.GetLastWriteTime(output)
if changeTime > generateTime then
printfn "Generating '%s.%O'" name ctx.OutputKind
func ctx file output
let outputDirectory = defaultArg outputDirectory inputDirectory
processDirectory inputDirectory outputDirectory (*[/omit]*)

35
packages/FSharp.Formatting.1.0.15/literate/templates/template-file.html

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<!--
The {page-title} parameters will be replaced with the
document title extracted from the <h1> element or
file name, if there is no <h1> heading
-->
<title>{page-title}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="http://code.jquery.com/jquery-1.8.0.js"></script>
<script src="http://code.jquery.com/ui/1.8.23/jquery-ui.js"></script>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/js/bootstrap.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/css/bootstrap-combined.min.css" rel="stylesheet">
<link type="text/css" rel="stylesheet" href="content/style.css" />
<script src="content/tips.js" type="text/javascript"></script>
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<div class="row" style="margin-top:30px">
<div class="span1"></div>
<div class="span10" id="main">
{document}
{tooltips}
</div>
<div class="span1"></div>
</div>
</div>
</body>
</html>

62
packages/FSharp.Formatting.1.0.15/literate/templates/template-project.html

@ -0,0 +1,62 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<!--
The {page-title} parameters will be replaced with the
document title extracted from the <h1> element or
file name, if there is no <h1> heading
-->
<title>{page-title}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{page-description}">
<meta name="author" content="{page-author}">
<script src="http://code.jquery.com/jquery-1.8.0.js"></script>
<script src="http://code.jquery.com/ui/1.8.23/jquery-ui.js"></script>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/js/bootstrap.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/css/bootstrap-combined.min.css" rel="stylesheet">
<link type="text/css" rel="stylesheet" href="content/style.css" />
<script src="content/tips.js" type="text/javascript"></script>
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<div class="masthead">
<ul class="nav nav-pills pull-right">
<li><a href="http://fsharp.org">fsharp.org</a></li>
<li><a href="{github-link}">github page</a></li>
</ul>
<h3 class="muted">{project-name}</h3>
</div>
<hr />
<div class="row">
<div class="span9" id="main">
{document}
{tooltips}
</div>
<div class="span3">
<ul class="nav nav-list" id="menu">
<li class="nav-header">{project-name}</li>
<li><a href="../index.html">Home page</a></li>
<!--
Here you can add links to other pages of the documentation
The 'divider' element creates a separator and additional
'nav-header' can be used to add sub-headings in the menu:
* <li class="divider"></li>
* <li><a href="...">...</a></li>
* <li class="nav-header">Sub-heading</li>
-->
</ul>
</div>
</div>
</div>
<a href="{github-link}"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_orange_ff7600.png" alt="Fork me on GitHub"></a>
</body>
</html>

1
packages/repositories.config

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<repositories>
<repository path="..\src\FSharpExamples\packages.config" />
<repository path="..\src\FSharpUnitTests\packages.config" />
<repository path="..\src\UnitTests\packages.config" />
</repositories>

12
src/FSharp/Distributions.fs

@ -35,13 +35,13 @@ open MathNet.Numerics.Random
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Sample =
let transform f dist : System.Random -> 'T = fun rng -> f (dist rng)
let transform2 f dist1 dist2 : System.Random -> 'T = fun rng -> f (dist1 rng) (dist2 rng)
let transform3 f dist1 dist2 dist3 : System.Random -> 'T = fun rng -> f (dist1 rng) (dist2 rng) (dist3 rng)
let map f dist : System.Random -> 'T = fun rng -> f (dist rng)
let map2 f dist1 dist2 : System.Random -> 'T = fun rng -> f (dist1 rng) (dist2 rng)
let map3 f dist1 dist2 dist3 : System.Random -> 'T = fun rng -> f (dist1 rng) (dist2 rng) (dist3 rng)
let transformSeq f dist : System.Random -> 'T seq = fun rng -> dist rng |> Seq.map f
let transformSeq2 f dist1 dist2 : System.Random -> 'T seq = fun rng -> Seq.zip (dist1 rng) (dist2 rng) |> Seq.map (fun (d1, d2) -> f d1 d2)
let transformSeq3 f dist1 dist2 dist3 : System.Random -> 'T seq = fun rng -> Seq.zip3 (dist1 rng) (dist2 rng) (dist3 rng) |> Seq.map (fun (d1, d2, d3) -> f d1 d2 d3)
let mapSeq f dist : System.Random -> 'T seq = fun rng -> dist rng |> Seq.map f
let mapSeq2 f dist1 dist2 : System.Random -> 'T seq = fun rng -> Seq.zip (dist1 rng) (dist2 rng) |> Seq.map (fun (d1, d2) -> f d1 d2)
let mapSeq3 f dist1 dist2 dist3 : System.Random -> 'T seq = fun rng -> Seq.zip3 (dist1 rng) (dist2 rng) (dist3 rng) |> Seq.map (fun (d1, d2, d3) -> f d1 d2 d3)
/// Bernoulli with probability (p).
let bernoulli p rng = Bernoulli.Sample(rng, p)

13
src/FSharpExamples/FSharpExamples.fsproj

@ -52,9 +52,22 @@
<None Include="Matrices.fsx" />
<None Include="LinearRegression.fsx" />
<None Include="Apply.fsx" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Reference Include="FSharp.CodeFormat">
<HintPath>..\..\packages\FSharp.Formatting.1.0.15\lib\net40\FSharp.CodeFormat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="FSharp.CompilerBinding">
<HintPath>..\..\packages\FSharp.Formatting.1.0.15\lib\net40\FSharp.CompilerBinding.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="FSharp.Core" />
<Reference Include="FSharp.Markdown">
<HintPath>..\..\packages\FSharp.Formatting.1.0.15\lib\net40\FSharp.Markdown.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Core">

6
src/FSharpExamples/Matrices.fsx

@ -41,12 +41,12 @@ let a1 = DenseMatrix(2, 3, [| 1.0; 2.0; 10.0; 20.0; 100.0; 300.0 |])
let a2 = DenseMatrix.raw 2 3 [| 1.0; 2.0; 10.0; 20.0; 100.0; 300.0 |]
// Create a matrix of size 3x4 (3 rows, 4 columns) with a given number for each value
let b1 = DenseMatrix.zeroCreate 3 4
let b1 : float Matrix = DenseMatrix.zero 3 4
let b2 = DenseMatrix.create 3 4 20.5
let b3 = SparseMatrix.zeroCreate 3 4
let b3 : float Matrix = SparseMatrix.zero 3 4
// Create a matrix of size 3x4 with random values sampled from a distribution
let c = DenseMatrix.randomCreate 3 4 (Normal.WithMeanStdDev(2.0, 0.5))
let c : float Matrix = DenseMatrix.random 3 4 (Normal.WithMeanStdDev(2.0, 0.5))
// Create a matrix of size 3x4 with each value initialized by a lambda function
let d1 = DenseMatrix.init 3 4 (fun i j -> float i / 100.0 + float j)

269
src/FSharpExamples/RandomAndDistributions.fsx

@ -1,30 +1,34 @@
(**
Random Numbers and Probability Distributions
============================================
Math.NET Numerics: Random Numbers and Probability Distributions
===============================================================
The .Net base class library provides a pseudo-random number generator
for non-cryptography use in the form of the `System.Numerics` class.
The .Net Framework base class library includes a pseudo-random number generator
for non-cryptography use in the form of the `System.Random` class.
Math.NET Numerics provides a few alternatives with different characteristics
in randomness, bias, sequence length and performance. All these classes
inherit from System.Random so you can use them as a replacement for
System.Random even in third-party code.
inherit from `System.Random` so you can use them as a drop-in replacement
even in third-party code.
All random number generators (RNG) generate numbers in a more-or-less uniform
distribution. In practice you often need to sample random numbers with a different
distribution, like a Gaussian or Poisson. You can do that with one of our probability
distribution classes, or in F# also using the `Sample` module. Once parametrized,
the distribution classes also provide a variety of other functionality around probability
distributions, like evaluating statistical distribution properties or functions.
All random number generators generate numbers in a more-or-less uniform
distribution. Often you need to sample random numbers with a different
distribution, e.g. a Gaussian. You can do that with one of the distribution
classes, or in F# also using the `Sample` module. The distribution classes
also provide a lot of other functionality around probability distributions,
like parameter estimation or evaluating the commulative distribution function.
Initialization
--------------
Initializtation
---------------
We need to reference Math.NET Numerics and open the namespaces for
random numbers and probability distributions:
We need to reference Math.NET Numerics and the F# modules, and open
the namespaces for random numbers and probability distributions:
using MathNet.Numerics.Random;
using MathNet.Numerics.Distributions;
Or in F#:
*)
// Only needed in scripts/interactive
#r "../../out/lib/Net40/MathNet.Numerics.dll"
#r "../../out/lib/Net40/MathNet.Numerics.FSharp.dll"
@ -32,47 +36,85 @@ open MathNet.Numerics.Random
open MathNet.Numerics.Distributions
(**
Random Number Generators
------------------------
Let's sample a few uniform random values using Mersenne Twister in C#:
var rng = new MersenneTwister(42);
int randomInt = rng.Next();
double randomDouble = rng.NextDouble();
In F# you can use the constructor as well, or alternatively use the `Random` module.
In case of the latter, all objects will be cast to their common base type `System.Random`:
*)
let rng = MersenneTwister(42)
let rngEx = Random.mersenneTwisterSeed 42
let randomInt = rng.Next()
(**
If you have used `System.Random` before, you may remember that it only offers `Next` methods
to sample integers, and `NextDouble` for floating point numbers in the [0,1) interval.
Did you ever have a need to generate numbers of the full integer range including negative numbers,
or a `System.Decimal`? Extending discrete random numbers to different ranges or types is non-trivial
if the distribution should still be uniform over the chosen range. That's why we've added a few extensions
methods which are available on all RNGs (including `System.Random` itself):
*)
let values =
( rng.Next(), // built-in: int32 in the range [0, Int.MaxValue)
rng.NextInt64(), // int64 in the range [0, Long.MaxValue)
rng.NextFullRangeInt32(), // int32 in the range [Int.MinValue, Int.MaxValue]
rng.NextFullRangeInt64(), // int64 in the range [Long.MinValue, Long.MaxValue]
rng.NextDouble(), // built-in: double in the range [0.0, 1.0)
rng.NextDecimal() ) // decimal in then range [0.0, 1.0)
(**
The following custom RNGs are currently available in Math.NET Numerics:
* `MersenneTwister`: Mersenne Twister 19937 generator
* `Xorshift`: Multiply-with-carry XOR-shift generator
* `Mcg31m1`: Multiplicative congruental generator using a modulus of 2^31-1 and a multiplier of 1132489760
* `Mcg59`: Multiplicative congruental generator using a modulus of 2^59 and a multiplier of 13^13
* `WH1982`: Wichmann-Hill's 1982 combined multiplicative congruental generator
* `WH2006`: Wichmann-Hill's 2006 combined multiplicative congruental generator
* `Mrg32k3a`: 32-bit combined multiple recursive generator with 2 components of order 3
* `Palf`: Parallel Additive Lagged Fibonacci generator
* `SystemCryptoRandomNumberGenerator`: Using the RNGCryptoServiceProvider of the .Net Framework. *Not available in portable builds.*
Seeds and Thread Safety
-----------------------
Other than for cryptographic random numbers where you'd never want to provide
a seed, all pseudo-random numbers can be initialized with a custom seed.
The same seed causes the same number sequence to be generated, which can be
very useful if you need results to be reproducible, e.g. in testing/verification.
a seed, all other RNGs can be initialized with a custom seed. In the code sample
above we've used `42` as seed. The same seed causes the same number sequence
to be generated, which can be very useful if you need results to be reproducible,
e.g. in testing/verification.
If no seed is provided, System.Random uses a time based seed equivalent to the
If no seed is provided, `System.Random` uses a time based seed equivalent to the
one below. This means that all instances created within a short timeframe
(which typically spans around a thousand CPU clock cycles) will generate
(which typically spans about a thousand CPU clock cycles) will generate
exactly the same sequence. This can happen easily e.g. in parallel computing
and is often unwanted. That's why all number generators created using
Math.NET Numerics routines are by default initialized with a seed that combines
the time with a Guid (which are supposed to be generated uniquely, worldwide).
*)
let someTimeSeed = RandomSeed.Time()
let someGuidSeed = RandomSeed.Guid()
(**
Random number generators can be created using the `Random` module. Most functions
optionally accept a manual seed when using the variant with the Seed-suffix.
Some of them, like xor-shift, also have a variant with a Custom-suffix that
allow to pass additional parameters specific to that generator.
Note that the generators should be reused when generating multiple numbers.
If you'd create a new generator each time, the numbers it generates would be
exactly as random as your seed - and thus not very random at all.
However, generators are not automatically thread-safe. They *are* thread-safe
in Math.NET Numerics by default, but that can be disabled either using a
boolean argument at creation, or by setting `Control.ThreadSafeRandomNumberGenerators`.
However, generators are not automatically thread-safe in .Net. They *are* thread-safe
when created using Math.NET Numerics by default, but that can be controlled either by a
boolean argument at creation or by setting `Control.ThreadSafeRandomNumberGenerators`.
*)
let a = Random.system ()
let b = Random.systemSeed (RandomSeed.Time())
let b2 = Random.systemSeed someGuidSeed
let b = Random.systemSeed (RandomSeed.Guid())
let c = Random.crypto ()
let d = Random.mersenneTwister ()
let e = Random.mersenneTwisterWith 1000 true (* thread-safe *)
@ -81,28 +123,24 @@ let g = Random.xorshiftCustom someTimeSeed false 916905990L 13579L 362436069L 77
let h = Random.wh2006 ()
let i = Random.palf ()
// Generate some uniform random values
let values = (
a.Next(),
b.NextFullRangeInt32(),
c.NextFullRangeInt64(),
d.NextInt64(),
e.NextDouble(),
f.NextDecimal()
)
(**
Probability Distributions
-------------------------
Non-uniform probability distributions can be created using their normal constructor,
some also offer static functions if there are multiple ways to parametrize them.
For non-uniform random number generation you can use one the wide range of probability
distributions in the `MathNet.Numerics.Distributions` namespace.
There are many ways to parametrize a distribution in the literature. When using the
default constructor, read carefully which parameters it requires. For distributions where
multiple ways are common there are also static methods, so you can use the one that fits best.
For example, a normal distribution is usually parametrized with mean and standard deviation,
but if you'd rather use mean and precision:
var normal = Normal.WithMeanPrecision(0.0, 0.5);
Since probability distributions can also be sampled to generate random numbers
with the configured distribution, all constructors optionally accept a random generator
as last argument.
as last argument. A few more examples, this time in F#:
*)
// some probability distributions
@ -114,17 +152,15 @@ let poisson = Poisson(3.0)
let geometric = Geometric(0.8, Random.system())
// sample some random rumbers from these distributions
let continuous = [
yield normal.Sample()
yield exponential.Sample()
yield! gamma.Samples() |> Seq.take 10
]
let discrete = [
poisson.Sample()
poisson.Sample()
geometric.Sample()
]
let continuous =
[ yield normal.Sample()
yield exponential.Sample()
yield! gamma.Samples() |> Seq.take 10 ]
let discrete =
[ poisson.Sample()
poisson.Sample()
geometric.Sample() ]
// direct sampling (without creating a distribution object)
let u = Normal.Sample(Random.system(), 2.0, 4.0)
@ -133,78 +169,85 @@ let w = Rayleigh.Sample(c, 1.5)
let x = Hypergeometric.Sample(h, 100, 20, 5)
(**
Specifically for F# there is also a `Sample` module that allow a somewhat
more functional view on the distributions by allowing them to be curried such that
the random source is passed in as last arguments. This way distributions can
be combined and transformed arbitrarily:
Distribution Functions and Properties
-------------------------------------
Distributions can not just be used to generate non-uniform random samples.
Once parametrized they can compute a variety of distribution properties
or evaluate distribution functions. Because it is often numerically more stable
and faster to compute and work with such quantities in the logarithmic domain,
some of them are also available with the `Ln`-suffix.
*)
/// Transform a sample distribution
let s1 rng = tanh (Sample.normal 2.0 0.5 rng)
/// Alternative way where we transform the function instead of its result
let s1alt rng = Sample.transform tanh (Sample.normal 2.0 0.5) rng
// distribution properties of the gamma we've configured above
let gammaStats =
( gamma.Mean,
gamma.Variance,
gamma.StdDev,
gamma.Entropy,
gamma.Skewness,
gamma.Mode )
// probability distribution functions of the normal we've configured above.
let nd = normal.Density(4.0) (* pdf *)
let ndLn = normal.DensityLn(4.0) (* ln(pdf) *)
let nc = normal.CumulativeDistribution(4.0) (* cdf *)
let nic = normal.InverseCumulativeDistribution(0.7) (* invcdf *)
/// Alternative way that works exactly the same but operates on functions generating sequences
let s1seq rng = Sample.transformSeq tanh (Sample.normalSeq 2.0 0.5) rng
// Distribution functions can also be evaluated without creating an object,
// but then you have to pass in the distribution parameters as first arguments:
let nd2 = Normal.PDF(3.0, sqrt 1.5, 4.0)
let ndLn2 = Normal.PDFLn(3.0, sqrt 1.5, 4.0)
let nc2 = Normal.CDF(3.0, sqrt 1.5, 4.0)
let nic2 = Normal.InvCDF(3.0, sqrt 1.5, 0.7)
/// The same with multiple distributions:
let s2 rng = (Sample.normal 2.0 1.5 rng) * (Sample.cauchy 2.0 0.5 rng)
let s2alt rng = Sample.transform2 (*) (Sample.normal 2.0 1.5) (Sample.cauchy 2.0 0.5) rng
let s2seq rng = Sample.transformSeq2 (*) (Sample.normalSeq 2.0 1.5) (Sample.cauchySeq 2.0 0.5) rng
(**
Some of the distributions also have routines for maximum-likelihood parameter
estimation from a set of samples:
*)
Seq.take 10 (s2seq (Random.system())) |> Seq.toArray
let estimation = LogNormal.Estimate([| 2.0; 1.5; 2.1; 1.2; 3.0; 2.4; 1.8 |])
let mean, variance = estimation.Mean, estimation.Variance
let moreSamples = estimation.Samples() |> Seq.take 10 |> Seq.toArray
(**
or in C#:
Let's do some random walks, using distributions and random sources defined above:
LogNormal estimation = LogNormal.Estimate(new [] {2.0, 1.5, 2.1, 1.2, 3.0, 2.4, 1.8});
double mean = estimation.Mean, variance = estimation.Variance;
double[] moreSamples = estimation.Samples().Take(10).ToArray();
Let's do some random walks, using distributions and random sources defined above (TODO: Graph):
*)
Seq.scan (+) 0.0 (normal.Samples()) |> Seq.take 10 |> Seq.toArray
Seq.scan (+) 0.0 (Sample.normalSeq 0.0 0.5 a) |> Seq.take 10 |> Seq.toArray
Seq.scan (+) 0.0 (s1seq a) |> Seq.take 10 |> Seq.toArray
(**
Composing Distributions
-----------------------
Distributions can not just be used to generate random samples.
You can use them to evaluate distribution properties or functions
with the given parametrization.
Specifically for F# there is also a `Sample` module that allows a somewhat more functional
view on distribution sampling functions by having the random source passed in as last argument.
This way they can be composed and transformed arbitrarily if curried:
*)
// distribution properties of the gamma dist we configured above
let gammaStats = (
gamma.Mean,
gamma.Variance,
gamma.StdDev,
gamma.Entropy,
gamma.Skewness,
gamma.Mode
)
// probability distribution functions of the normal dist we configured above
let nd = normal.Density(4.0) (* pdf *)
let ndLn = normal.DensityLn(4.0) (* ln(pdf) *)
let nc = normal.CumulativeDistribution(4.0) (* cdf *)
let nic = normal.InverseCumulativeDistribution(0.7) (* invcdf *)
/// Transform a sample from a distribution
let s1 rng = tanh (Sample.normal 2.0 0.5 rng)
// Distribution functions can also be evaluated without creating an object,
// but then you have to pass in the distribution parameters as first arguments:
let nd2 = Normal.PDF(3.0, sqrt 1.5, 4.0)
let ndLn2 = Normal.PDFLn(3.0, sqrt 1.5, 4.0)
let nc2 = Normal.CDF(3.0, sqrt 1.5, 4.0)
let nic2 = Normal.InvCDF(3.0, sqrt 1.5, 0.7)
/// But we really want to transform the function, not the resulting sample:
let s1f rng = Sample.map tanh (Sample.normal 2.0 0.5) rng
(**
/// Exactly the same also works with functions generating full sequences
let s1s rng = Sample.mapSeq tanh (Sample.normalSeq 2.0 0.5) rng
Some of the distributions also have routines for maximum-likelihood parameter
estimation from a set of samples:
/// Now with multiple distributions, e.g. their product:
let s2 rng = (Sample.normal 2.0 1.5 rng) * (Sample.cauchy 2.0 0.5 rng)
let s2f rng = Sample.map2 (*) (Sample.normal 2.0 1.5) (Sample.cauchy 2.0 0.5) rng
let s2s rng = Sample.mapSeq2 (*) (Sample.normalSeq 2.0 1.5) (Sample.cauchySeq 2.0 0.5) rng
*)
// Taking some samples from the composed function
Seq.take 10 (s2s (Random.system())) |> Seq.toArray
let estimation = LogNormal.Estimate([| 2.0; 1.5; 2.1; 1.2; 3.0; 2.4; 1.8 |])
let mean, variance = estimation.Mean, estimation.Variance
let moreSamples = estimation.Samples() |> Seq.take 10 |> Seq.toArray
// The random walk from above, but this time using the composition from above
Seq.scan (+) 0.0 (s1s a) |> Seq.take 10 |> Seq.toArray

6
src/FSharpExamples/Vectors.fsx

@ -40,12 +40,12 @@ let a1 = DenseVector [| 1.0; 2.0; 3.0 |]
let a2 = DenseVector.raw [| 1.0; 2.0; 3.0 |]
// Create a vector of length 100 with a given number for each value
let b1 = DenseVector.zeroCreate 100
let b1 : float Vector = DenseVector.zero 100
let b2 = DenseVector.create 100 20.5
let b3 = SparseVector.zeroCreate 100
let b3 : float Vector = SparseVector.zero 100
// Create a vector of length 100 with random values sampled from a distribution
let c = DenseVector.randomCreate 100 (Normal.WithMeanStdDev(2.0, 0.5))
let c : float Vector = DenseVector.random 100 (Normal.WithMeanStdDev(2.0, 0.5))
// Create a vector of length 100 with each value initialized by a lambda function
let d1 = DenseVector.init 100 (fun i -> float i / 100.0)

4
src/FSharpExamples/packages.config

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="FSharp.Formatting" version="1.0.15" targetFramework="net40" />
</packages>
Loading…
Cancel
Save