Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.SupportVectorMachines/3.2/SupportVectorRegression.cs @ 2139

Last change on this file since 2139 was 2127, checked in by gkronber, 15 years ago

Fixed a bug in nu-SVR engine. #682

File size: 21.5 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.Linq;
25using System.Text;
26using HeuristicLab.Core;
27using System.Xml;
28using System.Diagnostics;
29using HeuristicLab.DataAnalysis;
30using HeuristicLab.Data;
31using HeuristicLab.Operators;
32using HeuristicLab.GP.StructureIdentification;
33using HeuristicLab.Logging;
34using HeuristicLab.Operators.Programmable;
35using HeuristicLab.Modeling;
36using HeuristicLab.Random;
37using HeuristicLab.Selection;
38
39namespace HeuristicLab.SupportVectorMachines {
40  public class SupportVectorRegression : ItemBase, IEditable, IAlgorithm {
41
42    public string Name { get { return "SupportVectorRegression"; } }
43    public string Description { get { return "TODO"; } }
44
45    private SequentialEngine.SequentialEngine engine;
46    public IEngine Engine {
47      get { return engine; }
48    }
49
50    public Dataset Dataset {
51      get { return ProblemInjector.GetVariableValue<Dataset>("Dataset", null, false); }
52      set { ProblemInjector.GetVariable("Dataset").Value = value; }
53    }
54
55    public int TargetVariable {
56      get { return ProblemInjector.GetVariableValue<IntData>("TargetVariable", null, false).Data; }
57      set { ProblemInjector.GetVariableValue<IntData>("TargetVariable", null, false).Data = value; }
58    }
59
60    public IOperator ProblemInjector {
61      get {
62        IOperator main = GetMainOperator();
63        return main.SubOperators[0].SubOperators[1];
64      }
65      set {
66        IOperator main = GetMainOperator();
67        main.RemoveSubOperator(1);
68        main.AddSubOperator(value, 1);
69      }
70    }
71
72    public IModel Model {
73      get {
74        if (!engine.Terminated) throw new InvalidOperationException("The algorithm is still running. Wait until the algorithm is terminated to retrieve the result.");
75        IScope bestModelScope = engine.GlobalScope.SubScopes[0];
76        return CreateSVMModel(bestModelScope);
77      }
78    }
79
80    public DoubleArrayData NuList {
81      get { return GetVariableInjector().GetVariable("NuList").GetValue<DoubleArrayData>(); }
82      set { GetVariableInjector().GetVariable("NuList").Value = value; }
83    }
84
85    public int MaxNuIndex {
86      get { return GetVariableInjector().GetVariable("MaxNuIndex").GetValue<IntData>().Data; }
87      set { GetVariableInjector().GetVariable("MaxNuIndex").GetValue<IntData>().Data = value; }
88    }
89
90    public DoubleArrayData CostList {
91      get { return GetVariableInjector().GetVariable("CostList").GetValue<DoubleArrayData>(); }
92      set { GetVariableInjector().GetVariable("CostList").Value = value; }
93    }
94
95    public int MaxCostIndex {
96      get { return GetVariableInjector().GetVariable("MaxCostIndex").GetValue<IntData>().Data; }
97      set { GetVariableInjector().GetVariable("MaxCostIndex").GetValue<IntData>().Data = value; }
98    }
99
100    public DoubleArrayData GammaList {
101      get { return GetVariableInjector().GetVariable("GammaList").GetValue<DoubleArrayData>(); }
102      set { GetVariableInjector().GetVariable("GammaList").Value = value; }
103    }
104
105    public int MaxGammaIndex {
106      get { return GetVariableInjector().GetVariable("MaxGammaIndex").GetValue<IntData>().Data; }
107      set { GetVariableInjector().GetVariable("MaxGammaIndex").GetValue<IntData>().Data = value; }
108    }
109
110    public SupportVectorRegression() {
111      engine = new SequentialEngine.SequentialEngine();
112      CombinedOperator algo = CreateAlgorithm();
113      engine.OperatorGraph.AddOperator(algo);
114      engine.OperatorGraph.InitialOperator = algo;
115      MaxCostIndex = CostList.Data.Length;
116      MaxNuIndex = NuList.Data.Length;
117      MaxGammaIndex = GammaList.Data.Length;
118    }
119
120    private CombinedOperator CreateAlgorithm() {
121      CombinedOperator algo = new CombinedOperator();
122      SequentialProcessor seq = new SequentialProcessor();
123      algo.Name = "SupportVectorRegression";
124      seq.Name = "SupportVectorRegression";
125
126      IOperator initialization = CreateInitialization();
127      IOperator main = CreateMainLoop();
128      IOperator postProc = CreateModelAnalyser();
129
130      seq.AddSubOperator(initialization);
131      seq.AddSubOperator(main);
132      seq.AddSubOperator(postProc);
133
134      algo.OperatorGraph.InitialOperator = seq;
135      algo.OperatorGraph.AddOperator(seq);
136
137      return algo;
138    }
139
140    private IOperator CreateInitialization() {
141      SequentialProcessor seq = new SequentialProcessor();
142      seq.Name = "Initialization";
143      seq.AddSubOperator(CreateGlobalInjector());
144      seq.AddSubOperator(new ProblemInjector());
145      seq.AddSubOperator(new RandomInjector());
146      return seq;
147    }
148
149    private IOperator CreateMainLoop() {
150      SequentialProcessor main = new SequentialProcessor();
151      main.Name = "Main";
152      #region initial solution
153      SubScopesCreater modelScopeCreator = new SubScopesCreater();
154      modelScopeCreator.GetVariableInfo("SubScopes").Local = true;
155      modelScopeCreator.AddVariable(new HeuristicLab.Core.Variable("SubScopes", new IntData(1)));
156      main.AddSubOperator(modelScopeCreator);
157     
158      SequentialSubScopesProcessor seqSubScopesProc = new SequentialSubScopesProcessor();
159      IOperator modelProcessor = CreateModelProcessor();
160
161      seqSubScopesProc.AddSubOperator(modelProcessor);
162      main.AddSubOperator(seqSubScopesProc);
163      #endregion
164
165      SequentialProcessor nuLoop = new SequentialProcessor();
166      nuLoop.Name = "NuLoop";
167
168      SequentialProcessor gammaLoop = new SequentialProcessor();
169      gammaLoop.Name = "GammaLoop";
170
171      nuLoop.AddSubOperator(gammaLoop);
172
173      IOperator costCounter = CreateCounter("Cost");
174      IOperator costComparator = CreateComparator("Cost");
175      gammaLoop.AddSubOperator(costCounter);
176      gammaLoop.AddSubOperator(costComparator);
177
178      ConditionalBranch costBranch = new ConditionalBranch();
179      costBranch.Name = "IfValidCostIndex";
180      costBranch.GetVariableInfo("Condition").ActualName = "RepeatCostLoop";
181
182      // build cost loop
183      SequentialProcessor costLoop = new SequentialProcessor();
184      costLoop.Name = "CostLoop";
185
186      #region selection of better solution
187      costLoop.AddSubOperator(modelScopeCreator);
188      SequentialSubScopesProcessor subScopesProcessor = new SequentialSubScopesProcessor();
189      costLoop.AddSubOperator(subScopesProcessor);
190      subScopesProcessor.AddSubOperator(new EmptyOperator());
191      subScopesProcessor.AddSubOperator(modelProcessor);
192
193      Sorter sorter = new Sorter();
194      sorter.GetVariableInfo("Value").ActualName = "ValidationQuality";
195      sorter.GetVariableInfo("Descending").Local = true;
196      sorter.AddVariable(new Variable("Descending", new BoolData(false)));
197      costLoop.AddSubOperator(sorter);
198
199      LeftSelector selector = new LeftSelector();
200      selector.GetVariableInfo("Selected").Local = true;
201      selector.AddVariable(new Variable("Selected", new IntData(1)));
202      costLoop.AddSubOperator(selector);
203
204      RightReducer reducer = new RightReducer();
205      costLoop.AddSubOperator(reducer);
206      #endregion
207
208      costLoop.AddSubOperator(costCounter);
209      costLoop.AddSubOperator(costComparator);
210
211      costBranch.AddSubOperator(costLoop);
212      costLoop.AddSubOperator(costBranch);
213
214      gammaLoop.AddSubOperator(costBranch); // inner loop
215      gammaLoop.AddSubOperator(CreateResetOperator("CostIndex", -1));
216      gammaLoop.AddSubOperator(CreateCounter("Gamma"));
217      gammaLoop.AddSubOperator(CreateComparator("Gamma"));
218
219      ConditionalBranch gammaBranch = new ConditionalBranch();
220      gammaBranch.Name = "GammaLoop";
221      gammaBranch.GetVariableInfo("Condition").ActualName = "RepeatGammaLoop";
222      gammaBranch.AddSubOperator(gammaLoop);
223      gammaLoop.AddSubOperator(gammaBranch);
224
225      nuLoop.AddSubOperator(CreateResetOperator("GammaIndex", 0));
226
227      nuLoop.AddSubOperator(CreateCounter("Nu"));
228      nuLoop.AddSubOperator(CreateComparator("Nu"));
229
230      ConditionalBranch nuBranch = new ConditionalBranch();
231      nuBranch.Name = "NuLoop";
232      nuBranch.GetVariableInfo("Condition").ActualName = "RepeatNuLoop";
233     
234      nuBranch.AddSubOperator(nuLoop);
235      nuLoop.AddSubOperator(nuBranch);
236
237      main.AddSubOperator(nuLoop);
238      return main;
239    }
240
241    private IOperator CreateModelProcessor() {
242      SequentialProcessor modelProcessor = new SequentialProcessor();
243      modelProcessor.AddSubOperator(CreateSetNextParameterValueOperator("Nu"));
244      modelProcessor.AddSubOperator(CreateSetNextParameterValueOperator("Cost"));
245      modelProcessor.AddSubOperator(CreateSetNextParameterValueOperator("Gamma"));
246
247      SupportVectorCreator modelCreator = new SupportVectorCreator();
248      modelCreator.GetVariableInfo("SamplesStart").ActualName = "TrainingSamplesStart";
249      modelCreator.GetVariableInfo("SamplesEnd").ActualName = "TrainingSamplesEnd";
250      modelCreator.GetVariableInfo("SVMCost").ActualName = "Cost";
251      modelCreator.GetVariableInfo("SVMGamma").ActualName = "Gamma";
252      modelCreator.GetVariableInfo("SVMKernelType").ActualName = "KernelType";
253      modelCreator.GetVariableInfo("SVMModel").ActualName = "Model";
254      modelCreator.GetVariableInfo("SVMNu").ActualName = "Nu";
255      modelCreator.GetVariableInfo("SVMType").ActualName = "Type";
256
257      modelProcessor.AddSubOperator(modelCreator);
258      CombinedOperator trainingEvaluator = (CombinedOperator)CreateEvaluator("Training");
259      trainingEvaluator.OperatorGraph.InitialOperator.SubOperators[1].GetVariableInfo("MSE").ActualName = "Quality";
260      modelProcessor.AddSubOperator(trainingEvaluator);
261      modelProcessor.AddSubOperator(CreateEvaluator("Validation"));
262      modelProcessor.AddSubOperator(CreateEvaluator("Test"));
263
264      DataCollector collector = new DataCollector();
265      collector.GetVariableInfo("Values").ActualName = "Log";
266      ((ItemList<StringData>)collector.GetVariable("VariableNames").Value).Add(new StringData("Nu"));
267      ((ItemList<StringData>)collector.GetVariable("VariableNames").Value).Add(new StringData("Cost"));
268      ((ItemList<StringData>)collector.GetVariable("VariableNames").Value).Add(new StringData("Gamma"));
269      ((ItemList<StringData>)collector.GetVariable("VariableNames").Value).Add(new StringData("ValidationQuality"));
270      modelProcessor.AddSubOperator(collector);
271      return modelProcessor;
272    }
273
274    private IOperator CreateComparator(string p) {
275      LessThanComparator comparator = new LessThanComparator();
276      comparator.Name = p + "IndexComparator";
277      comparator.GetVariableInfo("LeftSide").ActualName = p + "Index";
278      comparator.GetVariableInfo("RightSide").ActualName = "Max" + p + "Index";
279      comparator.GetVariableInfo("Result").ActualName = "Repeat" + p + "Loop";
280      return comparator;
281    }
282
283    private IOperator CreateCounter(string p) {
284      Counter c = new Counter();
285      c.GetVariableInfo("Value").ActualName = p + "Index";
286      c.Name = p + "Counter";
287      return c;
288    }
289
290    private IOperator CreateEvaluator(string p) {
291      CombinedOperator op = new CombinedOperator();
292      op.Name = p + "Evaluator";
293      SequentialProcessor seqProc = new SequentialProcessor();
294
295      SupportVectorEvaluator evaluator = new SupportVectorEvaluator();
296      evaluator.Name = p + "SimpleEvaluator";
297      evaluator.GetVariableInfo("SVMModel").ActualName = "Model";
298      evaluator.GetVariableInfo("SamplesStart").ActualName = p + "SamplesStart";
299      evaluator.GetVariableInfo("SamplesEnd").ActualName = p + "SamplesEnd";
300      evaluator.GetVariableInfo("Values").ActualName = p + "Values";
301      SimpleMSEEvaluator mseEvaluator = new SimpleMSEEvaluator();
302      mseEvaluator.Name = p + "MseEvaluator";
303      mseEvaluator.GetVariableInfo("Values").ActualName = p + "Values";
304      mseEvaluator.GetVariableInfo("MSE").ActualName = p + "Quality";
305      SimpleR2Evaluator r2Evaluator = new SimpleR2Evaluator();
306      r2Evaluator.Name = p + "R2Evaluator";
307      r2Evaluator.GetVariableInfo("Values").ActualName = p + "Values";
308      r2Evaluator.GetVariableInfo("R2").ActualName = p + "R2";
309      SimpleMeanAbsolutePercentageErrorEvaluator mapeEvaluator = new SimpleMeanAbsolutePercentageErrorEvaluator();
310      mapeEvaluator.Name = p + "MAPEEvaluator";
311      mapeEvaluator.GetVariableInfo("Values").ActualName = p + "Values";
312      mapeEvaluator.GetVariableInfo("MAPE").ActualName = p + "MAPE";
313      SimpleMeanAbsolutePercentageOfRangeErrorEvaluator mapreEvaluator = new SimpleMeanAbsolutePercentageOfRangeErrorEvaluator();
314      mapreEvaluator.Name = p + "MAPREEvaluator";
315      mapreEvaluator.GetVariableInfo("Values").ActualName = p + "Values";
316      mapreEvaluator.GetVariableInfo("MAPRE").ActualName = p + "MAPRE";
317      SimpleVarianceAccountedForEvaluator vafEvaluator = new SimpleVarianceAccountedForEvaluator();
318      vafEvaluator.Name = p + "VAFEvaluator";
319      vafEvaluator.GetVariableInfo("Values").ActualName = p + "Values";
320      vafEvaluator.GetVariableInfo("VAF").ActualName = p + "VAF";
321
322      seqProc.AddSubOperator(evaluator);
323      seqProc.AddSubOperator(mseEvaluator);
324      seqProc.AddSubOperator(r2Evaluator);
325      seqProc.AddSubOperator(mapeEvaluator);
326      seqProc.AddSubOperator(mapreEvaluator);
327      seqProc.AddSubOperator(vafEvaluator);
328
329      op.OperatorGraph.AddOperator(seqProc);
330      op.OperatorGraph.InitialOperator = seqProc;
331      return op;
332    }
333
334    private IOperator CreateSetNextParameterValueOperator(string paramName) {
335      ProgrammableOperator progOp = new ProgrammableOperator();
336      progOp.Name = "SetNext" + paramName;
337      progOp.RemoveVariableInfo("Result");
338      progOp.AddVariableInfo(new VariableInfo("Value", "Value", typeof(DoubleData), VariableKind.New));
339      progOp.AddVariableInfo(new VariableInfo("ValueIndex", "ValueIndex", typeof(IntData), VariableKind.In));
340      progOp.AddVariableInfo(new VariableInfo("ValueList", "ValueList", typeof(DoubleArrayData), VariableKind.In));
341      progOp.Code =
342@"
343Value.Data = ValueList.Data[ValueIndex.Data];
344";
345
346      progOp.GetVariableInfo("Value").ActualName = paramName;
347      progOp.GetVariableInfo("ValueIndex").ActualName = paramName + "Index";
348      progOp.GetVariableInfo("ValueList").ActualName = paramName + "List";
349      return progOp;
350    }
351
352    private IOperator CreateResetOperator(string paramName, int value) {
353      ProgrammableOperator progOp = new ProgrammableOperator();
354      progOp.Name = "Reset" + paramName;
355      progOp.RemoveVariableInfo("Result");
356      progOp.AddVariableInfo(new VariableInfo("Value", "Value", typeof(IntData), VariableKind.In | VariableKind.Out));
357      progOp.Code = "Value.Data = "+value+";";
358      progOp.GetVariableInfo("Value").ActualName = paramName;
359      return progOp;
360    }
361
362    private IOperator CreateGlobalInjector() {
363      VariableInjector injector = new VariableInjector();
364      injector.AddVariable(new HeuristicLab.Core.Variable("CostIndex", new IntData(0)));
365      injector.AddVariable(new HeuristicLab.Core.Variable("CostList", new DoubleArrayData(new double[] {
366        Math.Pow(2,-5),
367        Math.Pow(2,-3),
368        Math.Pow(2,-1),
369        2,
370        Math.Pow(2,3),
371        Math.Pow(2,5),
372        Math.Pow(2,7),
373        Math.Pow(2,9),
374        Math.Pow(2,11),
375        Math.Pow(2,13),
376        Math.Pow(2,15)})));
377      injector.AddVariable(new HeuristicLab.Core.Variable("MaxCostIndex", new IntData()));
378      injector.AddVariable(new HeuristicLab.Core.Variable("NuIndex", new IntData(0)));
379      injector.AddVariable(new HeuristicLab.Core.Variable("NuList", new DoubleArrayData(new double[] { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.9, 0.8, 1 })));
380      injector.AddVariable(new HeuristicLab.Core.Variable("MaxNuIndex", new IntData()));
381      injector.AddVariable(new HeuristicLab.Core.Variable("Log", new ItemList()));
382      injector.AddVariable(new HeuristicLab.Core.Variable("GammaIndex", new IntData(0)));
383      injector.AddVariable(new HeuristicLab.Core.Variable("GammaList", new DoubleArrayData(new double[] {
384        3.0517578125E-05, 0.0001220703125,0.00048828125,0.001953125,
385        0.0078125,0.03125,0.125,0.5,2,4,8})));
386      injector.AddVariable(new HeuristicLab.Core.Variable("MaxGammaIndex", new IntData()));
387      injector.AddVariable(new HeuristicLab.Core.Variable("KernelType", new StringData("RBF")));
388      injector.AddVariable(new HeuristicLab.Core.Variable("Type", new StringData("NU_SVR")));
389
390      return injector;
391    }
392
393    private IOperator CreateModelAnalyser() {
394      CombinedOperator modelAnalyser = new CombinedOperator();
395      modelAnalyser.Name = "Model Analyzer";
396      SequentialSubScopesProcessor seqSubScopeProc = new SequentialSubScopesProcessor();
397      SequentialProcessor seqProc = new SequentialProcessor();
398      VariableEvaluationImpactCalculator evalImpactCalc = new VariableEvaluationImpactCalculator();
399      evalImpactCalc.GetVariableInfo("SVMModel").ActualName = "Model";
400      VariableQualityImpactCalculator qualImpactCalc = new VariableQualityImpactCalculator();
401      qualImpactCalc.GetVariableInfo("SVMModel").ActualName = "Model";
402
403      seqProc.AddSubOperator(evalImpactCalc);
404      seqProc.AddSubOperator(qualImpactCalc);
405      seqSubScopeProc.AddSubOperator(seqProc);
406      modelAnalyser.OperatorGraph.InitialOperator = seqSubScopeProc;
407      modelAnalyser.OperatorGraph.AddOperator(seqSubScopeProc);
408      return modelAnalyser;
409    }
410
411
412    protected internal virtual Model CreateSVMModel(IScope bestModelScope) {
413      Model model = new Model();
414      model.TrainingMeanSquaredError = bestModelScope.GetVariableValue<DoubleData>("Quality", false).Data;
415      model.ValidationMeanSquaredError = bestModelScope.GetVariableValue<DoubleData>("ValidationQuality", false).Data;
416      model.TestMeanSquaredError = bestModelScope.GetVariableValue<DoubleData>("TestQuality", false).Data;
417      model.TrainingCoefficientOfDetermination = bestModelScope.GetVariableValue<DoubleData>("TrainingR2", false).Data;
418      model.ValidationCoefficientOfDetermination = bestModelScope.GetVariableValue<DoubleData>("ValidationR2", false).Data;
419      model.TestCoefficientOfDetermination = bestModelScope.GetVariableValue<DoubleData>("TestR2", false).Data;
420      model.TrainingMeanAbsolutePercentageError = bestModelScope.GetVariableValue<DoubleData>("TrainingMAPE", false).Data;
421      model.ValidationMeanAbsolutePercentageError = bestModelScope.GetVariableValue<DoubleData>("ValidationMAPE", false).Data;
422      model.TestMeanAbsolutePercentageError = bestModelScope.GetVariableValue<DoubleData>("TestMAPE", false).Data;
423      model.TrainingMeanAbsolutePercentageOfRangeError = bestModelScope.GetVariableValue<DoubleData>("TrainingMAPRE", false).Data;
424      model.ValidationMeanAbsolutePercentageOfRangeError = bestModelScope.GetVariableValue<DoubleData>("ValidationMAPRE", false).Data;
425      model.TestMeanAbsolutePercentageOfRangeError = bestModelScope.GetVariableValue<DoubleData>("TestMAPRE", false).Data;
426      model.TrainingVarianceAccountedFor = bestModelScope.GetVariableValue<DoubleData>("TrainingVAF", false).Data;
427      model.ValidationVarianceAccountedFor = bestModelScope.GetVariableValue<DoubleData>("ValidationVAF", false).Data;
428      model.TestVarianceAccountedFor = bestModelScope.GetVariableValue<DoubleData>("TestVAF", false).Data;
429
430      model.Data = bestModelScope.GetVariableValue<SVMModel>("Model", false);
431      HeuristicLab.DataAnalysis.Dataset ds = bestModelScope.GetVariableValue<Dataset>("Dataset", true);
432      model.Dataset = ds;
433      model.TargetVariable = ds.GetVariableName(bestModelScope.GetVariableValue<IntData>("TargetVariable", true).Data);
434
435      ItemList evaluationImpacts = bestModelScope.GetVariableValue<ItemList>("VariableEvaluationImpacts", false);
436      ItemList qualityImpacts = bestModelScope.GetVariableValue<ItemList>("VariableQualityImpacts", false);
437      foreach (ItemList row in evaluationImpacts) {
438        string variableName = ((StringData)row[0]).Data;
439        double impact = ((DoubleData)row[1]).Data;
440        model.SetVariableEvaluationImpact(variableName, impact);
441      }
442      foreach (ItemList row in qualityImpacts) {
443        string variableName = ((StringData)row[0]).Data;
444        double impact = ((DoubleData)row[1]).Data;
445        model.SetVariableQualityImpact(variableName, impact);
446      }
447
448      return model;
449    }
450
451    private IOperator GetVariableInjector() {
452      return GetMainOperator().SubOperators[0].SubOperators[0];
453    }
454
455    private IOperator GetMainOperator() {
456      CombinedOperator svm = (CombinedOperator)Engine.OperatorGraph.InitialOperator;
457      return svm.OperatorGraph.InitialOperator;
458    }
459
460    public override IView CreateView() {
461      return engine.CreateView();
462    }
463
464    #region IEditable Members
465
466    public IEditor CreateEditor() {
467      return engine.CreateEditor();
468    }
469
470    #endregion
471  }
472}
Note: See TracBrowser for help on using the repository browser.