public static PathStats ShortestPath(DirectedGraph g, int s) { #region Initialization var stats = new PathStats(g.V); for (var i = 0; i < stats.Dist.Length; i++) { stats.Dist[i] = int.MaxValue; stats.Prev[i] = -1; } stats.Dist[s] = 0; #endregion var dfsStats = Dfs.DepthFirstSearch(g); var linearization = dfsStats.Linearization; Debug.WriteLine(dfsStats); foreach (var u in linearization) { foreach (var v in g.Adjacent(u)) { if (stats.Dist[v.V2] > stats.Dist[v.V1] + v.Weight) { stats.Dist[v.V2] = stats.Dist[v.V1] + v.Weight; stats.Prev[v.V2] = u; } } } return stats; }
public static PathStats ShortestPath(GraphBase g, int s) { #region Initialization var ps = new PathStats(g.V); for (int i = 0; i < ps.Dist.Length; i++) { ps.Dist[i] = int.MaxValue; ps.Prev[i] = -1; } ps.Dist[s] = 0; #endregion for (int i = 0; i < g.V - 1; i++)//run |V|-1 times { for (var u = g.V - 1; u >= 0; u--)//'S' starts first, earlier to get finall status { foreach (var e in g.Adjacent(u)) { if (ps.Dist[u] == int.MaxValue)//if distance of u hasn't ever be udpated, skip break; if (ps.Dist[e.V2] > ps.Dist[e.V1] + e.Weight) { ps.Dist[e.V2] = ps.Dist[e.V1] + e.Weight; ps.Prev[e.V2] = u; } } } } return ps; }
/// <summary> /// Dijkstra algorithm (shortest path) based on graph g for start vertice s. Positive cycles are allowed in shortest path algorithm /// </summary> /// <param name="g">Graph for search</param> /// <param name="s">Start vertice</param> public static PathStats ShortestPath(GraphBase g, int s) { var ps = new PathStats(g.V); for (var i = 0; i < ps.Dist.Length; i++) { ps.Dist[i] = int.MaxValue; ps.Prev[i] = -1; } ps.Dist[s] = 0;//start vertice var pq = new IndexMinPQ<Distance>(ps.Dist.Length); for (int i = 0; i < ps.Dist.Length; i++) { pq.Insert(i, new Distance { V = i, Dist = ps.Dist[i] }); } while (!pq.IsEmpty()) { var v = pq.DelRoot(); foreach (var e in g.Adjacent(v)) { if (ps.Dist[e.V2] > ps.Dist[v] + e.Weight) { ps.Dist[e.V2] = ps.Dist[v] + e.Weight; ps.Prev[e.V2] = v; pq.ChangeKey(e.V2, new Distance { V = e.V2, Dist = ps.Dist[e.V2] }); } } } return ps; }
private static PathStats GetPathStats(GraphBase g, int s, bool isShortest) { var ps = new PathStats(g.V); for (var i = 0; i < ps.Dist.Length; i++) { ps.Dist[i] = isShortest ? int.MaxValue : int.MinValue; ps.Prev[i] = -1; } ps.Dist[s] = 0;//start vertice var pq = isShortest ? new MinPQ<Distance>(ps.Dist.Length) : new MaxPQ<Distance>(ps.Dist.Length); pq.Insert(new Distance { Dist = 0, V = s }); while (!pq.IsEmpty()) { var v = pq.DelRoot(); foreach (var e in g.Adjacent(v.V)) { if ((isShortest && ps.Dist[e.V2] > ps.Dist[v.V] + e.Weight) || //shortest path (!isShortest && ps.Dist[e.V2] < ps.Dist[v.V] + e.Weight)) //longest path { ps.Dist[e.V2] = ps.Dist[v.V] + e.Weight; ps.Prev[e.V2] = v.V; pq.Insert(new Distance { V = e.V2, Dist = ps.Dist[e.V2] }); } } } return ps; }
public async Task <bool> ApplyPathRatingAsyc(BiblePathsCoreDbContext context) { // This Rating System is likely to change over time but for now we've got the following rules. // Rating is the average of the following Scores ranging from 0 - 5 (there is a little arbitrary uplift) // 1. Initial Rating on entry to this method counts as one Rating (all paths start at 4.5) // 2. A Rating is calculated from the % of Reads (FinishCount / StartCount * 100) this is a % of 5 // 3. A "Book Diversity Rating" where a path gets 1 point for each unique Book and a point for spanning testaments up to 5 // 4. Average of all UserRatings (uplift creates a 1.1 - 5.5 range) int firstNTBook = 40; // the first book in the New Testemant is book 40 in the protestant Bible. int ScoreCount = 0; // this becomes the number of total Scores that we will average together. double TotalScore = 0; // load all of the PathStats for this Path... we'll need these // We need to load the collection of Steps assocaited with this Path, as well as the Nodes. context.Entry(this) .Collection(p => p.PathStats) .Load(); context.Entry(this) .Collection(p => p.PathNodes) .Load(); // 1. Initial Rating on entry to this method counts as one Rating (all paths start at 4.5) if (ComputedRating.HasValue) { TotalScore += (double)ComputedRating; ScoreCount++; } // 2. A Rating is calculated from the % of Reads (FinishCount / StartCount * 100) this is a % of 5.25 (a quarter point uplift) int NumStarts = PathStats.Where(s => s.EventType == (int)EventType.PathStarted).ToList().Count; if (NumStarts > 0) { int NumCompletes = PathStats.Where(s => s.EventType == (int)EventType.PathCompleted).ToList().Count; double ReadPercent = NumCompletes / NumStarts; TotalScore += ReadPercent * 5.25; ScoreCount++; } // 3. A "Book Diversity Rating" where a path gets 1 point for each unique Book up to 5 (any count over 5 = 5.25) if (PathNodes.Count > 0) { int BookDiversityScore = 0; var BookHash = new HashSet <int>(); foreach (PathNode node in PathNodes) { BookHash.Add(node.BookNumber); } BookDiversityScore += BookHash.Count(); // Does the path span testaments? if ((BookHash.Max() >= firstNTBook) && (BookHash.Min() < firstNTBook)) { BookDiversityScore += 1; // Add a free point for spanning testaments. } TotalScore += BookDiversityScore > 5 ? 5.25 : BookDiversityScore; ScoreCount++; } // 4. Average of all UserRatings List <PathStat> UserRatings = PathStats.Where(s => s.EventType == (int)EventType.UserRating).ToList(); int SumRatings = 0; int NumRatings = 0; foreach (PathStat UserRating in UserRatings) { int Rating = 0; try { Rating = int.Parse(UserRating.EventData); } catch { continue; } if (Rating > 0 && Rating <= 5) { SumRatings += Rating; NumRatings++; } } double AvgUserRating = SumRatings / NumRatings; if (AvgUserRating > 0 && AvgUserRating <= 5) { TotalScore += (AvgUserRating * 1.1); // Make this count by applying a small uplift. ScoreCount++; } // Ok now it's time to calculate a our new rating. double TempRating = TotalScore / ScoreCount; TempRating = TempRating > 5 ? 5 : TempRating; TempRating = TempRating < 0 ? 0.5 : TempRating; // Save our Rating Now. context.Attach(this).State = EntityState.Modified; ComputedRating = (decimal)TempRating; await context.SaveChangesAsync(); return(true); }