1  using System;


2  using System.Collections.Generic;


3  using System.Globalization;


4  using System.Linq;


5  using System.Text.RegularExpressions;


6 


7  namespace 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∂])([09][²³])?(.*[^\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 targetvariable constraint


55  if (trimmedLine.StartsWith("Target:")) {


56  var start = "Target:".Length;


57  var end = trimmedLine.Length;


58  var targetConstraint = trimmedLine.Substring(start, endstart);


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 targetconstraint 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("Target:" + 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 derivationconstraint 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  }

