Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2971_named_intervals/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Interval/IntervalConstraintsParser.cs @ 17250

Last change on this file since 17250 was 17250, checked in by chaider, 5 years ago

#2971 Added exception handling for constraint parser

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