Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
07/06/17 10:19:37 (7 years ago)
Author:
gkronber
Message:

#2650: merged r14826 from trunk to stable. The only remaining conflict is DataTableControl and ScatterPlotControl which have been renamed within r14982 (-> tree conflict).

Location:
stable
Files:
34 edited
8 copied

Legend:

Unmodified
Added
Removed
  • stable

  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic

  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisAlleleFrequencyAnalyzer.cs

    r14186 r15131  
    8989      var varTreeNode = tree as VariableTreeNode;
    9090      var constTreeNode = tree as ConstantTreeNode;
     91      var factorVarTreeNode = tree as FactorVariableTreeNode;
     92      var binFactorVarTreeNode = tree as BinaryFactorVariableTreeNode;
    9193      if (varTreeNode != null) {
    9294        builder.Append("(var " + varTreeNode.VariableName);
     95      } else if (factorVarTreeNode != null) {
     96        builder.Append("(factor " + factorVarTreeNode.VariableName);
     97      } else if (binFactorVarTreeNode != null) {
     98        builder.Append("(factor " + binFactorVarTreeNode.VariableName + "=" + binFactorVarTreeNode.VariableValue);
    9399      } else if (constTreeNode != null) {
    94100        builder.Append("(const");
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisVariableFrequencyAnalyzer.cs

    r14186 r15131  
    2222using System;
    2323using System.Collections.Generic;
     24using System.Globalization;
    2425using System.Linq;
    2526using HeuristicLab.Analysis;
     
    4142    private const string VariableFrequenciesParameterName = "VariableFrequencies";
    4243    private const string AggregateLaggedVariablesParameterName = "AggregateLaggedVariables";
     44    private const string AggregateFactorVariablesParameterName = "AggregateFactorVariables";
    4345    private const string VariableImpactsParameterName = "VariableImpacts";
    4446
     
    5254    public IValueLookupParameter<BoolValue> AggregateLaggedVariablesParameter {
    5355      get { return (IValueLookupParameter<BoolValue>)Parameters[AggregateLaggedVariablesParameterName]; }
     56    }
     57    public IValueLookupParameter<BoolValue> AggregateFactorVariablesParameter {
     58      get { return (IValueLookupParameter<BoolValue>)Parameters[AggregateFactorVariablesParameterName]; }
    5459    }
    5560    #endregion
     
    5964      set { AggregateLaggedVariablesParameter.Value = value; }
    6065    }
     66    public BoolValue AggregateFactorVariables {
     67      get { return AggregateFactorVariablesParameter.ActualValue; }
     68      set { AggregateFactorVariablesParameter.Value = value; }
     69    }
    6170    #endregion
    6271    [StorableConstructor]
     
    7079      Parameters.Add(new LookupParameter<DoubleMatrix>(VariableImpactsParameterName, "The relative variable relevance calculated as the average relative variable frequency over the whole run."));
    7180      Parameters.Add(new ValueLookupParameter<BoolValue>(AggregateLaggedVariablesParameterName, "Switch that determines whether all references to a variable should be aggregated regardless of time-offsets. Turn off to analyze all variable references with different time offsets separately.", new BoolValue(true)));
     81      Parameters.Add(new ValueLookupParameter<BoolValue>(AggregateFactorVariablesParameterName, "Switch that determines whether all references to factor variables should be aggregated regardless of the value. Turn off to analyze all factor variable references with different values separately.", new BoolValue(true)));
     82    }
     83
     84    [StorableHook(HookType.AfterDeserialization)]
     85    private void AfterDeserialization() {
     86      // BackwardsCompatibility3.3
     87      #region Backwards compatible code, remove with 3.4
     88      if (!Parameters.ContainsKey(AggregateFactorVariablesParameterName)) {
     89        Parameters.Add(new ValueLookupParameter<BoolValue>(AggregateFactorVariablesParameterName, "Switch that determines whether all references to factor variables should be aggregated regardless of the value. Turn off to analyze all factor variable references with different values separately.", new BoolValue(true)));
     90      }
     91      #endregion
    7292    }
    7393
     
    93113      int numberOfValues = datatable.Rows.Select(r => r.Values.Count).DefaultIfEmpty().First();
    94114
    95       foreach (var pair in SymbolicDataAnalysisVariableFrequencyAnalyzer.CalculateVariableFrequencies(expressions, AggregateLaggedVariables.Value)) {
     115      foreach (var pair in CalculateVariableFrequencies(expressions, AggregateLaggedVariables.Value, AggregateFactorVariables.Value)) {
    96116        if (!datatable.Rows.ContainsKey(pair.Key)) {
    97117          // initialize a new row for the variable and pad with zeros
     
    128148    }
    129149
    130     public static IEnumerable<KeyValuePair<string, double>> CalculateVariableFrequencies(IEnumerable<ISymbolicExpressionTree> trees, bool aggregateLaggedVariables = true) {
     150    public static IEnumerable<KeyValuePair<string, double>> CalculateVariableFrequencies(IEnumerable<ISymbolicExpressionTree> trees,
     151      bool aggregateLaggedVariables = true, bool aggregateFactorVariables = true) {
    131152
    132153      var variableFrequencies = trees
    133         .SelectMany(t => GetVariableReferences(t, aggregateLaggedVariables))
     154        .SelectMany(t => GetVariableReferences(t, aggregateLaggedVariables, aggregateFactorVariables))
    134155        .GroupBy(pair => pair.Key, pair => pair.Value)
    135156        .ToDictionary(g => g.Key, g => (double)g.Sum());
     
    141162    }
    142163
    143     private static IEnumerable<KeyValuePair<string, int>> GetVariableReferences(ISymbolicExpressionTree tree, bool aggregateLaggedVariables = true) {
     164    private static IEnumerable<KeyValuePair<string, int>> GetVariableReferences(ISymbolicExpressionTree tree,
     165      bool aggregateLaggedVariables = true, bool aggregateFactorVariables = true) {
    144166      Dictionary<string, int> references = new Dictionary<string, int>();
    145167      if (aggregateLaggedVariables) {
    146168        tree.Root.ForEachNodePrefix(node => {
    147           if (node.Symbol is Variable) {
    148             var varNode = node as VariableTreeNode;
    149             IncReferenceCount(references, varNode.VariableName);
    150           } else if (node.Symbol is VariableCondition) {
    151             var varCondNode = node as VariableConditionTreeNode;
    152             IncReferenceCount(references, varCondNode.VariableName);
     169          if (node is IVariableTreeNode) {
     170            var factorNode = node as BinaryFactorVariableTreeNode;
     171            if (factorNode != null && !aggregateFactorVariables) {
     172              IncReferenceCount(references, factorNode.VariableName + "=" + factorNode.VariableValue);
     173            } else {
     174              var varNode = node as IVariableTreeNode;
     175              IncReferenceCount(references, varNode.VariableName);
     176            }
    153177          }
    154178        });
    155179      } else {
    156         GetVariableReferences(references, tree.Root, 0);
     180        GetVariableReferences(references, tree.Root, 0, aggregateFactorVariables);
    157181      }
    158182      return references;
    159183    }
    160184
    161     private static void GetVariableReferences(Dictionary<string, int> references, ISymbolicExpressionTreeNode node, int currentLag) {
    162       if (node.Symbol is LaggedVariable) {
    163         var laggedVarNode = node as LaggedVariableTreeNode;
    164         IncReferenceCount(references, laggedVarNode.VariableName, currentLag + laggedVarNode.Lag);
    165       } else if (node.Symbol is Variable) {
    166         var varNode = node as VariableTreeNode;
    167         IncReferenceCount(references, varNode.VariableName, currentLag);
    168       } else if (node.Symbol is VariableCondition) {
    169         var varCondNode = node as VariableConditionTreeNode;
    170         IncReferenceCount(references, varCondNode.VariableName, currentLag);
    171         GetVariableReferences(references, node.GetSubtree(0), currentLag);
    172         GetVariableReferences(references, node.GetSubtree(1), currentLag);
     185    private static void GetVariableReferences(Dictionary<string, int> references, ISymbolicExpressionTreeNode node, int currentLag, bool aggregateFactorVariables) {
     186      if (node is IVariableTreeNode) {
     187        var laggedVarTreeNode = node as LaggedVariableTreeNode;
     188        var binFactorVariableTreeNode = node as BinaryFactorVariableTreeNode;
     189        var varConditionTreeNode = node as VariableConditionTreeNode;
     190        if (laggedVarTreeNode != null) {
     191          IncReferenceCount(references, laggedVarTreeNode.VariableName, currentLag + laggedVarTreeNode.Lag);
     192        } else if (binFactorVariableTreeNode != null) {
     193          if (aggregateFactorVariables) {
     194            IncReferenceCount(references, binFactorVariableTreeNode.VariableName, currentLag);
     195          } else {
     196            IncReferenceCount(references, binFactorVariableTreeNode.VariableName + "=" + binFactorVariableTreeNode.VariableValue, currentLag);
     197          }
     198        } else if (varConditionTreeNode != null) {
     199          IncReferenceCount(references, varConditionTreeNode.VariableName, currentLag);
     200          GetVariableReferences(references, node.GetSubtree(0), currentLag, aggregateFactorVariables);
     201          GetVariableReferences(references, node.GetSubtree(1), currentLag, aggregateFactorVariables);
     202        } else {
     203          var varNode = node as IVariableTreeNode;
     204          IncReferenceCount(references, varNode.VariableName, currentLag);
     205        }
    173206      } else if (node.Symbol is Integral) {
    174207        var laggedNode = node as LaggedTreeNode;
    175208        for (int l = laggedNode.Lag; l <= 0; l++) {
    176           GetVariableReferences(references, node.GetSubtree(0), currentLag + l);
     209          GetVariableReferences(references, node.GetSubtree(0), currentLag + l, aggregateFactorVariables);
    177210        }
    178211      } else if (node.Symbol is Derivative) {
    179212        for (int l = -4; l <= 0; l++) {
    180           GetVariableReferences(references, node.GetSubtree(0), currentLag + l);
     213          GetVariableReferences(references, node.GetSubtree(0), currentLag + l, aggregateFactorVariables);
    181214        }
    182215      } else if (node.Symbol is TimeLag) {
    183216        var laggedNode = node as LaggedTreeNode;
    184         GetVariableReferences(references, node.GetSubtree(0), currentLag + laggedNode.Lag);
     217        GetVariableReferences(references, node.GetSubtree(0), currentLag + laggedNode.Lag, aggregateFactorVariables);
    185218      } else {
    186219        foreach (var subtree in node.Subtrees) {
    187           GetVariableReferences(references, subtree, currentLag);
     220          GetVariableReferences(references, subtree, currentLag, aggregateFactorVariables);
    188221        }
    189222      }
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/InfixExpressionFormatter.cs

    r14565 r15131  
    141141            strBuilder.Append(")");
    142142          }
     143        } else if (node.Symbol is FactorVariable) {
     144          var factorNode = node as FactorVariableTreeNode;
     145          if (factorNode.VariableName.Contains("'")) {
     146            strBuilder.AppendFormat("\"{0}\"", factorNode.VariableName);
     147          } else {
     148            strBuilder.AppendFormat("'{0}'", factorNode.VariableName);
     149          }
     150          strBuilder.AppendFormat("[{0}]",
     151            string.Join(", ", factorNode.Weights.Select(w => w.ToString(CultureInfo.InvariantCulture))));
     152        } else if (node.Symbol is BinaryFactorVariable) {
     153          var factorNode = node as BinaryFactorVariableTreeNode;
     154          if (!factorNode.Weight.IsAlmost(1.0)) {
     155            strBuilder.Append("(");
     156            strBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}", factorNode.Weight);
     157            strBuilder.Append("*");
     158          }
     159          if (factorNode.VariableName.Contains("'")) {
     160            strBuilder.AppendFormat("\"{0}\"", factorNode.VariableName);
     161          } else {
     162            strBuilder.AppendFormat("'{0}'", factorNode.VariableName);
     163          }
     164          strBuilder.Append(" = ");
     165          if (factorNode.VariableValue.Contains("'")) {
     166            strBuilder.AppendFormat("\"{0}\"", factorNode.VariableValue);
     167          } else {
     168            strBuilder.AppendFormat("'{0}'", factorNode.VariableValue);
     169          }
     170
     171          if (!factorNode.Weight.IsAlmost(1.0)) {
     172            strBuilder.Append(")");
     173          }
     174
    143175        } else if (node.Symbol is Constant) {
    144176          var constNode = node as ConstantTreeNode;
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionCSharpFormatter.cs

    r14186 r15131  
    2525using System.Linq;
    2626using System.Text;
     27using System.Text.RegularExpressions;
    2728using HeuristicLab.Common;
    2829using HeuristicLab.Core;
     
    5354      GenerateFooter(strBuilder);
    5455      return strBuilder.ToString();
     56    }
     57
     58    private string VariableName2Identifier(string name) {     
     59      /*
     60       * identifier-start-character:
     61       *    letter-character
     62       *    _ (the underscore character U+005F)
     63       *  identifier-part-characters:
     64       *    identifier-part-character
     65       *    identifier-part-characters   identifier-part-character
     66       *  identifier-part-character:
     67       *    letter-character
     68       *    decimal-digit-character
     69       *    connecting-character
     70       *    combining-character
     71       *    formatting-character
     72       *  letter-character:
     73       *    A Unicode character of classes Lu, Ll, Lt, Lm, Lo, or Nl
     74       *    A unicode-escape-sequence representing a character of classes Lu, Ll, Lt, Lm, Lo, or Nl
     75       *  combining-character:
     76       *    A Unicode character of classes Mn or Mc
     77       *    A unicode-escape-sequence representing a character of classes Mn or Mc
     78       *  decimal-digit-character:
     79       *    A Unicode character of the class Nd
     80       *    A unicode-escape-sequence representing a character of the class Nd
     81       *  connecting-character:
     82       *    A Unicode character of the class Pc
     83       *    A unicode-escape-sequence representing a character of the class Pc
     84       *  formatting-character:
     85       *    A Unicode character of the class Cf
     86       *    A unicode-escape-sequence representing a character of the class Cf
     87       */
     88
     89      var invalidIdentifierStarts = new Regex(@"[^_\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nl}]");
     90      var invalidIdentifierParts = new Regex(@"[^\p{Lu}\p{Ll}\p{Lt}\p{Lm}\p{Lo}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\p{Cf}]");
     91      return "@" +
     92        (invalidIdentifierStarts.IsMatch(name.Substring(0, 1)) ? "_" : "") + // prepend '_' if necessary
     93        invalidIdentifierParts.Replace(name, "_");
    5594    }
    5695
     
    106145        if (node is VariableTreeNode) {
    107146          var varNode = node as VariableTreeNode;
    108           strBuilder.AppendFormat("{0} * {1}", varNode.VariableName, varNode.Weight.ToString("g17", CultureInfo.InvariantCulture));
     147          strBuilder.AppendFormat("{0} * {1}", VariableName2Identifier(varNode.VariableName), varNode.Weight.ToString("g17", CultureInfo.InvariantCulture));
    109148        } else if (node is ConstantTreeNode) {
    110149          var constNode = node as ConstantTreeNode;
    111150          strBuilder.Append(constNode.Value.ToString("g17", CultureInfo.InvariantCulture));
     151        } else if (node.Symbol is FactorVariable) {
     152          var factorNode = node as FactorVariableTreeNode;
     153          FormatFactor(factorNode, strBuilder);
     154        } else if (node.Symbol is BinaryFactorVariable) {
     155          var binFactorNode = node as BinaryFactorVariableTreeNode;
     156          FormatBinaryFactor(binFactorNode, strBuilder);
    112157        } else {
    113158          throw new NotSupportedException("Formatting of symbol: " + node.Symbol + " not supported for C# symbolic expression tree formatter.");
    114159        }
    115160      }
     161    }
     162
     163    private void FormatFactor(FactorVariableTreeNode node, StringBuilder strBuilder) {
     164      strBuilder.AppendFormat("EvaluateFactor({0}, new [] {{ {1} }}, new [] {{ {2} }})", VariableName2Identifier(node.VariableName),
     165        string.Join(",", node.Symbol.GetVariableValues(node.VariableName).Select(name => "\"" + name + "\"")), string.Join(",", node.Weights.Select(v => v.ToString(CultureInfo.InvariantCulture))));
     166    }
     167
     168    private void FormatBinaryFactor(BinaryFactorVariableTreeNode node, StringBuilder strBuilder) {
     169      strBuilder.AppendFormat(CultureInfo.InvariantCulture, "EvaluateBinaryFactor({0}, \"{1}\", {2})", VariableName2Identifier(node.VariableName), node.VariableValue, node.Weight);
    116170    }
    117171
     
    182236      GenerateAverageSource(strBuilder);
    183237      GenerateIfThenElseSource(strBuilder);
     238      GenerateFactorSource(strBuilder);
     239      GenerateBinaryFactorSource(strBuilder);
    184240      strBuilder.Append(Environment.NewLine + "public static double Evaluate (");
    185241
    186       HashSet<string> varNames = new HashSet<string>();
    187       foreach (var node in symbolicExpressionTree.IterateNodesPostfix().Where(x => x is VariableTreeNode)) {
    188         varNames.Add(((VariableTreeNode)node).VariableName);
    189       }
    190 
    191       var orderedNames = varNames.OrderBy(n => n, new NaturalStringComparer()).Select(n => "double " + n);
     242      // here we don't have access to problemData to determine the type for each variable (double/string) therefore we must distinguish based on the symbol type
     243      HashSet<string> doubleVarNames = new HashSet<string>();
     244      foreach (var node in symbolicExpressionTree.IterateNodesPostfix().Where(x => x is VariableTreeNode || x is VariableConditionTreeNode)) {
     245        doubleVarNames.Add(((IVariableTreeNode)node).VariableName);
     246      }
     247
     248      HashSet<string> stringVarNames = new HashSet<string>();
     249      foreach (var node in symbolicExpressionTree.IterateNodesPostfix().Where(x => x is BinaryFactorVariableTreeNode || x is FactorVariableTreeNode)) {
     250        stringVarNames.Add(((IVariableTreeNode)node).VariableName);
     251      }
     252
     253      var orderedNames = stringVarNames.OrderBy(n => n, new NaturalStringComparer()).Select(n => "string " + VariableName2Identifier(n) + " /* " + n + " */");
    192254      strBuilder.Append(string.Join(", ", orderedNames));
     255
     256      if (stringVarNames.Any() && doubleVarNames.Any())
     257        strBuilder.AppendLine(",");
     258      orderedNames = doubleVarNames.OrderBy(n => n, new NaturalStringComparer()).Select(n => "double " + VariableName2Identifier(n) + " /* " + n + " */");
     259      strBuilder.Append(string.Join(", ", orderedNames));
     260
    193261
    194262      strBuilder.AppendLine(") {");
     
    198266    private void GenerateFooter(StringBuilder strBuilder) {
    199267      strBuilder.AppendLine(";");
     268
    200269      strBuilder.AppendLine("return result;");
    201270      strBuilder.AppendLine("}");
     
    215284      strBuilder.AppendLine("}");
    216285    }
     286
     287    private void GenerateFactorSource(StringBuilder strBuilder) {
     288      strBuilder.AppendLine("private static double EvaluateFactor(string factorValue, string[] factorValues, double[] constants) {");
     289      strBuilder.AppendLine("   for(int i=0;i<factorValues.Length;i++) " +
     290                            "      if(factorValues[i] == factorValue) return constants[i];" +
     291                            "   throw new ArgumentException();");
     292      strBuilder.AppendLine("}");
     293    }
     294
     295    private void GenerateBinaryFactorSource(StringBuilder strBuilder) {
     296      strBuilder.AppendLine("private static double EvaluateBinaryFactor(string factorValue, string targetValue, double weight) {");
     297      strBuilder.AppendLine("  return factorValue == targetValue ? weight : 0.0;");
     298      strBuilder.AppendLine("}");
     299    }
     300
    217301  }
    218302}
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionExcelFormatter.cs

    r14186 r15131  
    5151      while (dividend > 0) {
    5252        int modulo = (dividend - 1) % 26;
    53         columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
     53        columnName = Convert.ToChar(65 + modulo) + columnName;
    5454        dividend = (int)((dividend - modulo) / 26);
    5555      }
     
    6060    private readonly Dictionary<string, string> variableNameMapping = new Dictionary<string, string>();
    6161    private int currentVariableIndex = 0;
    62     private string GetColumnToVariableName(string variabelName) {
    63       if (!variableNameMapping.ContainsKey(variabelName)) {
     62    private string GetColumnToVariableName(string varName) {
     63      if (!variableNameMapping.ContainsKey(varName)) {
    6464        currentVariableIndex++;
    65         variableNameMapping.Add(variabelName, GetExcelColumnName(currentVariableIndex));
    66       }
    67       return string.Format("${0}1", variableNameMapping[variabelName]);
     65        variableNameMapping.Add(varName, GetExcelColumnName(currentVariableIndex));
     66      }
     67      return string.Format("${0}1", variableNameMapping[varName]);
    6868    }
    6969    public string Format(ISymbolicExpressionTree symbolicExpressionTree) {
     
    7171    }
    7272
     73
    7374    public string Format(ISymbolicExpressionTree symbolicExpressionTree, IDataset dataset) {
     75      if (dataset != null)
     76        return FormatWithMapping(symbolicExpressionTree, CalculateVariableMapping(symbolicExpressionTree, dataset));
     77      else return FormatWithMapping(symbolicExpressionTree, new Dictionary<string, string>());
     78    }
     79
     80    public string FormatWithMapping(ISymbolicExpressionTree symbolicExpressionTree, Dictionary<string,string> variableNameMapping)
     81    {
     82      foreach(var kvp in variableNameMapping) this.variableNameMapping.Add(kvp.Key,kvp.Value);
    7483      var stringBuilder = new StringBuilder();
    75       if (dataset != null) CalculateVariableMapping(symbolicExpressionTree, dataset);
    76 
     84     
    7785      stringBuilder.Append("=");
    7886      stringBuilder.Append(FormatRecursively(symbolicExpressionTree.Root));
    7987
    80       foreach (var variable in variableNameMapping) {
     88      foreach (var variable in this.variableNameMapping) {
    8189        stringBuilder.AppendLine();
    8290        stringBuilder.Append(variable.Key + " = " + variable.Value);
     
    8593    }
    8694
    87     private void CalculateVariableMapping(ISymbolicExpressionTree tree, IDataset dataset) {
    88       int columnIndex = 0;
     95    private Dictionary<string,string> CalculateVariableMapping(ISymbolicExpressionTree tree, IDataset dataset) {
     96      var mapping = new Dictionary<string,string>();
    8997      int inputIndex = 0;
    90       var usedVariables = tree.IterateNodesPrefix().OfType<VariableTreeNode>().Select(v => v.VariableName).Distinct();
     98      var usedVariables = tree.IterateNodesPrefix().OfType<IVariableTreeNode>().Select(v => v.VariableName).Distinct().ToArray();
    9199      foreach (var variable in dataset.VariableNames) {
    92         columnIndex++;
    93100        if (!usedVariables.Contains(variable)) continue;
    94101        inputIndex++;
    95         variableNameMapping[variable] = GetExcelColumnName(inputIndex);
    96       }
     102        mapping[variable] = GetExcelColumnName(inputIndex);
     103      }
     104      return mapping;
    97105    }
    98106
     
    190198        stringBuilder.Append(variableTreeNode.Weight.ToString(CultureInfo.InvariantCulture));
    191199        stringBuilder.Append("*");
    192         stringBuilder.Append(GetColumnToVariableName(variableTreeNode.VariableName));// + LagToString(currentLag));
     200        stringBuilder.Append(GetColumnToVariableName(variableTreeNode.VariableName));
     201      } else if (symbol is BinaryFactorVariable) {
     202        var binFactorNode = node as BinaryFactorVariableTreeNode;
     203        stringBuilder.AppendFormat("IF({0}=\"{1}\", {2}, 0)",
     204          GetColumnToVariableName(binFactorNode.VariableName),
     205          binFactorNode.VariableValue,
     206          binFactorNode.Weight.ToString(CultureInfo.InvariantCulture)
     207          );
     208      } else if (symbol is FactorVariable) {
     209        var factorNode = node as FactorVariableTreeNode;
     210        var values = factorNode.Symbol.GetVariableValues(factorNode.VariableName).ToArray();
     211        var w = factorNode.Weights;
     212        // create nested if
     213        for (int i = 0; i < values.Length; i++) {
     214          stringBuilder.AppendFormat("IF({0}=\"{1}\", {2}, ",
     215            GetColumnToVariableName(factorNode.VariableName),
     216            values[i],
     217            w[i].ToString(CultureInfo.InvariantCulture));
     218        }
     219        stringBuilder.Append("\"\""); // return empty string on unknown value
     220        stringBuilder.Append(')', values.Length); // add closing parenthesis
    193221      } else if (symbol is Power) {
    194222        stringBuilder.Append("POWER(");
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionLatexFormatter.cs

    r14569 r15131  
    3333  [StorableClass]
    3434  public sealed class SymbolicDataAnalysisExpressionLatexFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {
    35     private readonly List<double> constants;
     35    private readonly List<KeyValuePair<string, double>> constants;
     36    private int constIndex;
    3637    private int targetCount;
    3738    private int currentLag;
     
    4344    private SymbolicDataAnalysisExpressionLatexFormatter(SymbolicDataAnalysisExpressionLatexFormatter original, Cloner cloner)
    4445      : base(original, cloner) {
    45       constants = new List<double>(original.constants);
     46      constants = new List<KeyValuePair<string, double>>(original.constants);
     47      constIndex = original.constIndex;
     48      currentLag = original.currentLag;
     49      targetCount = original.targetCount;
    4650    }
    4751    public SymbolicDataAnalysisExpressionLatexFormatter()
     
    4953      Name = ItemName;
    5054      Description = ItemDescription;
    51       constants = new List<double>();
     55      constants = new List<KeyValuePair<string, double>>();
    5256    }
    5357
     
    6367        StringBuilder strBuilder = new StringBuilder();
    6468        constants.Clear();
     69        constIndex = 0;
    6570        this.targetVariable = targetVariable;
    6671        containsTimeSeriesSymbol = symbolicExpressionTree.IterateNodesBreadth().Any(n => IsTimeSeriesSymbol(n.Symbol));
     
    8489      }
    8590      int i = 1;
    86       foreach (SymbolicExpressionTreeNode subTree in node.Subtrees.Skip(1)) {
     91      foreach (var subTree in node.Subtrees.Skip(1)) {
    8792        FormatSep(node, strBuilder, i);
    8893        // format the whole subtree
     
    175180        strBuilder.Append(@" \operatorname{if}  \left( ");
    176181      } else if (node.Symbol is Constant) {
     182        var constName = "c_{" + constIndex + "}";
     183        constIndex++;
    177184        var constNode = node as ConstantTreeNode;
    178185        if (constNode.Value.IsAlmost(1.0)) {
    179186          strBuilder.Append("1 ");
    180187        } else {
    181           strBuilder.Append("c_{" + constants.Count + "} ");
    182           constants.Add(constNode.Value);
    183         }
     188          strBuilder.Append(constName);
     189          constants.Add(new KeyValuePair<string, double>(constName, constNode.Value));
     190        }
     191
     192      } else if (node.Symbol is FactorVariable) {
     193        var factorNode = node as FactorVariableTreeNode;
     194        var constName = "c_{" + constIndex + "}";
     195        strBuilder.Append(constName + " ");
     196        foreach (var e in factorNode.Symbol.GetVariableValues(factorNode.VariableName)
     197          .Zip(factorNode.Weights, Tuple.Create)) {
     198          constants.Add(new KeyValuePair<string, double>("c_{" + constIndex + ", " + EscapeLatexString(factorNode.VariableName) + "=" + EscapeLatexString(e.Item1) + "}", e.Item2));
     199        }
     200        constIndex++;
     201      } else if (node.Symbol is BinaryFactorVariable) {
     202        var binFactorNode = node as BinaryFactorVariableTreeNode;
     203        if (!binFactorNode.Weight.IsAlmost((1.0))) {
     204          var constName = "c_{" + constIndex + "}";
     205          strBuilder.Append(constName + "  \\cdot");
     206          constants.Add(new KeyValuePair<string, double>(constName, binFactorNode.Weight));
     207          constIndex++;
     208        }
     209        strBuilder.Append("(" + EscapeLatexString(binFactorNode.VariableName));
     210        strBuilder.Append(LagToString(currentLag));
     211        strBuilder.Append(" = " + EscapeLatexString(binFactorNode.VariableValue) + " )");
    184212      } else if (node.Symbol is LaggedVariable) {
    185213        var laggedVarNode = node as LaggedVariableTreeNode;
    186214        if (!laggedVarNode.Weight.IsAlmost(1.0)) {
    187           strBuilder.Append("c_{" + constants.Count + "} \\cdot ");
    188           constants.Add(laggedVarNode.Weight);
     215          var constName = "c_{" + constIndex + "}";
     216          strBuilder.Append(constName + "  \\cdot");
     217          constants.Add(new KeyValuePair<string, double>(constName, laggedVarNode.Weight));
     218          constIndex++;
    189219        }
    190220        strBuilder.Append(EscapeLatexString(laggedVarNode.VariableName));
     
    194224        var varNode = node as VariableTreeNode;
    195225        if (!varNode.Weight.IsAlmost((1.0))) {
    196           strBuilder.Append("c_{" + constants.Count + "} \\cdot ");
    197           constants.Add(varNode.Weight);
     226          var constName = "c_{" + constIndex + "}";
     227          strBuilder.Append(constName + "  \\cdot");
     228          constants.Add(new KeyValuePair<string, double>(constName, varNode.Weight));
     229          constIndex++;
    198230        }
    199231        strBuilder.Append(EscapeLatexString(varNode.VariableName));
     
    229261      } else if (node.Symbol is VariableCondition) {
    230262        var conditionTreeNode = node as VariableConditionTreeNode;
    231         string p = @"1 /  1 + \exp  - c_{" + constants.Count + "} ";
    232         constants.Add(conditionTreeNode.Slope);
    233         p += @" \cdot " + EscapeLatexString(conditionTreeNode.VariableName) + LagToString(currentLag) + " - c_{" + constants.Count + @"}   ";
    234         constants.Add(conditionTreeNode.Threshold);
     263        var constName = "c_{" + constants.Count + "}";
     264        string p = @"1 /  1 + \exp  - " + constName + " ";
     265        constants.Add(new KeyValuePair<string, double>(constName, conditionTreeNode.Slope));
     266        constIndex++;
     267        var const2Name = "c_{" + constants.Count + @"}";
     268        p += @" \cdot " + EscapeLatexString(conditionTreeNode.VariableName) + LagToString(currentLag) + " - " + const2Name + "   ";
     269        constants.Add(new KeyValuePair<string, double>(const2Name, conditionTreeNode.Threshold));
     270        constIndex++;
    235271        strBuilder.Append(@" \left( " + p + @"\cdot ");
    236272      } else {
     
    323359      } else if (node.Symbol is VariableCondition) {
    324360        var conditionTreeNode = node as VariableConditionTreeNode;
    325         string p = @"1 / \left( 1 + \exp \left( - c_{" + constants.Count + "} ";
    326         constants.Add(conditionTreeNode.Slope);
    327         p += @" \cdot " + EscapeLatexString(conditionTreeNode.VariableName) + LagToString(currentLag) + " - c_{" + constants.Count + @"} \right) \right) \right)   ";
    328         constants.Add(conditionTreeNode.Threshold);
     361        var const1Name = "c_{" + constants.Count + "}";
     362        string p = @"1 / \left( 1 + \exp \left( - " + const1Name + " ";
     363        constants.Add(new KeyValuePair<string, double>(const1Name, conditionTreeNode.Slope));
     364        constIndex++;
     365        var const2Name = "c_{" + constants.Count + "}";
     366        p += @" \cdot " + EscapeLatexString(conditionTreeNode.VariableName) + LagToString(currentLag) + " - " + const2Name + " \right) \right) \right)   ";
     367        constants.Add(new KeyValuePair<string, double>(const2Name, conditionTreeNode.Threshold));
     368        constIndex++;
    329369        strBuilder.Append(@" +  \left( 1 - " + p + @" \right) \cdot ");
    330370      } else {
     
    404444      } else if (node.Symbol is LaggedVariable) {
    405445      } else if (node.Symbol is Variable) {
     446      } else if (node.Symbol is FactorVariable) {
     447      } else if (node.Symbol is BinaryFactorVariable) {
    406448      } else if (node.Symbol is ProgramRootSymbol) {
    407449        strBuilder
     
    411453        // output all constant values
    412454        if (constants.Count > 0) {
    413           int i = 0;
    414455          foreach (var constant in constants) {
    415456            // replace "." with ".&" to align decimal points
    416             var constStr = string.Format(System.Globalization.NumberFormatInfo.InvariantInfo, "{0:G5}", constant);
     457            var constStr = string.Format(System.Globalization.NumberFormatInfo.InvariantInfo, "{0:G5}", constant.Value);
    417458            if (!constStr.Contains(".")) constStr = constStr + ".0";
    418459            constStr = constStr.Replace(".", "&.");  // fix problem in rendering of aligned expressions
    419             strBuilder.Append("c_{" + i + "}& = & " + constStr);
     460            strBuilder.Append(constant.Key + "& = & " + constStr);
    420461            strBuilder.Append(@"\\");
    421             i++;
    422462          }
    423463        }
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionMATLABFormatter.cs

    r14186 r15131  
    2121
    2222using System.Globalization;
     23using System.Linq;
    2324using System.Text;
    2425using HeuristicLab.Common;
     
    7778      stringBuilder.AppendLine("  y = (f0 + 2*f1 - 2*f3 - f4) / 8;");
    7879      stringBuilder.AppendLine("end");
     80
     81      var factorVariableNames =
     82        symbolicExpressionTree.IterateNodesPostfix()
     83          .OfType<FactorVariableTreeNode>()
     84          .Select(n => n.VariableName)
     85          .Distinct();
     86
     87      foreach (var factorVarName in factorVariableNames) {
     88        var factorSymb = symbolicExpressionTree.IterateNodesPostfix()
     89          .OfType<FactorVariableTreeNode>()
     90          .First(n => n.VariableName == factorVarName)
     91          .Symbol;
     92        stringBuilder.AppendFormat("function y = switch_{0}(val, v)", factorVarName).AppendLine();
     93        var values = factorSymb.GetVariableValues(factorVarName).ToArray();
     94        stringBuilder.AppendLine("switch val");
     95        for (int i = 0; i < values.Length; i++) {
     96          stringBuilder.AppendFormat(CultureInfo.InvariantCulture, "  case \"{0}\" y = v({1})", values[i], i).AppendLine();
     97        }
     98        stringBuilder.AppendLine("end");
     99        stringBuilder.AppendLine();
     100      }
     101
    79102      return stringBuilder.ToString();
    80103    }
     
    296319        stringBuilder.Append("*");
    297320        stringBuilder.Append(variableTreeNode.VariableName + LagToString(currentLag));
     321      } else if (symbol is HeuristicLab.Problems.DataAnalysis.Symbolic.FactorVariable) {
     322        var factorNode = node as FactorVariableTreeNode;
     323        var weights = string.Join(" ", factorNode.Weights.Select(w => w.ToString("G17", CultureInfo.InvariantCulture)));
     324        stringBuilder.AppendFormat("switch_{0}(\"{1}\",[{2}])",
     325          factorNode.VariableName, factorNode.VariableName, weights)
     326          .AppendLine();
     327      } else if (symbol is HeuristicLab.Problems.DataAnalysis.Symbolic.BinaryFactorVariable) {
     328        var factorNode = node as BinaryFactorVariableTreeNode;
     329        stringBuilder.AppendFormat(CultureInfo.InvariantCulture,
     330          "((strcmp({0},\"{1}\")==1) * {2:G17})", factorNode.VariableName, factorNode.VariableValue, factorNode.Weight);
    298331      } else if (symbol is Power) {
    299332        stringBuilder.Append("(");
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionMathematicaFormatter.cs

    r14186 r15131  
    110110        }
    111111      } else {
    112         if (node is VariableTreeNode) {
     112        // terminals
     113        if (node.Symbol is Variable) {
    113114          var varNode = node as VariableTreeNode;
    114115          strBuilder.AppendFormat("Times[{0}, {1}]", varNode.VariableName, varNode.Weight.ToString("G17", CultureInfo.InvariantCulture));
    115         } else if (node is ConstantTreeNode) {
     116        } else if (node.Symbol is Constant) {
    116117          var constNode = node as ConstantTreeNode;
    117118          strBuilder.Append(constNode.Value.ToString("G17", CultureInfo.InvariantCulture));
     119        } else if (node.Symbol is FactorVariable) {
     120          var factorNode = node as FactorVariableTreeNode;
     121          strBuilder.AppendFormat("Switch[{0},", factorNode.VariableName);
     122          var varValues = factorNode.Symbol.GetVariableValues(factorNode.VariableName).ToArray();
     123          var weights = varValues.Select(factorNode.GetValue).ToArray();
     124
     125          var weightStr = string.Join(", ",
     126            varValues.Zip(weights, (s, d) => string.Format(CultureInfo.InvariantCulture, "\"{0}\", {1:G17}", s, d)));
     127          strBuilder.Append(weightStr);
     128          strBuilder.Append("]");
     129        } else if (node.Symbol is BinaryFactorVariable) {
     130          var factorNode = node as BinaryFactorVariableTreeNode;
     131          strBuilder.AppendFormat(CultureInfo.InvariantCulture, "If[{0}==\"{1}\",{2:G17},0.0]",
     132            factorNode.VariableName, factorNode.VariableValue, factorNode.Weight);
    118133        } else {
    119134          throw new NotSupportedException("Formatting of symbol: " + node.Symbol + " is not supported.");
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/SymbolicDataAnalysisExpressionSmalltalkFormatter.cs

    r14186 r15131  
    115115        stringBuilder.Append("]");
    116116      } else if (symbol is LaggedVariable) {
    117         stringBuilder.Append("lagged variable not implemented");
     117        stringBuilder.Append("lagged variables are not supported");
    118118      } else if (symbol is LessThan) {
    119119        stringBuilder.Append("(");
     
    165165        stringBuilder.Append("*");
    166166        stringBuilder.Append(variableTreeNode.VariableName);
     167      } else if (symbol is BinaryFactorVariable || symbol is FactorVariable) {
     168        stringBuilder.Append("factor variables are not supported");
    167169      } else {
    168170        stringBuilder.Append("(");
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Grammars/ArithmeticExpressionGrammar.cs

    r14186 r15131  
    5353      constant.MaxValue = 20;
    5454      var variableSymbol = new HeuristicLab.Problems.DataAnalysis.Symbolic.Variable();
     55      var binFactorVariableSymbol = new BinaryFactorVariable();
     56      var factorVariableSymbol = new FactorVariable();
    5557
    56       var allSymbols = new List<Symbol>() { add, sub, mul, div, constant, variableSymbol };
     58      var allSymbols = new List<Symbol>() { add, sub, mul, div, constant, variableSymbol, binFactorVariableSymbol, factorVariableSymbol};
    5759      var functionSymbols = new List<Symbol>() { add, sub, mul, div };
    5860
     
    6567      SetSubtreeCount(constant, 0, 0);
    6668      SetSubtreeCount(variableSymbol, 0, 0);
     69      SetSubtreeCount(binFactorVariableSymbol, 0, 0);
     70      SetSubtreeCount(factorVariableSymbol, 0, 0);
    6771
    6872      // allow each symbol as child of the start symbol
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Grammars/FullFunctionalExpressionGrammar.cs

    r14186 r15131  
    115115      constant.MaxValue = 20;
    116116      var variableSymbol = new HeuristicLab.Problems.DataAnalysis.Symbolic.Variable();
     117      var binFactorVariable = new BinaryFactorVariable();
     118      var factorVariable = new FactorVariable();
    117119      var laggedVariable = new LaggedVariable();
    118120      laggedVariable.InitialFrequency = 0.0;
     
    123125      var allSymbols = new List<Symbol>() { add, sub, mul, div, mean, sin, cos, tan, log, square, pow, sqrt, root, exp,
    124126        airyA, airyB, bessel, cosineIntegral, dawson, erf, expIntegralEi, fresnelCosineIntegral, fresnelSineIntegral, gamma, hypCosineIntegral, hypSineIntegral, norm, psi, sineIntegral,
    125         @if, gt, lt, and, or, not,xor, timeLag, integral, derivative, constant, variableSymbol, laggedVariable,autoregressiveVariable, variableCondition };
     127        @if, gt, lt, and, or, not,xor, timeLag, integral, derivative, constant, variableSymbol, binFactorVariable, factorVariable, laggedVariable,autoregressiveVariable, variableCondition };
    126128      var unaryFunctionSymbols = new List<Symbol>() { square, sqrt, sin, cos, tan, log, exp, not, timeLag, integral, derivative,
    127129        airyA, airyB, bessel, cosineIntegral, dawson, erf, expIntegralEi, fresnelCosineIntegral, fresnelSineIntegral, gamma, hypCosineIntegral, hypSineIntegral, norm, psi, sineIntegral
     
    130132      var binaryFunctionSymbols = new List<Symbol>() { pow, root, gt, lt, variableCondition };
    131133      var ternarySymbols = new List<Symbol>() { add, sub, mul, div, mean, and, or, xor };
    132       var terminalSymbols = new List<Symbol>() { variableSymbol, constant, laggedVariable, autoregressiveVariable };
     134      var terminalSymbols = new List<Symbol>() { variableSymbol, binFactorVariable, factorVariable, constant, laggedVariable, autoregressiveVariable };
    133135
    134136      foreach (var symb in allSymbols)
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Grammars/TypeCoherentExpressionGrammar.cs

    r14186 r15131  
    104104      constant.MaxValue = 20;
    105105      var variableSymbol = new Variable();
     106      var binFactorVariable = new BinaryFactorVariable();
     107      var factorVariable = new FactorVariable();
    106108      var laggedVariable = new LaggedVariable();
    107109      var autoregressiveVariable = new AutoregressiveTargetVariable();
     
    112114      var trigonometricSymbols = new GroupSymbol(TrigonometricFunctionsName, new List<ISymbol>() { sin, cos, tan });
    113115      var exponentialAndLogarithmicSymbols = new GroupSymbol(ExponentialFunctionsName, new List<ISymbol> { exp, log });
    114       var specialFunctions = new GroupSymbol(SpecialFunctionsName, new List<ISymbol> { airyA, airyB, bessel, cosineIntegral, dawson, erf, expIntegralEi, 
     116      var specialFunctions = new GroupSymbol(SpecialFunctionsName, new List<ISymbol> { airyA, airyB, bessel, cosineIntegral, dawson, erf, expIntegralEi,
    115117        fresnelCosineIntegral,fresnelSineIntegral,gamma,hypCosineIntegral,hypSineIntegral,norm, psi, sineIntegral});
    116       var terminalSymbols = new GroupSymbol(TerminalsName, new List<ISymbol> { constant, variableSymbol });
     118      var terminalSymbols = new GroupSymbol(TerminalsName, new List<ISymbol> { constant, variableSymbol, binFactorVariable, factorVariable });
    117119      var realValuedSymbols = new GroupSymbol(RealValuedSymbolsName, new List<ISymbol>() { arithmeticSymbols, trigonometricSymbols, exponentialAndLogarithmicSymbols, specialFunctions, terminalSymbols });
    118120
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj

    r14811 r15131  
    140140    <Compile Include="Importer\Token.cs" />
    141141    <Compile Include="Interfaces\IModelBacktransformator.cs" />
     142    <Compile Include="Interfaces\IVariableTreeNode.cs" />
     143    <Compile Include="Interfaces\IVariableSymbol.cs" />
    142144    <Compile Include="Interpreter\SymbolicDataAnalysisExpressionCompiledTreeInterpreter.cs" />
    143145    <Compile Include="SymbolicDataAnalysisExpressionTreeSimplificationOperator.cs" />
     
    198200    <Compile Include="Symbols\AiryB.cs" />
    199201    <Compile Include="Symbols\Bessel.cs" />
     202    <Compile Include="Symbols\BinaryFactorVariable.cs" />
     203    <Compile Include="Symbols\BinaryFactorVariableTreeNode.cs" />
     204    <Compile Include="Symbols\FactorVariableTreeNode.cs" />
     205    <Compile Include="Symbols\FactorVariable.cs" />
     206    <Compile Include="Symbols\VariableBase.cs" />
     207    <Compile Include="Symbols\VariableTreeNodeBase.cs" />
    200208    <Compile Include="Symbols\Xor.cs" />
    201209    <Compile Include="Symbols\Erf.cs" />
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/InfixExpressionParser.cs

    r14565 r15131  
    3333  /// Parses mathematical expressions in infix form. E.g. x1 * (3.0 * x2 + x3)
    3434  /// Identifier format (functions or variables): '_' | letter { '_' | letter | digit }
    35   /// Variables names can be set under quotes "" or '' because variable names might contain spaces.
     35  /// Variables names and variable values can be set under quotes "" or '' because variable names might contain spaces.
     36  ///   Variable = ident | " ident " | ' ident '
    3637  /// It is also possible to use functions e.g. log("x1") or real-valued constants e.g. 3.1415 .
    3738  /// Variable names are case sensitive. Function names are not case sensitive.
     39  ///
     40  ///
     41  /// S             = Expr EOF
     42  /// Expr          = ['-' | '+'] Term { '+' Term | '-' Term }
     43  /// Term          = Fact { '*' Fact | '/' Fact }
     44  /// Fact          = '(' Expr ')'
     45  ///                 | 'LAG' '(' varId ',' ['+' | '-' ] number ')'
     46  ///                 | funcId '(' ArgList ')'
     47  ///                 | VarExpr | number
     48  /// ArgList       = Expr { ',' Expr }
     49  /// VarExpr       = varId OptFactorPart
     50  /// OptFactorPart = [ ('=' varVal | '[' ['+' | '-' ] number {',' ['+' | '-' ] number } ']' ) ]
     51  /// varId         =  ident | ' ident ' | " ident "
     52  /// varVal        =  ident | ' ident ' | " ident "
     53  /// ident         =  '_' | letter { '_' | letter | digit }
    3854  /// </summary>
    3955  public sealed class InfixExpressionParser {
    40     private enum TokenType { Operator, Identifier, Number, LeftPar, RightPar, Comma, End, NA };
     56    private enum TokenType { Operator, Identifier, Number, LeftPar, RightPar, LeftBracket, RightBracket, Comma, Eq, End, NA };
    4157    private class Token {
    4258      internal double doubleVal;
     
    6581    private Constant constant = new Constant();
    6682    private Variable variable = new Variable();
     83    private BinaryFactorVariable binaryFactorVar = new BinaryFactorVariable();
     84    private FactorVariable factorVar = new FactorVariable();
    6785
    6886    private ProgramRootSymbol programRootSymbol = new ProgramRootSymbol();
     
    150168            && str[pos] != '/'
    151169            && str[pos] != ')'
     170            && str[pos] != ']'
    152171            && str[pos] != ',') {
    153172            sb.Append(str[pos]);
     
    214233          pos++;
    215234          yield return new Token { TokenType = TokenType.RightPar, strVal = ")" };
     235        } else if (str[pos] == '[') {
     236          pos++;
     237          yield return new Token { TokenType = TokenType.LeftBracket, strVal = "[" };
     238        } else if (str[pos] == ']') {
     239          pos++;
     240          yield return new Token { TokenType = TokenType.RightBracket, strVal = "]" };
     241        } else if (str[pos] == '=') {
     242          pos++;
     243          yield return new Token { TokenType = TokenType.Eq, strVal = "=" };
    216244        } else if (str[pos] == ',') {
    217245          pos++;
     
    222250      }
    223251    }
    224 
    225     // S       = Expr EOF
    226     // Expr    = ['-' | '+'] Term { '+' Term | '-' Term }
    227     // Term    = Fact { '*' Fact | '/' Fact }
    228     // Fact    = '(' Expr ')' | funcId '(' ArgList ')' | varId | number
    229     // ArgList = Expr { ',' Expr }
     252    /// S             = Expr EOF
    230253    private ISymbolicExpressionTreeNode ParseS(Queue<Token> tokens) {
    231254      var expr = ParseExpr(tokens);
     
    237260      return expr;
    238261    }
     262
     263    /// Expr          = ['-' | '+'] Term { '+' Term | '-' Term }
    239264    private ISymbolicExpressionTreeNode ParseExpr(Queue<Token> tokens) {
    240265      var next = tokens.Peek();
     
    300325    }
    301326
    302     // Term = Fact { '*' Fact | '/' Fact }
     327    /// Term          = Fact { '*' Fact | '/' Fact }
    303328    private ISymbolicExpressionTreeNode ParseTerm(Queue<Token> tokens) {
    304329      var factors = new List<ISymbolicExpressionTreeNode>();
     
    335360    }
    336361
    337     // Fact = '(' Expr ')' | 'LAG' '(' varId ',' ['+' | '-'] number ')' | funcId '(' ArgList ')' | varId | number
     362    /// Fact          = '(' Expr ')'
     363    ///                 | 'LAG' '(' varId ',' ['+' | '-' ] number ')'
     364    ///                 | funcId '(' ArgList ')'
     365    ///                 | VarExpr | number
     366    /// ArgList       = Expr { ',' Expr }
     367    /// VarExpr       = varId OptFactorPart
     368    /// OptFactorPart = [ ('=' varVal | '[' ['+' | '-' ] number {',' ['+' | '-' ] number } ']' ) ]
     369    /// varId         =  ident | ' ident ' | " ident "
     370    /// varVal        =  ident | ' ident ' | " ident "
     371    /// ident         =  '_' | letter { '_' | letter | digit }
    338372    private ISymbolicExpressionTreeNode ParseFact(Queue<Token> tokens) {
    339373      var next = tokens.Peek();
     
    348382        var idTok = tokens.Dequeue();
    349383        if (tokens.Peek().TokenType == TokenType.LeftPar) {
    350           // function identifier
     384          // function identifier or LAG
    351385          var funcId = idTok.strVal.ToUpperInvariant();
    352386
     
    394428        } else {
    395429          // variable
    396           var varNode = (VariableTreeNode)variable.CreateTreeNode();
    397           varNode.Weight = 1.0;
    398           varNode.VariableName = idTok.strVal;
    399           return varNode;
     430          if (tokens.Peek().TokenType == TokenType.Eq) {
     431            // binary factor
     432            tokens.Dequeue(); // skip Eq
     433            var valTok = tokens.Dequeue();
     434            if (valTok.TokenType != TokenType.Identifier) throw new ArgumentException("expected identifier");
     435            var binFactorNode = (BinaryFactorVariableTreeNode)binaryFactorVar.CreateTreeNode();
     436            binFactorNode.Weight = 1.0;
     437            binFactorNode.VariableName = idTok.strVal;
     438            binFactorNode.VariableValue = valTok.strVal;
     439            return binFactorNode;
     440          } else if (tokens.Peek().TokenType == TokenType.LeftBracket) {
     441            // factor variable
     442            var factorVariableNode = (FactorVariableTreeNode)factorVar.CreateTreeNode();
     443            factorVariableNode.VariableName = idTok.strVal;
     444
     445            tokens.Dequeue(); // skip [
     446            var weights = new List<double>();
     447            // at least one weight is necessary
     448            var sign = 1.0;
     449            if (tokens.Peek().TokenType == TokenType.Operator) {
     450              var opToken = tokens.Dequeue();
     451              if (opToken.strVal == "+") sign = 1.0;
     452              else if (opToken.strVal == "-") sign = -1.0;
     453              else throw new ArgumentException();
     454            }
     455            if (tokens.Peek().TokenType != TokenType.Number) throw new ArgumentException("number expected");
     456            var weightTok = tokens.Dequeue();
     457            weights.Add(sign * weightTok.doubleVal);
     458            while (tokens.Peek().TokenType == TokenType.Comma) {
     459              // skip comma
     460              tokens.Dequeue();
     461              if (tokens.Peek().TokenType == TokenType.Operator) {
     462                var opToken = tokens.Dequeue();
     463                if (opToken.strVal == "+") sign = 1.0;
     464                else if (opToken.strVal == "-") sign = -1.0;
     465                else throw new ArgumentException();
     466              }
     467              weightTok = tokens.Dequeue();
     468              if (weightTok.TokenType != TokenType.Number) throw new ArgumentException("number expected");
     469              weights.Add(sign * weightTok.doubleVal);
     470            }
     471            var rightBracketToken = tokens.Dequeue();
     472            if (rightBracketToken.TokenType != TokenType.RightBracket) throw new ArgumentException("closing bracket ] expected");
     473            factorVariableNode.Weights = weights.ToArray();
     474            return factorVariableNode;
     475          } else {
     476            // variable
     477            var varNode = (VariableTreeNode)variable.CreateTreeNode();
     478            varNode.Weight = 1.0;
     479            varNode.VariableName = idTok.strVal;
     480            return varNode;
     481          }
    400482        }
    401483      } else if (next.TokenType == TokenType.Number) {
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/SymbolicExpressionImporter.cs

    r14186 r15131  
    3535    private const string INVOKESTART = "CALL";
    3636    private const string TIMELAGSTART = "LAG";
    37     private Dictionary<string, Symbol> knownSymbols = new Dictionary<string, Symbol>() 
     37    private Dictionary<string, Symbol> knownSymbols = new Dictionary<string, Symbol>()
    3838      {
    3939        {"+", new Addition()},
     
    4545        {"POW", new Power()},
    4646        {"ROOT", new Root()},
     47        {"SQR", new Square()},
     48        {"SQRT", new SquareRoot()},
    4749        {"SIN",new Sine()},
    4850        {"COS", new Cosine()},
     
    7476        {"PROG", new ProgramRootSymbol()},
    7577        {"MAIN", new StartSymbol()},
     78        {"FACTOR", new FactorVariable() },
     79        {"BINFACTOR", new BinaryFactorVariable()}
    7680      };
    7781
     
    8286    TimeLag timeLag = new TimeLag();
    8387    Integral integral = new Integral();
     88    FactorVariable factorVar = new FactorVariable();
     89    BinaryFactorVariable binFactorVar = new BinaryFactorVariable();
    8490
    8591    ProgramRootSymbol programRootSymbol = new ProgramRootSymbol();
     
    136142            tree.AddSubtree(ParseSexp(tokens));
    137143          }
     144        } else if (tokens.Peek().StringValue.StartsWith("FACTOR")) {
     145          tree = ParseFactor(tokens);
     146        } else if (tokens.Peek().StringValue.StartsWith("BINFACTOR")) {
     147          tree = ParseBinaryFactor(tokens);
    138148        } else {
    139149          Token curToken = tokens.Dequeue();
     
    201211    }
    202212
     213    private ISymbolicExpressionTreeNode ParseFactor(Queue<Token> tokens) {
     214      Token tok = tokens.Dequeue();
     215      Debug.Assert(tok.StringValue == "FACTOR");
     216      FactorVariableTreeNode t = (FactorVariableTreeNode)(new FactorVariable()).CreateTreeNode(); // create a new symbol each time on purpose
     217      var varNameTok = tokens.Dequeue();
     218      Debug.Assert(tok.Symbol == TokenSymbol.SYMB);
     219      t.VariableName = varNameTok.StringValue;
     220
     221      var weights = new List<double>();
     222      while (tokens.Peek().Symbol == TokenSymbol.NUMBER) {
     223        weights.Add(tokens.Dequeue().DoubleValue);
     224      }
     225
     226      t.Weights = weights.ToArray();
     227
     228      // create a set of (virtual) values to match the number of weights
     229      t.Symbol.VariableNames = new string[] { t.VariableName };
     230      t.Symbol.VariableValues = new[]
     231      { new KeyValuePair<string, Dictionary<string,int>>(
     232        t.VariableName,
     233        weights.Select((_, i) => Tuple.Create(_,i)).ToDictionary(tup=>"X" + tup.Item2, tup=>tup.Item2)) };
     234      return t;
     235    }
     236
     237    private ISymbolicExpressionTreeNode ParseBinaryFactor(Queue<Token> tokens) {
     238      Token tok = tokens.Dequeue();
     239      Debug.Assert(tok.StringValue == "BINFACTOR");
     240      var t = (BinaryFactorVariableTreeNode)binFactorVar.CreateTreeNode();
     241      var varNameTok = tokens.Dequeue();
     242      Debug.Assert(varNameTok.Symbol == TokenSymbol.SYMB);
     243      t.VariableName = varNameTok.StringValue;
     244
     245      var varValTok = tokens.Dequeue();
     246      Debug.Assert(varValTok.Symbol == TokenSymbol.SYMB);
     247      t.VariableValue = varValTok.StringValue;
     248
     249      var weightTok = tokens.Dequeue();
     250      Debug.Assert(weightTok.Symbol == TokenSymbol.NUMBER);
     251      t.Weight = weightTok.DoubleValue;
     252
     253      return t;
     254    }
     255
     256
    203257    private ISymbolicExpressionTreeNode ParseLaggedVariable(Queue<Token> tokens) {
    204258      Token varTok = tokens.Dequeue();
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interfaces/ISymbolicDataAnalysisImpactValuesCalculator.cs

    r12745 r15131  
    55namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
    66  public interface ISymbolicDataAnalysisSolutionImpactValuesCalculator : IItem {
    7     double CalculateReplacementValue(ISymbolicDataAnalysisModel model, ISymbolicExpressionTreeNode node, IDataAnalysisProblemData problemData, IEnumerable<int> rows);
    8     double CalculateImpactValue(ISymbolicDataAnalysisModel model, ISymbolicExpressionTreeNode node, IDataAnalysisProblemData problemData, IEnumerable<int> rows, double qualityForImpactsCalculation = double.NaN);
    97    void CalculateImpactAndReplacementValues(ISymbolicDataAnalysisModel model, ISymbolicExpressionTreeNode node, IDataAnalysisProblemData problemData,
    108      IEnumerable<int> rows, out double impactValue, out double replacementValue, out double newQualityForImpactsCalculation, double qualityForImpactsCalculation = double.NaN);
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/OpCodes.cs

    r14186 r15131  
    8383    public const byte Erf = 43;
    8484    public const byte Bessel = 44;
     85    public const byte FactorVariable = 46;
     86    public const byte BinaryFactorVariable = 47;
     87
    8588
    8689    private static Dictionary<Type, byte> symbolToOpcode = new Dictionary<Type, byte>() {
     
    130133      { typeof(Norm), OpCodes.Norm},
    131134      { typeof(Erf), OpCodes.Erf},
    132       { typeof(Bessel), OpCodes.Bessel}   
     135      { typeof(Bessel), OpCodes.Bessel},
     136      { typeof(FactorVariable), OpCodes.FactorVariable },
     137      { typeof(BinaryFactorVariable), OpCodes.BinaryFactorVariable }
    133138    };
    134139
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeILEmittingInterpreter.cs

    r14811 r15131  
    6666    private static MethodInfo erf = thisType.GetMethod("Erf", new Type[] { typeof(double) });
    6767    private static MethodInfo bessel = thisType.GetMethod("Bessel", new Type[] { typeof(double) });
     68    private static MethodInfo string_eq = typeof(string).GetMethod("Equals", new Type[] { typeof(string) });
    6869    #endregion
    6970
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeInterpreter.cs

    r15127 r15131  
    2222using System;
    2323using System.Collections.Generic;
     24using System.Linq;
    2425using HeuristicLab.Common;
    2526using HeuristicLab.Core;
     
    143144          var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
    144145          instr.data = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
     146        } else if (instr.opCode == OpCodes.FactorVariable) {
     147          var factorTreeNode = instr.dynamicNode as FactorVariableTreeNode;
     148          instr.data = dataset.GetReadOnlyStringValues(factorTreeNode.VariableName);
     149        } else if (instr.opCode == OpCodes.BinaryFactorVariable) {
     150          var factorTreeNode = instr.dynamicNode as BinaryFactorVariableTreeNode;
     151          instr.data = dataset.GetReadOnlyStringValues(factorTreeNode.VariableName);
    145152        } else if (instr.opCode == OpCodes.LagVariable) {
    146153          var laggedVariableTreeNode = (LaggedVariableTreeNode)instr.dynamicNode;
     
    455462            return ((IList<double>)currentInstr.data)[row] * variableTreeNode.Weight;
    456463          }
     464        case OpCodes.BinaryFactorVariable: {
     465            if (row < 0 || row >= dataset.Rows) return double.NaN;
     466            var factorVarTreeNode = currentInstr.dynamicNode as BinaryFactorVariableTreeNode;
     467            return ((IList<string>)currentInstr.data)[row] == factorVarTreeNode.VariableValue ? factorVarTreeNode.Weight : 0;
     468          }
     469        case OpCodes.FactorVariable: {
     470            if (row < 0 || row >= dataset.Rows) return double.NaN;
     471            var factorVarTreeNode = currentInstr.dynamicNode as FactorVariableTreeNode;
     472            return factorVarTreeNode.GetValue(((IList<string>)currentInstr.data)[row]);
     473          }
    457474        case OpCodes.LagVariable: {
    458475            var laggedVariableTreeNode = (LaggedVariableTreeNode)currentInstr.dynamicNode;
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeLinearInterpreter.cs

    r15127 r15131  
    149149            var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
    150150            instr.value = ((IList<double>)instr.data)[row] * variableTreeNode.Weight;
     151          }
     152        } else if (instr.opCode == OpCodes.BinaryFactorVariable) {
     153          if (row < 0 || row >= dataset.Rows) instr.value = double.NaN;
     154          else {
     155            var factorTreeNode = instr.dynamicNode as BinaryFactorVariableTreeNode;
     156            instr.value = ((IList<string>)instr.data)[row] == factorTreeNode.VariableValue ? factorTreeNode.Weight : 0;
     157          }
     158        } else if (instr.opCode == OpCodes.FactorVariable) {
     159          if (row < 0 || row >= dataset.Rows) instr.value = double.NaN;
     160          else {
     161            var factorTreeNode = instr.dynamicNode as FactorVariableTreeNode;
     162            instr.value = factorTreeNode.GetValue(((IList<string>)instr.data)[row]);
    151163          }
    152164        } else if (instr.opCode == OpCodes.LagVariable) {
     
    403415            }
    404416            break;
     417          case OpCodes.BinaryFactorVariable: {
     418              var factorVariableTreeNode = instr.dynamicNode as BinaryFactorVariableTreeNode;
     419              instr.data = dataset.GetReadOnlyStringValues(factorVariableTreeNode.VariableName);
     420            }
     421            break;
     422          case OpCodes.FactorVariable: {
     423              var factorVariableTreeNode = instr.dynamicNode as FactorVariableTreeNode;
     424              instr.data = dataset.GetReadOnlyStringValues(factorVariableTreeNode.VariableName);
     425            }
     426            break;
    405427          case OpCodes.LagVariable: {
    406428              var laggedVariableTreeNode = (LaggedVariableTreeNode)instr.dynamicNode;
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeSimplifier.cs

    r14186 r15131  
    11#region License Information
     2
    23/* HeuristicLab
    34 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
     
    1819 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
    1920 */
     21
    2022#endregion
    2123
    2224using System;
    2325using System.Collections.Generic;
     26using System.Diagnostics;
    2427using System.Linq;
    2528using HeuristicLab.Common;
     29using HeuristicLab.Core;
    2630using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
    2731
     
    3236  public class SymbolicDataAnalysisExpressionTreeSimplifier {
    3337    private Addition addSymbol = new Addition();
    34     private Subtraction subSymbol = new Subtraction();
    3538    private Multiplication mulSymbol = new Multiplication();
    3639    private Division divSymbol = new Division();
     
    6265      ISymbolicExpressionTreeNode rootNode = (new ProgramRootSymbol()).CreateTreeNode();
    6366      rootNode.AddSubtree(GetSimplifiedTree(macroExpandedTree));
     67
     68#if DEBUG
     69      // check that each node is only referenced once
     70      var nodes = rootNode.IterateNodesPrefix().ToArray();
     71      foreach(var n in nodes) if(nodes.Count(ni => ni == n) > 1) throw new InvalidOperationException();
     72#endif
    6473      return new SymbolicExpressionTree(rootNode);
    6574    }
    6675
    6776    // the argumentTrees list contains already expanded trees used as arguments for invocations
    68     private ISymbolicExpressionTreeNode MacroExpand(ISymbolicExpressionTreeNode root, ISymbolicExpressionTreeNode node, IList<ISymbolicExpressionTreeNode> argumentTrees) {
     77    private ISymbolicExpressionTreeNode MacroExpand(ISymbolicExpressionTreeNode root, ISymbolicExpressionTreeNode node,
     78      IList<ISymbolicExpressionTreeNode> argumentTrees) {
    6979      List<ISymbolicExpressionTreeNode> subtrees = new List<ISymbolicExpressionTreeNode>(node.Subtrees);
    7080      while (node.SubtreeCount > 0) node.RemoveSubtree(0);
     
    98108    }
    99109
    100 
    101110    #region symbol predicates
     111
    102112    // arithmetic
    103113    private bool IsDivision(ISymbolicExpressionTreeNode node) {
     
    120130      return node.Symbol is Average;
    121131    }
     132
    122133    // exponential
    123134    private bool IsLog(ISymbolicExpressionTreeNode node) {
    124135      return node.Symbol is Logarithm;
    125136    }
     137
    126138    private bool IsExp(ISymbolicExpressionTreeNode node) {
    127139      return node.Symbol is Exponential;
    128140    }
     141
    129142    private bool IsRoot(ISymbolicExpressionTreeNode node) {
    130143      return node.Symbol is Root;
    131144    }
     145
    132146    private bool IsSquare(ISymbolicExpressionTreeNode node) {
    133147      return node.Symbol is Square;
    134148    }
     149
    135150    private bool IsSquareRoot(ISymbolicExpressionTreeNode node) {
    136151      return node.Symbol is SquareRoot;
    137152    }
     153
    138154    private bool IsPower(ISymbolicExpressionTreeNode node) {
    139155      return node.Symbol is Power;
    140156    }
     157
    141158    // trigonometric
    142159    private bool IsSine(ISymbolicExpressionTreeNode node) {
    143160      return node.Symbol is Sine;
    144161    }
     162
    145163    private bool IsCosine(ISymbolicExpressionTreeNode node) {
    146164      return node.Symbol is Cosine;
    147165    }
     166
    148167    private bool IsTangent(ISymbolicExpressionTreeNode node) {
    149168      return node.Symbol is Tangent;
    150169    }
     170
    151171    // boolean
    152172    private bool IsIfThenElse(ISymbolicExpressionTreeNode node) {
    153173      return node.Symbol is IfThenElse;
    154174    }
     175
    155176    private bool IsAnd(ISymbolicExpressionTreeNode node) {
    156177      return node.Symbol is And;
    157178    }
     179
    158180    private bool IsOr(ISymbolicExpressionTreeNode node) {
    159181      return node.Symbol is Or;
    160182    }
     183
    161184    private bool IsNot(ISymbolicExpressionTreeNode node) {
    162185      return node.Symbol is Not;
    163186    }
     187
    164188    // comparison
    165189    private bool IsGreaterThan(ISymbolicExpressionTreeNode node) {
    166190      return node.Symbol is GreaterThan;
    167191    }
     192
    168193    private bool IsLessThan(ISymbolicExpressionTreeNode node) {
    169194      return node.Symbol is LessThan;
     
    183208    }
    184209
     210    private bool IsVariableBase(ISymbolicExpressionTreeNode node) {
     211      return node is VariableTreeNodeBase;
     212    }
     213
     214    private bool IsFactor(ISymbolicExpressionTreeNode node) {
     215      return node is FactorVariableTreeNode;
     216    }
     217
     218    private bool IsBinFactor(ISymbolicExpressionTreeNode node) {
     219      return node is BinaryFactorVariableTreeNode;
     220    }
     221
    185222    private bool IsConstant(ISymbolicExpressionTreeNode node) {
    186223      return node.Symbol is Constant;
     
    191228      return node.Symbol is TimeLag;
    192229    }
     230
    193231    private bool IsIntegral(ISymbolicExpressionTreeNode node) {
    194232      return node.Symbol is Integral;
     
    203241    /// <returns></returns>
    204242    public ISymbolicExpressionTreeNode GetSimplifiedTree(ISymbolicExpressionTreeNode original) {
    205       if (IsConstant(original) || IsVariable(original)) {
     243      if (IsConstant(original) || IsVariableBase(original)) {
    206244        return (ISymbolicExpressionTreeNode)original.Clone();
    207245      } else if (IsAddition(original)) {
     
    254292    }
    255293
    256 
    257294    #region specific simplification routines
     295
    258296    private ISymbolicExpressionTreeNode SimplifyAny(ISymbolicExpressionTreeNode original) {
    259297      // can't simplify this function but simplify all subtrees
     
    303341        var remaining = original.Subtrees.Skip(2);
    304342        return
    305           MakeProduct(GetSimplifiedTree(first), Invert(remaining.Aggregate(GetSimplifiedTree(second), (a, b) => MakeProduct(a, GetSimplifiedTree(b)))));
     343          MakeProduct(GetSimplifiedTree(first),
     344            Invert(remaining.Aggregate(GetSimplifiedTree(second), (a, b) => MakeProduct(a, GetSimplifiedTree(b)))));
    306345      }
    307346    }
     
    344383      return MakeNot(GetSimplifiedTree(original.GetSubtree(0)));
    345384    }
     385
    346386    private ISymbolicExpressionTreeNode SimplifyOr(ISymbolicExpressionTreeNode original) {
    347387      return original.Subtrees
     
    349389        .Aggregate(MakeOr);
    350390    }
     391
    351392    private ISymbolicExpressionTreeNode SimplifyAnd(ISymbolicExpressionTreeNode original) {
    352393      return original.Subtrees
     
    354395        .Aggregate(MakeAnd);
    355396    }
     397
    356398    private ISymbolicExpressionTreeNode SimplifyLessThan(ISymbolicExpressionTreeNode original) {
    357399      return MakeLessThan(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
    358400    }
     401
    359402    private ISymbolicExpressionTreeNode SimplifyGreaterThan(ISymbolicExpressionTreeNode original) {
    360403      return MakeGreaterThan(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
    361404    }
     405
    362406    private ISymbolicExpressionTreeNode SimplifyIfThenElse(ISymbolicExpressionTreeNode original) {
    363       return MakeIfThenElse(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)), GetSimplifiedTree(original.GetSubtree(2)));
    364     }
     407      return MakeIfThenElse(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)),
     408        GetSimplifiedTree(original.GetSubtree(2)));
     409    }
     410
    365411    private ISymbolicExpressionTreeNode SimplifyTangent(ISymbolicExpressionTreeNode original) {
    366412      return MakeTangent(GetSimplifiedTree(original.GetSubtree(0)));
    367413    }
     414
    368415    private ISymbolicExpressionTreeNode SimplifyCosine(ISymbolicExpressionTreeNode original) {
    369416      return MakeCosine(GetSimplifiedTree(original.GetSubtree(0)));
    370417    }
     418
    371419    private ISymbolicExpressionTreeNode SimplifySine(ISymbolicExpressionTreeNode original) {
    372420      return MakeSine(GetSimplifiedTree(original.GetSubtree(0)));
    373421    }
     422
    374423    private ISymbolicExpressionTreeNode SimplifyExp(ISymbolicExpressionTreeNode original) {
    375424      return MakeExp(GetSimplifiedTree(original.GetSubtree(0)));
    376425    }
     426
    377427    private ISymbolicExpressionTreeNode SimplifySquare(ISymbolicExpressionTreeNode original) {
    378428      return MakeSquare(GetSimplifiedTree(original.GetSubtree(0)));
    379429    }
     430
    380431    private ISymbolicExpressionTreeNode SimplifySquareRoot(ISymbolicExpressionTreeNode original) {
    381432      return MakeSquareRoot(GetSimplifiedTree(original.GetSubtree(0)));
     
    385436      return MakeLog(GetSimplifiedTree(original.GetSubtree(0)));
    386437    }
     438
    387439    private ISymbolicExpressionTreeNode SimplifyRoot(ISymbolicExpressionTreeNode original) {
    388440      return MakeRoot(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
     
    392444      return MakePower(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
    393445    }
     446
    394447    private ISymbolicExpressionTreeNode SimplifyTimeLag(ISymbolicExpressionTreeNode original) {
    395448      var laggedTreeNode = original as ILaggedTreeNode;
     
    401454      }
    402455    }
     456
    403457    private ISymbolicExpressionTreeNode SimplifyIntegral(ISymbolicExpressionTreeNode original) {
    404458      var laggedTreeNode = original as ILaggedTreeNode;
     
    414468
    415469    #region low level tree restructuring
     470
    416471    private ISymbolicExpressionTreeNode MakeTimeLag(ISymbolicExpressionTreeNode subtree, int lag) {
    417472      if (lag == 0) return subtree;
     
    444499      } else if (!IsBoolean(t)) {
    445500        var gtNode = gtSymbol.CreateTreeNode();
    446         gtNode.AddSubtree(t); gtNode.AddSubtree(MakeConstant(0.0));
     501        gtNode.AddSubtree(t);
     502        gtNode.AddSubtree(MakeConstant(0.0));
    447503        var notNode = notSymbol.CreateTreeNode();
    448504        notNode.AddSubtree(gtNode);
     
    484540      }
    485541    }
     542
    486543    private ISymbolicExpressionTreeNode MakeAnd(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
    487544      if (IsConstant(a) && IsConstant(b)) {
     
    513570      }
    514571    }
    515     private ISymbolicExpressionTreeNode MakeLessThan(ISymbolicExpressionTreeNode leftSide, ISymbolicExpressionTreeNode rightSide) {
     572
     573    private ISymbolicExpressionTreeNode MakeLessThan(ISymbolicExpressionTreeNode leftSide,
     574      ISymbolicExpressionTreeNode rightSide) {
    516575      if (IsConstant(leftSide) && IsConstant(rightSide)) {
    517576        var lsConst = leftSide as ConstantTreeNode;
     
    526585      }
    527586    }
    528     private ISymbolicExpressionTreeNode MakeGreaterThan(ISymbolicExpressionTreeNode leftSide, ISymbolicExpressionTreeNode rightSide) {
     587
     588    private ISymbolicExpressionTreeNode MakeGreaterThan(ISymbolicExpressionTreeNode leftSide,
     589      ISymbolicExpressionTreeNode rightSide) {
    529590      if (IsConstant(leftSide) && IsConstant(rightSide)) {
    530591        var lsConst = leftSide as ConstantTreeNode;
     
    539600      }
    540601    }
    541     private ISymbolicExpressionTreeNode MakeIfThenElse(ISymbolicExpressionTreeNode condition, ISymbolicExpressionTreeNode trueBranch, ISymbolicExpressionTreeNode falseBranch) {
     602
     603    private ISymbolicExpressionTreeNode MakeIfThenElse(ISymbolicExpressionTreeNode condition,
     604      ISymbolicExpressionTreeNode trueBranch, ISymbolicExpressionTreeNode falseBranch) {
    542605      if (IsConstant(condition)) {
    543606        var constT = condition as ConstantTreeNode;
     
    550613        } else {
    551614          var gtNode = gtSymbol.CreateTreeNode();
    552           gtNode.AddSubtree(condition); gtNode.AddSubtree(MakeConstant(0.0));
     615          gtNode.AddSubtree(condition);
     616          gtNode.AddSubtree(MakeConstant(0.0));
    553617          ifNode.AddSubtree(gtNode);
    554618        }
     
    563627        var constT = node as ConstantTreeNode;
    564628        return MakeConstant(Math.Sin(constT.Value));
     629      } else if (IsFactor(node)) {
     630        var factor = node as FactorVariableTreeNode;
     631        return MakeFactor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Sin));
     632      } else if (IsBinFactor(node)) {
     633        var binFactor = node as BinaryFactorVariableTreeNode;
     634        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sin(binFactor.Weight));
    565635      } else {
    566636        var sineNode = sineSymbol.CreateTreeNode();
     
    569639      }
    570640    }
     641
    571642    private ISymbolicExpressionTreeNode MakeTangent(ISymbolicExpressionTreeNode node) {
    572643      if (IsConstant(node)) {
    573644        var constT = node as ConstantTreeNode;
    574645        return MakeConstant(Math.Tan(constT.Value));
     646      } else if (IsFactor(node)) {
     647        var factor = node as FactorVariableTreeNode;
     648        return MakeFactor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Tan));
     649      } else if (IsBinFactor(node)) {
     650        var binFactor = node as BinaryFactorVariableTreeNode;
     651        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Tan(binFactor.Weight));
    575652      } else {
    576653        var tanNode = tanSymbol.CreateTreeNode();
     
    579656      }
    580657    }
     658
    581659    private ISymbolicExpressionTreeNode MakeCosine(ISymbolicExpressionTreeNode node) {
    582660      if (IsConstant(node)) {
    583661        var constT = node as ConstantTreeNode;
    584662        return MakeConstant(Math.Cos(constT.Value));
     663      } else if (IsFactor(node)) {
     664        var factor = node as FactorVariableTreeNode;
     665        return MakeFactor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Cos));
     666      } else if (IsBinFactor(node)) {
     667        var binFactor = node as BinaryFactorVariableTreeNode;
     668        // cos(0) = 1 see similar case for Exp(binfactor)
     669        return MakeSum(MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Cos(binFactor.Weight) - 1),
     670          MakeConstant(1.0));
    585671      } else {
    586672        var cosNode = cosineSymbol.CreateTreeNode();
     
    589675      }
    590676    }
     677
    591678    private ISymbolicExpressionTreeNode MakeExp(ISymbolicExpressionTreeNode node) {
    592679      if (IsConstant(node)) {
    593680        var constT = node as ConstantTreeNode;
    594681        return MakeConstant(Math.Exp(constT.Value));
     682      } else if (IsFactor(node)) {
     683        var factNode = node as FactorVariableTreeNode;
     684        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Exp(w)));
     685      } else if (IsBinFactor(node)) {
     686        // exp( binfactor w val=a) = if(val=a) exp(w) else exp(0) = binfactor( (exp(w) - 1) val a) + 1
     687        var binFactor = node as BinaryFactorVariableTreeNode;
     688        return
     689          MakeSum(MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Exp(binFactor.Weight) - 1), MakeConstant(1.0));
    595690      } else if (IsLog(node)) {
    596691        return node.GetSubtree(0);
     
    605700      }
    606701    }
     702    private ISymbolicExpressionTreeNode MakeLog(ISymbolicExpressionTreeNode node) {
     703      if (IsConstant(node)) {
     704        var constT = node as ConstantTreeNode;
     705        return MakeConstant(Math.Log(constT.Value));
     706      } else if (IsFactor(node)) {
     707        var factNode = node as FactorVariableTreeNode;
     708        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Log(w)));
     709      } else if (IsExp(node)) {
     710        return node.GetSubtree(0);
     711      } else if (IsSquareRoot(node)) {
     712        return MakeFraction(MakeLog(node.GetSubtree(0)), MakeConstant(2.0));
     713      } else {
     714        var logNode = logSymbol.CreateTreeNode();
     715        logNode.AddSubtree(node);
     716        return logNode;
     717      }
     718    }
    607719
    608720    private ISymbolicExpressionTreeNode MakeSquare(ISymbolicExpressionTreeNode node) {
     
    610722        var constT = node as ConstantTreeNode;
    611723        return MakeConstant(constT.Value * constT.Value);
     724      } else if (IsFactor(node)) {
     725        var factNode = node as FactorVariableTreeNode;
     726        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => w * w));
     727      } else if (IsBinFactor(node)) {
     728        var binFactor = node as BinaryFactorVariableTreeNode;
     729        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, binFactor.Weight * binFactor.Weight);
    612730      } else if (IsSquareRoot(node)) {
    613731        return node.GetSubtree(0);
     
    618736      }
    619737    }
     738
    620739    private ISymbolicExpressionTreeNode MakeSquareRoot(ISymbolicExpressionTreeNode node) {
    621740      if (IsConstant(node)) {
    622741        var constT = node as ConstantTreeNode;
    623742        return MakeConstant(Math.Sqrt(constT.Value));
     743      } else if (IsFactor(node)) {
     744        var factNode = node as FactorVariableTreeNode;
     745        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Sqrt(w)));
     746      } else if (IsBinFactor(node)) {
     747        var binFactor = node as BinaryFactorVariableTreeNode;
     748        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sqrt(binFactor.Weight));
    624749      } else if (IsSquare(node)) {
    625750        return node.GetSubtree(0);
     
    631756    }
    632757
    633     private ISymbolicExpressionTreeNode MakeLog(ISymbolicExpressionTreeNode node) {
    634       if (IsConstant(node)) {
    635         var constT = node as ConstantTreeNode;
    636         return MakeConstant(Math.Log(constT.Value));
    637       } else if (IsExp(node)) {
    638         return node.GetSubtree(0);
    639       } else if (IsSquareRoot(node)) {
    640         return MakeFraction(MakeLog(node.GetSubtree(0)), MakeConstant(2.0));
    641       } else {
    642         var logNode = logSymbol.CreateTreeNode();
    643         logNode.AddSubtree(node);
    644         return logNode;
    645       }
    646     }
    647758    private ISymbolicExpressionTreeNode MakeRoot(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
    648759      if (IsConstant(a) && IsConstant(b)) {
     
    650761        var constB = b as ConstantTreeNode;
    651762        return MakeConstant(Math.Pow(constA.Value, 1.0 / Math.Round(constB.Value)));
     763      } else if (IsFactor(a) && IsConstant(b)) {
     764        var factNode = a as FactorVariableTreeNode;
     765        var constNode = b as ConstantTreeNode;
     766        return MakeFactor(factNode.Symbol, factNode.VariableName,
     767          factNode.Weights.Select(w => Math.Pow(w, 1.0 / Math.Round(constNode.Value))));
     768      } else if (IsBinFactor(a) && IsConstant(b)) {
     769        var binFactor = a as BinaryFactorVariableTreeNode;
     770        var constNode = b as ConstantTreeNode;
     771        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Pow(binFactor.Weight, 1.0 / Math.Round(constNode.Value)));
     772      } else if (IsConstant(a) && IsFactor(b)) {
     773        var constNode = a as ConstantTreeNode;
     774        var factNode = b as FactorVariableTreeNode;
     775        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(constNode.Value, 1.0 / Math.Round(w))));
     776      } else if (IsConstant(a) && IsBinFactor(b)) {
     777        var constNode = a as ConstantTreeNode;
     778        var factNode = b as BinaryFactorVariableTreeNode;
     779        return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, Math.Pow(constNode.Value, 1.0 / Math.Round(factNode.Weight)));
     780      } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
     781        var node0 = a as FactorVariableTreeNode;
     782        var node1 = b as FactorVariableTreeNode;
     783        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => Math.Pow(u, 1.0 / Math.Round(v))));
    652784      } else if (IsConstant(b)) {
    653785        var constB = b as ConstantTreeNode;
     
    677809      }
    678810    }
     811
     812
    679813    private ISymbolicExpressionTreeNode MakePower(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
    680814      if (IsConstant(a) && IsConstant(b)) {
     
    682816        var constB = b as ConstantTreeNode;
    683817        return MakeConstant(Math.Pow(constA.Value, Math.Round(constB.Value)));
     818      } else if (IsFactor(a) && IsConstant(b)) {
     819        var factNode = a as FactorVariableTreeNode;
     820        var constNode = b as ConstantTreeNode;
     821        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(w, Math.Round(constNode.Value))));
     822      } else if (IsBinFactor(a) && IsConstant(b)) {
     823        var binFactor = a as BinaryFactorVariableTreeNode;
     824        var constNode = b as ConstantTreeNode;
     825        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Pow(binFactor.Weight, Math.Round(constNode.Value)));
     826      } else if (IsConstant(a) && IsFactor(b)) {
     827        var constNode = a as ConstantTreeNode;
     828        var factNode = b as FactorVariableTreeNode;
     829        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(constNode.Value, Math.Round(w))));
     830      } else if (IsConstant(a) && IsBinFactor(b)) {
     831        var constNode = a as ConstantTreeNode;
     832        var factNode = b as BinaryFactorVariableTreeNode;
     833        return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, Math.Pow(constNode.Value, Math.Round(factNode.Weight)));
     834      } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
     835        var node0 = a as FactorVariableTreeNode;
     836        var node1 = b as FactorVariableTreeNode;
     837        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => Math.Pow(u, Math.Round(v))));
    684838      } else if (IsConstant(b)) {
    685839        var constB = b as ConstantTreeNode;
     
    716870        // fold constants
    717871        return MakeConstant(((ConstantTreeNode)a).Value / ((ConstantTreeNode)b).Value);
    718       } if (IsConstant(a) && !((ConstantTreeNode)a).Value.IsAlmost(1.0)) {
     872      } else if ((IsConstant(a) && !((ConstantTreeNode)a).Value.IsAlmost(1.0))) {
    719873        return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
    720       } else if (IsVariable(a) && IsConstant(b)) {
     874      } else if (IsVariableBase(a) && IsConstant(b)) {
    721875        // merge constant values into variable weights
    722876        var constB = ((ConstantTreeNode)b).Value;
    723         ((VariableTreeNode)a).Weight /= constB;
     877        ((VariableTreeNodeBase)a).Weight /= constB;
    724878        return a;
    725       } else if (IsVariable(a) && IsVariable(b) && AreSameVariable(a, b)) {
    726         // cancel variables
     879      } else if (IsFactor(a) && IsConstant(b)) {
     880        var factNode = a as FactorVariableTreeNode;
     881        var constNode = b as ConstantTreeNode;
     882        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => w / constNode.Value));
     883      } else if (IsBinFactor(a) && IsConstant(b)) {
     884        var factNode = a as BinaryFactorVariableTreeNode;
     885        var constNode = b as ConstantTreeNode;
     886        return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, factNode.Weight / constNode.Value);
     887      } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
     888        var node0 = a as FactorVariableTreeNode;
     889        var node1 = b as FactorVariableTreeNode;
     890        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u / v));
     891      } else if (IsFactor(a) && IsBinFactor(b) && ((IVariableTreeNode)a).VariableName == ((IVariableTreeNode)b).VariableName) {
     892        var node0 = a as FactorVariableTreeNode;
     893        var node1 = b as BinaryFactorVariableTreeNode;
     894        var varValues = node0.Symbol.GetVariableValues(node0.VariableName).ToArray();
     895        var wi = Array.IndexOf(varValues, node1.VariableValue);
     896        if (wi < 0) throw new ArgumentException();
     897        var newWeighs = new double[varValues.Length];
     898        node0.Weights.CopyTo(newWeighs, 0);
     899        for (int i = 0; i < newWeighs.Length; i++)
     900          if (wi == i) newWeighs[i] /= node1.Weight;
     901          else newWeighs[i] /= 0.0;
     902        return MakeFactor(node0.Symbol, node0.VariableName, newWeighs);
     903      } else if (IsFactor(a)) {
     904        return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
     905      } else if (IsVariableBase(a) && IsVariableBase(b) && AreSameTypeAndVariable(a, b) && !IsBinFactor(b)) {
     906        // cancel variables (not allowed for bin factors because of division by zero)
    727907        var aVar = a as VariableTreeNode;
    728908        var bVar = b as VariableTreeNode;
     
    731911        return a.Subtrees
    732912          .Select(x => GetSimplifiedTree(x))
    733          .Select(x => MakeFraction(x, b))
    734          .Aggregate((c, d) => MakeSum(c, d));
     913          .Select(x => MakeFraction(x, GetSimplifiedTree(b)))
     914          .Aggregate((c, d) => MakeSum(c, d));
    735915      } else if (IsMultiplication(a) && IsConstant(b)) {
    736916        return MakeProduct(a, Invert(b));
     
    767947        // x + 0 => x
    768948        return a;
     949      } else if (IsFactor(a) && IsConstant(b)) {
     950        var factNode = a as FactorVariableTreeNode;
     951        var constNode = b as ConstantTreeNode;
     952        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select((w) => w + constNode.Value));
     953      } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
     954        var node0 = a as FactorVariableTreeNode;
     955        var node1 = b as FactorVariableTreeNode;
     956        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u + v));
     957      } else if (IsBinFactor(a) && IsFactor(b)) {
     958        return MakeSum(b, a);
     959      } else if (IsFactor(a) && IsBinFactor(b) &&
     960        ((IVariableTreeNode)a).VariableName == ((IVariableTreeNode)b).VariableName) {
     961        var node0 = a as FactorVariableTreeNode;
     962        var node1 = b as BinaryFactorVariableTreeNode;
     963        var varValues = node0.Symbol.GetVariableValues(node0.VariableName).ToArray();
     964        var wi = Array.IndexOf(varValues, node1.VariableValue);
     965        if (wi < 0) throw new ArgumentException();
     966        var newWeighs = new double[varValues.Length];
     967        node0.Weights.CopyTo(newWeighs, 0);
     968        newWeighs[wi] += node1.Weight;
     969        return MakeFactor(node0.Symbol, node0.VariableName, newWeighs);
    769970      } else if (IsAddition(a) && IsAddition(b)) {
    770971        // merge additions
     
    8291030
    8301031    // makes sure variable symbols in sums are combined
    831     // possible improvement: combine sums of products where the products only reference the same variable
    8321032    private void MergeVariablesInSum(ISymbolicExpressionTreeNode sum) {
    8331033      var subtrees = new List<ISymbolicExpressionTreeNode>(sum.Subtrees);
    8341034      while (sum.Subtrees.Any()) sum.RemoveSubtree(0);
    835       var groupedVarNodes = from node in subtrees.OfType<VariableTreeNode>()
    836                             let lag = (node is LaggedVariableTreeNode) ? ((LaggedVariableTreeNode)node).Lag : 0
    837                             group node by node.VariableName + lag into g
     1035      var groupedVarNodes = from node in subtrees.OfType<IVariableTreeNode>()
     1036                            where node.SubtreeCount == 0
     1037                            group node by GroupId(node) into g
    8381038                            select g;
    839       var unchangedSubtrees = subtrees.Where(t => !(t is VariableTreeNode));
     1039      var constant = (from node in subtrees.OfType<ConstantTreeNode>()
     1040                      select node.Value).DefaultIfEmpty(0.0).Sum();
     1041      var unchangedSubtrees = subtrees.Where(t => t.SubtreeCount > 0 || !(t is IVariableTreeNode) && !(t is ConstantTreeNode));
    8401042
    8411043      foreach (var variableNodeGroup in groupedVarNodes) {
    842         var weightSum = variableNodeGroup.Select(t => t.Weight).Sum();
    843         var representative = variableNodeGroup.First();
    844         representative.Weight = weightSum;
    845         sum.AddSubtree(representative);
     1044        var firstNode = variableNodeGroup.First();
     1045        if (firstNode is VariableTreeNodeBase) {
     1046          var representative = firstNode as VariableTreeNodeBase;
     1047          var weightSum = variableNodeGroup.Cast<VariableTreeNodeBase>().Select(t => t.Weight).Sum();
     1048          representative.Weight = weightSum;
     1049          sum.AddSubtree(representative);
     1050        } else if (firstNode is FactorVariableTreeNode) {
     1051          var representative = firstNode as FactorVariableTreeNode;
     1052          foreach (var node in variableNodeGroup.Skip(1).Cast<FactorVariableTreeNode>()) {
     1053            for (int j = 0; j < representative.Weights.Length; j++) {
     1054              representative.Weights[j] += node.Weights[j];
     1055            }
     1056          }
     1057          for (int j = 0; j < representative.Weights.Length; j++) {
     1058            representative.Weights[j] += constant;
     1059          }
     1060          sum.AddSubtree(representative);
     1061        }
    8461062      }
    8471063      foreach (var unchangedSubtree in unchangedSubtrees)
    8481064        sum.AddSubtree(unchangedSubtree);
     1065      if (!constant.IsAlmost(0.0)) {
     1066        sum.AddSubtree(MakeConstant(constant));
     1067      }
     1068    }
     1069
     1070    // nodes referencing variables can be grouped if they have
     1071    private string GroupId(IVariableTreeNode node) {
     1072      var binaryFactorNode = node as BinaryFactorVariableTreeNode;
     1073      var factorNode = node as FactorVariableTreeNode;
     1074      var variableNode = node as VariableTreeNode;
     1075      var laggedVarNode = node as LaggedVariableTreeNode;
     1076      if (variableNode != null) {
     1077        return "var " + variableNode.VariableName;
     1078      } else if (binaryFactorNode != null) {
     1079        return "binfactor " + binaryFactorNode.VariableName + " " + binaryFactorNode.VariableValue;
     1080      } else if (factorNode != null) {
     1081        return "factor " + factorNode.VariableName;
     1082      } else if (laggedVarNode != null) {
     1083        return "lagged " + laggedVarNode.VariableName + " " + laggedVarNode.Lag;
     1084      } else {
     1085        throw new NotSupportedException();
     1086      }
    8491087    }
    8501088
     
    8531091      if (IsConstant(a) && IsConstant(b)) {
    8541092        // fold constants
    855         ((ConstantTreeNode)a).Value *= ((ConstantTreeNode)b).Value;
    856         return a;
     1093        return MakeConstant(((ConstantTreeNode)a).Value * ((ConstantTreeNode)b).Value);
    8571094      } else if (IsConstant(a)) {
    8581095        // a * $ => $ * a
    8591096        return MakeProduct(b, a);
     1097      } else if (IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
     1098        var node0 = a as FactorVariableTreeNode;
     1099        var node1 = b as FactorVariableTreeNode;
     1100        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u * v));
     1101      } else if (IsBinFactor(a) && IsBinFactor(b) && AreSameTypeAndVariable(a, b)) {
     1102        var node0 = a as BinaryFactorVariableTreeNode;
     1103        var node1 = b as BinaryFactorVariableTreeNode;
     1104        return MakeBinFactor(node0.Symbol, node0.VariableName, node0.VariableValue, node0.Weight * node1.Weight);
     1105      } else if (IsFactor(a) && IsConstant(b)) {
     1106        var node0 = a as FactorVariableTreeNode;
     1107        var node1 = b as ConstantTreeNode;
     1108        return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Select(w => w * node1.Value));
     1109      } else if (IsBinFactor(a) && IsConstant(b)) {
     1110        var node0 = a as BinaryFactorVariableTreeNode;
     1111        var node1 = b as ConstantTreeNode;
     1112        return MakeBinFactor(node0.Symbol, node0.VariableName, node0.VariableValue, node0.Weight * node1.Value);
     1113      } else if (IsBinFactor(a) && IsFactor(b)) {
     1114        return MakeProduct(b, a);
     1115      } else if (IsFactor(a) && IsBinFactor(b) &&
     1116        ((IVariableTreeNode)a).VariableName == ((IVariableTreeNode)b).VariableName) {
     1117        var node0 = a as FactorVariableTreeNode;
     1118        var node1 = b as BinaryFactorVariableTreeNode;
     1119        var varValues = node0.Symbol.GetVariableValues(node0.VariableName).ToArray();
     1120        var wi = Array.IndexOf(varValues, node1.VariableValue);
     1121        if (wi < 0) throw new ArgumentException();
     1122        return MakeBinFactor(node1.Symbol, node1.VariableName, node1.VariableValue, node1.Weight * node0.Weights[wi]);
    8601123      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(1.0)) {
    8611124        // $ * 1.0 => $
    8621125        return a;
    863       } else if (IsConstant(b) && IsVariable(a)) {
     1126      } else if (IsConstant(b) && IsVariableBase(a)) {
    8641127        // multiply constants into variables weights
    865         ((VariableTreeNode)a).Weight *= ((ConstantTreeNode)b).Value;
     1128        ((VariableTreeNodeBase)a).Weight *= ((ConstantTreeNode)b).Value;
    8661129        return a;
    867       } else if (IsConstant(b) && IsAddition(a)) {
     1130      } else if (IsConstant(b) && IsAddition(a) ||
     1131          IsFactor(b) && IsAddition(a) ||
     1132          IsBinFactor(b) && IsAddition(a)) {
    8681133        // multiply constants into additions
    869         return a.Subtrees.Select(x => MakeProduct(x, b)).Aggregate((c, d) => MakeSum(c, d));
     1134        return a.Subtrees.Select(x => MakeProduct(GetSimplifiedTree(x), GetSimplifiedTree(b))).Aggregate((c, d) => MakeSum(c, d));
    8701135      } else if (IsDivision(a) && IsDivision(b)) {
    8711136        // (a1 / a2) * (b1 / b2) => (a1 * b1) / (a2 * b2)
     
    8881153      } else if (IsMultiplication(a)) {
    8891154        // a is already an multiplication => append b
    890         a.AddSubtree(b);
     1155        a.AddSubtree(GetSimplifiedTree(b));
    8911156        MergeVariablesAndConstantsInProduct(a);
    8921157        return a;
     
    8991164      }
    9001165    }
     1166
    9011167    #endregion
    9021168
    903 
    9041169    #region helper functions
     1170
    9051171    private bool ContainsVariableCondition(ISymbolicExpressionTreeNode node) {
    9061172      if (node.Symbol is VariableCondition) return true;
     
    9321198    }
    9331199
    934     private bool AreSameVariable(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
    935       var aLaggedVar = a as LaggedVariableTreeNode;
    936       var bLaggedVar = b as LaggedVariableTreeNode;
    937       if (aLaggedVar != null && bLaggedVar != null) {
    938         return aLaggedVar.VariableName == bLaggedVar.VariableName &&
    939           aLaggedVar.Lag == bLaggedVar.Lag;
    940       }
    941       var aVar = a as VariableTreeNode;
    942       var bVar = b as VariableTreeNode;
    943       if (aVar != null && bVar != null) {
    944         return aVar.VariableName == bVar.VariableName;
    945       }
    946       return false;
     1200    private bool AreSameTypeAndVariable(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
     1201      return GroupId((IVariableTreeNode)a) == GroupId((IVariableTreeNode)b);
    9471202    }
    9481203
     
    9511206      var subtrees = new List<ISymbolicExpressionTreeNode>(prod.Subtrees);
    9521207      while (prod.Subtrees.Any()) prod.RemoveSubtree(0);
    953       var groupedVarNodes = from node in subtrees.OfType<VariableTreeNode>()
    954                             let lag = (node is LaggedVariableTreeNode) ? ((LaggedVariableTreeNode)node).Lag : 0
    955                             group node by node.VariableName + lag into g
     1208      var groupedVarNodes = from node in subtrees.OfType<IVariableTreeNode>()
     1209                            where node.SubtreeCount == 0
     1210                            group node by GroupId(node) into g
    9561211                            orderby g.Count()
    9571212                            select g;
    958       var constantProduct = (from node in subtrees.OfType<VariableTreeNode>()
     1213      var constantProduct = (from node in subtrees.OfType<VariableTreeNodeBase>()
    9591214                             select node.Weight)
    960                             .Concat(from node in subtrees.OfType<ConstantTreeNode>()
    961                                     select node.Value)
    962                             .DefaultIfEmpty(1.0)
    963                             .Aggregate((c1, c2) => c1 * c2);
     1215        .Concat(from node in subtrees.OfType<ConstantTreeNode>()
     1216                select node.Value)
     1217        .DefaultIfEmpty(1.0)
     1218        .Aggregate((c1, c2) => c1 * c2);
    9641219
    9651220      var unchangedSubtrees = from tree in subtrees
    966                               where !(tree is VariableTreeNode)
    967                               where !(tree is ConstantTreeNode)
     1221                              where tree.SubtreeCount > 0 || !(tree is IVariableTreeNode) && !(tree is ConstantTreeNode)
    9681222                              select tree;
    9691223
    9701224      foreach (var variableNodeGroup in groupedVarNodes) {
    971         var representative = variableNodeGroup.First();
    972         representative.Weight = 1.0;
    973         if (variableNodeGroup.Count() > 1) {
    974           var poly = mulSymbol.CreateTreeNode();
    975           for (int p = 0; p < variableNodeGroup.Count(); p++) {
    976             poly.AddSubtree((ISymbolicExpressionTreeNode)representative.Clone());
     1225        var firstNode = variableNodeGroup.First();
     1226        if (firstNode is VariableTreeNodeBase) {
     1227          var representative = (VariableTreeNodeBase)firstNode;
     1228          representative.Weight = 1.0;
     1229          if (variableNodeGroup.Count() > 1) {
     1230            var poly = mulSymbol.CreateTreeNode();
     1231            for (int p = 0; p < variableNodeGroup.Count(); p++) {
     1232              poly.AddSubtree((ISymbolicExpressionTreeNode)representative.Clone());
     1233            }
     1234            prod.AddSubtree(poly);
     1235          } else {
     1236            prod.AddSubtree(representative);
    9771237          }
    978           prod.AddSubtree(poly);
    979         } else {
     1238        } else if (firstNode is FactorVariableTreeNode) {
     1239          var representative = (FactorVariableTreeNode)firstNode;
     1240          foreach (var node in variableNodeGroup.Skip(1).Cast<FactorVariableTreeNode>()) {
     1241            for (int j = 0; j < representative.Weights.Length; j++) {
     1242              representative.Weights[j] *= node.Weights[j];
     1243            }
     1244          }
     1245          for (int j = 0; j < representative.Weights.Length; j++) {
     1246            representative.Weights[j] *= constantProduct;
     1247          }
     1248          constantProduct = 1.0;
     1249          // if the product already contains a factor it is not necessary to multiply a constant below
    9801250          prod.AddSubtree(representative);
    9811251        }
     
    9931263    /// <summary>
    9941264    /// x => x * -1
    995     /// Doesn't create new trees and manipulates x
     1265    /// Is only used in cases where it is not necessary to create new tree nodes. Manipulates x directly.
    9961266    /// </summary>
    9971267    /// <param name="x"></param>
     
    10001270      if (IsConstant(x)) {
    10011271        ((ConstantTreeNode)x).Value *= -1;
    1002       } else if (IsVariable(x)) {
    1003         var variableTree = (VariableTreeNode)x;
     1272      } else if (IsVariableBase(x)) {
     1273        var variableTree = (VariableTreeNodeBase)x;
    10041274        variableTree.Weight *= -1.0;
     1275      } else if (IsFactor(x)) {
     1276        var factorNode = (FactorVariableTreeNode)x;
     1277        for (int i = 0; i < factorNode.Weights.Length; i++) factorNode.Weights[i] *= -1;
     1278      } else if (IsBinFactor(x)) {
     1279        var factorNode = (BinaryFactorVariableTreeNode)x;
     1280        factorNode.Weight *= -1;
    10051281      } else if (IsAddition(x)) {
    10061282        // (x0 + x1 + .. + xn) * -1 => (-x0 + -x1 + .. + -xn)       
     
    10241300    /// <summary>
    10251301    /// x => 1/x
    1026     /// Doesn't create new trees and manipulates x
     1302    /// Must create new tree nodes
    10271303    /// </summary>
    10281304    /// <param name="x"></param>
     
    10311307      if (IsConstant(x)) {
    10321308        return MakeConstant(1.0 / ((ConstantTreeNode)x).Value);
     1309      } else if (IsFactor(x)) {
     1310        var factorNode = (FactorVariableTreeNode)x;
     1311        return MakeFactor(factorNode.Symbol, factorNode.VariableName, factorNode.Weights.Select(w => 1.0 / w));
    10331312      } else if (IsDivision(x)) {
    10341313        return MakeFraction(x.GetSubtree(1), x.GetSubtree(0));
     
    10451324    }
    10461325
    1047     private ISymbolicExpressionTreeNode MakeVariable(double weight, string name) {
    1048       var tree = (VariableTreeNode)varSymbol.CreateTreeNode();
     1326    private ISymbolicExpressionTreeNode MakeFactor(FactorVariable sy, string variableName, IEnumerable<double> weights) {
     1327      var tree = (FactorVariableTreeNode)sy.CreateTreeNode();
     1328      tree.VariableName = variableName;
     1329      tree.Weights = weights.ToArray();
     1330      return tree;
     1331    }
     1332    private ISymbolicExpressionTreeNode MakeBinFactor(BinaryFactorVariable sy, string variableName, string variableValue, double weight) {
     1333      var tree = (BinaryFactorVariableTreeNode)sy.CreateTreeNode();
     1334      tree.VariableName = variableName;
     1335      tree.VariableValue = variableValue;
    10491336      tree.Weight = weight;
    1050       tree.VariableName = name;
    10511337      return tree;
    10521338    }
     1339
     1340
    10531341    #endregion
    10541342  }
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisModel.cs

    r14186 r15131  
    6363        var variables =
    6464          SymbolicExpressionTree.IterateNodesPrefix()
    65             .OfType<VariableTreeNode>()
     65            .OfType<IVariableTreeNode>()
    6666            .Select(x => x.VariableName)
    6767            .Distinct();
    68         var variableConditions = SymbolicExpressionTree.IterateNodesPrefix()
    69           .OfType<VariableConditionTreeNode>().Select(x => x.VariableName).Distinct();
    7068
    71         return variables.Union(variableConditions).OrderBy(x => x);
     69        return variables.OrderBy(x => x);
    7270      }
    7371    }
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisModelComplexityCalculator.cs

    r14186 r15131  
    3939            return 1;
    4040          }
    41         case OpCodes.Variable: {
     41        case OpCodes.Variable:
     42        case OpCodes.BinaryFactorVariable:
     43        case OpCodes.FactorVariable: {
    4244            return 2;
    4345          }
    44         case OpCodes.Add: 
     46        case OpCodes.Add:
    4547        case OpCodes.Sub: {
    4648            double complexity = 0;
     
    5052            return complexity;
    5153          }
    52         case OpCodes.Mul: 
     54        case OpCodes.Mul:
    5355        case OpCodes.Div: {
    5456            double complexity = 1;
     
    6062          }
    6163        case OpCodes.Sin:
    62         case OpCodes.Cos: 
     64        case OpCodes.Cos:
    6365        case OpCodes.Tan:
    64         case OpCodes.Exp: 
     66        case OpCodes.Exp:
    6567        case OpCodes.Log: {
    6668            double complexity = CalculateComplexity(node.GetSubtree(0));
     
    7577            return complexity * complexity * complexity;
    7678          }
    77         case OpCodes.Power:         
     79        case OpCodes.Power:
    7880        case OpCodes.Root: {
    7981            double complexity = CalculateComplexity(node.GetSubtree(0));
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisProblem.cs

    r14186 r15131  
    208208
    209209    protected virtual void UpdateGrammar() {
    210       SymbolicExpressionTreeGrammar.MaximumFunctionArguments = MaximumFunctionArguments.Value;
    211       SymbolicExpressionTreeGrammar.MaximumFunctionDefinitions = MaximumFunctionDefinitions.Value;
    212       foreach (var varSymbol in SymbolicExpressionTreeGrammar.Symbols.OfType<HeuristicLab.Problems.DataAnalysis.Symbolic.Variable>()) {
     210      var problemData = ProblemData;
     211      var ds = problemData.Dataset;
     212      var grammar = SymbolicExpressionTreeGrammar;
     213      grammar.MaximumFunctionArguments = MaximumFunctionArguments.Value;
     214      grammar.MaximumFunctionDefinitions = MaximumFunctionDefinitions.Value;
     215      foreach (var varSymbol in grammar.Symbols.OfType<HeuristicLab.Problems.DataAnalysis.Symbolic.VariableBase>()) {
    213216        if (!varSymbol.Fixed) {
    214           varSymbol.AllVariableNames = ProblemData.InputVariables.Select(x => x.Value);
    215           varSymbol.VariableNames = ProblemData.AllowedInputVariables;
     217          varSymbol.AllVariableNames = problemData.InputVariables.Select(x => x.Value).Where(x => ds.VariableHasType<double>(x));
     218          varSymbol.VariableNames = problemData.AllowedInputVariables.Where(x => ds.VariableHasType<double>(x));
    216219        }
    217220      }
    218       foreach (var varSymbol in SymbolicExpressionTreeGrammar.Symbols.OfType<HeuristicLab.Problems.DataAnalysis.Symbolic.VariableCondition>()) {
    219         if (!varSymbol.Fixed) {
    220           varSymbol.AllVariableNames = ProblemData.InputVariables.Select(x => x.Value);
    221           varSymbol.VariableNames = ProblemData.AllowedInputVariables;
     221      foreach (var factorSymbol in grammar.Symbols.OfType<BinaryFactorVariable>()) {
     222        if (!factorSymbol.Fixed) {
     223          factorSymbol.AllVariableNames = problemData.InputVariables.Select(x => x.Value).Where(x => ds.VariableHasType<string>(x));
     224          factorSymbol.VariableNames = problemData.AllowedInputVariables.Where(x => ds.VariableHasType<string>(x));
     225          factorSymbol.VariableValues = factorSymbol.VariableNames
     226            .ToDictionary(varName => varName, varName => ds.GetStringValues(varName).Distinct().ToList());
     227        }
     228      }
     229      foreach (var factorSymbol in grammar.Symbols.OfType<FactorVariable>()) {
     230        if (!factorSymbol.Fixed) {
     231          factorSymbol.AllVariableNames = problemData.InputVariables.Select(x => x.Value).Where(x => ds.VariableHasType<string>(x));
     232          factorSymbol.VariableNames = problemData.AllowedInputVariables.Where(x => ds.VariableHasType<string>(x));
     233          factorSymbol.VariableValues = factorSymbol.VariableNames
     234            .ToDictionary(varName => varName,
     235            varName => ds.GetStringValues(varName).Distinct()
     236            .Select((n, i) => Tuple.Create(n, i))
     237            .ToDictionary(tup => tup.Item1, tup => tup.Item2));
    222238        }
    223239      }
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisSingleObjectiveProblem.cs

    r14186 r15131  
    7373    }
    7474
    75     public SymbolicDataAnalysisSingleObjectiveProblem(T problemData, U evaluator, V solutionCreator)
     75    protected SymbolicDataAnalysisSingleObjectiveProblem(T problemData, U evaluator, V solutionCreator)
    7676      : base(problemData, evaluator, solutionCreator) {
    7777      Parameters.Add(new FixedValueParameter<BoolValue>(MaximizationParameterName, "Set to false if the problem should be minimized."));
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisSolutionImpactValuesCalculator.cs

    r14186 r15131  
    2121
    2222using System.Collections.Generic;
     23using System.Linq;
    2324using HeuristicLab.Common;
    2425using HeuristicLab.Core;
     
    3637    [StorableConstructor]
    3738    protected SymbolicDataAnalysisSolutionImpactValuesCalculator(bool deserializing) : base(deserializing) { }
    38     public abstract double CalculateReplacementValue(ISymbolicDataAnalysisModel model, ISymbolicExpressionTreeNode node, IDataAnalysisProblemData problemData, IEnumerable<int> rows);
    39     public abstract double CalculateImpactValue(ISymbolicDataAnalysisModel model, ISymbolicExpressionTreeNode node, IDataAnalysisProblemData problemData, IEnumerable<int> rows, double qualityForImpactsCalculation = double.NaN);
    4039    public abstract void CalculateImpactAndReplacementValues(ISymbolicDataAnalysisModel model, ISymbolicExpressionTreeNode node, IDataAnalysisProblemData problemData, IEnumerable<int> rows, out double impactValue, out double replacementValue, out double newQualityForImpactsCalculation, double qualityForImpactsCalculation = double.NaN);
    4140
    42     protected static double CalculateReplacementValue(ISymbolicExpressionTreeNode node, ISymbolicExpressionTree sourceTree, ISymbolicDataAnalysisExpressionTreeInterpreter interpreter,
     41    protected IEnumerable<double> CalculateReplacementValues(ISymbolicExpressionTreeNode node, ISymbolicExpressionTree sourceTree, ISymbolicDataAnalysisExpressionTreeInterpreter interpreter,
    4342      IDataset dataset, IEnumerable<int> rows) {
    4443      //optimization: constant nodes return always the same value
    4544      ConstantTreeNode constantNode = node as ConstantTreeNode;
    46       if (constantNode != null) return constantNode.Value;
     45      BinaryFactorVariableTreeNode binaryFactorNode = node as BinaryFactorVariableTreeNode;
     46      FactorVariableTreeNode factorNode = node as FactorVariableTreeNode;
     47      if (constantNode != null) {
     48        yield return constantNode.Value;
     49      } else if (binaryFactorNode != null) {
     50        // valid replacements are either all off or all on
     51        yield return 0;
     52        yield return 1;
     53      } else if (factorNode != null) {
     54        foreach (var w in factorNode.Weights) yield return w;
     55        yield return 0.0;
     56      } else {
     57        var rootSymbol = new ProgramRootSymbol().CreateTreeNode();
     58        var startSymbol = new StartSymbol().CreateTreeNode();
     59        rootSymbol.AddSubtree(startSymbol);
     60        startSymbol.AddSubtree((ISymbolicExpressionTreeNode)node.Clone());
    4761
    48       var rootSymbol = new ProgramRootSymbol().CreateTreeNode();
    49       var startSymbol = new StartSymbol().CreateTreeNode();
    50       rootSymbol.AddSubtree(startSymbol);
    51       startSymbol.AddSubtree((ISymbolicExpressionTreeNode)node.Clone());
    52 
    53       var tempTree = new SymbolicExpressionTree(rootSymbol);
    54       // clone ADFs of source tree
    55       for (int i = 1; i < sourceTree.Root.SubtreeCount; i++) {
    56         tempTree.Root.AddSubtree((ISymbolicExpressionTreeNode)sourceTree.Root.GetSubtree(i).Clone());
     62        var tempTree = new SymbolicExpressionTree(rootSymbol);
     63        // clone ADFs of source tree
     64        for (int i = 1; i < sourceTree.Root.SubtreeCount; i++) {
     65          tempTree.Root.AddSubtree((ISymbolicExpressionTreeNode)sourceTree.Root.GetSubtree(i).Clone());
     66        }
     67        yield return interpreter.GetSymbolicExpressionTreeValues(tempTree, dataset, rows).Median();
     68        yield return interpreter.GetSymbolicExpressionTreeValues(tempTree, dataset, rows).Average(); // TODO perf
    5769      }
    58       return interpreter.GetSymbolicExpressionTreeValues(tempTree, dataset, rows).Median();
    5970    }
    6071  }
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/LaggedVariable.cs

    r14186 r15131  
    2727  [StorableClass]
    2828  [Item("LaggedVariable", "Represents a variable value with a time offset.")]
    29   public class LaggedVariable : Variable {
     29  public class LaggedVariable : VariableBase {
    3030    [Storable]
    3131    private int minLag;
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/LaggedVariableTreeNode.cs

    r14186 r15131  
    2626namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
    2727  [StorableClass]
    28   public sealed class LaggedVariableTreeNode : VariableTreeNode, ILaggedTreeNode {
     28  public sealed class LaggedVariableTreeNode : VariableTreeNodeBase, ILaggedTreeNode {
    2929    public new LaggedVariable Symbol {
    3030      get { return (LaggedVariable)base.Symbol; }
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/Variable.cs

    r14186 r15131  
    2929  [StorableClass]
    3030  [Item("Variable", "Represents a variable value.")]
    31   public class Variable : Symbol {
    32     #region Properties
    33     [Storable]
    34     private double weightMu;
    35     public double WeightMu {
    36       get { return weightMu; }
    37       set {
    38         if (value != weightMu) {
    39           weightMu = value;
    40           OnChanged(EventArgs.Empty);
    41         }
    42       }
    43     }
    44     [Storable]
    45     private double weightSigma;
    46     public double WeightSigma {
    47       get { return weightSigma; }
    48       set {
    49         if (weightSigma < 0.0) throw new ArgumentException("Negative sigma is not allowed.");
    50         if (value != weightSigma) {
    51           weightSigma = value;
    52           OnChanged(EventArgs.Empty);
    53         }
    54       }
    55     }
    56     [Storable]
    57     private double weightManipulatorMu;
    58     public double WeightManipulatorMu {
    59       get { return weightManipulatorMu; }
    60       set {
    61         if (value != weightManipulatorMu) {
    62           weightManipulatorMu = value;
    63           OnChanged(EventArgs.Empty);
    64         }
    65       }
    66     }
    67     [Storable]
    68     private double weightManipulatorSigma;
    69     public double WeightManipulatorSigma {
    70       get { return weightManipulatorSigma; }
    71       set {
    72         if (weightManipulatorSigma < 0.0) throw new ArgumentException("Negative sigma is not allowed.");
    73         if (value != weightManipulatorSigma) {
    74           weightManipulatorSigma = value;
    75           OnChanged(EventArgs.Empty);
    76         }
    77       }
    78     }
    79     [Storable(DefaultValue = 0.0)]
    80     private double multiplicativeWeightManipulatorSigma;
    81     public double MultiplicativeWeightManipulatorSigma {
    82       get { return multiplicativeWeightManipulatorSigma; }
    83       set {
    84         if (multiplicativeWeightManipulatorSigma < 0.0) throw new ArgumentException("Negative sigma is not allowed.");
    85         if (value != multiplicativeWeightManipulatorSigma) {
    86           multiplicativeWeightManipulatorSigma = value;
    87           OnChanged(EventArgs.Empty);
    88         }
    89       }
    90     }
    91     private List<string> variableNames;
    92     [Storable]
    93     public IEnumerable<string> VariableNames {
    94       get { return variableNames; }
    95       set {
    96         if (value == null) throw new ArgumentNullException();
    97         variableNames.Clear();
    98         variableNames.AddRange(value);
    99         OnChanged(EventArgs.Empty);
    100       }
    101     }
    102 
    103     private List<string> allVariableNames;
    104     [Storable]
    105     public IEnumerable<string> AllVariableNames {
    106       get { return allVariableNames; }
    107       set {
    108         if (value == null) throw new ArgumentNullException();
    109         allVariableNames.Clear();
    110         allVariableNames.AddRange(value);
    111       }
    112     }
    113 
    114     public override bool Enabled {
    115       get {
    116         if (variableNames.Count == 0) return false;
    117         return base.Enabled;
    118       }
    119       set {
    120         if (variableNames.Count == 0) base.Enabled = false;
    121         else base.Enabled = value;
    122       }
    123     }
    124 
    125     private const int minimumArity = 0;
    126     private const int maximumArity = 0;
    127 
    128     public override int MinimumArity {
    129       get { return minimumArity; }
    130     }
    131     public override int MaximumArity {
    132       get { return maximumArity; }
    133     }
    134     #endregion
    135 
    136     [StorableHook(HookType.AfterDeserialization)]
    137     private void AfterDeserialization() {
    138       if (allVariableNames == null || (allVariableNames.Count == 0 && variableNames.Count > 0)) {
    139         allVariableNames = variableNames;
    140       }
    141     }
     31  public class Variable : VariableBase {
    14232
    14333    [StorableConstructor]
    14434    protected Variable(bool deserializing)
    14535      : base(deserializing) {
    146       variableNames = new List<string>();
    147       allVariableNames = new List<string>();
    14836    }
    14937    protected Variable(Variable original, Cloner cloner)
    15038      : base(original, cloner) {
    151       weightMu = original.weightMu;
    152       weightSigma = original.weightSigma;
    153       variableNames = new List<string>(original.variableNames);
    154       allVariableNames = new List<string>(original.allVariableNames);
    155       weightManipulatorMu = original.weightManipulatorMu;
    156       weightManipulatorSigma = original.weightManipulatorSigma;
    157       multiplicativeWeightManipulatorSigma = original.multiplicativeWeightManipulatorSigma;
    15839    }
    159     public Variable() : this("Variable", "Represents a variable value.") { }
    160     public Variable(string name, string description)
    161       : base(name, description) {
    162       weightMu = 1.0;
    163       weightSigma = 1.0;
    164       weightManipulatorMu = 0.0;
    165       weightManipulatorSigma = 0.05;
    166       multiplicativeWeightManipulatorSigma = 0.03;
    167       variableNames = new List<string>();
    168       allVariableNames = new List<string>();
    169     }
     40    public Variable() : base("Variable", "Represents a variable value.") { }
     41    public Variable(string name, string description) : base(name, description) { }
    17042
    17143    public override ISymbolicExpressionTreeNode CreateTreeNode() {
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableCondition.cs

    r15127 r15131  
    3030  [StorableClass]
    3131  [Item("Variable Condition", "Represents a condition that tests a given variable against a specified threshold.")]
    32   public sealed class VariableCondition : Symbol {
     32  public sealed class VariableCondition : Symbol, IVariableSymbol {
    3333    #region properties
    3434    [Storable]
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableConditionTreeNode.cs

    r15127 r15131  
    2929namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
    3030  [StorableClass]
    31   public sealed class VariableConditionTreeNode : SymbolicExpressionTreeNode {
     31  public sealed class VariableConditionTreeNode : SymbolicExpressionTreeNode, IVariableTreeNode {
    3232    #region properties
    3333    public new VariableCondition Symbol {
  • stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableTreeNode.cs

    r14186 r15131  
    2121
    2222using HeuristicLab.Common;
    23 using HeuristicLab.Core;
    24 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
    2523using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
    26 using HeuristicLab.Random;
    2724namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
    2825  [StorableClass]
    29   public class VariableTreeNode : SymbolicExpressionTreeTerminalNode {
     26  public sealed class VariableTreeNode : VariableTreeNodeBase {
    3027    public new Variable Symbol {
    3128      get { return (Variable)base.Symbol; }
    3229    }
    33     [Storable]
    34     private double weight;
    35     public double Weight {
    36       get { return weight; }
    37       set { weight = value; }
     30    [StorableConstructor]
     31    private VariableTreeNode(bool deserializing) : base(deserializing) { }
     32    private VariableTreeNode(VariableTreeNode original, Cloner cloner)
     33      : base(original, cloner) {
    3834    }
    39     [Storable]
    40     private string variableName;
    41     public string VariableName {
    42       get { return variableName; }
    43       set { variableName = value; }
    44     }
    45 
    46     [StorableConstructor]
    47     protected VariableTreeNode(bool deserializing) : base(deserializing) { }
    48     protected VariableTreeNode(VariableTreeNode original, Cloner cloner)
    49       : base(original, cloner) {
    50       weight = original.weight;
    51       variableName = original.variableName;
    52     }
    53     protected VariableTreeNode() { }
     35    private VariableTreeNode() { }
    5436    public VariableTreeNode(Variable variableSymbol) : base(variableSymbol) { }
    55 
    56     public override bool HasLocalParameters {
    57       get { return true; }
    58     }
    59 
    60     public override void ResetLocalParameters(IRandom random) {
    61       base.ResetLocalParameters(random);
    62       weight = NormalDistributedRandom.NextDouble(random, Symbol.WeightMu, Symbol.WeightSigma);
    63 
    64 #pragma warning disable 612, 618
    65       variableName = Symbol.VariableNames.SelectRandom(random);
    66 #pragma warning restore 612, 618
    67     }
    68 
    69     public override void ShakeLocalParameters(IRandom random, double shakingFactor) {
    70       base.ShakeLocalParameters(random, shakingFactor);
    71       // 50% additive & 50% multiplicative
    72       if (random.NextDouble() < 0) {
    73         double x = NormalDistributedRandom.NextDouble(random, Symbol.WeightManipulatorMu, Symbol.WeightManipulatorSigma);
    74         weight = weight + x * shakingFactor;
    75       } else {
    76         double x = NormalDistributedRandom.NextDouble(random, 1.0, Symbol.MultiplicativeWeightManipulatorSigma);
    77         weight = weight * x;
    78       }
    79 #pragma warning disable 612, 618
    80       variableName = Symbol.VariableNames.SelectRandom(random);
    81 #pragma warning restore 612, 618
    82     }
    8337
    8438    public override IDeepCloneable Clone(Cloner cloner) {
    8539      return new VariableTreeNode(this, cloner);
    8640    }
    87 
    88     public override string ToString() {
    89       if (weight.IsAlmost(1.0)) return variableName;
    90       else return weight.ToString("E4") + " " + variableName;
    91     }
    9241  }
    9342}
Note: See TracChangeset for help on using the changeset viewer.