public void GraphDiffNullReferenceBoth() { GraphDiff diff = new GraphDiff(); GraphDiffReport report = diff.Difference(null, null); TestTools.ShowDifferences(report); Assert.True(report.AreEqual, "Graphs should have been reported as equal for two null references"); Assert.False(report.AreDifferentSizes, "Graphs should have been reported same size for two null references"); }
public void GraphDiffNullReferenceA() { Graph g = new Graph(); g.LoadFromFile("resources\\InferenceTest.ttl"); GraphDiff diff = new GraphDiff(); GraphDiffReport report = diff.Difference(null, g); TestTools.ShowDifferences(report); Assert.False(report.AreEqual, "Graphs should have been reported as non-equal for one null reference"); Assert.True(report.AreDifferentSizes, "Graphs should have been reported as different sizes for one null reference"); Assert.True(report.AddedTriples.Any(), "Report should list added triples"); }
/// <summary> /// Computes MSGs for a Graph /// </summary> /// <param name="g">Graph</param> /// <param name="unassigned">Triples that need assigning to MSGs</param> /// <param name="msgs">MSGs list to populate</param> public static void ComputeMSGs(IGraph g, HashSet <Triple> unassigned, List <IGraph> msgs) { //While we have unassigned Triples build MSGs while (unassigned.Count > 0) { HashSet <INode> processed = new HashSet <INode>(); Queue <INode> unprocessed = new Queue <INode>(); //Get next Triple from unassigned Triple first = unassigned.First(); unassigned.Remove(first); //Get the BNodes from it that need to be processed GraphDiff.GetNodesForProcessing(first, unprocessed); //Start building an MSG starting from the Triple Graph msg = new Graph(); msg.Assert(first); while (unprocessed.Count > 0) { INode next = unprocessed.Dequeue(); //Can safely skip Nodes we've already processed if (processed.Contains(next)) { continue; } //Get all the Triples that use the given Node and find any additional Blank Nodes for processing foreach (Triple t in g.GetTriples(next)) { //When a Triple is added to an MSG it is removed from the unassigned list unassigned.Remove(t); msg.Assert(t); GraphDiff.GetNodesForProcessing(t, unprocessed); } processed.Add(next); } msgs.Add(msg); } }
private IGraph ExecuteDiff(IGraph older, IGraph newer, Uri graphUri = null) { var diff = new GraphDiff().Difference(older, newer); var update = diff.AsUpdate(graphUri); var sparql = update.ToString(); output.WriteLine(sparql); older = older ?? new Graph(); var ts = new TripleStore(); ts.Add(older); var store = new InMemoryManager(ts) as IUpdateableStorage; store.Update(sparql); return(older); }
/// <summary> /// Computes the Difference between this Graph the given Graph. /// </summary> /// <param name="g">Graph.</param> /// <returns></returns> /// <remarks> /// <para> /// Produces a report which shows the changes that must be made to this Graph to produce the given Graph. /// </para> /// </remarks> public GraphDiffReport Difference(IGraph g) { GraphDiff differ = new GraphDiff(); return(differ.Difference(this, g)); }
/// <summary> /// Calculates the Difference between the two Graphs i.e. the changes required to get from the 1st Graph to the 2nd Graph /// </summary> /// <param name="a">First Graph</param> /// <param name="b">Second Graph</param> /// <returns></returns> public GraphDiffReport Difference(IGraph a, IGraph b) { GraphDiffReport report = new GraphDiffReport(); if (a == null) { if (b == null) { //Both Graphs are null so considered equal with no differences report.AreEqual = true; report.AreDifferentSizes = false; return(report); } else { //A is null and B is non-null so considered non-equal with everything from B listed as added report.AreEqual = false; report.AreDifferentSizes = true; foreach (Triple t in b.Triples) { if (t.IsGroundTriple) { report.AddAddedTriple(t); } else { this._rhsUnassigned.Add(t); } } GraphDiff.ComputeMSGs(b, this._rhsUnassigned, this._rhsMSGs); foreach (IGraph msg in this._rhsMSGs) { report.AddAddedMSG(msg); } return(report); } } else if (b == null) { //A is non-null and B is null so considered non-equal with everything from A listed as removed report.AreEqual = false; report.AreDifferentSizes = true; foreach (Triple t in a.Triples) { if (t.IsGroundTriple) { report.AddRemovedTriple(t); } else { this._lhsUnassigned.Add(t); } } GraphDiff.ComputeMSGs(a, this._lhsUnassigned, this._lhsMSGs); foreach (IGraph msg in this._lhsMSGs) { report.AddRemovedMSG(msg); } return(report); } //Firstly check for Graph Equality Dictionary <INode, INode> equalityMapping = new Dictionary <INode, INode>(); if (a.Equals(b, out equalityMapping)) { //If Graphs are equal set AreEqual to true, assign the mapping and return report.AreEqual = true; if (equalityMapping != null) { report.Mapping = equalityMapping; } return(report); } Debug.WriteLine(String.Empty); report.AreDifferentSizes = (a.Triples.Count != b.Triples.Count); //Next check for changes in Ground Triples //Iterate over the Ground Triples in the 1st Graph to find those that have been removed in the 2nd foreach (Triple t in a.Triples.Where(t => t.IsGroundTriple)) { if (!b.Triples.Contains(t)) { report.AddRemovedTriple(t); } } //Iterate over the Ground Triples in the 2nd Graph to find those that have been added in the 2nd foreach (Triple t in b.Triples.Where(t => t.IsGroundTriple)) { if (!a.Triples.Contains(t)) { report.AddAddedTriple(t); } } //Do we need to compute MSGs? //If all Triples are Ground Triples then this step gets skipped which saves on computation if (a.Triples.Any(t => !t.IsGroundTriple) || b.Triples.Any(t => !t.IsGroundTriple)) { //Some non-ground Triples so start computing MSGs //First build 2 HashSets of the non-ground Triples from the Graphs foreach (Triple t in a.Triples.Where(t => !t.IsGroundTriple)) { this._lhsUnassigned.Add(t); } foreach (Triple t in b.Triples.Where(t => !t.IsGroundTriple)) { this._rhsUnassigned.Add(t); } //Then compute all the MSGs GraphDiff.ComputeMSGs(a, this._lhsUnassigned, this._lhsMSGs); GraphDiff.ComputeMSGs(b, this._rhsUnassigned, this._rhsMSGs); //Sort MSGs by size - this is just so we start checking MSG equality from smallest MSGs first for efficiency GraphSizeComparer comparer = new GraphSizeComparer(); this._lhsMSGs.Sort(comparer); this._rhsMSGs.Sort(comparer); //Now start trying to match MSG foreach (IGraph msg in this._lhsMSGs) { //Get Candidate MSGs from RHS i.e. those of equal size List <IGraph> candidates = (from g in this._rhsMSGs where g.Triples.Count == msg.Triples.Count select g).ToList(); if (candidates.Count == 0) { //No Candidate Matches so this MSG is not present in the 2nd Graph so add to report as a Removed MSG report.AddRemovedMSG(msg); } else { //Do any of the candidates match? bool hasMatch = false; foreach (IGraph candidate in candidates) { Dictionary <INode, INode> tempMapping = new Dictionary <INode, INode>(); if (msg.Equals(candidate, out tempMapping)) { //This MSG has a Match in the 2nd Graph so add the Mapping information hasMatch = true; try { this.MergeMapping(report, tempMapping); } catch (RdfException) { //If the Mapping cannot be merged it is a bad mapping and we try other candidates hasMatch = false; continue; } //Remove the matched MSG from the RHS MSGs so we cannot match another LHS MSG to it later //We use ReferenceEquals for this remove to avoid potentially costly Graph Equality calculations this._rhsMSGs.RemoveAll(g => ReferenceEquals(g, candidate)); } } //No match was found so the MSG is removed from the 2nd Graph if (!hasMatch) { report.AddRemovedMSG(msg); } } } //If we are left with any MSGs in the RHS then these are added MSG foreach (IGraph msg in this._rhsMSGs) { report.AddAddedMSG(msg); } } return(report); }