Free cookie consent management tool by TermsFeed Policy Generator

source: branches/GP.Grammar.Editor/HeuristicLab.Optimization/3.3/Calculator.cs @ 6675

Last change on this file since 6675 was 6675, checked in by mkommend, 13 years ago

#1479: Integrated trunk changes.

File size: 3.5 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Drawing;
4using System.Linq;
5using System.Text.RegularExpressions;
6using HeuristicLab.Common;
7using HeuristicLab.Core;
8using HeuristicLab.Data;
9using HeuristicLab.Parameters;
10using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
11using System.Globalization;
12
13namespace HeuristicLab.Optimization { 
14   
15  [StorableClass]
16  public class Calculator : IDeepCloneable {
17
18    #region Fields & Properties
19   
20    private List<string> tokens;
21
22    [Storable]
23    public string Formula {
24      get { return string.Join(" ", tokens); }
25      set { tokens = Tokenize(value).ToList(); }
26    }
27
28    private static readonly Regex TokenRegex = new Regex(@"[a-zA-Z0-9._]+|""([^""]|\"")+""|[-+*/^]|log");   
29
30    #endregion
31
32    #region Construction & Cloning
33
34    [StorableConstructor]
35    protected Calculator(bool deserializing) { }
36    public Calculator() { }
37    public Calculator(Calculator original, Cloner cloner) {
38      this.tokens = original.tokens.ToList();
39    }
40    public IDeepCloneable Clone(Cloner cloner) {
41      return new Calculator(this, cloner);
42    }
43    public object Clone() {
44      return Clone(new Cloner());
45    }
46    #endregion
47
48    public IEnumerable<string> Tokenize(string s) {
49      return TokenRegex.Matches(s).Cast<Match>().Select(m => m.Value);
50    }
51
52    private double GetVariableValue(IDictionary<string, IItem> variables, string name) {
53      if (variables.ContainsKey(name)) {
54        var item = variables[name];
55        var intValue = item as IntValue;
56        if (intValue != null) {
57          return intValue.Value;
58        } else {
59          var doubleValue = item as DoubleValue;
60          if (doubleValue != null)
61            return doubleValue.Value;
62          else
63            throw new InvalidOperationException("Non numerical argument");
64        }
65      } else {
66        throw new InvalidOperationException(string.Format("variable \"{0}\" not found", name));
67      }
68    }
69
70    public IItem GetValue(IDictionary<string, IItem> variables) {
71      var stack = new Stack<double>();
72      Action<Func<double, double, double>> binf = op => {
73        var b = stack.Pop();
74        stack.Push(op(stack.Pop(), b));
75      };
76      try {
77        foreach (var token in tokens) {
78          double d;
79          if (double.TryParse(token,
80                NumberStyles.AllowDecimalPoint |
81              NumberStyles.AllowExponent |
82              NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out d)) {
83            stack.Push(d);
84          } else if (token.StartsWith("\"")) {
85            stack.Push(GetVariableValue(variables, token.Substring(1, token.Length - 2).Replace(@"\""", @"""")));
86          } else {
87            switch (token) {
88              case "log": stack.Push(Math.Log(stack.Pop())); break;
89              case "+": binf((x, y) => x + y); break;
90              case "-": binf((x, y) => x - y); break;
91              case "*": binf((x, y) => x * y); break;
92              case "/": binf((x, y) => x / y); break;
93              case "^": binf(Math.Pow); break;
94              default: stack.Push(GetVariableValue(variables, token)); break;
95            }
96          }
97        }
98      } catch (InvalidOperationException x) {
99        return new StringValue(string.Format("Calculation Failed: {0}", x.Message));
100      }
101      if (stack.Count != 1)
102        return new StringValue("Invalid final evaluation stack size != 1");
103      return new DoubleValue(stack.Pop());     
104    }   
105  }
106}
Note: See TracBrowser for help on using the repository browser.