[pypy-svn] r21164 - in pypy/dist/pypy/lib/pyontology: . test
ale at codespeak.net
ale at codespeak.net
Thu Dec 15 10:31:40 CET 2005
Author: ale
Date: Thu Dec 15 10:31:39 2005
New Revision: 21164
Added:
pypy/dist/pypy/lib/pyontology/
pypy/dist/pypy/lib/pyontology/__init__.py
pypy/dist/pypy/lib/pyontology/pyontology.py
pypy/dist/pypy/lib/pyontology/test/
pypy/dist/pypy/lib/pyontology/test/test_ontology.py
Log:
First checkin of OWL parser/inferer. This is work in progress. The tests are disabled if rdflib and/or logilab.constraint is not installed.
There is still a lot missing
Added: pypy/dist/pypy/lib/pyontology/__init__.py
==============================================================================
Added: pypy/dist/pypy/lib/pyontology/pyontology.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/lib/pyontology/pyontology.py Thu Dec 15 10:31:39 2005
@@ -0,0 +1,473 @@
+from rdflib import Graph, URIRef, BNode
+from logilab.constraint import Repository, Solver
+from logilab.constraint.fd import Equals, AllDistinct, BinaryExpression, Expression
+from logilab.constraint.fd import FiniteDomain as fd
+from logilab.constraint.propagation import AbstractDomain, AbstractConstraint, ConsistencyFailure
+import sys
+
+namespaces = {'rdf':'http://www.w3.org/1999/02/22-rdf-syntax-ns',
+ 'rdfs':'http://www.w3.org/2000/01/rdf-schema',
+ 'dc':'http://purl.org/dc/elements/1.0/',
+ 'xmlns':'http://www.w3.org/1999/xhtml',
+ 'owl':'http://www.w3.org/2002/07/owl',
+}
+uris = {}
+for k,v in namespaces.items():
+ uris[v] = k
+
+Thing = URIRef(u'http://www.w3.org/2002/07/owl#Thing')
+Class = URIRef(u'http://www.w3.org/2002/07/owl#Class')
+builtin_voc = [
+ 'Thing',
+ 'Class',
+ 'ObjectProperty',
+ 'AllDifferent',
+ 'AnnotationProperty',
+ 'DataRange',
+ 'DatatypeProperty',
+ 'DeprecatedClass',
+ 'DeprecatedProperty',
+ 'FunctionalProperty',
+ 'InverseFunctionalProperty',
+ 'Nothing',
+ 'ObjectProperty',
+ 'Ontology',
+ 'OntologyProperty',
+ 'Restriction',
+ 'SymmetricProperty',
+ 'TransitiveProperty'
+ ]
+
+class Ontology(Graph):
+
+ def __init__(self):
+ Graph.__init__(self)
+ self.variables = {}
+ self.constraints = []
+ self.seen = {}
+ self.var2ns ={}
+
+ def add_file(self, f):
+ tmp = Graph()
+ tmp.load(f)
+ for i in tmp.triples((None,)*3):
+ self.add(i)
+
+ def attach_fd(self):
+ for (s, p, o) in (self.triples((None, None, None))):
+ if p.find('#') != -1:
+ owl,func = p.split('#')
+ else:
+ owl =''
+ func = p
+ #print s, p, o
+ #raise Exception
+ if owl in [namespaces['owl'],namespaces['rdf'],namespaces['rdfs']]:
+ pred = getattr(self, func)
+ else:
+ pred = None
+ if pred:
+ res = pred(s, p, o)
+ if res == None:
+ continue
+ if type(res) != list :
+ res = [res]
+ avar = self.make_var(s)
+ else:
+ res = [o]
+ avar = self.make_var(s,p)
+ if self.variables.get(avar) and type(self.variables[avar]) == fd:
+ self.variables[avar] = fd(list(self.variables[avar].getValues()) + res)
+ else:
+ self.variables[avar] = fd(res)
+ # for var in self.seen:
+ # self.variables.pop(var)
+ # self.seen = {}
+
+ def solve(self,verbose=0):
+ rep = Repository(self.variables.keys(), self.variables, self.constraints)
+ return Solver().solve(rep,verbose)
+
+ def consistency(self):
+ rep = Repository(self.variables.keys(), self.variables, self.constraints)
+ rep.consistency()
+
+ def get_list(self, subject):
+ res = []
+ p = URIRef(u'http://www.w3.org/1999/02/22-rdf-syntax-ns#first')
+ first = list(self.objects(subject, p))
+ assert len(first) == 1
+ self.seen[self.make_var(subject,p)]= 1
+ if type(first[0]) == URIRef:
+ var = self.make_var(first[0])
+ if var not in self.variables.keys():
+ self.variables[var] = ClassDomain(var)
+ res += first
+
+ p = URIRef(u'http://www.w3.org/1999/02/22-rdf-syntax-ns#rest')
+ rest = list(self.objects(subject, p))
+ self.seen[self.make_var(subject,p)]= 1
+ if "#nil" in rest[0] :
+ return res
+ else:
+ res += self.get_list(rest[0])
+ return res
+
+ def make_var(self,*args):
+ res = []
+ for a in args:
+ if type(a) == URIRef:
+ if a.find('#') != -1:
+ ns,name = a.split('#')
+ else:
+ ns,name = a,''
+ if ns not in uris.keys():
+ uris[ns] = ns.split('/')[-1]
+ namespaces[uris[ns]] = ns
+ mangle_name = uris[ns] + '_' + name
+ res.append(mangle_name)
+ else:
+ res.append(a)
+ var = '.'.join([str(a.replace('-','_')) for a in res])
+ return var
+
+ def find_prop(self, s):
+ p = URIRef(u'http://www.w3.org/2002/07/owl#onProperty')
+ pr = list(self.objects(s,p))
+ assert len(pr) == 1
+ return pr[0]
+
+ def find_cls(self, s):
+ p = URIRef(u'http://www.w3.org/1999/02/22-rdf-syntax-ns#type')
+ r = URIRef(u'http://www.w3.org/2000/01/rdf-schema#subClassOf')
+ if type(s) == BNode:
+ pr = list( self.subjects(p,s) )
+ if len(pr) == 0:
+ return
+ # pr = list( self.subjects(r,s) )
+ # assert len(pr) == 1
+ return pr[0]
+ else:
+ return s
+
+ def find_uriref(self, s):
+ while type(s) == BNode:
+ s = list(self.subjects(None,s))[0]
+ return s
+
+ def find_property(self, s):
+ prop = self.find_prop(s)
+ cls = self.find_cls(s)
+ if cls :
+ avar = self.make_var(cls, prop)
+ else:
+ avar = self.make_var( prop)
+ if not self.variables.get(avar):
+ self.variables[avar] = ClassDomain(avar)
+ return avar
+
+#---------------- Implementation ----------------
+
+ def type(self, s, p, var):
+ avar = self.make_var(var)
+ svar = self.make_var(s)
+ if (type(var) == URIRef and not
+ (var in [URIRef(namespaces['owl']+'#'+x) for x in builtin_voc])):
+ # var is not one of the builtin classes
+ if not self.variables.get(svar):
+ self.variables[svar] = ClassDomain(svar)
+ if not self.variables.get(avar):
+ self.variables[avar] = ClassDomain(avar)
+
+# if self.variables[avar].values:
+ self.variables[svar].values += self.variables[avar].values
+ constrain = BinaryExpression([svar, avar],"%s in %s" %(svar, avar))
+ self.constraints.append(constrain)
+ else:
+ # var is a builtin class
+ pass
+
+ def first(self, s, p, var):
+ pass
+
+ def rest(self, s, p, var):
+ pass
+
+ def range(self, s, p, var):
+ pass
+
+ def domain(self, s, p, var):
+ pass
+
+# --------- Class Axioms ---------------------
+
+ def subClassOf(self, s, p, var):
+ # s is a subclass of var means that the
+ # class extension of s is a subset of the
+ # class extension of var.
+ avar = self.make_var(var)
+ svar = self.make_var(s)
+ if not self.variables.get(avar):
+ self.variables[avar] = ClassDomain(avar)
+ constrain = SubClassConstraint(svar, avar)
+ self.constraints.append(constrain)
+
+ def equivalentClass(self, s, p, var):
+ avar = self.make_var(var)
+ svar = self.make_var(s)
+ if not self.variables.get(avar):
+ self.variables[avar] = ClassDomain(avar)
+# constrain = EquivalentClassConstraint(svar, avar)
+# self.constraints.append(constrain)
+ self.subClassOf(s, p, var)
+ self.subClassOf(var, p, s)
+
+ def disjointWith(self, s, p, var):
+ avar = self.make_var(var)
+ svar = self.make_var(s)
+ if not self.variables.get(avar):
+ self.variables[avar] = ClassDomain(avar)
+ constrain = DisjointClassConstraint(svar, avar)
+ self.constraints.append(constrain)
+
+ def oneOf(self, s, p, var):
+ res = self.get_list(var)
+ prop = self.find_uriref(s)
+ avar = self.make_var( prop)
+ if self.variables.get(avar) and type(self.variables[avar]) == fd:
+ self.variables[avar] = fd(list(self.variables[avar].getValues()) + res)
+ else:
+ self.variables[avar] = fd(res)
+
+ def maxCardinality(self, s, p, var):
+ """ Len of finite domain of the property shall be less than or equal to var"""
+ avar = self.find_property(s)
+ constrain = MaxCardinality(avar,int(var))
+ self.constraints.append(constrain)
+
+ def minCardinality(self, s, p, var):
+ """ Len of finite domain of the property shall be greater than or equal to var"""
+ avar = self.find_property(s)
+ constrain = MinCardinality(avar,int(var))
+ self.constraints.append(constrain)
+
+ def cardinality(self, s, p, var):
+ """ Len of finite domain of the property shall be equal to var"""
+ avar = self.find_property(s)
+ # Check if var is an int, else find the int buried in the structure
+ constrain = Cardinality(avar,int(var))
+ self.constraints.append(constrain)
+
+ def unionOf(self,s, p, var):
+ res = self.get_list(var)
+ return res #There might be doubles (but fd takes care of that)
+
+ def intersectionOf(self, s, p, var):
+ res = self.get_list(var)
+ result = {}.fromkeys(res[0])
+ for el in res:
+ for cls in result.keys():
+ if cls not in el:
+ result.pop(cls)
+ return result.keys()
+
+ def differentFrom(self, s, p, var):
+ s_var = self.make_var(s)
+ var_var = self.make_var(var)
+ if not self.variables.get(s_var):
+ self.variables[s_var] = ClassDomain(s_var)
+ if not self.variables.get(var_var):
+ self.variables[var_var] = fd([])
+ constrain = BinaryExpression([s_var, var_var],"%s != %s" %(s_var, var_var))
+ self.constraints.append(constrain)
+
+ def distinctMembers(self, s, p, var):
+ res = self.get_list(var)
+ self.constraints.append(AllDistinct([self.make_var(y) for y in res]))
+ return res
+
+ def sameAs(self, s, p, var):
+ constrain = BinaryExpression([self.make_var(s), self.make_var(var)],"%s == %s" %(self.make_var(s), self.make_var( var)))
+ self.constraints.append(constrain)
+
+ def complementOf(self, s, p, var):
+ # add constraint of not var
+ pass
+
+ def onProperty(self, s, p, var):
+ pass
+
+ def hasValue(self, s, p, var):
+ pass
+
+ def allValuesFrom(self, s, p, var):
+ pass
+
+ def someValuesFrom(self, s, p, var):
+ pass
+
+ def equivalentProperty(self, s, p, var):
+ pass
+
+ def inverseOf(self, s, p, var):
+ pass
+
+ def someValuesFrom(self, s, p, var):
+ pass
+
+ def subPropertyOf(self, s, p, var):
+ pass
+
+ def imports(self, s, p, var):
+ pass
+
+# ----------------- Helper classes ----------------
+
+class MaxCardinality(AbstractConstraint):
+ """Contraint: all values must be distinct"""
+
+ def __init__(self, variable, cardinality):
+ AbstractConstraint.__init__(self, [variable])
+ # worst case complexity
+ self.__cost = 1 #len(variables) * (len(variables) - 1) / 2
+ self.cardinality = cardinality
+
+ def __repr__(self):
+ return '<MaxCardinality %s,%i>' % (str(self._variables[0]),self.cardinality)
+
+ def estimateCost(self, domains):
+ return self.__cost
+
+ def narrow(self, domains):
+ """narrowing algorithm for the constraint"""
+ if len(domains[self._variables[0]]) > self.cardinality:
+ print " I Think I will raise an exception"
+ raise ConsistencyFailure("Maxcardinality exceeded")
+ else:
+ return 1
+
+class MinCardinality(MaxCardinality):
+
+ def __repr__(self):
+ return '<MinCardinality %s,%i>' % (str(self._variables[0]),self.cardinality)
+
+ def narrow(self, domains):
+ """narrowing algorithm for the constraint"""
+
+ if len(domains[self._variables[0]]) < self.cardinality:
+ raise ConsistencyFailure()
+ else:
+ return 1
+
+class Cardinality(MaxCardinality):
+
+ def __repr__(self):
+ return '<Cardinality %s,%i>' % (str(self._variables[0]),self.cardinality)
+
+ def narrow(self, domains):
+ """narrowing algorithm for the constraint"""
+
+ if len(domains[self._variables[0]]) != self.cardinality:
+ raise ConsistencyFailure()
+ else:
+ return 1
+
+def get_bases(cls_dom, domains):
+ res = {}
+ for bas in cls_dom.bases:
+ res[bas] = 1
+ if bas in domains.keys():
+ res.update( get_bases(bas, domains))
+ res[cls_dom] = 1
+ return res
+
+class SubClassConstraint(AbstractConstraint):
+
+ def __init__(self, variable, cls_or_restriction):
+ AbstractConstraint.__init__(self, [variable])
+ # worst case complexity
+ self.__cost = 1 #len(variables) * (len(variables) - 1) / 2
+ self.super = cls_or_restriction
+ self.variable = variable
+
+ def narrow(self, domains):
+ subdom = domains[self.variable]
+ superdom = domains[self.super]
+ bases = get_bases(superdom, domains).keys()
+ print subdom,superdom, bases, subdom.bases
+ subdom.bases += [bas for bas in bases if bas not in subdom.bases]
+
+class EquivalentClassConstraint(AbstractConstraint):
+
+ def __init__(self, variable, cls_or_restriction):
+ AbstractConstraint.__init__(self, [variable])
+ # worst case complexity
+ self.__cost = 1 #len(variables) * (len(variables) - 1) / 2
+ self.other = cls_or_restriction
+ self.variable = variable
+
+ def narrow(self, domains):
+ subdom = domains[self.variable]
+ otherdom = domains[self.other]
+ bases = get_bases(subdom, domains).keys()
+ otherbases = get_bases(otherdom, domains).keys()
+ print subdom, otherdom, "----",bases , otherbases
+ if bases != otherbases:
+ raise ConsistencyFailure()
+ else:
+ return 1
+
+class DisjointClassConstraint(AbstractConstraint):
+
+ def __init__(self, variable, cls_or_restriction):
+ AbstractConstraint.__init__(self, [variable])
+ # worst case complexity
+ self.__cost = 1 #len(variables) * (len(variables) - 1) / 2
+ self.super = cls_or_restriction
+ self.variable = variable
+
+ def narrow(self, domains):
+ subdom = domains[self.variable]
+ superdom = domains[self.super]
+ bases = get_bases(superdom, domains).keys()
+ print subdom,superdom, bases, subdom.bases
+ subdom.bases += [bas for bas in bases if bas not in subdom.bases]
+
+class ClassDomain(AbstractDomain):
+ # Class domain is intended as a (abstract/virtual) domain for implementing
+ # Class axioms. Working on class descriptions the class domain should allow
+ # creation of classes through axioms.
+ # The instances of a class can be represented as a FiniteDomain in values (not always see Disjointwith)
+ # Properties of a class is in the dictionary "properties"
+ # The bases of a class is in the list "bases"
+
+ def __init__(self, name='', values=[], bases = []):
+ AbstractDomain.__init__(self)
+ self.bases = bases+[self]
+ self.values = values
+ self.name = name
+
+ def __repr__(self):
+ return "<ClassDomain %s>" % str(self.name)
+
+ def __getitem__(self, index):
+ return None
+
+ def __iter__(self):
+ return iter(self.bases)
+
+ def size(self):
+ return sys.maxint
+
+ __len__ = size
+
+ def copy(self):
+ return self
+
+ def removeValues(self, values):
+ print "remove values from ClassDomain", values
+ self.bases.pop(self.bases.index(values[0]))
+
+ def getValues(self):
+ return self.bases
+
Added: pypy/dist/pypy/lib/pyontology/test/test_ontology.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/lib/pyontology/test/test_ontology.py Thu Dec 15 10:31:39 2005
@@ -0,0 +1,97 @@
+# tests for the Ontology class
+
+try:
+ import logilab.constraint
+ import rdflib
+except ImportError:
+ import py
+ py.test.skip("Logilab.constraint and/or rdflib not installed")
+
+from pypy.lib.pyontology.pyontology import * # Ontology, ClassDomain, SubClassConstraint
+from rdflib import Graph, URIRef, BNode
+
+def test_makevar():
+ O = Ontology()
+ var = URIRef(u'http://www.w3.org/2002/03owlt/unionOf/premises004#A-and-B')
+ cod = O.make_var(var)+' = 1'
+ exec cod
+ assert O.make_var(var) in locals()
+
+def DONOT_test_subClassof():
+ O = Ontology()
+ a = b = c = URIRef(u'http://www.w3.org/2002/03owlt/unionOf/premises004#A-and-B')
+ O.subClassOf(b, None, a)
+ O.subClassOf(c, None, b)
+ assert O.solve()
+ O.subClassOf(c, None, a)
+ assert O.solve()
+
+def test_ClassDomain():
+ a = ClassDomain()
+ assert a.bases == [a]
+ cls = 1
+ b = ClassDomain('B',[],[a])
+ assert b in b.bases
+ assert a in b.bases
+ assert len(b.bases) == 2
+
+def test_subClassconstraint():
+ a = ClassDomain('A')
+ b = ClassDomain('B')
+ c = ClassDomain('C')
+ con = SubClassConstraint('b','a')
+ con2 = SubClassConstraint('c','b')
+ con.narrow({'a': a, 'b': b, 'c': c})
+ con2.narrow({'a': a, 'b': b, 'c': c})
+ assert a in c.bases
+ assert b in c.bases
+ assert c in c.bases
+
+def test_subClassconstraintMulti():
+ a = ClassDomain('A')
+ b = ClassDomain('B')
+ c = ClassDomain('C')
+ con = SubClassConstraint('c','a')
+ con2 = SubClassConstraint('c','b')
+ con.narrow({'a': a, 'b': b, 'c': c})
+ con2.narrow({'a': a, 'b': b, 'c': c})
+ assert a in c.bases
+ assert b in c.bases
+ assert c in c.bases
+
+def test_subClassconstraintMulti2():
+ a = ClassDomain('A')
+ b = ClassDomain('B')
+ c = ClassDomain('C')
+ con = SubClassConstraint('c','a')
+ con2 = SubClassConstraint('c','b')
+ con3 = SubClassConstraint('a','c')
+ con.narrow({'a': a, 'b': b, 'c': c})
+ con2.narrow({'a': a, 'b': b, 'c': c})
+ con3.narrow({'a': a, 'b': b, 'c': c})
+ assert a in c.bases
+ assert b in c.bases
+ assert c in c.bases
+ assert c in a.bases
+ assert len(c.bases) == len(a.bases)
+ assert [bas in a.bases for bas in c.bases] == [True]*len(a.bases)
+
+def DONOT_test_equivalentClass():
+ a = ClassDomain('A')
+ b = ClassDomain('B')
+ c = ClassDomain('C')
+ con = EquivalentClassConstraint('c','a')
+ con2 = EquivalentClassConstraint('c','b')
+ con.narrow({'a': a, 'b': b, 'c': c})
+ con2.narrow({'a': a, 'b': b, 'c': c})
+ assert a == b
+
+def test_type():
+ sub = URIRef('a')
+ pred = URIRef('type')
+ obj = URIRef('o')
+ O = Ontology()
+ O.type(sub, pred , obj)
+ assert O.variables[O.make_var(sub)].__class__ == ClassDomain
+
+
More information about the Pypy-commit
mailing list