source: branches/2971_named_intervals/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Parser/IntervalConstraintsParser.cs @ 16778

Last change on this file since 16778 was 16778, checked in by chaider, 3 months ago

#2971

  • Changed field numberOfDerivation
  • Added numberOfDerivation to Expression string
  • Added numberOfDerivation to parser
File size: 8.4 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Globalization;
4using System.Linq;
5using System.Text.RegularExpressions;
6
7namespace HeuristicLab.Problems.DataAnalysis {
8  public static class IntervalConstraintsParser {
9    public static IEnumerable<IntervalConstraint> Parse(string input) {
10      var options = RegexOptions.Multiline | RegexOptions.IgnoreCase;
11      var matches = Regex.Matches(input, @"^(.*)\bin\b\s*([\[\]])(.*[^\s])(\s*\.\.\s*)([^\s].*)([\[\]])\n*\r*\s*$", options);
12
13      for (var i = 0; i < matches.Count; ++i) {
14        if (matches[i].Groups.Count == 7) {
15          var intervalConstraint = new IntervalConstraint();
16          //pattern 1 = defintion
17          var definition = Regex.Replace(matches[i].Groups[1].Value, @"\s *", "");
18          if (Regex.IsMatch(definition, @"\/")) {
19            var splitted = Regex.Split(definition.Replace(" ", string.Empty), @"\/");
20            var match = Regex.Match(splitted[0], @"([d∂])([0-9]|[²³])?(.*[^\s*])");
21            if (match.Success) {
22              intervalConstraint.NumberOfDerivation = match.Groups[2].Success ? ParseDerivationCount(match.Groups[2].Value) : 1;
23              intervalConstraint.Definition = match.Groups[3].Value;
24              intervalConstraint.IsDerivation = true;
25              var formulation = Regex.Match(splitted[1], @"([d∂])(.*[^²³])([²³])?");
26              if (formulation.Success) {
27                intervalConstraint.Variable = formulation.Groups[2].Success ? formulation.Groups[2].Value : "";
28              }
29            } else {
30              throw new ArgumentException($"An error occured in the derivation part: {splitted[0]}");
31            }
32          } else {
33            intervalConstraint.Definition = Regex.Match(definition, @".*[^.\s]*").Value;
34            intervalConstraint.IsDerivation = false;
35          }
36          intervalConstraint.Expression = matches[i].Groups[0].Value.Trim(' ', '\t', '\n', '\r');
37          intervalConstraint.InclusiveLowerBound = (matches[i].Groups[2].Value == "[");
38          intervalConstraint.InclusiveUpperBound = (matches[i].Groups[6].Value == "]");
39          intervalConstraint.Interval = new Interval(ParseIntervalBounds(matches[i].Groups[3].Value.Replace(" ", string.Empty)),
40            ParseIntervalBounds(matches[i].Groups[5].Value.Replace(" ", string.Empty)));
41
42          yield return intervalConstraint;
43        } else {
44          throw new ArgumentException($"The given constraint: {matches[i].Value} is not valid.");
45        }
46      }
47    }
48
49   
50    public static IEnumerable<IntervalConstraint> ParseInput(string input, string target = "", IEnumerable<string> variables = null) {
51      var lines = input.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
52      foreach (var line in lines) {
53        var trimmedLine = line.TrimStart();
54        //Check for target-variable constraint
55        if (trimmedLine.StartsWith("Target:")) {
56          var start = "Target:".Length;
57          var end = trimmedLine.Length;
58          var targetConstraint = trimmedLine.Substring(start, end-start);
59          var match = Regex.Match(targetConstraint,
60            @"([^\s]*)\s*(\bin\b)\s*([\[\]])\s*(\S*)\s*(..)\s*(\S*)\s*([\[\]])");
61          if (match.Success) {
62            if (match.Groups.Count != 8) {
63              throw new ArgumentException("The given target-constraint is not complete!");
64            } else {
65              if (target != "") {
66                if (match.Groups[1].Value.Trim() != target) {
67                  throw new ArgumentException("The given target variable is not in the given dataset!");
68                }
69              }
70              var lowerBound = ParseIntervalBounds(match.Groups[4].Value);
71              var upperBound = ParseIntervalBounds(match.Groups[6].Value);
72              var constraint = new IntervalConstraint(match.Groups[0].Value);
73              constraint.Expression = "Target " + match.Groups[0].Value;
74              constraint.Definition = "Target " + match.Groups[1].Value.Trim();
75              constraint.Variable = match.Groups[1].Value.Trim();
76              constraint.InclusiveLowerBound = match.Groups[3].Value.Trim() == "[";
77              constraint.InclusiveUpperBound = match.Groups[7].Value.Trim() == "]";
78              constraint.IsDerivation = false;
79              constraint.NumberOfDerivation = 0;
80              constraint.Interval = new Interval(lowerBound, upperBound);
81
82              yield return constraint;
83            }
84          } else {
85            throw new ArgumentException("The inserted target constraint is not valid!");
86          }
87          //Check for derivation
88        } else if (trimmedLine.StartsWith("d") || trimmedLine.StartsWith("\u2202")) {
89          var match = Regex.Match(trimmedLine,
90            @"([d∂])([²³])?\s*(\S*)\s*(\/)([d∂])\s*([^²³]*)([²³])?\s*\bin\b\s*([\[\]])\s*(\S*)\s*(..)\s*(\S*)\s*([\[\]])");
91
92          if (match.Success) {
93            if (match.Groups.Count != 13) {
94              throw new ArgumentException("The given derivation-constraint is not complete");
95            } else {
96              if (target != "") {
97                if (match.Groups[3].Value != target) 
98                  throw new ArgumentException("The given target variable is not given in the dataset!");
99              }
100
101              if (variables != null && variables.Any()) {
102                if (variables.All(v => v != match.Groups[6].Value.Trim())) {
103                  throw new ArgumentException("The given variable does not exist in the dataset!");
104                }
105              }
106
107              if (match.Groups[2].Value.Trim() != "" || match.Groups[7].Value.Trim() != "") {
108                if (match.Groups[2].Value.Trim() == "" || match.Groups[7].Value.Trim() == "")
109                  throw new ArgumentException("Number of derivation has to be written on both sides!");
110                if (match.Groups[2].Value.Trim() != match.Groups[7].Value.Trim())
111                  throw new ArgumentException("Derivation number is not equal on both sides!");
112              }
113
114              var lowerBound = ParseIntervalBounds(match.Groups[9].Value);
115              var upperBound = ParseIntervalBounds(match.Groups[11].Value);
116              var constraint = new IntervalConstraint(match.Groups[0].Value);
117              constraint.Expression = match.Groups[0].Value;
118              constraint.Definition = match.Groups[1].Value + match.Groups[2].Value + match.Groups[3].Value +
119                                      match.Groups[4].Value + match.Groups[5].Value + match.Groups[6].Value + match.Groups[7].Value;
120              constraint.IsDerivation = true;
121              constraint.InclusiveLowerBound = match.Groups[8].Value.Trim() == "[";
122              constraint.InclusiveUpperBound = match.Groups[12].Value.Trim() == "]";
123              constraint.Variable = match.Groups[6].Value.Trim();
124              constraint.NumberOfDerivation = ParseDerivationCount(match.Groups[2].Value.Trim());
125              constraint.Interval = new Interval(lowerBound, upperBound);
126
127              yield return constraint;
128            }
129          } else {
130            throw new ArgumentException("The inserted derivation constraint is not valid!");
131          }
132          //Check for comment
133        } else if (trimmedLine.StartsWith("#") || trimmedLine == "") {
134          //If it is a comment just continue without saving anything
135          continue;
136        } else {
137          throw new ArgumentException("Error at your constraints definition constraints have to start with Target: | d | \u2202 | #");
138        }
139      }
140    }
141
142    private static double ParseIntervalBounds(string input) {
143      input = input.ToLower();
144      switch (input) {
145        case "+inf.":
146        case "inf.":
147          return double.PositiveInfinity;
148        case "-inf.":
149          return double.NegativeInfinity;
150        default: {
151            if (double.TryParse(input, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)) {
152              return value;
153            } else {
154              throw new ArgumentException("The given boundary is not a double value!");
155            }
156          }
157      }
158    }
159
160    private static int ParseDerivationCount(string input) {
161      switch (input) {
162        case "":
163          return 1;
164        case "²":
165          return 2;
166        case "³":
167          return 3;
168        default:
169          int.TryParse(input, out var value);
170          return value;
171      }
172    }
173  }
174}
Note: See TracBrowser for help on using the repository browser.