Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 170 was 165, checked in by gkronber, 17 years ago

implemented ProgrammableFunction inherited from ProgrammableOperator (fixes #106)

File size: 7.9 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 double Evaluate(Dataset dataset, int sampleIndex, IFunctionTree tree) {
122      // evaluate sub-trees
123      double[] evaluationResults = new double[tree.SubTrees.Count];
124      for(int subTree=0; subTree < tree.SubTrees.Count; subTree++) {
125        evaluationResults[subTree] = tree.SubTrees[subTree].Evaluate(dataset, sampleIndex);
126      }
127      // lazy activation of the user-programmed code
128      if(applyMethod == null) {
129        Compile();
130      }
131
132      // collect parameters
133      object[] parameters = new object[VariableInfos.Count + 3];
134      parameters[0] = dataset;
135      parameters[1] = sampleIndex;
136      int i = 2;
137      // all local variables are available in the custom function
138      foreach(IVariable variable in tree.LocalVariables) {
139        parameters[i] = variable;
140        i++;
141      }
142      parameters[i] = evaluationResults;
143      return (double)applyMethod.Invoke(null, parameters);
144    }
145
146    // application of programmable-function is not possible
147    public double Apply(Dataset dataset, int sampleIndex, double[] args) {
148      throw new NotSupportedException();
149    }
150
151    #endregion
152
153    #region disabled operator functionality
154    // operator-tree style evaluation is not supported for functions.
155    public override IOperation Apply(IScope scope) {
156      throw new NotSupportedException();
157    }
158
159    private static readonly List<IOperator> emptySubOperatorList = new List<IOperator>();
160    public override IList<IOperator> SubOperators {
161      get { return emptySubOperatorList; }
162    }
163
164    public override void AddSubOperator(IOperator subOperator) {
165      throw new NotSupportedException();
166    }
167
168    public override bool TryAddSubOperator(IOperator subOperator) {
169      throw new NotSupportedException();
170    }
171
172    public override bool TryAddSubOperator(IOperator subOperator, int index) {
173      throw new NotSupportedException();
174    }
175
176    public override bool TryAddSubOperator(IOperator subOperator, int index, out ICollection<IConstraint> violatedConstraints) {
177      throw new NotSupportedException();
178    }
179
180    public override bool TryAddSubOperator(IOperator subOperator, out ICollection<IConstraint> violatedConstraints) {
181      throw new NotSupportedException();
182    }
183
184    public override void AddSubOperator(IOperator subOperator, int index) {
185      throw new NotSupportedException();
186    }
187
188    public override void RemoveSubOperator(int index) {
189      throw new NotSupportedException();
190    }
191
192    public override bool TryRemoveSubOperator(int index) {
193      throw new NotSupportedException();
194    }
195
196    public override bool TryRemoveSubOperator(int index, out ICollection<IConstraint> violatedConstraints) {
197      throw new NotSupportedException();
198    }
199    #endregion
200  }
201}
Note: See TracBrowser for help on using the repository browser.