/// <summary> /// Initializes and incrementally creates a minimal <see cref="IMinimalDAGNode{T}"/> from a sorted collection of sequences of values. /// </summary> /// <typeparam name="T">The type to be arranged as a <see cref="IMinimalDAG{T}"/></typeparam> /// <param name="sortedSequences">The ascending ordered sequences of <typeparamref name="T"/> to be minimized.</param> /// <param name="nodeFactory">Factory for <see cref="IMinimalDAGNode{T}"/> creation</param> public MinimalDAG(IEnumerable <IEnumerable <T> > sortedSequences, IMinimalDAGNodeFactory <T> nodeFactory)//, T sourceValue = default(T), T sinkValue = default(T)) { _registrationBySuffix = new HashSet <IMinimalDAGNode <T> >(); _dagNodeFactory = nodeFactory ?? new MinimalDAGNodeFactory <T>(); _nodes = new Dictionary <Guid, IMinimalDAGNode <T> >(); _source = _dagNodeFactory.CreateNode(default(T), Guid.NewGuid()); _sink = _dagNodeFactory.CreateNode(default(T), Guid.NewGuid()); _source.Children.Add(_sink.ID); _registrationBySuffix.Add(_sink); _sink.IsSuffixRegistered = true; var LastSequence = new List <T>() { _sink.Value }.DefaultIfEmpty(); //lazy but simple fix foreach (IEnumerable <T> Sequence in sortedSequences) { AddNextOrderedSequence(Sequence, LastSequence); LastSequence = Sequence; } HandleExistingSuffixes(_source); BuildParentLinks(); BuildNodesByValueDictionary(); }
/// <summary> /// Compares the most recently added <see cref="IMinimalDAGNode{T}"/> (and children) to the existing nodes, /// merging any matches. /// </summary> /// <param name="parent"></param> private void HandleExistingSuffixes(IMinimalDAGNode <T> parent) { var NewestChild = GetLastChild(parent); if (NewestChild != default(IMinimalDAGNode <T>)) { if (!NewestChild.IsSuffixRegistered) { if (NewestChild.Children.Count > 0) { HandleExistingSuffixes(NewestChild); } else { NewestChild.Children.Add(_sink.ID); } IMinimalDAGNode <T> EquivalentNode; if (_registrationBySuffix.TryGetValue(NewestChild, out EquivalentNode)) { parent.Children.Remove(NewestChild.ID); _nodes.Remove(NewestChild.ID); parent.Children.Add(EquivalentNode.ID); } else { _registrationBySuffix.Add(NewestChild); NewestChild.IsSuffixRegistered = true; } } } }
/// <summary> /// Returns the last (ie most recently added) child <see cref="IMinimalDAGNode{T}"/> linked to the selected node. /// </summary> /// <param name="node"></param> /// <returns></returns> private IMinimalDAGNode <T> GetLastChild(IMinimalDAGNode <T> node) { IMinimalDAGNode <T> ReturnValue = null; _nodes.TryGetValue(node.Children.Last(), out ReturnValue); return(ReturnValue); //return Nodes[node.GetChildIDs().Last()]; }
internal SequenceSearchState(SequenceSearchState <T> other, IMinimalDAGNode <T> nextNode, int stepDirection) { Index = other.Index + stepDirection; CurrentNode = nextNode; //PreviousNode = other.CurrentNode; ValuePool = new List <T>(other.ValuePool); //.ToList(); UsedValues = new Dictionary <int, T>(other.UsedValues); // { Index, CurrentNode.GetValue() }; this.WildCardIndices = new List <int>(other.WildCardIndices); this.WildCardCount = other.WildCardCount; }
internal SequenceSearchState(IMinimalDAGNode <T> currentNode, IEnumerable <T> valuePool, int index, int wildCardCount = 0, Dictionary <int, T> usedValues = null, List <int> wildCardIndices = null) { WildCardIndices = wildCardIndices ?? new List <int>(); CurrentNode = currentNode; ValuePool = valuePool; Index = index; UsedValues = (usedValues == null)? new Dictionary <int, T>(): new Dictionary <int, T>(usedValues);//new List<T>(); WildCardCount = wildCardCount; }
public MinimalDAG(IMinimalDAGNode <T> _source, IMinimalDAGNode <T> _sink, IMinimalDAGNodeFactory <T> _dagNodeFactory, Dictionary <Guid, IMinimalDAGNode <T> > _nodes, Dictionary <T, List <Guid> > _nodeIDsByValue, HashSet <Guid> _nodeIDsWithNullValue) { this._sink = _sink; this._source = _source; this._nodeIDsByValue = _nodeIDsByValue; this._nodes = _nodes; this._dagNodeFactory = _dagNodeFactory; this._nodeIDsWithNullValue = _nodeIDsWithNullValue; }
/// <summary> /// Returns a boolean representing whether <paramref name="possibleBoundaryNode"/> is a sink or source <see cref="IMinimalDAGNode{T}"/>. /// </summary> /// <param name="possibleBoundaryNode"></param> /// <returns></returns> public bool IsDAGBoundary(IMinimalDAGNode <T> possibleBoundaryNode) { var ID = possibleBoundaryNode.ID; if (ID == _sink.ID || ID == _source.ID) { return(true); } return(false); }
/// <summary> /// Adds a sequence of child <see cref="IMinimalDAGNode{T}"/> nodes to the selected <see cref="IMinimalDAGNode{T}"/> /// - the addition of a new sequence of values to the DAG. /// </summary> /// <param name="currentNode">The parent node to add the sequence to.</param> /// <param name="currentSuffix">A new sequence of nodes.</param> private void AddSuffix(IMinimalDAGNode <T> currentNode, IEnumerable <T> currentSuffix) { var CurrentNode = currentNode; foreach (var value in currentSuffix) { var NewNode = _dagNodeFactory.CreateNode(value, Guid.NewGuid()); RecordNode(NewNode); CurrentNode.Children.Add(NewNode.ID); CurrentNode = NewNode; } CurrentNode.Children.Add(_sink.ID); }
/// <summary> /// Returns the <see cref="IMinimalDAGNode{T}"/> children of <paramref name="node"/> /// </summary> /// <param name="node"></param> /// <returns></returns> public IEnumerable <IMinimalDAGNode <T> > GetChildren(IMinimalDAGNode <T> node) { IMinimalDAGNode <T> value; foreach (var ID in node.Children) { if (_nodes.TryGetValue(ID, out value)) { yield return(value); } else if (ID == _sink.ID) { yield return(_sink); } } }
/// <summary> /// Returns the <see cref="IMinimalDAGNode{T}"/> parents of <paramref name="node"/> /// </summary> /// <param name="node"></param> /// <returns></returns> public IEnumerable <IMinimalDAGNode <T> > GetParents(IMinimalDAGNode <T> node) { IMinimalDAGNode <T> value; foreach (var ID in node.Parents) { if (_nodes.TryGetValue(ID, out value)) { yield return(value); } else if (ID == _source.ID) { yield return(_source); } } //yield return _nodes[ID]; }
internal SequenceSearchState(SequenceSearchState <T> other, IMinimalDAGNode <T> nextNode, int stepDirection, T UsedValue, bool wildCard) { this.WildCardIndices = new List <int>(other.WildCardIndices); Index = other.Index + stepDirection; CurrentNode = nextNode; UsedValues = new Dictionary <int, T>(other.UsedValues); //doesn't make sense: //if(!UsedValues.ContainsKey(Index)) UsedValues.Add(Index, UsedValue); // PreviousNode = other.CurrentNode; if (wildCard) { WildCardCount = other.WildCardCount - 1; ValuePool = new List <T>(other.ValuePool); WildCardIndices.Add(Index); } else { WildCardCount = other.WildCardCount; ValuePool = other.ValuePool.ExceptFirst(UsedValue).ToList(); } }
/// <summary> /// Traverses the graph from a specified node, returning all sequences with that parent. /// </summary> /// <param name="root">The starting point of the sequence search.</param> /// <param name="partial">The current sequence/s being traversed</param> /// <returns></returns> private List <List <T> > GetSequences(IMinimalDAGNode <T> root, List <T> partial) { List <List <T> > Values = new List <List <T> >(); if (root.ID.Equals(_sink.ID)) { Values.Add(partial); return(Values); } List <T> Sequence = new List <T>(partial) { root.Value }; foreach (var Child in GetChildren(root)) { foreach (var Subsequence in GetSequences(Child, Sequence)) { Values.Add(Subsequence); } } return(Values); }
/// <summary> /// Records a <see cref="IMinimalDAGNode{T}"/> into the register of nodes. /// </summary> /// <param name="toRecord"></param> private void RecordNode(IMinimalDAGNode <T> toRecord) { _nodes[toRecord.ID] = toRecord; }