#region License Information
/* HeuristicLab
* Copyright (C) 2002-2008 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.Text;
using System.Xml;
using HeuristicLab.Common;
namespace HeuristicLab.Core {
///
/// The base class for all operators.
///
public abstract class OperatorBase : ConstrainedItemBase, IOperator {
private string myName;
///
/// Gets or sets the name of the operator.
///
/// Calls in the setter.
public string Name {
get { return myName; }
set {
if (myName != value) {
myName = value;
OnNameChanged();
}
}
}
///
/// Gets the description of the current operator.
///
/// Returns "No operator description available" if the method is not overriden.
public virtual string Description {
get { return "No operator description available."; }
}
///
/// Flag whether the current instance has been canceled.
///
protected bool myCanceled;
///
public bool Canceled {
get { return myCanceled; }
}
private bool myBreakpoint;
///
/// Calls in the setter.
public bool Breakpoint {
get { return myBreakpoint; }
set {
if (value != myBreakpoint) {
myBreakpoint = value;
OnBreakpointChanged();
}
}
}
private List mySubOperators;
///
/// Gets a list of all suboperators.
/// Returns the suboperators read-only!
///
public virtual IList SubOperators {
get { return mySubOperators.AsReadOnly(); }
}
private Dictionary myVariableInfos;
///
public virtual ICollection VariableInfos {
get { return myVariableInfos.Values; }
}
private Dictionary myVariables;
///
public virtual ICollection Variables {
get { return myVariables.Values; }
}
///
/// Initializes a new instance of setting the breakpoint flag and
/// the canceled flag to false and the name of the operator to the type name.
///
protected OperatorBase() {
myName = this.GetType().Name;
myCanceled = false;
myBreakpoint = false;
mySubOperators = new List();
myVariableInfos = new Dictionary();
myVariables = new Dictionary();
}
///
/// Clones the current instance (deep clone).
///
/// Clones also sub operators, variables and variable infos.
/// Dictionary of all already cloned objects. (Needed to avoid cycles.)
/// The cloned object as .
public override object Clone(IDictionary clonedObjects) {
OperatorBase clone = (OperatorBase)base.Clone(clonedObjects);
clone.myName = Name;
clone.mySubOperators.Clear();
for (int i = 0; i < SubOperators.Count; i++)
clone.AddSubOperator((IOperator)Auxiliary.Clone(SubOperators[i], clonedObjects));
clone.myVariableInfos.Clear();
foreach (IVariableInfo variableInfo in myVariableInfos.Values)
clone.AddVariableInfo((IVariableInfo)Auxiliary.Clone(variableInfo, clonedObjects));
clone.myVariables.Clear();
foreach (IVariable variable in myVariables.Values)
clone.AddVariable((IVariable)Auxiliary.Clone(variable, clonedObjects));
return clone;
}
///
/// Creates a new instance of to represent the current operator
/// visually.
///
/// The created view as .
public override IView CreateView() {
return new OperatorBaseView(this);
}
#region SubOperator Methods
///
/// The sub operator to add.
/// Calls .
public virtual void AddSubOperator(IOperator subOperator) {
mySubOperators.Add(subOperator);
OnSubOperatorAdded(subOperator, mySubOperators.Count - 1);
}
///
/// The sub operator to add.
/// Calls .
public virtual bool TryAddSubOperator(IOperator subOperator) {
mySubOperators.Add(subOperator);
if (IsValid()) {
OnSubOperatorAdded(subOperator, mySubOperators.Count - 1);
return true;
} else {
mySubOperators.RemoveAt(mySubOperators.Count - 1);
return false;
}
}
///
/// The sub operator to add.
/// Calls .
public virtual bool TryAddSubOperator(IOperator subOperator, out ICollection violatedConstraints) {
mySubOperators.Add(subOperator);
if (IsValid(out violatedConstraints)) {
OnSubOperatorAdded(subOperator, mySubOperators.Count - 1);
return true;
} else {
mySubOperators.RemoveAt(mySubOperators.Count - 1);
return false;
}
}
///
/// The sub operator to add.
/// Calls .
public virtual void AddSubOperator(IOperator subOperator, int index) {
mySubOperators.Insert(index, subOperator);
OnSubOperatorAdded(subOperator, index);
}
///
/// The sub operator to add.
/// Calls .
public virtual bool TryAddSubOperator(IOperator subOperator, int index) {
mySubOperators.Insert(index, subOperator);
if (IsValid()) {
OnSubOperatorAdded(subOperator, index);
return true;
} else {
mySubOperators.RemoveAt(index);
return false;
}
}
///
/// The sub operator to add.
/// Calls .
public virtual bool TryAddSubOperator(IOperator subOperator, int index, out ICollection violatedConstraints) {
mySubOperators.Insert(index, subOperator);
if (IsValid(out violatedConstraints)) {
OnSubOperatorAdded(subOperator, index);
return true;
} else {
mySubOperators.RemoveAt(index);
return false;
}
}
///
/// Calls .
public virtual void RemoveSubOperator(int index) {
IOperator op = mySubOperators[index];
mySubOperators.RemoveAt(index);
OnSubOperatorRemoved(op, index);
}
///
/// Calls .
public virtual bool TryRemoveSubOperator(int index) {
IOperator op = mySubOperators[index];
mySubOperators.RemoveAt(index);
if (IsValid()) {
OnSubOperatorRemoved(op, index);
return true;
} else {
mySubOperators.Insert(index, op);
return false;
}
}
///
/// Calls .
public virtual bool TryRemoveSubOperator(int index, out ICollection violatedConstraints) {
IOperator op = mySubOperators[index];
mySubOperators.RemoveAt(index);
if (IsValid(out violatedConstraints)) {
OnSubOperatorRemoved(op, index);
return true;
} else {
mySubOperators.Insert(index, op);
return false;
}
}
#endregion
#region VariableInfo Methods
///
public virtual IVariableInfo GetVariableInfo(string formalName) {
IVariableInfo info;
if (myVariableInfos.TryGetValue(formalName, out info))
return info;
else
return null;
}
///
/// Calls .
public virtual void AddVariableInfo(IVariableInfo variableInfo) {
myVariableInfos.Add(variableInfo.FormalName, variableInfo);
OnVariableInfoAdded(variableInfo);
}
///
/// Calls .
public virtual bool TryAddVariableInfo(IVariableInfo variableInfo) {
myVariableInfos.Add(variableInfo.FormalName, variableInfo);
if (IsValid()) {
OnVariableInfoAdded(variableInfo);
return true;
} else {
myVariableInfos.Remove(variableInfo.FormalName);
return false;
}
}
///
/// Calls .
public virtual bool TryAddVariableInfo(IVariableInfo variableInfo, out ICollection violatedConstraints) {
myVariableInfos.Add(variableInfo.FormalName, variableInfo);
if (IsValid(out violatedConstraints)) {
OnVariableInfoAdded(variableInfo);
return true;
} else {
myVariableInfos.Remove(variableInfo.FormalName);
return false;
}
}
///
/// Calls .
public virtual void RemoveVariableInfo(string formalName) {
IVariableInfo variableInfo;
if (myVariableInfos.TryGetValue(formalName, out variableInfo)) {
myVariableInfos.Remove(formalName);
OnVariableInfoRemoved(variableInfo);
}
}
///
/// Calls .
public virtual bool TryRemoveVariableInfo(string formalName) {
IVariableInfo variableInfo;
if (myVariableInfos.TryGetValue(formalName, out variableInfo)) {
myVariableInfos.Remove(formalName);
if (IsValid()) {
OnVariableInfoRemoved(variableInfo);
return true;
} else {
myVariableInfos.Add(formalName, variableInfo);
return false;
}
}
return true;
}
///
/// Calls .
public virtual bool TryRemoveVariableInfo(string formalName, out ICollection violatedConstraints) {
IVariableInfo variableInfo;
if (myVariableInfos.TryGetValue(formalName, out variableInfo)) {
myVariableInfos.Remove(formalName);
if (IsValid(out violatedConstraints)) {
OnVariableInfoRemoved(variableInfo);
return true;
} else {
myVariableInfos.Add(formalName, variableInfo);
return false;
}
}
violatedConstraints = new List();
return true;
}
#endregion
#region Variable Methods
///
public virtual IVariable GetVariable(string name) {
IVariable variable;
if (myVariables.TryGetValue(name, out variable))
return variable;
else
return null;
}
///
/// Calls and adds NameChanging and NameChanged
/// event handlers.
public virtual void AddVariable(IVariable variable) {
myVariables.Add(variable.Name, variable);
variable.NameChanging += new EventHandler>(Variable_NameChanging);
variable.NameChanged += new EventHandler(Variable_NameChanged);
OnVariableAdded(variable);
}
///
/// Calls and adds NameChanging and NameChanged
/// event handlers.
public virtual bool TryAddVariable(IVariable variable) {
myVariables.Add(variable.Name, variable);
if (IsValid()) {
variable.NameChanging += new EventHandler>(Variable_NameChanging);
variable.NameChanged += new EventHandler(Variable_NameChanged);
OnVariableAdded(variable);
return true;
} else {
myVariableInfos.Remove(variable.Name);
return false;
}
}
///
/// Calls and adds NameChanging and NameChanged
/// event handlers.
public virtual bool TryAddVariable(IVariable variable, out ICollection violatedConstraints) {
myVariables.Add(variable.Name, variable);
if (IsValid(out violatedConstraints)) {
variable.NameChanging += new EventHandler>(Variable_NameChanging);
variable.NameChanged += new EventHandler(Variable_NameChanged);
OnVariableAdded(variable);
return true;
} else {
myVariableInfos.Remove(variable.Name);
return false;
}
}
///
/// Calls and removes NameChanging and NameChanged
/// event handlers.
public virtual void RemoveVariable(string name) {
IVariable variable;
if (myVariables.TryGetValue(name, out variable)) {
variable.NameChanging -= new EventHandler>(Variable_NameChanging);
variable.NameChanged -= new EventHandler(Variable_NameChanged);
myVariables.Remove(name);
OnVariableRemoved(variable);
}
}
///
/// Calls and removes NameChanging and NameChanged
/// event handlers.
public virtual bool TryRemoveVariable(string name) {
IVariable variable;
if (myVariables.TryGetValue(name, out variable)) {
myVariables.Remove(name);
if (IsValid()) {
variable.NameChanging -= new EventHandler>(Variable_NameChanging);
variable.NameChanged -= new EventHandler(Variable_NameChanged);
OnVariableRemoved(variable);
return true;
} else {
myVariables.Add(name, variable);
return false;
}
}
return true;
}
///
/// Calls and removes NameChanging and NameChanged
/// event handlers.
public virtual bool TryRemoveVariable(string name, out ICollection violatedConstraints) {
IVariable variable;
if (myVariables.TryGetValue(name, out variable)) {
myVariables.Remove(name);
if (IsValid(out violatedConstraints)) {
variable.NameChanging -= new EventHandler>(Variable_NameChanging);
variable.NameChanged -= new EventHandler(Variable_NameChanged);
OnVariableRemoved(variable);
return true;
} else {
myVariables.Add(name, variable);
return false;
}
}
violatedConstraints = new List();
return true;
}
private void Variable_NameChanging(object sender, CancelEventArgs e) {
e.Cancel = myVariables.ContainsKey(e.Value);
}
private void Variable_NameChanged(object sender, EventArgs e) {
IVariable variable = (IVariable)sender;
string oldName = null;
foreach (KeyValuePair element in myVariables) {
if (element.Value == variable)
oldName = element.Key;
}
myVariables.Remove(oldName);
myVariables.Add(variable.Name, variable);
}
///
/// Calls
/// with throwOnError set to false.
public T GetVariableValue(string formalName, IScope scope, bool recursiveLookup) where T : class, IItem {
return GetVariableValue(formalName, scope, recursiveLookup, true);
}
///
/// Calls
/// .
public T GetVariableValue(string formalName, IScope scope, bool recursiveLookup, bool throwOnError) where T : class, IItem {
return (T)GetVariableValue(formalName, scope, recursiveLookup, throwOnError);
}
///
/// Calls
/// with throwOnError set to false.
public IItem GetVariableValue(string formalName, IScope scope, bool recursiveLookup) {
return GetVariableValue(formalName, scope, recursiveLookup, true);
}
///
public virtual IItem GetVariableValue(string formalName, IScope scope, bool recursiveLookup, bool throwOnError) {
IVariableInfo info = GetVariableInfo(formalName);
if (info.Local) {
IVariable variable;
if (myVariables.TryGetValue(info.ActualName, out variable))
return variable.Value;
else {
if (throwOnError)
throw new ArgumentException("Variable " + info.ActualName + " not found");
else
return null;
}
} else {
return scope.GetVariableValue(formalName, recursiveLookup, throwOnError);
}
}
#endregion
///
public virtual IOperation Execute(IScope scope) {
myCanceled = false;
foreach (IVariableInfo variableInfo in VariableInfos)
scope.AddAlias(variableInfo.FormalName, variableInfo.ActualName);
IOperation next = Apply(scope);
foreach (IVariableInfo variableInfo in VariableInfos)
scope.RemoveAlias(variableInfo.FormalName);
OnExecuted();
return next;
}
///
/// Sets property to true.
public virtual void Abort() {
myCanceled = true;
}
///
/// Performs the current operator on the specified .
///
/// The scope where to execute the operator
/// null.
public virtual IOperation Apply(IScope scope) {
return null;
}
///
public event EventHandler NameChanged;
///
/// Fires a new NameChanged event.
///
protected virtual void OnNameChanged() {
if (NameChanged != null) {
NameChanged(this, new EventArgs());
}
}
///
public event EventHandler BreakpointChanged;
///
/// Fires a new BreakpointChanged event.
///
protected virtual void OnBreakpointChanged() {
if (BreakpointChanged != null) {
BreakpointChanged(this, new EventArgs());
}
}
///
public event EventHandler> SubOperatorAdded;
///
/// Fires a new SubOperatorAdded event.
///
/// The sub operator that has been added.
/// The position where the operator has been added.
protected virtual void OnSubOperatorAdded(IOperator subOperator, int index) {
if (SubOperatorAdded != null)
SubOperatorAdded(this, new EventArgs(subOperator, index));
}
///
public event EventHandler> SubOperatorRemoved;
///
/// Fires a new SubOperatorRemoved event.
///
/// The sub operator that has been removed.
/// The position where the operator has been removed.
protected virtual void OnSubOperatorRemoved(IOperator subOperator, int index) {
if (SubOperatorRemoved != null)
SubOperatorRemoved(this, new EventArgs(subOperator, index));
}
///
public event EventHandler> VariableInfoAdded;
///
/// Fires a new VariableInfoAdded event.
///
/// The variable info that has been added.
protected virtual void OnVariableInfoAdded(IVariableInfo variableInfo) {
if (VariableInfoAdded != null)
VariableInfoAdded(this, new EventArgs(variableInfo));
}
///
public event EventHandler> VariableInfoRemoved;
///
/// Fires a new VariableInfoRemoved event.
///
/// The variable info that has been removed.
protected virtual void OnVariableInfoRemoved(IVariableInfo variableInfo) {
if (VariableInfoRemoved != null)
VariableInfoRemoved(this, new EventArgs(variableInfo));
}
///
public event EventHandler> VariableAdded;
///
/// Fires a new VariableAdded event.
///
/// The variable that has been added.
protected virtual void OnVariableAdded(IVariable variable) {
if (VariableAdded != null)
VariableAdded(this, new EventArgs(variable));
}
///
public event EventHandler> VariableRemoved;
///
/// Fires a new VariableRemoved event.
///
/// The variable that has been removed
protected virtual void OnVariableRemoved(IVariable variable) {
if (VariableRemoved != null)
VariableRemoved(this, new EventArgs(variable));
}
///
public event EventHandler Executed;
///
/// Fires a new Executed event.
///
protected virtual void OnExecuted() {
if (Executed != null) {
Executed(this, new EventArgs());
}
}
#region Persistence Methods
///
/// Saves the current instance as in the specified .
///
///
/// Calls of base class .
///
A quick overview how the single elements of the current instance are saved:
///
/// -
/// Name:
/// Saved as an with the name Name.
///
/// -
/// Breakpoint:
/// Is only saved if it set to true.
/// Saved as an with the name Breakpoint.
///
/// -
/// Sub operators:
/// Saved as child node with tag name SubOperators. All sub operators are themselves
/// saved as child nodes.
///
/// -
/// Variable infos:
/// Saved as child node with tag name VariableInfos. All variable infos are themselves
/// saved as child nodes.
///
/// -
/// Variables:
/// Saved as child node with tag name Variables. All variables are themselves
/// saved as child nodes.
///
///
///
/// The (tag)name of the .
/// The where to save the data.
/// The dictionary of all already persisted objects. (Needed to avoid cycles.)
/// The saved .
public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary persistedObjects) {
XmlNode node = base.GetXmlNode(name, document, persistedObjects);
XmlAttribute nameAttribute = document.CreateAttribute("Name");
nameAttribute.Value = Name;
node.Attributes.Append(nameAttribute);
if (Breakpoint) {
XmlAttribute breakpointAttribute = document.CreateAttribute("Breakpoint");
breakpointAttribute.Value = Breakpoint.ToString();
node.Attributes.Append(breakpointAttribute);
}
XmlNode subOperatorsNode = document.CreateNode(XmlNodeType.Element, "SubOperators", null);
for (int i = 0; i < SubOperators.Count; i++)
subOperatorsNode.AppendChild(PersistenceManager.Persist(SubOperators[i], document, persistedObjects));
node.AppendChild(subOperatorsNode);
XmlNode infosNode = document.CreateNode(XmlNodeType.Element, "VariableInfos", null);
foreach (IVariableInfo info in myVariableInfos.Values)
infosNode.AppendChild(PersistenceManager.Persist(info, document, persistedObjects));
node.AppendChild(infosNode);
XmlNode variablesNode = document.CreateNode(XmlNodeType.Element, "Variables", null);
foreach (IVariable variable in myVariables.Values)
variablesNode.AppendChild(PersistenceManager.Persist(variable, document, persistedObjects));
node.AppendChild(variablesNode);
return node;
}
///
/// Loads the persisted operation from the specified .
///
/// Calls of base class
/// .
/// For informations how the different elements must be saved please see .
/// The where the operation is saved.
/// A dictionary of all already restored objects. (Needed to avoid cycles.)
public override void Populate(XmlNode node, IDictionary restoredObjects) {
base.Populate(node, restoredObjects);
myName = node.Attributes["Name"].Value;
if (node.Attributes["Breakpoint"] != null)
myBreakpoint = bool.Parse(node.Attributes["Breakpoint"].Value);
XmlNode subOperatorsNode = node.SelectSingleNode("SubOperators");
for (int i = 0; i < subOperatorsNode.ChildNodes.Count; i++)
AddSubOperator((IOperator)PersistenceManager.Restore(subOperatorsNode.ChildNodes[i], restoredObjects));
XmlNode infosNode = node.SelectSingleNode("VariableInfos");
myVariableInfos.Clear();
foreach (XmlNode infoNode in infosNode.ChildNodes)
AddVariableInfo((IVariableInfo)PersistenceManager.Restore(infoNode, restoredObjects));
XmlNode variablesNode = node.SelectSingleNode("Variables");
myVariables.Clear();
foreach (XmlNode variableNode in variablesNode.ChildNodes)
AddVariable((IVariable)PersistenceManager.Restore(variableNode, restoredObjects));
}
#endregion
}
}