#region License Information
/* HeuristicLab
* Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HeuristicLab.Analysis;
using HeuristicLab.Collections;
using HeuristicLab.Common;
using HeuristicLab.Core;
using HeuristicLab.Data;
using HeuristicLab.Optimization;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
using HeuristicLab.Problems.DataAnalysis;
namespace HeuristicLab.DatastreamAnalysis {
internal enum DatastreamAnalysisOptimizerAction {
None,
Prepare,
Start,
Stop,
Pause
}
[StorableClass]
[Item("DatastreamAnalysis Optimizer",
"The main loop for evaluating ensemble models against a incoming datastream of time series fashion.")]
[Creatable(CreatableAttribute.Categories.Algorithms)]
public class DatastreamAnalysisOptimizer : Executable, IOptimizer, IStorableContent {
#region properties
public string Filename { get; set; }
private DatastreamAnalysisOptimizerAction daoAction;
public IEnumerable NestedOptimizers { get; }
[Storable]
protected ILog log;
public ILog Log {
get { return log; }
}
[Storable]
private ResultCollection results;
public ResultCollection Results {
get { return results; }
}
//private double lastStateValue;
private double pR2Sum;
private int detectionCount;
private int evaluationCount;
private double exclusivitySum;
private double accuracySum;
private CancellationTokenSource cancellationTokenSource;
private bool stopPending;
private DateTime lastUpdateTime;
private bool prepared;
private bool finished;
[Storable]
protected int runsCounter;
[Storable]
private RunCollection runs;
public RunCollection Runs
{
get { return runs; }
protected set
{
if (value == null) throw new ArgumentNullException();
if (runs != value) {
if (runs != null) DeregisterRunsEvents();
runs = value;
if (runs != null) RegisterRunsEvents();
}
}
}
[Storable]
private IItemList ensembles;
public IItemList Ensembles {
get { return ensembles; }
set {
if (value == null || value == ensembles)
return;
if (!(value is IProxyEnsembleModel)) throw new ArgumentException("Invaid ensemble model type");
DeregisterEnsembleEvents();
ensembles = value;
RegisterEnsembleEvents();
OnEnsemblesChanged();
Prepare();
}
}
// VAR 1: datastream ~= problem data, VAR 2 (TODO): datastream = external source e.g. webservice, AMQP-Queue, etc.
[Storable]
private Datastream datastream;
public Datastream Datastream {
get { return datastream; }
set {
if (value == null || value == datastream)
return;
if(!(value is IDatastream)) throw new ArgumentException("Invalid datastream type");
DeregisterDatastreamEvents();
datastream = value;
RegisterDatastreamEvents();
OnDatastreamChanged();
Prepare();
}
}
#endregion properties
#region results properties
private int ResultsSlidingWindowMovements {
get { return ((IntValue)Results["Sliding Window Movements"].Value).Value; }
set { ((IntValue)Results["Sliding Window Movements"].Value).Value = value; }
}
private DataTable ResultsQualities {
get { return ((DataTable)Results["Qualities 1"].Value); }
}
private DataTable ResultsPeakQualities {
get { return ((DataTable) Results["Qualities 2"].Value); }
}
private const string ResultsQualitiesMSE = "Mean squared error";
private const string ResultsQualitiesPR2 = "Pearson R²";
private DataTable ResultsTargets {
get { return ((DataTable) Results["Targets"].Value); }
}
private DataTable ResultsStateDetection {
get { return ((DataTable) Results["State Detection"].Value);}
}
private const string ResultsTargetsReal = "Real";
private DataBarSet ResultsSWQualitiesBars {
get { return (DataBarSet) Results["Ensemble Comparison [SW-Quality]"].Value; }
}
private DataBarSet ResultsSWVotingBars {
get { return (DataBarSet) Results["Ensemble Comparison [SW-Voting]"].Value; }
}
private DataBarSet ResultsSonarQualitiesBars {
get { return (DataBarSet)Results["Ensemble Comparison [Sonar-Quality]"].Value; }
}
private DataBarSet ResultsSWPeakQualitiesBars {
get { return (DataBarSet)Results["Ensemble Comparison [SW-PeakQuality]"].Value; }
}
private double ResultsMeanPR2 {
get { return ((DoubleValue) Results["Mean PR2"].Value).Value; }
set { ((DoubleValue)Results["Mean PR2"].Value).Value = value; }
}
private double ResultsDetectionAccuracy {
get { return ((DoubleValue)Results["Detection Accuracy"].Value).Value; }
set { ((DoubleValue)Results["Detection Accuracy"].Value).Value = value; }
}
private double ResultsDetectionExclusivity {
get { return ((DoubleValue)Results["Detection Exclusivity"].Value).Value; }
set { ((DoubleValue)Results["Detection Exclusivity"].Value).Value = value; }
}
//private int ResultsTrueDetectionCount {
// get { return ((IntValue)Results["True Detection Count"].Value).Value; }
// set { ((IntValue)Results["True Detection Count"].Value).Value = value; }
//}
//private int ResultsFalseDetectionCount {
// get { return ((IntValue)Results["False Detection Count"].Value).Value; }
// set { ((IntValue)Results["False Detection Count"].Value).Value = value; }
//}
protected void SetupResults() {
evaluationCount = 0;
//lastStateValue = 0.0;
pR2Sum = 0.0;
exclusivitySum = 0.0;
accuracySum = 0.0;
detectionCount = 0;
Results.Clear();
Results.Add(new Result("Sliding Window Movements", new IntValue(0)));
Results.Add(new Result("Qualities 1", new DataTable("Average Pearson R²")));
Results.Add(new Result("Qualities 2", new DataTable("Peak Pearson R²")));
Results.Add(new Result("Targets", new DataTable("Targets")));
Results.Add(new Result("State Detection", new DataTable("State Detection")));
Results.Add(new Result("Ensemble Comparison [SW-Quality]", new DataBarSet("Ensemble Comparison [SW-Quality]")));
Results.Add(new Result("Ensemble Comparison [SW-Voting]", new DataBarSet("Ensemble Comparison [SW-Voting]")));
Results.Add(new Result("Ensemble Comparison [Sonar-Quality]", new DataBarSet("Ensemble Comparison [Sonar-Quality]")));
Results.Add(new Result("Ensemble Comparison [SW-PeakQuality]", new DataBarSet("Ensemble Comparison [SW-PeakQuality]")));
Results.Add(new Result("Mean PR2", new DoubleValue()));
Results.Add(new Result("Detection Accuracy", new DoubleValue()));
Results.Add(new Result("Detection Exclusivity", new DoubleValue()));
ResultsTargets.Rows.Add(new DataRow(ResultsTargetsReal));
foreach (var ensemble in Ensembles) {
// targets table
ResultsTargets.Rows.Add(new DataRow(ensemble.Name));
ResultsStateDetection.Rows.Add(new DataRow(ensemble.Name));
// qualities (series)
//ResultsQualities.Rows.Add(new DataRow(ensemble.Name + " - " + ResultsQualitiesMSE));
ResultsQualities.Rows.Add(new DataRow(ensemble.Name));
ResultsPeakQualities.Rows.Add(new DataRow(ensemble.Name));
// qualities (bars)
ResultsSWQualitiesBars.Bars.Add(new DataBar(ensemble.Name, ensemble.QualityThreshold.Start, ensemble.QualityThreshold.End));
// voting (bars)
ResultsSWVotingBars.Bars.Add(new DataBar(ensemble.Name, ensemble.ConfidenceThreshold.Start, ensemble.ConfidenceThreshold.End));
// sonar quality (bars)
ResultsSonarQualitiesBars.Bars.Add(new DataBar(ensemble.Name, ensemble.QualityThreshold.Start, ensemble.QualityThreshold.End));
// quality peaks (bars)
ResultsSWPeakQualitiesBars.Bars.Add(new DataBar(ensemble.Name, ensemble.QualityThreshold.Start, ensemble.QualityThreshold.End));
}
}
#endregion
#region constructors, cloner,...
public DatastreamAnalysisOptimizer() : base() {
name = "Datastream Analysis";
log = new Log();
results = new ResultCollection();
ensembles = new ItemList();
datastream = new Datastream();
runsCounter = 0;
runs = new RunCollection();
Initialize();
}
[StorableConstructor]
protected DatastreamAnalysisOptimizer(bool deserializing) : base(deserializing) {
}
[StorableHook(HookType.AfterDeserialization)]
private void AfterDeserialization() {
Initialize();
}
protected DatastreamAnalysisOptimizer(DatastreamAnalysisOptimizer original, Cloner cloner) : base(original, cloner) {
name = original.name;
log = cloner.Clone(original.log);
results = cloner.Clone(original.results);
ensembles = (ItemList) original.Ensembles.Clone(cloner);
datastream = (Datastream) original.Datastream.Clone(cloner);
runsCounter = original.runsCounter;
runs = cloner.Clone(original.runs);
Initialize();
}
public override IDeepCloneable Clone(Cloner cloner) {
return new DatastreamAnalysisOptimizer(this, cloner);
}
private void Initialize() {
if (runs != null) RegisterRunsEvents();
if (datastream != null) RegisterDatastreamEvents();
if (ensembles != null) RegisterEnsembleEvents();
}
#endregion
#region control actions
public override void Prepare() {
if (ensembles == null || ensembles.Count == 0 || datastream == null || !datastream.SlidingWindowEvaluationPossible) return;
//if (ensembles.SelectMany(x => x.Models).Count() == 0) return;
base.Prepare();
OnPrepared();
}
public void Prepare(bool clearRuns) {
if (ensembles == null || ensembles.Count == 0 || datastream == null || !datastream.SlidingWindowEvaluationPossible) return;
base.Prepare();
if (clearRuns) runs.Clear();
OnPrepared();
}
public override void Start(CancellationToken cancellationToken) {
base.Start(cancellationToken);
if (ensembles == null || datastream == null) return;
cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
stopPending = false;
if (prepared) {
SetupResults();
Datastream.InitializeState();
}
Task task = Task.Factory.StartNew(Run, cancellationTokenSource.Token, cancellationTokenSource.Token);
task.ContinueWith(t => {
try {
t.Wait();
}
catch (AggregateException ex) {
try {
ex.Flatten().Handle(x => x is OperationCanceledException);
} catch (AggregateException remaining) {
if(remaining.InnerExceptions.Count == 1) OnExceptionOccurred(remaining.InnerExceptions[0]);
else OnExceptionOccurred(remaining);
}
}
cancellationTokenSource.Dispose();
cancellationTokenSource = null;
// handle stop/pause
if (stopPending || finished) {
OnStopped();
} else {
OnPaused();
}
});
}
public override void Pause() {
if (ensembles == null || datastream == null) return;
base.Pause();
cancellationTokenSource.Cancel();
}
public override void Stop() {
if (ensembles == null || datastream == null) return;
base.Stop();
if (ExecutionState == ExecutionState.Paused) {
OnStopped();
} else {
stopPending = true;
cancellationTokenSource.Cancel();
}
}
protected override void OnPrepared() {
ExecutionTime = TimeSpan.Zero;
foreach (IStatefulItem statefulItem in this.GetObjectGraphObjects(new HashSet