source: Dev/branches/rest-dojo-ui/jQueryUI/server/rdfapi/infModel/InfModelB.php @ 312

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