#region License Information
/* HeuristicLab
* Copyright (C) 2002-2010 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.Drawing;
using System.Threading;
using HeuristicLab.Common;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
namespace HeuristicLab.Core {
///
/// Base class to represent an engine, which is an interpreter, holding the code, the data and
/// the actual state, which is the runtime stack and a pointer onto the next operation. It represents
/// one execution and can handle parallel executions.
///
[Item("Engine", "A base class for engines.")]
public abstract class Engine : Item, IEngine {
public override Image ItemImage {
get { return HeuristicLab.Common.Resources.VS2008ImageLibrary.Event; }
}
private OperatorGraph operatorGraph;
///
/// Gets or sets the current operator graph.
///
[Storable]
public OperatorGraph OperatorGraph {
get { return operatorGraph; }
set {
if (value == null) throw new ArgumentNullException();
if (value != operatorGraph) {
if (operatorGraph != null) operatorGraph.InitialOperatorChanged -= new EventHandler(operatorGraph_InitialOperatorChanged);
operatorGraph = value;
if (operatorGraph != null) operatorGraph.InitialOperatorChanged += new EventHandler(operatorGraph_InitialOperatorChanged);
OnOperatorGraphChanged();
Prepare();
}
}
}
///
/// Field of the current instance that represent the global scope.
///
[Storable]
private IScope globalScope;
///
/// Gets the current global scope.
///
public IScope GlobalScope {
get { return globalScope; }
}
[Storable]
private TimeSpan executionTime;
///
/// Gets or sets the execution time.
///
/// Calls in the setter.
public TimeSpan ExecutionTime {
get { return executionTime; }
protected set {
executionTime = value;
OnExecutionTimeChanged();
}
}
///
/// Field of the current instance that represent the execution stack.
///
[Storable]
private Stack executionStack;
///
/// Gets the current execution stack.
///
protected Stack ExecutionStack {
get { return executionStack; }
}
///
/// Flag of the current instance whether it is currently running.
///
private bool running;
///
/// Gets information whether the instance is currently running.
///
public bool Running {
get { return running; }
}
///
/// Flag of the current instance whether it is canceled.
///
private bool canceled;
///
/// Gets information whether the instance is currently canceled.
///
protected bool Canceled {
get { return canceled; }
private set {
if (canceled != value) {
canceled = value;
OnCanceledChanged();
}
}
}
///
/// Gets information whether the instance has already terminated.
///
public bool Finished {
get { return executionStack.Count == 0; }
}
///
/// Initializes a new instance of with a new global scope.
///
protected Engine() {
globalScope = new Scope("Global");
executionStack = new Stack();
OperatorGraph = new OperatorGraph();
}
///
/// Clones the current instance (deep clone).
///
/// Deep clone through method of helper class
/// .
/// Dictionary of all already clone objects. (Needed to avoid cycles.)
/// The cloned object as .
public override IDeepCloneable Clone(Cloner cloner) {
Engine clone = (Engine)base.Clone(cloner);
clone.OperatorGraph = (OperatorGraph)cloner.Clone(operatorGraph);
clone.globalScope = (Scope)cloner.Clone(globalScope);
clone.executionTime = executionTime;
IOperation[] contexts = executionStack.ToArray();
for (int i = contexts.Length - 1; i >= 0; i--)
clone.executionStack.Push((IOperation)cloner.Clone(contexts[i]));
clone.running = running;
clone.canceled = canceled;
return clone;
}
public void Prepare(IOperation initialOperation) {
Canceled = false;
running = false;
globalScope.Clear();
ExecutionTime = new TimeSpan();
executionStack.Clear();
if (initialOperation != null)
executionStack.Push(initialOperation);
OnPrepared();
}
///
/// Sets myCanceled and myRunning to false. The global scope is cleared,
/// the execution time is reset, the execution stack is cleared and a new
/// with the initial operator is added.
/// Calls .
public void Prepare() {
if (OperatorGraph.InitialOperator != null)
Prepare(new ExecutionContext(null, OperatorGraph.InitialOperator, GlobalScope));
}
///
/// Calls
/// of class .
public void Start() {
running = true;
Canceled = false;
ThreadPool.QueueUserWorkItem(new WaitCallback(Run), null);
}
///
/// Calls
/// of class .
public void Step() {
running = true;
Canceled = false;
ThreadPool.QueueUserWorkItem(new WaitCallback(RunStep), null);
}
///
/// Sets the protected flag myCanceled to true.
public void Stop() {
Canceled = true;
}
private void Run(object state) {
OnStarted();
DateTime start = DateTime.Now;
DateTime end;
while ((!Canceled) && (!Finished)) {
ProcessNextOperator();
end = DateTime.Now;
ExecutionTime += end - start;
start = end;
}
ExecutionTime += DateTime.Now - start;
running = false;
OnStopped();
}
private void RunStep(object state) {
OnStarted();
DateTime start = DateTime.Now;
if ((!Canceled) && (!Finished))
ProcessNextOperator();
ExecutionTime += DateTime.Now - start;
running = false;
OnStopped();
}
///
/// Performs the next operation.
///
protected abstract void ProcessNextOperator();
private void operatorGraph_InitialOperatorChanged(object sender, EventArgs e) {
Prepare();
}
///
/// Occurs when the operator graph was changed.
///
public event EventHandler OperatorGraphChanged;
///
/// Fires a new OperatorGraphChanged event.
///
protected virtual void OnOperatorGraphChanged() {
if (OperatorGraphChanged != null)
OperatorGraphChanged(this, EventArgs.Empty);
}
///
/// Occurs when the execution time changed.
///
public event EventHandler ExecutionTimeChanged;
///
/// Fires a new ExecutionTimeChanged event.
///
protected virtual void OnExecutionTimeChanged() {
if (ExecutionTimeChanged != null)
ExecutionTimeChanged(this, EventArgs.Empty);
}
///
/// Occurs when the execution is prepared for a new run.
///
public event EventHandler Prepared;
///
/// Fires a new Prepared event.
///
protected virtual void OnPrepared() {
if (Prepared != null)
Prepared(this, EventArgs.Empty);
}
///
/// Occurs when the execution is executed.
///
public event EventHandler Started;
///
/// Fires a new Started event.
///
protected virtual void OnStarted() {
if (Started != null)
Started(this, EventArgs.Empty);
}
///
/// Occurs when the execution is finished.
///
public event EventHandler Stopped;
///
/// Fires a new Stopped event.
///
protected virtual void OnStopped() {
if (Stopped != null)
Stopped(this, EventArgs.Empty);
}
protected virtual void OnCanceledChanged() { }
///
/// Occurs when an exception occured during the execution.
///
public event EventHandler> ExceptionOccurred;
///
/// Aborts the execution and fires a new ExceptionOccurred event.
///
/// The exception that was thrown.
protected virtual void OnExceptionOccurred(Exception exception) {
if (ExceptionOccurred != null)
ExceptionOccurred(this, new EventArgs(exception));
}
}
}