Пример #1
0
        public void GraphMatchTrivial1()
        {
            Graph g = new Graph();

            g.LoadFromFile("turtle11-unofficial/test-13.ttl");
            Graph h = new Graph();

            h.LoadFromFile("turtle11-unofficial/test-13.out", new NTriplesParser());

            GraphDiffReport report = g.Difference(h);

            if (!report.AreEqual)
            {
                TestTools.ShowDifferences(report);
            }
            Assert.IsTrue(report.AreEqual);
        }
        public void GraphDiffRemovedGroundTriples()
        {
            Graph g = new Graph();
            Graph h = new Graph();

            g.LoadFromFile("resources\\InferenceTest.ttl");
            h.LoadFromFile("resources\\InferenceTest.ttl");

            //Remove Triples about Ford Fiestas from 2nd Graph
            h.Retract(h.GetTriplesWithSubject(new Uri("http://example.org/vehicles/FordFiesta")).ToList());

            GraphDiffReport report = g.Difference(h);

            TestTools.ShowDifferences(report);

            Assert.False(report.AreEqual, "Graphs should not have been reported as equal");
            Assert.True(report.RemovedTriples.Any(), "Difference should have reported some Removed Triples");
        }
Пример #3
0
 private void MergeMapping(GraphDiffReport report, Dictionary <INode, INode> mapping)
 {
     //This first run through ensures the mappings don't conflict in which case it is an invalid mapping
     foreach (KeyValuePair <INode, INode> kvp in mapping)
     {
         if (report.Mapping.ContainsKey(kvp.Key))
         {
             if (!report.Mapping[kvp.Key].Equals(kvp.Value))
             {
                 throw new RdfException("Error in GraphDiff - " + kvp.Key.ToString() + " is already mapped to " + report.Mapping[kvp.Key].ToString() + " so cannot be remapped to " + kvp.Value.ToString());
             }
         }
     }
     //The second run through does the actual merge
     foreach (KeyValuePair <INode, INode> kvp in mapping)
     {
         report.Mapping.Add(kvp.Key, kvp.Value);
     }
 }
        /// <summary>
        /// Converts a <see cref="GraphDiffReport">diff</see> to an equivalent <see cref="ModifyCommand">SPARQL Update INSERT/DELETE command</see>.
        /// </summary>
        /// <param name="diff">The <see cref="GraphDiffReport">diff</see> to convert.</param>
        /// <param name="graphUri">Optional <see cref="Uri">URI</see> of the affected graph.</param>
        /// <param name="prefixes">Optional <see cref="INamespaceMapper">mapper</see> used to resolve prefixes.</param>
        /// <returns>A <see cref="ModifyCommand">SPARQL Update INSERT/DELETE command</see> that represents the <see cref="GraphDiffReport">diff</see>.</returns>
        public static ModifyCommand AsUpdate(this GraphDiffReport diff, Uri graphUri = null, INamespaceMapper prefixes = null)
        {
            var delete = new GraphPatternBuilder();
            var insert = new GraphPatternBuilder();

            var where = new GraphPatternBuilder();

            // Removed ground triples are added as is to both delete and where clauses
            foreach (var t in diff.RemovedTriples)
            {
                delete.AddTriplePattern(t);
                where.AddTriplePattern(t);
            }

            foreach (var g in diff.RemovedMSGs)
            {
                // Blank nodes in removed non-ground triples are converted to variables and added to both delete and where clauses
                foreach (var t in g.Triples)
                {
                    delete.AddVariablePattern(t);
                    where.AddVariablePattern(t);
                }

                // An ISBLANK filter is added for each blank node in removed non-ground triples
                foreach (var n in g.BlankNodes())
                {
                    where.AddBlankNodeFilter(n);
                }
            }

            // Added triples (ground or not) are added as is to the insert clause
            foreach (var t in diff.AllAddedTriples())
            {
                insert.AddTriplePattern(t);
            }

            return(new ModifyCommand(
                       delete.BuildGraphPattern(prefixes),
                       insert.BuildGraphPattern(prefixes),
                       where.BuildGraphPattern(prefixes),
                       graphUri));
        }
        /// <summary>
        /// Converts a <see cref="GraphDiffReport">diff</see> to an equivalent <see cref="ModifyCommand">SPARQL Update query</see>
        /// </summary>
        /// <param name="diff">The <see cref="GraphDiffReport">diff</see> to convert</param>
        /// <returns>A <see cref="ModifyCommand">SPARQL Update query</see> that represents the <see cref="GraphDiffReport">diff</see></returns>
        internal static ModifyCommand AsUpdate(this GraphDiffReport diff)
        {
            var delete = new GraphPatternBuilder();
            var insert = new GraphPatternBuilder();

            var where = new GraphPatternBuilder();

            // Groud removed triples are added as is to both delete and where clauses
            foreach (var t in diff.RemovedTriples)
            {
                delete.AddTriplePattern(t);
                where.AddTriplePattern(t);
            }

            foreach (var g in diff.RemovedMSGs)
            {
                // Blank nodes in non-ground removed triples are converted to variables and added to both delete and where clauses
                foreach (var t in g.Triples)
                {
                    delete.AddVariablePattern(t);
                    where.AddVariablePattern(t);
                }

                // An ISBLANK filter is added for each blank node in non-ground removed triples
                foreach (var n in g.BlankNodes())
                {
                    where.AddBlankNodeFilter(n);
                }
            }

            // Added triples (ground or not) are added as is to the insert clause
            foreach (var t in diff.AllAddedTriples())
            {
                insert.AddTriplePattern(t);
            }

            return(new ModifyCommand(
                       delete.BuildGraphPattern(),
                       insert.BuildGraphPattern(),
                       where.BuildGraphPattern()));
        }
        public void GraphDiffRemovedMSG()
        {
            Graph g = new Graph();
            Graph h = new Graph();

            g.LoadFromFile("resources\\InferenceTest.ttl");
            h.LoadFromFile("resources\\InferenceTest.ttl");

            //Remove MSG from 2nd Graph
            INode toRemove = h.Nodes.BlankNodes().FirstOrDefault();

            Skip.If(toRemove == null, "No MSGs in test graph");
            h.Retract(h.GetTriplesWithSubject(toRemove).ToList());

            GraphDiffReport report = g.Difference(h);

            TestTools.ShowDifferences(report);

            Assert.False(report.AreEqual, "Graphs should not have been reported as equal");
            Assert.True(report.RemovedMSGs.Any(), "Difference should have reported some Removed MSGs");
        }
        public void GraphDiffAddedMSG()
        {
            Graph g = new Graph();
            Graph h = new Graph();

            g.LoadFromFile("resources\\InferenceTest.ttl");
            h.LoadFromFile("resources\\InferenceTest.ttl");

            //Add additional Triple to 2nd Graph
            INode    blank    = h.CreateBlankNode();
            IUriNode subClass = h.CreateUriNode("rdfs:subClassOf");
            IUriNode vehicle  = h.CreateUriNode("eg:Vehicle");

            h.Assert(new Triple(blank, subClass, vehicle));

            GraphDiffReport report = g.Difference(h);

            TestTools.ShowDifferences(report);

            Assert.False(report.AreEqual, "Graphs should not have been reported as equal");
            Assert.True(report.AddedMSGs.Any(), "Difference should have reported some Added MSGs");
        }
Пример #8
0
        public void GraphDiffAddedGroundTriples()
        {
            Graph g = new Graph();
            Graph h = new Graph();

            FileLoader.Load(g, "InferenceTest.ttl");
            FileLoader.Load(h, "InferenceTest.ttl");

            //Add additional Triple to 2nd Graph
            IUriNode spaceVehicle = h.CreateUriNode("eg:SpaceVehicle");
            IUriNode subClass     = h.CreateUriNode("rdfs:subClassOf");
            IUriNode vehicle      = h.CreateUriNode("eg:Vehicle");

            h.Assert(new Triple(spaceVehicle, subClass, vehicle));

            GraphDiffReport report = g.Difference(h);

            TestTools.ShowDifferences(report);

            Assert.IsFalse(report.AreEqual, "Graphs should not have been reported as equal");
            Assert.IsTrue(report.AddedTriples.Any(), "Difference should have reported some Added Triples");
        }
Пример #9
0
        public void GraphMatchTrivial2()
        {
            Graph      g    = new Graph();
            IBlankNode a    = g.CreateBlankNode("b1");
            IBlankNode b    = g.CreateBlankNode("b2");
            IBlankNode c    = g.CreateBlankNode("b3");
            INode      pred = g.CreateUriNode(UriFactory.Create("http://predicate"));

            g.Assert(a, pred, g.CreateLiteralNode("A"));
            g.Assert(a, pred, b);
            g.Assert(b, pred, g.CreateLiteralNode("B"));
            g.Assert(b, pred, c);
            g.Assert(c, pred, g.CreateLiteralNode("C"));
            g.Assert(c, pred, a);

            Graph      h     = new Graph();
            IBlankNode a2    = h.CreateBlankNode("b4");
            IBlankNode b2    = h.CreateBlankNode("b5");
            IBlankNode c2    = h.CreateBlankNode("b3");
            INode      pred2 = h.CreateUriNode(UriFactory.Create("http://predicate"));

            h.Assert(a2, pred2, h.CreateLiteralNode("A"));
            h.Assert(a2, pred2, b2);
            h.Assert(b2, pred2, h.CreateLiteralNode("B"));
            h.Assert(b2, pred2, c2);
            h.Assert(c2, pred2, h.CreateLiteralNode("C"));
            h.Assert(c2, pred2, a2);

            GraphDiffReport report = g.Difference(h);

            if (!report.AreEqual)
            {
                TestTools.ShowDifferences(report);
            }
            Assert.IsTrue(report.AreEqual);
        }
Пример #10
0
        public void GraphDiffRemovedMSG()
        {
            Graph g = new Graph();
            Graph h = new Graph();

            FileLoader.Load(g, "InferenceTest.ttl");
            FileLoader.Load(h, "InferenceTest.ttl");

            //Remove MSG from 2nd Graph
            INode toRemove = h.Nodes.BlankNodes().FirstOrDefault();

            if (toRemove == null)
            {
                Assert.Inconclusive("No MSGs in test graph");
            }
            h.Retract(h.GetTriplesWithSubject(toRemove).ToList());

            GraphDiffReport report = g.Difference(h);

            TestTools.ShowDifferences(report);

            Assert.IsFalse(report.AreEqual, "Graphs should not have been reported as equal");
            Assert.IsTrue(report.RemovedMSGs.Any(), "Difference should have reported some Removed MSGs");
        }
 private static IEnumerable <Triple> AllAddedTriples(this GraphDiffReport diff)
 {
     return(diff.AddedMSGs.SelectMany(msg => msg.Triples).Union(diff.AddedTriples));
 }
Пример #12
0
        /// <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();

            //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);
            }

            //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
                this.ComputeMSGs(a, this._lhsUnassigned, this._lhsMSGs);
                this.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);
        }
Пример #13
0
        public static void ShowDifferences(GraphDiffReport report, String lhsName, String rhsName)
        {
            NTriplesFormatter formatter = new NTriplesFormatter();

            lhsName = String.IsNullOrEmpty(lhsName) ? "1st Graph" : lhsName;
            rhsName = String.IsNullOrEmpty(rhsName) ? "2nd Graph" : rhsName;

            if (report.AreEqual)
            {
                Console.WriteLine("Graphs are Equal");
                Console.WriteLine();
                Console.WriteLine("Blank Node Mapping between Graphs:");
                foreach (KeyValuePair <INode, INode> kvp in report.Mapping)
                {
                    Console.WriteLine(kvp.Key.ToString(formatter) + " => " + kvp.Value.ToString(formatter));
                }
            }
            else
            {
                Console.WriteLine("Graphs are non-equal");
                Console.WriteLine();
                Console.WriteLine("Triples added to " + lhsName + " to give " + rhsName + ":");
                foreach (Triple t in report.AddedTriples)
                {
                    Console.WriteLine(t.ToString(formatter));
                }
                Console.WriteLine();
                Console.WriteLine("Triples removed from " + lhsName + " to give " + rhsName + ":");
                foreach (Triple t in report.RemovedTriples)
                {
                    Console.WriteLine(t.ToString(formatter));
                }
                Console.WriteLine();
                Console.WriteLine("Blank Node Mapping between Graphs:");
                foreach (KeyValuePair <INode, INode> kvp in report.Mapping)
                {
                    Console.WriteLine(kvp.Key.ToString(formatter) + " => " + kvp.Value.ToString(formatter));
                }
                Console.WriteLine();
                if (report.AddedMSGs.Any())
                {
                    Console.WriteLine("MSGs added to " + lhsName + " to give " + rhsName + ":");
                    foreach (IGraph msg in report.AddedMSGs)
                    {
                        Console.WriteLine(msg.Triples.Count + " Triple(s):");
                        foreach (Triple t in msg.Triples)
                        {
                            Console.WriteLine(t.ToString(formatter));
                        }
                        Console.WriteLine();
                    }
                    Console.WriteLine();
                }
                if (report.RemovedMSGs.Any())
                {
                    Console.WriteLine("MSGs removed from " + lhsName + " to give " + rhsName + ":");
                    foreach (IGraph msg in report.RemovedMSGs)
                    {
                        Console.WriteLine(msg.Triples.Count + " Triple(s):");
                        foreach (Triple t in msg.Triples)
                        {
                            Console.WriteLine(t.ToString(formatter));
                        }
                        Console.WriteLine();
                    }
                }
            }
        }
Пример #14
0
 public static void ShowDifferences(GraphDiffReport report)
 {
     ShowDifferences(report, "1st Graph", "2nd Graph");
 }