Source for file InfModelB.php

Documentation is available at InfModelB.php

  1. <?php
  2. // ----------------------------------------------------------------------------------
  3. // Class: InfModelB
  4. // ----------------------------------------------------------------------------------
  5.  
  6. /**
  7. * A InfModelB extends the InfModel Class, with a backward chaining algorithm.
  8. * Only the loaded or added base-triples are stored.
  9. * A find-query evaluates the inference rules and recursively tries to find the statements.
  10. * InfModelB memorises "Dead-Ends" until the next add() command, thus
  11. * makin a second find much faster.
  12. * InfModelB is safe for loops in Ontologies, that would cause infinite loops.
  13. * WARNING: A find(null,null,null) might take very long.
  14. *
  15. * <BR><BR>History:<UL>
  16. * <LI>10-07-2004 : Function findFirstMatchingStatement() added paramter $offset
  17. * to set an search offset
  18. * <LI>09-10-2004 : First version of this class.</LI>
  19. * <LI>09-15-2004 : Added Index over InRule Entailments
  20. * to increase performance
  21. *</UL>
  22. * @version V0.9.3
  23. * @author Daniel Westphal <mail at d-westphal dot de>
  24.  
  25. *
  26. * @package infModel
  27. * @access public
  28. ***/
  29. class InfModelB extends InfModel
  30. {
  31.  
  32. /**
  33. * Array that holds combinations of inference rules with distinct
  34. * find-querys, that don''t lead to any inference.
  35. * @var array
  36. * @access private
  37. */
  38. var $findDeadEnds;
  39. /**
  40. * Constructor
  41. * You can supply a base_uri
  42. *
  43. * @param string $baseURI
  44. * @access public
  45. */
  46. function InfModelB($baseURI = null)
  47. {
  48. parent::InfModel($baseURI);
  49. $this->findDeadEnds=array();
  50. }
  51. /**
  52. * Adds a new triple to the Model without checking, if the statement
  53. * is already in the Model. So if you want a duplicate free Model use
  54. * the addWithoutDuplicates() function (which is slower then add())
  55. *
  56. * @param object Statement $statement
  57. * @access public
  58. * @throws PhpError
  59. */
  60. function add($statement)
  61. {
  62. parent::add($statement);
  63. //Reset the found dead-ends.
  64. $this->findDeadEnds=array();
  65. }
  66. /**
  67. * General method to search for triples.
  68. * NULL input for any parameter will match anything.
  69. * Example: $result = $m->find( NULL, NULL, $node );
  70. * Finds all triples with $node as object.
  71. * Returns an empty MemModel if nothing is found.
  72. * To improve the search speed with big Models, call index(INDEX_TYPE)
  73. * before seaching.
  74. *
  75. * It recursively searches in the statements and rules to find
  76. * matching statements
  77. *
  78. * @param object Node $subject
  79. * @param object Node $predicate
  80. * @param object Node $object
  81. * @return object MemModel
  82. * @access public
  83. * @throws PhpError
  84. */
  85. function find($subject,$predicate,$object)
  86. {
  87. $searchStringIndex=array();
  88. $resultModel=new MemModel();
  89. //add all infered statements without duplicates to the result model
  90. foreach ($this->_infFind($subject,$predicate,$object,array())as $statement)
  91. {
  92. $resultModel->addWithoutDuplicates($statement);
  93. };
  94. return $resultModel;
  95. }
  96.  
  97. /**
  98. * This is the main inference method of the InfModelB
  99. * The algorithm works as follows:
  100. * Find all statements in the base model, that matches the current
  101. * find-query.
  102. * Check all rules, if they are able to deliver infered statements,
  103. * that match the current find-query. Don''t use rules with queries,
  104. * that lead to dead-ends and don''t use a rule-query-combination that
  105. * was used before in this branch (ontology loops).
  106. * If a rule is possible do deliver such statements, get a new
  107. * find-query, that is possible to find those statements, that are able
  108. * to trigger this rule.
  109. * Call this _infFind method wirh the new find-query and entail the
  110. * resulting statements.
  111. * If this rule, wasn''t able to return any statements with this distinct
  112. * query, add this combination to the dead-ends.
  113. * Return the statements from the base triples and those, which were infered.
  114. *
  115. * If $findOnlyFirstMatching is set to true, only the first match in
  116. * the base-statements is entailed an returned (used in contains() and
  117. * findFirstMatchingStatement() methods).
  118. *
  119. * You can set an offset to look for the first matching statement by setting the
  120. * $offset var.
  121. *
  122. * It recursively searches in the statements and rules to find matching
  123. * statements
  124. *
  125. * @param object Node $subject
  126. * @param object Node $predicate
  127. * @param object Node $object
  128. * @param array $searchStringIndex
  129. * @param boolean $findOnlyFirstMatching
  130. * @param integer $offset
  131. * @param integer $resultCount
  132. * @return object array Statements
  133. * @access private
  134. */
  135. function _infFind ($subject,$predicate,$object, $searchStringIndex, $findOnlyFirstMatching = false, $offset = 0,$resultCount = 0 )
  136. {
  137. $return=array();
  138. //Find all matching statements in the base statements
  139. $findResult=parent::find($subject,$predicate,$object);
  140. //For all found statements
  141. foreach ($findResult->triples as $statement)
  142. {
  143. $return[]=$statement;
  144. $resultCount++;
  145.  
  146. //Return, if only the firstMatchingStatement was wanted
  147. if ($findOnlyFirstMatching && $resultCount > $offset)
  148. return $return;
  149. };
  150. //Don''t infer statements about the schema (rdfs:subClass, etc..)
  151. //is false
  152. if ($predicate == null ||
  153. (is_a($predicate,''Node'') &&
  154. !in_array($predicate->getLabel(),$this->supportedInference))
  155. )
  156. //Check only Rules, that the EntailmentIndex returned.
  157. foreach ($this->_findRuleEntailmentInIndex($subject,$predicate,$object) as $ruleKey)
  158. {
  159. $infRule=$this->infRules[$ruleKey];
  160. $serializedRuleStatement=$ruleKey.serialize($subject).serialize($predicate).serialize($object);
  161. //If it is to ontology loop and no dead-end
  162. if (!in_array($serializedRuleStatement, $searchStringIndex) &&
  163. !in_array($serializedRuleStatement, $this->findDeadEnds))
  164. {
  165. //Keep this distinct rule query cobination for
  166. //this branch to detect loops
  167. $searchStringIndex[]=$serializedRuleStatement;
  168. //If the rule is able to deliver statements that match
  169. //this query
  170. if ($infRule->checkEntailment($subject,$predicate,$object))
  171. {
  172. //Get a modified find-query, that matches statements,
  173. //that trigger this rule
  174. $modefiedFind=$infRule->getModifiedFind($subject,$predicate,$object);
  175. //Call this method with the new find-query
  176. $infFindResult=$this->_infFind($modefiedFind[''s''],
  177. $modefiedFind[''p''],
  178. $modefiedFind[''o''],
  179. $searchStringIndex,
  180. $findOnlyFirstMatching,
  181. $offset,
  182. $resultCount) ;
  183. //If it deliverd statements that matches the trigger
  184. if (isset($infFindResult[0]))
  185. {
  186. foreach ($infFindResult as $statement)
  187. {
  188. //Entail the statements and check, if they are not about the
  189. //ontology
  190. $newStatement=$infRule->entail($statement);
  191. if (!in_array($newStatement->getLabelPredicate(),$this->supportedInference))
  192. //Check if, the entailed statements are, what we are looking for
  193. if($this->_nodeEqualsFind($subject,$newStatement->getSubject()) &&
  194. $this->_nodeEqualsFind($predicate,$newStatement->getPredicate()) &&
  195. $this->_nodeEqualsFind($object,$newStatement->getObject() ) )
  196. {
  197. //Add to results
  198. $return[]=$newStatement;
  199. $resultCount++;
  200. //or return at once
  201. if ($findOnlyFirstMatching && $resultCount > $offset)
  202. return $return;
  203. }
  204. }
  205. } else
  206. {
  207. //If there were no results of the rule-query-combination,
  208. //mark this combination as a dead-end.
  209. $this->findDeadEnds[]=$serializedRuleStatement;
  210. }
  211. }
  212. }
  213. }
  214. //Return the array of the found statements
  215. return $return;
  216. }
  217. /**
  218. * Tests if the Model contains the given triple.
  219. * TRUE if the triple belongs to the Model;
  220. * FALSE otherwise.
  221. *
  222. * @param object Statement &$statement
  223. * @return boolean
  224. * @access public
  225. */
  226. function contains(&$statement)
  227. {
  228. //throws an error, if $statement is not of class Statement
  229. if(!is_a($statement,''Statement''))
  230. trigger_error(RDFAPI_ERROR . ''(class: InfModelB; method: contains):
  231. $statement has to be object of class Statement'', E_USER_ERROR);
  232. //Call the _infFind method, but let it stop, if it finds the first match.
  233. if (count( $this->_infFind($statement->getSubject(),
  234. $statement->getPredicate(),
  235. $statement->getObject(),
  236. array(),true) ) >0)
  237. {
  238. return true;
  239. } else
  240. {
  241. return false;
  242. };
  243. }
  244. /**
  245. * Searches for triples and returns the first matching statement.
  246. * NULL input for any parameter will match anything.
  247. * Example: $result = $m->findFirstMatchingStatement( NULL, NULL, $node );
  248. * Returns the first statement of the MemModel where the object equals $node.
  249. * Returns an NULL if nothing is found.
  250. * You can define an offset to search for. Default = 0
  251. *
  252. * @param object Node $subject
  253. * @param object Node $predicate
  254. * @param object Node $object
  255. * @param integer $offset
  256. * @return object Statement
  257. * @access public
  258. */
  259. function findFirstMatchingStatement($subject, $predicate, $object, $offset = 0)
  260. {
  261. //Call the _infFind method, but let it stop, if it finds the
  262. //first match.
  263. $res= $this->_infFind($subject,$predicate,$object,array(),true,$offset);
  264. if (isset($res[$offset]))
  265. {
  266. return $res[$offset];
  267. } else
  268. {
  269. return NULL;
  270. };
  271. }
  272.  
  273. /**
  274. * Returns a StatementIterator for traversing the Model.
  275. * @access public
  276. * @return object StatementIterator
  277. */
  278. function & getStatementIterator()
  279. {
  280. // Import Package Utility
  281. include_once(RDFAPI_INCLUDE_DIR.PACKAGE_UTILITY);
  282. // Gets a MemModel by executing a find(null,null,null) to get a
  283. //inferable statements.
  284. // WARNING: might be slow
  285. return new StatementIterator($this->getMemModel());
  286. }
  287. /**
  288. * Number of all inferable triples in the Model.
  289. * WARNING: uses a find(null,null,null) to find all statements! (might take a while)
  290. *
  291. * @param boolean
  292. * @return integer
  293. * @access public
  294. */
  295. function size()
  296. {
  297. // Gets a MemModel by executing a find(null,null,null) to get a
  298. //inferable statements.
  299. // WARNING: might be slow
  300. $res = $this->getMemModel();
  301. return $res->size();
  302. }
  303. /**
  304. * Create a MemModel containing all the triples (including inferred
  305. * statements) of the current InfModelB
  306. *
  307. * @return object MemModel
  308. * @access public
  309. */
  310. function & getMemModel()
  311. {
  312. $return=$this->find(null,null,null);
  313. $return->setBaseURI($this->baseURI);
  314. $return->addParsedNamespaces($this->getParsedNamespaces());
  315. return $return;
  316. }
  317.  
  318. /**
  319. * Create a MemModel containing only the base triples (without inferred
  320. * statements) of the current InfModelB
  321. *
  322. * @return object MemModel
  323. * @access public
  324. */
  325. function & getBaseMemModel()
  326. {
  327. $return= new MemModel();
  328. $return->setBaseURI($this->baseURI);
  329. foreach ($this->triples as $statement)
  330. $return->add($statement);
  331. $retun->addParsedNamespaces($this->getParsedNamespaces());
  332. return $return;
  333. }
  334.  
  335. /**
  336. * Short Dump of the InfModelB.
  337. *
  338. * @access public
  339. * @return string
  340. */
  341. function toString()
  342. {
  343. return ''InfModelB[baseURI='' . $this->getBaseURI() . ''; size='' . $this->size(true) . '']'';
  344. }
  345.  
  346. /**
  347. * Dumps of the InfModelB including ALL inferable triples.
  348. *
  349. * @access public
  350. * @return string
  351. */
  352. function toStringIncludingTriples()
  353. {
  354. $dump = $this->toString() . chr(13);
  355. $stateIt=new StatementIterator($this->find(null,null,null));
  356. while($statement=$stateIt->next())
  357. {
  358. $dump .= $statement->toString() . chr(13);
  359. }
  360. return $dump;
  361. }
  362.  
  363. /**
  364. * Saves the RDF,N3 or N-Triple serialization of the full InfModelB
  365. * (including inferred triples) to a file.
  366. * You can decide to which format the model should be serialized by
  367. * using a corresponding suffix-string as $type parameter. If no $type
  368. * parameter is placed this method will serialize the model to XML/RDF
  369. * format.
  370. * Returns FALSE if the InfModelB couldn''t be saved to the file.
  371. *
  372. * @access public
  373. * @param string $filename
  374. * @param string $type
  375. * @throw PhpError
  376. * @return boolean
  377. */
  378. function saveAs($filename, $type =''rdf'')
  379. {
  380. $memmodel=$this->getMemModel();
  381. return $memmodel->saveAs($filename, $type);
  382. }
  383.  
  384. /**
  385. * Writes the RDF serialization of the Model including ALL inferable
  386. * triples as HTML.
  387. *
  388. * @access public
  389. */
  390. function writeAsHtml()
  391. {
  392. require_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_RDF);
  393. $ser = new RdfSerializer();
  394. $rdf =& $ser->serialize($this->getMemModel());
  395. $rdf = htmlspecialchars($rdf, ENT_QUOTES);
  396. $rdf = str_replace('' '', ''&nbsp;'', $rdf);
  397. $rdf = nl2br($rdf);
  398. echo $rdf;
  399. }
  400.  
  401. /**
  402. * Writes the RDF serialization of the Model including ALL inferable
  403. * triples as HTML table.
  404. *
  405. * @access public
  406. */
  407. function writeAsHtmlTable()
  408. {
  409. // Import Package Utility
  410. include_once(RDFAPI_INCLUDE_DIR.PACKAGE_UTILITY);
  411. RDFUtil::writeHTMLTable($this->getMemModel());
  412. }
  413. /**
  414. * Writes the RDF serialization of the Model including ALL inferable
  415. * triples.
  416. *
  417. * @access public
  418. * @return string
  419. */
  420. function writeRdfToString()
  421. {
  422. // Import Package Syntax
  423. include_once(RDFAPI_INCLUDE_DIR.PACKAGE_SYNTAX_RDF);
  424. $ser = new RdfSerializer();
  425. $rdf =& $ser->serialize($this->getMemModel());
  426. return $rdf;
  427. }
  428.  
  429. /**
  430. * Removes the triple from the MemModel.
  431. * TRUE if the triple is removed.
  432. * FALSE otherwise.
  433. *
  434. * Checks, if it touches any statements, that added inference rules
  435. * to the model
  436. *
  437. * @param object Statement $statement
  438. * @return boolean
  439. * @access public
  440. * @throws PhpError
  441. */
  442. function remove($statement)
  443. {
  444. if (parent::contains($statement))
  445. {
  446. if (in_array($statement->getLabelPredicate(),$this->supportedInference));
  447. while (count($this->_removeFromInference($statement))>0);
  448. $this->findDeadEnds=array();
  449. return parent::remove($statement);
  450. } else
  451. {
  452. return false;
  453. }
  454. }
  455.  
  456. /**
  457. * Checks, if a single node matches a single find pattern.
  458. * TRUE if the node matches.
  459. * FALSE otherwise.
  460. *
  461. * Checks, if it touches any statements, that added inference rules
  462. * to the model
  463. *
  464. * @param object Statement $statement
  465. * @return boolean
  466. * @access private
  467. */
  468. function _nodeEqualsFind(& $find, $node)
  469. {
  470. //If the find pattern is a node, use the nodes equal-method and
  471. //return the result.
  472. if (is_a($find,''Node''))
  473. return $node->equals($find);
  474. //Null-pattern matches anything.
  475. if ($find == null)
  476. {
  477. return true;
  478. } else
  479. {
  480. return false;
  481. }
  482. }
  483. /**
  484. * Returns a FindIterator for traversing the MemModel.
  485. * Disabled in InfModelB
  486. * @access public
  487. * @return object FindIterator
  488. */
  489. function & findAsIterator($sub=null,$pred=null,$obj=null) {
  490. $errmsg = RDFAPI_ERROR . ''(class: InfModelB; method: findAsIterator):
  491. This function is disabled in the
  492. Inference Model'';
  493. trigger_error($errmsg, E_USER_ERROR);
  494. }
  495. }
  496. ?>

Documentation generated on Fri, 13 Jan 2006 07:48:21 +0100 by phpDocumentor 1.3.0RC4