private static void GetEditCost( IList <ITreeProgram <TOutput> > subProgs1, IList <ITreeProgram <TOutput> > subProgs2, ref uint idx1, ref uint idx2, ref uint curCost, ref uint totalCost) { totalCost++; var subProg1 = idx1 < subProgs1.Count ? subProgs1[(int)idx1] : null; var subProg2 = idx2 < subProgs2.Count ? subProgs2[(int)idx2] : null; // if programs are equal if (subProg1 != null && subProg2 != null && subProg1.Equals(subProg2)) { // just advance both indexes and adds total cost (cur cost remains the same) var remainder = subProg1.Length - 1u; idx1 += remainder; idx2 += remainder; totalCost += (subProg1 is WeightedVariable variable ? variable.Weight : subProg1.Length) - 1; return; } // check if one of the sub-programs is null or has no children if (subProg1 == null || subProg2 == null || subProg1.Input == null || subProg1.Input.Count == 0 || subProg2.Input == null || subProg2.Input.Count == 0) { // adds cost of adding / removing the null node curCost++; // advance the indexes of both sub-trees and adds cost of adding / removing remainder nodes if (subProg1 != null) { if (subProg1 is WeightedVariable variable) { // it was a swap: ignores cost of adding/removing nodes the original program's nodes totalCost += variable.Weight - 1; } else if (subProg1.Length > 1) { // normal, uncommon program, count cost of adding/removing its nodes var remainder1 = subProg1.Length - 1u; idx1 += remainder1; curCost += remainder1; totalCost += remainder1; } } if (subProg2 != null) { if (subProg2 is WeightedVariable variable) { // it was a swap: ignores cost of adding/removing nodes the original program's nodes totalCost += variable.Weight - 1; } else if (subProg2.Length > 1) { // normal, uncommon program, count cost of adding/removing its nodes var remainder2 = subProg2.Length - 1u; idx2 += remainder2; curCost += remainder2; totalCost += remainder2; } } return; } // both programs have children, compares type of function var sameNode = subProg1.IsLeaf() ? subProg2.IsLeaf() && subProg1.Equals(subProg2) : subProg1.GetType() == subProg2.GetType(); // adds transformation cost if (!sameNode) { curCost++; } var children1 = new List <ITreeProgram <TOutput> >(subProg1.Input); var children2 = new List <ITreeProgram <TOutput> >(subProg2.Input); // try to align children if one (or both) function are commutative if (subProg1 is ICommutativeTreeProgram <TOutput> ) { CollectionUtil.Align(children2, children1); } else if (subProg2 is ICommutativeTreeProgram <TOutput> ) { CollectionUtil.Align(children1, children2); } // iterate recursively through both sub-programs' children in parallel var maxNumChildren = Math.Max(children1.Count, children2.Count); for (var i = 0; i < maxNumChildren; i++) { // advances indexes if corresponding child exists var prevIdx1 = children1.Count > i ? idx1 + 1 : uint.MaxValue; var prevIdx2 = children2.Count > i ? idx2 + 1 : uint.MaxValue; GetEditCost(subProgs1, subProgs2, ref prevIdx1, ref prevIdx2, ref curCost, ref totalCost); // updates indexes based on search idx1 = prevIdx1 == uint.MaxValue ? idx1 : prevIdx1; idx2 = prevIdx2 == uint.MaxValue ? idx2 : prevIdx2; } }