#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 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); } } }