#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 HeuristicLab.Data;
using HeuristicLab.Core;
using System.Xml;
using HeuristicLab.DataAnalysis;
namespace HeuristicLab.Functions {
public abstract class FunctionBase : OperatorBase, IFunction {
private List subFunctions;
// instance subfunctions
public IList SubFunctions {
get {
return subFunctions;
}
}
// instance variables
private List variables;
public ICollection LocalVariables {
get { return variables.AsReadOnly(); }
}
// reference to the 'type' of the function
private FunctionBase metaObject;
public IFunction MetaObject {
get { return metaObject; }
}
public FunctionBase() {
metaObject = this; // (FunctionBase)Activator.CreateInstance(this.GetType());
AddVariableInfo(new VariableInfo("Dataset", "Dataset from which to read samples", typeof(DoubleMatrixData), VariableKind.In));
AddVariableInfo(new VariableInfo("SampleIndex", "Gives the row index from which to read the sample", typeof(IntData), VariableKind.In));
AddVariableInfo(new VariableInfo("Result", "The result of the evaluation of the function", typeof(DoubleData), VariableKind.Out));
subFunctions = new List();
variables = new List();
}
public FunctionBase(FunctionBase source, IDictionary clonedObjects)
: base() {
this.metaObject = source.metaObject;
variables = new List();
subFunctions = new List();
foreach (IFunction subFunction in source.SubFunctions) {
subFunctions.Add((IFunction)Auxiliary.Clone(subFunction, clonedObjects));
}
foreach (IVariable variable in source.variables) {
variables.Add((IVariable)Auxiliary.Clone(variable, clonedObjects));
}
}
public abstract double Evaluate(Dataset dataset, int sampleIndex);
public override IOperation Apply(IScope scope) {
DoubleData result = this.GetVariableValue("Result", scope, false);
Dataset dataset = GetVariableValue("Dataset", scope, true);
IntData sampleIndex = GetVariableValue("SampleIndex", scope, true);
result.Data = Evaluate(dataset, sampleIndex.Data);
return null;
}
public virtual void Accept(IFunctionVisitor visitor) {
visitor.Visit(this);
}
public override void AddSubOperator(IOperator subOperator) {
subFunctions.Add((IFunction)subOperator);
}
public override bool TryAddSubOperator(IOperator subOperator) {
subFunctions.Add((IFunction)subOperator);
bool valid = IsValid();
if (!valid) {
subFunctions.RemoveAt(subFunctions.Count - 1);
}
return valid;
}
public override bool TryAddSubOperator(IOperator subOperator, int index) {
subFunctions.Insert(index, (IFunction)subOperator);
bool valid = IsValid();
if (!valid) {
subFunctions.RemoveAt(index);
}
return valid;
}
public override bool TryAddSubOperator(IOperator subOperator, int index, out ICollection violatedConstraints) {
subFunctions.Insert(index, (IFunction)subOperator);
bool valid = IsValid(out violatedConstraints);
if (!valid) {
subFunctions.RemoveAt(index);
}
return valid;
}
public override bool TryAddSubOperator(IOperator subOperator, out ICollection violatedConstraints) {
subFunctions.Add((IFunction)subOperator);
bool valid = IsValid(out violatedConstraints);
if (!valid) {
subFunctions.RemoveAt(subFunctions.Count - 1);
}
return valid;
}
public override void AddSubOperator(IOperator subOperator, int index) {
subFunctions.Insert(index, (IFunction)subOperator);
}
public override void RemoveSubOperator(int index) {
if (index >= subFunctions.Count) throw new InvalidOperationException();
subFunctions.RemoveAt(index);
}
public override IList SubOperators {
get { return subFunctions.ConvertAll(f => (IOperator)f); }
}
public override ICollection Variables {
get {
List mergedVariables = new List(variables);
if (this == metaObject) {
foreach (IVariable variable in base.Variables) {
if (!IsLocalVariable(variable.Name)) {
mergedVariables.Add(variable);
}
}
} else {
foreach (IVariable variable in metaObject.Variables) {
if (!IsLocalVariable(variable.Name)) {
mergedVariables.Add(variable);
}
}
}
return mergedVariables;
}
}
private bool IsLocalVariable(string name) {
foreach (IVariable variable in variables) {
if (variable.Name == name) return true;
}
return false;
}
public override bool TryRemoveSubOperator(int index) {
IFunction removedFunction = subFunctions[index];
subFunctions.RemoveAt(index);
bool valid = IsValid();
if (!valid) {
subFunctions.Insert(index, removedFunction);
}
return valid;
}
public override bool TryRemoveSubOperator(int index, out ICollection violatedConstraints) {
IFunction removedFunction = subFunctions[index];
subFunctions.RemoveAt(index);
bool valid = IsValid(out violatedConstraints);
if (!valid) {
subFunctions.Insert(index, removedFunction);
}
return valid;
}
public override void AddVariable(IVariable variable) {
if (metaObject == this) {
base.AddVariable(variable);
} else {
metaObject.AddVariable(variable);
}
}
public override IVariable GetVariable(string name) {
foreach (IVariable variable in variables) {
if (variable.Name == name) return variable;
}
if (metaObject == this) {
return base.GetVariable(name);
} else {
return metaObject.GetVariable(name);
}
}
public void AddLocalVariable(IVariable variable) {
variables.Add(variable);
}
public override void RemoveVariable(string name) {
foreach (IVariable variable in variables) {
if (variable.Name == name) {
variables.Remove(variable);
return;
}
}
if (metaObject == this) {
base.RemoveVariable(name);
} else {
metaObject.RemoveVariable(name);
}
}
public override IItem GetVariableValue(string formalName, IScope scope, bool recursiveLookup, bool throwOnError) {
foreach (IVariable variable in Variables) {
if (variable.Name == formalName) {
return variable.Value;
}
}
return metaObject.GetVariableValue(formalName, scope, recursiveLookup, throwOnError);
}
public override ICollection VariableInfos {
get {
if (metaObject == this) {
return base.VariableInfos;
} else {
return metaObject.VariableInfos;
}
}
}
public override void AddVariableInfo(IVariableInfo variableInfo) {
if (metaObject == this) {
base.AddVariableInfo(variableInfo);
} else {
metaObject.AddVariableInfo(variableInfo);
}
}
public override void RemoveVariableInfo(string formalName) {
if (metaObject == this) {
base.RemoveVariableInfo(formalName);
} else {
metaObject.RemoveVariableInfo(formalName);
}
}
public override ICollection Constraints {
get {
if (metaObject == this) {
return base.Constraints;
} else {
return metaObject.Constraints;
}
}
}
public override void AddConstraint(IConstraint constraint) {
if (metaObject == this) {
base.AddConstraint(constraint);
} else {
metaObject.AddConstraint(constraint);
}
}
public override void RemoveConstraint(IConstraint constraint) {
if (metaObject == this) {
base.RemoveConstraint(constraint);
} else {
metaObject.RemoveConstraint(constraint);
}
}
//public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary persistedObjects) {
// XmlNode node = base.GetXmlNode(name, document, persistedObjects);
// if (metaObject != this) {
// XmlNode functionTemplateNode = document.CreateElement("FunctionTemplate");
// functionTemplateNode.AppendChild(PersistenceManager.Persist(metaObject, document, persistedObjects));
// node.AppendChild(functionTemplateNode);
// }
// // don't need to persist the sub-functions because OperatorBase.GetXmlNode already persisted the sub-operators
// // persist local variables
// XmlNode variablesNode = document.CreateNode(XmlNodeType.Element, "LocalVariables", null);
// foreach (IVariable variable in variables) {
// variablesNode.AppendChild(PersistenceManager.Persist(variable, document, persistedObjects));
// }
// node.AppendChild(variablesNode);
// return node;
//}
public override void Persist(string name, XmlWriter writer, IDictionary persistedObjects) {
base.Persist(name, writer, persistedObjects);
if(MetaObject != this) {
writer.WriteStartElement("FunctionTemplate");
PersistenceManager.Persist(metaObject, writer, persistedObjects);
writer.WriteEndElement();
}
writer.WriteStartElement("LocalVariables");
foreach(IVariable variable in variables)
PersistenceManager.Persist(variable, writer, persistedObjects);
writer.WriteEndElement(); //
}
//public override void Populate(XmlNode node, IDictionary restoredObjects) {
// base.Populate(node, restoredObjects);
// XmlNode functionTemplateNode = node.SelectSingleNode("FunctionTemplate");
// if(functionTemplateNode != null) {
// metaObject = (FunctionBase)PersistenceManager.Restore(functionTemplateNode.ChildNodes[0], restoredObjects);
// } else {
// metaObject = this;
// }
// // don't need to explicitly load the sub-functions because that has already been done in OperatorBase.Populate()
// // load local variables
// XmlNode variablesNode = node.SelectSingleNode("LocalVariables");
// // remove the variables that have been added in a constructor
// variables.Clear();
// // load the persisted variables
// foreach(XmlNode variableNode in variablesNode.ChildNodes)
// variables.Add((IVariable)PersistenceManager.Restore(variableNode, restoredObjects));
//}
public override void Populate(XmlReader reader, IDictionary restoredObjects) {
base.Populate(reader, restoredObjects);
if(reader.Name == "FunctionTemplate") {
reader.Read();
metaObject = (FunctionBase)PersistenceManager.Restore(reader, restoredObjects);
reader.Read();
reader.ReadEndElement();
} else {
metaObject = this;
}
// don't need to explicitly load the sub-functions because that has already been done in OperatorBase.Populate()
// load local variables
if(reader.Name!="LocalVariables") throw new XmlException("Expected: \"LocalVariables\", found: \""+reader.Name+"\"");
// remove the variables that have been added in a constructor
variables.Clear();
// load the persisted variables
if(!reader.IsEmptyElement) {
reader.Read();
while(reader.IsStartElement()) {
variables.Add((IVariable)PersistenceManager.Restore(reader, restoredObjects));
reader.Skip();
}
reader.ReadEndElement();
} else {
reader.Read();
}
}
public override IView CreateView() {
return new FunctionView(this);
}
}
}