public void Union_Test() { var n1 = new UnionFindNode(); var n2 = new UnionFindNode(); var n3 = new UnionFindNode(); var n4 = new UnionFindNode(); var n5 = new UnionFindNode(); Assert.True(n1.Union(n2)); Assert.True(n2.Union(n3)); Assert.False(n3.Union(n1)); Assert.True(n4.Union(n5)); Assert.False(n5.Union(n4)); Assert.True(n1.IsUnionedWith(n1)); Assert.True(n2.IsUnionedWith(n2)); Assert.True(n1.IsUnionedWith(n2)); Assert.True(n1.IsUnionedWith(n3)); Assert.False(n4.IsUnionedWith(n1)); Assert.False(n5.IsUnionedWith(n2)); Assert.True(n4.IsUnionedWith(n5)); }
/// <summary> /// Merges the sets represented by this node and the other node into a single set. /// Returns whether or not the nodes were disjoint before the union operation (i.e. if the operation had an effect). /// </summary> /// <returns>True when the union had an effect, false when the nodes were already in the same set.</returns> public bool Union(UnionFindNode other) { if (other == null) { throw new ArgumentNullException("other"); } var root1 = this.Find(); var root2 = other.Find(); if (ReferenceEquals(root1, root2)) { return(false); } if (root1.NodeId < root2.NodeId) { root2._parent = root1; } else { root1._parent = root2; } /* * if (root1._rank < root2._rank) { * root1._parent = root2; * } else if (root1._rank > root2._rank) { * root2._parent = root1; * } else { * root2._parent = root1; * root1._rank++; * } */ return(true); }
public void TestTrivial() { var n1 = new UnionFindNode(); var n2 = new UnionFindNode(); Assert.True(n1.IsUnionedWith(n1)); Assert.False(n1.IsUnionedWith(n2)); }
/// <summary> /// Determines whether or not this node and the other node are in the same set. /// </summary> public bool IsUnionedWith(UnionFindNode other) { if (other == null) { throw new ArgumentNullException("other"); } return(ReferenceEquals(Find(), other.Find())); }
/// <summary> /// Returns the current representative of the set this node is in. /// Note that the representative is only accurate untl the next Union operation. /// </summary> public UnionFindNode Find() { if (!ReferenceEquals(_parent, this)) { _parent = _parent.Find(); } return(_parent); }
public void Trivial_Test() { var n1 = new UnionFindNode(); var n2 = new UnionFindNode(); Assert.True(n1.IsUnionedWith(n1)); Assert.False(n1.IsUnionedWith(n2)); Assert.Throws <ArgumentNullException>(() => n1.Union(null)); Assert.Throws <ArgumentNullException>(() => n1.IsUnionedWith(null)); }
//TODO: for testnet we only have a single chain, thus grouper only take care of txList in one chain (hence Process has chainId as parameter) public async Task <Tuple <List <List <Transaction> >, Dictionary <Transaction, Exception> > > ProcessNaive(int chainId, List <Transaction> transactions) { var txResourceHandle = new Dictionary <Transaction, string>(); var failedTxs = new Dictionary <Transaction, Exception>(); if (transactions.Count == 0) { return(new Tuple <List <List <Transaction> >, Dictionary <Transaction, Exception> >(new List <List <Transaction> >(), failedTxs)); } Dictionary <string, UnionFindNode> resourceUnionSet = new Dictionary <string, UnionFindNode>(); //set up the union find set as the representation of graph and the connected components will be the resulting groups foreach (var tx in transactions) { UnionFindNode first = null; List <string> resources; try { resources = (await _resourceUsageDetectionService.GetResources(tx)).ToList(); } catch (Exception e) { failedTxs.Add(tx, e); continue; } //Logger.LogDebug(string.Format("tx {0} have resource [{1}]", tx.From, string.Join(" ||| ", resources))); foreach (var resource in resources) { if (!resourceUnionSet.TryGetValue(resource, out var node)) { node = new UnionFindNode(); resourceUnionSet.Add(resource, node); } if (first == null) { first = node; txResourceHandle.Add(tx, resource); } else { node.Union(first); } } } Dictionary <int, List <Transaction> > grouped = new Dictionary <int, List <Transaction> >(); List <List <Transaction> > result = new List <List <Transaction> >(); foreach (var tx in transactions) { if (txResourceHandle.TryGetValue(tx, out var firstResource)) { int nodeId = resourceUnionSet[firstResource].Find().NodeId; if (!grouped.TryGetValue(nodeId, out var group)) { group = new List <Transaction>(); grouped.Add(nodeId, group); } group.Add(tx); } else { if (!failedTxs.ContainsKey(tx)) { //each "resource-free" transaction have its own group result.Add(new List <Transaction>() { tx }); } } } result.AddRange(grouped.Values); Logger.LogInformation(string.Format( "Grouper on chainId \"{0}\" group [{1}] transactions into [{2}] groups with sizes [{3}], There are also {4} transactions failed retriving resource", ChainHelpers.ConvertChainIdToBase58(chainId), transactions.Count, result.Count, string.Join(", ", result.Select(a => a.Count)), failedTxs.Count)); return(new Tuple <List <List <Transaction> >, Dictionary <Transaction, Exception> >(result, failedTxs)); }
/// <summary> /// Creates a new disjoint node, representative of a set containing only the new node. /// </summary> public UnionFindNode() { _parent = this; NodeId = Interlocked.Increment(ref _nextId); }