Index: /branches/3119_AdditionalShapeConstraintFeatures/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Interval/ShapeConstraint.cs
===================================================================
--- /branches/3119_AdditionalShapeConstraintFeatures/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Interval/ShapeConstraint.cs	(revision 17945)
+++ /branches/3119_AdditionalShapeConstraintFeatures/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Interval/ShapeConstraint.cs	(revision 17946)
@@ -106,4 +106,17 @@
     }
 
+    [Storable]
+    private Interval threshold;
+    public Interval Threshold {
+      get => threshold;
+      set {
+        if (threshold == value)
+          return;
+        threshold = value;
+        OnToStringChanged();
+        OnChanged();
+      }
+    }
+
     [StorableConstructor]
     private ShapeConstraint(StorableConstructorFlag _) : base(_) { }
@@ -115,19 +128,19 @@
 
     // without derivation
-    public ShapeConstraint(Interval interval, double weight)
+    public ShapeConstraint(Interval interval, double weight, Interval threshold)
       : this(string.Empty, 0,
-         interval, new IntervalCollection(), weight) { }
-
-    public ShapeConstraint(Interval interval, IntervalCollection regions, double weight)
+         interval, new IntervalCollection(), weight, threshold) { }
+
+    public ShapeConstraint(Interval interval, IntervalCollection regions, double weight, Interval threshold)
       : this(string.Empty, 0,
-         interval, regions, weight) { }
+         interval, regions, weight, threshold) { }
 
     public ShapeConstraint(string variable, int numberOfDerivations,
-                              Interval interval, double weight)
+                              Interval interval, double weight, Interval threshold)
       : this(variable, numberOfDerivations,
-             interval, new IntervalCollection(), weight) { }
+             interval, new IntervalCollection(), weight, threshold) { }
 
     public ShapeConstraint(string variable, int numberOfDerivations,
-                              Interval interval, IntervalCollection regions, double weight) {
+                              Interval interval, IntervalCollection regions, double weight, Interval threshold) {
       Variable = variable;
       NumberOfDerivations = numberOfDerivations;
@@ -135,4 +148,5 @@
       Regions = regions;
       Weight = weight;
+      Threshold = threshold;
     }
 
@@ -175,25 +189,17 @@
       if (!IsDerivative) {
         expression = string.Format($"f in [{write(Interval.LowerBound)} .. {write(Interval.UpperBound)}]");
-        if (Regions != null) {
-          foreach (var region in Regions.GetReadonlyDictionary())
-            expression += $", {region.Key} in [{write(region.Value.LowerBound)} .. {write(region.Value.UpperBound)}]";
+      } else {
+        var derivationString = string.Empty;
+        switch (numberOfDerivations) {
+          case 1:
+            derivationString = ""; break;
+          case 2:
+            derivationString = "²"; break;
+          case 3:
+            derivationString = "³"; break;
         }
-        if (Weight != 1.0) {
-          expression += $" weight: {weight}";
-        }
-
-        return expression;
-      }
-
-      var derivationString = string.Empty;
-      switch (numberOfDerivations) {
-        case 1:
-          derivationString = ""; break;
-        case 2:
-          derivationString = "²"; break;
-        case 3:
-          derivationString = "³"; break;
-      }
-      expression = string.Format($"∂{derivationString}f/∂{Variable}{derivationString} in [{write(Interval.LowerBound)} .. {write(Interval.UpperBound)}]");
+        expression = string.Format($"∂{derivationString}f/∂{Variable}{derivationString} in [{write(Interval.LowerBound)} .. {write(Interval.UpperBound)}]");
+      }
+
       if (Regions != null) {
         foreach (var region in Regions.GetReadonlyDictionary())
@@ -203,4 +209,7 @@
         expression += $" weight: {weight}";
       }
+      if (!double.IsNegativeInfinity(Threshold.LowerBound) || !double.IsPositiveInfinity(Threshold.UpperBound))
+        expression += $" threshold: [{write(Threshold.LowerBound)} .. {write(Threshold.UpperBound)}]";
+
       return expression;
     }
Index: /branches/3119_AdditionalShapeConstraintFeatures/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Interval/ShapeConstraintsParser.cs
===================================================================
--- /branches/3119_AdditionalShapeConstraintFeatures/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Interval/ShapeConstraintsParser.cs	(revision 17945)
+++ /branches/3119_AdditionalShapeConstraintFeatures/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Interval/ShapeConstraintsParser.cs	(revision 17946)
@@ -75,4 +75,5 @@
     private const string variableRegex = @"(['](?<varName>.*)[']|(?<varName>[^\s²³]+))\s*";
     private const string weightRegex = @"\s*(weight:\s*(?<weight>\S*))?";
+    private const string thresholdRegex = @"\s*(threshold\s*in\s*(?<threshold> "+ intervalRegex + @"))?";
     public static ShapeConstraint ParseFunctionRangeConstraint(string expr) {
       if (!expr.StartsWith("f")) throw new ArgumentException($"Invalid function range constraint {expr} (e.g. f in [1..2])");
@@ -90,5 +91,5 @@
       // df / d'x' in [0..10], 'x' in [1 .. 3]
       // df / d'x' in [0..10], 'x' in [1 .. 3], y in [10..30] weight: 1.2
-
+      // df / d'x' in [0..10], 'x' in [1 .. 3], y in [10..30] weight: 1.2 threshold in [-10 .. 10]
       var match = Regex.Match(targetConstraint,
                     @"\s*\bin\b" +
@@ -99,5 +100,6 @@
                       intervalRegex +
                     @")*" +
-                    weightRegex
+                    weightRegex +
+                    thresholdRegex
                     );
 
@@ -110,7 +112,16 @@
         var interval = new Interval(lowerBound, upperBound);
         var weight = 1.0;
+        var threshold = new Interval(double.NegativeInfinity, double.PositiveInfinity);
 
         if (match.Groups["weight"].Success && !string.IsNullOrWhiteSpace(match.Groups["weight"].Value))
           weight = ParseAndValidateDouble(match.Groups["weight"].Value);
+
+        if(match.Groups["threshold"].Success) {
+          var lowerboundCount = match.Groups["lowerBound"].Captures.Count;
+          var upperboundCount = match.Groups["upperBound"].Captures.Count;
+          var thresholdLb = ParseIntervalBounds(match.Groups["lowerBound"].Captures[lowerboundCount - 1].Value);
+          var thresholdUb = ParseIntervalBounds(match.Groups["upperBound"].Captures[upperboundCount - 1].Value);
+          threshold = new Interval(thresholdLb, thresholdUb);
+        }
 
         if (match.Groups["varName"].Success) {
@@ -127,7 +138,7 @@
               throw new ArgumentException($"The constraint {expr} has multiple regions of the same variable.");
           }
-          return new ShapeConstraint(interval, regions, weight);
+          return new ShapeConstraint(interval, regions, weight, threshold);
         } else
-          return new ShapeConstraint(interval, weight);
+          return new ShapeConstraint(interval, weight, threshold);
       } else
         throw new ArgumentException($"The target constraint {expr} is not valid.");
@@ -148,5 +159,6 @@
                                   intervalRegex +
                                   @")*" +
-                                weightRegex
+                                weightRegex +
+                                thresholdRegex
                                 );
 
@@ -172,7 +184,16 @@
         var interval = new Interval(lowerBound, upperBound);
         var weight = 1.0;
+        var threshold = new Interval(double.NegativeInfinity, double.PositiveInfinity);
 
         if (match.Groups["weight"].Success && !string.IsNullOrWhiteSpace(match.Groups["weight"].Value))
           weight = ParseAndValidateDouble(match.Groups["weight"].Value);
+
+        if (match.Groups["threshold"].Success) {
+          var lowerboundCount = match.Groups["lowerBound"].Captures.Count;
+          var upperboundCount = match.Groups["upperBound"].Captures.Count;
+          var thresholdLb = ParseIntervalBounds(match.Groups["lowerBound"].Captures[lowerboundCount - 1].Value);
+          var thresholdUb = ParseIntervalBounds(match.Groups["upperBound"].Captures[upperboundCount - 1].Value);
+          threshold = new Interval(thresholdLb, thresholdUb);
+        }
 
         if (match.Groups["varName"].Captures.Count > 1) {
@@ -189,7 +210,7 @@
               throw new ArgumentException($"The constraint {expr} has multiple regions of the same variable.");
           }
-          return new ShapeConstraint(variable, numberOfDerivation, interval, regions, weight);
+          return new ShapeConstraint(variable, numberOfDerivation, interval, regions, weight, threshold);
         } else
-          return new ShapeConstraint(variable, numberOfDerivation, interval, weight);
+          return new ShapeConstraint(variable, numberOfDerivation, interval, weight, threshold);
       } else
         throw new ArgumentException($"The derivation constraint {expr} is not valid.");
