public override int Transform([NotNull] GlobalContext globalContext, Ignore configureOptions, [NotNull] TransformOptions transformOptions, [NotNull][ItemNotNull] IEnumerable <Dependency> dependencies, [NotNull] List <Dependency> transformedDependencies) { Dependency[] matchingDependencies = dependencies .Where(d => !transformOptions.Matches.Any() || transformOptions.Matches.Any(m => ItemMatch.IsMatch(m, d.UsingItem)) && transformOptions.Matches.Any(m => ItemMatch.IsMatch(m, d.UsedItem))) .ToArray(); MatrixDictionary <Item, int> aggregatedCounts = MatrixDictionary.CreateCounts(matchingDependencies, d => d.Ct, globalContext.CurrentGraph); // Force each item to exist on both matrix axes foreach (var from in aggregatedCounts.RowKeys) { aggregatedCounts.GetColumnSum(from); } foreach (var to in aggregatedCounts.ColumnKeys) { aggregatedCounts.GetRowSum(to); } // aggregatedCounts is used destructively in both following Mark runs; this is no problem, // because no sink can also be a source in NDepCheck: Nodes without any edges do not // appear; and nodes with only self cycles are either not a source and sink (if ignoreSelfCycles=false), // or they are both a source and a sink and hence are found in the first Mark run. if (transformOptions.MarkSinks) { Mark(aggregatedCounts, ac => ac.RowKeys, i => aggregatedCounts.GetRowSum(i), !transformOptions.ConsiderSelfCyclesInSourcesAndSinks, transformOptions.Recursive, transformOptions.MarkerToAdd); } if (transformOptions.MarkSources) { Mark(aggregatedCounts, ac => ac.ColumnKeys, i => aggregatedCounts.GetColumnSum(i), !transformOptions.ConsiderSelfCyclesInSourcesAndSinks, transformOptions.Recursive, transformOptions.MarkerToAdd); } var remainingNodes = new HashSet <Item>(aggregatedCounts.RowKeys); remainingNodes.UnionWith(aggregatedCounts.ColumnKeys); if (transformOptions.MarkSingleCycleNodes) { foreach (var d in matchingDependencies) { if (Equals(d.UsingItem, d.UsedItem)) { d.UsingItem.IncrementMarker(transformOptions.MarkerToAdd); } } } transformedDependencies.AddRange(dependencies); return(Program.OK_RESULT); }
public override int Transform([NotNull] GlobalContext globalContext, Ignore Ignore, [NotNull] TransformOptions transformOptions, [NotNull][ItemNotNull] IEnumerable <Dependency> dependencies, [NotNull] List <Dependency> transformedDependencies) { // Only items are changed (Order is added) transformedDependencies.AddRange(dependencies); // Algorithm: // LOOP // Find the item with the least outgoing edges (measured relative to outgoing and ingoing ones) // Put it into result list; and move edges to it from consideration // UNTIL list of items is empty MatrixDictionary <Item, int> aggregatedCounts = MatrixDictionary.CreateCounts(dependencies.Where(d => !Equals(d.UsingItem, d.UsedItem)), transformOptions.OrderBy, globalContext.CurrentGraph); for (int i = 0; aggregatedCounts.ColumnKeys.Any(); i++) { var itemsToSortValues = aggregatedCounts.ColumnKeys.Select( k => new { Item = k, Value = transformOptions.GetSortValue(aggregatedCounts.GetRowSum(k), aggregatedCounts.GetColumnSum(k)) }); decimal minToRatio = itemsToSortValues.Min(ir => ir.Value); Item minItem = itemsToSortValues.First(ir => ir.Value == minToRatio).Item; aggregatedCounts.RemoveColumn(minItem); minItem.IncrementMarker(transformOptions.OrderMarkerPrefix + i.ToString("D4")); } return(Program.OK_RESULT); }
public void TestSmallMatrixDictionary() { var d = new MatrixDictionary <string, int>((s, i) => s + i, (s, i) => s - i); // | A B # // ------------#---- // A | 1 2 # 3 // B | 4 8 # 12 // ======================== // | 5 10 # d.Add("A", "A", 1); d.Add("A", "B", 2); d.Add("B", "A", 4); d.Add("B", "B", 8); Assert.AreEqual(3, d.GetRowSum("A")); Assert.AreEqual(12, d.GetRowSum("B")); Assert.AreEqual(5, d.GetColumnSum("A")); Assert.AreEqual(10, d.GetColumnSum("B")); // | A B # // ------------#---- // A | 1 2 # 3 // B | - - # 0 // ======================== // | 1 2 # for (int i = 0; i < 3; i++) { d.RemoveRow("B"); Assert.AreEqual(3, d.GetRowSum("A")); Assert.AreEqual(0, d.GetRowSum("B")); Assert.AreEqual(1, d.GetColumnSum("A")); Assert.AreEqual(2, d.GetColumnSum("B")); } }
public void TestOneTopologicalSortStep() { var gc = new GlobalContext(); WorkingGraph graph = gc.CurrentGraph; Item a = graph.CreateItem(ItemType.SIMPLE, "a"); Item b = graph.CreateItem(ItemType.SIMPLE, "b"); Item c = graph.CreateItem(ItemType.SIMPLE, "c"); var dependencies = new[] { graph.CreateDependency(a, b, source: null, markers: "", ct: 1), graph.CreateDependency(c, a, source: null, markers: "", ct: 100), graph.CreateDependency(c, b, source: null, markers: "", ct: 100) }; var aggregated = new Dictionary <FromTo, Dependency>(); foreach (var d in dependencies.Where(d => !Equals(d.UsingItem, d.UsedItem))) { new FromTo(d.UsingItem, d.UsedItem).AggregateDependency(graph, d, aggregated); } var aggregatedCounts = new MatrixDictionary <Item, int>((s, i) => s + i, (s, i) => s - i); foreach (var kvp in aggregated) { aggregatedCounts.Add(kvp.Key.From, kvp.Key.To, kvp.Value.Ct); } var itemsToRatios = aggregatedCounts.ColumnKeys.Select( k => new { Item = k, Ratio = aggregatedCounts.GetRowSum(k) / (aggregatedCounts.GetColumnSum(k) + aggregatedCounts.GetRowSum(k) + 0.001m) }); decimal minToRatio = itemsToRatios.Min(ir => ir.Ratio); Item minItem = itemsToRatios.First(ir => ir.Ratio == minToRatio).Item; Assert.AreEqual(b, minItem); }
public void TestMatrixDictionary() { var d = new MatrixDictionary <string, int>((s, i) => s + i, (s, i) => s - i); // | A B C D # // ---------------------#---- // A | 15 100 0 . # 115 // B | 3 20 101 . # 124 // C | 7 5 30 . # 42 // D | . 2 300 . # 302 // ========================= // | 25 127 431 0 # d.Add("A", "A", 15); d.Add("A", "B", 100); d.Add("A", "C", 0); d.Add("B", "A", 3); d.Add("B", "B", 20); d.Add("B", "C", 101); d.Add("C", "A", 7); d.Add("C", "B", 5); d.Add("C", "C", 30); d.Add("D", "B", 2); d.Add("D", "C", 300); Assert.AreEqual(115, d.GetRowSum("A")); Assert.AreEqual(124, d.GetRowSum("B")); Assert.AreEqual(42, d.GetRowSum("C")); Assert.AreEqual(302, d.GetRowSum("D")); Assert.AreEqual(25, d.GetColumnSum("A")); Assert.AreEqual(127, d.GetColumnSum("B")); Assert.AreEqual(431, d.GetColumnSum("C")); Assert.AreEqual(0, d.GetColumnSum("D")); CollectionAssert.IsSubsetOf(new[] { "A", "B", "C", "D" }, d.RowKeys.ToList()); CollectionAssert.IsSubsetOf(new[] { "A", "B", "C" }, d.ColumnKeys.ToList()); for (int i = 0; i < 2; i++) { Assert.IsTrue(d.RemoveRow("B")); // | A B C D # // ---------------------#---- // A | 15 100 0 . # 115 // B | - - - . # - // C | 7 5 30 . # 42 // D | . 2 300 . # 302 // ========================= // | 22 107 330 0 # Assert.AreEqual(115, d.GetRowSum("A")); Assert.AreEqual(0, d.GetRowSum("B")); Assert.AreEqual(42, d.GetRowSum("C")); Assert.AreEqual(302, d.GetRowSum("D")); Assert.AreEqual(22, d.GetColumnSum("A")); Assert.AreEqual(107, d.GetColumnSum("B")); Assert.AreEqual(330, d.GetColumnSum("C")); Assert.AreEqual(0, d.GetColumnSum("D")); CollectionAssert.IsSubsetOf(new[] { "A", "C", "D" }, d.RowKeys.ToList()); CollectionAssert.IsSubsetOf(new[] { "A", "B", "C" }, d.ColumnKeys.ToList()); } Assert.IsTrue(d.RemoveRow("B")); Assert.IsFalse(d.RemoveRow("B")); for (int i = 0; i < 2; i++) { Assert.IsTrue(d.RemoveColumn("A")); // | A B C D # // ---------------------#---- // A | = 100 0 . # 100 // B | - - - . # - // C | = 5 30 . # 35 // D | . 2 300 . # 302 // ========================= // | 0 107 330 0 # Assert.AreEqual(100, d.GetRowSum("A")); Assert.AreEqual(0, d.GetRowSum("B")); Assert.AreEqual(35, d.GetRowSum("C")); Assert.AreEqual(302, d.GetRowSum("D")); Assert.AreEqual(0, d.GetColumnSum("A")); Assert.AreEqual(107, d.GetColumnSum("B")); Assert.AreEqual(330, d.GetColumnSum("C")); Assert.AreEqual(0, d.GetColumnSum("D")); CollectionAssert.IsSubsetOf(new[] { "A", "C", "D" }, d.RowKeys.ToList()); CollectionAssert.IsSubsetOf(new[] { "B", "C" }, d.ColumnKeys.ToList()); } Assert.IsTrue(d.RemoveColumn("A")); Assert.IsFalse(d.RemoveColumn("A")); }