/// <summary> /// Gets the minimum-weight path to a goal using the A* algorithm. /// </summary> /// <remarks>Because the heuristic is not known to be consistent, we cannot use the closed set optimization.</remarks> /// <typeparam name="TNode">The type of a node.</typeparam> /// <typeparam name="TKey">The type of a node key.</typeparam> /// <param name="sources">The set of nodes from which to start the search, weighted by their initial cost.</param> /// <param name="key">The function which maps a node to its key.</param> /// <param name="next">The function which maps a node to its adjacent nodes.</param> /// <param name="goal">The goal predicate.</param> /// <param name="heuristic">The possibly-inconsistent heuristic function.</param> /// <returns>The minimum-weight path, or null if none exists.</returns> private static IWeighted <IEnumerable <TNode> > AStarInconsistent <TNode, TKey>( IEnumerable <IWeighted <TNode> > sources, Func <TNode, TKey> key, Func <TNode, IEnumerable <IWeighted <TNode> > > next, Func <TNode, bool> goal, Func <TNode, double> heuristic) { var came_from = new Dictionary <TKey, TNode>(); IPriorityQueue <double, AStarOpen <TNode> > open_queue = new PairingHeap <double, AStarOpen <TNode> >(); var open_lookup = new Dictionary <TKey, IPriorityQueueHandle <double, AStarOpen <TNode> > >(); foreach (var source in sources) { var u = source.Value; var key_u = key(u); var g_u = source.Weight; var f_u = g_u + heuristic(u); var open_u = new AStarOpen <TNode>(u, g_u); open_u.Handle = open_queue.Add(f_u, open_u); open_lookup.Add(key_u, open_u.Handle); } while (open_queue.Count > 0) { var handle_u = open_queue.Min; var u = handle_u.Value.Node; var key_u = key(u); if (goal(u)) { var path = ReconstructPath(key, came_from, u); return(new Weighted <IEnumerable <TNode> >(path, handle_u.Value.G)); } open_queue.Remove(handle_u); open_lookup.Remove(key_u); foreach (var uv in next(u)) { var v = uv.Value; var key_v = key(v); var g_v = handle_u.Value.G + uv.Weight; var f_v = g_v + heuristic(v); IPriorityQueueHandle <double, AStarOpen <TNode> > handle_v; if (open_lookup.TryGetValue(key_v, out handle_v)) { if (f_v < handle_v.Key) { open_queue.UpdateKey(handle_v, f_v); handle_v.Value.G = g_v; came_from[key_v] = u; } } else { var open_v = new AStarOpen <TNode>(v, g_v); open_v.Handle = open_queue.Add(f_v, open_v); open_lookup.Add(key_v, open_v.Handle); came_from[key_v] = u; } } } return(null); }
/// <summary> /// Gets the minimum-weight path to a goal using uniform cost search. /// </summary> /// <typeparam name="TNode">The type of a node.</typeparam> /// <typeparam name="TKey">The type of a node key.</typeparam> /// <param name="sources">The set of nodes from which to start the search, weighted by their initial cost.</param> /// <param name="key">The function which maps a node to its key.</param> /// <param name="next">The function which maps a node to its adjacent nodes.</param> /// <param name="goal">The goal predicate.</param> /// <returns>The minimum-weight path, or null if none exists.</returns> public static IWeighted <IEnumerable <TNode> > UniformCostSearch <TNode, TKey>( this IEnumerable <IWeighted <TNode> > sources, Func <TNode, TKey> key, Func <TNode, IEnumerable <IWeighted <TNode> > > next, Func <TNode, bool> goal) { var came_from = new Dictionary <TKey, TNode>(); var open_lookup = new Dictionary <TKey, IPriorityQueueHandle <double, TNode> >(); IPriorityQueue <double, TNode> open_queue = new PairingHeap <double, TNode>(); var closed = new HashSet <TKey>(); foreach (var source in sources) { var u = source.Value; var g_u = source.Weight; open_lookup.Add(key(u), open_queue.Add(g_u, u)); } while (open_queue.Count > 0) { var handle_u = open_queue.Min; var u = handle_u.Value; var key_u = key(u); var g_u = handle_u.Key; if (goal(u)) { var path = ReconstructPath(key, came_from, u); return(new Weighted <IEnumerable <TNode> >(path, g_u)); } open_lookup.Remove(key_u); open_queue.Remove(handle_u); closed.Add(key_u); foreach (var uv in next(u)) { var v = uv.Value; var key_v = key(v); if (closed.Contains(key_v)) { continue; } IPriorityQueueHandle <double, TNode> v_handle; var g_uv = g_u + uv.Weight; if (open_lookup.TryGetValue(key_v, out v_handle)) { if (g_uv < v_handle.Key) { open_queue.UpdateKey(v_handle, g_uv); came_from[key_v] = u; } } else { open_lookup.Add(key_v, open_queue.Add(g_uv, v)); came_from[key_v] = u; } } } return(null); }
public IEnumerable<Tuple<Word, int>> Derive() { var derivedWords = new HashSet<string>(); var pq = new PairingHeap<Word, int>(); pq.Add(new Word(Grammar.StartSymbol), 0); var rules = Grammar.Rules.OrderBy(r => r.WordToInsert.Length - r.WordToReplace.Length).ToArray(); while (pq.Count > 0) { var elementToDerive = pq.Min; pq.Remove(elementToDerive); var wordToDerive = elementToDerive.Key; foreach (var nw in rules.SelectMany(rule => wordToDerive.ReplaceAll(rule.WordToReplace, rule.WordToInsert)) .Where(nw => !derivedWords.Contains(nw.ToString()))) { derivedWords.Add(nw.ToString()); pq.Add(nw, nw.Length); yield return Tuple.Create(nw, wordToDerive.Length); } } }