diff options
Diffstat (limited to 'www/wiki/extensions/SemanticMediaWiki/src/Query/Language/Disjunction.php')
-rw-r--r-- | www/wiki/extensions/SemanticMediaWiki/src/Query/Language/Disjunction.php | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/www/wiki/extensions/SemanticMediaWiki/src/Query/Language/Disjunction.php b/www/wiki/extensions/SemanticMediaWiki/src/Query/Language/Disjunction.php new file mode 100644 index 00000000..04fddc15 --- /dev/null +++ b/www/wiki/extensions/SemanticMediaWiki/src/Query/Language/Disjunction.php @@ -0,0 +1,239 @@ +<?php + +namespace SMW\Query\Language; + +/** + * Description of a collection of many descriptions, at least one of which + * must be satisfied (OR, disjunction). + * + * Corresponds to disjunction in OWL and SPARQL. Not available in RDFS. + * + * @license GNU GPL v2+ + * @since 1.6 + * + * @author Markus Krötzsch + */ +class Disjunction extends Description { + + /** + * @var Description[] + */ + private $descriptions = []; + + /** + * contains a single class description if any such disjunct was given; + * disjunctive classes are aggregated therei + * n + * @var null|ClassDescription + */ + private $classDescription = null; + + /** + * Used if disjunction is trivially true already + * + * @var boolean + */ + private $isTrue = false; + + public function __construct( array $descriptions = [] ) { + foreach ( $descriptions as $desc ) { + $this->addDescription( $desc ); + } + } + + /** + * @see Description::getFingerprint + * @since 2.5 + * + * @return string + */ + public function getFingerprint() { + + // Avoid a recursive tree + if ( $this->fingerprint !== null ) { + return $this->fingerprint; + } + + $fingerprint = []; + + foreach ( $this->descriptions as $description ) { + $fingerprint[$description->getFingerprint()] = true; + } + + ksort( $fingerprint ); + + return $this->fingerprint = 'D:' . md5( implode( '|', array_keys( $fingerprint ) ) ); + } + + /** + * @since 3.0 + * + * @param integer $hierarchyDepth + */ + public function setHierarchyDepth( $hierarchyDepth ) { + + $this->fingerprint = null; + + if ( $this->classDescription !== null ) { + $this->classDescription->setHierarchyDepth( $hierarchyDepth ); + } + + foreach ( $this->descriptions as $key => $description ) { + if ( $description instanceof SomeProperty ) { + $description->setHierarchyDepth( $hierarchyDepth ); + } + } + } + + public function getDescriptions() { + return $this->descriptions; + } + + public function addDescription( Description $description ) { + + $this->fingerprint = null; + $fingerprint = $description->getFingerprint(); + + if ( $description instanceof ThingDescription ) { + $this->isTrue = true; + $this->descriptions = []; // no conditions any more + $this->classDescription = null; + } + + if ( !$this->isTrue ) { + // Combine class descriptions only when those describe the same state + if ( $description instanceof ClassDescription ) { + if ( is_null( $this->classDescription ) ) { // first class description + $this->classDescription = $description; + $this->descriptions[$description->getFingerprint()] = $description; + } elseif ( $this->classDescription->isMergableDescription( $description ) ) { + $this->classDescription->addDescription( $description ); + } else { + $this->descriptions[$description->getFingerprint()] = $description; + } + } elseif ( $description instanceof Disjunction ) { // absorb sub-disjunctions + foreach ( $description->getDescriptions() as $subdesc ) { + $this->descriptions[$subdesc->getFingerprint()] = $subdesc; + } + // } elseif ($description instanceof SMWSomeProperty) { + ///TODO: use subdisjunct. for multiple SMWSomeProperty descs with same property + } else { + $this->descriptions[$fingerprint] = $description; + } + } + + // move print descriptions downwards + ///TODO: This may not be a good solution, since it does modify $description and since it does not react to future cahges + $this->m_printreqs = array_merge( $this->m_printreqs, $description->getPrintRequests() ); + $description->setPrintRequests( [] ); + } + + public function getQueryString( $asValue = false ) { + + if ( $this->isTrue ) { + return '+'; + } + + $result = ''; + $sep = $asValue ? '||':' OR '; + + foreach ( $this->descriptions as $desc ) { + $subdesc = $desc->getQueryString( $asValue ); + + if ( $desc instanceof SomeProperty ) { // enclose in <q> for parsing + if ( $asValue ) { + $subdesc = ' <q>[[' . $subdesc . ']]</q> '; + } else { + $subdesc = ' <q>' . $subdesc . '</q> '; + } + } + + $result .= ( $result ? $sep:'' ) . $subdesc; + } + + if ( $asValue ) { + return $result; + } + + return ' <q>' . $result . '</q> '; + } + + public function isSingleton() { + /// NOTE: this neglects the unimportant case where several disjuncts describe the same object. + if ( count( $this->descriptions ) != 1 ) { + return false; + } + + return $this->descriptions[0]->isSingleton(); + } + + public function getSize() { + $size = 0; + + foreach ( $this->descriptions as $desc ) { + $size += $desc->getSize(); + } + + return $size; + } + + public function getDepth() { + $depth = 0; + + foreach ( $this->descriptions as $desc ) { + $depth = max( $depth, $desc->getDepth() ); + } + + return $depth; + } + + public function getQueryFeatures() { + $result = SMW_DISJUNCTION_QUERY; + + foreach ( $this->descriptions as $desc ) { + $result = $result | $desc->getQueryFeatures(); + } + + return $result; + } + + public function prune( &$maxsize, &$maxdepth, &$log ) { + + if ( $maxsize <= 0 ) { + $log[] = $this->getQueryString(); + return new ThingDescription(); + } + + $prunelog = []; + $newdepth = $maxdepth; + $result = new Disjunction(); + + foreach ( $this->descriptions as $desc ) { + $restdepth = $maxdepth; + $result->addDescription( $desc->prune( $maxsize, $restdepth, $prunelog ) ); + $newdepth = min( $newdepth, $restdepth ); + } + + if ( count( $result->getDescriptions() ) > 0 ) { + $log = array_merge( $log, $prunelog ); + $maxdepth = $newdepth; + + if ( count( $result->getDescriptions() ) == 1 ) { // simplify unary disjunctions! + $descriptions = $result->getDescriptions(); + $result = array_shift( $descriptions ); + } + + $result->setPrintRequests( $this->getPrintRequests() ); + + return $result; + } + + $log[] = $this->getQueryString(); + + $result = new ThingDescription(); + $result->setPrintRequests( $this->getPrintRequests() ); + + return $result; + } + +} |