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

Last change on this file since 303 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

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.