def parse_db(mln, content, ignore_unknown_preds=False, db=None, dirs=['.'], projectpath=None): ''' Reads one or more databases in a string representation and returns the respective Database objects. :param mln: the MLN object which should be used to load the database. :param content: the string representation of one or multiple ('---'-separated) databases :param ignore_unknown_preds: by default this function raises an Exception when it encounters a predicate in the DB that has not been declared in the associated MLN. ignore_unknown_preds=True simply ignores such predicates. :param db: the Database object that shall receive the facts stored in the new DB. If None, a new `Database` object will be created. ''' log = logging.getLogger('db') content = stripComments(content) allow_multiple = True if db is None: allow_multiple = True db = Database(mln, ignore_unknown_preds=ignore_unknown_preds) dbs = [] # expand domains with dbtext constants and save evidence for line, l in enumerate(content.split("\n")): l = l.strip() if l == '': continue # separator between independent databases elif l == '---' and not db.isempty(): dbs.append(db) db = Database(mln) continue # domain declaration elif "{" in l: domname, constants = db.mln.logic.parse_domain(l) domnames = [domname for _ in constants] # include elif l.startswith('#include'): filename = l[len("#include "):].strip() m = re.match(r'"(?P<filename>.+)"', filename) if m is not None: filename = m.group('filename') # if the path is relative, look for the respective file # relatively to all paths specified. Take the first file matching. if not mlnpath(filename).exists: includefilename = None for d in dirs: mlnp = '/'.join([d, filename]) if mlnpath(mlnp).exists: includefilename = mlnp break if includefilename is None: raise Exception('File not found: %s' % filename) else: includefilename = filename else: m = re.match(r'<(?P<filename>.+)>', filename) if m is not None: filename = m.group('filename') else: raise MLNParsingError('Malformed #include statement: %s' % line) if projectpath is None: raise MLNParsingError('No project specified: Cannot locate import from project: %s' % filename) includefilename = ':'.join([projectpath, filename]) logger.debug('Including file: "%s"' % includefilename) p = mlnpath(includefilename) dbs.extend(parse_db(content=mlnpath(includefilename).content, ignore_unknown_preds=ignore_unknown_preds, dirs=[p.resolve_path()]+dirs, projectpath=ifNone(p.project, projectpath, lambda x: '/'.join(p.path+[x])), mln=mln)) continue # valued evidence elif l[0] in "0123456789": s = l.find(" ") gndatom = l[s + 1:].replace(" ", "") value = float(l[:s]) if value < 0 or value > 1: raise Exception('Valued evidence must be in [0,1]') if gndatom in db.evidence: raise Exception("Duplicate soft evidence for '%s'" % gndatom) try: positive, predname, constants = mln.logic.parse_literal(gndatom) # TODO Should we allow soft evidence on non-atoms here? (This assumes atoms) except NoSuchPredicateError, e: if ignore_unknown_preds: continue else: raise e domnames = mln.predicate(predname).argdoms db << (gndatom, value) # literal else: if l[0] == "?": raise Exception("Unknown literals not supported (%s)" % l) # this is an Alchemy feature try: true, predname, constants = mln.logic.parse_literal(l) except NoSuchPredicateError, e: if ignore_unknown_preds: continue else: raise e except Exception, e: traceback.print_exc() raise MLNParsingError('Error parsing line %d: %s (%s)' % (line+1, l, e.message))
def apply(self, line, state): result = OperationResult(line, False) trimmed = stripComments(line) output = line expanded_line = line # find the directive dirsearch = regex['directive'].search(trimmed) if dirsearch: directive = dirsearch.group(1) identifier = dirsearch.group(2) output = commentLine(line) if directive == "#macro": if self.macro: warnings.add("Trying to define multiline macro %s inside other macro %s" % (identifier, self.macro.name)) return result self.macro = Macro(dirsearch, trimmed) self.payload = "" elif directive == "#endmacro": #print ("macro %s ends") % (self.macro.name) self.macro.payload = self.macro.payload.rstrip('\n') self.multimacros[self.macro.name] = self.macro self.macro = None # TODO this is basically duplicate of the above functionality, clean it up elif directive == "#lambda": if self.macro: warnings.add("Trying to define multiline lambda %s inside other macro %s" % (identifier, self.macro.name)) return result self.macro = Macro(dirsearch, trimmed) self.macro.oneliner = True self.payload = "" elif directive == "#endlambda": #print ("macro %s ends") % (self.macro.name) self.macro.payload = self.macro.payload.rstrip('\n') self.macro.payload = re.sub("\n+", r':', self.macro.payload) self.multimacros[self.macro.name] = self.macro self.macro = None elif directive == "#undef": temp_macro = Macro(dirsearch, trimmed) if temp_macro.name in self.multimacros: del self.multimacros[temp_macro.name] else: output = output else: if state.args.nomacros: return result # Expand collected macros only if not inside a multiline macro. if self.macro: line_trimmed = line if self.macro.oneliner: line_trimmed = line.lstrip(" ").lstrip("\t") self.macro.payload += line_trimmed output = commentLine(output) else: output = expandAll(line, self.multimacros, Stack(), state) result.line = output return result
def parse_db(mln, content, ignore_unknown_preds=False, db=None, dirs=['.'], projectpath=None): ''' Reads one or more databases in a string representation and returns the respective Database objects. :param mln: the MLN object which should be used to load the database. :param content: the string representation of one or multiple ('---'-separated) databases :param ignore_unknown_preds: by default this function raises an Exception when it encounters a predicate in the DB that has not been declared in the associated MLN. ignore_unknown_preds=True simply ignores such predicates. :param db: the Database object that shall receive the facts stored in the new DB. If None, a new `Database` object will be created. ''' log = logs.getlogger('db') content = stripComments(content) allow_multiple = True if db is None: allow_multiple = True db = Database(mln, ignore_unknown_preds=ignore_unknown_preds) dbs = [] # expand domains with dbtext constants and save evidence for line, l in enumerate(content.split("\n")): l = l.strip() if l == '': continue # separator between independent databases elif l == '---' and not db.isempty(): dbs.append(db) db = Database(mln) continue # domain declaration elif "{" in l: domname, constants = db.mln.logic.parse_domain(l) domnames = [domname for _ in constants] # include elif l.startswith('#include'): filename = l[len("#include "):].strip() m = re.match(r'"(?P<filename>.+)"', filename) if m is not None: filename = m.group('filename') # if the path is relative, look for the respective file # relatively to all paths specified. Take the first file matching. if not mlnpath(filename).exists: includefilename = None for d in dirs: mlnp = '/'.join([d, filename]) if mlnpath(mlnp).exists: includefilename = mlnp break if includefilename is None: raise Exception('File not found: %s' % filename) else: includefilename = filename else: m = re.match(r'<(?P<filename>.+)>', filename) if m is not None: filename = m.group('filename') else: raise MLNParsingError('Malformed #include statement: %s' % line) if projectpath is None: raise MLNParsingError('No project specified: Cannot locate import from project: %s' % filename) includefilename = ':'.join([projectpath, filename]) logger.debug('Including file: "%s"' % includefilename) p = mlnpath(includefilename) dbs.extend(parse_db(content=mlnpath(includefilename).content, ignore_unknown_preds=ignore_unknown_preds, dirs=[p.resolve_path()]+dirs, projectpath=ifnone(p.project, projectpath, lambda x: '/'.join(p.path+[x])), mln=mln)) continue # valued evidence elif l[0] in "0123456789": s = l.find(" ") gndatom = l[s + 1:].replace(" ", "") value = float(l[:s]) if value < 0 or value > 1: raise Exception('Valued evidence must be in [0,1]') if gndatom in db.evidence: raise Exception("Duplicate soft evidence for '%s'" % gndatom) try: _, predname, constants = mln.logic.parse_literal(gndatom) # TODO Should we allow soft evidence on non-atoms here? (This assumes atoms) except NoSuchPredicateError, e: if ignore_unknown_preds: continue else: raise e domnames = mln.predicate(predname).argdoms db << (gndatom, value) # literal else: if l[0] == "?": raise Exception("Unknown literals not supported (%s)" % l) # this is an Alchemy feature try: true, predname, constants = mln.logic.parse_literal(l) except NoSuchPredicateError, e: if ignore_unknown_preds: continue else: raise e except Exception, e: traceback.print_exc() raise MLNParsingError('Error parsing line %d: %s (%s)' % (line+1, l, e.message))
def apply(self, line, state): result = OperationResult(line, False) trimmed = stripComments(line) output = line expanded_line = line # find the directive dirsearch = regex['directive'].search(trimmed) if dirsearch: directive = dirsearch.group(1) identifier = dirsearch.group(2) output = commentLine(line) if directive == "#macro": if self.macro: warnings.add( "Trying to define multiline macro %s inside other macro %s" % (identifier, self.macro.name)) return result self.macro = Macro(dirsearch, trimmed) self.payload = "" elif directive == "#endmacro": #print ("macro %s ends") % (self.macro.name) self.macro.payload = self.macro.payload.rstrip('\n') self.multimacros[self.macro.name] = self.macro self.macro = None # TODO this is basically duplicate of the above functionality, clean it up elif directive == "#lambda": if self.macro: warnings.add( "Trying to define multiline lambda %s inside other macro %s" % (identifier, self.macro.name)) return result self.macro = Macro(dirsearch, trimmed) self.macro.oneliner = True self.payload = "" elif directive == "#endlambda": #print ("macro %s ends") % (self.macro.name) self.macro.payload = self.macro.payload.rstrip('\n') self.macro.payload = re.sub("\n+", r':', self.macro.payload) self.multimacros[self.macro.name] = self.macro self.macro = None elif directive == "#undef": temp_macro = Macro(dirsearch, trimmed) if temp_macro.name in self.multimacros: del self.multimacros[temp_macro.name] else: output = output else: if state.args.nomacros: return result # Expand collected macros only if not inside a multiline macro. if self.macro: line_trimmed = line if self.macro.oneliner: line_trimmed = line.lstrip(" ").lstrip("\t") self.macro.payload += line_trimmed output = commentLine(output) else: output = expandAll(line, self.multimacros, Stack(), state) result.line = output return result