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