Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nmf-optimizable-expressions #38

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@

namespace NMF.Expressions
{
internal class CastExpression<T> : IEnumerableExpression<T>
internal class CastExpression<T> : IEnumerableExpression<T>, ISQO
{
public IEnumerableExpression Source { get; private set; }
private INotifyEnumerable<T> notifyEnumerable;

public IEnumerableExpression OptSource => Source;

public CastExpression(IEnumerableExpression source)
{
if (source == null) throw new ArgumentNullException("source");
Expand Down
38 changes: 38 additions & 0 deletions Expressions/Expressions.Linq/EnumerableExpressions/DebugVisitor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.Linq.Expressions;

namespace NMF.Expressions
{
public class DebugVisitor : ExpressionVisitor
{
private int level = 0;

public override Expression Visit(Expression exp)
{
if (exp != null)
{
if (level == 0)
{
System.Diagnostics.Debug.WriteLine("#################################");
}


for (int i = 0; i < level; i++)
{
System.Diagnostics.Debug.Write("   ");
}
System.Diagnostics.Debug.WriteLine("{0}  -  {1} : || {2} ||",
exp.NodeType, exp.GetType().Name, exp.ToString());
}
level++;
Expression result = base.Visit(exp);
level--;
return result;
}

public void Display(Expression exp)
{
System.Diagnostics.Debug.WriteLine("===== DisplayVisitor.Display =====");
this.Visit(exp);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@

namespace NMF.Expressions
{
internal class DistinctExpression<T> : IEnumerableExpression<T>
internal class DistinctExpression<T> : IEnumerableExpression<T>, ISQO
{
public IEnumerableExpression<T> Source { get; private set; }
public IEqualityComparer<T> Comparer { get; set; }
private INotifyEnumerable<T> notifyEnumerable;

public IEnumerableExpression OptSource => Source;

public DistinctExpression(IEnumerableExpression<T> source, IEqualityComparer<T> comparer)
{
if (source == null) throw new ArgumentNullException("source");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
using NMF.Expressions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
//using TrainBenchmark;

namespace NMF.Expressions.EnumerableExpressions
{
public static class DDGDgmlVisualizer
{
private static XNamespace ns = XNamespace.Get("http://schemas.microsoft.com/vs/2009/dgml");

public static void initDgmlVisualizer(INotifyEnumerable func)
{
//var test = new SwitchSet();
//var query = test.Data.Query;
var changeSources = Enumerable.Empty<INotifiable>();

var doc = CreateDgml(func, changeSources);
OpenDgml(doc);
}

private static XDocument CreateDgml(INotifiable query, IEnumerable<INotifiable> changeSources)
{
var doc = CreateDgmlDoc();
var nodes = doc.Root.Element(ns + "Nodes");
var links = doc.Root.Element(ns + "Links");

var allNodes = new[] { query }.Concat(NMF.Utilities.Extensions.SelectRecursive(query, n => n.Dependencies)).ToList();
foreach (var node in allNodes)
{
nodes.Add(ToDgmlNode(node));
foreach (var link in ToDgmlLink(node))
links.Add(link);
}

var sourceNodesIds = changeSources.Select(n => n.GetHashCode().ToString()).ToList();
var actualSources = nodes.Elements().Where(e => sourceNodesIds.Contains(e.Attribute("Id").Value));
foreach (var s in actualSources)
s.SetAttributeValue("Category", "ActualChangeSource");

var syncNodes = FindSyncNodes(changeSources);
var syncNodesIds = syncNodes.Select(n => n.GetHashCode().ToString()).ToList();
var syncs = nodes.Elements().Where(e => syncNodesIds.Contains(e.Attribute("Id").Value));
foreach (var s in syncs)
s.SetAttributeValue("Category", "SyncNode");

foreach (var node in changeSources)
{
var path = NMF.Utilities.Extensions.SelectRecursive(node, n => n.Successors).ToList();
for (int i = 0; i < path.Count - 1; i++)
{
var src = path[i];
var dst = path[i + 1];
var link = links.Elements().First(e => e.Attribute("Source").Value == src.GetHashCode().ToString() && e.Attribute("Target").Value == dst.GetHashCode().ToString());
link.SetAttributeValue("Category", "ActualChangeSource");
}
}

return doc;
}

private static void OpenDgml(XDocument doc)
{
var fileName = DateTime.Now.ToString("hh-mm-ss") + ".dgml";
var filePath = Path.Combine(Path.GetTempPath(), fileName);
doc.Save(filePath);
//System.Diagnostics.Process.Start(filePath);
}

private static XDocument CreateDgmlDoc()
{
var doc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"));
doc.Add(new XElement(ns + "DirectedGraph"));
doc.Root.SetAttributeValue("Layout", "Sugiyama");
doc.Root.SetAttributeValue("GraphDirection", "BottomToTop");
var nodes = new XElement(ns + "Nodes");
doc.Root.Add(nodes);
var links = new XElement(ns + "Links");
doc.Root.Add(links);
var categories = new XElement(ns + "Categories");
doc.Root.Add(categories);
var potentialChangeSource = new XElement(ns + "Category");
potentialChangeSource.SetAttributeValue("Id", "PotentialChangeSource");
potentialChangeSource.SetAttributeValue("Background", "LightBlue");
categories.Add(potentialChangeSource);
var actualChangeSource = new XElement(ns + "Category");
actualChangeSource.SetAttributeValue("Id", "ActualChangeSource");
actualChangeSource.SetAttributeValue("Background", "Green");
actualChangeSource.SetAttributeValue("Stroke", "Green");
actualChangeSource.SetAttributeValue("StrokeThickness", "3");
categories.Add(actualChangeSource);
var syncNode = new XElement(ns + "Category");
syncNode.SetAttributeValue("Id", "SyncNode");
syncNode.SetAttributeValue("Background", "Red");
categories.Add(syncNode);
return doc;
}

private static XElement ToDgmlNode(INotifiable node)
{
var e = new XElement(ns + "Node");
e.SetAttributeValue("Id", node.GetHashCode());
e.SetAttributeValue("Label", NodeToLabel(node));
return e;
}

private static string NodeToLabel(INotifiable node)
{
var typeName = node.GetType().Name;
var result = typeName.Replace("Observable", "");
int genericIndex = result.IndexOf('`');
if (genericIndex > 0)
result = result.Remove(genericIndex);

var valueProp = node.GetType().GetProperties().FirstOrDefault(p => p.Name == "Value");
if (valueProp != null)
result += "\nValue: " + valueProp.GetValue(node);

var countProp = node.GetType().GetProperty("Count");
if (countProp != null)
result += "\nCount: " + countProp.GetValue(node);

return result;
}

private static IEnumerable<XElement> ToDgmlLink(INotifiable node)
{
return node.Dependencies.Select(d =>
{
var e = new XElement(ns + "Link");
e.SetAttributeValue("Source", d.GetHashCode());
e.SetAttributeValue("Target", node.GetHashCode());
return e;
});
}

private static List<INotifiable> FindSyncNodes(IEnumerable<INotifiable> sourceNodes)
{
var result = new List<INotifiable>();
var visited = new HashSet<int>();
var stack = new Stack<INotifiable>(sourceNodes);

while (stack.Any())
{
var item = stack.Pop();
visited.Add(item.GetHashCode());
foreach (var suc in item.Successors)
stack.Push(suc);

if (item.Dependencies.Count(d => visited.Contains(d.GetHashCode())) == 2)
result.Add(item);
}

return result;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@

namespace NMF.Expressions
{
internal abstract class SetExpression<T> : IEnumerableExpression<T>
internal abstract class SetExpression<T> : IEnumerableExpression<T>, ISQO
{
public IEnumerableExpression<T> Source { get; private set; }
public IEnumerable<T> Other { get; private set; }
public IEqualityComparer<T> Comparer { get; private set; }
protected INotifyEnumerable<T> notifyEnumerable;

public IEnumerableExpression OptSource => Source;

public SetExpression(IEnumerableExpression<T> source, IEnumerable<T> other, IEqualityComparer<T> comparer)
{
if (source == null) throw new ArgumentNullException("source");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace NMF.Expressions
{
internal class GroupByExpression<TElement, TKey> : IEnumerableExpression<IGroupingExpression<TKey, TElement>>
internal class GroupByExpression<TElement, TKey> : IEnumerableExpression<IGroupingExpression<TKey, TElement>>, ISQO
{
private class GroupingExpression : IGroupingExpression<TKey, TElement>
{
Expand Down Expand Up @@ -37,6 +37,7 @@ public INotifyEnumerable<TElement> AsNotifiable()
groupBy.CreateIncremental();
return groupBy.notifyEnumerable[Key];
}
public IEnumerableExpression OptSource => throw new InvalidOperationException();

IEnumerator IEnumerable.GetEnumerator()
{
Expand All @@ -51,6 +52,10 @@ INotifyEnumerable IEnumerableExpression.AsNotifiable()


public IEnumerableExpression<TElement> Source { get; private set; }

public IEnumerableExpression OptSource => Source;


public Expression<Func<TElement, TKey>> Predicate { get; private set; }
public Func<TElement, TKey> PredicateCompiled { get; private set; }
public IEqualityComparer<TKey> Comparer { get; private set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Text;
using SL = System.Linq.Enumerable;
using NMF.Expressions.Linq;

namespace NMF.Expressions
{
internal class GroupJoinExpression<TOuter, TInner, TKey, TResult> : IEnumerableExpression<TResult>
internal class GroupJoinExpression<TOuter, TInner, TKey, TResult> : IEnumerableExpression<TResult>, IOptimizableEnumerableExpression<TResult>
{
public IEnumerableExpression<TOuter> Source { get; set; }
public IEnumerable<TInner> Inner { get; set; }
Expand All @@ -20,6 +21,13 @@ internal class GroupJoinExpression<TOuter, TInner, TKey, TResult> : IEnumerableE
public IEqualityComparer<TKey> Comparer { get; set; }
private INotifyEnumerable<TResult> notifyEnumerable;

public Expression OptSelectorExpression => ResultSelector;

public Expression PrevExpression { get; set; }

public IEnumerableExpression OptSource => Source;


public GroupJoinExpression(IEnumerableExpression<TOuter> outer, IEnumerable<TInner> inner, Expression<Func<TOuter, TKey>> outerKeySelector, Func<TOuter, TKey> outerKeySelectorCompiled, Expression<Func<TInner, TKey>> innerKeySelector, Func<TInner, TKey> innerKeySelectorCompiled, Expression<Func<TOuter, IEnumerable<TInner>, TResult>> resultSelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelectorCompiled, IEqualityComparer<TKey> comparer)
{
if (outer == null) throw new ArgumentNullException("outer");
Expand All @@ -37,6 +45,9 @@ public GroupJoinExpression(IEnumerableExpression<TOuter> outer, IEnumerable<TInn
ResultSelector = resultSelector;
ResultSelectorCompiled = resultSelectorCompiled ?? ExpressionCompileRewriter.Compile(resultSelector);
Comparer = comparer;
#if DEBUG
QueryExpressionDgmlVisualizer.AddNode(this);
#endif
}

public INotifyEnumerable<TResult> AsNotifiable()
Expand All @@ -63,5 +74,33 @@ INotifyEnumerable IEnumerableExpression.AsNotifiable()
{
return AsNotifiable();
}

public IEnumerableExpression<TOptimizedResult> AsOptimized<TOptimizedResult>(IOptimizableEnumerableExpression expression = null)
{
#if DEBUG
VisitForDebugging(ResultSelector);
#endif
if (expression != null)
return Merge<TOptimizedResult>(expression);
return (IEnumerableExpression<TOptimizedResult>)this;
}

public IEnumerableExpression<TOptimizedResult> Merge<TOptimizedResult>(IOptimizableEnumerableExpression prevExpr)
{
var mergedSelectorExpression = new ProjectionMergeQueryOptimizer().Optimize<TOuter, TResult, TOptimizedResult>(prevExpr.OptSelectorExpression, OptSelectorExpression) as Expression<Func<TOuter, IEnumerable<TInner>, TOptimizedResult>>;
return new GroupJoinExpression<TOuter, TInner, TKey, TOptimizedResult>(Source, Inner, OuterKeySelector, null, InnerKeySelector, null, mergedSelectorExpression, null, Comparer);
}

IOptimizableEnumerableExpression<TOptimizedResult> IOptimizableEnumerableExpression.AsOptimized2<TOptimizedResult>(IQueryOptimizer queryOptimizer)
{
return (IOptimizableEnumerableExpression<TOptimizedResult>)queryOptimizer.OptimizeExpression<TOuter, TInner, TKey, TResult, TOptimizedResult>(this);
}

private void VisitForDebugging(Expression expression)
{
//Ausgabe überprüfen
DebugVisitor debugVisitor = new DebugVisitor();
debugVisitor.Visit(expression);
}
}
}
Loading