From 71e650e373369f71b75fc495751dfb50ebaa2542 Mon Sep 17 00:00:00 2001 From: Arthur Bols Date: Sat, 18 May 2019 23:40:07 +0200 Subject: [PATCH] fixed --- TMI-practicum/Intersection.cs | 18 ++++ TMI-practicum/Program.cs | 53 ++++++++++- TMI-practicum/SweepLineEffAlgorithm.cs | 124 ++++++++++++------------- TMI-practicum/TMI-practicum.csproj | 4 + TMI-practicum/packages.config | 1 + 5 files changed, 129 insertions(+), 71 deletions(-) diff --git a/TMI-practicum/Intersection.cs b/TMI-practicum/Intersection.cs index 16e354e..19662fe 100644 --- a/TMI-practicum/Intersection.cs +++ b/TMI-practicum/Intersection.cs @@ -10,5 +10,23 @@ namespace TMI_practicum X = x; Y = y; } + + public override int GetHashCode() + { + return X.GetHashCode() ^ Y.GetHashCode(); + } + + public override bool Equals(object obj) + { + return obj is Intersection && this == (Intersection) obj; + } + public static bool operator ==(Intersection x, Intersection y) + { + return x.X == y.X && x.Y == y.Y; + } + public static bool operator !=(Intersection x, Intersection y) + { + return !(x == y); + } } } \ No newline at end of file diff --git a/TMI-practicum/Program.cs b/TMI-practicum/Program.cs index 9531c13..9a59fe5 100644 --- a/TMI-practicum/Program.cs +++ b/TMI-practicum/Program.cs @@ -10,8 +10,7 @@ namespace TMI_practicum { public static void Main(string[] args) { - - //SweepLineEffAlgorithm.Solve(null); + GetChartData(); if (args.Length < 1) { Console.WriteLine("Please enter a file."); @@ -26,9 +25,11 @@ namespace TMI_practicum var (algorithm, _, circles) = ParseFile(args[0]); - IEnumerable solved; + Stopwatch stopwatch = new Stopwatch(); + IEnumerable solved; + stopwatch.Start(); switch (algorithm) @@ -45,12 +46,56 @@ namespace TMI_practicum default: throw new ArgumentException("Algorithm with id: " + algorithm + " is not defined!"); } - + stopwatch.Stop(); WriteOutput(solved, stopwatch.ElapsedMilliseconds); } + private static List CreateRandomCircles(double amount) + { + var circles = new List(); + Random rnd = new Random(); + + for (int i = 0; i < amount; i++) + { + circles.Add(new Circle(Math.Round(rnd.NextDouble() * 1.0, 15), Math.Round(rnd.NextDouble() * 1.0, 15), Math.Round(rnd.NextDouble() * 0.01, 15))); + } + + return circles; + } + + private static void GetChartData() + { + + var stopwatch = new Stopwatch(); + + //warmup + var circles = CreateRandomCircles(20); + IEnumerable solved = SweepLineEffAlgorithm.Solve(circles); + var times = new List(); + + Console.WriteLine("size, time"); + + for (int s = 10; s < 100000; s *= 2) + { + for (int i = 0; i < 100; i++) + { + circles = CreateRandomCircles(s); + + stopwatch.Restart(); + solved = SweepLineEffAlgorithm.Solve(circles); + stopwatch.Stop(); + times.Add(stopwatch.ElapsedMilliseconds); + } + + Console.WriteLine("{0}, {1}", s, times.Average()); + times.Clear(); + } + + stopwatch.Stop(); + } + private static (byte Algorithm, int NbCircles, IList Circles) ParseFile(string path) { diff --git a/TMI-practicum/SweepLineEffAlgorithm.cs b/TMI-practicum/SweepLineEffAlgorithm.cs index ff080e5..5031f53 100644 --- a/TMI-practicum/SweepLineEffAlgorithm.cs +++ b/TMI-practicum/SweepLineEffAlgorithm.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Medallion.Collections; namespace TMI_practicum @@ -9,17 +8,15 @@ namespace TMI_practicum { public static IEnumerable Solve(IEnumerable circles) { - var intersections = new Stack(); + var intersections = new HashSet(); var events = new PriorityQueue(); - - var upperActive = new CircleTree(); - var bottomActive = new CircleTree(); + var active = new C5.TreeDictionary(); foreach (var circle in circles) { - events.Enqueue(new Event(Event.EventType.Start, circle.X - circle.R, circle)); - events.Enqueue(new Event(Event.EventType.End, circle.X + circle.R, circle)); + events.Enqueue(new Event(Event.EventType.Start, circle.X - circle.R, circle, circle.Y)); + events.Enqueue(new Event(Event.EventType.End, circle.X + circle.R, circle, circle.Y)); } while (events.Count != 0) @@ -29,73 +26,63 @@ namespace TMI_practicum switch (e.Type) { case Event.EventType.Start: - upperActive.Add( - new SegmentKey(e.X, e.Circle.Y + e.Circle.R, SegmentKey.SegmentType.Upper, hash), e.Circle); - bottomActive.Add( - new SegmentKey(e.X, e.Circle.Y - e.Circle.R, SegmentKey.SegmentType.Bottom, hash), + active.Add( + new SegmentKey(e.Circle.X, e.Circle.Y + e.Circle.R, SegmentKey.SegmentType.Upper, hash), e.Circle); + active.Add( + new SegmentKey(e.Circle.X, e.Circle.Y - e.Circle.R, SegmentKey.SegmentType.Bottom, hash), e.Circle); - CheckIntersections(upperActive, e, intersections, true); - CheckIntersections(bottomActive, e, intersections, false); + CheckIntersections(active, e, intersections, true, events); + CheckIntersections(active, e, intersections, false, events); break; case Event.EventType.End: - upperActive.Remove(new SegmentKey(e.X, e.Circle.Y + e.Circle.R, SegmentKey.SegmentType.Upper, + CheckIntersections(active, e, intersections, true, events); + CheckIntersections(active, e, intersections, false, events); + active.Remove(new SegmentKey(e.Circle.X, e.Circle.Y + e.Circle.R, SegmentKey.SegmentType.Upper, hash)); - bottomActive.Remove(new SegmentKey(e.X, e.Circle.Y - e.Circle.R, SegmentKey.SegmentType.Bottom, + active.Remove(new SegmentKey(e.Circle.X, e.Circle.Y - e.Circle.R, SegmentKey.SegmentType.Bottom, hash)); break; + case Event.EventType.Intersection: + CheckIntersections(active, e, intersections, true, events); + CheckIntersections(active, e, intersections, false, events); + break; default: throw new ArgumentOutOfRangeException(); } } - - + return intersections; } - private static void CheckIntersections(CircleTree active, Event e, - Stack intersections, bool upper) + private static void CheckIntersections(C5.TreeDictionary active, Event e, + HashSet intersections, bool upper, PriorityQueue events) { - Circle other = null; - try - { - other = upper - ? active.FindSuccessor(new SegmentKey(e.X, e.Circle.Y, SegmentKey.SegmentType.Upper, - e.GetHashCode())) - : active.FindPredecessor(new SegmentKey(e.X, e.Circle.Y, SegmentKey.SegmentType.Bottom, - e.GetHashCode())); - } - catch (KeyNotFoundException) - { - } + + C5.KeyValuePair other; - if (other != null) + if (upper) { - var intersects = e.Circle.FindIntersections(other); - if (intersects != null) + if (!active.TrySuccessor(new SegmentKey(e.X, e.Y, SegmentKey.SegmentType.Upper, + e.GetHashCode()), out other)) + return; + } + else + { + if (!active.TryPredecessor( + new SegmentKey(e.X, e.Y, SegmentKey.SegmentType.Bottom, e.GetHashCode()), out other)) { - foreach (var intersection in intersects) - { - if (upper && e.Circle.Y == intersection.Y) continue; - intersections.Push(intersection); - } + return; } } - } - - - private class CircleTree : SortedDictionary - { - public TValue FindSuccessor(TKey key) + + var intersects = e.Circle.FindIntersections(other.Value); + if (intersects == null) return; + foreach (var intersection in intersects) { - var other = this.Keys.Where(s => this.Comparer.Compare(s, key) > 0).MinOrDefault(); - return this[other]; - } - - public TValue FindPredecessor(TKey key) - { - var other = this.Keys.Where(s => this.Comparer.Compare(s, key) < 0).MaxOrDefault(); - return this[other]; + if (intersections.Contains(intersection)) continue; + events.Add(new Event(Event.EventType.Intersection, intersection.X, e.Circle, intersection.Y)); + intersections.Add(intersection); } } @@ -104,24 +91,40 @@ namespace TMI_practicum public EventType Type { get; } public Circle Circle { get; } public double X { get; } + public double Y { get; } public enum EventType { Start, + Intersection, End } - public Event(EventType type, double x, Circle circle) + public Event(EventType type, double x, Circle circle, double y) { Type = type; X = x; Circle = circle; + Y = y; } public int CompareTo(Event other) { return X.CompareTo(other.X); } + + public override int GetHashCode() + { + unchecked // Overflow is fine, just wrap + { + int hash = 17; + // Suitable nullity checks etc, of course :) + hash = hash * 23 + Type.GetHashCode(); + hash = hash * 23 + X.GetHashCode(); + hash = hash * 23 + Y.GetHashCode(); + return hash; + } + } } private struct SegmentKey : IComparable @@ -168,17 +171,4 @@ namespace TMI_practicum } } } - - public static class EnumerableExtensions - { - public static T MinOrDefault(this IEnumerable sequence) - { - return sequence.Any() ? sequence.Min() : default; - } - - public static T MaxOrDefault(this IEnumerable sequence) - { - return sequence.Any() ? sequence.Max() : default; - } - } } \ No newline at end of file diff --git a/TMI-practicum/TMI-practicum.csproj b/TMI-practicum/TMI-practicum.csproj index faf61bb..7ab512f 100644 --- a/TMI-practicum/TMI-practicum.csproj +++ b/TMI-practicum/TMI-practicum.csproj @@ -33,6 +33,10 @@ 4 + + ..\packages\C5.2.5.3\lib\net45\C5.dll + True + ..\packages\MedallionPriorityQueue.1.1.0\lib\net45\MedallionPriorityQueue.dll True diff --git a/TMI-practicum/packages.config b/TMI-practicum/packages.config index 19d8e41..5d5ea08 100644 --- a/TMI-practicum/packages.config +++ b/TMI-practicum/packages.config @@ -1,5 +1,6 @@  + \ No newline at end of file