/// <summary> /// Left Joins the Multiset to another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <param name="expr">Expression which the Join is predicated on</param> /// <returns>The other Multiset</returns> public override BaseMultiset LeftJoin(BaseMultiset other, ISparqlExpression expr) { //If Other is Null/Empty then the Join still results in Identity if (other is NullMultiset) return this; if (other.IsEmpty) return this; return other; }
/// <summary> /// Calculates the product of two mutlisets asynchronously with a timeout to restrict long running computations /// </summary> /// <param name="multiset">Multiset</param> /// <param name="other">Other Multiset</param> /// <param name="timeout">Timeout, if <=0 no timeout is used and product will be computed sychronously</param> /// <returns></returns> public static BaseMultiset ProductWithTimeout(this BaseMultiset multiset, BaseMultiset other, long timeout) { if (other is IdentityMultiset) return multiset; if (other is NullMultiset) return other; if (other.IsEmpty) return new NullMultiset(); if (timeout <= 0) { return multiset.Product(other); } //Invoke using an Async call Multiset productSet = new Multiset(); StopToken stop = new StopToken(); GenerateProductDelegate d = new GenerateProductDelegate(GenerateProduct); IAsyncResult r = d.BeginInvoke(multiset, other, productSet, stop, null, null); //Wait int t = (int)Math.Min(timeout, Int32.MaxValue); r.AsyncWaitHandle.WaitOne(t); if (!r.IsCompleted) { stop.ShouldStop = true; r.AsyncWaitHandle.WaitOne(); } return productSet; }
public void Fill(BaseMultiset multiset) { foreach (ISet s in multiset.Sets) { this.ProcessResult(new SparqlResult(s)); } }
/// <summary> /// Calculates the product of two mutlisets asynchronously with a timeout to restrict long running computations /// </summary> /// <param name="multiset">Multiset</param> /// <param name="other">Other Multiset</param> /// <param name="timeout">Timeout, if <=0 no timeout is used and product will be computed sychronously</param> /// <returns></returns> public static BaseMultiset ProductWithTimeout(this BaseMultiset multiset, BaseMultiset other, long timeout) { if (other is IdentityMultiset) { return(multiset); } if (other is NullMultiset) { return(other); } if (other.IsEmpty) { return(new NullMultiset()); } //If no timeout use default implementation if (timeout <= 0) { return(multiset.Product(other)); } //Otherwise Invoke using an Async call BaseMultiset productSet; #if NET40 && !SILVERLIGHT if (Options.UsePLinqEvaluation) { if (multiset.Count >= other.Count) { productSet = new PartitionedMultiset(multiset.Count, other.Count); } else { productSet = new PartitionedMultiset(other.Count, multiset.Count); } } else { #endif productSet = new Multiset(); #if NET40 && !SILVERLIGHT } #endif StopToken stop = new StopToken(); GenerateProductDelegate d = new GenerateProductDelegate(GenerateProduct); IAsyncResult r = d.BeginInvoke(multiset, other, productSet, stop, null, null); //Wait int t = (int)Math.Min(timeout, Int32.MaxValue); r.AsyncWaitHandle.WaitOne(t); if (!r.IsCompleted) { stop.ShouldStop = true; r.AsyncWaitHandle.WaitOne(); } return(productSet); }
/// <summary> /// Determines whether this Multiset is disjoint with another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <returns></returns> public override bool IsDisjointWith(BaseMultiset other) { if (other is IdentityMultiset || other is NullMultiset) { return(false); } return(this.Variables.All(v => !other.ContainsVariable(v))); }
/// <summary> /// Creates a new Evaluation Context for the given Query over the given Dataset /// </summary> /// <param name="q">Query</param> /// <param name="data">Dataset</param> public SparqlEvaluationContext(SparqlQuery q, ISparqlDataset data) { this._query = q; this._data = data; this._inputSet = new IdentityMultiset(); this._binder = new LeviathanResultBinder(this); this.CalculateTimeout(); }
/// <summary> /// Evaluates the Union /// </summary> /// <param name="context"></param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { //Create a copy of the evaluation context for the RHS SparqlEvaluationContext context2 = new SparqlEvaluationContext(context.Query, context.Data, context.Processor); if (!(context.InputMultiset is IdentityMultiset)) { context2.InputMultiset = new Multiset(); foreach (ISet s in context.InputMultiset.Sets) { context2.InputMultiset.Add(s.Copy()); } } List <Uri> activeGraphs = context.Data.ActiveGraphUris.ToList(); List <Uri> defaultGraphs = context.Data.DefaultGraphUris.ToList(); ParallelEvaluateDelegate d = new ParallelEvaluateDelegate(this.ParallelEvaluate); IAsyncResult lhs = d.BeginInvoke(this._lhs, context, activeGraphs, defaultGraphs, null, null); IAsyncResult rhs = d.BeginInvoke(this._rhs, context2, activeGraphs, defaultGraphs, null, null); WaitHandle.WaitAll(new WaitHandle[] { lhs.AsyncWaitHandle, rhs.AsyncWaitHandle }); bool rhsOk = false; try { BaseMultiset lhsResult = d.EndInvoke(lhs); rhsOk = true; BaseMultiset rhsResult = d.EndInvoke(rhs); context.CheckTimeout(); context.OutputMultiset = lhsResult.Union(rhsResult); context.CheckTimeout(); context.InputMultiset = context.OutputMultiset; return(context.OutputMultiset); } catch { if (!rhsOk) { //Clean up the RHS evaluation call if the LHS has errored try { d.EndInvoke(rhs); } catch { //Ignore this error as we're already going to throw the other error } } throw; } }
/// <summary> /// Evaluates the Algebra in the given context /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { //First evaluate the inner algebra BaseMultiset results = context.Evaluate(this._inner); context.OutputMultiset = new Multiset(); if (results is NullMultiset) { context.OutputMultiset = results; } else if (results is IdentityMultiset) { context.OutputMultiset.AddVariable(this._var); Set s = new Set(); try { INode temp = this._expr.Evaluate(context, 0); s.Add(this._var, temp); } catch { //No assignment if there's an error s.Add(this._var, null); } context.OutputMultiset.Add(s.Copy()); } else { if (results.ContainsVariable(this._var)) { throw new RdfQueryException("Cannot assign to the variable ?" + this._var + "since it has previously been used in the Query"); } context.InputMultiset = results; context.OutputMultiset.AddVariable(this._var); #if NET40 && !SILVERLIGHT if (Options.UsePLinqEvaluation && this._expr.CanParallelise) { results.SetIDs.AsParallel().ForAll(id => EvalExtend(context, results, id)); } else { #endif foreach (int id in results.SetIDs) { EvalExtend(context, results, id); } #if NET40 && !SILVERLIGHT } #endif } return(context.OutputMultiset); }
/// <summary> /// Evaluates the Algebra in the given context /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { //First evaluate the inner algebra BaseMultiset results = context.Evaluate(this._inner); context.OutputMultiset = new Multiset(); if (results is NullMultiset) { context.OutputMultiset = results; } else if (results is IdentityMultiset) { context.OutputMultiset.AddVariable(this._var); Set s = new Set(); try { INode temp = this._expr.Evaluate(context, 0); s.Add(this._var, temp); } catch { //No assignment if there's an error s.Add(this._var, null); } context.OutputMultiset.Add(s.Copy()); } else { if (results.ContainsVariable(this._var)) { throw new RdfQueryException("Cannot use a BIND assigment to BIND to a variable that has previously been used in the Query"); } context.OutputMultiset.AddVariable(this._var); foreach (int id in results.SetIDs.ToList()) { ISet s = results[id].Copy(); try { //Make a new assignment INode temp = this._expr.Evaluate(context, id); s.Add(this._var, temp); } catch { //No assignment if there's an error but the solution is preserved } context.OutputMultiset.Add(s); } } return(context.OutputMultiset); }
private void EvalProduct(ISet x, BaseMultiset other, PartitionedMultiset productSet) { int id = productSet.GetNextBaseID(); foreach (ISet y in other.Sets) { id++; ISet z = x.Join(y); z.ID = id; productSet.Add(z); } }
private void RhsCallback(IAsyncResult result) { try { this._rhsResult = this._d.EndInvoke(result); } catch (Exception ex) { this._rhsError = ex; this._rhsResult = null; } }
/// <summary> /// Calculates the product of two multi-sets asynchronously with a timeout to restrict long running computations. /// </summary> /// <param name="multiset">Multiset.</param> /// <param name="other">Other Multiset.</param> /// <param name="timeout">Timeout, if <=0 no timeout is used and product will be computed synchronously.</param> /// <returns></returns> public static BaseMultiset ProductWithTimeout(this BaseMultiset multiset, BaseMultiset other, long timeout) { if (other is IdentityMultiset) { return(multiset); } if (other is NullMultiset) { return(other); } if (other.IsEmpty) { return(new NullMultiset()); } // If no timeout use default implementation if (timeout <= 0) { return(multiset.Product(other)); } // Otherwise Invoke using an Async call BaseMultiset productSet; if (Options.UsePLinqEvaluation) { if (multiset.Count >= other.Count) { productSet = new PartitionedMultiset(multiset.Count, other.Count); } else { productSet = new PartitionedMultiset(other.Count, multiset.Count); } } else { productSet = new Multiset(); } var stop = new StopToken(); var t = (int)Math.Min(timeout, int.MaxValue); var productTask = Task.Factory.StartNew(() => GenerateProduct(multiset, other, productSet, stop)); if (!productTask.Wait(t)) { stop.ShouldStop = true; productTask.Wait(); } return(productSet); }
/// <summary> /// Left Joins the Multiset to another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <param name="expr">Expression which the Join is predicated on</param> /// <returns>The other Multiset</returns> public override BaseMultiset LeftJoin(BaseMultiset other, ISparqlExpression expr) { //If Other is Null/Empty then the Join still results in Identity if (other is NullMultiset) { return(this); } if (other.IsEmpty) { return(this); } return(other); }
/// <summary> /// Generates the Union of this Set and another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <returns>The other Multiset</returns> public override BaseMultiset Union(BaseMultiset other) { //If Other is Null/Empty then the Join still results in Identity if (other is NullMultiset) { return(this); } if (other.IsEmpty) { return(this); } return(other); }
/// <summary> /// Determines the starting points for Path evaluation /// </summary> /// <param name="context">Evaluation Context</param> /// <param name="paths">Paths</param> /// <param name="reverse">Whether to evaluate Paths in reverse</param> protected void GetPathStarts(SparqlEvaluationContext context, List <List <INode> > paths, bool reverse) { HashSet <KeyValuePair <INode, INode> > nodes = new HashSet <KeyValuePair <INode, INode> >(); if (this.Path is Property) { INode predicate = ((Property)this.Path).Predicate; foreach (Triple t in context.Data.GetTriplesWithPredicate(predicate)) { if (reverse) { nodes.Add(new KeyValuePair <INode, INode>(t.Object, t.Subject)); } else { nodes.Add(new KeyValuePair <INode, INode>(t.Subject, t.Object)); } } } else { BaseMultiset initialInput = context.InputMultiset; context.InputMultiset = new IdentityMultiset(); VariablePattern x = new VariablePattern("?x"); VariablePattern y = new VariablePattern("?y"); Bgp bgp = new Bgp(new PropertyPathPattern(x, this.Path, y)); BaseMultiset results = context.Evaluate(bgp); //bgp.Evaluate(context); context.InputMultiset = initialInput; if (!results.IsEmpty) { foreach (ISet s in results.Sets) { if (s["x"] != null && s["y"] != null) { if (reverse) { nodes.Add(new KeyValuePair <INode, INode>(s["y"], s["x"])); } else { nodes.Add(new KeyValuePair <INode, INode>(s["x"], s["y"])); } } } } } paths.AddRange(nodes.Select(kvp => new List <INode>(new INode[] { kvp.Key, kvp.Value }))); }
/// <summary> /// Does a Product of this Multiset and another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <returns></returns> public virtual BaseMultiset Product(BaseMultiset other) { if (other is IdentityMultiset) { return(this); } if (other is NullMultiset) { return(other); } if (other.IsEmpty) { return(new NullMultiset()); } #if NET40 && !SILVERLIGHT if (Options.UsePLinqEvaluation) { //Determine partition sizes so we can do a parallel product //Want to parallelize over whichever side is larger PartitionedMultiset partitionedSet; if (this.Count >= other.Count) { partitionedSet = new PartitionedMultiset(this.Count, other.Count); this.Sets.AsParallel().ForAll(x => this.EvalProduct(x, other, partitionedSet)); } else { partitionedSet = new PartitionedMultiset(other.Count, this.Count); other.Sets.AsParallel().ForAll(y => this.EvalProduct(y, this, partitionedSet)); } return(partitionedSet); } else { #endif //Use serial calculation which is likely to really suck for big products Multiset productSet = new Multiset(); foreach (ISet x in this.Sets) { foreach (ISet y in other.Sets) { productSet.Add(x.Join(y)); } } return(productSet); #if NET40 && !SILVERLIGHT } #endif }
/// <summary> /// Joins this Multiset to another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <returns></returns> public override BaseMultiset Join(BaseMultiset other) { //If the Other is the Identity Multiset the result is this Multiset if (other is IdentityMultiset) { return(this); } //If the Other is the Null Multiset the result is the Null Multiset if (other is NullMultiset) { return(other); } //If the Other is Empty then the result is the Null Multiset if (other.IsEmpty) { return(new NullMultiset()); } //Find the First Variable from this Multiset which is in both Multisets //If there is no Variable from this Multiset in the other Multiset then this //should be a Join operation instead of a LeftJoin List <String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList(); if (joinVars.Count == 0) { return(this.Product(other)); } //Start building the Joined Set Multiset joinedSet = new Multiset(); foreach (ISet x in this.Sets) { //For sets to be compatible for every joinable variable they must either have a null for the //variable in one of the sets or if they have values the values must be equal ////This first check is to try speed things up, it looks whether there are solutions that may match ////without needing to do a full table scan of the RHS results as the subsequent LINQ call will do ////if (!joinVars.All(v => x[v] == null || other.ContainsValue(v, x[v]) || other.ContainsValue(v, null))) continue; IEnumerable <ISet> ys = other.Sets.Where(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v]))); //IEnumerable<ISet> ys = other.Sets.Where(s => s.IsCompatibleWith(x, joinVars)); foreach (ISet y in ys) { joinedSet.Add(x.Join(y)); } } return(joinedSet); }
/// <summary> /// Exists Joins the Multiset to another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <param name="mustExist">Whether solutions must exist in the Other Multiset for the Join to suceed</param> /// <returns></returns> public override BaseMultiset ExistsJoin(BaseMultiset other, bool mustExist) { if (mustExist) { if (other is NullMultiset) return other; return this; } else { if (other is NullMultiset) return this; if (other is IdentityMultiset) return new NullMultiset(); return this; } }
/// <summary> /// Evaluates the BGP against the Evaluation Context /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { bool halt; BaseMultiset results = this.StreamingEvaluate(context, 0, out halt); if (results is Multiset && results.IsEmpty) { results = new NullMultiset(); } context.OutputMultiset = results; context.OutputMultiset.Trim(); return(context.OutputMultiset); }
/// <summary> /// Method for generating product of two multisets asynchronously /// </summary> /// <param name="multiset">Multiset</param> /// <param name="other">Other Multiset</param> /// <param name="target">Mutliset to generate the product in</param> /// <param name="stop">Stop Token</param> private static void GenerateProduct(BaseMultiset multiset, BaseMultiset other, BaseMultiset target, StopToken stop) { foreach (ISet x in multiset.Sets) { foreach (ISet y in other.Sets) { target.Add(x.Join(y)); //if (stop.ShouldStop) break; } if (stop.ShouldStop) { break; } } }
private void EvalExtend(SparqlEvaluationContext context, BaseMultiset results, int id) { ISet s = results[id].Copy(); try { // Make a new assignment INode temp = _expr.Evaluate(context, id); s.Add(_var, temp); } catch { // No assignment if there's an error but the solution is preserved } context.OutputMultiset.Add(s); }
public void SparqlAlgebraJoinSingleVariable1() { ISet x = new Set(); x.Add("a", this._factory.CreateUriNode(UriFactory.Create("http://x"))); BaseMultiset lhs = new Multiset(); lhs.Add(x); BaseMultiset rhs = new Multiset(); rhs.Add(x); BaseMultiset joined = lhs.Join(rhs); Assert.AreEqual(1, joined.Count); }
/// <summary> /// Does a Union of this Multiset and another Multiset. /// </summary> /// <param name="other">Other Multiset.</param> /// <returns></returns> public override BaseMultiset Union(BaseMultiset other) { if (other is IdentityMultiset) return this; if (other is NullMultiset) return this; if (other.IsEmpty) return this; Multiset m = new Multiset(); foreach (ISet s in this.Sets) { m.Add(s.Copy()); } foreach (ISet s in other.Sets) { m.Add(s.Copy()); } return m; }
/// <summary> /// Evaluates the Path in the given context. /// </summary> /// <param name="context">Evaluation Context.</param> /// <returns></returns> public override BaseMultiset Evaluate(SparqlEvaluationContext context) { // Try and generate an Algebra expression // Make sure we don't generate clashing temporary variable IDs over the life of the // Evaluation PathTransformContext transformContext = new PathTransformContext(PathStart, PathEnd); if (context["PathTransformID"] != null) { transformContext.NextID = (int)context["PathTransformID"]; } ISparqlAlgebra algebra = Path.ToAlgebra(transformContext); context["PathTransformID"] = transformContext.NextID; // Now we can evaluate the resulting algebra BaseMultiset initialInput = context.InputMultiset; bool trimMode = context.TrimTemporaryVariables; bool rigMode = Options.RigorousEvaluation; try { // Must enable rigorous evaluation or we get incorrect interactions between property and non-property path patterns Options.RigorousEvaluation = true; // Note: We may need to preserve Blank Node variables across evaluations // which we usually don't do BUT because of the way we translate only part of the path // into an algebra at a time and may need to do further nested translate calls we do // need to do this here context.TrimTemporaryVariables = false; BaseMultiset result = context.Evaluate(algebra); // Also note that we don't trim temporary variables here even if we've set the setting back // to enabled since a Trim will be done at the end of whatever BGP we are being evaluated in // Once we have our results can join then into our input context.OutputMultiset = initialInput.Join(result); } finally { context.TrimTemporaryVariables = trimMode; Options.RigorousEvaluation = rigMode; } return(context.OutputMultiset); }
/// <summary> /// Evaluates the BINDINGS modifier /// </summary> /// <param name="context">Evaluation Context</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { //Evalute the Pattern BaseMultiset results = context.Evaluate(this._pattern);//this._pattern.Evaluate(context); //If the result is Null/Identity/Empty if (results is NullMultiset || results is IdentityMultiset || results.IsEmpty) { context.OutputMultiset = results; return(results); } else { //Result is an Join from the results to the Input Bindings context.OutputMultiset = results.Join(this._bindings.ToMultiset()); return(context.OutputMultiset); } }
/// <summary> /// Creates a new Group Multiset /// </summary> /// <param name="contents">Multiset which contains the Member Sets of the Groups</param> /// <param name="groups">Groups</param> public GroupMultiset(BaseMultiset contents, List<BindingGroup> groups) { this._contents = contents; this._groups = groups; bool first = true; foreach (BindingGroup group in groups) { Set s = new Set(); foreach (KeyValuePair<String, INode> assignment in group.Assignments) { if (first) this.AddVariable(assignment.Key); s.Add(assignment.Key, assignment.Value); } first = false; base.Add(s); } }
/// <summary> /// Evaluates the Union /// </summary> /// <param name="context"></param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset initialInput = context.InputMultiset; BaseMultiset lhsResult = context.Evaluate(this._lhs);//this._lhs.Evaluate(context); context.CheckTimeout(); context.InputMultiset = initialInput; BaseMultiset rhsResult = context.Evaluate(this._rhs);//this._rhs.Evaluate(context); context.CheckTimeout(); context.OutputMultiset = lhsResult.Union(rhsResult); context.CheckTimeout(); context.InputMultiset = context.OutputMultiset; return(context.OutputMultiset); }
private static void EvalProduct(ISet x, BaseMultiset other, PartitionedMultiset productSet, StopToken stop) { if (stop.ShouldStop) { return; } var id = productSet.GetNextBaseID(); foreach (var y in other.Sets) { id++; var z = x.Join(y); z.ID = id; productSet.Add(z); if (stop.ShouldStop) { return; } } }
/// <summary> /// Does a Minus Join of this Multiset to another Multiset where any joinable results are subtracted from this Multiset to give the resulting Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <returns></returns> public override BaseMultiset MinusJoin(BaseMultiset other) { //If the other Multiset is the Identity/Null Multiset then minus-ing it doesn't alter this set if (other is IdentityMultiset) { return(this); } if (other is NullMultiset) { return(this); } //If the other Multiset is disjoint then minus-ing it also doesn't alter this set if (this.IsDisjointWith(other)) { return(this); } //Find the Variables that are to be used for Joining List <String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList(); if (joinVars.Count == 0) { return(this.Product(other)); } //Start building the Joined Set Multiset joinedSet = new Multiset(); foreach (ISet x in this.Sets) { //New Minus logic based on the improved Join() logic bool minus = other.Sets.Any(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v]))); //If no compatible sets then this set is preserved if (!minus) { joinedSet.Add(x); } } return(joinedSet); }
/// <summary> /// Does a Union of this Multiset and another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <returns></returns> public override BaseMultiset Union(BaseMultiset other) { if (other is IdentityMultiset) { return(this); } if (other is NullMultiset) { return(this); } if (other.IsEmpty) { return(this); } foreach (ISet s in other.Sets) { this.Add(s); } return(this); }
/// <summary> /// Does a Union of this Multiset and another Multiset. /// </summary> /// <param name="other">Other Multiset.</param> /// <returns></returns> public virtual BaseMultiset Union(BaseMultiset other) { if (other is IdentityMultiset) { return(this); } if (other is NullMultiset) { return(this); } if (other.IsEmpty) { return(this); } foreach (ISet s in other.Sets) { Add(s.Copy()); } return(this); }
private void EvalLeftJoinProduct(ISet x, BaseMultiset other, PartitionedMultiset partitionedSet, ISparqlExpression expr) { LeviathanLeftJoinBinder binder = new LeviathanLeftJoinBinder(partitionedSet); SparqlEvaluationContext subcontext = new SparqlEvaluationContext(binder); bool standalone = false, matched = false; int id = partitionedSet.GetNextBaseID(); foreach (ISet y in other.Sets) { id++; ISet z = x.Join(y); z.ID = id; try { partitionedSet.Add(z); if (!expr.Evaluate(subcontext, z.ID).AsSafeBoolean()) { partitionedSet.Remove(z.ID); standalone = true; } else { matched = true; } } catch { partitionedSet.Remove(z.ID); standalone = true; } } if (standalone && !matched) { id++; ISet z = x.Copy(); z.ID = id; partitionedSet.Add(z); } }
/// <summary> /// Creates a new Group Multiset /// </summary> /// <param name="contents">Multiset which contains the Member Sets of the Groups</param> /// <param name="groups">Groups</param> public GroupMultiset(BaseMultiset contents, List <BindingGroup> groups) { this._contents = contents; bool first = true; foreach (BindingGroup group in groups) { Set s = new Set(); foreach (KeyValuePair <String, INode> assignment in group.Assignments) { if (first) { this.AddVariable(assignment.Key); } s.Add(assignment.Key, assignment.Value); } first = false; base.Add(s); this._groups.Add(s.ID, group); } }
/// <summary> /// Exists Joins the Multiset to another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <param name="mustExist">Whether solutions must exist in the Other Multiset for the Join to suceed</param> /// <returns></returns> public override BaseMultiset ExistsJoin(BaseMultiset other, bool mustExist) { if (mustExist) { if (other is NullMultiset) { return(other); } return(this); } else { if (other is NullMultiset) { return(this); } if (other is IdentityMultiset) { return(new NullMultiset()); } return(this); } }
/// <summary> /// Evaluates the Minus join by evaluating the LHS and RHS and substracting the RHS results from the LHS. /// </summary> /// <param name="context">Evaluation Context.</param> /// <returns></returns> public BaseMultiset Evaluate(SparqlEvaluationContext context) { BaseMultiset initialInput = context.InputMultiset; BaseMultiset lhsResult = context.Evaluate(_lhs);//this._lhs.Evaluate(context); context.CheckTimeout(); if (lhsResult is NullMultiset) { context.OutputMultiset = lhsResult; } else if (lhsResult.IsEmpty) { context.OutputMultiset = new NullMultiset(); } else if (_lhs.Variables.IsDisjoint(_rhs.Variables)) { // If the RHS is disjoint then there is no need to evaluate the RHS context.OutputMultiset = lhsResult; } else { // If we get here then the RHS is not disjoint so it does affect the ouput // Only execute the RHS if the LHS had results // context.InputMultiset = lhsResult; context.InputMultiset = initialInput; BaseMultiset rhsResult = context.Evaluate(_rhs);//this._rhs.Evaluate(context); context.CheckTimeout(); context.OutputMultiset = lhsResult.MinusJoin(rhsResult); context.CheckTimeout(); } context.InputMultiset = context.OutputMultiset; return(context.OutputMultiset); }
/// <summary> /// Calculates the product of two mutlisets asynchronously with a timeout to restrict long running computations /// </summary> /// <param name="multiset">Multiset</param> /// <param name="other">Other Multiset</param> /// <param name="timeout">Timeout, if <=0 no timeout is used and product will be computed sychronously</param> /// <returns></returns> public static BaseMultiset ProductWithTimeout(this BaseMultiset multiset, BaseMultiset other, long timeout) { if (other is IdentityMultiset) { return(multiset); } if (other is NullMultiset) { return(other); } if (other.IsEmpty) { return(new NullMultiset()); } if (timeout <= 0) { return(multiset.Product(other)); } //Invoke using an Async call Multiset productSet = new Multiset(); StopToken stop = new StopToken(); GenerateProductDelegate d = new GenerateProductDelegate(GenerateProduct); IAsyncResult r = d.BeginInvoke(multiset, other, productSet, stop, null, null); //Wait int t = (int)Math.Min(timeout, Int32.MaxValue); r.AsyncWaitHandle.WaitOne(t); if (!r.IsCompleted) { stop.ShouldStop = true; r.AsyncWaitHandle.WaitOne(); } return(productSet); }
/// <summary> /// Does a Minus Join of this Multiset to another Multiset where any joinable results are subtracted from this Multiset to give the resulting Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <returns></returns> public override BaseMultiset MinusJoin(BaseMultiset other) { //If the other Multiset is the Identity/Null Multiset then minus-ing it doesn't alter this set if (other is IdentityMultiset) return this; if (other is NullMultiset) return this; //If the other Multiset is disjoint then minus-ing it also doesn't alter this set if (this.IsDisjointWith(other)) return this; //Find the Variables that are to be used for Joining List<String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList(); if (joinVars.Count == 0) return this.Product(other); //Start building the Joined Set Multiset joinedSet = new Multiset(); //This is the old algorithm which is correct but naive and has O(n^2) complexity //foreach (ISet x in this.Sets) //{ // //New Minus logic based on the improved Join() logic // bool minus = other.Sets.Any(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v]))); // //If no compatible sets then this set is preserved // if (!minus) // { // joinedSet.Add(x); // } //} //This is the new algorithm which is also correct but is O(3n) so much faster and scalable //Downside is that it does require more memory than the old algorithm List<HashTable<INode, int>> values = new List<HashTable<INode, int>>(); List<List<int>> nulls = new List<List<int>>(); foreach (String var in joinVars) { values.Add(new HashTable<INode, int>(HashTableBias.Enumeration)); nulls.Add(new List<int>()); } //First do a pass over the LHS Result to find all possible values for joined variables foreach (ISet x in this.Sets) { int i = 0; foreach (String var in joinVars) { INode value = x[var]; if (value != null) { values[i].Add(value, x.ID); } else { nulls[i].Add(x.ID); } i++; } } //Then do a pass over the RHS and work out the intersections HashSet<int> toMinus = new HashSet<int>(); foreach (ISet y in other.Sets) { IEnumerable<int> possMatches = null; int i = 0; foreach (String var in joinVars) { INode value = y[var]; if (value != null) { if (values[i].ContainsKey(value)) { possMatches = (possMatches == null ? values[i].GetValues(value).Concat(nulls[i]) : possMatches.Intersect(values[i].GetValues(value).Concat(nulls[i]))); } else { possMatches = Enumerable.Empty<int>(); break; } } else { //Don't forget that a null will be potentially compatible with everything possMatches = (possMatches == null ? this.SetIDs : possMatches.Intersect(this.SetIDs)); } i++; } if (possMatches == null) continue; //Look at possible matches, if is a valid match then mark the matched set for minus'ing //Don't reconsider sets which have already been marked for minusing foreach (int poss in possMatches) { if (toMinus.Contains(poss)) continue; if (this._sets[poss].IsCompatibleWith(y, joinVars)) { toMinus.Add(poss); } } } //Apply the actual minus if (toMinus.Count == this.Count) { //If number of sets to minus is equal to number of sets then we're minusing everything return new NullMultiset(); } else { //Otherwise iterate foreach (ISet x in this.Sets) { if (!toMinus.Contains(x.ID)) { joinedSet.Add(x.Copy()); } } } return joinedSet; }
/// <summary> /// Unions this Multiset with another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <returns> /// Results in the Other Multiset as this is an empty Multiset /// </returns> public override BaseMultiset Union(BaseMultiset other) { //Union results in Other Multiset return other; }
/// <summary> /// Does a Union of this Multiset and another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <returns></returns> public override BaseMultiset Union(BaseMultiset other) { if (other is IdentityMultiset) return this; if (other is NullMultiset) return this; if (other.IsEmpty) return this; foreach (ISet s in other.Sets) { this.Add(s.Copy()); } return this; }
/// <summary> /// Exists Joins another Multiset to this Null Mutliset /// </summary> /// <param name="other">Other Multiset</param> /// <param name="mustExist">Whether joinable solutions must exist in the other Multiset for joins to be made</param> /// <returns> /// Results in this Null Multiset since Null joined to anything is Null /// </returns> public override BaseMultiset ExistsJoin(BaseMultiset other, bool mustExist) { return this; }
/// <summary> /// Minus Join is a special type of Join which only preserves sets from this Multiset which cannot be joined to the other Multiset /// </summary> /// <param name="other">Multiset to join with</param> /// <returns></returns> public abstract BaseMultiset MinusJoin(BaseMultiset other);
/// <summary> /// Union combines two concatenates two mutlisets /// </summary> /// <param name="other">Multiset to concatenate with</param> /// <returns></returns> public abstract BaseMultiset Union(BaseMultiset other);
/// <summary> /// Left Join combines two multisets where the join is predicated on an arbitrary expression /// </summary> /// <param name="other">Multiset to join with</param> /// <param name="expr">Expression on which the Join is predicated</param> /// <returns></returns> /// <remarks> /// Used for doing OPTIONALs /// </remarks> public abstract BaseMultiset LeftJoin(BaseMultiset other, ISparqlExpression expr);
/// <summary> /// Does an Exists Join of this Multiset to another Multiset where the Join is predicated on the existence/non-existence of a joinable solution on the RHS /// </summary> /// <param name="other">Other Multiset</param> /// <param name="mustExist">Whether a solution must exist in the Other Multiset for the join to be made</param> /// <returns></returns> public override BaseMultiset ExistsJoin(BaseMultiset other, bool mustExist) { //For EXISTS and NOT EXISTS if the other is the Identity then it has no effect if (other is IdentityMultiset) return this; if (mustExist) { //If an EXISTS then Null/Empty Other results in Null if (other is NullMultiset) return other; if (other.IsEmpty) return new NullMultiset(); } else { //If a NOT EXISTS then Null/Empty results in this if (other is NullMultiset) return this; if (other.IsEmpty) return this; } //Find the Variables that are to be used for Joining List<String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList(); if (joinVars.Count == 0) { //All Disjoint Solutions are compatible if (mustExist) { //If an EXISTS and disjoint then result is this return this; } else { //If a NOT EXISTS and disjoint then result is null return new NullMultiset(); } } //Start building the Joined Set Multiset joinedSet = new Multiset(); //This is the old algorithm which is correct but naive with worse case O(n^2) //foreach (ISet x in this.Sets) //{ // //New ExistsJoin() logic based on the improved Join() logic // bool exists = other.Sets.Any(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v]))); // //bool exists = other.Sets.Any(s => s.IsCompatibleWith(x, joinVars)); // if (exists) // { // //If there are compatible sets and this is an EXIST then preserve the solution // if (mustExist) joinedSet.Add(x); // } // else // { // //If there are no compatible sets and this is a NOT EXISTS then preserve the solution // if (!mustExist) joinedSet.Add(x); // } //} //This is the new algorithm which is also correct but is O(3n) so much faster and scalable //Downside is that it does require more memory than the old algorithm List<HashTable<INode, int>> values = new List<HashTable<INode, int>>(); List<List<int>> nulls = new List<List<int>>(); foreach (String var in joinVars) { values.Add(new HashTable<INode, int>(HashTableBias.Enumeration)); nulls.Add(new List<int>()); } //First do a pass over the LHS Result to find all possible values for joined variables foreach (ISet x in this.Sets) { int i = 0; foreach (String var in joinVars) { INode value = x[var]; if (value != null) { values[i].Add(value, x.ID); } else { nulls[i].Add(x.ID); } i++; } } //Then do a pass over the RHS and work out the intersections HashSet<int> exists = new HashSet<int>(); foreach (ISet y in other.Sets) { IEnumerable<int> possMatches = null; int i = 0; foreach (String var in joinVars) { INode value = y[var]; if (value != null) { if (values[i].ContainsKey(value)) { possMatches = (possMatches == null ? values[i].GetValues(value).Concat(nulls[i]) : possMatches.Intersect(values[i].GetValues(value).Concat(nulls[i]))); } else { possMatches = Enumerable.Empty<int>(); break; } } else { //Don't forget that a null will be potentially compatible with everything possMatches = (possMatches == null ? this.SetIDs : possMatches.Intersect(this.SetIDs)); } i++; } if (possMatches == null) continue; //Look at possible matches, if is a valid match then mark the set as having an existing match //Don't reconsider sets which have already been marked as having an existing match foreach (int poss in possMatches) { if (exists.Contains(poss)) continue; if (this._sets[poss].IsCompatibleWith(y, joinVars)) { exists.Add(poss); } } } //Apply the actual exists if (exists.Count == this.Count) { //If number of sets that have a match is equal to number of sets then we're either returning everything or nothing if (mustExist) { return this; } else { return new NullMultiset(); } } else { //Otherwise iterate foreach (ISet x in this.Sets) { if (mustExist) { if (exists.Contains(x.ID)) { joinedSet.Add(x.Copy()); } } else { if (!exists.Contains(x.ID)) { joinedSet.Add(x.Copy()); } } } } return joinedSet; }
/// <summary> /// Does a Left Join of this Multiset to another Multiset where the Join is predicated on the given Expression /// </summary> /// <param name="other">Other Multiset</param> /// <param name="expr">Expression</param> /// <returns></returns> public override BaseMultiset LeftJoin(BaseMultiset other, ISparqlExpression expr) { //If the Other is the Identity/Null Multiset the result is this Multiset if (other is IdentityMultiset) return this; if (other is NullMultiset) return this; if (other.IsEmpty) return this; Multiset joinedSet = new Multiset(); LeviathanLeftJoinBinder binder = new LeviathanLeftJoinBinder(joinedSet); SparqlEvaluationContext subcontext = new SparqlEvaluationContext(binder); //Find the First Variable from this Multiset which is in both Multisets //If there is no Variable from this Multiset in the other Multiset then this //should be a Join operation instead of a LeftJoin List<String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList(); if (joinVars.Count == 0) { //Calculate a Product filtering as we go foreach (ISet x in this.Sets) { bool standalone = false; foreach (ISet y in other.Sets) { ISet z = x.Join(y); try { joinedSet.Add(z); if (!expr.Evaluate(subcontext, z.ID).AsSafeBoolean()) { joinedSet.Remove(z.ID); standalone = true; } } catch { joinedSet.Remove(z.ID); standalone = true; } } if (standalone) joinedSet.Add(x.Copy()); } } else { //This is the old algorithm which is correct but has complexity O(n^2) so it scales terribly //foreach (ISet x in this.Sets) //{ // IEnumerable<ISet> ys = other.Sets.Where(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v]))); // //IEnumerable<ISet> ys = other.Sets.Where(s => s.IsCompatibleWith(x, joinVars)); // bool standalone = false; // int i = 0; // foreach (ISet y in ys) // { // i++; // ISet z = x.Join(y); // try // { // joinedSet.Add(z); // if (!expr.Evaluate(subcontext, z.ID).AsSafeBoolean()) // { // joinedSet.Remove(z.ID); // standalone = true; // } // } // catch // { // joinedSet.Remove(z.ID); // standalone = true; // } // } // if (standalone || i == 0) joinedSet.Add(x); //} //This is the new Join algorithm which is also correct but is O(2n) so much faster and scalable //Downside is that it does require more memory than the old algorithm List<HashTable<INode, int>> values = new List<HashTable<INode, int>>(); List<List<int>> nulls = new List<List<int>>(); foreach (String var in joinVars) { values.Add(new HashTable<INode, int>(HashTableBias.Enumeration)); nulls.Add(new List<int>()); } //First do a pass over the LHS Result to find all possible values for joined variables HashSet<int> matched = new HashSet<int>(); HashSet<int> standalone = new HashSet<int>(); foreach (ISet x in this.Sets) { int i = 0; foreach (String var in joinVars) { INode value = x[var]; if (value != null) { values[i].Add(value, x.ID); } else { nulls[i].Add(x.ID); } i++; } } //Then do a pass over the RHS and work out the intersections foreach (ISet y in other.Sets) { IEnumerable<int> possMatches = null; int i = 0; foreach (String var in joinVars) { INode value = y[var]; if (value != null) { if (values[i].ContainsKey(value)) { possMatches = (possMatches == null ? values[i].GetValues(value).Concat(nulls[i]) : possMatches.Intersect(values[i].GetValues(value).Concat(nulls[i]))); } else { possMatches = Enumerable.Empty<int>(); break; } } else { //Don't forget that a null will be potentially compatible with everything possMatches = (possMatches == null ? this.SetIDs : possMatches.Intersect(this.SetIDs)); } i++; } if (possMatches == null) continue; //Now do the actual joins for the current set //Note - We access the dictionary directly here because going through the this[int id] method //incurs a Contains() call each time and we know the IDs must exist because they came from //our dictionary originally! foreach (int poss in possMatches) { if (this._sets[poss].IsCompatibleWith(y, joinVars)) { ISet z = this._sets[poss].Join(y); joinedSet.Add(z); try { if (!expr.Evaluate(subcontext, z.ID).AsSafeBoolean()) { joinedSet.Remove(z.ID); standalone.Add(poss); } else { matched.Add(poss); } } catch { joinedSet.Remove(z.ID); standalone.Add(poss); } } } } //Finally add in unmatched sets from LHS foreach (int id in this.SetIDs) { if (!matched.Contains(id) || standalone.Contains(id)) joinedSet.Add(this._sets[id].Copy()); } } return joinedSet; }
/// <summary> /// Joins this Multiset to another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <returns></returns> public override BaseMultiset Join(BaseMultiset other) { //If the Other is the Identity Multiset the result is this Multiset if (other is IdentityMultiset) return this; //If the Other is the Null Multiset the result is the Null Multiset if (other is NullMultiset) return other; //If the Other is Empty then the result is the Null Multiset if (other.IsEmpty) return new NullMultiset(); //Find the First Variable from this Multiset which is in both Multisets //If there is no Variable from this Multiset in the other Multiset then this //should be a Join operation instead of a LeftJoin List<String> joinVars = this._variables.Where(v => other.Variables.Contains(v)).ToList(); if (joinVars.Count == 0) return this.Product(other); //Start building the Joined Set Multiset joinedSet = new Multiset(); //This is the old Join algorithm which while correct is O(n^2) so scales terribly //foreach (ISet x in this.Sets) //{ // //For sets to be compatible for every joinable variable they must either have a null for the // //variable in one of the sets or if they have values the values must be equal // ////This first check is to try speed things up, it looks whether there are solutions that may match // ////without needing to do a full table scan of the RHS results as the subsequent LINQ call will do // ////if (!joinVars.All(v => x[v] == null || other.ContainsValue(v, x[v]) || other.ContainsValue(v, null))) continue; // IEnumerable<ISet> ys = other.Sets.Where(s => joinVars.All(v => x[v] == null || s[v] == null || x[v].Equals(s[v]))); // //IEnumerable<ISet> ys = other.Sets.Where(s => s.IsCompatibleWith(x, joinVars)); // foreach (ISet y in ys) // { // joinedSet.Add(x.Join(y)); // } //} //This is the new Join algorithm which is also correct but is O(2n) so much faster and scalable //Downside is that it does require more memory than the old algorithm List<HashTable<INode, int>> values = new List<HashTable<INode, int>>(); List<List<int>> nulls = new List<List<int>>(); foreach (String var in joinVars) { values.Add(new HashTable<INode, int>(HashTableBias.Enumeration)); nulls.Add(new List<int>()); } //First do a pass over the LHS Result to find all possible values for joined variables foreach (ISet x in this.Sets) { int i = 0; foreach (String var in joinVars) { INode value = x[var]; if (value != null) { values[i].Add(value, x.ID); } else { nulls[i].Add(x.ID); } i++; } } #if NET40 && !SILVERLIGHT if (Options.UsePLinqEvaluation) { //Use a paralllel join other.Sets.AsParallel().ForAll(y => EvalJoin(y, joinVars, values, nulls, joinedSet)); } else { #endif //Use a serial join //Then do a pass over the RHS and work out the intersections foreach (ISet y in other.Sets) { this.EvalJoin(y, joinVars, values, nulls, joinedSet); } #if NET40 && !SILVERLIGHT } #endif return joinedSet; }
/// <summary> /// Determines whether this Multiset is disjoint with another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <returns></returns> public override bool IsDisjointWith(BaseMultiset other) { if (other is IdentityMultiset || other is NullMultiset) return false; return this._variables.All(v => !other.ContainsVariable(v)); }
/// <summary> /// Determines whether the Mutliset is disjoint with the given Multiset /// </summary> /// <param name="other">Multiset</param> /// <returns></returns> public abstract bool IsDisjointWith(BaseMultiset other);
/// <summary> /// Does a Product of this Multiset and another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <returns></returns> public override BaseMultiset Product(BaseMultiset other) { if (other is IdentityMultiset) return this; if (other is NullMultiset) return other; if (other.IsEmpty) return new NullMultiset(); Multiset productSet = new Multiset(); foreach (ISet x in this.Sets) { foreach (ISet y in other.Sets) { productSet.Add(x.Join(y)); } } return productSet; }
/// <summary> /// Exists Join is the equivalent of Left Join where the Join is predicated on the existence/non-existince of an appropriate join candidate in the other multiset /// </summary> /// <param name="other">Multiset to join with</param> /// <param name="mustExist">Whether a valid join candidate must exist in the other multiset for sets from this multiset to be kept</param> /// <returns></returns> public abstract BaseMultiset ExistsJoin(BaseMultiset other, bool mustExist);
/// <summary> /// Minus Joins this Multiset to another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <returns></returns> public override BaseMultiset MinusJoin(BaseMultiset other) { //Identity is always disjoint with Minus so return Identity return this; }
/// <summary> /// Product combines two multisets that are disjoint /// </summary> /// <param name="other">Multiset to join with</param> /// <returns></returns> public abstract BaseMultiset Product(BaseMultiset other);
/// <summary> /// Generates the Union of this Set and another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <returns>The other Multiset</returns> public override BaseMultiset Union(BaseMultiset other) { //If Other is Null/Empty then the Join still results in Identity if (other is NullMultiset) return this; if (other.IsEmpty) return this; return other; }
private void ShowMultiset(BaseMultiset multiset) { Console.WriteLine(multiset.GetType().ToString()); foreach (Set s in multiset.Sets) { Console.WriteLine(s.ToString()); } Console.WriteLine(); }
/// <summary> /// Returns False since the Identity Multiset is not disjoint with anything /// </summary> /// <param name="other">Other Multiset</param> /// <returns></returns> public override bool IsDisjointWith(BaseMultiset other) { return false; }
/// <summary> /// Left Joins another Multiset to this Null Mutliset /// </summary> /// <param name="other">Other Multiset</param> /// <param name="expr">Expression the join is predicate upon</param> /// <returns> /// Results in this Null Multiset since Null joined to anything is Null /// </returns> public override BaseMultiset LeftJoin(BaseMultiset other, ISparqlExpression expr) { //Left Outer Join results in Null Multiset return this; }
/// <summary> /// Joins another Multiset to this Null Mutliset /// </summary> /// <param name="other">Other Multiset</param> /// <returns> /// Results in this Null Multiset since Null joined to anything is Null /// </returns> public override BaseMultiset Join(BaseMultiset other) { //Left Join results in Null Multiset return this; }
private void EvalJoin(ISet y, List<String> joinVars, List<HashTable<INode, int>> values, List<List<int>> nulls, BaseMultiset joinedSet) { IEnumerable<int> possMatches = null; int i = 0; foreach (String var in joinVars) { INode value = y[var]; if (value != null) { if (values[i].ContainsKey(value)) { possMatches = (possMatches == null ? values[i].GetValues(value).Concat(nulls[i]) : possMatches.Intersect(values[i].GetValues(value).Concat(nulls[i]))); } else { possMatches = Enumerable.Empty<int>(); break; } } else { //Don't forget that a null will be potentially compatible with everything possMatches = (possMatches == null ? this.SetIDs : possMatches.Intersect(this.SetIDs)); } i++; } if (possMatches == null) return; //Now do the actual joins for the current set //Note - We access the dictionary directly here because going through the this[int id] method //incurs a Contains() call each time and we know the IDs must exist because they came from //our dictionary originally! foreach (int poss in possMatches) { if (this._sets[poss].IsCompatibleWith(y, joinVars)) { joinedSet.Add(this._sets[poss].Join(y)); } } }
/// <summary> /// Minus Joins this Multiset to another Multiset /// </summary> /// <param name="other">Other Multiset</param> /// <returns></returns> public override BaseMultiset MinusJoin(BaseMultiset other) { return this; }