Source for file InfModelB.php

Documentation is available at InfModelB.php

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

Documentation generated on Fri, 17 Dec 2004 16:15:10 +0100 by phpDocumentor 1.3.0RC3