/// <inheritdoc /> public override int Similarity(ITreeNode <T> other, DEquality <ITreeNode <T> > equality) { int similarity = equality(this, other) ? 1 : 0; List <ITreeNode <T> > nodes = new List <ITreeNode <T> >(other.Children); foreach (ITreeNode <T> child in Children) { ITreeNode <T> node = nodes.Find(n => equality(n, child)); // if node is default then no equal node exists. subtract from similarity if (node == default(ITreeNode <T>)) { similarity -= (1 + child.DescendentCount); } // Otherwise, add the similarity of the new node else { similarity += child.Similarity(node); nodes.Remove(node); } } // subtract remaining foreach (ITreeNode <T> child in nodes) { similarity -= (1 + child.DescendentCount); } return(similarity); }
/// <inheritdoc /> public override ITreeNode <T> Difference(ITreeNode <T> other, DEquality <ITreeNode <T> > traversalEquality, DEquality <T> deletionEquality) { // if nodes arn't equal return nothing if (Equals(other)) { return(null); } // if these arn't traversal equal, return a copy of this node if (!traversalEquality(this, other)) { return(Copy()); } // if this has no children, test for deletion if (ChildCount == 0) { return(deletionEquality(Value, other.Value) ? null : new UniqueChildrenTreeNode <T>(this.Value)); } // if other has no children, retun this as copy if (other.ChildCount == 0) { return(Copy()); } // calculate difference of children nodes UniqueChildrenTreeNode <T> differenceTree = new UniqueChildrenTreeNode <T>(Value); List <ITreeNode <T> > originalNodesWithoutTraversalNeighbour = new List <ITreeNode <T> >(Children); foreach (ITreeNode <T> child in other.Children) { ITreeNode <T> traversalNode = originalNodesWithoutTraversalNeighbour.Find(n => traversalEquality(n, child)); // if node exists, perform a difference and add new node to output if (traversalNode != default(ITreeNode <T>)) { UniqueChildrenTreeNode <T> newDifference = traversalNode.Difference(child, traversalEquality, deletionEquality) as UniqueChildrenTreeNode <T>; originalNodesWithoutTraversalNeighbour.Remove(traversalNode); if (newDifference == null) { continue; } UnsafeAddChild(differenceTree, newDifference); } } // Add all nodes without a traversale neighbour to output foreach (ITreeNode <T> node in originalNodesWithoutTraversalNeighbour) { node.Copy(differenceTree); } return(differenceTree); }
/// <inheritdoc /> public override ITreeNode <T> Union(ITreeNode <T> other, DEquality <ITreeNode <T> > equality, DMerge <T> merge) { // if there not equal, Union results in null if (!equality(this, other)) { return(null); } // Create a new node using the provided merge rule. // The merge rule determines how equal values resolve TreeNode <T> unionTree = new TreeNode <T>(merge(Value, other.Value)); // Get the children of the other node, to test against the children of the current node List <ITreeNode <T> > testNodes = new List <ITreeNode <T> >(other.Children); // Foreach node in Children, preform a test to determine the case and handle // the union calculation foreach (ITreeNode <T> child in Children) { // candidates for a deeper union are testsNodes that equal the child IEnumerable <ITreeNode <T> > candidates = testNodes.Where(n => equality(n, child)); // if no candidates, add this child to the new tree if (candidates == null || candidates.Count() == 0) { child.Copy(unionTree); continue; } // Determine which candidate should be used to perform the union // This is the most similar candidate ITreeNode <T> chosenCandidate = null; if (candidates.Count() == 1) { chosenCandidate = candidates.First(); } else { chosenCandidate = child.MostSimilar(candidates); } // Perform a union with the chosen candidate InternalAddChild(unionTree, child.Union(chosenCandidate, equality, merge) as TreeNode <T>); // Remove the candidate testNodes.Remove(chosenCandidate); } // Add all remaining nodes without performing a merge foreach (ITreeNode <T> node in testNodes) { node.Copy(unionTree); } return(unionTree); }
/// <inheritdoc /> public override ITreeNode <T> Intersection(ITreeNode <T> other, DEquality <ITreeNode <T> > equality) { // return null if other is null or if this does not equal other if (other == null || !equality(this, other)) { return(null); } // make a new node as the intersection tree TreeNode <T> intersectionTree = new TreeNode <T>(Value); // Get other children as nodes to test for intersection List <ITreeNode <T> > testNodes = new List <ITreeNode <T> >(other.Children); // Determine which candidate should be used to perform the intersection // This is the most similar candidate foreach (ITreeNode <T> child in Children) { // candidates are children that are equal IEnumerable <ITreeNode <T> > candidates = testNodes.Where(n => equality(n, child)); // if there are no candidates, ignore this child. These are not included in the // intersection if (candidates == null || candidates.Count() == 0) { continue; } // chose the mosre similar candidate available ITreeNode <T> chosenCandidate = null; if (candidates.Count() == 1) { chosenCandidate = candidates.First(); } else { chosenCandidate = child.MostSimilar(candidates); } // Add the intersection of child and candidate and add the result to the tree InternalAddChild(intersectionTree, child.Intersection(chosenCandidate, equality) as TreeNode <T>); testNodes.Remove(chosenCandidate); } return(intersectionTree); }
/// <inheritdoc /> public override ITreeNode <T> Intersection(ITreeNode <T> other, DEquality <ITreeNode <T> > equality) { // if not equal return null if (!equality(this, other)) { return(null); } // if netiehr have children return new tree node if (ChildCount == 0 || other.ChildCount == 0) { return(new UniqueChildrenTreeNode <T>(Value)); } // process node and children to find intersection UniqueChildrenTreeNode <T> intersectionRoot = new UniqueChildrenTreeNode <T>(Value); List <ITreeNode <T> > otherChildren = new List <ITreeNode <T> >(other.Children); foreach (ITreeNode <T> originalChild in Children) { ITreeNode <T> matchingOtherNode = otherChildren.Find(n => equality(n, originalChild)); // if a match exists, perform an intersection if (matchingOtherNode != default(ITreeNode <T>)) { UniqueChildrenTreeNode <T> newIntersection = originalChild.Intersection(matchingOtherNode) as UniqueChildrenTreeNode <T>; if (newIntersection == null) { continue; } UnsafeAddChild(intersectionRoot, newIntersection); otherChildren.Remove(matchingOtherNode); } } return(intersectionRoot); }
/// <inheritdoc /> public abstract ITreeNode <T> Union(ITreeNode <T> other, DEquality <ITreeNode <T> > equality, DMerge <T> merge);
/// <inheritdoc /> public abstract ITreeNode <T> Union(ITreeNode <T> other, DEquality <ITreeNode <T> > equality);
/// <inheritdoc /> public abstract int Similarity(ITreeNode <T> other, DEquality <ITreeNode <T> > equality);
/// <inheritdoc /> public abstract ITreeNode <T> Difference(ITreeNode <T> other, DEquality <ITreeNode <T> > traversal_equality, DEquality <T> deletion_equality);
/// <inheritdoc /> public abstract ITreeNode <T> Intersection(ITreeNode <T> other, DEquality <ITreeNode <T> > equality);
/// <inheritdoc /> public override int Similarity(ITreeNode <T> other, DEquality <ITreeNode <T> > equality) { // if equal, give one similarity point int similarity = equality(this, other) ? 1 : 0; // Find out how many children are similar int sharedChildren = UTIEquatable.SharedValuesCount <T>( Children.Select(n => n.Value), other.Children.Select(n => n.Value) ); // remove similarity points based on non-shared children similarity -= (ChildCount - sharedChildren); similarity -= (other.ChildCount - sharedChildren); // Use other children as a test of similarity List <ITreeNode <T> > testNodes = new List <ITreeNode <T> >(other.Children); foreach (ITreeNode <T> child in Children) { // determine the pairedNode (Node that is the equivalent of the this node) ITreeNode <T> pairedNode = null; // Find the nodes that are considered equal IEnumerable <ITreeNode <T> > possibleTestNodes = testNodes.Where(n => equality(n, child)); int count = possibleTestNodes.Count(); if (count > 1) { // if there is more than one possible test node, do a similarity test on each // and set paired node to the most similar. int innerSimilarity = int.MinValue; foreach (ITreeNode <T> node in possibleTestNodes) { int sim = child.Similarity(node, equality); if (sim > innerSimilarity) { innerSimilarity = sim; pairedNode = node; } } // Add the innerSimilarity to the similarity calculation similarity += innerSimilarity; } else if (count == 1) { // if there is only one, then add the similarty of these nodes // and remove the test node ITreeNode <T> testNode = possibleTestNodes.First(); similarity += child.Similarity(testNode, equality); pairedNode = testNode; } // remove candidate if (pairedNode != null) { testNodes.Remove(pairedNode); } } // All lingering nodes are subtracted from similarity foreach (ITreeNode <T> node in testNodes) { similarity -= node.DescendentCount; } return(similarity); }
/// <inheritdoc /> public override ITreeNode <T> Difference(ITreeNode <T> other, DEquality <ITreeNode <T> > travsersalEquality, DEquality <T> deletionEquality) { // nodes do not meet traveseral criteria, no further difference can be performed and // the original node value is returned. Difference ends here if (!travsersalEquality(this, other)) { return(new TreeNode <T>(Value)); } // If there are no more children that could be removed, check if the node should be deleted. // if so delete, otherwise, keep if (ChildCount == 0) { return(deletionEquality(Value, other.Value) ? null : new TreeNode <T>(Value)); } // Make a tree with the current value TreeNode <T> differenceTree = new TreeNode <T>(Value); // test against the childrne of the other List <ITreeNode <T> > testNodes = new List <ITreeNode <T> >(other.Children); foreach (ITreeNode <T> child in Children) { // candidates for travseral match travseralEquality IEnumerable <ITreeNode <T> > candidates = testNodes.Where(n => travsersalEquality(n, child)); // if there are no candidates, then copy this child to the difference tree // it is kept, and not deleted if (candidates == null || candidates.Count() == 0) { child.Copy(differenceTree); continue; } // find the candidate that requires traversal for more granular difference // This is the most similar node ITreeNode <T> chosenCandidate = null; if (candidates.Count() == 1) { chosenCandidate = candidates.First(); } else { chosenCandidate = child.MostSimilar(candidates); } // Perform a difference on the current child and the chosen candidate TreeNode <T> possibleChild = child.Difference(chosenCandidate, travsersalEquality, deletionEquality) as TreeNode <T>; // If the child isn't null, add it to the difference tree if (possibleChild != null) { InternalAddChild(differenceTree, possibleChild); } // remove candidate from future tests testNodes.Remove(chosenCandidate); } // if there are no children in the difference tree, check if it should be deleted if (differenceTree.ChildCount == 0) { return(deletionEquality(Value, other.Value) ? null : new TreeNode <T>(Value)); } return(differenceTree); }
/// <inheritdoc /> public override ITreeNode <T> Difference(ITreeNode <T> other, DEquality <ITreeNode <T> > travsersalEquality) { return(Difference(other, travsersalEquality, (t1, t2) => true)); }
/// <inheritdoc /> public override ITreeNode <T> Union(ITreeNode <T> other, DEquality <ITreeNode <T> > equality) { return(Union(other, equality, (o1, o2) => o1)); }
/// <inheritdoc /> public override ITreeNode <T> Union(ITreeNode <T> other, DEquality <ITreeNode <T> > equality, DMerge <T> merge) { // if not equal, return null if (!equality(this, other)) { return(null); } // since values are equal, if they both have no children, return node with value if (ChildCount == 0 && other.ChildCount == 0) { return(new UniqueChildrenTreeNode <T>(merge(Value, other.Value))); } // return copy of node with children if only 1 has children if (ChildCount > 0 && other.ChildCount == 0) { return(Copy()); } if (other.ChildCount > 0 && ChildCount == 0) { return(other.Copy()); } // set up the union tree for recursive calculation UniqueChildrenTreeNode <T> unionTree = new UniqueChildrenTreeNode <T>(merge(Value, other.Value)); // sort out children in both that have no equivalent in other // perform a union on any nodes that match List <ITreeNode <T> > otherNodesNotInOriginal = new List <ITreeNode <T> >(other.Children); List <ITreeNode <T> > originalNodesNotInOther = new List <ITreeNode <T> >(); foreach (ITreeNode <T> child in Children) { ITreeNode <T> matchingOtherNode = otherNodesNotInOriginal.Find(n => equality(n, child)); if (matchingOtherNode == default(ITreeNode <T>)) { originalNodesNotInOther.Add(child); } else { UniqueChildrenTreeNode <T> newUnion = child.Union(matchingOtherNode) as UniqueChildrenTreeNode <T>; if (newUnion == null) { continue; } // add union of matching nodes to tree UnsafeAddChild(unionTree, newUnion); otherNodesNotInOriginal.Remove(matchingOtherNode); } } // copy other nodes missing from original foreach (ITreeNode <T> node in otherNodesNotInOriginal) { node.Copy(unionTree); } // copy original nodes missing from other foreach (ITreeNode <T> node in originalNodesNotInOther) { node.Copy(unionTree); } return(unionTree); }