From a07f93b0f8a04f98f0b4f7982f359bd4a0279875 Mon Sep 17 00:00:00 2001 From: glopesdev Date: Fri, 12 May 2023 17:42:28 +0100 Subject: [PATCH] Ensure successor edges follow topological sort --- .../ExpressionBuilderGraphDescriptor.cs | 24 +++++++++++-- .../ExpressionBuilderGraphExtensions.cs | 34 +++++++++++-------- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/Bonsai.Core/Expressions/ExpressionBuilderGraphDescriptor.cs b/Bonsai.Core/Expressions/ExpressionBuilderGraphDescriptor.cs index 39bef7d9d..118b41891 100644 --- a/Bonsai.Core/Expressions/ExpressionBuilderGraphDescriptor.cs +++ b/Bonsai.Core/Expressions/ExpressionBuilderGraphDescriptor.cs @@ -1,4 +1,5 @@ -using System.Collections.ObjectModel; +using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Xml.Serialization; namespace Bonsai.Expressions @@ -8,15 +9,32 @@ namespace Bonsai.Expressions /// public class ExpressionBuilderGraphDescriptor { + /// + /// Initializes a new instance of the class. + /// + public ExpressionBuilderGraphDescriptor() + { + Nodes = new Collection(); + Edges = new Collection(); + } + + internal ExpressionBuilderGraphDescriptor( + IList nodes, + IList edges) + { + Nodes = new Collection(nodes); + Edges = new Collection(edges); + } + /// /// Gets the collection of labels associated with each node in the expression builder graph. /// - public Collection Nodes { get; } = new Collection(); + public Collection Nodes { get; } /// /// Gets a collection of descriptors corresponding to each edge in the expression builder graph. /// [XmlArrayItem("Edge")] - public Collection Edges { get; } = new Collection(); + public Collection Edges { get; } } } diff --git a/Bonsai.Core/Expressions/ExpressionBuilderGraphExtensions.cs b/Bonsai.Core/Expressions/ExpressionBuilderGraphExtensions.cs index b5984440f..dd6257ce1 100644 --- a/Bonsai.Core/Expressions/ExpressionBuilderGraphExtensions.cs +++ b/Bonsai.Core/Expressions/ExpressionBuilderGraphExtensions.cs @@ -1249,26 +1249,32 @@ public static ExpressionBuilderGraphDescriptor ToDescriptor(this ExpressionBuild throw new ArgumentException("Cannot serialize a workflow with cyclical dependencies.", nameof(source)); } - var nodes = buildOrder.SelectMany(component => component).ToArray(); - var descriptor = new ExpressionBuilderGraphDescriptor(); + int index = 0; + var nodeMap = buildOrder + .SelectMany(component => component) + .ToDictionary(node => node, node => index++); - foreach (var node in nodes) - { - descriptor.Nodes.Add(node.Value); - } + var nodes = new List(nodeMap.Count); + nodes.AddRange(nodeMap.Keys.Select(node => node.Value)); - var from = 0; - foreach (var node in nodes) + var edges = new List(); + foreach (var entry in nodeMap) { - foreach (var successor in node.Successors) + var from = entry.Value; + foreach (var successor in entry.Key.Successors) { - var to = Array.IndexOf(nodes, successor.Target); - descriptor.Edges.Add(new ExpressionBuilderArgumentDescriptor(from, to, successor.Label.Name)); + var to = nodeMap[successor.Target]; + edges.Add(new ExpressionBuilderArgumentDescriptor(from, to, successor.Label.Name)); } - - from++; } - return descriptor; + + edges.Sort((x, y) => + { + var from = x.From.CompareTo(y.From); + if (from != 0) return from; + else return x.To.CompareTo(y.To); + }); + return new ExpressionBuilderGraphDescriptor(nodes, edges); } ///