Changeset 16461


Ignore:
Timestamp:
12/28/18 15:44:31 (8 weeks ago)
Author:
mkommend
Message:

#2974: Added unit tests and refactoring.

Location:
branches/2974_Constants_Optimization
Files:
7 added
5 edited

Legend:

Unmodified
Added
Removed
  • branches/2974_Constants_Optimization/ConstantsOptimization.sln

    r16456 r16461  
    1515EndProject
    1616Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Problems.DataAnalysis.Symbolic-3.4", "HeuristicLab.Problems.DataAnalysis.Symbolic\3.4\HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj", "{3D28463F-EC96-4D82-AFEE-38BE91A0CA00}"
     17EndProject
     18Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{9617D7C7-90FB-41BB-A9B2-6DAC68E15197}"
    1719EndProject
    1820Global
     
    5052    {3D28463F-EC96-4D82-AFEE-38BE91A0CA00}.Release|x86.ActiveCfg = Release|x86
    5153    {3D28463F-EC96-4D82-AFEE-38BE91A0CA00}.Release|x86.Build.0 = Release|x86
     54    {9617D7C7-90FB-41BB-A9B2-6DAC68E15197}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
     55    {9617D7C7-90FB-41BB-A9B2-6DAC68E15197}.Debug|Any CPU.Build.0 = Debug|Any CPU
     56    {9617D7C7-90FB-41BB-A9B2-6DAC68E15197}.Debug|x64.ActiveCfg = Debug|Any CPU
     57    {9617D7C7-90FB-41BB-A9B2-6DAC68E15197}.Debug|x64.Build.0 = Debug|Any CPU
     58    {9617D7C7-90FB-41BB-A9B2-6DAC68E15197}.Debug|x86.ActiveCfg = Debug|Any CPU
     59    {9617D7C7-90FB-41BB-A9B2-6DAC68E15197}.Debug|x86.Build.0 = Debug|Any CPU
     60    {9617D7C7-90FB-41BB-A9B2-6DAC68E15197}.Release|Any CPU.ActiveCfg = Release|Any CPU
     61    {9617D7C7-90FB-41BB-A9B2-6DAC68E15197}.Release|Any CPU.Build.0 = Release|Any CPU
     62    {9617D7C7-90FB-41BB-A9B2-6DAC68E15197}.Release|x64.ActiveCfg = Release|Any CPU
     63    {9617D7C7-90FB-41BB-A9B2-6DAC68E15197}.Release|x64.Build.0 = Release|Any CPU
     64    {9617D7C7-90FB-41BB-A9B2-6DAC68E15197}.Release|x86.ActiveCfg = Release|Any CPU
     65    {9617D7C7-90FB-41BB-A9B2-6DAC68E15197}.Release|x86.Build.0 = Release|Any CPU
    5266  EndGlobalSection
    5367  GlobalSection(SolutionProperties) = preSolution
  • branches/2974_Constants_Optimization/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4.csproj

    r16460 r16461  
    102102      <HintPath>..\..\..\..\trunk\bin\ALGLIB-3.7.0.dll</HintPath>
    103103      <Private>False</Private>
     104    </Reference>
     105    <Reference Include="AutoDiff-1.0, Version=1.0.0.14388, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
     106      <SpecificVersion>False</SpecificVersion>
     107      <HintPath>..\..\..\..\trunk\bin\AutoDiff-1.0.dll</HintPath>
    104108    </Reference>
    105109    <Reference Include="HeuristicLab.Analysis-3.3">
  • branches/2974_Constants_Optimization/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/Evaluators/ConstantsOptimizationEvaluator.cs

    r16459 r16461  
    131131    }
    132132
    133 
    134133    private static readonly object locker = new object();
    135134    public override IOperation InstrumentedApply() {
     
    189188    }
    190189
     190    [ThreadStatic]
     191    private static double[,] x = null;
     192    [ThreadStatic]
     193    private static IDataset ds = null;
     194    [ThreadStatic]
     195    private static Dictionary<DataForVariable, AutoDiff.Variable> parameters;
     196
    191197    public static double OptimizeConstants(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter,
    192198      ISymbolicExpressionTree tree, IRegressionProblemData problemData, IEnumerable<int> rows, bool applyLinearScaling,
     
    195201      bool updateConstantsInTree = true, Action<double[], double, object> iterationCallback = null, EvaluationsCounter counter = null) {
    196202
     203      if (ds == null || ds != problemData.Dataset) {
     204        ds = problemData.Dataset;
     205        parameters = ConstantsOptimization.Util.ExtractParameters(problemData.Dataset);
     206        x = ConstantsOptimization.Util.ExtractData(ds, parameters.Keys, rows);
     207       
     208      }
     209      double[] y = ds.GetDoubleValues(problemData.TargetVariable, rows).ToArray();
     210
    197211
    198212      // numeric constants in the tree become variables for constant opt
     
    201215      // variable name, variable value (for factor vars) and lag as a DataForVariable object.
    202216      // A dictionary is used to find parameters
    203       double[] initialConstants;
    204       var parameters = new List<TreeToAutoDiffTermConverter.DataForVariable>();
    205 
    206217      TreeToAutoDiffTermConverter.ParametricFunction func;
    207218      TreeToAutoDiffTermConverter.ParametricFunctionGradient func_grad;
    208       if (!TreeToAutoDiffTermConverter.TryConvertToAutoDiff(tree, updateVariableWeights, applyLinearScaling, out parameters, out initialConstants, out func, out func_grad))
     219
     220      if (!TreeToAutoDiffTermConverter.TryConvertToAutoDiff(tree, updateVariableWeights, applyLinearScaling, parameters, out func, out func_grad))
    209221        throw new NotSupportedException("Could not optimize constants of symbolic expression tree due to not supported symbols used in the tree.");
    210222      if (parameters.Count == 0) return 0.0; // gkronber: constant expressions always have a R² of 0.0
    211       //var parameterEntries = parameters.ToArray(); // order of entries must be the same for x
     223
     224      var initialConstants = ConstantsOptimization.Util.ExtractConstants(tree);
    212225
    213226      //extract inital constants
     
    231244      int retVal;
    232245
    233       IDataset ds = problemData.Dataset;
    234       var x = ConstantsOptimization.Util.ExtractData(ds, parameters, rows);
    235       double[] y = ds.GetDoubleValues(problemData.TargetVariable, rows).ToArray();
     246
    236247      int n = x.GetLength(0);
    237248      int m = x.GetLength(1);
     
    263274          var tmp = new double[c.Length - 2];
    264275          Array.Copy(c, 2, tmp, 0, tmp.Length);
    265           UpdateConstants(tree, tmp, updateVariableWeights);
    266         } else UpdateConstants(tree, c, updateVariableWeights);
     276          ConstantsOptimization.Util.UpdateConstants(tree, tmp);
     277        } else ConstantsOptimization.Util.UpdateConstants(tree, c);
    267278      }
    268279      var quality = SymbolicRegressionSingleObjectivePearsonRSquaredEvaluator.Calculate(interpreter, tree, lowerEstimationLimit, upperEstimationLimit, problemData, rows, applyLinearScaling);
    269280
    270       if (!updateConstantsInTree) UpdateConstants(tree, initialConstants, updateVariableWeights);
     281      if (!updateConstantsInTree)
     282        ConstantsOptimization.Util.UpdateConstants(tree, initialConstants);
    271283
    272284      if (originalQuality - quality > 0.001 || double.IsNaN(quality)) {
    273         UpdateConstants(tree, initialConstants, updateVariableWeights);
     285        ConstantsOptimization.Util.UpdateConstants(tree, initialConstants);
    274286        return originalQuality;
    275287      }
    276288      return quality;
    277     }
    278 
    279     private static void UpdateConstants(ISymbolicExpressionTree tree, double[] constants, bool updateVariableWeights) {
    280       int i = 0;
    281       foreach (var node in tree.Root.IterateNodesPrefix().OfType<SymbolicExpressionTreeTerminalNode>()) {
    282         ConstantTreeNode constantTreeNode = node as ConstantTreeNode;
    283         VariableTreeNodeBase variableTreeNodeBase = node as VariableTreeNodeBase;
    284         FactorVariableTreeNode factorVarTreeNode = node as FactorVariableTreeNode;
    285         if (constantTreeNode != null)
    286           constantTreeNode.Value = constants[i++];
    287         else if (updateVariableWeights && variableTreeNodeBase != null)
    288           variableTreeNodeBase.Weight = constants[i++];
    289         else if (factorVarTreeNode != null) {
    290           for (int j = 0; j < factorVarTreeNode.Weights.Length; j++)
    291             factorVarTreeNode.Weights[j] = constants[i++];
    292         }
    293       }
    294289    }
    295290
  • branches/2974_Constants_Optimization/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Constants Optimization/Util.cs

    r16459 r16461  
    3737        foreach (var variable in variables) {
    3838          if (dataset.VariableHasType<double>(variable.variableName)) {
    39             x[row, col] = dataset.GetDoubleValue(variable.variableName, r+variable.lag);
     39            x[row, col] = dataset.GetDoubleValue(variable.variableName, r + variable.lag);
    4040          } else if (dataset.VariableHasType<string>(variable.variableName)) {
    4141            x[row, col] = dataset.GetStringValue(variable.variableName, r) == variable.variableValue ? 1 : 0;
     
    5050    public static Dictionary<DataForVariable, AutoDiff.Variable> ExtractParameters(IDataset dataset) {
    5151      var parameters = new Dictionary<DataForVariable, AutoDiff.Variable>();
    52       foreach(var doubleVariable in dataset.DoubleVariables) {
     52      foreach (var doubleVariable in dataset.DoubleVariables) {
    5353        var data = new DataForVariable(doubleVariable, string.Empty, 0);
    5454        var param = new AutoDiff.Variable();
    55         parameters.Add(data,param);
     55        parameters.Add(data, param);
    5656      }
    5757
    58       foreach(var stringVariable in dataset.StringVariables) {
    59         foreach(var stringValue in dataset.GetStringValues(stringVariable).Distinct()) {
    60           var data = new DataForVariable(stringVariable, stringVariable, 0);
     58      foreach (var stringVariable in dataset.StringVariables) {
     59        foreach (var stringValue in dataset.GetStringValues(stringVariable).Distinct()) {
     60          var data = new DataForVariable(stringVariable, stringValue, 0);
    6161          var param = new AutoDiff.Variable();
    6262          parameters.Add(data, param);
     
    6464      }
    6565      return parameters;
     66    }
     67
     68    public static double[] ExtractConstants(ISymbolicExpressionTree tree) {
     69      var constants = new List<double>();
     70      foreach (var node in tree.IterateNodesPrefix().OfType<SymbolicExpressionTreeTerminalNode>()) {
     71        ConstantTreeNode constantTreeNode = node as ConstantTreeNode;
     72        VariableTreeNodeBase variableTreeNodeBase = node as VariableTreeNodeBase;
     73        FactorVariableTreeNode factorVarTreeNode = node as FactorVariableTreeNode;
     74        if (constantTreeNode != null)
     75          constants.Add(constantTreeNode.Value);
     76        else if (variableTreeNodeBase != null)
     77          constants.Add(variableTreeNodeBase.Weight);
     78        else if (factorVarTreeNode != null) {
     79          for (int j = 0; j < factorVarTreeNode.Weights.Length; j++)
     80            constants.Add(factorVarTreeNode.Weights[j]);
     81        }       
     82      }
     83      return constants.ToArray();
    6684    }
    6785
  • branches/2974_Constants_Optimization/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/TreeToAutoDiffTermConverter.cs

    r16458 r16461  
    131131    }
    132132
     133    public static bool TryConvertToAutoDiff(ISymbolicExpressionTree tree, bool makeVariableWeightsVariable, bool addLinearScalingTerms, Dictionary<DataForVariable, AutoDiff.Variable> parameters,
     134      out ParametricFunction func,
     135      out ParametricFunctionGradient func_grad
     136  ) {
     137
     138      // use a transformator object which holds the state (variable list, parameter list, ...) for recursive transformation of the tree
     139      var transformator = new TreeToAutoDiffTermConverter(makeVariableWeightsVariable, parameters);
     140      AutoDiff.Term term;
     141      try {
     142        term = transformator.ConvertToAutoDiff(tree.Root.GetSubtree(0));
     143
     144        if (addLinearScalingTerms) {
     145          // scaling variables α, β are given at the beginning of the parameter vector
     146          var alpha = new AutoDiff.Variable();
     147          var beta = new AutoDiff.Variable();
     148          transformator.variables.Insert(0, alpha);
     149          transformator.variables.Insert(0, beta);
     150
     151          term = term * alpha + beta;
     152        }
     153       
     154        var compiledTerm = term.Compile(transformator.variables.ToArray(), parameters.Select(kvp => kvp.Value).ToArray());
     155
     156
     157        func = (vars, @params) => compiledTerm.Evaluate(vars, @params);
     158        func_grad = (vars, @params) => compiledTerm.Differentiate(vars, @params);
     159        return true;
     160      } catch (ConversionException) {
     161        func = null;
     162        func_grad = null;
     163      }
     164      return false;
     165    }
     166
    133167    // state for recursive transformation of trees
    134168    private readonly List<double> initialConstants;
     
    137171    private readonly bool makeVariableWeightsVariable;
    138172
    139     private TreeToAutoDiffTermConverter(bool makeVariableWeightsVariable) {
     173    private TreeToAutoDiffTermConverter(bool makeVariableWeightsVariable, Dictionary<DataForVariable, AutoDiff.Variable> parameters = null) {
    140174      this.makeVariableWeightsVariable = makeVariableWeightsVariable;
    141175      this.initialConstants = new List<double>();
    142       this.parameters = new Dictionary<DataForVariable, AutoDiff.Variable>();
     176      if (parameters == null)
     177        this.parameters = new Dictionary<DataForVariable, AutoDiff.Variable>();
     178      else
     179        this.parameters = parameters;
    143180      this.variables = new List<AutoDiff.Variable>();
    144181    }
Note: See TracChangeset for help on using the changeset viewer.