Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Functions/ProgrammableFunction.cs @ 202

Last change on this file since 202 was 189, checked in by gkronber, 17 years ago

fixed #131

File size: 8.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Text;
25using HeuristicLab.Core;
26using System.Diagnostics;
27using HeuristicLab.Constraints;
28using HeuristicLab.DataAnalysis;
29using System.Xml;
30using System.Reflection;
31using System.CodeDom;
32using System.CodeDom.Compiler;
33using Microsoft.CSharp;
34using System.IO;
35using HeuristicLab.Operators.Programmable;
36
37namespace HeuristicLab.Functions {
38  public class ProgrammableFunction : ProgrammableOperator, IFunction {
39    private MethodInfo applyMethod;
40    public ProgrammableFunction()
41      : base() {
42      Code = "return 0.0;";
43      SetDescription("A function that can be programmed for arbitrary needs.");
44      applyMethod = null;
45    }
46
47    public override void Compile() {
48      CodeNamespace ns = new CodeNamespace("HeuristicLab.Functions.CustomFunctions");
49      CodeTypeDeclaration typeDecl = new CodeTypeDeclaration("Function");
50      typeDecl.IsClass = true;
51      typeDecl.TypeAttributes = TypeAttributes.Public;
52
53      CodeMemberMethod method = new CodeMemberMethod();
54      method.Name = "Apply";
55      method.ReturnType = new CodeTypeReference(typeof(double));
56      method.Attributes = MemberAttributes.Public | MemberAttributes.Static;
57      method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(Dataset), "dataset"));
58      method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "index"));
59      foreach(IVariableInfo info in VariableInfos)
60        method.Parameters.Add(new CodeParameterDeclarationExpression(info.DataType, info.FormalName));
61      method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(double[]), "args"));
62      string code = Code;
63      method.Statements.Add(new CodeSnippetStatement(code));
64      typeDecl.Members.Add(method);
65
66      ns.Types.Add(typeDecl);
67      ns.Imports.Add(new CodeNamespaceImport("System"));
68      ns.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
69      ns.Imports.Add(new CodeNamespaceImport("System.Text"));
70      ns.Imports.Add(new CodeNamespaceImport("HeuristicLab.Core"));
71      ns.Imports.Add(new CodeNamespaceImport("HeuristicLab.Functions"));
72      foreach(IVariableInfo variableInfo in VariableInfos)
73        ns.Imports.Add(new CodeNamespaceImport(variableInfo.DataType.Namespace));
74
75      CodeCompileUnit unit = new CodeCompileUnit();
76      unit.Namespaces.Add(ns);
77      CompilerParameters parameters = new CompilerParameters();
78      parameters.GenerateExecutable = false;
79      parameters.GenerateInMemory = true;
80      parameters.IncludeDebugInformation = false;
81      Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
82      foreach(Assembly loadedAssembly in loadedAssemblies)
83        parameters.ReferencedAssemblies.Add(loadedAssembly.Location);
84      CodeDomProvider provider = new CSharpCodeProvider();
85      CompilerResults results = provider.CompileAssemblyFromDom(parameters, unit);
86
87      applyMethod = null;
88      if(results.Errors.HasErrors) {
89        StringWriter writer = new StringWriter();
90        CodeGeneratorOptions options = new CodeGeneratorOptions();
91        options.BlankLinesBetweenMembers = false;
92        options.ElseOnClosing = true;
93        options.IndentString = "  ";
94        provider.GenerateCodeFromCompileUnit(unit, writer, options);
95        writer.Flush();
96        string[] source = writer.ToString().Split(new string[] { "\r\n" }, StringSplitOptions.None);
97        StringBuilder builder = new StringBuilder();
98        for(int i = 0; i < source.Length; i++)
99          builder.AppendLine((i + 1).ToString("###") + "     " + source[i]);
100        builder.AppendLine();
101        builder.AppendLine();
102        builder.AppendLine();
103        foreach(CompilerError error in results.Errors) {
104          builder.Append("Line " + error.Line.ToString());
105          builder.Append(", Column " + error.Column.ToString());
106          builder.AppendLine(": " + error.ErrorText);
107        }
108        throw new Exception("Compile Errors:\n\n" + builder.ToString());
109      } else {
110        Assembly assembly = results.CompiledAssembly;
111        Type[] types = assembly.GetTypes();
112        applyMethod = types[0].GetMethod("Apply");
113      }
114    }
115
116    #region IFunction Members
117    public void Accept(IFunctionVisitor visitor) {
118      visitor.Visit(this);
119    }
120
121    public IFunctionTree GetTreeNode() {
122      return new ProgrammableFunctionTree(this);
123    }
124
125    // application of programmable-function is not possible
126    public double Apply(Dataset dataset, int sampleIndex, double[] args) {
127      throw new NotSupportedException();
128    }
129
130    internal double Call(object[] parameters) {
131      // lazy activation of the user-programmed code
132      if(applyMethod == null) {
133        Compile();
134      }
135      return (double)applyMethod.Invoke(null, parameters);
136    }
137
138    #endregion
139
140    #region disabled operator functionality
141    // operator-tree style evaluation is not supported for functions.
142    public override IOperation Apply(IScope scope) {
143      throw new NotSupportedException();
144    }
145
146    private static readonly List<IOperator> emptySubOperatorList = new List<IOperator>();
147    public override IList<IOperator> SubOperators {
148      get { return emptySubOperatorList; }
149    }
150
151    public override void AddSubOperator(IOperator subOperator) {
152      throw new NotSupportedException();
153    }
154
155    public override bool TryAddSubOperator(IOperator subOperator) {
156      throw new NotSupportedException();
157    }
158
159    public override bool TryAddSubOperator(IOperator subOperator, int index) {
160      throw new NotSupportedException();
161    }
162
163    public override bool TryAddSubOperator(IOperator subOperator, int index, out ICollection<IConstraint> violatedConstraints) {
164      throw new NotSupportedException();
165    }
166
167    public override bool TryAddSubOperator(IOperator subOperator, out ICollection<IConstraint> violatedConstraints) {
168      throw new NotSupportedException();
169    }
170
171    public override void AddSubOperator(IOperator subOperator, int index) {
172      throw new NotSupportedException();
173    }
174
175    public override void RemoveSubOperator(int index) {
176      throw new NotSupportedException();
177    }
178
179    public override bool TryRemoveSubOperator(int index) {
180      throw new NotSupportedException();
181    }
182
183    public override bool TryRemoveSubOperator(int index, out ICollection<IConstraint> violatedConstraints) {
184      throw new NotSupportedException();
185    }
186    #endregion
187  }
188
189  class ProgrammableFunctionTree : FunctionTree {
190    private ProgrammableFunction progFun;
191    public ProgrammableFunctionTree() : base() { }
192    public ProgrammableFunctionTree(ProgrammableFunction progFun) : base(progFun) {
193      this.progFun = progFun;
194    }
195    public override double Evaluate(Dataset dataset, int sampleIndex) {
196      // evaluate sub-trees
197      double[] evaluationResults = new double[SubTrees.Count];
198      for(int subTree = 0; subTree < SubTrees.Count; subTree++) {
199        evaluationResults[subTree] = SubTrees[subTree].Evaluate(dataset, sampleIndex);
200      }
201
202      // collect parameters
203      object[] parameters = new object[LocalVariables.Count + 3];
204      parameters[0] = dataset;
205      parameters[1] = sampleIndex;
206      int i = 2;
207      // all local variables are available in the custom function
208      foreach(IVariable variable in LocalVariables) {
209        parameters[i] = variable;
210        i++;
211      }
212      parameters[i] = evaluationResults;
213      return progFun.Call(parameters);
214    }
215  }
216}
Note: See TracBrowser for help on using the repository browser.