PageRenderTime 39ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/Library/php53/lib/php/Structures/Graph/Node.php

http://github.com/jyr/MNPP
PHP | 342 lines | 95 code | 19 blank | 228 comment | 20 complexity | 77f02ad43ba579a307a7d4552059ec72 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0, LGPL-2.0, LGPL-3.0, MPL-2.0-no-copyleft-exception, GPL-2.0, BSD-3-Clause, GPL-3.0, BSD-2-Clause
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  3. // +-----------------------------------------------------------------------------+
  4. // | Copyright (c) 2003 Sérgio Gonçalves Carvalho |
  5. // +-----------------------------------------------------------------------------+
  6. // | This file is part of Structures_Graph. |
  7. // | |
  8. // | Structures_Graph is free software; you can redistribute it and/or modify |
  9. // | it under the terms of the GNU Lesser General Public License as published by |
  10. // | the Free Software Foundation; either version 2.1 of the License, or |
  11. // | (at your option) any later version. |
  12. // | |
  13. // | Structures_Graph is distributed in the hope that it will be useful, |
  14. // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
  15. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
  16. // | GNU Lesser General Public License for more details. |
  17. // | |
  18. // | You should have received a copy of the GNU Lesser General Public License |
  19. // | along with Structures_Graph; if not, write to the Free Software |
  20. // | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
  21. // | 02111-1307 USA |
  22. // +-----------------------------------------------------------------------------+
  23. // | Author: Sérgio Carvalho <sergio.carvalho@portugalmail.com> |
  24. // +-----------------------------------------------------------------------------+
  25. //
  26. /**
  27. * This file contains the definition of the Structures_Graph_Node class
  28. *
  29. * @see Structures_Graph_Node
  30. * @package Structures_Graph
  31. */
  32. /* dependencies {{{ */
  33. /** */
  34. require_once 'PEAR.php';
  35. /** */
  36. require_once 'Structures/Graph.php';
  37. /* }}} */
  38. /* class Structures_Graph_Node {{{ */
  39. /**
  40. * The Structures_Graph_Node class represents a Node that can be member of a
  41. * graph node set.
  42. *
  43. * A graph node can contain data. Under this API, the node contains default data,
  44. * and key index data. It behaves, thus, both as a regular data node, and as a
  45. * dictionary (or associative array) node.
  46. *
  47. * Regular data is accessed via getData and setData. Key indexed data is accessed
  48. * via getMetadata and setMetadata.
  49. *
  50. * @author Sérgio Carvalho <sergio.carvalho@portugalmail.com>
  51. * @copyright (c) 2004 by Sérgio Carvalho
  52. * @package Structures_Graph
  53. */
  54. /* }}} */
  55. class Structures_Graph_Node {
  56. /* fields {{{ */
  57. /**
  58. * @access private
  59. */
  60. var $_data = null;
  61. /** @access private */
  62. var $_metadata = array();
  63. /** @access private */
  64. var $_arcs = array();
  65. /** @access private */
  66. var $_graph = null;
  67. /* }}} */
  68. /* Constructor {{{ */
  69. /**
  70. *
  71. * Constructor
  72. *
  73. * @access public
  74. */
  75. function Structures_Graph_Node() {
  76. }
  77. /* }}} */
  78. /* getGraph {{{ */
  79. /**
  80. *
  81. * Node graph getter
  82. *
  83. * @return Structures_Graph Graph where node is stored
  84. * @access public
  85. */
  86. function &getGraph() {
  87. return $this->_graph;
  88. }
  89. /* }}} */
  90. /* setGraph {{{ */
  91. /**
  92. *
  93. * Node graph setter. This method should not be called directly. Use Graph::addNode instead.
  94. *
  95. * @param Structures_Graph Set the graph for this node.
  96. * @see Structures_Graph::addNode()
  97. * @access public
  98. */
  99. function setGraph(&$graph) {
  100. $this->_graph =& $graph;
  101. }
  102. /* }}} */
  103. /* getData {{{ */
  104. /**
  105. *
  106. * Node data getter.
  107. *
  108. * Each graph node can contain a reference to one variable. This is the getter for that reference.
  109. *
  110. * @return mixed Data stored in node
  111. * @access public
  112. */
  113. function &getData() {
  114. return $this->_data;
  115. }
  116. /* }}} */
  117. /* setData {{{ */
  118. /**
  119. *
  120. * Node data setter
  121. *
  122. * Each graph node can contain a reference to one variable. This is the setter for that reference.
  123. *
  124. * @return mixed Data to store in node
  125. * @access public
  126. */
  127. function setData($data) {
  128. $this->_data =& $data;
  129. }
  130. /* }}} */
  131. /* metadataKeyExists {{{ */
  132. /**
  133. *
  134. * Test for existence of metadata under a given key.
  135. *
  136. * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an
  137. * associative array or in a dictionary. This method tests whether a given metadata key exists for this node.
  138. *
  139. * @param string Key to test
  140. * @return boolean
  141. * @access public
  142. */
  143. function metadataKeyExists($key) {
  144. return array_key_exists($key, $this->_metadata);
  145. }
  146. /* }}} */
  147. /* getMetadata {{{ */
  148. /**
  149. *
  150. * Node metadata getter
  151. *
  152. * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an
  153. * associative array or in a dictionary. This method gets the data under the given key. If the key does
  154. * not exist, an error will be thrown, so testing using metadataKeyExists might be needed.
  155. *
  156. * @param string Key
  157. * @param boolean nullIfNonexistent (defaults to false).
  158. * @return mixed Metadata Data stored in node under given key
  159. * @see metadataKeyExists
  160. * @access public
  161. */
  162. function &getMetadata($key, $nullIfNonexistent = false) {
  163. if (array_key_exists($key, $this->_metadata)) {
  164. return $this->_metadata[$key];
  165. } else {
  166. if ($nullIfNonexistent) {
  167. $a = null;
  168. return $a;
  169. } else {
  170. $a = Pear::raiseError('Structures_Graph_Node::getMetadata: Requested key does not exist', STRUCTURES_GRAPH_ERROR_GENERIC);
  171. return $a;
  172. }
  173. }
  174. }
  175. /* }}} */
  176. /* unsetMetadata {{{ */
  177. /**
  178. *
  179. * Delete metadata by key
  180. *
  181. * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an
  182. * associative array or in a dictionary. This method removes any data that might be stored under the provided key.
  183. * If the key does not exist, no error is thrown, so it is safe using this method without testing for key existence.
  184. *
  185. * @param string Key
  186. * @access public
  187. */
  188. function unsetMetadata($key) {
  189. if (array_key_exists($key, $this->_metadata)) unset($this->_metadata[$key]);
  190. }
  191. /* }}} */
  192. /* setMetadata {{{ */
  193. /**
  194. *
  195. * Node metadata setter
  196. *
  197. * Each graph node can contain multiple 'metadata' entries, each stored under a different key, as in an
  198. * associative array or in a dictionary. This method stores data under the given key. If the key already exists,
  199. * previously stored data is discarded.
  200. *
  201. * @param string Key
  202. * @param mixed Data
  203. * @access public
  204. */
  205. function setMetadata($key, $data) {
  206. $this->_metadata[$key] =& $data;
  207. }
  208. /* }}} */
  209. /* _connectTo {{{ */
  210. /** @access private */
  211. function _connectTo(&$destinationNode) {
  212. $this->_arcs[] =& $destinationNode;
  213. }
  214. /* }}} */
  215. /* connectTo {{{ */
  216. /**
  217. *
  218. * Connect this node to another one.
  219. *
  220. * If the graph is not directed, the reverse arc, connecting $destinationNode to $this is also created.
  221. *
  222. * @param Structures_Graph_Node Node to connect to
  223. * @access public
  224. */
  225. function connectTo(&$destinationNode) {
  226. // We only connect to nodes
  227. if (!is_a($destinationNode, 'Structures_Graph_Node')) return Pear::raiseError('Structures_Graph_Node::connectTo received an object that is not a Structures_Graph_Node', STRUCTURES_GRAPH_ERROR_GENERIC);
  228. // Nodes must already be in graphs to be connected
  229. if ($this->_graph == null) return Pear::raiseError('Structures_Graph_Node::connectTo Tried to connect a node that is not in a graph', STRUCTURES_GRAPH_ERROR_GENERIC);
  230. if ($destinationNode->getGraph() == null) return Pear::raiseError('Structures_Graph_Node::connectTo Tried to connect to a node that is not in a graph', STRUCTURES_GRAPH_ERROR_GENERIC);
  231. // Connect here
  232. $this->_connectTo($destinationNode);
  233. // If graph is undirected, connect back
  234. if (!$this->_graph->isDirected()) {
  235. $destinationNode->_connectTo($this);
  236. }
  237. }
  238. /* }}} */
  239. /* getNeighbours {{{ */
  240. /**
  241. *
  242. * Return nodes connected to this one.
  243. *
  244. * @return array Array of nodes
  245. * @access public
  246. */
  247. function getNeighbours() {
  248. return $this->_arcs;
  249. }
  250. /* }}} */
  251. /* connectsTo {{{ */
  252. /**
  253. *
  254. * Test wether this node has an arc to the target node
  255. *
  256. * @return boolean True if the two nodes are connected
  257. * @access public
  258. */
  259. function connectsTo(&$target) {
  260. if (version_compare(PHP_VERSION, '5.0.0') >= 0) {
  261. return in_array($target, $this->getNeighbours(), true);
  262. }
  263. $copy = $target;
  264. $arcKeys = array_keys($this->_arcs);
  265. foreach($arcKeys as $key) {
  266. /* ZE1 chokes on this expression:
  267. if ($target === $arc) return true;
  268. so, we'll use more convoluted stuff
  269. */
  270. $arc =& $this->_arcs[$key];
  271. $target = true;
  272. if ($arc === true) {
  273. $target = false;
  274. if ($arc === false) {
  275. $target = $copy;
  276. return true;
  277. }
  278. }
  279. }
  280. $target = $copy;
  281. return false;
  282. }
  283. /* }}} */
  284. /* inDegree {{{ */
  285. /**
  286. *
  287. * Calculate the in degree of the node.
  288. *
  289. * The indegree for a node is the number of arcs entering the node. For non directed graphs,
  290. * the indegree is equal to the outdegree.
  291. *
  292. * @return integer In degree of the node
  293. * @access public
  294. */
  295. function inDegree() {
  296. if ($this->_graph == null) return 0;
  297. if (!$this->_graph->isDirected()) return $this->outDegree();
  298. $result = 0;
  299. $graphNodes =& $this->_graph->getNodes();
  300. foreach (array_keys($graphNodes) as $key) {
  301. if ($graphNodes[$key]->connectsTo($this)) $result++;
  302. }
  303. return $result;
  304. }
  305. /* }}} */
  306. /* outDegree {{{ */
  307. /**
  308. *
  309. * Calculate the out degree of the node.
  310. *
  311. * The outdegree for a node is the number of arcs exiting the node. For non directed graphs,
  312. * the outdegree is always equal to the indegree.
  313. *
  314. * @return integer Out degree of the node
  315. * @access public
  316. */
  317. function outDegree() {
  318. if ($this->_graph == null) return 0;
  319. return sizeof($this->_arcs);
  320. }
  321. /* }}} */
  322. }
  323. ?>