/[drupal]/contributions/sandbox/aronnovak/graph_creating/routes.php
ViewVC logotype

Contents of /contributions/sandbox/aronnovak/graph_creating/routes.php

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.20 - (show annotations) (download) (as text)
Tue Aug 15 19:19:24 2006 UTC (3 years, 3 months ago) by aronnovak
Branch: MAIN
CVS Tags: HEAD
Changes since 1.19: +48 -24 lines
File MIME type: text/x-php
Beautifuled code and major bugfixes
1 <?php
2 // $Id$
3 /**
4 * Finding minimal routes, BFS and DFS searches, collecting groups from the graph
5 *
6 * @author Aron Novak <aaron@szentimre.hu>
7 * @version 0.1
8 * @package sna
9 */
10
11 /**
12 * Get sql access and important functions
13 */
14 require_once 'common.php';
15
16 /**
17 * Track back the route
18 *
19 * @param array $result The minimal tree of routes
20 * @param integer $to The vertex's id
21 * @return array The route from $to to the root
22 */
23 function rollback($result, $to) {
24
25 $out = array();
26 $prev = $to;
27
28 while ($result['prev'][$prev] != '-') {
29 $out[] = array('n' => $prev, 'd' => $result['dist'][$prev]);
30 $prev = $result['prev'][$prev];
31 }
32 return $out;
33 }
34
35 /**
36 * Returns the shortest route from <var>$from</var> to <var>$to</var>
37 *
38 * @param array $edges The adjacentcy list of the graph
39 * @param integer $from The from vertex
40 * @param integer $to The to vertex
41 * @param boolean $step If False - Dijkstra, True - BFS
42 */
43 function a_to_b($edges, $from, $to, $step = FALSE) {
44 if ($from === $to) {
45 return array();
46 }
47 if ($step === FALSE) {
48 $min_tree = a_to_any($edges, $from);
49 }
50 else {
51 $min_tree = breadth_first_walk($edges, $from, -1);
52 }
53 /*print "eredm\n";
54 print_r($min_tree);
55 print "eredmvege\n";
56 ob_flush();*/
57 if (isset($min_tree['dist'][$to]) && $min_tree['dist'][$to] !== '-') {
58 $route = rollback($min_tree, $to);
59 $route[] = array('n' => $from, 'd' => 0);
60 return $route;
61 }
62 else {
63 return FALSE;
64 }
65 }
66
67 /**
68 * Measure the needed steps between two vertices
69 *
70 * @param array $edges The adjacentcy list of the graph
71 * @param integer $from The from vertex
72 * @param integer $to The to vertex
73 * @return integer The count of needed steps
74 */
75 function n_step_distance($edges, $from, $to) {
76 static $cached, $cached_uid;
77 if ($from === $to) {
78 return 0;
79 }
80 if ($cached_uid === $from && is_array($cached)) {
81 /* It's optimal caching because the average_step_separation function
82 calls this function repeatedly */
83 $min_tree = $cached;
84 }
85 else {
86 $min_tree = breadth_first_walk($edges, $from, -1);
87 $cached = $min_tree;
88 $cached_uid = $from;
89 }
90
91 if (isset($min_tree['dist'][$to]) && $min_tree['dist'][$to] !== '-') {
92 $route = rollback($min_tree, $to);
93 return count($route);
94 }
95 else {
96 return FALSE;
97 }
98 }
99
100 /**
101 * Compute the average step of separation in the network
102 *
103 * @param array $edges The adjacentcy list of the graph
104 * @return integer Step of separation
105 */
106 function average_step_separation($edges) {
107 $users = get_all_vertices();
108 $num = 0;
109 foreach ($users as $uid1) {
110 foreach ($users as $uid2) {
111 if ($uid1 !== $uid2) {
112 $dist = n_step_distance($edges, $uid1, $uid2);
113 if ($dist !== FALSE) {
114 //print "F:" . $uid1 . " T:" . $uid2 . " D:" . $dist . "\n";
115 $sum += $dist;
116 ++$num;
117 }
118 }
119 }
120 //print $uid1 . " is done\n";
121 }
122 if ($num != 0) { // Avoid division by zero!
123 return $sum / $num;
124 }
125 else {
126 return 0;
127 }
128 }
129
130 /**
131 * Read the graph from storage
132 *
133 * @param array_ref $edges This array will be filled with the graph's adjacentcy list
134 */
135 function get_graph(&$edges) {
136 include(DATA_PATH);
137 $limit = variable_get('sna_limit', 0);
138 if ($limit > 0) {
139 $edges = shrink($edges, $limit);
140 }
141 }
142
143 /**
144 * Breadt-first search algorithm
145 *
146 * @param graph $edges The adjacentcy list of the graph
147 * @param vertex $start Starting vertex
148 * @param integer $max Maximum step. -1 for no limit
149 * @return array Result
150 */
151 function breadth_first_walk($edges, $start, $max = -1) {
152 // Set start values
153 foreach ($edges as $key => $rel) {
154 $c[$key] = 0;
155 /* Color of point. 0 - white, 1 - grey, 2 - black
156 white - not reached
157 grey - reached
158 black - reached and all neighbours is reached too
159 */
160 $d[$key] = '-'; // Distance from $start
161 $p[$key] = '-'; // Previous vertex
162 foreach (array_keys($rel) as $child) {
163 $c[$child] = 0;
164 $d[$child] = '-';
165 $p[$child] = '-';
166 }
167 }
168 $c[$start] = 1;
169 $d[$start] = 0;
170 $p[$start] = '-';
171 $Q = array();
172 $Q[] = $start;
173 while (!empty($Q)) {
174 foreach ($Q as $vk => $vertex) {
175 if ($c[$vertex] === 1) {
176 $u = $vertex;
177 $u_k = $vk;
178 break;
179 }
180 }
181 if (($max !== -1) && $d[$u] + 1 > $max) { // Reached the specified depth
182 return array('dist' => $d, 'prev' => $p);
183 }
184 $neighbours = is_array($edges[$u]) ? array_keys($edges[$u]) : array();
185 foreach ($neighbours as $vert) {
186 if ($c[$vert] === 0) {
187 $c[$vert] = 1;
188 $d[$vert] = $d[$u] + 1;
189 $p[$vert] = $u;
190 $Q[] = $vert;
191 }
192 }
193 $c[$u] = 2;
194 unset($Q[$u_k]);
195 }
196 return array('dist' => $d, 'prev' => $p);
197 }
198
199 /**
200 * Depth-first search algorithm
201 *
202 * @param array $edges The adjacentcy list of the graph
203 */
204 function depth_first_walk($edges) {
205 foreach (array_keys($edges) as $u) {
206 $c[$u] = 0;
207 /* Color of point. 0 - white, 1 - grey, 2 - black
208 white - not reached
209 grey - reached
210 black - reached and all neighbours is reached too
211 */
212 $p[$u] = '-'; // Previous vertex
213 }
214 $time = 0;
215 foreach (array_keys($edges) as $u) {
216 if ($c[$u] === 0) {
217
218 walk($u, $edges, $time, $c, $p, $f, $d);
219
220 }
221 }
222 return array($f, $p);
223 }
224
225 /**
226 * Depth-first search according to a previous BFS result (for interconnected parts)
227 *
228 * @param array $edges The adjacentcy list of the graph
229 * @param array $prev_res The previous BFS's results
230 */
231 function mod_depth_first_walk($edges, $prev_res) {
232 $prev_f = $prev_res[0];
233 $p = $prev_res[1];
234 foreach (array_keys($edges) as $u) {
235 $c[$u] = 0;
236 /* Color of point. 0 - white, 1 - grey, 2 - black
237 white - not reached
238 grey - reached
239 black - reached and all neighbours is reached too
240 */
241 $p[$u] = '-'; // Previous vertex
242 }
243 $time = 0;
244 $prev_f_keys = empty($prev_f) ? array() : array_keys($prev_f);
245 while ($u = array_pop($prev_f_keys)) {
246 if ($c[$u] === 0) {
247 walk($u, $edges, $time, $c, $p, $f, $d);
248 }
249 }
250 return array($f, $p, $d);
251 }
252
253 /**
254 * Helper function for BFS search algorithm
255 *
256 * @param integer $u The vertex's id
257 * @param array $edges The adjacentcy list of the graph
258 */
259 function walk($u, $edges, &$time, &$c, &$p, &$f, &$d) {
260
261 $c[$u] = 1;
262 $d[$u] = $time++;
263 foreach (array_keys($edges[$u]) as $v) {
264 if ($c[$v] === 0) {
265 $p[$v] = $u;
266 walk($v, $edges, $time, $c, $p, $f, $d);
267 }
268 }
269 $c[$u] = 2;
270 $f[$u] = $time++;
271
272 }
273
274 /**
275 * Generate GML for outside tree visualization
276 * Input for http://www.cs.ubc.ca/~sfingram/cs533C/small_world.html
277 *
278 * @param array $tree The BFS search result
279 */
280 function show_tree($tree) {
281 $num_of_edges = 0;
282 foreach ($tree['prev'] as $vert => $prev) {
283 if (is_numeric($prev)) {
284 $map .= "<param name=\"edge". $num_of_edges++ ."\" value=\"". str_replace(' ', '_', get_real_name($prev)) . ' ' . str_replace(' ', '_', get_real_name($vert)) ."\">";
285 }
286 }
287 $map .= "<param name=\"edgenum\" value=\"". $num_of_edges ."\">";
288 return $map;
289 }
290
291 /**
292 * Generate GML for outside network visualization
293 *
294 *
295 * @param array $edges The adjacentcy list of the graph
296 * @return string The GML string
297 */
298 function show_map($edges) {
299 $num_of_edges = 0;
300 foreach (array_keys($edges) as $A) {
301 foreach (array_keys($edges[$A]) as $B) {
302 $map .= "<param name=\"edge". $num_of_edges++ ."\" value=\"". str_replace(' ', '_', get_real_name($A)) . ' ' . str_replace(' ', '_', get_real_name($B)) ."\">";
303
304 }
305
306 }
307 $map .= "<param name=\"edgenum\" value=\"". $num_of_edges ."\">";
308 return $map;
309 }
310
311 /**
312 * Transpose a graph.
313 * $new grgraph is $edges with all its edges reversed.
314 *
315 * @param array $edges The original graph
316 * @return array $new_graph The transposed graph
317 */
318 function transpose($edges) {
319 $new_graph = array();
320 foreach (array_keys($edges) as $A) {
321 foreach (array_keys($edges[$A]) as $B) {
322 $new_graph[$B][$A] = $edges[$A][$B];
323 }
324 }
325 return $new_graph;
326 }
327
328 /**
329 * Collect interconnected subgraphs according to two DFS search.
330 *
331 * @param array $prev The result of DFS
332 * @return array The subgraphs (vertices list)
333 */
334 function search_groups($edges) {
335
336 $dfs_res = depth_first_walk($edges);
337
338 $mod_dfs_res = mod_depth_first_walk(transpose($edges), $dfs_res);
339 $f = $mod_dfs_res[0];
340 $prev = $mod_dfs_res[1];
341 if (empty($prev)) {
342 return array();
343 }
344 $d = $mod_dfs_res[2];
345 $d = empty($d) ? array() : $d;
346 $f = empty($f) ? array() : $f;
347 $groups = array();
348 $index = 0;
349 foreach (array_keys($prev) as $vert) {
350 if ($prev[$vert] === '-') {
351 $time = $d[$vert] + 1;
352 $groups[$index][] = $vert;
353 while ((($key = array_search($time, $d)) || array_search($time, $f)) && $prev[$key] !== '-') {
354 if (!empty($key)) {
355 $groups[$index][] = $key;
356 unset($prev[$key]);
357 }
358 //$vert_prev = $prev[$vert_prev];
359 $time++;
360 }
361 $index++;
362
363 }
364 }
365 return $groups;
366
367 }
368 /**
369 * Throw away edges from an adjacentcy list according to edge weight
370 *
371 * @param array $edges The adjacentcy list of the graph
372 * @return array The shrinked $edges graph
373 */
374 function shrink($edges, $limit) {
375 foreach (array_keys($edges) as $A) {
376 foreach (array_keys($edges[$A]) as $B) {
377 if ($edges[$A][$B] > $limit) {
378 unset($edges[$A][$B]);
379 }
380 }
381 }
382 return $edges;
383 }
384
385 /**
386 * Collect all the vertices degree
387 *
388 * @param array $edges The adjacentcy list of the graph
389 */
390 function distribution_of_degree($edges) {
391 $dist = array();
392 foreach (array_keys($edges) as $vertex) {
393 $dist[] = vertex_degree($edges, $vertex);
394 }
395 rsort($dist);
396 return $dist;
397 }
398
399 /**
400 * Draw a distribution of edges picture in SVG format. (should be replaced with imagemagick integration module?)
401 *
402 * @param array $distribution
403 * @return string The SVG picture file
404 */
405 function visualize_distribution($distribution) {
406 $max = $distribution[0];
407 $height = count($distribution) == 0 ? 1 : count($distribution);
408 $scale_height_factor = PIC_HEIGHT / $height;
409 $scale_width_factor = PIC_WIDTH / $height;
410 $svg_pic = '<svg width = "'. PIC_WIDTH .'px" height = "'. PIC_HEIGHT .'px" xmlns = "http://www.w3.org/2000/svg">';
411 $svg_pic .= '<g transform="scale('. $scale_width_factor .' '. $scale_height_factor .')">';
412 /* Draw the curve */
413 $svg_pic .= '<polygon style="fill: #000000; stroke: #000000" points="';
414 for ($i = 0; $i < $height; $i++) {
415 if ($num !== 0) {
416 $svg_pic .= ($i + 1) .",". ($height -($height * ($distribution[$i] / $max))) ." ";
417 }
418 }
419 $svg_pic .= "0,". $height;
420 $svg_pic .= ' " /> ';
421 /* Create the captions */
422 $svg_pic .= '<text x = "'. $height * 0.01 .'" y = "'. $height * 0.09 .'"
423 font-family = "Verdana" font-size = "'. $height / 30 .'" fill = "blue" >'. $max .'</text>';
424 $svg_pic .= '</g></svg>';
425 return $svg_pic;
426 }
427
428 /**
429 * Watts-Strogatz: Clustering coefficient
430 * The clustering coefficient for a vertex is the proportion of links between the vertices within
431 * its neighbourhood divided by the number of links that could possibly exist between them.
432 *
433 * @param integer $vertex
434 * @param array $edges The adjacentcy list of the graph
435 */
436 function clustering_coefficient($edges, $vertex) {
437 if (!isset($edges[$vertex])) {
438 if (function_exists('t')) { // Used in drupal, so we inform the user
439 return t('Cannot compute clustering coefficient while user not have any connection.');
440 }
441 else { // Used in sna_test so possible to be rude :)
442 return FALSE;
443 }
444 }
445 /* Count the edges between the */
446 $num_conn = 0;
447 //print_r($edges);
448 $neighbours = array_keys($edges[$vertex]);
449 foreach ($neighbours as $vert) {
450 if (is_array($edges[$vert])) {
451 foreach (array_keys($edges[$vert]) as $vert_next) {
452 if (array_search($vert_next, $neighbours) !== FALSE) {
453 $num_conn++;
454 }
455 }
456 }
457 }
458 $kn_vertices = num_vertices_of_complete_graph(count($neighbours));
459 return $kn_vertices === 0 ? 0 : $num_conn / $kn_vertices;
460 }
461
462 /**
463 * Compute the number of edges in Kn graph.
464 *
465 * @param integer $n Number of vertices
466 * @return integer number of edges
467 */
468 function num_vertices_of_complete_graph($n) {
469 return $n * ($n - 1);
470 }
471
472 /**
473 * Average shortest route
474 *
475 * @param unknown_type $edges
476 * @return unknown
477 */
478 function average_shortest_route($edges) {
479 $all = get_all_vertices();
480 $how_many_vertices = count($all);
481 $how_many_probe = ceil(log($how_many_vertices) * 10);
482 for ($i = 0; $i < $how_many_probe; $i++) {
483 $rand1 = rand(0, $how_many_vertices - 1);
484 $rand2 = rand(0, $how_many_vertices - 1);
485 if ($rand1 !== $rand2) {
486 print $rand1 ." ". $rand2 ."\n";
487 $best_route = a_to_b($edges, $rand1, $rand2);
488 $sum += count($best_route);
489 }
490 }
491 return $sum / $how_many_probe;
492 }
493
494
495
496 /*$at_start = res_start();
497 $edges = array();*/
498 //get_graph($edges);
499 //print n_step_distance($edges, 9, 5);
500 /*$best_route = a_to_b($edges, 1, 577);
501
502 for ($i = end($best_route); is_array($i); $i = prev($best_route)) {
503 print get_real_name($i['n']) . " - " . $i['d'] . "\n";
504 }
505
506 /*header("Content-type: image/png");
507 $tree_img = imagecreate(1000, 1000);
508 $white = imagecolorallocate($tree_img, 255, 255, 255);
509 $black = imagecolorallocate($tree_img, 0, 0, 0);
510 imagestring($tree_img, 1, 10, 10, "Minimal tree of trey", $black);*/
511 //print average_step_separation($edges);
512 /*imagepng($tree_img);
513 imagedestroy($tree_img);*/
514
515 //print_r(vertex_degree($edges, 4));
516 //print n_step_distance($edges, 1, 3);
517 //print_r(res_stop($at_start));
518 //$edges = shrink($edges);
519
520 /*print "-d-\n";
521 print_r($d);
522 print "-f-\n";
523 print_r($f);
524 print "-p-\n";
525 print_r($p);*/
526
527 /*print "-d-\n";
528 print_r($d);
529 print "-f-\n";
530 print_r($f);
531 print "-p-\n";
532 print_r($p);*/
533 //print_r(search_groups($edges));
534 //if ($_GET['cmd'] == 'distribution') {*/
535
536
537 /* header('Content-type: image/svg+xml');
538 print_r(visualize_distribution(distribution_of_degree($edges)));
539 exit(0);
540 //}
541
542 //print clustering_coefficient(1, $edges) . "\n";
543 //print average_shortest_route($edges);
544 //print_r(count(a_to_b($edges, 1, 1)));;
545 $edges = shrink($edges, 40);*/
546 //print show_tree(breadth_first_walk($edges, 577, 3));
547 ?>

  ViewVC Help
Powered by ViewVC 1.1.2