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

Last change on this file since 16830 was 16830, checked in by chaider, 5 months ago

#2971 Fixed review comments

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