Free cookie consent management tool by TermsFeed Policy Generator

Changeset 17803


Ignore:
Timestamp:
12/23/20 17:02:12 (4 years ago)
Author:
mkommend
Message:

#2971: Merged r17579, r17580, r17583, r17584, r17754 into stable.

Location:
stable
Files:
1 deleted
29 edited
3 copied

Legend:

Unmodified
Added
Removed
  • stable

  • stable/HeuristicLab.Problems.DataAnalysis

  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic

  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression

  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4

  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/Interfaces/ISymbolicRegressionEvaluator.cs

    r17181 r17803  
    1 using HEAL.Attic;
    2 #region License Information
     1#region License Information
    32/* HeuristicLab
    43 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
     
    2019 */
    2120#endregion
    22 
     21using HEAL.Attic;
    2322
    2423namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression {
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/Interfaces/ISymbolicRegressionModel.cs

    r17181 r17803  
    1 using HEAL.Attic;
    2 #region License Information
     1#region License Information
    32/* HeuristicLab
    43 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
     
    2120#endregion
    2221
     22using HEAL.Attic;
     23
    2324namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression {
    2425  [StorableType("a411e2b5-f926-41a6-b55b-1aef862db2fb")]
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/Interfaces/ISymbolicRegressionSolution.cs

    r17181 r17803  
    2222
    2323
     24
    2425namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression {
    2526  [StorableType("dff1a450-e958-454f-bf8e-6b763fdcaff3")]
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SymbolicRegressionSolution.cs

    r17181 r17803  
    1 #region License Information
     1#region License Information
    22/* HeuristicLab
    33 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
     
    2121
    2222using System.Linq;
     23using HEAL.Attic;
    2324using HeuristicLab.Common;
    2425using HeuristicLab.Core;
     
    2627using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
    2728using HeuristicLab.Optimization;
    28 using HEAL.Attic;
    2929
    3030namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression {
     
    4747    private const string TestNaNEvaluationsResultName = "Test NaN Evaluations";
    4848
     49    private const string ModelBoundsResultName = "Model Bounds";
     50
    4951    public new ISymbolicRegressionModel Model {
    5052      get { return (ISymbolicRegressionModel)base.Model; }
     
    9597      private set { ((IntValue)EstimationLimitsResultCollection[TestNaNEvaluationsResultName].Value).Value = value; }
    9698    }
     99
     100    public IntervalCollection ModelBoundsCollection {
     101      get {
     102        if (!ContainsKey(ModelBoundsResultName)) return null;
     103        return (IntervalCollection)this[ModelBoundsResultName].Value;
     104      }
     105      private set {
     106        if (ContainsKey(ModelBoundsResultName)) {
     107          this[ModelBoundsResultName].Value = value;
     108        } else {
     109          Add(new Result(ModelBoundsResultName, "Results concerning the derivation of symbolic regression solution", value));
     110        }
     111
     112      }
     113    }
     114
     115
    97116
    98117    [StorableConstructor]
     
    118137      estimationLimitResults.Add(new Result(TestNaNEvaluationsResultName, "", new IntValue()));
    119138      Add(new Result(EstimationLimitsResultsResultName, "Results concerning the estimation limits of symbolic regression solution", estimationLimitResults));
     139
     140      if (IntervalInterpreter.IsCompatible(Model.SymbolicExpressionTree))
     141        Add(new Result(ModelBoundsResultName, "Results concerning the derivation of symbolic regression solution", new IntervalCollection()));
     142
    120143      RecalculateResults();
    121144    }
     
    139162        CalculateResults();
    140163      }
     164
     165      if (!ContainsKey(ModelBoundsResultName)) {
     166        if (IntervalInterpreter.IsCompatible(Model.SymbolicExpressionTree)) {
     167          Add(new Result(ModelBoundsResultName, "Results concerning the derivation of symbolic regression solution", new IntervalCollection()));
     168          CalculateResults();
     169        }
     170      }
    141171    }
    142172
     
    159189      TrainingNaNEvaluations = Model.Interpreter.GetSymbolicExpressionTreeValues(Model.SymbolicExpressionTree, ProblemData.Dataset, ProblemData.TrainingIndices).Count(double.IsNaN);
    160190      TestNaNEvaluations = Model.Interpreter.GetSymbolicExpressionTreeValues(Model.SymbolicExpressionTree, ProblemData.Dataset, ProblemData.TestIndices).Count(double.IsNaN);
     191
     192      //Check if the tree contains unknown symbols for the interval calculation
     193      if (IntervalInterpreter.IsCompatible(Model.SymbolicExpressionTree))
     194        ModelBoundsCollection = CalculateModelIntervals(this);
     195    }
     196
     197    private static IntervalCollection CalculateModelIntervals(ISymbolicRegressionSolution solution) {
     198      var intervalEvaluation = new IntervalCollection();
     199      var interpreter = new IntervalInterpreter();
     200      var problemData = solution.ProblemData;
     201      var model = solution.Model;
     202      var variableRanges = problemData.VariableRanges.GetReadonlyDictionary();
     203
     204      intervalEvaluation.AddInterval($"Target {problemData.TargetVariable}", new Interval(variableRanges[problemData.TargetVariable].LowerBound, variableRanges[problemData.TargetVariable].UpperBound));
     205      intervalEvaluation.AddInterval("Model", interpreter.GetSymbolicExpressionTreeInterval(model.SymbolicExpressionTree, variableRanges));
     206
     207      if (DerivativeCalculator.IsCompatible(model.SymbolicExpressionTree)) {
     208        foreach (var inputVariable in model.VariablesUsedForPrediction.OrderBy(v => v, new NaturalStringComparer())) {
     209          var derivedModel = DerivativeCalculator.Derive(model.SymbolicExpressionTree, inputVariable);
     210          var derivedResultInterval = interpreter.GetSymbolicExpressionTreeInterval(derivedModel, variableRanges);
     211
     212          intervalEvaluation.AddInterval(" ∂f/∂" + inputVariable, new Interval(derivedResultInterval.LowerBound, derivedResultInterval.UpperBound));
     213        }
     214      }
     215
     216      return intervalEvaluation;
    161217    }
    162218  }
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Views

  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicDataAnalysisSolutionSimplifierView.cs

    r17500 r17803  
    3535namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Views {
    3636  public abstract partial class InteractiveSymbolicDataAnalysisSolutionSimplifierView : AsynchronousContentView {
    37     private Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> foldedNodes;
    38     private Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> changedNodes;
    39     private Dictionary<ISymbolicExpressionTreeNode, double> nodeImpacts;
     37    private readonly Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> foldedNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>();
     38    private readonly Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> changedNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>();
     39    private readonly Dictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals = new Dictionary<ISymbolicExpressionTreeNode, Interval>();
     40    private readonly Dictionary<ISymbolicExpressionTreeNode, double> nodeImpacts = new Dictionary<ISymbolicExpressionTreeNode, double>();
    4041
    4142    private readonly ISymbolicDataAnalysisSolutionImpactValuesCalculator impactCalculator;
     
    4950    protected InteractiveSymbolicDataAnalysisSolutionSimplifierView(ISymbolicDataAnalysisSolutionImpactValuesCalculator impactCalculator) {
    5051      InitializeComponent();
    51       foldedNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>();
    52       changedNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>();
    53       nodeImpacts = new Dictionary<ISymbolicExpressionTreeNode, double>();
    5452      this.Caption = "Interactive Solution Simplifier";
    5553      this.impactCalculator = impactCalculator;
     
    173171    protected override void OnContentChanged() {
    174172      base.OnContentChanged();
    175       foldedNodes = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>();
     173      foldedNodes.Clear();
     174      changedNodes.Clear();
     175      nodeIntervals.Clear();
     176      nodeImpacts.Clear();
    176177      UpdateView();
    177178      viewHost.Content = this.Content;
     
    205206          foldedNodes[pair.Key] = MakeConstantTreeNode(pair.Value);
    206207        }
    207 
    208         nodeImpacts = impactAndReplacementValues.ToDictionary(x => x.Key, x => x.Value.Item1);
     208       
     209        foreach (var pair in impactAndReplacementValues) {
     210          nodeImpacts[pair.Key] = pair.Value.Item1;
     211        }
     212
     213        if (IntervalInterpreter.IsCompatible(tree)) {
     214          var regressionProblemData = Content.ProblemData as IRegressionProblemData;
     215          if (regressionProblemData != null) {
     216            var interpreter = new IntervalInterpreter();
     217            var variableRanges = regressionProblemData.VariableRanges.GetReadonlyDictionary();
     218            IDictionary<ISymbolicExpressionTreeNode, Interval> intervals;
     219            interpreter.GetSymbolicExpressionTreeIntervals(tree, variableRanges, out intervals);
     220            foreach (var kvp in intervals) {
     221              nodeIntervals[kvp.Key] = kvp.Value;
     222            }
     223          }
     224        }
    209225      } finally {
    210226        progress.Finish();
     
    303319          }
    304320        }
    305         if (visualTree != null)
     321        if (visualTree != null) {
     322          if (nodeIntervals.ContainsKey(treeNode))
     323            visualTree.ToolTip += String.Format($"{Environment.NewLine}Intervals: [{nodeIntervals[treeNode].LowerBound:G5} ... {nodeIntervals[treeNode].UpperBound:G5}]");
    306324          if (changedNodes.ContainsKey(treeNode)) {
    307325            visualTree.LineColor = Color.DodgerBlue;
     
    309327            visualTree.LineColor = Color.DarkOrange;
    310328          }
     329        }
    311330      }
    312331      treeChart.RepaintNodes();
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/IntervalInterpreter.cs

    r17181 r17803  
    2323using System.Collections.Generic;
    2424using System.Linq;
     25using HEAL.Attic;
    2526using HeuristicLab.Common;
    2627using HeuristicLab.Core;
    2728using HeuristicLab.Data;
    2829using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
    29 using HEAL.Attic;
    3030using HeuristicLab.Parameters;
    3131
     
    8080    }
    8181
    82     public Interval GetSymbolicExpressionTreeInterval(ISymbolicExpressionTree tree, IDictionary<string, Interval> variableRanges) {
     82    public Interval GetSymbolicExpressionTreeInterval(ISymbolicExpressionTree tree, IReadOnlyDictionary<string, Interval> variableRanges) {
    8383      lock (syncRoot) {
    8484        EvaluatedSolutions++;
     
    9797
    9898    public Interval GetSymbolicExpressionTreeIntervals(ISymbolicExpressionTree tree,
    99       IDictionary<string, Interval> variableRanges, out IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals) {
     99      IReadOnlyDictionary<string, Interval> variableRanges, out IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals) {
    100100      lock (syncRoot) {
    101101        EvaluatedSolutions++;
     
    124124
    125125
    126     private static Instruction[] PrepareInterpreterState(ISymbolicExpressionTree tree, IDictionary<string, Interval> variableRanges) {
     126    private static Instruction[] PrepareInterpreterState(ISymbolicExpressionTree tree, IReadOnlyDictionary<string, Interval> variableRanges) {
    127127      if (variableRanges == null)
    128128        throw new ArgumentNullException("No variablew ranges are present!", nameof(variableRanges));
     
    234234            break;
    235235          }
    236         case OpCodes.Power: {
    237             result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    238             for (int i = 1; i < currentInstr.nArguments; i++) {
    239               var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    240               result = Interval.Power(result, argumentInterval);
    241             }
    242             break;
    243           }
    244236        case OpCodes.Square: {
    245237            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     
    247239            break;
    248240          }
    249         case OpCodes.Root: {
    250             result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    251             for (int i = 1; i < currentInstr.nArguments; i++) {
    252               var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    253               result = Interval.Root(result, argumentInterval);
    254             }
    255             break;
    256           }
    257241        case OpCodes.SquareRoot: {
    258242            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
    259243            result = Interval.SquareRoot(argumentInterval);
     244            break;
     245          }
     246        case OpCodes.Cube: {
     247            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     248            result = Interval.Cube(argumentInterval);
     249            break;
     250          }
     251        case OpCodes.CubeRoot: {
     252            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     253            result = Interval.CubicRoot(argumentInterval);
     254            break;
     255          }
     256        case OpCodes.Absolute: {
     257            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     258            result = Interval.Absolute(argumentInterval);
     259            break;
     260          }
     261        case OpCodes.AnalyticQuotient: {
     262            result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     263            for (var i = 1; i < currentInstr.nArguments; i++) {
     264              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
     265              result = Interval.AnalyticalQuotient(result, argumentInterval);
     266            }
     267
    260268            break;
    261269          }
     
    274282        from n in tree.Root.GetSubtree(0).IterateNodesPrefix()
    275283        where
     284          !(n.Symbol is Problems.DataAnalysis.Symbolic.Variable) &&
     285          !(n.Symbol is Constant) &&
    276286          !(n.Symbol is StartSymbol) &&
    277287          !(n.Symbol is Addition) &&
     
    284294          !(n.Symbol is Logarithm) &&
    285295          !(n.Symbol is Exponential) &&
    286           !(n.Symbol is Power) &&
    287296          !(n.Symbol is Square) &&
    288           !(n.Symbol is Root) &&
    289297          !(n.Symbol is SquareRoot) &&
    290           !(n.Symbol is Problems.DataAnalysis.Symbolic.Variable) &&
    291           !(n.Symbol is Constant)
     298          !(n.Symbol is Cube) &&
     299          !(n.Symbol is CubeRoot) &&
     300          !(n.Symbol is Absolute) &&
     301          !(n.Symbol is AnalyticQuotient)
    292302        select n).Any();
    293303      return !containsUnknownSyumbol;
  • stable/HeuristicLab.Problems.DataAnalysis.Views

  • stable/HeuristicLab.Problems.DataAnalysis.Views/3.4

  • stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/Controls/PartialDependencePlot.cs

    r17181 r17803  
    3636namespace HeuristicLab.Problems.DataAnalysis.Views {
    3737  public partial class PartialDependencePlot : UserControl, IPartialDependencePlot {
    38     private ModifiableDataset sharedFixedVariables; // used for syncronising variable values between charts
     38    private ModifiableDataset sharedFixedVariables; // used for synchronizing variable values between charts
    3939    private ModifiableDataset internalDataset; // holds the x values for each point drawn
    4040
     
    351351
    352352    private void RecalculateTrainingLimits(bool initializeAxisRanges) {
    353       trainingMin = solutions.Select(s => s.ProblemData.Dataset.GetDoubleValues(freeVariable, s.ProblemData.TrainingIndices).Where(x => !double.IsNaN(x)).Min()).Max();
    354       trainingMax = solutions.Select(s => s.ProblemData.Dataset.GetDoubleValues(freeVariable, s.ProblemData.TrainingIndices).Where(x => !double.IsNaN(x)).Max()).Min();
     353      //Set min and max to the interval ranges
     354      trainingMin = solutions.Select(s => s.ProblemData.VariableRanges.GetInterval(freeVariable).LowerBound).Max();
     355      trainingMax = solutions.Select(s => s.ProblemData.VariableRanges.GetInterval(freeVariable).UpperBound).Min();
    355356
    356357      if (initializeAxisRanges) {
     
    438439      chart.Palette = ChartColorPalette.None;
    439440
    440       // Add confidence interval series before its coresponding series for correct z index
     441      // Add confidence interval series before its corresponding series for correct z index
    441442      foreach (var solution in solutions) {
    442443        Series ciSeries;
  • stable/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj

    r17105 r17803  
    221221    <Compile Include="Interfaces\IDataPreprocessorStarter.cs" />
    222222    <Compile Include="Interfaces\IPartialDependencePlot.cs" />
     223    <Compile Include="IntervalCollectionView.cs">
     224      <SubType>UserControl</SubType>
     225    </Compile>
     226    <Compile Include="IntervalCollectionView.Designer.cs">
     227      <DependentUpon>IntervalCollectionView.cs</DependentUpon>
     228    </Compile>
    223229    <Compile Include="MenuItems\ChangeDataOfOptimizersMenuItem.cs" />
    224230    <Compile Include="MenuItems\ShrinkDataAnalysisRunsMenuItem.cs" />
  • stable/HeuristicLab.Problems.DataAnalysis/3.4

  • stable/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj

    r17177 r17803  
    140140    <Compile Include="Implementation\ConstantModel.cs" />
    141141    <Compile Include="Implementation\DataAnalysisModel.cs" />
    142     <Compile Include="Implementation\Interval.cs" />
     142    <Compile Include="Implementation\Interval\Interval.cs" />
     143    <Compile Include="Implementation\Interval\IntervalCollection.cs" />
    143144    <Compile Include="Implementation\Regression\ConfidenceBoundRegressionSolution.cs" />
    144145    <Compile Include="Implementation\Regression\ConstantRegressionModel.cs" />
  • stable/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Interval/Interval.cs

    r17579 r17803  
    237237
    238238    /// <summary>
    239     /// Calculates the principal square root of a given interval. Discards the second possible result of root, because
    240     /// all interpreters just calculate the positive principal root.
     239    /// The interval contains both possible results of the calculated square root +-sqrt(x). That results in a wider
     240    /// interval, but it contains all possible solutions.
    241241    /// </summary>
    242242    /// <param name="a">Interval to build square root from.</param>
     
    244244    public static Interval SquareRoot(Interval a) {
    245245      if (a.LowerBound < 0) return new Interval(double.NaN, double.NaN);
    246       return new Interval(Math.Sqrt(a.LowerBound), Math.Sqrt(a.UpperBound));
     246      return new Interval(-Math.Sqrt(a.UpperBound), Math.Sqrt(a.UpperBound));
    247247    }
    248248
  • stable/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblemData.cs

    r17181 r17803  
    1 #region License Information
     1#region License Information
    22/* HeuristicLab
    33 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
     
    2323using System.Collections.Generic;
    2424using System.Linq;
     25using HEAL.Attic;
    2526using HeuristicLab.Common;
    2627using HeuristicLab.Core;
    2728using HeuristicLab.Data;
    2829using HeuristicLab.Parameters;
    29 using HEAL.Attic;
    3030
    3131namespace HeuristicLab.Problems.DataAnalysis {
     
    3434  public class RegressionProblemData : DataAnalysisProblemData, IRegressionProblemData, IStorableContent {
    3535    protected const string TargetVariableParameterName = "TargetVariable";
     36    protected const string VariableRangesParameterName = "VariableRanges";
     37    protected const string IntervalConstraintsParameterName = "IntervalConstraints";
    3638    public string Filename { get; set; }
    3739
     
    9193      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TestPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
    9294      problemData.Parameters.Add(new ConstrainedValueParameter<StringValue>(TargetVariableParameterName, new ItemSet<StringValue>()));
     95      problemData.Parameters.Add(new FixedValueParameter<IntervalCollection>(VariableRangesParameterName, "", new IntervalCollection()));
    9396      emptyProblemData = problemData;
    9497    }
     
    98101      get { return (IConstrainedValueParameter<StringValue>)Parameters[TargetVariableParameterName]; }
    99102    }
     103
     104    public IFixedValueParameter<IntervalCollection> VariableRangesParameter => (IFixedValueParameter<IntervalCollection>)Parameters[VariableRangesParameterName];
     105
     106    public IntervalCollection VariableRanges {
     107      get => VariableRangesParameter.Value;
     108    }
     109
     110
    100111    public string TargetVariable {
    101112      get { return TargetVariableParameter.Value.Value; }
     
    125136    [StorableHook(HookType.AfterDeserialization)]
    126137    private void AfterDeserialization() {
     138      if (!Parameters.ContainsKey(VariableRangesParameterName)) {
     139        var intervalCollection = CalculateDatasetIntervals(this.Dataset);
     140        Parameters.Add(new FixedValueParameter<IntervalCollection>(VariableRangesParameterName, intervalCollection));
     141      }
    127142      RegisterParameterEvents();
    128143    }
     
    152167      var variables = InputVariables.Select(x => x.AsReadOnly()).ToList();
    153168      Parameters.Add(new ConstrainedValueParameter<StringValue>(TargetVariableParameterName, new ItemSet<StringValue>(variables), variables.Where(x => x.Value == targetVariable).First()));
     169      var intervalCollection = CalculateDatasetIntervals(this.Dataset);
     170      Parameters.Add(new FixedValueParameter<IntervalCollection>(VariableRangesParameterName, intervalCollection));
    154171      RegisterParameterEvents();
     172    }
     173
     174    private static IntervalCollection CalculateDatasetIntervals(IDataset dataset) {
     175      IntervalCollection intervalCollection = new IntervalCollection();
     176      foreach (var variable in dataset.DoubleVariables) {// intervals are only possible for double variables
     177        var variableInterval = Interval.GetInterval(dataset.GetDoubleValues(variable));
     178        intervalCollection.AddInterval(variable, variableInterval);
     179      }
     180
     181      return intervalCollection;
    155182    }
    156183
  • stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisModel.cs

    r17181 r17803  
    2525
    2626namespace HeuristicLab.Problems.DataAnalysis {
    27   [StorableType("f85ccf7a-7df5-431e-bc4d-be6f3c4c2338")]
    2827  /// <summary>
    2928  /// Interface for all data-analysis models (regression/classification/clustering).
    3029  /// <remarks>All methods and properties in in this interface must be implemented thread safely</remarks>
    3130  /// </summary>
     31  [StorableType("f85ccf7a-7df5-431e-bc4d-be6f3c4c2338")]
    3232  public interface IDataAnalysisModel : INamedItem {
    3333    IEnumerable<string> VariablesUsedForPrediction { get; }
  • stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisProblem.cs

    r17181 r17803  
    3535  [StorableType("c2f6fcdd-ab62-4423-be75-01aa694df411")]
    3636  public interface IDataAnalysisProblem<T> : IDataAnalysisProblem
    37   where T : class, IDataAnalysisProblemData {
     37    where T : class, IDataAnalysisProblemData {
    3838    new IValueParameter<T> ProblemDataParameter { get; }
    3939    new T ProblemData { get; set; }
  • stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDependencyCalculator.cs

    r17181 r17803  
    2222using System;
    2323using System.Collections.Generic;
     24using HEAL.Attic;
    2425
    2526namespace HeuristicLab.Problems.DataAnalysis {
     27  [StorableType("3283B3FB-8467-4B99-9B6E-23BF3D1B8505")]
    2628  public interface IDependencyCalculator {
    2729    double Maximum { get; }
  • stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IOnlineCalculator.cs

    r17181 r17803  
    2222
    2323using System;
     24using HEAL.Attic;
     25
    2426namespace HeuristicLab.Problems.DataAnalysis {
    2527  [Flags]
     28  [StorableType("8A28DDA1-4814-4B77-9457-0EE930BE9C73")]
    2629  public enum OnlineCalculatorError {
    2730    /// <summary>
     
    3841    InsufficientElementsAdded = 2
    3942  }
     43
     44  [StorableType("119C8242-3EE7-4C34-A7AC-68ABF76EB11B")]
    4045  public interface IOnlineCalculator {
    4146    OnlineCalculatorError ErrorState { get; }
  • stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionProblemData.cs

    r17181 r17803  
    2828    string TargetVariable { get; set; }
    2929
     30    IntervalCollection VariableRanges { get;}
     31
    3032    IEnumerable<double> TargetVariableValues { get; }
    3133    IEnumerable<double> TargetVariableTrainingValues { get; }
  • stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/IOnlineTimeSeriesCalculator.cs

    r17181 r17803  
    2222
    2323using System.Collections.Generic;
     24using HEAL.Attic;
    2425
    2526namespace HeuristicLab.Problems.DataAnalysis {
     27  [StorableType("7461AC5D-9D9A-4DCD-B32F-602260E58FFC")]
    2628  public interface IOnlineTimeSeriesCalculator {
    2729    OnlineCalculatorError ErrorState { get; }
  • stable/HeuristicLab.Tests

  • stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis-3.4/IntervalTest.cs

    r17495 r17803  
    11using System;
     2using System.Collections.Generic;
    23using Microsoft.VisualStudio.TestTools.UnitTesting;
    34
     
    141142    [TestProperty("Time", "short")]
    142143    public void SquarerootIntervalTest() {
    143       Assert.AreEqual<Interval>(new Interval(1, 2), Interval.SquareRoot(new Interval(1, 4)));
     144      Assert.AreEqual<Interval>(new Interval(-2, 2), Interval.SquareRoot(new Interval(1, 4)));
    144145      Assert.AreEqual<Interval>(new Interval(double.NaN, double.NaN), Interval.SquareRoot(new Interval(-4, -1)));
    145146    }
     
    192193
    193194      //Second interval goes over zero
    194       Assert.AreEqual(new Interval(aPos.LowerBound/Math.Sqrt(17), aPos.UpperBound), Interval.AnalyticalQuotient(aPos, bZero));
    195       Assert.AreEqual(new Interval(aZero.LowerBound, aZero.UpperBound), Interval.AnalyticalQuotient(aZero, bZero));
    196       Assert.AreEqual(new Interval(aNeg.LowerBound, aNeg.UpperBound/Math.Sqrt(17)), Interval.AnalyticalQuotient(aNeg, bZero));
    197       //Second interval is positive
    198       Assert.AreEqual(new Interval(aPos.LowerBound/Math.Sqrt(17), aPos.UpperBound/Math.Sqrt(5)), Interval.AnalyticalQuotient(aPos, bPos));
    199       Assert.AreEqual(new Interval(aZero.LowerBound/Math.Sqrt(5), aZero.UpperBound/Math.Sqrt(5)), Interval.AnalyticalQuotient(aZero, bPos));
    200       Assert.AreEqual(new Interval(aNeg.LowerBound/Math.Sqrt(5), aNeg.UpperBound/Math.Sqrt(17)), Interval.AnalyticalQuotient(aNeg, bPos));
    201       //Second interval is negative
    202       Assert.AreEqual(new Interval(aPos.LowerBound/Math.Sqrt(17), aPos.UpperBound/Math.Sqrt(5)), Interval.AnalyticalQuotient(aPos, bNeg));
    203       Assert.AreEqual(new Interval(aZero.LowerBound/Math.Sqrt(5), aZero.UpperBound/Math.Sqrt(5)), Interval.AnalyticalQuotient(aZero, bNeg));
    204       Assert.AreEqual(new Interval(aNeg.LowerBound/Math.Sqrt(5), aNeg.UpperBound/Math.Sqrt(17)), Interval.AnalyticalQuotient(aNeg, bNeg));
     195      //Assert.AreEqual(new Interval(aPos.LowerBound/Math.Sqrt(17), aPos.UpperBound), Interval.AnalyticalQuotient(aPos, bZero));
     196      //Assert.AreEqual(new Interval(aZero.LowerBound, aZero.UpperBound), Interval.AnalyticalQuotient(aZero, bZero));
     197      //Assert.AreEqual(new Interval(aNeg.LowerBound, aNeg.UpperBound/Math.Sqrt(17)), Interval.AnalyticalQuotient(aNeg, bZero));
     198      ////Second interval is positive
     199      //Assert.AreEqual(new Interval(aPos.LowerBound/Math.Sqrt(17), aPos.UpperBound/Math.Sqrt(5)), Interval.AnalyticalQuotient(aPos, bPos));
     200      //Assert.AreEqual(new Interval(aZero.LowerBound/Math.Sqrt(5), aZero.UpperBound/Math.Sqrt(5)), Interval.AnalyticalQuotient(aZero, bPos));
     201      //Assert.AreEqual(new Interval(aNeg.LowerBound/Math.Sqrt(5), aNeg.UpperBound/Math.Sqrt(17)), Interval.AnalyticalQuotient(aNeg, bPos));
     202      ////Second interval is negative
     203      //Assert.AreEqual(new Interval(aPos.LowerBound/Math.Sqrt(17), aPos.UpperBound/Math.Sqrt(5)), Interval.AnalyticalQuotient(aPos, bNeg));
     204      //Assert.AreEqual(new Interval(aZero.LowerBound/Math.Sqrt(5), aZero.UpperBound/Math.Sqrt(5)), Interval.AnalyticalQuotient(aZero, bNeg));
     205      //Assert.AreEqual(new Interval(aNeg.LowerBound/Math.Sqrt(5), aNeg.UpperBound/Math.Sqrt(17)), Interval.AnalyticalQuotient(aNeg, bNeg));
     206      Assert.AreEqual(new Interval(double.NegativeInfinity, double.PositiveInfinity), Interval.AnalyticalQuotient(aPos, bZero));
     207      Assert.AreEqual(new Interval(double.NegativeInfinity, double.PositiveInfinity), Interval.AnalyticalQuotient(aPos, bPos));
     208      Assert.AreEqual(new Interval(double.NegativeInfinity, double.PositiveInfinity), Interval.AnalyticalQuotient(aZero, bNeg));
    205209    }
    206210
     
    247251      Assert.AreEqual(0, zeroInterval.LowerBound);
    248252      Assert.AreEqual(0, zeroInterval.UpperBound);
    249 
    250     }
     253    }
     254
     255    [TestMethod]
     256    [TestCategory("Problems.DataAnalysis")]
     257    [TestProperty("Time", "short")]
     258    public void ContaintsTest() {
     259      var negativeInterval = new Interval(-10, -5);
     260      var positiveInterval = new Interval(5, 10);
     261      var overZeroInterval = new Interval(-5, 5);
     262
     263      //Tests for negative intervals
     264      Assert.AreEqual(true, negativeInterval.Contains(new Interval(-9, -7)));
     265      Assert.AreEqual(false, negativeInterval.Contains(new Interval(-11, -3)));
     266      Assert.AreEqual(false, negativeInterval.Contains(positiveInterval));
     267      Assert.AreEqual(false, negativeInterval.Contains(overZeroInterval));
     268      Assert.AreEqual(true, negativeInterval.Contains(-8));
     269      Assert.AreEqual(false, negativeInterval.Contains(-12));
     270      Assert.AreEqual(false, negativeInterval.Contains(0));
     271      //Testes for positive intervals
     272      Assert.AreEqual(true, positiveInterval.Contains(new Interval(6, 10)));
     273      Assert.AreEqual(false, positiveInterval.Contains(new Interval(6, 12)));
     274      Assert.AreEqual(false, positiveInterval.Contains(negativeInterval));
     275      Assert.AreEqual(false, positiveInterval.Contains(overZeroInterval));
     276      Assert.AreEqual(true, positiveInterval.Contains(7));
     277      Assert.AreEqual(false, positiveInterval.Contains(11));
     278      Assert.AreEqual(false, positiveInterval.Contains(0));
     279      //Tests for over zero intervals
     280      Assert.AreEqual(true, overZeroInterval.Contains(new Interval(-3, 3)));
     281      Assert.AreEqual(true, overZeroInterval.Contains(new Interval(-4, -1)));
     282      Assert.AreEqual(true, overZeroInterval.Contains(new Interval(1, 5)));
     283      Assert.AreEqual(false, overZeroInterval.Contains(new Interval(-6, 0)));
     284      Assert.AreEqual(false, overZeroInterval.Contains(new Interval(0, 6)));
     285      Assert.AreEqual(false, overZeroInterval.Contains(new Interval(-7, 7)));
     286      Assert.AreEqual(true, overZeroInterval.Contains(-3));
     287      Assert.AreEqual(true, overZeroInterval.Contains(0));
     288      Assert.AreEqual(true, overZeroInterval.Contains(3));
     289      Assert.AreEqual(false, overZeroInterval.Contains(12));
     290      Assert.AreEqual(false, overZeroInterval.Contains(-7));
     291    }
     292
     293    [TestMethod]
     294    [TestCategory("Problems.DataAnalysis")]
     295    [TestProperty("Time", "short")]
     296    public void GetIntervalTest() {
     297      var values = new List<double>() { -2.5, -9, 2, 7, 0 ,12, 12.4, 12.4, 9.29, 1002, -29.9};
     298      var valuesNan = new List<double>() { double.NaN, 2, 4, 19, -2, -12.2};
     299      var valuesInf = new List<double>() {double.NegativeInfinity, double.PositiveInfinity, 12, 2, -2, -12.2};
     300
     301      var valuesInterval = new Interval(-29.9, 1002);
     302      var valuesNanInterval = new Interval(double.NaN, double.NaN);
     303      var valuesInfInterval = new Interval(double.NegativeInfinity, double.PositiveInfinity);
     304
     305
     306      Assert.AreEqual(valuesInterval, Interval.GetInterval(values));
     307      Assert.AreEqual(valuesNanInterval, Interval.GetInterval(valuesNan));
     308      Assert.AreEqual(valuesInfInterval, Interval.GetInterval(valuesInf));
     309    }
     310
     311    [TestMethod]
     312    [TestCategory("Problems.DataAnalysis")]
     313    [TestProperty("Time", "short")]
     314    public void GeometricTest() {
     315      Assert.AreEqual(new Interval(-1, -0.936456687290796), Interval.Cosine(new Interval(3, 3.5)));
     316      Assert.AreEqual(new Interval(-1, -0.936456687290796), Interval.Cosine(new Interval(-3.5, -3)));
     317      Assert.AreEqual(new Interval(-1, 1), Interval.Cosine(new Interval(-3.5, 3)));
     318      Assert.AreEqual(new Interval(-0.839071529076452, 0.843853958732493), Interval.Cosine(new Interval(10, 12)));
     319      Assert.AreEqual(new Interval(0.136737218207833, 0.907446781450197), Interval.Cosine(new Interval(13, 14)));
     320      Assert.AreEqual(new Interval(-0.839071529076452, 1), Interval.Cosine(new Interval(10, 14)));
     321      Assert.AreEqual(new Interval(-1, 0.136737218207833), Interval.Cosine(new Interval(14, 16)));
     322      Assert.AreEqual(new Interval(-0.839071529076452, 0.004425697988051), Interval.Cosine(new Interval(-11, -10)));
     323      Assert.AreEqual(new Interval(0.136737218207833, 0.907446781450197), Interval.Cosine(new Interval(-14, -13)));
     324      Assert.AreEqual(new Interval(-1, 0.136737218207833), Interval.Cosine(new Interval(-16, -14)));
     325      Assert.AreEqual(new Interval(0.101585703696621, 1), Interval.Cosine(new Interval(-102, -100)));
     326      Assert.AreEqual(new Interval(-1, 1), Interval.Cosine(new Interval(4.6e15, 4.7e15)));
     327      Assert.AreEqual(new Interval(0.87758256189037265, 0.87758256189037276), Interval.Cosine(new Interval(0.5, 0.5)));
     328      Assert.AreEqual(new Interval(-0.09904103659872825, 0.8775825618903728), Interval.Cosine(new Interval(0.5, 1.67)));
     329      Assert.AreEqual(new Interval(-1.0, 0.77556587851025016), Interval.Cosine(new Interval(2.1, 5.6)));
     330      Assert.AreEqual(new Interval(-1.0, 1.0), Interval.Cosine(new Interval(0.5, 8.5)));
     331      Assert.AreEqual(new Interval(-1.0, -0.09904103659872801), Interval.Cosine(new Interval(1.67, 3.2)));
     332
     333
     334      Assert.AreEqual(new Interval(double.NegativeInfinity, double.PositiveInfinity), Interval.Tangens(new Interval(double.NegativeInfinity, double.PositiveInfinity)));
     335      Assert.AreEqual(new Interval(0, 1.55740772465490223051), Interval.Tangens(new Interval(0, 1)));
     336      Assert.AreEqual(new Interval(-1.55740772465490223051, 0), Interval.Tangens(new Interval(-1, 0)));
     337      Assert.AreEqual(new Interval(double.NegativeInfinity, double.PositiveInfinity), Interval.Tangens(new Interval(-2, -1)));
     338      Assert.AreEqual(new Interval(double.NegativeInfinity, double.PositiveInfinity), Interval.Tangens(new Interval(202, 203)));
     339      Assert.AreEqual(new Interval(0.54630248984379048, 0.5463024898437906), Interval.Tangens(new Interval(0.5, 0.5)));
     340      Assert.AreEqual(new Interval(double.NegativeInfinity, double.PositiveInfinity), Interval.Tangens(new Interval(0.5,
     341        1.67)));
     342      //Assert.AreEqual(new Interval(-10.047182299210307, 0.5847385445957865), Interval.Tangens(new Interval(1.67, 3.2)));
     343      Assert.AreEqual(new Interval(double.NegativeInfinity, double.PositiveInfinity), Interval.Tangens(new Interval(
     344        6.638314112824137, 8.38263151220128)));
     345
     346
     347
     348      Assert.AreEqual(new Interval(0.47942553860420295, 0.47942553860420301), Interval.Sine(new Interval(0.5, 0.5)));
     349      Assert.AreEqual(new Interval(4.7942553860420295e-01, 1.0), Interval.Sine(new Interval(0.5, 1.67)));
     350      Assert.AreEqual(new Interval(-5.8374143427580093e-02, 9.9508334981018021e-01), Interval.Sine(new Interval(1.67,
     351        3.2)));
     352      Assert.AreEqual(new Interval(-1.0, 0.863209366648874), Interval.Sine(new Interval(2.1, 5.6)));
     353      Assert.AreEqual(new Interval(-1.0, 1.0), Interval.Sine(new Interval(0.5, 8.5)));
     354      Assert.AreEqual(new Interval(-1.0, 0.9775301176650971), Interval.Sine(new Interval(-4.5, 0.1)));
     355      Assert.AreEqual(new Interval(-1.0, 1.0), Interval.Sine(new Interval(1.3, 6.3)));
     356    }
     357
     358    [TestMethod]
     359    [TestCategory("Problems.DataAnalysis")]
     360    [TestProperty("Time", "short")]
     361    public void EqualsTest() {
     362      var interval1 = new Interval(0, 12);
     363      var interval2 = new Interval(-12, 8);
     364      var interval3 = new Interval(double.NegativeInfinity, 0);
     365
     366      Assert.AreEqual(true, interval1.Equals(new Interval(0, 12)));
     367      Assert.AreEqual(false, interval1.Equals(interval2));
     368      Assert.AreEqual(true, interval3 == new Interval(double.NegativeInfinity, 0));
     369      Assert.AreEqual(true, interval1 != interval2);
     370      Assert.AreEqual(false, interval2 == interval3);
     371      Assert.AreEqual(false, interval1 != new Interval(0, 12));
     372    }
     373    //[TestMethod]
     374    //[TestCategory("Problems.DataAnalysis")]
     375    //[TestProperty("Time", "short")]
     376    //public void RootTest() {
     377    //  var posInterval = new Interval(3, 5);
     378    //  var negInterval = new Interval(-6, -2);
     379    //  var posIntervalConst = new Interval(5, 5);
     380    //  var negIntervalConst = new Interval(-3, -3);
     381    //  var zeroIntervalConst = new Interval(0, 0);
     382    //  var zeroPosInterval = new Interval(0, 2);
     383    //  var zeroNegInterval = new Interval(-2, 0);
     384
     385    //  var posRoot = new Interval(4, 4);
     386    //  var negRoot = new Interval(-4, -4);
     387    //  var zeroRoot = new Interval(0, 0);
     388    //  var oneRoot = new Interval(1, 1);
     389
     390    //  Assert.AreEqual(Interval.Root(posInterval, posRoot), new Interval(Math.Pow(3, (1.0/4)), Math.Pow(5, (1.0/4))));
     391    //  Assert.AreEqual(Interval.Root(posInterval, negRoot), new Interval(Math.Pow(5, -(1.0/4)), Math.Pow(3, -(1.0/4))));
     392    //  Assert.AreEqual(Interval.Root(posInterval, zeroRoot), new Interval(double.NaN, double.NaN));
     393    //  Assert.AreEqual(Interval.Root(posInterval, oneRoot), new Interval(3, 5));
     394
     395    //  Assert.AreEqual(Interval.Root(negInterval, posRoot), new Interval(Math.Pow(-6, (1.0 / 4)), Math.Pow(-2, (1.0 / 4))));
     396    //  Assert.AreEqual(Interval.Root(negInterval, negRoot), new Interval(Math.Pow(-2, -(1.0 / 4)), Math.Pow(-6, -(1.0 / 4))));
     397    //  Assert.AreEqual(Interval.Root(negInterval, zeroRoot), new Interval(double.NaN, double.NaN));
     398    //  Assert.AreEqual(Interval.Root(negInterval, oneRoot), new Interval(-6, -2));
     399
     400    //  Assert.AreEqual(Interval.Root(posIntervalConst, posRoot), new Interval(Math.Pow(5, (1.0 / 4)), Math.Pow(5, (1.0 / 4))));
     401    //  Assert.AreEqual(Interval.Root(posIntervalConst, negRoot), new Interval(Math.Pow(5, -(1.0 / 4)), Math.Pow(5, -(1.0 / 4))));
     402    //  Assert.AreEqual(Interval.Root(posIntervalConst, zeroRoot), new Interval(double.NaN, double.NaN));
     403    //  Assert.AreEqual(Interval.Root(posIntervalConst, oneRoot), new Interval(5, 5));
     404
     405    //  Assert.AreEqual(Interval.Root(negIntervalConst, posRoot), new Interval(Math.Pow(-3, (1.0 / 4)), Math.Pow(-3, (1.0 / 4))));
     406    //  Assert.AreEqual(Interval.Root(negIntervalConst, negRoot), new Interval(Math.Pow(-3, -(1.0 / 4)), Math.Pow(-3, -(1.0 / 4))));
     407    //  Assert.AreEqual(Interval.Root(negIntervalConst, zeroRoot), new Interval(double.NaN, double.NaN));
     408    //  Assert.AreEqual(Interval.Root(negIntervalConst, oneRoot), new Interval(-3, -3));
     409
     410    //  Assert.AreEqual(Interval.Root(zeroIntervalConst, posRoot), new Interval(0, 0));
     411    //  //Compley Infinity https://www.wolframalpha.com/input/?i=root%28-4%2C+0%29
     412    //  Assert.AreEqual(Interval.Root(zeroIntervalConst, negRoot), new Interval(double.PositiveInfinity, double.PositiveInfinity));
     413    //  Assert.AreEqual(Interval.Root(zeroIntervalConst, zeroRoot), new Interval(0, 0));
     414    //  Assert.AreEqual(Interval.Root(zeroIntervalConst, oneRoot), new Interval(0, 0));
     415
     416    //  Assert.AreEqual(Interval.Root(zeroPosInterval, posRoot), new Interval(0, Math.Pow(2, (1.0 / 4))));
     417    //  //Check for complex infinity
     418    //  Assert.AreEqual(Interval.Root(zeroPosInterval, negRoot), new Interval(Math.Pow(2, -(1.0 / 4)), double.PositiveInfinity));
     419    //  Assert.AreEqual(Interval.Root(zeroPosInterval, zeroRoot), new Interval(0, 0));
     420    //  Assert.AreEqual(Interval.Root(zeroPosInterval, oneRoot), new Interval(0, 2));
     421
     422    //  Assert.AreEqual(Interval.Root(zeroNegInterval, posRoot), new Interval(Math.Pow(-2, (1.0 / 4)),0));
     423    //  //Check for complex infinity
     424    //  Assert.AreEqual(Interval.Root(zeroNegInterval, negRoot), new Interval(Math.Pow(-2, -(1.0 / 4)), double.PositiveInfinity));
     425    //  Assert.AreEqual(Interval.Root(zeroNegInterval, zeroRoot), new Interval(double.NaN, double.NaN));
     426    //  Assert.AreEqual(Interval.Root(zeroNegInterval, oneRoot), new Interval(-2, 0));
     427    //}
    251428  }
    252429}
  • stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/IntervalInterpreterTest.cs

    r17100 r17803  
    4040      Interval result;
    4141      if (variableRanges == null)
    42         result = interpreter.GetSymbolicExpressionTreeInterval(tree, problemData.Dataset, problemData.AllIndices);
     42        result = interpreter.GetSymbolicExpressionTreeInterval(tree, problemData.Dataset, rows:problemData.AllIndices);
    4343      else
    4444        result = interpreter.GetSymbolicExpressionTreeInterval(tree, variableRanges);
     
    163163    }
    164164
    165     [TestMethod]
    166     [TestCategory("Problems.DataAnalysis.Symbolic")]
    167     [TestProperty("Time", "short")]
    168     public void TestIntervalInterpreterExpRoot() {
    169       EvaluateTest("exp(root(x1*x2, 2))", new Interval(Math.Exp(Math.Sqrt(6)), Math.Exp(Math.Sqrt(48))));
    170       EvaluateTest("exp(root(x1*x2, 2))", new Interval(Math.Exp(Math.Sqrt(4)), Math.Exp(Math.Sqrt(60))), variableRanges);
    171     }
    172 
    173     [TestMethod]
    174     [TestCategory("Problems.DataAnalysis.Symbolic")]
    175     [TestProperty("Time", "short")]
    176     public void TestIntervalInterpreterPower() {
    177       EvaluateTest("pow(x1, 2)", new Interval(Math.Pow(3, 1), Math.Pow(8, 3)));
    178     }
    179165  }
    180166}
Note: See TracChangeset for help on using the changeset viewer.