def map_rule_predicates(self, rule): """ Finds all predicates in the head and the body and constructs a predicate map (a.k.a. and adjacency list) according to the above description Must be given a rule at the top-level, where child keys are ["head", "body"] Otherwise performs no operations """ if isinstance(rule, clingo.ast.AST) and rule.type == clingo.ast.ASTType.Rule: # Reset head and body predicate lists such that this class # may be reused for all rules in the program self.head_predicates = set() self.body_predicates = set() super(ASTPredicateMapper, self).visit(rule["head"], TreeData(head=True)) super(ASTPredicateMapper, self).visit(rule["body"], TreeData(head=False)) for head_predicate in self.head_predicates: if head_predicate not in self.predicate_map.keys(): self.predicate_map[head_predicate] = set() self.predicate_map[head_predicate].update(self.body_predicates)
def explore(self, x, data=TreeData()): """ Recursively traverse AST of the rule. Record encountered comparisons and functions for use in checking for potential rewritings of the rule """ if isinstance(x, clingo.ast.AST): # Record non-equality comparisons for use in rewritability checking if x.type == clingo.ast.ASTType.Comparison: if x['comparison'] != clingo.ast.ComparisonOperator.Equal: self.variable_counter.mark_comparison( x['left'], x['right'], x['comparison']) # Record body functions for use in rewritability checking elif x.type == clingo.ast.ASTType.Function: if not data.head: self.rule_functions.append(x) # Record aggregate literals for use in rewritability checking elif x.type == clingo.ast.ASTType.Literal and \ x['atom'].type == clingo.ast.ASTType.BodyAggregate: self.aggregate_counter.record_aggregate_literal(x) return self.explore_children(x, data) elif isinstance(x, list): return [self.explore(y, data) for y in x] elif x is None: return x else: raise TypeError("unexpected type")
def visit_Pool(self, pool, data=TreeData()): if self.operational_pool_hash is None: # Encountered a pool while we are not actively replacing a pool with a specific one of its arguments instantiations = [] for arg in pool['arguments']: # Store a flag (string hash) of the argument we wish to use to replace its parent pool; # Add a rule with that argument in place of its parent pool to a list of instantiations self.operational_pool_hash = pool_and_arg_hash(pool, arg) instantiations.append(super(ASTPoolInstantiator, self).visit(self.astCopier.deep_copy(self.stm))) # Class-recursive part; instantiate all instantiations, in case multiple pools exist within the rule self.astPoolInstantiator = ASTPoolInstantiator() for instantiation in instantiations: for instantiation_instantiation in self.astPoolInstantiator.instantiate_pools(instantiation): self.instantiations.append(instantiation_instantiation) else: # Encountered a pool while we are actively replacing a pool with a specific one of its arguments # If this is that specific pool, replace it with its visited argument # Otherwise, visit the pool's children as normal for arg in pool['arguments']: if self.operational_pool_hash == pool_and_arg_hash(pool, arg): return super(ASTPoolInstantiator, self).visit(arg, data) return super(ASTPoolInstantiator, self).visit_children(pool, data)
def visit_Function(self, function, data=TreeData()): predicate = Predicate(function['name'], len(function['arguments'])) if data.head: self.head_predicates.add(predicate) else: self.body_predicates.add(predicate) return super(ASTPredicateMapper, self).visit_children(function, data)
def visit( self, x, data=TreeData() ): # 'data' needed in arguments list so ASTVisitor will call this visit if isinstance(x, clingo.ast.AST): x = clingo.ast.AST(x.type, **dict(x)) return super(ASTCopier, self).visit(x, data) else: return super(ASTCopier, self).visit(x, data)
def visit_ConditionalLiteral(self, conditional_literal, data=TreeData()): """ If we encounter a conditional literal in the head, we are within either an Aggregate, Head Aggregate, or a Disjoint. In all cases, we have a conditional literal of the form literal : conditions where conditions are a set of literals. We want predicates in the literal to be marked as in the head, and predicates in the conditions to be marked as in the body. """ if data.head: conditional_literal['literal'] = super(ASTPredicateMapper, self).visit(conditional_literal['literal'], data) conditional_literal['condition'] = super(ASTPredicateMapper, self).visit(conditional_literal['condition'], TreeData(head=False)) return conditional_literal else: return super(ASTPredicateMapper, self).visit_children(conditional_literal, data)
def visit(self, x, data=TreeData()): if isinstance(x, clingo.ast.AST): attr = "visit_" + str(x.type) if hasattr(self, attr): return getattr(self, attr)(x, data) else: after = self.visit_children(x, data) return after elif isinstance(x, list): return [self.visit(y, data) for y in x] elif x is None: return x else: raise TypeError("unexpected type (%s)" % type(x))
def explore_children(self, x, data=TreeData()): for key in x.child_keys: attr = self.explore(x[key], TreeData(data.head or key == "head")) x[key] = attr return x
def visit_ShowSignature(self, show_signature, data=TreeData()): fixed_show_signature = ShowSignature(show_signature) return super(ASTReplacer, self).visit_children(fixed_show_signature, data)
def visit_Definition(self, definition, data=TreeData()): fixed_definition = Definition(definition) return super(ASTReplacer, self).visit_children(fixed_definition, data)
def visit_ConditionalLiteral(self, conditional_literal, data=TreeData()): fixed_conditional_literal = ConditionalLiteral(conditional_literal) return super(ASTReplacer, self).visit_children(fixed_conditional_literal, data)
def visit_children(self, x, data=TreeData()): for key in x.child_keys: getattr_tmp=getattr(x, key) child_x = self.visit(getattr_tmp, data) x[key] = child_x return x