SLIDE 1 Growing and Shrinking Polygons
for Random Testing
- f Computational Geometry Algorithms
Ilya Sergey
Experience Report
ICFP 2016 September 20th, 2016
SLIDE 2
Polygons
SLIDE 3
Polygons
SLIDE 4
Polygons
SLIDE 5
Polygons
SLIDE 6
Polygons are Trees
SLIDE 7 Polygons are Trees
SLIDE 8 Polygons are Trees
- We can grow them;
- We can also trim them;
SLIDE 9 Polygons are Trees
- We can grow them;
- We can also trim them;
- We can use QuickCheck to test their properties.
SLIDE 10
SLIDE 11
SLIDE 12
SLIDE 13 Would you like to run a scenario project this year?
SLIDE 14 Sure,
why not.
Would you like to run a scenario project this year?
SLIDE 15
Scenario Project Requirements
SLIDE 16 Scenario Project Requirements
- For 2nd year undergrads, team work,
SLIDE 17 Scenario Project Requirements
- For 2nd year undergrads, team work,
- One week-long,
SLIDE 18 Scenario Project Requirements
- For 2nd year undergrads, team work,
- One week-long,
- Should involve math and programming,
SLIDE 19 Scenario Project Requirements
- For 2nd year undergrads, team work,
- One week-long,
- Should involve math and programming,
- Challenging for students, but easy to assess,
SLIDE 20 Scenario Project Requirements
- For 2nd year undergrads, team work,
- One week-long,
- Should involve math and programming,
- Challenging for students, but easy to assess,
- To be delivered in about a month.
SLIDE 21 Scenario Project Requirements
- For 2nd year undergrads, team work,
- One week-long,
- Should involve math and programming,
- Challenging for students, but easy to assess,
- To be delivered in about a month.
SLIDE 22
SLIDE 23
SLIDE 24
SLIDE 25
SLIDE 26
How many guards do we really need?
SLIDE 27 How many guards do we really need?
The answer depends on the shape of the gallery.
SLIDE 28 How many guards do we really need?
The answer depends on the shape of the gallery.
SLIDE 29 How many guards do we really need?
The answer depends on the shape of the gallery.
SLIDE 30
How many guards do we really need?
SLIDE 31
How many guards do we really need?
SLIDE 32
How many guards do we really need?
SLIDE 33
How many guards do we really need?
SLIDE 34 For a given gallery (polygon),
find the minimal set of guards’ positions,
so together the guards can “see” the whole interior.
Art Gallery Problem
SLIDE 35 For a given gallery (polygon),
find the minimal set of guards’ positions,
so together the guards can “see” the whole interior.
NP-hard
Art Gallery Problem
SLIDE 36 Project: Art Gallery Competition
Find the best solutions for a collection of large polygons.
SLIDE 37 Project: Art Gallery Competition
Find the best solutions for a collection of large polygons.
SLIDE 38
Organizers’ TODO
SLIDE 39 Organizers’ TODO
- Problem generator;
- Polygons with different “features” (convex, rectangular, etc.)
SLIDE 40 Organizers’ TODO
- Problem generator;
- Polygons with different “features” (convex, rectangular, etc.)
- Solution checker with online feedback
- geometric machinery (triangulation, visibility, …)
- web-server
SLIDE 41 Organizers’ TODO
- Problem generator;
- Polygons with different “features” (convex, rectangular, etc.)
- Solution checker with online feedback
- geometric machinery (triangulation, visibility, …)
- web-server
- Make sure that it all works.
SLIDE 42 Organizers’ TODO
- Problem generator;
- Polygons with different “features” (convex, rectangular, etc.)
- Solution checker with online feedback
- geometric machinery (triangulation, visibility, …)
- web-server
- Make sure that it all works.
SLIDE 43 Organizers’ TODO
- Problem generator;
- Polygons with different “features” (convex, rectangular, etc.)
- Solution checker with online feedback
- geometric machinery (triangulation, visibility, …)
- web-server
- Make sure that it all works.
SLIDE 44
- Problem generator;
- Polygons with different “features” (convex, rectangular, etc.)
- Solution checker with online feedback
- geometric machinery (triangulation, visibility, …)
- web-server
- Make sure that it all works.
Organizers’ TODO
SLIDE 45
Growing polygons
SLIDE 46 Growing polygons
Primitive polygons with specific “features”
SLIDE 47 Growing polygons
Primitive polygons with specific “features”
SLIDE 48 Seed
Growing polygons
SLIDE 49 Seed
Growing polygons
SLIDE 50
Growing polygons
SLIDE 51
Growing polygons
SLIDE 52
Growing polygons
SLIDE 53
Growing polygons
SLIDE 54
Growing polygons
SLIDE 55
Growing polygons
SLIDE 56
Growing polygons
SLIDE 57
Growing polygons
SLIDE 58
Growing polygons
SLIDE 59
Growing polygons
SLIDE 60
Growing polygons
SLIDE 61 Algorithm for growing polygons
1. Pick a primitive polygon; 2. Locate a segment on a host polygon edge; 3. Scale, rotate and attach the primitive;
check for self-intersections
SLIDE 62 Abstract polygon generator
trait PolygonGenerator extends GeneratorPrimitives {
val seeds : List[Polygon] val primitives : List[(Int) => Polygon] val locate : Double => Option[(Double, Double)] val seedFreqs : List[Int] val primFreqs : List[Int] val generations : Int ... }
SLIDE 63 Abstract polygon generator
trait PolygonGenerator extends GeneratorPrimitives {
val seeds : List[Polygon] val primitives : List[(Int) => Polygon] val locate : Double => Option[(Double, Double)] val seedFreqs : List[Int] val primFreqs : List[Int] val generations : Int ... }
SLIDE 64 Abstract polygon generator
trait PolygonGenerator extends GeneratorPrimitives {
val seeds : List[Polygon] val primitives : List[(Int) => Polygon] val locate : Double => Option[(Double, Double)] val seedFreqs : List[Int] val primFreqs : List[Int] val generations : Int ... }
SLIDE 65 Abstract polygon generator
trait PolygonGenerator extends GeneratorPrimitives {
val seeds : List[Polygon] val primitives : List[(Int) => Polygon] val locate : Double => Option[(Double, Double)] val seedFreqs : List[Int] val primFreqs : List[Int] val generations : Int ... }
SLIDE 66 Generating contest problems
Rectilinear
SLIDE 67 Quasi-convex
Generating contest problems
SLIDE 68 Crazy
Generating contest problems
SLIDE 69
- Problem generator;
- Polygons with different “features” (convex, rectangular, etc.)
- Solution checker with online feedback
- geometric machinery (triangulation, visibility, …)
- web-server
- Make sure that it all works.
Organizers’ TODO
SLIDE 70
- Problem generator;
- Polygons with different “features” (convex, rectangular, etc.)
- Solution checker with online feedback
- geometric machinery (triangulation, visibility, …)
- web-server
- Make sure that it all works.
Organizers’ TODO
SLIDE 71
Testing with ScalaCheck
SLIDE 72 Testing with ScalaCheck
- Triangulation of a polygon of size N:
- centre of each triangle lies within a polygon;
- triangulation generates N − 2 (possibly degenerate) triangles;
SLIDE 73 Testing with ScalaCheck
- Triangulation of a polygon of size N:
- centre of each triangle lies within a polygon;
- triangulation generates N − 2 (possibly degenerate) triangles;
- Joe-Simpson algorithm for visibility polygons (VPs):
- a vertex of a VP is also within the original polygon;
- every VP’s edge is within the original polygon;
- a random point within a VP is indeed visible from its origin;
SLIDE 74 Testing with ScalaCheck
- Triangulation of a polygon of size N:
- centre of each triangle lies within a polygon;
- triangulation generates N − 2 (possibly degenerate) triangles;
- Joe-Simpson algorithm for visibility polygons (VPs):
- a vertex of a VP is also within the original polygon;
- every VP’s edge is within the original polygon;
- a random point within a VP is indeed visible from its origin;
- Solution visibility checker:
- a refutation (if it exists) is within the original polygon;
- a refutation for a set of guards is not within any of their VPs;
SLIDE 75 Testing with ScalaCheck
- Triangulation of a polygon of size N:
- centre of each triangle lies within a polygon;
- triangulation generates N − 2 (possibly degenerate) triangles;
- Joe-Simpson algorithm for visibility polygons (VPs):
- a vertex of a VP is also within the original polygon;
- every VP’s edge is within the original polygon;
- a random point within a VP is indeed visible from its origin;
- Solution visibility checker:
- a refutation (if it exists) is within the original polygon;
- a refutation for a set of guards is not within any of their VPs;
- Basic algorithm for solving AGP by Fisk:
- delivers a solution of size within the boundary ⌊N/3⌋;
- the solution checker finds no refutations for its result.
SLIDE 76
How well did that work?
SLIDE 77 How well did that work?
- Multiple bugs (>20) due to inaccurate treatment of
floating points;
SLIDE 78 How well did that work?
- Multiple bugs (>20) due to inaccurate treatment of
floating points;
- Several bugs (~10) due to misreading of the textbook
algorithms or simplifications in their descriptions;
SLIDE 79 How well did that work?
- Multiple bugs (>20) due to inaccurate treatment of
floating points;
- Several bugs (~10) due to misreading of the textbook
algorithms or simplifications in their descriptions;
- Two bugs in the Joe-Simpson algorithm itself;
SLIDE 80 How well did that work?
- Multiple bugs (>20) due to inaccurate treatment of
floating points;
- Several bugs (~10) due to misreading of the textbook
algorithms or simplifications in their descriptions;
- Two bugs in the Joe-Simpson algorithm itself;
- Bonus: an undocumented behavior in the
state-of-the-art CGAL library
(written in C++ using exact arithmetics).
SLIDE 81 How well did that work?
- Multiple bugs (>20) due to inaccurate treatment of
floating points;
- Several bugs (~10) due to misreading of the textbook
algorithms or simplifications in their descriptions;
- Two bugs in the Joe-Simpson algorithm itself;
- Bonus: an undocumented behavior in the
state-of-the-art CGAL library
(written in C++ using exact arithmetics).
SLIDE 82 Testing basic visibility algorithm
- Main component for checking arbitrary solutions;
- Original description (1986) has a number of simplifications and
is given in pseudocode.
SLIDE 83 import RandomRectilinearPolygonGenerator._
property("All visibility polygons lie within the original polygon") =
forAll { (p : Polygon) =>
val guards = p.vertices
val vps = guards.map(visibilityPolygon(p, _))
"Every edge of a visibility polygon is within ${p}" |: {
val edges = for (vp <- vps; e <- vp.edges) yield e
edges.forall(p.containsSegment)
}
}
Testing basic visibility algorithm
SLIDE 84 import RandomRectilinearPolygonGenerator._
property("All visibility polygons lie within the original polygon") =
forAll { (p : Polygon) =>
val guards = p.vertices
val vps = guards.map(visibilityPolygon(p, _))
"Every edge of a visibility polygon is within ${p}" |: {
val edges = for (vp <- vps; e <- vp.edges) yield e
edges.forall(p.containsSegment)
}
}
Testing basic visibility algorithm
SLIDE 85 import RandomRectilinearPolygonGenerator._
property("All visibility polygons lie within the original polygon") =
forAll { (p : Polygon) =>
val guards = p.vertices
val vps = guards.map(visibilityPolygon(p, _))
"Every edge of a visibility polygon is within ${p}" |: {
val edges = for (vp <- vps; e <- vp.edges) yield e
edges.forall(p.containsSegment)
}
}
Testing basic visibility algorithm
SLIDE 86 import RandomRectilinearPolygonGenerator._
property("All visibility polygons lie within the original polygon") =
forAll { (p : Polygon) =>
val guards = p.vertices
val vps = guards.map(visibilityPolygon(p, _))
"Every edge of a visibility polygon is within ${p}" |: {
val edges = for (vp <- vps; e <- vp.edges) yield e
edges.forall(p.containsSegment)
}
}
Testing basic visibility algorithm
SLIDE 87 Bug in Joe-Simpson algorithm
Randomly generated, 260 vertices, guards in every node
SLIDE 88 Bug in Joe-Simpson algorithm
??! Randomly generated, 260 vertices, guards in every node
SLIDE 89
Shrinking Polygons
SLIDE 90
Shrinking Polygons Trimming
SLIDE 91
Reconstructing polygon generation
SLIDE 92 Reconstructing polygon generation
1 2 3 4 5 6 7 1 2 3 4 5 6 7
SLIDE 93 Reconstructing polygon generation
1 2 3 4 5 6 7 1 2 3 4 5 6 7
“Attachment tree”
SLIDE 94 Trimming polygons
1 3 4 5 6 7 1 2 4 5 6 7 3 2
SLIDE 95 1 2 3 4 5 6 7 1 2 3 4 5 6 7
Trimming polygons
SLIDE 96 Shrinking strategy
- Build the attachment tree while constructing a
random polygon;
- Construct all its subtrees;
- “Render” the corresponding trimmed polygons.
SLIDE 97 Bug in Joe-Simpson algorithm
Randomly generated, 260 vertices, guards in every node
SLIDE 98 Bug in Joe-Simpson algorithm
Randomly generated, 260 vertices, guards in every node
SLIDE 99 Bug in Joe-Simpson algorithm
After trimming, 20 vertices
SLIDE 100 Bug in Joe-Simpson algorithm
Removed
irrelevant guards
SLIDE 101
Bug in Joe-Simpson algorithm
SLIDE 102
Bug in Joe-Simpson algorithm
SLIDE 103 ... intersectWithWindow(v(i), v(i + 1), s.top, windowEnd) match {
case Some(p) =>
s.push(p)
advance(v, s, i)
case _ =>
scan(v, s, i, windowEnd, ccw)
} ...
Bug in Joe-Simpson algorithm
SLIDE 104 Bug in Joe-Simpson algorithm
... intersectWithWindow(v(i), v(i + 1), s.top, windowEnd) match {
case Some(p) if !(windowEnd.isDefined && p =~= windowEnd) =>
s.push(p)
advance(v, s, i)
case _ =>
scan(v, s, i, windowEnd, ccw)
} ...
SLIDE 105 Implementation effort
- Geometric primitives and procedures: 1450 LOC
- Server infrastructure: 1500 LOC
- Testing framework: 350 LOC
SLIDE 106
Running the Art Gallery Competition
SLIDE 107 Running the Art Gallery Competition
- 94 participants, 24 teams, 2360 submissions in five days
SLIDE 108 Running the Art Gallery Competition
- 94 participants, 24 teams, 2360 submissions in five days
- Server running 24/5
- for different teams, solution processed concurrently
- no crashes during the week
- one non-critical bug in server logic (fixed without restarting)
SLIDE 109 Running the Art Gallery Competition
- 94 participants, 24 teams, 2360 submissions in five days
- Server running 24/5
- for different teams, solution processed concurrently
- no crashes during the week
- one non-critical bug in server logic (fixed without restarting)
- Most of the solutions: textbook algorithm with optimizations;
SLIDE 110 Running the Art Gallery Competition
- 94 participants, 24 teams, 2360 submissions in five days
- Server running 24/5
- for different teams, solution processed concurrently
- no crashes during the week
- one non-critical bug in server logic (fixed without restarting)
- Most of the solutions: textbook algorithm with optimizations;
- The winning team implemented the state-of-the art algorithm
(2014) using linear programming;
SLIDE 111 Mon Tue Wed The Fri
SLIDE 112
To take away
SLIDE 113 To take away
- FP works great for rapid development of
non-trivial and robust geometric applications;
SLIDE 114 To take away
- FP works great for rapid development of
non-trivial and robust geometric applications;
- QuickCheck-ing CG with polygons is
feasible and efficient in practice;
SLIDE 115 To take away
- FP works great for rapid development of
non-trivial and robust geometric applications;
- QuickCheck-ing CG with polygons is
feasible and efficient in practice;
- Polygons can be grown and trimmed,
just like trees.
SLIDE 116 To take away
Thanks!
- FP works great for rapid development of
non-trivial and robust geometric applications;
- QuickCheck-ing CG with polygons is
feasible and efficient in practice;
- Polygons can be grown and trimmed,
just like trees.