Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 229 was 229, checked in by gkronber, 16 years ago

merged changes (r201 r203 r206 r208 r220 r223 r224 r225 r226 r227) from branch ExperimentalFunctionsBaking into the trunk. (ticket #139)

File size: 8.4 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 sealed 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 BakedFunctionTree(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.