-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathProgram.fs
282 lines (258 loc) · 13.1 KB
/
Program.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
//--------------------------------------------------------------
// Program.fs Chess analysis for the NIPS paper
//
// 2007/2008 written by Ralf Herbrich
//
// Copyright (c) 2002-2011 Microsoft Research Ltd.
//
// This source code is subject to terms and conditions of the Microsoft Public License. A
// copy of the license can be found in the License.html file at the root of this distribution.
//
//
//--------------------------------------------------------------
open System
open System.IO
open System.Collections.Generic
open MSRC.Inference.Distributions
open MSRC.Inference.Distributions.Gaussians
open MSRC.Chess
open MSRC.Arg
/// The skill belief of a player in a year
type PlayerData =
{
/// Name of the player
PlayerName : string
/// Year of the analysis
Year : int
/// Mean skill
Mu : float
/// Skill uncertainty
Sigma : float
}
/// The skill and draw margin belief of a player in a year
type ExtendedPlayerData =
{
/// Name of the player
PlayerName : string
/// Year of the analysis
Year : int
/// Mean skill
SkillMu : float
/// Skill uncertainty
SkillSigma : float
/// Mean draw margin
DrawMarginMu : float
/// Draw Margin uncertainty
DrawMarginSigma : float
}
/// The Log Evidence as a function of the Beta and Tau factor
type ModelData =
{
/// Beta/Sigma0
BetaFactor : float
/// Tau/Sigma0
TauFactor : float
/// Log Evidence
LogEvidence : float
/// Name of the result table
ResultTableName : string
}
/// The Log Evidence as a function of the Mu factor and Tau factor
type DrawModelData =
{
/// Mu/Beta
MuFactor : float
/// Tau/Sigma0
TauFactor : float
/// Log Evidence
LogEvidence : float
/// Name of the result table
ResultTableName : string
}
/// Type of models for the Chess data
type Model =
| FixedDrawMargin
| FixedDrawMargin2
| FixedDrawMarginADFOverYears
| FixedDrawMarginADF
| VariableDrawMargin
/// Types of analysis for the Chess data
type Analysis =
| SingleRun
| ModelSelection
/// Verbosity level
let verbose = ref true
/// The type of analysis to perform
let analysis = ref SingleRun
/// The type of model to use
let model = ref FixedDrawMargin
/// The name of the CSV data file
let csvFile = ref "ChessBase.csv"
/// The path to the output file.
let outputPath = ref "output.csv"
/// The mean of the prior skill belief
let muSkill = ref 1200.0
/// The standard deviation of the prior skill belief
let sigmaSkill = ref 400.0
/// The mean of the prior draw margin belief
let muDrawMargin = ref 300.0
/// The standard deviation of the prior draw margin belief
let sigmaDrawMargin = ref 100.0
/// The standard deviation of the performance distribution
let beta = ref 600.0
/// The standard deviation of the skill dynamics distribution
let tauSkill = ref 40.0
/// The standard deviation of the draw margin dynamics distribution
let tauDrawMargin = ref 10.0
/// The number of games to take
let noGames = ref None
/// Should results be saved
let notSave = ref false
/// Maximum deviation for any marginal to define convergence
let delta = ref 0.01
/// A small function which returns the name for the current model
let ModelName () =
match !model with
| FixedDrawMargin -> "FixedDrawMargin"
| FixedDrawMargin2 -> "FixedDrawMargin2"
| FixedDrawMarginADFOverYears -> "FixedDrawMarginADFOverYears"
| FixedDrawMarginADF -> "FixedDrawMarginADF"
| VariableDrawMargin -> "VariableDrawMargin"
/// A small function which returns the name for the current analysis
let AnalysisName () =
match !analysis with
| SingleRun -> "SingleRun"
| ModelSelection -> "ModelSelection"
/// The list of arguments of this application
let argspec =
[
ArgInfo("-no-safe",Arg.Set notSave, "Does not save results predictions (default: off)")
ArgInfo("-q", Arg.Clear verbose, "Verbosity level off; only works on single runs (default: on)")
ArgInfo("-N", Arg.Int (fun n -> noGames := Some (n)), "First N games only (default: ALL)")
ArgInfo("-delta", Arg.Float (fun aDelta -> delta := aDelta), "Maximum deviation in any marginal for convergence (default: 0.01)")
ArgInfo("-muS", Arg.Float (fun aMu -> muSkill := aMu), "Mean of prior skill belief (default: 1200)")
ArgInfo("-sigmaS", Arg.Float (fun aSigma -> sigmaSkill := aSigma), "Standard deviation of prior skill belief (default: 400)")
ArgInfo("-muD", Arg.Float (fun aMu -> muDrawMargin := aMu), "Mean of prior draw margin belief (default: 300)")
ArgInfo("-sigmaD", Arg.Float (fun aSigma -> sigmaDrawMargin := aSigma),"Standard deviation of prior draw margin belief (default: 100)")
ArgInfo("-beta", Arg.Float (fun aBeta -> beta := aBeta), "Standard deviation of performance distr. (default: 600)")
ArgInfo("-tauS", Arg.Float (fun aTau -> tauSkill := aTau), "Standard deviation of skill dynamics distr. (default: 40)")
ArgInfo("-tauD", Arg.Float (fun aTau -> tauDrawMargin := aTau), "Standard deviation of draw margin dynamics distr. (default: 10)")
ArgInfo("-out", Arg.String (fun aPath -> outputPath := aPath), "Path of CSV output (default: 'output.csv')")
ArgInfo("-mf", Arg.Unit (fun () -> model := FixedDrawMargin), "Fixed draw margin (default)")
ArgInfo("-mf2", Arg.Unit (fun () -> model := FixedDrawMargin2), "Fixed draw margin with two factors for draw")
ArgInfo("-maf", Arg.Unit (fun () -> model := FixedDrawMarginADFOverYears), "Fixed draw margin with ADF (iterate per year)")
ArgInfo("-maf2", Arg.Unit (fun () -> model := FixedDrawMarginADF), "Fixed draw margin with pure ADF")
ArgInfo("-mv", Arg.Unit (fun () -> model := VariableDrawMargin), "Variable draw margin")
ArgInfo("-as", Arg.Unit (fun () -> analysis := SingleRun), "Single run (default)")
ArgInfo("-am", Arg.Unit (fun () -> analysis := ModelSelection), "Model selection")
]
/// Saves the result of a fixed draw margin analysis to a CSV file
let SaveFixedDrawMarginResults (results:Dictionary<string,SortedList<int,Gaussian<_>>>) =
if !notSave then
()
else
let wr = new System.IO.StreamWriter(!outputPath)
wr.WriteLine("playerName,year,mu,sigma")
results |> Seq.iter (fun kvp ->
let playerName = kvp.Key
kvp.Value |> Seq.iter (fun kvp ->
let year = string kvp.Key
let mu = string kvp.Value.Mu
let sigma = string kvp.Value.Sigma
[playerName; year; mu; sigma] |> String.concat(",") |> wr.WriteLine
)
)
wr.Close()
/// Saves the result of a variable draw margin analysis to a CSV file
let SaveVariableDrawMarginResults (results:Dictionary<string,SortedList<int,Gaussian<_>*Gaussian<_>>>) =
if !notSave then
()
else
let wr = new System.IO.StreamWriter(!outputPath)
wr.WriteLine("playerName,year,skillMu,skillSigma,drawMarginMu,drawMarginSigma")
results |> Seq.iter (fun kvp ->
let playerName = kvp.Key
kvp.Value |> Seq.iter (fun kvp ->
let year = string kvp.Key
let skillMu = string (fst kvp.Value).Mu
let skillSigma = string (fst kvp.Value).Sigma
let drawMarginMu = string (snd kvp.Value).Mu
let drawMarginSigma = string (snd kvp.Value).Sigma
[playerName; year; skillMu; skillSigma; drawMarginMu; drawMarginSigma] |> String.concat(",") |> wr.WriteLine
)
)
wr.Close()
do
/// Some useful information on the screen
printfn "Chess Analysis program v 1.0"
printfn "2007 written by Ralf Herbrich"
printfn "Microsoft Research Ltd."
printfn ""
/// Parse the arguments
ArgParser.Parse (argspec,(fun fileName -> csvFile := fileName),"USAGE: chess [params] [<csv-file>]")
/// Allocate the chess dataset
let cds = ChessDataset ()
printfn "[Reading the dataset]"
cds.ReadFromCSVFile (!csvFile,!noGames)
match !analysis with
| SingleRun ->
/// Output some useful info and get the empirical draw probability
printfn "[Single run on the dataset using model '%s']" (ModelName())
let p = float (cds.MatchSequence |> Seq.filter (fun mtch -> mtch.Outcome = MatchOutcome.Draw) |> Seq.length) / float (cds.MatchSequence |> Seq.length)
let chessAnalysisParameters = ChessAnalysisParameters (PriorMuSkill = !muSkill * 1.0<ELOPoints>, PriorSigmaSkill = !sigmaSkill * 1.0<ELOPoints>, PriorMuDrawMargin = !muDrawMargin * 1.0<ELOPoints>, PriorSigmaDrawMargin = !sigmaDrawMargin * 1.0<ELOPoints>, Beta = !beta * 1.0<ELOPoints>, TauSkill = !tauSkill * 1.0<ELOPoints>, TauDrawMargin = !tauDrawMargin * 1.0<ELOPoints>, DrawProbability = p)
printfn "[Parameters used]"
printfn "%O" chessAnalysisParameters
match !model with
| FixedDrawMargin ->
let (results,logZ) = cds.FixedDrawMarginAnalyse chessAnalysisParameters !verbose
SaveFixedDrawMarginResults results
| FixedDrawMargin2 ->
let (results,logZ) = cds.FixedDrawMarginAnalyse2 chessAnalysisParameters !verbose
SaveFixedDrawMarginResults results
| FixedDrawMarginADFOverYears ->
let results = cds.FixedDrawMarginADFAnalyse chessAnalysisParameters true !verbose
SaveFixedDrawMarginResults results
| FixedDrawMarginADF ->
let results = cds.FixedDrawMarginADFAnalyse chessAnalysisParameters false !verbose
SaveFixedDrawMarginResults results
| VariableDrawMargin ->
let (results,logZ) = cds.VariableDrawMarginAnalyse chessAnalysisParameters !verbose
SaveVariableDrawMarginResults results
()
// SaveFixedDrawMarginResults results
| ModelSelection ->
/// Output some useful info and get the empirical draw probability
printfn "[Model selection run on the dataset using model '%s']" (ModelName())
let p = float (cds.MatchSequence |> Seq.filter (fun mtch -> mtch.Outcome = MatchOutcome.Draw) |> Seq.length) / float (cds.MatchSequence |> Seq.length)
match !model with
| FixedDrawMargin ->
let p = float (cds.MatchSequence |> Seq.filter (fun mtch -> mtch.Outcome = MatchOutcome.Draw) |> Seq.length) / float (cds.MatchSequence |> Seq.length)
/// Iterate over the range of all beta/tau values
let betaTauRange = [| for betaF in 2 .. 2 .. 20 do for tauF in 5 .. 5 .. 50 -> ((float betaF)/10.0,(float tauF)/100.0) |]
/// Map the range to the log normalisation constant
betaTauRange |> Array.iteri (fun i (betaF,tauF) ->
let chessAnalysisParameters = ChessAnalysisParameters (PriorMuSkill = !muSkill * 1.0<ELOPoints>, PriorSigmaSkill = !sigmaSkill * 1.0<ELOPoints>, Beta = !sigmaSkill*betaF * 1.0<ELOPoints>, TauSkill = !sigmaSkill*tauF * 1.0<ELOPoints>, DrawProbability = p)
let (results,logZ) = cds.FixedDrawMarginAnalyse chessAnalysisParameters false
printf "%f,%f,%f\n" betaF tauF logZ
SaveFixedDrawMarginResults results
)
| FixedDrawMargin2 ->
printfn "Not implemented!"
| FixedDrawMarginADFOverYears ->
printfn "Not implemented!"
| FixedDrawMarginADF ->
printfn "Not implemented!"
| VariableDrawMargin ->
/// Build the result schema
let p = float (cds.MatchSequence |> Seq.filter (fun mtch -> mtch.Outcome = MatchOutcome.Draw) |> Seq.length) / float (cds.MatchSequence |> Seq.length)
/// Iterate over the range of all beta/tau values
let muDrawMarginTauDrawMarginRange = [| for muDrawMarginF in 5 .. 1 .. 10 do for tauDrawMarginF in 5 .. 5 .. 20 -> ((float muDrawMarginF)/10.0,(float tauDrawMarginF)/100.0) |]
/// Map the range to the log normalisation constant
muDrawMarginTauDrawMarginRange |> Array.iteri (fun i (muDrawMarginF,tauDrawMarginF) ->
let sigmaDrawMargin = !beta / 6.0
let chessAnalysisParameters = ChessAnalysisParameters (PriorMuSkill = !muSkill * 1.0<ELOPoints>, PriorSigmaSkill = !sigmaSkill * 1.0<ELOPoints>, PriorMuDrawMargin = !beta*muDrawMarginF * 1.0<ELOPoints>, PriorSigmaDrawMargin = sigmaDrawMargin * 1.0<ELOPoints>, Beta = !beta * 1.0<ELOPoints>, TauSkill = !tauSkill * 1.0<ELOPoints>, TauDrawMargin = tauDrawMarginF*sigmaDrawMargin * 1.0<ELOPoints>, DrawProbability = p)
let (results,logZ) = cds.VariableDrawMarginAnalyse chessAnalysisParameters false
printf "%f,%f,%f\n" muDrawMarginF tauDrawMarginF logZ
/// Output the dataset to a CSV file
SaveVariableDrawMarginResults results
)