static void CompareModels(Store a, Store b) { string failures = ""; ArrayList abnodes = GetBlankNodes(a); ArrayList bbnodes = GetBlankNodes(b); // If the number of blank nodes differ, of course // the stores aren't identical, but for matching // purposes we'll add bnodes so they have the // same number. if (abnodes.Count != bbnodes.Count) failures += "\nInput/output have different number of blank nodes"; while (abnodes.Count < bbnodes.Count) abnodes.Add(new BNode()); while (bbnodes.Count < abnodes.Count) bbnodes.Add(new BNode()); // Set up the permutation array. int[] nodemap = new int[abnodes.Count]; int mindiffc = int.MaxValue; string mindiffs = null; do { // Check that two nodes don't map to the same thing. bool dup = false; for (int i = 0; i < nodemap.Length; i++) { for (int j = 0; j < i; j++) { if (nodemap[i] == nodemap[j]) { dup = true; } } } if (dup) continue; // Create maps Hashtable mapab = new Hashtable(); Hashtable mapba = new Hashtable(); for (int i = 0; i < nodemap.Length; i++) { mapab[abnodes[i]] = bbnodes[nodemap[i]]; mapba[bbnodes[nodemap[i]]] = abnodes[i]; } // Test for differences string diff = ""; int diffct = 0; foreach (Statement s in a.Select(Statement.All)) { if (!b.Contains(Replace(s, mapab))) { diff += "\nInput has: " + s; diffct++; } } foreach (Statement s in b.Select(Statement.All)) { if (!a.Contains(Replace(s, mapba))) { diff += "\nOutput has: " + s; diffct++; } } if (diffct < mindiffc) { mindiffc = diffct; mindiffs = diff; } } while (Permute(nodemap, bbnodes.Count)); if (mindiffs != null && mindiffc != 0) failures += mindiffs; if (failures != "") throw new ParserException(failures); }
private static bool MakeLeanMSG3(Store msg, ResSet predicates, StatementSink removed, ResSet nodesremoved, SyncPath path) { // The variable path has to be expanded by including the statements // connected to the variables on the frontier. Statements // mentioning a variable node have already been considered. // The target of each such statement can be considered fixed // or variable. If a variable is considered fixed, the edge // must exist in the MSG substituting the variables for their // values. If it's variable, it has to have at least one // match in the MSG but not as any of the variable nodes. // If all targets are considered fixed (and have matches), // then the variables so far (and their edges) can all be // removed and no more processing needs to be done. // There are (2^N)-1 other considerations. For each of those, // the targets considered variables all become the new // frontier, and this is repeated. // First, get a list of edges from the frontier that we // haven't considered yet. ArrayList alledges = new ArrayList(); foreach (BNode b in path.FrontierVariables) { // Make sure all edges are kept because even the ones // to literals have to be removed when duplication is found. foreach (Statement s in msg.Select(new Statement(b, null, null))) alledges.Add(new Edge(true, b, s.Predicate, s.Object)); foreach (Statement s in msg.Select(new Statement(null, null, b))) alledges.Add(new Edge(false, b, s.Predicate, s.Subject)); } ArrayList newedges = new ArrayList(); ResSet alltargets = new ResSet(); ResSet fixabletargetsset = new ResSet(); // can be fixed ResSet variabletargetsset = new ResSet(); // must be variable foreach (Edge e in alledges) { if (path.Path.ContainsKey(e)) continue; path.Path[e] = e; // This checks if we can keep the target of this edge // fixed, given the variable mappings we have so far. bool isTargetFixable = msg.Contains(e.AsStatement().Replace(path.Mapping)); // If the target of e is any of the following, we // can check immediately if the edge is supported // by the MSG under the variable mapping we have so far: // a named node, literal, fixed node, or predicate // a variable we've seen already // If it's not supported, this path fails. If it is // supported, we're done with this edge. if (!(e.End is BNode) || path.FixedNodes.Contains(e.End) || predicates.Contains(e.End) || path.VariableNodes.Contains(e.End)) { if (!isTargetFixable) return false; continue; // this edge is supported, so we can continue } // The target of e is a new BNode. // If this target is not fixable via this edge, it's // not fixable at all. if (!isTargetFixable) { fixabletargetsset.Remove(e.End); variabletargetsset.Add(e.End); } if (!alltargets.Contains(e.End)) { alltargets.Add(e.End); fixabletargetsset.Add(e.End); } newedges.Add(e); } // If all of the targets were fixable (trivially true also // if there simple were no new edges/targets), then we've reached // the end of this path. We can immediately remove // the edges we've seen so far, under the variable mapping // we've chosen. if (variabletargetsset.Count == 0) { foreach (Edge e in path.Path.Keys) { Statement s = e.AsStatement(); msg.Remove(s); if (removed != null) removed.Add(s); } foreach (Entity e in path.Mapping.Keys) nodesremoved.Add(e); return true; } // At this point, at least one target must be a variable // and we'll have to expand the path in that direction. // We might want to permute through the ways we can // take fixable nodes as either fixed or variable, but // we'll be greedy and assume everything fixable is // fixed and everything else is a variable. path.FixedNodes.AddRange(fixabletargetsset); path.VariableNodes.AddRange(variabletargetsset); // But we need to look at all the ways each variable target // can be mapped to a new value, which means intersecting // the possible matches for each relevant edge. Entity[] variables = variabletargetsset.ToEntityArray(); ResSet[] values = new ResSet[variables.Length]; Entity[][] values_array = new Entity[variables.Length][]; int[] choices = new int[variables.Length]; for (int i = 0; i < variables.Length; i++) { foreach (Edge e in newedges) { if (e.End != variables[i]) continue; // Get the possible values this edge allows Resource[] vr; if (e.Direction) vr = msg.SelectObjects((Entity)path.Mapping[e.Start], e.Predicate); else vr = msg.SelectSubjects(e.Predicate, (Entity)path.Mapping[e.Start]); // Filter out literals and any variables // on the path! The two paths can't intersect // except at fixed nodes. ResSet v = new ResSet(); foreach (Resource r in vr) { if (r is Literal) continue; if (path.Mapping.ContainsKey(r)) continue; v.Add(r); } // Intersect these with the values we have already. if (values[i] == null) values[i] = v; else values[i].RetainAll(v); // If no values are available for this variable, // we're totally done. if (values[i].Count == 0) return false; } choices[i] = values[i].Count; values_array[i] = values[i].ToEntityArray(); } // Now we have to permute through the choice of values. // Make an array of the number of choices for each variable. Permutation p = new Permutation(choices); int[] pstate; while ((pstate = p.Next()) != null) { SyncPath newpath = new SyncPath(); newpath.FixedNodes.AddRange(path.FixedNodes); newpath.VariableNodes.AddRange(path.VariableNodes); newpath.Mapping = (Hashtable)path.Mapping.Clone(); newpath.Path = (Hashtable)path.Path.Clone(); newpath.FrontierVariables = variabletargetsset; for (int i = 0; i < variables.Length; i++) { Entity value = values_array[i][pstate[i]]; newpath.Mapping[variables[i]] = value; newpath.FixedNodes.Add(value); } if (MakeLeanMSG3(msg, predicates, removed, nodesremoved, newpath)) return true; } return false; }
private static void MakeLeanMSG2(Store msg, ResSet predicates, StatementSink removed, ResSet nodesremoved, BNode startingnode) { // Find every pair of two distinct outgoing edges from startingnode // with the same predicate, targeting entities only. MultiMap edges = new MultiMap(); foreach (Statement s in msg.Select(new Statement(startingnode, null, null))) if (s.Object is Entity) edges.Put(new Edge(true, startingnode, s.Predicate, null), s.Object); foreach (Statement s in msg.Select(new Statement(null, null, startingnode))) edges.Put(new Edge(false, startingnode, s.Predicate, null), s.Subject); foreach (Edge e in edges.Keys) { // Make sure we have a distinct set of targets. ResSet targets_set = new ResSet(); foreach (Entity r in edges.Get(e)) targets_set.Add(r); if (targets_set.Count == 1) continue; IList targets = targets_set.ToEntityArray(); // Take every pair of targets, provided // one is a bnode that can be a variable. for (int i = 0; i < targets.Count; i++) { if (!(targets[i] is BNode) || predicates.Contains((BNode)targets[i])) continue; if (nodesremoved.Contains((BNode)targets[i])) continue; for (int j = 0; j < targets.Count; j++) { if (i == j) continue; // Create a new synchronous-path object. SyncPath p = new SyncPath(); p.FixedNodes.Add((Resource)targets[j]); p.FrontierVariables.Add((Resource)targets[i]); p.Mapping[targets[i]] = targets[j]; p.Path[new Edge(e.Direction, e.Start, e.Predicate, (BNode)targets[i])] = p.Path; if (MakeLeanMSG3(msg, predicates, removed, nodesremoved, p)) break; // the target was removed } } } }
private static void MakeLeanMSG(Store msg, ICollection bnodecollection, StatementSink removed) { // To make any graph lean, we try to eliminate duplicate // paths through the graph, where duplicate means we // take some subset of the bnodes and call them variables, // and we relabel them as other bnodes from the remaining // set (the fixed nodes). But there are 2^N subsets of bnodes // we could choose as variables (N=number of bnodes), so we can't // reasonably iterate through them. // I'll make a simplifying assumption that bnode predicates // in the graph will be considered always fixed. // This lets us view the graph as actually a graph (with // nodes and edges), and then we can make the observation that // if variable node V is part of a subgraph that can be removed, // if V directly connects to fixed node F via an edge labeled P, // then F must connect to a fixed node G via an edge also // labeled P. That is, we can start our search looking for // nodes that project two edges with the same label. // Also, we only want to consider contiguous 'paths' -- subsets // of the bnodes connected only through those nodes -- // to see if there is another path in the MSG if we // map bnodes in the first path to nodes in the MSG. // So the strategy is to start at each node in the graph // and consider it fixed. If it has two outgoing // edges with the same property and one terminates on a // bnode, this is the beginning of a possible pair // of redundant paths (the one with the bnode being // eliminable). // However, the path with the bnode // has to be incremented with all of that bnode's // outgoing edges. The other path has to be // incremented in parallel, following the same predicates // to other nodes. If that can't be done, then these // paths are not duplicates. If the parallel predicates // terminate on the very same nodes, the bnode and its edges can // be removed. // From there, each of the nodes the bnode edges terminate on, // besides the initial node, can be considered fixed or // a variable. If it's a variable it might be able to have // one of many possible values, but then the path has to // be expanded to include all of the outgoing edges for this // variable. // Ok, here we go. // If there is only one bnode in the MSG, then // there are no subgraphs to check. That's nice. if (bnodecollection.Count == 1) return; // Remember which bnodes have been removed in // due course. ResSet nodesremoved = new ResSet(); // Remember which nodes are predicates and can't // be considered variable. ResSet predicates = new ResSet(); foreach (Statement s in msg.Select(Statement.All)) predicates.Add(s.Predicate); // Start with each bnode to consider fixed. foreach (BNode b in bnodecollection) { if (nodesremoved.Contains(b)) continue; MakeLeanMSG2(msg, predicates, removed, nodesremoved, b); } }
protected void TestReasoner(DalcRdfStore dalcStore) { var store = new Store(dalcStore); Euler engine = new Euler(new N3Reader(new StringReader(eulerRules))); store.AddReasoner(engine); Console.WriteLine( "Is Adam a parent of Bill? "+ store.Contains( new Statement(baseNs + "persons#1", baseNs + "terms#is_parent", (Entity)(baseNs + "persons#4"))).ToString()); Console.WriteLine( "Is Eve a parent of Bill? " + store.Contains( new Statement(baseNs + "persons#2", baseNs + "terms#is_parent", (Entity)(baseNs + "persons#4"))).ToString()); Console.Write("Children of Eve: "); var res = store.Select(new Statement(null, baseNs + "terms#is_child", (Entity)(baseNs + "persons#2") )); foreach (var st in res) { var nameRes = store.Select( new Statement( st.Subject.Uri, ns_foaf_name, null) ); Console.Write(String.Format("({0})", dalcStore.GetDataKey(st.Subject).Id)); foreach (var nameSt in nameRes) Console.Write( nameSt.Object.ToString() + " "); } Console.WriteLine(); }
private GraphMatch(Store queryModel, Entity queryNode) { // Find the query options if (queryNode != null) { ReturnStart = GetIntOption(queryModel, queryNode, qStart); ReturnLimit = GetIntOption(queryModel, queryNode, qLimit); } // Search the query for 'distinct' predicates between variables. foreach (Statement s in queryModel.Select(new Statement(null, qDistinctFrom, null))) { if (!(s.Object is BNode)) continue; MakeDistinct((BNode)s.Subject, (BNode)s.Object); } // Add all statements except the query predicates and value filters into a // new store with just the statements relevant to the search. foreach (Statement s in queryModel.Select(Statement.All)) { if (IsQueryPredicate(s.Predicate)) continue; /*if (s.Predicate.Uri != null && extraValueFilters != null && extraValueFilters.Contains(s.Predicate.Uri)) { ValueFilterFactory f = (ValueFilterFactory)extraValueFilters[s.Predicate.Uri]; AddValueFilter(s.Subject, f.GetValueFilter(s.Predicate.Uri, s.Object)); continue; } else { ValueFilter f = ValueFilter.GetValueFilter(s.Predicate, s.Object); if (f != null) { AddValueFilter(s.Subject, f); continue; } }*/ if (s.Meta == Statement.DefaultMeta) AddEdge(s); else if (queryNode != null && queryModel.Contains(new Statement(queryNode, qOptional, s.Meta))) AddOptionalEdge(s); } }