Merge pull request #3 from vassilyl/master

Serialization
This commit is contained in:
Vassily Lyutsarev 2016-04-20 09:32:11 +01:00
Родитель 5c56500909 10ccd28f5f
Коммит 4fea42533b
20 изменённых файлов: 582 добавлений и 635 удалений

Просмотреть файл

@ -1,9 +0,0 @@
language: csharp
sudo: false # use the new container-based Travis infrastructure
before_install:
- chmod +x build.sh
script:
- ./build.sh All

Просмотреть файл

@ -1,10 +1,8 @@
[![Issue Stats](http://issuestats.com/github/microsoft/Angara.Statistics/badge/issue)](http://issuestats.com/github/microsoft/Angara.Statistics)
[![Issue Stats](http://issuestats.com/github/microsoft/Angara.Statistics/badge/pr)](http://issuestats.com/github/microsoft/Angara.Statistics)
# Angara.Statistics
Angara.Statistics
======================
=================
A collection of essential algorithms for Bayesian data constrained modelling.
Includes Mersenne twister random number generator, common probability distributions,

Просмотреть файл

@ -1,3 +1,7 @@
### 0.1.4
* Sampler state can be serialized to continue unfinished computation.
### 0.1.3 - 2016-04-12
* Change layout of the repository to match [ProjectScaffold](http://fsprojects.github.io/ProjectScaffold/) recommendation.

Просмотреть файл

@ -1,9 +0,0 @@
init:
- git config --global core.autocrlf input
build_script:
- cmd: build.cmd
test: off
version: 0.1.3.{build}
artifacts:
- path: bin
name: bin

Просмотреть файл

@ -1,18 +0,0 @@
@echo off
cls
.paket\paket.bootstrapper.exe
if errorlevel 1 (
exit /b %errorlevel%
)
.paket\paket.exe restore
if errorlevel 1 (
exit /b %errorlevel%
)
IF NOT EXIST build.fsx (
.paket\paket.exe update
packages\build\FAKE\tools\FAKE.exe init.fsx
)
packages\build\FAKE\tools\FAKE.exe build.fsx %*

410
build.fsx
Просмотреть файл

@ -1,410 +0,0 @@
// --------------------------------------------------------------------------------------
// FAKE build script
// --------------------------------------------------------------------------------------
#r @"packages/build/FAKE/tools/FakeLib.dll"
open Fake
open Fake.Git
open Fake.AssemblyInfoFile
open Fake.ReleaseNotesHelper
open Fake.UserInputHelper
open System
open System.IO
#if MONO
#else
#load "packages/build/SourceLink.Fake/tools/Fake.fsx"
open SourceLink
#endif
// --------------------------------------------------------------------------------------
// START TODO: Provide project-specific details below
// --------------------------------------------------------------------------------------
// Information about the project are used
// - for version and project name in generated AssemblyInfo file
// - by the generated NuGet package
// - to run tests and to publish documentation on GitHub gh-pages
// - for documentation, you also need to edit info in "docs/tools/generate.fsx"
// The name of the project
// (used by attributes in AssemblyInfo, name of a NuGet package and directory in 'src')
let project = "Angara.Statistics"
// Short summary of the project
// (used as description in AssemblyInfo and as a short summary for NuGet package)
let summary = "A collection of statistics algorithms from Mersenne twister generator to MCMC sampling."
// Longer description of the project
// (used as a description for NuGet package; line breaks are automatically cleaned up)
let description = "Includes Mersenne twister random number generator, common probability distributions, statistics and quantiles, kernel density estimator, Metropolis-Hastings MCMC sampler."
// List of author names (for NuGet package)
let authors = [ "Vassily Lyutsarev" ]
// Tags for your project (for NuGet package)
let tags = "statistics probability fsharp"
// File system information
let solutionFile = "Angara.Statistics.sln"
// Pattern specifying assemblies to be tested using NUnit
let testAssemblies = "tests/**/bin/Release/*Tests*.dll"
// Git configuration (used for publishing documentation in gh-pages branch)
// The profile where the project is posted
let gitOwner = "microsoft"
let gitHome = "https://github.com/" + gitOwner
// The name of the project on GitHub
let gitName = "Angara.Statistics"
// The url for the raw files hosted
let gitRaw = environVarOrDefault "gitRaw" "https://raw.github.com/microsoft"
// --------------------------------------------------------------------------------------
// END TODO: The rest of the file includes standard build steps
// --------------------------------------------------------------------------------------
// Read additional information from the release notes document
let release = LoadReleaseNotes "RELEASE_NOTES.md"
// Helper active pattern for project types
let (|Fsproj|Csproj|Vbproj|Shproj|) (projFileName:string) =
match projFileName with
| f when f.EndsWith("fsproj") -> Fsproj
| f when f.EndsWith("csproj") -> Csproj
| f when f.EndsWith("vbproj") -> Vbproj
| f when f.EndsWith("shproj") -> Shproj
| _ -> failwith (sprintf "Project file %s not supported. Unknown project type." projFileName)
// Generate assembly info files with the right version & up-to-date information
Target "AssemblyInfo" (fun _ ->
let getAssemblyInfoAttributes projectName =
[ Attribute.Title (projectName)
Attribute.Product project
Attribute.Description summary
Attribute.Version release.AssemblyVersion
Attribute.FileVersion release.AssemblyVersion ]
let getProjectDetails projectPath =
let projectName = System.IO.Path.GetFileNameWithoutExtension(projectPath)
( projectPath,
projectName,
System.IO.Path.GetDirectoryName(projectPath),
(getAssemblyInfoAttributes projectName)
)
!! "src/**/*.??proj"
|> Seq.map getProjectDetails
|> Seq.iter (fun (projFileName, projectName, folderName, attributes) ->
match projFileName with
| Fsproj -> CreateFSharpAssemblyInfo (folderName </> "AssemblyInfo.fs") attributes
| Csproj -> CreateCSharpAssemblyInfo ((folderName </> "Properties") </> "AssemblyInfo.cs") attributes
| Vbproj -> CreateVisualBasicAssemblyInfo ((folderName </> "My Project") </> "AssemblyInfo.vb") attributes
| Shproj -> ()
)
)
// Copies binaries from default VS location to expected bin folder
// But keeps a subdirectory structure for each project in the
// src folder to support multiple project outputs
Target "CopyBinaries" (fun _ ->
!! "src/**/*.??proj"
-- "src/**/*.shproj"
|> Seq.map (fun f -> ((System.IO.Path.GetDirectoryName f) </> "bin/Release", "bin" </> (System.IO.Path.GetFileNameWithoutExtension f)))
|> Seq.iter (fun (fromDir, toDir) -> CopyDir toDir fromDir (fun _ -> true))
)
// --------------------------------------------------------------------------------------
// Clean build results
Target "Clean" (fun _ ->
CleanDirs ["bin"; "temp"]
)
Target "CleanDocs" (fun _ ->
CleanDirs ["docs/output"]
)
// --------------------------------------------------------------------------------------
// Build library & test project
Target "Build" (fun _ ->
!! solutionFile
#if MONO
|> MSBuildReleaseExt "" [ ("DefineConstants","MONO") ] "Rebuild"
#else
|> MSBuildRelease "" "Rebuild"
#endif
|> ignore
)
// --------------------------------------------------------------------------------------
// Run the unit tests using test runner
Target "RunTests" (fun _ ->
!! testAssemblies
|> NUnit (fun p ->
{ p with
DisableShadowCopy = true
TimeOut = TimeSpan.FromMinutes 20.
OutputFile = "TestResults.xml" })
)
#if MONO
#else
// --------------------------------------------------------------------------------------
// SourceLink allows Source Indexing on the PDB generated by the compiler, this allows
// the ability to step through the source code of external libraries http://ctaggart.github.io/SourceLink/
Target "SourceLink" (fun _ ->
let baseUrl = sprintf "%s/%s/{0}/%%var2%%" gitRaw project
!! "src/**/*.??proj"
-- "src/**/*.shproj"
|> Seq.iter (fun projFile ->
let proj = VsProj.LoadRelease projFile
SourceLink.Index proj.CompilesNotLinked proj.OutputFilePdb __SOURCE_DIRECTORY__ baseUrl
)
)
#endif
// --------------------------------------------------------------------------------------
// Build a NuGet package
Target "NuGet" (fun _ ->
Paket.Pack(fun p ->
{ p with
OutputPath = "bin"
Version = release.NugetVersion
ReleaseNotes = toLines release.Notes})
)
Target "PublishNuget" (fun _ ->
Paket.Push(fun p ->
{ p with
WorkingDir = "bin" })
)
// --------------------------------------------------------------------------------------
// Generate the documentation
let fakePath = "packages" </> "build" </> "FAKE" </> "tools" </> "FAKE.exe"
let fakeStartInfo script workingDirectory args fsiargs environmentVars =
(fun (info: System.Diagnostics.ProcessStartInfo) ->
info.FileName <- System.IO.Path.GetFullPath fakePath
info.Arguments <- sprintf "%s --fsiargs -d:FAKE %s \"%s\"" args fsiargs script
info.WorkingDirectory <- workingDirectory
let setVar k v =
info.EnvironmentVariables.[k] <- v
for (k, v) in environmentVars do
setVar k v
setVar "MSBuild" msBuildExe
setVar "GIT" Git.CommandHelper.gitPath
setVar "FSI" fsiPath)
/// Run the given buildscript with FAKE.exe
let executeFAKEWithOutput workingDirectory script fsiargs envArgs =
let exitCode =
ExecProcessWithLambdas
(fakeStartInfo script workingDirectory "" fsiargs envArgs)
TimeSpan.MaxValue false ignore ignore
System.Threading.Thread.Sleep 1000
exitCode
// Documentation
let buildDocumentationTarget fsiargs target =
trace (sprintf "Building documentation (%s), this could take some time, please wait..." target)
let exit = executeFAKEWithOutput "docs/tools" "generate.fsx" fsiargs ["target", target]
if exit <> 0 then
failwith "generating reference documentation failed"
()
Target "GenerateReferenceDocs" (fun _ ->
buildDocumentationTarget "-d:RELEASE -d:REFERENCE" "Default"
)
let generateHelp' fail debug =
let args =
if debug then "--define:HELP"
else "--define:RELEASE --define:HELP"
try
buildDocumentationTarget args "Default"
traceImportant "Help generated"
with
| e when not fail ->
traceImportant "generating help documentation failed"
let generateHelp fail =
generateHelp' fail false
Target "GenerateHelp" (fun _ ->
DeleteFile "docs/content/release-notes.md"
CopyFile "docs/content/" "RELEASE_NOTES.md"
Rename "docs/content/release-notes.md" "docs/content/RELEASE_NOTES.md"
DeleteFile "docs/content/license.md"
CopyFile "docs/content/" "LICENSE.txt"
Rename "docs/content/license.md" "docs/content/LICENSE.txt"
generateHelp true
)
Target "GenerateHelpDebug" (fun _ ->
DeleteFile "docs/content/release-notes.md"
CopyFile "docs/content/" "RELEASE_NOTES.md"
Rename "docs/content/release-notes.md" "docs/content/RELEASE_NOTES.md"
DeleteFile "docs/content/license.md"
CopyFile "docs/content/" "LICENSE.txt"
Rename "docs/content/license.md" "docs/content/LICENSE.txt"
generateHelp' true true
)
Target "KeepRunning" (fun _ ->
use watcher = !! "docs/content/**/*.*" |> WatchChanges (fun changes ->
generateHelp' true true
)
traceImportant "Waiting for help edits. Press any key to stop."
System.Console.ReadKey() |> ignore
watcher.Dispose()
)
Target "GenerateDocs" DoNothing
let createIndexFsx lang =
let content = """(*** hide ***)
// This block of code is omitted in the generated HTML documentation. Use
// it to define helpers that you do not want to show in the documentation.
#I "../../../bin"
(**
F# Project Scaffold ({0})
=========================
*)
"""
let targetDir = "docs/content" </> lang
let targetFile = targetDir </> "index.fsx"
ensureDirectory targetDir
System.IO.File.WriteAllText(targetFile, System.String.Format(content, lang))
Target "AddLangDocs" (fun _ ->
let args = System.Environment.GetCommandLineArgs()
if args.Length < 4 then
failwith "Language not specified."
args.[3..]
|> Seq.iter (fun lang ->
if lang.Length <> 2 && lang.Length <> 3 then
failwithf "Language must be 2 or 3 characters (ex. 'de', 'fr', 'ja', 'gsw', etc.): %s" lang
let templateFileName = "template.cshtml"
let templateDir = "docs/tools/templates"
let langTemplateDir = templateDir </> lang
let langTemplateFileName = langTemplateDir </> templateFileName
if System.IO.File.Exists(langTemplateFileName) then
failwithf "Documents for specified language '%s' have already been added." lang
ensureDirectory langTemplateDir
Copy langTemplateDir [ templateDir </> templateFileName ]
createIndexFsx lang)
)
// --------------------------------------------------------------------------------------
// Release Scripts
Target "ReleaseDocs" (fun _ ->
let tempDocsDir = "temp/gh-pages"
CleanDir tempDocsDir
Repository.cloneSingleBranch "" (gitHome + "/" + gitName + ".git") "gh-pages" tempDocsDir
CopyRecursive "docs/output" tempDocsDir true |> tracefn "%A"
StageAll tempDocsDir
Git.Commit.Commit tempDocsDir (sprintf "Update generated documentation for version %s" release.NugetVersion)
Branches.push tempDocsDir
)
#load "paket-files/build/fsharp/FAKE/modules/Octokit/Octokit.fsx"
open Octokit
Target "Release" (fun _ ->
let user =
match getBuildParam "github-user" with
| s when not (String.IsNullOrWhiteSpace s) -> s
| _ -> getUserInput "Username: "
let pw =
match getBuildParam "github-pw" with
| s when not (String.IsNullOrWhiteSpace s) -> s
| _ -> getUserPassword "Password: "
let remote =
Git.CommandHelper.getGitResult "" "remote -v"
|> Seq.filter (fun (s: string) -> s.EndsWith("(push)"))
|> Seq.tryFind (fun (s: string) -> s.Contains(gitOwner + "/" + gitName))
|> function None -> gitHome + "/" + gitName | Some (s: string) -> s.Split().[0]
StageAll ""
Git.Commit.Commit "" (sprintf "Bump version to %s" release.NugetVersion)
Branches.pushBranch "" remote (Information.getBranchName "")
Branches.tag "" release.NugetVersion
Branches.pushTag "" remote release.NugetVersion
// release on github
createClient user pw
|> createDraft gitOwner gitName release.NugetVersion (release.SemVer.PreRelease <> None) release.Notes
// TODO: |> uploadFile "PATH_TO_FILE"
|> releaseDraft
|> Async.RunSynchronously
)
Target "BuildPackage" DoNothing
// --------------------------------------------------------------------------------------
// Run all targets by default. Invoke 'build <Target>' to override
Target "All" DoNothing
"Clean"
==> "AssemblyInfo"
==> "Build"
==> "CopyBinaries"
==> "RunTests"
=?> ("GenerateDocs", TestDir "docs")
==> "All"
=?> ("ReleaseDocs",isLocalBuild)
"All"
#if MONO
#else
=?> ("SourceLink", Pdbstr.tryFind().IsSome )
#endif
==> "NuGet"
==> "BuildPackage"
"CleanDocs"
==> "GenerateHelp"
==> "GenerateReferenceDocs"
==> "GenerateDocs"
"CleanDocs"
==> "GenerateHelpDebug"
"GenerateHelpDebug"
==> "KeepRunning"
"ReleaseDocs"
==> "Release"
"BuildPackage"
==> "PublishNuget"
==> "Release"
RunTargetOrDefault "All"

Просмотреть файл

@ -1,74 +0,0 @@
#!/usr/bin/env bash
set -eu
set -o pipefail
cd `dirname $0`
PAKET_BOOTSTRAPPER_EXE=.paket/paket.bootstrapper.exe
PAKET_EXE=.paket/paket.exe
FAKE_EXE=packages/build/FAKE/tools/FAKE.exe
FSIARGS=""
OS=${OS:-"unknown"}
if [[ "$OS" != "Windows_NT" ]]
then
FSIARGS="--fsiargs -d:MONO"
fi
function run() {
if [[ "$OS" != "Windows_NT" ]]
then
mono "$@"
else
"$@"
fi
}
function yesno() {
# NOTE: Defaults to NO
read -p "$1 [y/N] " ynresult
case "$ynresult" in
[yY]*) true ;;
*) false ;;
esac
}
set +e
run $PAKET_BOOTSTRAPPER_EXE
bootstrapper_exitcode=$?
set -e
if [[ "$OS" != "Windows_NT" ]] &&
[ $bootstrapper_exitcode -ne 0 ] &&
[ $(certmgr -list -c Trust | grep X.509 | wc -l) -le 1 ] &&
[ $(certmgr -list -c -m Trust | grep X.509 | wc -l) -le 1 ]
then
echo "Your Mono installation has no trusted SSL root certificates set up."
echo "This may result in the Paket bootstrapper failing to download Paket"
echo "because Github's SSL certificate can't be verified. One way to fix"
echo "this issue would be to download the list of SSL root certificates"
echo "from the Mozilla project by running the following command:"
echo ""
echo " mozroots --import --sync"
echo ""
echo "This will import over 100 SSL root certificates into your Mono"
echo "certificate repository."
echo ""
if yesno "Run 'mozroots --import --sync' now?"
then
mozroots --import --sync
else
echo "Attempting to continue without running mozroots. This might fail."
fi
# Re-run bootstrapper whether or not the user ran mozroots, because maybe
# they fixed the problem in a separate terminal window.
run $PAKET_BOOTSTRAPPER_EXE
fi
run $PAKET_EXE restore
[ ! -e build.fsx ] && run $PAKET_EXE update
[ ! -e build.fsx ] && run $FAKE_EXE init.fsx
run $FAKE_EXE "$@" $FSIARGS build.fsx

Просмотреть файл

@ -1,17 +1,10 @@
source https://nuget.org/api/v2
group Build
source https://nuget.org/api/v2
nuget SourceLink.Fake
nuget FAKE
nuget FSharp.Formatting
github fsharp/FAKE modules/Octokit/Octokit.fsx
nuget Angara.Serialization
group Test
source https://nuget.org/api/v2
nuget Angara.Serialization.Json
nuget NUnit ~> 2
nuget NUnit.Runners ~> 2
nuget FsUnit

Просмотреть файл

@ -1,38 +1,21 @@
GROUP Build
NUGET
remote: https://www.nuget.org/api/v2
specs:
FAKE (4.23.1)
FSharp.Compiler.Service (2.0.0.6)
FSharp.Formatting (2.14.1)
FSharp.Compiler.Service (2.0.0.6)
FSharpVSPowerTools.Core (>= 2.3 < 2.4)
FSharpVSPowerTools.Core (2.3)
FSharp.Compiler.Service (>= 2.0.0.3)
Microsoft.Bcl (1.1.10) - framework: net10, net11, net20, net35, net40, net40-full
Microsoft.Bcl.Build (>= 1.0.14)
Microsoft.Bcl.Build (1.0.21) - import_targets: false, framework: net10, net11, net20, net35, net40, net40-full
Microsoft.Net.Http (2.2.29) - framework: net10, net11, net20, net35, net40, net40-full
Microsoft.Bcl (>= 1.1.10)
Microsoft.Bcl.Build (>= 1.0.14)
Octokit (0.19)
Microsoft.Net.Http
SourceLink.Fake (1.1)
GITHUB
remote: fsharp/FAKE
specs:
modules/Octokit/Octokit.fsx (a362ff28fc27c98f6195aab6421300e5f6c47581)
Octokit
Angara.Serialization (0.2)
GROUP Test
NUGET
remote: https://www.nuget.org/api/v2
specs:
Angara.Serialization (0.2)
Angara.Serialization.Json (0.2)
Angara.Serialization (>= 0.2)
Newtonsoft.Json (>= 8.0.3)
FSharp.Core (4.0.0.1)
FsUnit (1.4.1)
FSharp.Core (>= 3.1.2.5)
NUnit (2.6.4)
Newtonsoft.Json (8.0.3)
NUnit (2.6.4)
NUnit.Runners (2.6.4)
Unquote (3.1.1)

Просмотреть файл

@ -10,7 +10,7 @@
<RootNamespace>Angara.Statistics</RootNamespace>
<AssemblyName>Angara.Statistics</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<TargetFSharpCoreVersion>4.3.1.0</TargetFSharpCoreVersion>
<TargetFSharpCoreVersion>4.4.0.0</TargetFSharpCoreVersion>
<Name>Angara.Statistics</Name>
<TargetFrameworkProfile />
</PropertyGroup>
@ -74,4 +74,15 @@
</Target>
-->
<Import Project="..\..\.paket\paket.targets" />
<Choose>
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5.2' Or $(TargetFrameworkVersion) == 'v4.5.3' Or $(TargetFrameworkVersion) == 'v4.6' Or $(TargetFrameworkVersion) == 'v4.6.1')">
<ItemGroup>
<Reference Include="Angara.Serialization">
<HintPath>..\..\packages\Angara.Serialization\lib\net452\Angara.Serialization.dll</HintPath>
<Private>True</Private>
<Paket>True</Paket>
</Reference>
</ItemGroup>
</When>
</Choose>
</Project>

Просмотреть файл

@ -0,0 +1,13 @@
namespace System
open System.Reflection
[<assembly: AssemblyTitleAttribute("Angara.Statistics")>]
[<assembly: AssemblyProductAttribute("Angara.Statistics")>]
[<assembly: AssemblyDescriptionAttribute("A collection of statistics algorithms from Mersenne twister generator to MCMC sampling.")>]
[<assembly: AssemblyVersionAttribute("0.1.3")>]
[<assembly: AssemblyFileVersionAttribute("0.1.3")>]
do ()
module internal AssemblyVersionInformation =
let [<Literal>] Version = "0.1.3"
let [<Literal>] InformationalVersion = "0.1.3"

Просмотреть файл

@ -12,32 +12,44 @@ type ParameterDefinition =
lower: float
/// An upper bound of parameter values.
upper: float
/// Prior probability distribution of the parameter; all elements of a vector parameter reuse the same prior.
prior: Distribution
/// When `isLog=true` the sampler transforms the parameter to logarithmic space.
isLog: bool
/// A preset log_pdf of prior distribution; if isLog, then the first argument of prior is log-parameter.
/// This field automatically gets value from `prior`.
log_priordf: float -> float
/// If `delay<1`, the sampler initializes the parameter value with a random number.
/// If `delay=1`, the sampler starts with the value from the definition record.
/// If `delay>1`, the sampler doesn't change the parameter value for the first 'delay' iterations.
delay: int
/// log_pdf of prior distribution; if isLog, then the first argument of prior is log-parameter; all vector elements reuse the same prior.
prior: float -> float
}
member x.isFixed = x.delay = System.Int32.MaxValue
override x.Equals other =
match other with
| :? ParameterDefinition as y -> y.index = x.index && y.size = x.size && y.lower = x.lower && x.upper = x.upper && y.isLog = x.isLog && y.delay = x.delay
| :? ParameterDefinition as y ->
y.index = x.index && y.size = x.size && y.lower = x.lower && x.upper = x.upper
&& y.isLog = x.isLog && y.delay = x.delay && y.prior = x.prior
| _ -> false
override x.GetHashCode() =
x.index.GetHashCode() ^^^ x.size.GetHashCode() ^^^ x.lower.GetHashCode() ^^^ x.upper.GetHashCode() ^^^ x.isLog.GetHashCode() ^^^ x.delay.GetHashCode()
x.index.GetHashCode() ^^^ x.size.GetHashCode() ^^^ x.lower.GetHashCode() ^^^ x.upper.GetHashCode()
^^^ x.isLog.GetHashCode() ^^^ x.delay.GetHashCode() ^^^ x.prior.GetHashCode()
type IParameters = System.Collections.Generic.IReadOnlyDictionary<string, float[]>
/// A container for model parameters.
type Parameters private (pdefs: Map<string,ParameterDefinition>, pvalues: float[]) =
let defaultLog isLog = defaultArg isLog false
let defaultDelay delay = defaultArg delay 0
let uniformPrior _ = 0.
let normalPrior mu sigma v = let d = mu-v in -0.5*d*d/sigma
let defaultPrior prior = defaultArg prior uniformPrior
static let defaultLog isLog = defaultArg isLog false
static let defaultDelay delay = defaultArg delay 0
static let uniformPrior _ = 0.
static let log_priordf is_log prior =
match is_log, prior with
| false, Uniform(_,_)
| true, LogUniform(_,_) -> uniformPrior
| false, Normal(m,s) -> fun x -> let d = (x-m)/s in 0.5*d*d
| true, LogNormal(m,s) -> let log_m = log m in fun x -> let d = (x-log_m)/s in 0.5*d*d
| false, _ -> log_pdf prior
| true, _ -> fun x -> log_pdf prior (exp x)
let avalue pdef = Array.sub pvalues pdef.index pdef.size
let all = pdefs |> Seq.map (fun kv ->
System.Collections.Generic.KeyValuePair<string, float[]>(kv.Key, avalue kv.Value))
@ -63,22 +75,27 @@ type Parameters private (pdefs: Map<string,ParameterDefinition>, pvalues: float[
invalidArg "name" "parameters must have unique non-empty names."
if Array.length values < 1 then
invalidArg "values" "empty values array, each parameter must have at least one value."
if lower > upper then
invalidArg "lower" "lower must not be greater than upper."
let prior' = defaultArg prior (Uniform(lower, upper))
let lower' = match prior' with Uniform(a,_)|LogUniform(a,_) -> max a lower | _ -> lower
let upper' = match prior' with Uniform(_,b)|LogUniform(_,b) -> min b upper | _ -> upper
if lower' > upper' then
invalidArg "lower" (sprintf "lower %g must not be greater than upper %g." lower' upper')
values |> Array.iteri (fun i v ->
if v < lower || v > upper then
if v < lower' || v > upper' then
invalidArg "values" (sprintf "values[%d] is out of [lower..upper] range" i))
if isLog.IsSome && isLog.Value && lower <= 0. then
invalidArg "lower" "lower must not be greater than upper."
let isLog' = defaultLog isLog
if isLog' && lower' <= 0. then
invalidArg "lower" "lower must be >0 because isLog=true."
Parameters(
pdefs |> Map.add name {
index = Array.length pvalues
size = Array.length values
lower = lower
upper = upper
isLog = defaultLog isLog
delay = (if lower=upper then -1 else defaultDelay delay)
prior = defaultPrior prior
lower = lower'
upper = upper'
isLog = isLog'
delay = (if lower=upper then System.Int32.MaxValue else defaultDelay delay)
prior = prior'
log_priordf = log_priordf isLog' prior'
},
Array.append pvalues values)
/// Add a fixed scalar parameter.
@ -93,22 +110,22 @@ type Parameters private (pdefs: Map<string,ParameterDefinition>, pvalues: float[
| Uniform(lower, upper) ->
if upper<lower then invalidArg "prior" "in Uniform prior upper must not be less than lower" else
if upper=lower then x.Add(name, lower) else
x.Add(name, Array.create theSize (0.5*(lower+upper)), lower, upper, 0, false, uniformPrior)
x.Add(name, Array.create theSize (0.5*(lower+upper)), lower, upper, 0, false, prior)
| LogUniform(lower, upper) -> // isLog = true
if lower <= 0. then invalidArg "prior" "in LogUniform prior lower must be > 0" else
if upper<lower then invalidArg "prior" "in LogUniform prior upper must not be less than lower" else
if upper=lower then x.Add(name, lower) else
x.Add(name, Array.create theSize (0.5*(lower+upper)), lower, upper, 0, true, uniformPrior)
x.Add(name, Array.create theSize (0.5*(lower+upper)), lower, upper, 0, true, prior)
| Normal(mu, sigma) ->
// the below [lower, upper] interval contain 0.99999 of prior probability
if sigma <= 0. then invalidArg "prior" "in Normal prior sigma must be > 0" else
x.Add(name, Array.create theSize mu, mu - 4.417 * sigma, mu + 4.417 * sigma, 0, false, normalPrior mu sigma)
x.Add(name, Array.create theSize mu, mu - 4.417 * sigma, mu + 4.417 * sigma, 0, false, prior)
| LogNormal(mu, sigma) -> // isLog = true
// the below [lower, upper] interval contain 0.99999 of prior probability
if mu <= 0. then invalidArg "prior" "in Normal prior mean must be > 0" else
if sigma <= 0. then invalidArg "prior" "in Normal prior sigma must be > 0" else
let logMu = log mu
x.Add(name, Array.create theSize mu, exp(logMu - 4.417 * sigma), exp(logMu + 4.417 * sigma), 0, true, normalPrior logMu sigma)
x.Add(name, Array.create theSize mu, exp(logMu - 4.417 * sigma), exp(logMu + 4.417 * sigma), 0, true, prior)
| _ -> invalidArg "prior" "this method overload accepts only Uniform, LogUniform, Normal and LogNormal priors"
/// Add a parameter with a prior and starting values
@ -118,22 +135,22 @@ type Parameters private (pdefs: Map<string,ParameterDefinition>, pvalues: float[
| Uniform(lower, upper) ->
if upper<lower then invalidArg "prior" "in Uniform prior upper must not be less than lower" else
if upper=lower then x.Add(name, lower) else
x.Add(name, values, min lower (Array.min values), max upper (Array.max values), 1, false, uniformPrior)
x.Add(name, values, min lower (Array.min values), max upper (Array.max values), 1, false, prior)
| LogUniform(lower, upper) -> // isLog = true
if lower <= 0. then invalidArg "prior" "in LogUniform prior lower must be > 0" else
if upper<lower then invalidArg "prior" "in LogUniform prior upper must not be less than lower" else
if upper=lower then x.Add(name, lower) else
x.Add(name, values, min lower (Array.min values), max upper (Array.max values), 1, true, uniformPrior)
x.Add(name, values, min lower (Array.min values), max upper (Array.max values), 1, true, prior)
| Normal(mu, sigma) ->
// the below [lower, upper] interval contain 0.99999 of prior probability
if sigma <= 0. then invalidArg "prior" "in Normal prior sigma must be > 0" else
x.Add(name, values, min (mu - 4.417 * sigma) (Array.min values), max (mu + 4.417 * sigma) (Array.max values), 1, false, normalPrior mu sigma)
x.Add(name, values, min (mu - 4.417 * sigma) (Array.min values), max (mu + 4.417 * sigma) (Array.max values), 1, false, prior)
| LogNormal(mu, sigma) ->
// the below [lower, upper] interval contain 0.99999 of prior probability
if mu <= 0. then invalidArg "prior" "in Normal prior mean must be > 0" else
if sigma <= 0. then invalidArg "prior" "in Normal prior sigma must be > 0" else
let logMu = log mu
x.Add(name, values, min (exp(logMu - 4.417 * sigma)) (Array.min values), max (exp(logMu + 4.417 * sigma)) (Array.max values), 1, true, normalPrior logMu sigma)
x.Add(name, values, min (exp(logMu - 4.417 * sigma)) (Array.min values), max (exp(logMu + 4.417 * sigma)) (Array.max values), 1, true, prior)
| _ -> invalidArg "prior" "this method overload accepts only Uniform, LogUniform, Normal and LogNormal priors"
/// Add a parameter.
@ -141,8 +158,12 @@ type Parameters private (pdefs: Map<string,ParameterDefinition>, pvalues: float[
/// described in [Filzbach User Guide](http://research.microsoft.com/en-us/um/cambridge/groups/science/tools/filzbach/filzbach%20user%20gude%20v.1.1.pdf).
/// The `dsply` argument is not used here.
member x.Add(name, lb:float, ub:float, ``val``:float, ``type``, ``fixed``, dsply:int, ?number) =
ignore dsply // prevent 'not used' warning
let size = defaultArg number 1
x.Add(name, Array.create size ``val``, lb, ub, (if ``fixed`` = 0 then 0 else System.Int32.MaxValue), ``type`` <> 0, uniformPrior)
if ``type`` = 0 then
x.Add(name, Array.create size ``val``, lb, ub, (if ``fixed`` = 0 then 0 else System.Int32.MaxValue), false, Uniform(lb, ub))
else
x.Add(name, Array.create size ``val``, lb, ub, (if ``fixed`` = 0 then 0 else System.Int32.MaxValue), true, LogUniform(lb,ub))
/// Replaces all parameter values.
/// For a parameter `"p"` the parameter values are at index `x.GetDefinition("p").index` in the `values` array.
@ -207,11 +228,10 @@ type Parameters private (pdefs: Map<string,ParameterDefinition>, pvalues: float[
type Sample = {values:float[]; logLikelihood:float; logPrior:float}
type SamplerResult = {sampler:Sampler; samples:Sample seq; acceptanceRate: float}
type SamplerResult = {burnedIn:Sampler; final:Sampler; samples:Sample seq; acceptanceRate: float}
/// An immutable state of Filzbach MCMC sampler.
and Sampler private (logl: Parameters -> float,
// utilities
and Sampler private (// utilities
pall: ParameterDefinition[],
// variables
metr_k: int,
@ -224,20 +244,21 @@ and Sampler private (logl: Parameters -> float,
runalt:int[], // number of alterations of individual parameters
runacc:int[] // number of accepted alterations of individual parameters
) =
static let log_prior pall values = Array.fold2 (fun sum d v -> sum + d.prior v) 0. pall values
static let make_pall (pp:Parameters) =
let pall = Array.zeroCreate pp.CountValues
for kv in pp.definitions do
let pdef = kv.Value
let index = pdef.index
for offset in 0..pdef.size-1 do
pall.[index+offset] <- pdef
pall
static let log_prior pall values = Array.fold2 (fun sum d v -> sum + d.log_priordf v) 0. pall values
new(copy:Sampler) =
let metr_k, (seed:uint32[]), (pp:Parameters), deltas, ltotold, ptotold, accept, runalt, runacc = copy.State
let pall = Array.init pp.CountValues (fun i -> pp.GetName i |> pp.GetDefinition)
Sampler(pall, metr_k, MT19937 seed, pp, deltas, ltotold, ptotold, accept, runalt, runacc)
static member internal Restore(metr_k, rng, (pp:Parameters), deltas, ltotold, ptotold, accept, runalt, runacc) =
let pall = Array.init pp.CountValues (fun i -> pp.GetName i |> pp.GetDefinition)
Sampler(pall, metr_k, rng, pp, deltas, ltotold, ptotold, accept, runalt, runacc)
static member Create(pp: Parameters, rng: MT19937, logl: Parameters -> float) =
// init_chains
let pall = make_pall pp
let paramcount = pall.Length
let paramcount = pp.CountValues
let pall = Array.init paramcount (fun i -> pp.GetName i |> pp.GetDefinition)
// initRandomValues
let values = pall |> Array.mapi (fun i def ->
if def.delay<1
@ -254,10 +275,10 @@ and Sampler private (logl: Parameters -> float,
let ltotold = pp.SetValues values |> logl
let ptotold = log_prior pall values
// initialize iteration number
let metr_k = 1
Sampler(logl, pall, metr_k, rng, pp.SetValues values, deltas, ltotold, ptotold, false, runalt, runacc)
Sampler.Restore(1, rng, pp.SetValues values, deltas, ltotold, ptotold, false, runalt, runacc)
member x.Probe(isBurnIn:bool) =
/// Advance one iteration of either burn-in or sampling
member x.Probe(isBurnIn:bool, logl: Parameters -> float) =
let paramcount = pall.Length
let rng = MT19937(rng)
let values = Array.copy pp.values
@ -269,7 +290,7 @@ and Sampler private (logl: Parameters -> float,
let alterable = [for i in 0..paramcount-1 do if pall.[i].delay < metr_k then yield i]
let freeparamcount = alterable.Length
if freeparamcount=0 then
Sampler(logl, pall, metr_k+1, rng, pp, deltas, ltotold, ptotold, accept, runalt, runacc)
Sampler(pall, metr_k+1, rng, pp, deltas, ltotold, ptotold, accept, runalt, runacc)
else
let alt = // chain_params[i].alt=1 ~ alt |> List.any (fun item -> item=i)
if freeparamcount=1 then alterable // one parameter always alters
@ -356,37 +377,52 @@ and Sampler private (logl: Parameters -> float,
runacc.[ii] <- 0
if (accept) then
Sampler(logl, pall, metr_k+1, rng, pp.SetValues values, deltas, ltotnew, ptotnew, accept, runalt, runacc)
Sampler(pall, metr_k+1, rng, pp.SetValues values, deltas, ltotnew, ptotnew, accept, runalt, runacc)
else
Sampler(logl, pall, metr_k+1, rng, pp, deltas, ltotold, ptotold, accept, runalt, runacc)
Sampler(pall, metr_k+1, rng, pp, deltas, ltotold, ptotold, accept, runalt, runacc)
member x.Iteration = metr_k
member x.Parameters = pp
member x.LogLikelihood = ltotold
member x.LogPrior = ptotold
member x.SamplingWidths = Array.copy deltas
member x.IsAccepted = accept
member internal x.State = metr_k, rng.get_seed(), pp, Array.copy deltas, ltotold, ptotold, accept, Array.copy runalt, Array.copy runacc
/// Complete sampling procedure that does `burnCount` burn-in iterations
/// followed by collecting `sampleCount` samples from posterior.
/// Total number of iterations is `burnCount + thinning * sampleCount`.
static member runmcmc(pp, logl, burnCount, sampleCount, ?thinning, ?rng) =
let thinning = defaultArg thinning 100
if thinning<1 then invalidArg "thinning" "must be > 0."
let rng = defaultArg rng (MT19937())
Sampler.continuemcmc(Sampler.Create(pp, rng, logl), logl, burnCount, sampleCount, thinning)
/// Continuation of sampling procedure after incomplete burn-in. It does `burnCount` additional burn-in iterations
/// followed by collecting `sampleCount` samples from posterior.
/// Total number of iterations is `burnCount + thinning * sampleCount`.
static member continuemcmc(sampler:Sampler, logl, burnCount, sampleCount, ?thinning) =
let thinning = defaultArg thinning 100
if thinning<1 then invalidArg "thinning" "must be > 0."
// initialize sampler
let mutable sampler = Sampler.Create(pp, rng, logl)
let mutable sampler = sampler
// do burn-in iterations
for _ in 1..burnCount do sampler <- sampler.Probe(true)
for _ in 1..burnCount do sampler <- sampler.Probe(true, logl)
let burnedIn = Sampler(sampler) // saved copy
// collect sampleCount samples
let mutable countAccepted = 0
let samples =
[
for _ in 1..sampleCount ->
for _ in 1..thinning do
sampler <- sampler.Probe(false)
sampler <- sampler.Probe(false, logl)
if sampler.IsAccepted then countAccepted <- countAccepted + 1
{values=Array.copy sampler.Parameters.values; logLikelihood = sampler.LogLikelihood; logPrior = sampler.LogPrior}
]
{sampler = sampler; samples = samples; acceptanceRate = ((float countAccepted) / (float sampleCount * float thinning))}
static member print {sampler=sampler; samples=samples; acceptanceRate = acceptanceRate} =
{burnedIn=burnedIn; final = sampler; samples = samples; acceptanceRate = ((float countAccepted) / (float sampleCount * float thinning))}
/// Prints summary of results from `runmcmc` or `continuemcmc`.
static member print {final=sampler; samples=samples; acceptanceRate = acceptanceRate} =
printfn "Samples max log likelihood*prior = %g, acceptance rate at sampling = %5.3f"
(samples |> Seq.map (fun {logLikelihood=logl; logPrior=logp} -> logl+logp) |> Seq.max)
acceptanceRate
@ -405,3 +441,88 @@ and Sampler private (logl: Parameters -> float,
pdef.upper pdef.isLog
for off in 10..10..fullname.Length do
printfn " %10s" (fullname.Substring(off,min 10 (fullname.Length-off)))
module Serialization =
open Angara.Serialization
open Angara.Statistics.Serialization
let invalidInfoSet() = invalidArg "is" "invalid InfoSet"
let serializeParameters (p:Parameters) =
let pd =
p.definitions |> Seq.toArray
|> Array.sortBy (fun kv -> kv.Value.index)
|> Array.map (fun kv ->
Seq [
String kv.Key
Int kv.Value.size
Double kv.Value.lower
Double kv.Value.upper
Int kv.Value.delay
Bool kv.Value.isLog
serializeDistribution kv.Value.prior
])
InfoSet.EmptyMap
.AddInfoSet("v", DoubleArray(p.values))
.AddInfoSet("p", Seq(pd))
let deserializeParameters (is:InfoSet) =
match is with
| Map dict ->
if dict.ContainsKey "v" && dict.ContainsKey "p" then
match dict.["v"], dict.["p"] with
| (DoubleArray values), (Seq pd) ->
let values' = Array.ofSeq values
pd |> Seq.fold (fun (p:Parameters, index) is_args ->
match is_args with
| Seq args ->
match List.ofSeq args with
| [
String name
Int size
Double lower
Double upper
Int delay
Bool isLog
is_prior
] ->
p.Add(name, Array.sub values' index size, lower, upper, delay, isLog, deserializeDistribution is_prior), index+size
| _ -> invalidInfoSet()
| _ -> invalidInfoSet()
) (Parameters.Empty, 0)
|> fst
| _ -> invalidInfoSet()
else invalidInfoSet()
| _ -> invalidInfoSet()
type ParametersSerializer() =
interface ISerializer<Parameters> with
member x.TypeId = "FilzbachP"
member x.Serialize _ p = serializeParameters p
member x.Deserialize _ is = deserializeParameters is
let serializeSampler (s:Sampler) =
let metr_k, seed, pp, deltas, ltotold, ptotold, accept, runalt, runacc = s.State
Seq [Int metr_k; UIntArray seed; serializeParameters pp; DoubleArray deltas; Double ltotold; Double ptotold; Bool accept; IntArray runalt; IntArray runacc]
let deserializeSampler is =
match is with
| Seq is_fields ->
match is_fields |> List.ofSeq with
| [Int metr_k; UIntArray seed; is_pp; DoubleArray deltas; Double ltotold; Double ptotold; Bool accept; IntArray runalt; IntArray runacc] ->
let pp = deserializeParameters is_pp
Sampler.Restore(metr_k, MT19937(Array.ofSeq seed), pp, Array.ofSeq deltas, ltotold, ptotold, accept, Array.ofSeq runalt, Array.ofSeq runacc)
| _ -> invalidInfoSet()
| _ -> invalidInfoSet()
type SamplerSerializer() =
interface ISerializer<Sampler> with
member x.TypeId = "FilzbachS"
member x.Serialize _ s = serializeSampler s
member x.Deserialize _ is = deserializeSampler is
let Register (lib:ISerializerLibrary) =
lib.Register(Angara.Statistics.Serialization.MersenneTwisterSerializer())
lib.Register(Angara.Statistics.Serialization.DistributionSerializer())
lib.Register(ParametersSerializer())
lib.Register(SamplerSerializer())

Просмотреть файл

@ -476,8 +476,8 @@ type MT19937 private (
else
let state = init_by_array(seed)
MT19937(state, N)
member private x.getMt = mt
member private x.getIdx = idx
member private x.getMt = Array.copy mt
member private x.getIdx = mti
new(copy:MT19937) =
MT19937(copy.getMt, copy.getIdx)
@ -718,8 +718,8 @@ let idct (rxs:float[]) =
let interleave z =
let hz = z >>> 1
match z with
| Even(z) -> vals.[hz]
| Odd(z) -> vals.[len - hz - 1]
| Even _ -> vals.[hz]
| Odd _ -> vals.[len - hz - 1]
[| for i in 0..len-1 do yield interleave(i) |]
// http://hackage.haskell.org/package/statistics-0.10.5.0/docs/src/Statistics-Function.html#nextHighestPowerOfTwo
@ -905,4 +905,87 @@ let kde n0 (xs:float seq) =
if min > (xsi) then
min <- xsi)
if min >= max then 1.0 else max - min
kde2 n0 (min - range/10.0) (max + range/10.0) xs
kde2 n0 (min - range/10.0) (max + range/10.0) xs
module Serialization =
open Angara.Serialization
let rec serializeDistribution (d:Distribution) =
let islist =
match d with
| Uniform(lower,upper) -> [String "U"; Double lower; Double upper]
| LogUniform(lower,upper) -> [String "LU"; Double lower; Double upper]
| Normal(mean, stdev) -> [String "N"; Double mean; Double stdev]
| LogNormal(mean, stdev) -> [String "LN"; Double mean; Double stdev]
| Gamma(a, b) -> [String "G"; Double a; Double b]
| Binomial(n, p) -> [String "B"; Int n; Double p]
| NegativeBinomial(mean, r) -> [String "NB"; Double mean; Double r]
| Bernoulli(p) -> [String "C"; Double p]
| Exponential(mean) -> [String "E"; Double mean]
| Poisson(mean) -> [String "P"; Double mean]
| Mixture(components) ->
let cc = components |> List.map (fun (weight, c) ->
Seq [Double weight; serializeDistribution c])
[String "M"; Seq(cc)]
Seq islist
let rec deserializeDistribution (is:InfoSet) =
let invalidInfoSet() = invalidArg "is" "invalid InfoSet"
match is with
| Seq content ->
match content |> List.ofSeq with
| tag::args ->
match tag.ToStringValue() with
| "U" -> match args with [Double lower; Double upper] -> Uniform(lower, upper) | _ -> invalidInfoSet()
| "LU" -> match args with [Double lower; Double upper]-> LogUniform(lower, upper) | _ -> invalidInfoSet()
| "N" -> match args with [Double mean; Double stdev]-> Normal(mean, stdev) | _ -> invalidInfoSet()
| "LN" -> match args with [Double mean; Double stdev]-> LogNormal(mean, stdev) | _ -> invalidInfoSet()
| "G" -> match args with [Double a; Double b]-> Gamma(a, b) | _ -> invalidInfoSet()
| "NB" -> match args with [Double mean; Double r]-> NegativeBinomial(mean, r) | _ -> invalidInfoSet()
| "B" -> match args with [Int n; Double p]-> Binomial(n, p) | _ -> invalidInfoSet()
| "C" -> match args with [Double p]-> Bernoulli(p) | _ -> invalidInfoSet()
| "E" -> match args with [Double p]-> Exponential(p) | _ -> invalidInfoSet()
| "P" -> match args with [Double p]-> Poisson(p) | _ -> invalidInfoSet()
| "M" ->
match args with
| [Seq is_components] ->
let components =
is_components
|> Seq.map (function
| (Seq is_c) ->
match List.ofSeq is_c with [Double weight; is_d] -> weight, deserializeDistribution is_d | _ -> invalidInfoSet()
| _ -> invalidInfoSet())
|> List.ofSeq
Mixture components
| _ -> invalidInfoSet()
| _ -> invalidInfoSet()
| _ -> invalidInfoSet()
| _ -> invalidInfoSet()
let serializeMersenneTwister (mt:MT19937) =
let seed = mt.get_seed()
use buffer = new System.IO.MemoryStream (seed.Length*4)
use writer = new System.IO.BinaryWriter(buffer)
seed |> Array.iter writer.Write
ByteArray(buffer.GetBuffer())
let deserializeMersenneTwister is =
match is with
| ByteArray byteseq ->
let buffer = Array.ofSeq byteseq
use reader = new System.IO.BinaryReader(new System.IO.MemoryStream (buffer))
let seed = Array.init (buffer.Length/4) (fun _ -> reader.ReadUInt32())
MT19937 seed
| _ -> invalidArg "is" "Invalid InfoSet"
type DistributionSerializer() =
interface ISerializer<Distribution> with
member x.TypeId = "ProbDist"
member x.Serialize _ d = serializeDistribution d
member x.Deserialize _ is = deserializeDistribution is
type MersenneTwisterSerializer() =
interface ISerializer<MT19937> with
member x.TypeId = "MeresenneTwister"
member x.Serialize _ mt = serializeMersenneTwister mt
member x.Deserialize _ is = deserializeMersenneTwister is

Просмотреть файл

@ -0,0 +1 @@
Angara.Serialization

Просмотреть файл

@ -10,7 +10,7 @@
<RootNamespace>Angara.Statistics.Tests</RootNamespace>
<AssemblyName>Angara.Statistics.Tests</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<TargetFSharpCoreVersion>4.3.1.0</TargetFSharpCoreVersion>
<TargetFSharpCoreVersion>4.4.0.0</TargetFSharpCoreVersion>
<Name>Angara.Statistics.Tests</Name>
<TargetFrameworkProfile />
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
@ -54,10 +54,20 @@
</Choose>
<Import Project="$(FSharpTargetsPath)" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<Import Project="..\..\.paket\paket.targets" />
<ItemGroup>
<Compile Include="Tests.fs" />
<Compile Include="FilzbachTests.fs" />
<Compile Include="SerializationTests.fs" />
<None Include="paket.references" />
<Content Include="App.config" />
</ItemGroup>
<ItemGroup>
<Reference Include="mscorlib" />
@ -67,22 +77,34 @@
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Numerics" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Angara.Statistics\Angara.Statistics.fsproj">
<Name>Angara.Statistics</Name>
<Project>{5161430d-44b4-441c-be95-89c02f215d38}</Project>
<Private>True</Private>
</ProjectReference>
</ItemGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<Import Project="..\..\.paket\paket.targets" />
<Choose>
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5.2' Or $(TargetFrameworkVersion) == 'v4.5.3' Or $(TargetFrameworkVersion) == 'v4.6' Or $(TargetFrameworkVersion) == 'v4.6.1')">
<ItemGroup>
<Reference Include="Angara.Serialization">
<HintPath>..\..\packages\Angara.Serialization\lib\net452\Angara.Serialization.dll</HintPath>
<Private>True</Private>
<Paket>True</Paket>
</Reference>
</ItemGroup>
</When>
</Choose>
<Choose>
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5.2' Or $(TargetFrameworkVersion) == 'v4.5.3' Or $(TargetFrameworkVersion) == 'v4.6' Or $(TargetFrameworkVersion) == 'v4.6.1')">
<ItemGroup>
<Reference Include="Angara.Serialization.Json">
<HintPath>..\..\packages\test\Angara.Serialization.Json\lib\net452\Angara.Serialization.Json.dll</HintPath>
<Private>True</Private>
<Paket>True</Paket>
</Reference>
</ItemGroup>
</When>
</Choose>
<Choose>
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.1' Or $(TargetFrameworkVersion) == 'v4.5.2' Or $(TargetFrameworkVersion) == 'v4.5.3' Or $(TargetFrameworkVersion) == 'v4.6' Or $(TargetFrameworkVersion) == 'v4.6.1')">
<ItemGroup>
@ -99,6 +121,62 @@
</ItemGroup>
</When>
</Choose>
<Choose>
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And $(TargetFrameworkVersion) == 'v3.5'">
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath>..\..\packages\test\Newtonsoft.Json\lib\net35\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
<Paket>True</Paket>
</Reference>
</ItemGroup>
</When>
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v2.0' Or $(TargetFrameworkVersion) == 'v3.0')">
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath>..\..\packages\test\Newtonsoft.Json\lib\net20\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
<Paket>True</Paket>
</Reference>
</ItemGroup>
</When>
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.0')">
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath>..\..\packages\test\Newtonsoft.Json\lib\net40\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
<Paket>True</Paket>
</Reference>
</ItemGroup>
</When>
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.1' Or $(TargetFrameworkVersion) == 'v4.5.2' Or $(TargetFrameworkVersion) == 'v4.5.3' Or $(TargetFrameworkVersion) == 'v4.6' Or $(TargetFrameworkVersion) == 'v4.6.1')">
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath>..\..\packages\test\Newtonsoft.Json\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
<Paket>True</Paket>
</Reference>
</ItemGroup>
</When>
<When Condition="($(TargetFrameworkIdentifier) == 'MonoAndroid') Or ($(TargetFrameworkIdentifier) == 'MonoTouch') Or ($(TargetFrameworkIdentifier) == 'Xamarin.iOS') Or ($(TargetFrameworkIdentifier) == 'Xamarin.Mac') Or ($(TargetFrameworkProfile) == 'Profile7') Or ($(TargetFrameworkProfile) == 'Profile44') Or ($(TargetFrameworkProfile) == 'Profile49') Or ($(TargetFrameworkProfile) == 'Profile78') Or ($(TargetFrameworkProfile) == 'Profile111') Or ($(TargetFrameworkProfile) == 'Profile151') Or ($(TargetFrameworkProfile) == 'Profile259')">
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath>..\..\packages\test\Newtonsoft.Json\lib\portable-net45+wp80+win8+wpa81+dnxcore50\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
<Paket>True</Paket>
</Reference>
</ItemGroup>
</When>
<When Condition="($(TargetFrameworkIdentifier) == 'WindowsPhoneApp') Or ($(TargetFrameworkIdentifier) == '.NETCore') Or ($(TargetFrameworkIdentifier) == 'Silverlight' And $(TargetFrameworkVersion) == 'v5.0') Or ($(TargetFrameworkIdentifier) == 'WindowsPhone' And ($(TargetFrameworkVersion) == 'v8.0' Or $(TargetFrameworkVersion) == 'v8.1')) Or ($(TargetFrameworkProfile) == 'Profile5') Or ($(TargetFrameworkProfile) == 'Profile6') Or ($(TargetFrameworkProfile) == 'Profile14') Or ($(TargetFrameworkProfile) == 'Profile19') Or ($(TargetFrameworkProfile) == 'Profile24') Or ($(TargetFrameworkProfile) == 'Profile31') Or ($(TargetFrameworkProfile) == 'Profile32') Or ($(TargetFrameworkProfile) == 'Profile37') Or ($(TargetFrameworkProfile) == 'Profile42') Or ($(TargetFrameworkProfile) == 'Profile47') Or ($(TargetFrameworkProfile) == 'Profile84') Or ($(TargetFrameworkProfile) == 'Profile92') Or ($(TargetFrameworkProfile) == 'Profile102') Or ($(TargetFrameworkProfile) == 'Profile136') Or ($(TargetFrameworkProfile) == 'Profile147') Or ($(TargetFrameworkProfile) == 'Profile157') Or ($(TargetFrameworkProfile) == 'Profile158') Or ($(TargetFrameworkProfile) == 'Profile225') Or ($(TargetFrameworkProfile) == 'Profile240') Or ($(TargetFrameworkProfile) == 'Profile255') Or ($(TargetFrameworkProfile) == 'Profile328') Or ($(TargetFrameworkProfile) == 'Profile336') Or ($(TargetFrameworkProfile) == 'Profile344')">
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath>..\..\packages\test\Newtonsoft.Json\lib\portable-net40+sl5+wp80+win8+wpa81\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
<Paket>True</Paket>
</Reference>
</ItemGroup>
</When>
</Choose>
<ItemGroup>
<Reference Include="nunit.framework">
<HintPath>..\..\packages\test\NUnit\lib\nunit.framework.dll</HintPath>

Просмотреть файл

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.3.1.0" newVersion="4.4.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

Просмотреть файл

@ -1,10 +1,11 @@
module FilzbachTests
open NUnit.Framework
open FsUnit
open Swensen.Unquote
open Angara.Filzbach
let noPrior _ = 0.
let uniform = Angara.Statistics.Uniform(0.,1.)
[<Test>]
let ParametersTests() =
@ -35,7 +36,7 @@ let ParametersTests() =
p1.GetValue "s" |> should equal 0.5
p1.GetValue("s", 0) |> should equal 0.5
(fun () -> p1.GetValue("s", 1) |> ignore) |> should throw typeof<System.IndexOutOfRangeException>
p1.GetDefinition "s" |> should equal {index=0; size=1; lower=0.; upper=1.; delay=0; prior=noPrior; isLog=false}
p1.GetDefinition "s" |> should equal {index=0; size=1; lower=0.; upper=1.; delay=0; prior=uniform; isLog=false; log_priordf=id}
(p1:>IParameters).Count |> should equal 1
(p1:>IParameters).ContainsKey "s" |> should be True
(p1:>IParameters).ContainsKey "a" |> should be False
@ -56,7 +57,7 @@ let ParametersTests() =
(fun () -> p2.GetValue "v" |> ignore) |> should throw typeof<System.InvalidOperationException> // vector syntax
p2.GetValue("v", 0) |> should equal 0.6
p2.GetValue("v", 1) |> should equal 0.7
p2.GetDefinition "v" |> should equal {index=0; size=2; lower=0.; upper=1.; delay=0; prior=noPrior; isLog=false}
p2.GetDefinition "v" |> should equal {index=0; size=2; lower=0.; upper=1.; delay=0; prior=uniform; isLog=false; log_priordf=id}
(p2:>IParameters).Count |> should equal 1
(p2:>IParameters).ContainsKey "v" |> should be True
(p2:>IParameters).ContainsKey "a" |> should be False
@ -79,8 +80,8 @@ let ParametersTests() =
p3.GetValue("v", 1) |> should equal 0.7
p3.GetValue "s" |> should equal 0.5
p3.GetValue("s", 0) |> should equal 0.5
p3.GetDefinition "s" |> should equal {index=2; size=1; lower=0.; upper=1.; delay=0; prior=noPrior; isLog=false}
p3.GetDefinition "v" |> should equal {index=0; size=2; lower=0.; upper=1.; delay=0; prior=noPrior; isLog=false}
p3.GetDefinition "s" |> should equal {index=2; size=1; lower=0.; upper=1.; delay=0; prior=uniform; isLog=false; log_priordf=id}
p3.GetDefinition "v" |> should equal {index=0; size=2; lower=0.; upper=1.; delay=0; prior=uniform; isLog=false; log_priordf=id}
(p3:>IParameters).Count |> should equal 2
(p3:>IParameters).ContainsKey "s" |> should be True
(p3:>IParameters).ContainsKey "v" |> should be True
@ -106,8 +107,8 @@ let ParametersTests() =
p4.GetValue("v", 1) |> should equal 0.7
p4.GetValue "s" |> should equal 0.5
p4.GetValue("s", 0) |> should equal 0.5
p4.GetDefinition "s" |> should equal {index=0; size=1; lower=0.; upper=1.; delay=0; prior=noPrior; isLog=false}
p4.GetDefinition "v" |> should equal {index=1; size=2; lower=0.; upper=1.; delay=0; prior=noPrior; isLog=false}
p4.GetDefinition "s" |> should equal {index=0; size=1; lower=0.; upper=1.; delay=0; prior=uniform; isLog=false; log_priordf=id}
p4.GetDefinition "v" |> should equal {index=1; size=2; lower=0.; upper=1.; delay=0; prior=uniform; isLog=false; log_priordf=id}
(p4:>IParameters).Count |> should equal 2
(p4:>IParameters).ContainsKey "s" |> should be True
(p4:>IParameters).ContainsKey "v" |> should be True
@ -121,4 +122,62 @@ let ParametersTests() =
(p4:>IParameters).Keys |> Seq.toList |> should equal ["s";"v"]
(p4:>IParameters).Values |> Seq.toList |> should equal [[|0.5|]; [|0.6;0.7|]]
[<Test>]
let SamplerTests() =
let assertfail() : 'a = raise (AssertionException(null))
let mt = Angara.Statistics.MT19937()
let logl (p:Parameters) =
let s = p.AllValues |> Seq.sum
- log (1. + exp(-s))
let sample = Sampler.Create(Parameters.Empty, mt, logl)
test <@ Seq.isEmpty sample.Parameters.AllValues @>
test <@ Seq.isEmpty (sample.Probe(true, logl).Parameters.AllValues) @>
let s2 = Sampler.Create(Parameters.Empty.Add("a",1.), mt, logl)
test <@ s2.Parameters.AllValues |> Seq.toList = [1.] @>
test <@ s2.Probe(true, logl).Parameters.AllValues |> Seq.toList = [1.] @>
let s3 = Sampler.Create(Parameters.Empty.Add("a",Angara.Statistics.Uniform(1.,2.)), mt, logl)
let v3 = match s3.Parameters.AllValues |> Seq.toList with [v] -> v | _ -> assertfail()
test <@ v3 > 1. && v3 < 2. @>
let s3' = s3 |> Seq.unfold (fun s -> if s.IsAccepted then None else let s' = s.Probe(false,logl) in Some (s',s')) |> Seq.last
let v3' = match s3'.Parameters.AllValues |> Seq.toList with [v] -> v | _ -> assertfail()
test <@ s3'.IsAccepted && (v3 <> v3') @>
let s3'' = s3 |> Seq.unfold (fun s -> if s.IsAccepted then None else let s' = s.Probe(true,logl) in Some (s',s')) |> Seq.last
let v3'' = match s3''.Parameters.AllValues |> Seq.toList with [v] -> v | _ -> assertfail()
test <@ s3''.IsAccepted && (v3 <> v3'') @>
let s4 = Sampler.Create(Parameters.Empty.Add("a",Angara.Statistics.Uniform(1.,2.)).Add("b",3.), mt, logl)
let v4, v41 = match s4.Parameters.AllValues |> Seq.toList with [v;v'] -> v,v' | _ -> assertfail()
test <@ v41 = 3. && v4 > 1. && v4 < 2. @>
let s4' = s4 |> Seq.unfold (fun s -> if s.IsAccepted then None else let s' = s.Probe(false,logl) in Some (s',s')) |> Seq.last
let v4', v41' = match s4'.Parameters.AllValues |> Seq.toList with [v;v'] -> v,v' | _ -> assertfail()
test <@ v41' = 3. && s4'.IsAccepted && (v4 <> v4') @>
let s4'' = s4 |> Seq.unfold (fun s -> if s.IsAccepted then None else let s' = s.Probe(true,logl) in Some (s',s')) |> Seq.last
let v4'', v41'' = match s4''.Parameters.AllValues |> Seq.toList with [v;v'] -> v,v' | _ -> assertfail()
test <@ v41'' = 3. && s4''.IsAccepted && (v4 <> v4'') @>
let s5 = Sampler.Create(Parameters.Empty.Add("b",[|3.;3.1|]).Add("a",Angara.Statistics.Uniform(1.,2.)), mt, logl)
let v51, v52, v5 = match s5.Parameters.AllValues |> Seq.toList with [v;v';v''] -> v,v',v'' | _ -> assertfail()
test <@ v51 = 3. && v52 = 3.1 && v5 > 1. && v5 < 2. @>
let s5' = s5 |> Seq.unfold (fun s -> if s.IsAccepted then None else let s' = s.Probe(false,logl) in Some (s',s')) |> Seq.last
let v51', v52', v5' = match s5'.Parameters.AllValues |> Seq.toList with [v;v';v''] -> v,v',v'' | _ -> assertfail()
test <@ v51' = 3. && v52' = 3.1 && s5'.IsAccepted && (v5 <> v5') @>
let s5'' = s5 |> Seq.unfold (fun s -> if s.IsAccepted then None else let s' = s.Probe(true,logl) in Some (s',s')) |> Seq.last
let v51'', v52'', v5'' = match s5''.Parameters.AllValues |> Seq.toList with [v;v';v''] -> v,v',v'' | _ -> assertfail()
test <@ v51'' = 3. && v52'' = 3.1 && s5''.IsAccepted && (v5 <> v5'') @>
[<Test>]
let ContinueationTest() =
let logl (p:Parameters) =
let s = p.AllValues |> Seq.sum
- log (1. + exp(-s))
let pp =
Parameters.Empty
.Add("b", Angara.Statistics.Uniform(1.,2.))
.Add("a",Angara.Statistics.Normal(3.,4.),2)
.Add("a b",Angara.Statistics.Uniform(5.,6.))
let r = Sampler.runmcmc(pp, logl, 100, 100, 1)
test <@ 100 = (r.samples |> Seq.length) @>
let r1' = Sampler.runmcmc(pp, logl, 50, 100, 1)
test <@ 100 = (r1'.samples |> Seq.length) && r.acceptanceRate<>r1'.acceptanceRate && r.samples<>r1'.samples@>
let r1 = Sampler.continuemcmc(r1'.burnedIn, logl, 50, 100, 1)
test <@ r.acceptanceRate=r1.acceptanceRate && r.samples=r1.samples@>

Просмотреть файл

@ -0,0 +1,103 @@
module SerializationTests
open NUnit.Framework
open Swensen.Unquote
open Angara.Serialization
open Angara.Statistics
open Angara.Filzbach
open Angara.Statistics.Serialization
open Angara.Filzbach.Serialization
[<Test>]
let DistributionSerialization() =
let lib = SerializerLibrary.CreateDefault()
lib.Register(DistributionSerializer())
let check d =
let is = serializeDistribution d
d =! deserializeDistribution is
let json = Json.FromObject(lib,d).ToString()
d =! Json.ToObject(Newtonsoft.Json.Linq.JObject.Parse json,lib)
Uniform(1., 2.) |> check
LogUniform(1.,2.) |> check
Normal(1., 2.) |> check
LogNormal(1.,2.) |> check
Gamma(1., 2.) |> check
NegativeBinomial(1., 2.) |> check
Binomial(2, 1.) |> check
Bernoulli(0.7) |> check
Exponential(2.) |> check
Poisson(2.) |> check
Mixture[0.4,LogNormal(1.,2.); 0.6,Normal(3.,4.)] |> check
//
raises<System.ArgumentException> <@ deserializeDistribution InfoSet.EmptyMap @>
raises<System.ArgumentException> <@ deserializeDistribution (InfoSet.Seq[]) @>
raises<System.ArgumentException> <@ deserializeDistribution (InfoSet.String "") @>
raises<System.ArgumentException> <@ deserializeDistribution (InfoSet.Double 1.) @>
[<Test>]
let MersenneTwisterSerialization() =
let lib = SerializerLibrary.CreateDefault()
lib.Register(MersenneTwisterSerializer())
let check2 (mt1:MT19937) (mt2:MT19937) =
mt1.uniform_uint32() =! mt2.uniform_uint32()
mt1.uniform_float64() =! mt2.uniform_float64()
mt1.normal() =! mt2.normal()
mt1.uniform_uint32() =! mt2.uniform_uint32()
let check mt =
let is = serializeMersenneTwister mt
let json = Json.FromObject(lib,mt).ToString()
check2 (MT19937(mt)) (deserializeMersenneTwister is)
check2 (MT19937(mt)) (Json.ToObject(Newtonsoft.Json.Linq.JObject.Parse json,lib))
let mutable mt = MT19937()
for _ in 1..4 do
let seed = mt.get_seed()
check2 mt (MT19937(seed))
check (MT19937(seed))
mt <- MT19937(seed)
mt.uniform_uint32() |> ignore
[<Test>]
let ParametersSerialization() =
let lib = SerializerLibrary.CreateDefault()
lib.Register(ParametersSerializer())
let check p =
let is = serializeParameters p
p =! deserializeParameters is
let json = Json.FromObject(lib,p).ToString()
p =! Json.ToObject(Newtonsoft.Json.Linq.JObject.Parse json,lib)
Parameters.Empty |> check
Parameters.Empty.Add("a", 1.) |> check
Parameters.Empty.Add("a", 1.).Add("b", [|2.; 3.|]) |> check
Parameters.Empty.Add("b", [|2.; 3.|]).Add("a", 1.) |> check
Parameters.Empty
.Add("a", Uniform(1.,2.))
.Add("z y w", LogUniform(3.,4.), 2)
.Add("k", Normal(5.,6.), 3)
.Add("l", LogNormal(7.,8.),2) |> check
raises<System.ArgumentException> <@ deserializeParameters InfoSet.EmptyMap @>
raises<System.ArgumentException> <@ deserializeParameters (InfoSet.Seq[]) @>
raises<System.ArgumentException> <@ deserializeParameters (InfoSet.String "") @>
raises<System.ArgumentException> <@ deserializeParameters (InfoSet.Double 1.) @>
[<Test>]
let SamplerSerialization() =
let lib = SerializerLibrary.CreateDefault()
Register(lib)
let logl (p:Parameters) =
let s = p.AllValues |> Seq.sum
- log (1. + exp(-s))
let s =
Sampler.Create(Parameters.Empty.Add("b", Uniform(1.,2.)).Add("a",Normal(3.,4.),2).Add("a b",Uniform(5.,6.)), MT19937(), logl)
|> Seq.unfold (fun s -> if s.Iteration>100 then None else let s' = s.Probe(true,logl) in Some (s',s'))
|> Seq.last
let json = Json.FromObject(lib, s).ToString()
let s2 = Json.ToObject<Sampler>(Newtonsoft.Json.Linq.JObject.Parse json,lib)
test <@ (s.Parameters.AllValues |> Seq.toArray) = (s2.Parameters.AllValues |> Seq.toArray) @>
let s' = s |> Seq.unfold (fun s ->
if s.Iteration>200 then None else let s' = s.Probe(true,logl) in Some (s',s')) |> Seq.last
let s2' = s2 |> Seq.unfold (fun s ->
if s.Iteration>200 then None else let s' = s.Probe(true,logl) in Some (s',s')) |> Seq.last
test <@ (s'.Parameters.AllValues |> Seq.toArray) = (s2'.Parameters.AllValues |> Seq.toArray) @>

Просмотреть файл

@ -198,4 +198,11 @@ let KernelDensityEstimation_Normal() =
[<Test>]
let const_tests() =
test <@ maxint+1.0 = maxint && maxint-1.0 < maxint @>
test <@ 1.0 - tolerance < 1.0 && 1.0 - 0.5*tolerance = 1.0 @>
test <@ 1.0 - tolerance < 1.0 && 1.0 - 0.5*tolerance = 1.0 @>
[<Test>]
let Mersenne_twister_copy_constructor() =
let mt = MT19937()
mt.normal() |> ignore
let mt_copy = MT19937(mt)
test <@ mt.uniform_uint32() = mt_copy.uniform_uint32() @>

Просмотреть файл

@ -1,5 +1,7 @@
Angara.Serialization
group Test
NUnit
NUnit.Runners
FsUnit
Unquote
Angara.Serialization.Json