public async Task <UpdateResult> Recompile(Project gameProject, LoggerResult logger) { var result = new UpdateResult(logger); if (solution == null) { solution = gameProject.Solution; } // Detect new groups var gameProjectCompilation = await gameProject.GetCompilationAsync(); // Generate source dependency graph var sourceDependencyGraph = new SourceGroup(); // Make sure all vertices are added foreach (var syntaxTree in gameProjectCompilation.SyntaxTrees) { sourceDependencyGraph.AddVertex(syntaxTree); } foreach (var syntaxTree in gameProjectCompilation.SyntaxTrees) { var syntaxRoot = syntaxTree.GetRoot(); var semanticModel = gameProjectCompilation.GetSemanticModel(syntaxTree); var dependencies = new SourceDependencySyntaxVisitor(new HashSet <SyntaxTree>(gameProjectCompilation.SyntaxTrees), semanticModel).DefaultVisit(syntaxRoot); foreach (var dependency in dependencies) { sourceDependencyGraph.AddEdge(new SEdge <SyntaxTree>(syntaxTree, dependency)); } } // Generate strongly connected components for sources (group of sources that needs to be compiled together, and their dependencies) var stronglyConnected = sourceDependencyGraph.CondensateStronglyConnected <SyntaxTree, SEdge <SyntaxTree>, SourceGroup>(); var sortedConnectedGroups = stronglyConnected.TopologicalSort().ToArray(); var connectedGroups = ImmutableHashSet.Create(SourceGroupComparer.Default, sortedConnectedGroups); // Merge changes since previous time // 1. Tag obsolete groups (everything that don't match, and their dependencies) var groupsToUnload = new HashSet <SourceGroup>(SourceGroupComparer.Default); foreach (var sourceGroup in previousSortedConnectedGroups.Reverse()) { // Does this group needs reload? SourceGroup newSourceGroup; if (connectedGroups.TryGetValue(sourceGroup, out newSourceGroup)) { // Transfer project, as it can be reused newSourceGroup.Project = sourceGroup.Project; newSourceGroup.PE = sourceGroup.PE; newSourceGroup.PDB = sourceGroup.PDB; newSourceGroup.Assembly = sourceGroup.Assembly; } else { groupsToUnload.Add(sourceGroup); } // Mark dependencies if (groupsToUnload.Contains(sourceGroup)) { foreach (var test in previousStronglyConnected.InEdges(sourceGroup)) { groupsToUnload.Add(test.Source); } } } // Generate common InternalsVisibleTo attributes // TODO: Find more graceful solution var internalsVisibleToBuilder = new StringBuilder(); internalsVisibleToBuilder.Append("using System.Runtime.CompilerServices;"); for (int i = 0; i < 1000; i++) { internalsVisibleToBuilder.AppendFormat(@"[assembly: InternalsVisibleTo(""{0}.Part{1}"")]", gameProject.AssemblyName, i); } var internalsVisibleToSource = CSharpSyntaxTree.ParseText(internalsVisibleToBuilder.ToString(), null, "", Encoding.UTF8).GetText(); // 2. Compile assemblies foreach (var sourceGroup in sortedConnectedGroups.Reverse()) { // Check if it's either a new group, or one that has been unloaded if (!previousConnectedGroups.Contains(sourceGroup) || groupsToUnload.Contains(sourceGroup)) { var assemblyName = gameProject.AssemblyName + ".Part" + assemblyCounter++; // Create a project out of the source group var project = solution.AddProject(assemblyName, assemblyName, LanguageNames.CSharp) .WithMetadataReferences(gameProject.MetadataReferences) .WithProjectReferences(gameProject.AllProjectReferences) .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); // Add sources foreach (var syntaxTree in sourceGroup.Vertices) { project = project.AddDocument(syntaxTree.FilePath, syntaxTree.GetText()).Project; } // Add references to other sources foreach (var dependencySourceGroup in stronglyConnected.OutEdges(sourceGroup)) { project = project.AddProjectReference(new ProjectReference(dependencySourceGroup.Target.Project.Id)); } // Make internals visible to other assembly parts project = project.AddDocument("GeneratedInternalsVisibleTo", internalsVisibleToSource).Project; sourceGroup.Project = project; solution = project.Solution; var compilation = await project.GetCompilationAsync(); using (var peStream = new MemoryStream()) using (var pdbStream = new MemoryStream()) { var emitResult = compilation.Emit(peStream, pdbStream); result.Info($"Compiling assembly containing {sourceGroup}"); foreach (var diagnostic in emitResult.Diagnostics) { switch (diagnostic.Severity) { case DiagnosticSeverity.Error: result.Error(diagnostic.GetMessage()); break; case DiagnosticSeverity.Warning: result.Warning(diagnostic.GetMessage()); break; case DiagnosticSeverity.Info: result.Info(diagnostic.GetMessage()); break; } } if (!emitResult.Success) { result.Error($"Error compiling assembly containing {sourceGroup}"); break; } // Load csproj to evaluate assembly processor parameters var msbuildProject = await Task.Run(() => VSProjectHelper.LoadProject(gameProject.FilePath)); if (msbuildProject.GetPropertyValue("StrideAssemblyProcessor") == "true") { var referenceBuild = await Task.Run(() => VSProjectHelper.CompileProjectAssemblyAsync(null, gameProject.FilePath, result, "ResolveReferences", flags: Microsoft.Build.Execution.BuildRequestDataFlags.ProvideProjectStateAfterBuild)); if (referenceBuild == null) { result.Error("Could not properly run ResolveAssemblyReferences"); break; } var referenceBuildResult = await referenceBuild.BuildTask; if (referenceBuild.IsCanceled || result.HasErrors) { break; } var assemblyProcessorParameters = "--parameter-key --auto-module-initializer --serialization"; var assemblyProcessorApp = AssemblyProcessorProgram.CreateAssemblyProcessorApp(SplitCommandLine(assemblyProcessorParameters).ToArray(), new LoggerAssemblyProcessorWrapper(result)); foreach (var referencePath in referenceBuildResult.ProjectStateAfterBuild.Items.Where(x => x.ItemType == "ReferencePath")) { assemblyProcessorApp.References.Add(referencePath.EvaluatedInclude); if (referencePath.EvaluatedInclude.EndsWith("Stride.SpriteStudio.Runtime.dll")) //todo hard-coded! needs to go when plug in system is in { assemblyProcessorApp.ReferencesToAdd.Add(referencePath.EvaluatedInclude); } else if (referencePath.EvaluatedInclude.EndsWith("Stride.Physics.dll")) //todo hard-coded! needs to go when plug in system is in { assemblyProcessorApp.ReferencesToAdd.Add(referencePath.EvaluatedInclude); } else if (referencePath.EvaluatedInclude.EndsWith("Stride.Particles.dll")) //todo hard-coded! needs to go when plug in system is in { assemblyProcessorApp.ReferencesToAdd.Add(referencePath.EvaluatedInclude); } else if (referencePath.EvaluatedInclude.EndsWith("Stride.Native.dll")) //todo hard-coded! needs to go when plug in system is in { assemblyProcessorApp.ReferencesToAdd.Add(referencePath.EvaluatedInclude); } else if (referencePath.EvaluatedInclude.EndsWith("Stride.UI.dll")) //todo hard-coded! needs to go when plug in system is in { assemblyProcessorApp.ReferencesToAdd.Add(referencePath.EvaluatedInclude); } else if (referencePath.EvaluatedInclude.EndsWith("Stride.Video.dll")) //todo hard-coded! needs to go when plug in system is in { assemblyProcessorApp.ReferencesToAdd.Add(referencePath.EvaluatedInclude); } } var assemblyResolver = assemblyProcessorApp.CreateAssemblyResolver(); // Add dependencies to assembly resolver var recursiveDependencies = stronglyConnected.OutEdges(sourceGroup).SelectDeep(edge => stronglyConnected.OutEdges(edge.Target)); foreach (var dependencySourceGroup in recursiveDependencies) { assemblyResolver.Register(dependencySourceGroup.Target.Assembly, dependencySourceGroup.Target.PE); assemblyProcessorApp.MemoryReferences.Add(dependencySourceGroup.Target.Assembly); } // Rewind streams peStream.Position = 0; pdbStream.Position = 0; var assemblyDefinition = AssemblyDefinition.ReadAssembly(peStream, new ReaderParameters { AssemblyResolver = assemblyResolver, ReadSymbols = true, SymbolStream = pdbStream }); // Run assembly processor bool readWriteSymbols = true; bool modified; assemblyProcessorApp.SerializationAssembly = true; if (!assemblyProcessorApp.Run(ref assemblyDefinition, ref readWriteSymbols, out modified)) { result.Error("Error running assembly processor"); break; } sourceGroup.Assembly = assemblyDefinition; // Write to file for now, since Cecil does not use the SymbolStream var peFileName = Path.ChangeExtension(Path.GetTempFileName(), ".dll"); var pdbFileName = Path.ChangeExtension(peFileName, ".pdb"); assemblyDefinition.Write(peFileName, new WriterParameters { WriteSymbols = true }); sourceGroup.PE = File.ReadAllBytes(peFileName); sourceGroup.PDB = File.ReadAllBytes(pdbFileName); File.Delete(peFileName); File.Delete(pdbFileName); } else { sourceGroup.PE = peStream.ToArray(); sourceGroup.PDB = pdbStream.ToArray(); } } } } // We register unloading/loading only if everything succeeded if (!result.HasErrors) { // 3. Register old assemblies to unload foreach (var sourceGroup in previousSortedConnectedGroups) { if (groupsToUnload.Contains(sourceGroup)) { sourceGroup.Project = null; sourceGroup.Assembly = null; result.UnloadedProjects.Add(sourceGroup); } } // 4. Register new assemblies to load foreach (var sourceGroup in sortedConnectedGroups.Reverse()) { // Check if it's either a new group, or one that has been unloaded if (!previousConnectedGroups.Contains(sourceGroup) || groupsToUnload.Contains(sourceGroup)) { result.LoadedProjects.Add(sourceGroup); } } // Set as new state previousSortedConnectedGroups = sortedConnectedGroups; previousStronglyConnected = stronglyConnected; previousConnectedGroups = connectedGroups; } return(result); }
private static void RunStronglyConnectedCondensationAndCheck <TVertex, TEdge>( [NotNull] IVertexAndEdgeListGraph <TVertex, TEdge> graph) where TEdge : IEdge <TVertex> { IMutableBidirectionalGraph <AdjacencyGraph <TVertex, TEdge>, CondensedEdge <TVertex, TEdge, AdjacencyGraph <TVertex, TEdge> > > condensedGraph = graph.CondensateStronglyConnected <TVertex, TEdge, AdjacencyGraph <TVertex, TEdge> >(); Assert.IsNotNull(condensedGraph); CheckVertexCount(graph, condensedGraph); CheckEdgeCount(graph, condensedGraph); CheckComponentCount(graph, condensedGraph); CheckDAG(condensedGraph); }
public void MultipleWeaklyConnectedComponents() { var edge12 = new Edge <int>(1, 2); var edge13 = new Edge <int>(1, 3); var edge23 = new Edge <int>(2, 3); var edge42 = new Edge <int>(4, 2); var edge43 = new Edge <int>(4, 3); var edge56 = new Edge <int>(5, 6); var edge57 = new Edge <int>(5, 7); var edge76 = new Edge <int>(7, 6); var edge89 = new Edge <int>(8, 9); var graph = new AdjacencyGraph <int, Edge <int> >(); graph.AddVerticesAndEdgeRange(new[] { edge12, edge13, edge23, edge42, edge43, edge56, edge57, edge76, edge89 }); IMutableBidirectionalGraph <AdjacencyGraph <int, Edge <int> >, CondensedEdge <int, Edge <int>, AdjacencyGraph <int, Edge <int> > > > condensedGraph = graph.CondensateWeaklyConnected <int, Edge <int>, AdjacencyGraph <int, Edge <int> > >(); Assert.IsNotNull(condensedGraph); Assert.AreEqual(3, condensedGraph.VertexCount); Assert.AreEqual(0, condensedGraph.EdgeCount); CollectionAssert.AreEquivalent( new[] { 1, 2, 3, 4 }, condensedGraph.Vertices.ElementAt(0).Vertices); CollectionAssert.AreEquivalent( new[] { edge12, edge13, edge23, edge42, edge43 }, condensedGraph.Vertices.ElementAt(0).Edges); CollectionAssert.AreEquivalent( new[] { 5, 6, 7 }, condensedGraph.Vertices.ElementAt(1).Vertices); CollectionAssert.AreEquivalent( new[] { edge56, edge57, edge76 }, condensedGraph.Vertices.ElementAt(1).Edges); CollectionAssert.AreEquivalent( new[] { 8, 9 }, condensedGraph.Vertices.ElementAt(2).Vertices); CollectionAssert.AreEquivalent( new[] { edge89 }, condensedGraph.Vertices.ElementAt(2).Edges); }
protected override void InternalCompute() { // create condensated graph this.condensedGraph = new BidirectionalGraph < TGraph, CondensedEdge <TVertex, TEdge, TGraph> >(false); if (this.VisitedGraph.VertexCount == 0) { return; } // compute strongly connected components var components = new Dictionary <TVertex, int>(this.VisitedGraph.VertexCount); int componentCount = ComputeComponentCount(components); var cancelManager = this.Services.CancelManager; if (cancelManager.IsCancelling) { return; } // create list vertices var condensatedVertices = new Dictionary <int, TGraph>(componentCount); for (int i = 0; i < componentCount; ++i) { TGraph v = new TGraph(); condensatedVertices.Add(i, v); this.condensedGraph.AddVertex(v); } // addingvertices foreach (var v in this.VisitedGraph.Vertices) { condensatedVertices[components[v]].AddVertex(v); } if (cancelManager.IsCancelling) { return; } // condensated edges var condensatedEdges = new Dictionary <EdgeKey, CondensedEdge <TVertex, TEdge, TGraph> >(componentCount); // iterate over edges and condensate graph foreach (var edge in this.VisitedGraph.Edges) { // get component ids int sourceID = components[edge.Source]; int targetID = components[edge.Target]; // get vertices TGraph sources = condensatedVertices[sourceID]; if (sourceID == targetID) { sources.AddEdge(edge); continue; } var targets = condensatedVertices[targetID]; // at last add edge var edgeKey = new EdgeKey(sourceID, targetID); CondensedEdge <TVertex, TEdge, TGraph> condensatedEdge; if (!condensatedEdges.TryGetValue(edgeKey, out condensatedEdge)) { condensatedEdge = new CondensedEdge <TVertex, TEdge, TGraph>(sources, targets); condensatedEdges.Add(edgeKey, condensatedEdge); this.condensedGraph.AddEdge(condensatedEdge); } condensatedEdge.Edges.Add(edge); } }
internal ClusteredTopologicalSortAlgorithm(IVertexAndEdgeListGraph <TVertex, TEdge> graph, TopologicalSortOrder sortOrder) { _unprocessedGraph = graph.CopyTo <TVertex, TEdge, BidirectionalGraph <TVertex, TEdge> >(); _sortOrder = sortOrder; }
public GraphHideHelpers([NotNull] IMutableBidirectionalGraph <TVertex, TEdge> managedGraph) { Debug.Assert(managedGraph != null); _graph = managedGraph; }
public GraphHideHelper(IMutableBidirectionalGraph <TVertex, TEdge> managedGraph) { graph = managedGraph; }
public ILayoutAlgorithm <TVertex, TEdge, TGraph> CreateLayoutAlgorithm(LayoutAlgorithmTypeEnum newAlgorithmType, TGraph iGraph, IDictionary <TVertex, Point> positions = null, IDictionary <TVertex, Size> sizes = null, ILayoutParameters parameters = null) { if (iGraph == null) { return(null); } if (parameters == null) { parameters = CreateLayoutParameters(newAlgorithmType); } IMutableBidirectionalGraph <TVertex, TEdge> graph = iGraph.CopyToBidirectionalGraph(); /*var dic = new Dictionary<TVertex, Point>(); * if (Positions != null) * { * dic = Positions.Where(a => a.Key.SkipProcessing == ProcessingOptionEnum.Freeze).ToDictionary(a=> a.Key, a=> a.Value); * }*/ graph.RemoveEdgeIf(a => a.SkipProcessing == ProcessingOptionEnum.Exclude); graph.RemoveVertexIf(a => a.SkipProcessing == ProcessingOptionEnum.Exclude); switch (newAlgorithmType) { case LayoutAlgorithmTypeEnum.Tree: return(new SimpleTreeLayoutAlgorithm <TVertex, TEdge, TGraph>((TGraph)graph, positions, sizes, parameters as SimpleTreeLayoutParameters)); case LayoutAlgorithmTypeEnum.SimpleRandom: return(new RandomLayoutAlgorithm <TVertex, TEdge, TGraph>((TGraph)graph, positions)); case LayoutAlgorithmTypeEnum.Circular: return(new CircularLayoutAlgorithm <TVertex, TEdge, TGraph>((TGraph)graph, positions, sizes, parameters as CircularLayoutParameters)); case LayoutAlgorithmTypeEnum.FR: return(new FRLayoutAlgorithm <TVertex, TEdge, TGraph>((TGraph)graph, positions, parameters as FRLayoutParametersBase)); case LayoutAlgorithmTypeEnum.BoundedFR: return(new FRLayoutAlgorithm <TVertex, TEdge, TGraph>((TGraph)graph, positions, parameters as BoundedFRLayoutParameters)); case LayoutAlgorithmTypeEnum.KK: return(new KKLayoutAlgorithm <TVertex, TEdge, TGraph>((TGraph)graph, positions, parameters as KKLayoutParameters)); case LayoutAlgorithmTypeEnum.ISOM: return(new ISOMLayoutAlgorithm <TVertex, TEdge, TGraph>((TGraph)graph, positions, parameters as ISOMLayoutParameters)); case LayoutAlgorithmTypeEnum.LinLog: return(new LinLogLayoutAlgorithm <TVertex, TEdge, TGraph>((TGraph)graph, positions, parameters as LinLogLayoutParameters)); case LayoutAlgorithmTypeEnum.EfficientSugiyama: return(new EfficientSugiyamaLayoutAlgorithm <TVertex, TEdge, TGraph>((TGraph)graph, parameters as EfficientSugiyamaLayoutParameters, positions, sizes)); case LayoutAlgorithmTypeEnum.Sugiyama: return(new SugiyamaLayoutAlgorithm <TVertex, TEdge, TGraph>((TGraph)graph, sizes, positions, parameters as SugiyamaLayoutParameters, e => (e is TypedEdge <TVertex> ?(e as TypedEdge <TVertex>).Type : EdgeTypes.Hierarchical))); case LayoutAlgorithmTypeEnum.CompoundFDP: return(new CompoundFDPLayoutAlgorithm <TVertex, TEdge, TGraph>((TGraph)graph, sizes, new Dictionary <TVertex, Thickness>(), new Dictionary <TVertex, CompoundVertexInnerLayoutType>(), positions, parameters as CompoundFDPLayoutParameters)); /*case LayoutAlgorithmTypeEnum.BalloonTree: * return new BalloonTreeLayoutAlgorithm<TVertex, TEdge, TGraph>(Graph, Positions, Sizes, parameters as BalloonTreeLayoutParameters, Graph.Vertices.FirstOrDefault());*/ default: return(null); } }
public ExampleExternalLayoutAlgorithm(IMutableBidirectionalGraph <DataVertex, DataEdge> graph) { _graph = graph; }
public void MultipleStronglyConnectedComponents() { var edge12 = new Edge <int>(1, 2); var edge23 = new Edge <int>(2, 3); var edge24 = new Edge <int>(2, 4); var edge25 = new Edge <int>(2, 5); var edge31 = new Edge <int>(3, 1); var edge34 = new Edge <int>(3, 4); var edge46 = new Edge <int>(4, 6); var edge56 = new Edge <int>(5, 6); var edge57 = new Edge <int>(5, 7); var edge64 = new Edge <int>(6, 4); var edge75 = new Edge <int>(7, 5); var edge78 = new Edge <int>(7, 8); var edge86 = new Edge <int>(8, 6); var edge87 = new Edge <int>(8, 7); var graph = new AdjacencyGraph <int, Edge <int> >(); graph.AddVerticesAndEdgeRange(new[] { edge12, edge23, edge24, edge25, edge31, edge34, edge46, edge56, edge57, edge64, edge75, edge78, edge86, edge87 }); graph.AddVertex(10); IMutableBidirectionalGraph <AdjacencyGraph <int, Edge <int> >, CondensedEdge <int, Edge <int>, AdjacencyGraph <int, Edge <int> > > > condensedGraph = graph.CondensateStronglyConnected <int, Edge <int>, AdjacencyGraph <int, Edge <int> > >(); Assert.IsNotNull(condensedGraph); Assert.AreEqual(4, condensedGraph.VertexCount); Assert.AreEqual(3, condensedGraph.EdgeCount); // Condensed edge CollectionAssert.AreEquivalent( new[] { edge56, edge86 }, condensedGraph.Edges.ElementAt(0).Edges); CollectionAssert.AreEquivalent( new[] { edge24, edge34 }, condensedGraph.Edges.ElementAt(1).Edges); CollectionAssert.AreEquivalent( new[] { edge25 }, condensedGraph.Edges.ElementAt(2).Edges); // Components CollectionAssert.AreEquivalent( new[] { 4, 6 }, condensedGraph.Vertices.ElementAt(0).Vertices); CollectionAssert.AreEquivalent( new[] { edge46, edge64 }, condensedGraph.Vertices.ElementAt(0).Edges); CollectionAssert.AreEquivalent( new[] { 5, 7, 8 }, condensedGraph.Vertices.ElementAt(1).Vertices); CollectionAssert.AreEquivalent( new[] { edge57, edge75, edge78, edge87 }, condensedGraph.Vertices.ElementAt(1).Edges); CollectionAssert.AreEquivalent( new[] { 1, 2, 3 }, condensedGraph.Vertices.ElementAt(2).Vertices); CollectionAssert.AreEquivalent( new[] { edge12, edge23, edge31 }, condensedGraph.Vertices.ElementAt(2).Edges); CollectionAssert.AreEquivalent( new[] { 10 }, condensedGraph.Vertices.ElementAt(3).Vertices); CollectionAssert.IsEmpty(condensedGraph.Vertices.ElementAt(3).Edges); }
public void OneStronglyConnectedComponent() { var edge12 = new Edge <int>(1, 2); var edge23 = new Edge <int>(2, 3); var edge31 = new Edge <int>(3, 1); var graph = new AdjacencyGraph <int, Edge <int> >(); graph.AddVerticesAndEdgeRange(new[] { edge12, edge23, edge31 }); IMutableBidirectionalGraph <AdjacencyGraph <int, Edge <int> >, CondensedEdge <int, Edge <int>, AdjacencyGraph <int, Edge <int> > > > condensedGraph = graph.CondensateStronglyConnected <int, Edge <int>, AdjacencyGraph <int, Edge <int> > >(); Assert.IsNotNull(condensedGraph); Assert.AreEqual(1, condensedGraph.VertexCount); Assert.AreEqual(0, condensedGraph.EdgeCount); CollectionAssert.AreEquivalent(graph.Vertices, condensedGraph.Vertices.ElementAt(0).Vertices); CollectionAssert.AreEquivalent(graph.Edges, condensedGraph.Vertices.ElementAt(0).Edges); }