PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/benchmarks/php-octane/quick-hull.php

http://github.com/facebook/hiphop-php
PHP | 189 lines | 148 code | 28 blank | 13 comment | 29 complexity | 40d8347abe2898446a597e98d8f8f2c1 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, MIT, LGPL-2.0, Apache-2.0
  1. <?
  2. $MIN_POS = -100000;
  3. $MAX_POS = 100000;
  4. function generatePoints($n) {
  5. global $MIN_POS;
  6. global $MAX_POS;
  7. $points = array();
  8. for ($i = 0; $i < $n; $i++) {
  9. array_push($points, array(
  10. "x" => (float)rand($MIN_POS, $MAX_POS),
  11. "y" => (float)rand($MIN_POS, $MAX_POS)
  12. ));
  13. }
  14. array_unique($points, SORT_REGULAR);
  15. return $points;
  16. }
  17. function findMinXPos($points) {
  18. if (count($points) === 0) return null;
  19. $min_x_point = $points[0];
  20. for ($i = 1; $i < count($points); $i++) {
  21. $current_point = $points[$i];
  22. if ($min_x_point["x"] < $current_point["x"]) {
  23. $min_x_point = $current_point;
  24. }
  25. }
  26. return $min_x_point;
  27. }
  28. function side($a, $b, $c) {
  29. // Returns positive or negative depending on which side $c is when looking
  30. // from $a to $b.
  31. $determinant = ($b['x'] - $a['x']) * ($c['y'] - $a['y']) -
  32. ($b['y'] - $a['y']) * ($c['x'] - $a['x']);
  33. if ($determinant > 0) return 1;
  34. if ($determinant < 0) return -1;
  35. return 0;
  36. }
  37. function isInTriangle($p, $a, $b, $c) {
  38. list($p_x, $p_y) = array($p['x'], $p['y']);
  39. list($a_x, $a_y) = array($a['x'], $a['y']);
  40. list($b_x, $b_y) = array($b['x'], $b['y']);
  41. list($c_x, $c_y) = array($c['x'], $c['y']);
  42. $denom = ($b_y - $c_y) * ($a_x - $c_x) + ($c_x - $b_x) * ($a_y - $c_y);
  43. if ($denom > 0 || $denom < 0) {
  44. $alpha = (($b_y - $c_y) * ($p_x - $c_x) + ($c_x - $b_x) * ($p_y - $c_y)) /
  45. $denom;
  46. $beta = (($c_y - $a_y) * ($p_x - $c_x) + ($a_x - $c_x) * ($p_y - $c_y)) /
  47. $denom;
  48. } else {
  49. $alpha = 0.0;
  50. $beta = 0.0;
  51. }
  52. $gamma = 1.0 - $alpha - $beta;
  53. return $alpha > 0.0 && $beta > 0.0 && $gamma > 0.0;
  54. }
  55. function lineEquation($p1, $p2) {
  56. // y = mx + b
  57. // b = y - mx
  58. // mx - y + b = 0
  59. // ax + by + c = 0
  60. list($x1, $y1) = array($p1['x'], $p1['y']);
  61. list($x2, $y2) = array($p2['x'], $p2['y']);
  62. if ($x1 === $x2) {
  63. return array(
  64. "a" => 1.0,
  65. "b" => 0.0,
  66. "c" => -$x1
  67. );
  68. }
  69. $slope = ($y2 - $y1) / ($x2 - $x1);
  70. $b = $y1 - $slope * $x1;
  71. return array(
  72. "a" => $slope,
  73. "b" => -1.0,
  74. "c" => $b
  75. );
  76. }
  77. function distanceToLine($line, $p) {
  78. list($a, $b, $c) = array($line['a'], $line['b'], $line['c']);
  79. list($x_0, $y_0) = array($p['x'], $p['y']);
  80. return abs($a * $x_0 + $b * $y_0 + $c) / sqrt($a * $a + $b * $b);
  81. }
  82. function partitionSides($a, $b, $points) {
  83. return array(
  84. array_values(array_filter($points, function($p) use ($a, $b) {
  85. if ($p == $a || $p == $b)
  86. return false;
  87. return side($a, $b, $p) >= 0.0;
  88. })),
  89. array_values(array_filter($points, function($p) use ($a, $b) {
  90. if ($p == $a || $p == $b)
  91. return false;
  92. return side($a, $b, $p) < 0.0;
  93. }))
  94. );
  95. }
  96. function buildHullWithTriangles($a, $b, $points) {
  97. if (count($points) < 2) return $points;
  98. $hull = array();
  99. // Step 3: Find the point that is farthest from the dividing line.
  100. $line = lineEquation($a, $b);
  101. $farthest_dist = 0.0;
  102. $farthest_point = array_reduce($points,
  103. function($carry, $item) use ($line, &$farthest_dist) {
  104. $dist = distanceToLine($line, $item);
  105. if ($dist > $farthest_dist) {
  106. $farthest_dist = $dist;
  107. return $item;
  108. }
  109. return $carry;
  110. }, $points[0]);
  111. array_push($hull, $farthest_point);
  112. // Step 4: Filter out all points inside the triangle formed by the new point.
  113. $c = $farthest_point;
  114. $outsideTriangle = array_values(
  115. array_filter($points, function($p) use ($a, $b, $c) {
  116. if ($p == $a || $p == $b || $p == $c)
  117. return false;
  118. return !isInTriangle($p, $a, $b, $c);
  119. }));
  120. list($side1, $side2) = partitionSides($a, $c, $outsideTriangle);
  121. // Step 5: Using the two new lines, recursively create triangles to filter
  122. // points until there are no more left.
  123. $hull = array_merge(
  124. $hull,
  125. buildHullWithTriangles($a, $c, $side1),
  126. buildHullWithTriangles($b, $c, $side2)
  127. );
  128. return $hull;
  129. }
  130. function findConvexHull($points) {
  131. if (count($points) < 4) return $points;
  132. $hull = array();
  133. // Step 1: Find the two points with the min and max x positions.
  134. $min_point = array_reduce($points, function($carry, $item) {
  135. return ($item["x"] < $carry["x"]) ? $item : $carry;
  136. }, $points[0]);
  137. $max_point = array_reduce($points, function($carry, $item) {
  138. return ($item["x"] > $carry["x"]) ? $item : $carry;
  139. }, $points[0]);
  140. array_push($hull, $min_point, $max_point);
  141. // Step 2: Use the line between the two points to divide the remaining
  142. // points into two sets, one for each side of the line.
  143. list($side1, $side2) = partitionSides($min_point, $max_point, $points);
  144. $hull = array_merge(
  145. $hull,
  146. buildHullWithTriangles($min_point, $max_point, $side1),
  147. buildHullWithTriangles($min_point, $max_point, $side2)
  148. );
  149. return $hull;
  150. }
  151. function verifyConvexHull($actual, $expected) {
  152. return true;
  153. }
  154. $quickHull = function() {
  155. srand(42);
  156. $points = generatePoints(1000);
  157. $hull = findConvexHull($points);
  158. };
  159. $QuickHull = new BenchmarkSuite('QuickHull', [100000], array(
  160. new Benchmark('QuickHull', true, false, 4400, $quickHull)
  161. ));