#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 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 IRegressionEnsembleModel)) 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 double ResultsBestQuality {
get { return ((DoubleValue)Results["Best Quality"].Value).Value; }
set { ((DoubleValue)Results["Best Quality"].Value).Value = value; }
}
private DataTable ResultsQualities {
get { return ((DataTable)Results["Qualities"].Value); }
}
private const string ResultsQualitiesR2 = "R²";
private const string ResultsQualitiesPearson = "Pearson";
private DataTable ResultsTargets {
get { return ((DataTable) Results["Targets"].Value); }
}
private const string ResultsTargetsReal = "Real";
protected void SetupResults() {
Results.Clear();
Results.Add(new Result("Sliding Window Movements", new IntValue(0)));
Results.Add(new Result("Best Quality", new DoubleValue(0)));
Results.Add(new Result("Qualities", new DataTable("Qualities")));
Results.Add(new Result("Targets", new DataTable("Targets")));
ResultsQualities.Rows.Add(new DataRow(ResultsQualitiesR2));
ResultsQualities.Rows.Add(new DataRow(ResultsQualitiesPearson));
ResultsTargets.Rows.Add(new DataRow(ResultsTargetsReal));
foreach (var ensemble in Ensembles) {
ResultsTargets.Rows.Add(new DataRow(ensemble.Name));
}
}
#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() {
if (ensembles == null || datastream == null) return;
base.Start();
cancellationTokenSource = new CancellationTokenSource();
stopPending = false;
if (prepared) {
SetupResults();
//prepared = false;
}
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();
}
//if(!Datastream.SlidingWindowMovementPossible) 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