Opened 3 years ago

Last modified 4 months ago

#2997 accepted defect

When using multi encoding in combination with several symbolic expression trees, only the grammar of the first used symbolic expression tree is used to generate syntax trees.

Reported by: rhanghof Owned by: mkommend
Priority: medium Milestone: HeuristicLab 3.3.17
Component: Encodings.SymbolicExpressionTreeEncoding Version:
Keywords: Cc: chaider, dpiringe

Description (last modified by rhanghof)

When using multi encoding in combination with several symbolic expression trees, only the grammar of the first used symbolic expression tree is used to generate syntax trees. The grammar for creating the syntax trees is stored in the Global Scope and cloned from the grammar of the first syntax tree in the encoding when first used. The setting of the cloned grammar in the global scope can be found in the method InstrumentedApply of the class SymbolicExpressionTreeCreator.
Due to the query if (ClonedSymbolicExpressionTreeGrammarParameter.ActualValue == null) it is only set the very first time. Thus it is not possible to set the grammar for another symbolic expression tree.

Attachments (2)

Genetic Algorithm (GA) - Syntax Expression Tree MultiEncoding sample.hl (153.7 KB) - added by rhanghof 3 years ago.
Syntax expression tree multi-encoding sample
Genetic Algorithm (GA) - Syntax Expression Tree MultiEncoding sample - update.hl (104.7 KB) - added by rhanghof 3 years ago.
Syntax expression tree multi-encoding sample

Download all attachments as: .zip

Change History (13)

comment:1 Changed 3 years ago by rhanghof

  • Component changed from Problems.DataAnalysis.Symbolic to Encodings.SymbolicExpressionTreeEncoding
  • Description modified (diff)

comment:2 Changed 3 years ago by mkommend

Please attach a minimal sample (multi-encoding with two symbolic expression tree encodings and vastly different grammars) that reproduces the issue for debugging purposes.

Last edited 3 years ago by mkommend (previous) (diff)

Changed 3 years ago by rhanghof

Syntax expression tree multi-encoding sample

comment:3 Changed 3 years ago by mkommend

Unfortunately the provided example cannot be loaded with a standard version of HL, because it uses a proprietary plugin HeuristicLab.Problems.Matlab.ModelLearning or HeuristicLab.Problems.Matlab.ModelLearning.Optimization and maybe even others.

comment:4 Changed 3 years ago by mkommend

  • Owner set to rhanghof
  • Status changed from new to assigned

Changed 3 years ago by rhanghof

Syntax expression tree multi-encoding sample

comment:5 Changed 3 years ago by gkronber

Here is another small example where I have just spotted the same bug. Trees for t2 also contain terminals x,y,z instead of a,b,c.

namespace HeuristicLab.Problems.Programmable {
  public class CompiledSingleObjectiveProblemDefinition : CompiledProblemDefinition, ISingleObjectiveProblemDefinition {
    public bool Maximization { get { return false; } }

    public override void Initialize() {
      var g1 = new SimpleSymbolicExpressionGrammar();
      var g2 = new SimpleSymbolicExpressionGrammar();
      g1.AddSymbols(new string[] {"max", "add"}, 2, 2);
      g1.AddTerminalSymbols(new string[] {"x", "y", "z"});
      g2.AddSymbols(new string[] {"max", "add"}, 2, 2);
      g2.AddTerminalSymbols(new string[] {"a", "b", "c"});
     
      Encoding = new MultiEncoding()
        .Add(new SymbolicExpressionTreeEncoding("t1", g1, 50, 12))
        .Add(new SymbolicExpressionTreeEncoding("t2", g2, 50, 12))
      ;
    }

    public double Evaluate(Individual individual, IRandom random) {
      var trees = individual.Values.Select(v => v.Value).OfType<ISymbolicExpressionTree>().ToArray();
      
      var numAs = 0;
      var numXs = 0;
      foreach(var n in trees[0].Root.IterateNodesPrefix()) {
        if(n.Symbol.Name == "x") numXs++;
        else if(n.Symbol.Name == "a") numAs++;
      }
      foreach(var n in trees[1].Root.IterateNodesPrefix()) {
        if(n.Symbol.Name == "x") numXs++;
        else if(n.Symbol.Name == "a") numAs++;
      }
      
      return numAs + numXs;
    }

    public void Analyze(Individual[] individuals, double[] qualities, ResultCollection results, IRandom random) { }
    
    public IEnumerable<Individual> GetNeighbors(Individual individual, IRandom random) {  return Enumerable.Empty<Individual>();  }
  }
}

comment:6 Changed 3 years ago by abeham

  • Version 3.3.15 deleted

comment:7 Changed 2 years ago by gkronber

  • Milestone changed from HeuristicLab 3.3.16 to HeuristicLab 3.3.17

comment:8 Changed 4 months ago by mkommend

  • Owner changed from rhanghof to mkommend
  • Status changed from assigned to accepted

comment:9 Changed 4 months ago by mkommend

  • Cc chaider dpiringe added

I have investigated this issue as it is a blocker for the correct development of #3136.

The reason for this faulty behavior is that during the first execution of any tree creator the used grammar is cloned and put in the global scope. From now on only this cloned grammar is used for tree creation. In the case of a multi-encoding the cloning is performed only once and the tree creators for the other encoding parts detect the cloned grammar and wrongly use the cloned grammar, which could be vastly different from the configured one.

The reason for this strange behavior is AFAIK to avoid grammar manipulations when the algorithm is paused. Currently the grammar is set to readonly before it is cloned, thus preventing any manipulation. The readonly flag is afterwards removed in the ClearState method of the grammar, which is an IStatefulItem.

comment:10 Changed 4 months ago by mkommend

IMHO the best solution is to remove this awkward and unusual cloning of grammars all together and work directly with the configured grammar object. Hence, we could also remove the IStatefulItem interface from grammars, which further simplifies the tree creation.

Additionally, the current behavior that tree creators use a cloned grammar is not consistent, because all other operators that require a grammar use the normal grammar or the one within the tree.

The only thing that does not work after the proposed changed is that grammar manipulations during algorithm execution (while it is in a paused state) is possible. However, this is a larger issue which affects all parameters of an algorithm / problem and should be tackled more generally. E.g. the GA's population size / manipulation rate / ... can all be modified during algorithm execution.

Last edited 4 months ago by mkommend (previous) (diff)

comment:11 Changed 4 months ago by mkommend

r18064: Simplified tree creator interface and removed cloning of grammars,

Note: See TracTickets for help on using tickets.