def tile_expr( _expr ): tiles = [] expr = copy.deepcopy( _expr ) lhs, rhs = expr.get_children() if isinstance( rhs, Predicate ): tiles_per_arg = [] for i, arg in enumerate( rhs.get_children() ): if not isOperand( arg ): tiles_per_arg.append( list(all_tilings( arg )) ) else: tiles_per_arg.append( [[arg]] ) cross = itertools.product( *tiles_per_arg ) for comb in cross: new_pred = copy.deepcopy( rhs ) new_ch = [ t[-1] for t in comb ] for i,ch in enumerate( new_ch ): new_pred.set_children( i, ch ) updates = list(itertools.chain.from_iterable( [t[:-1] for t in comb] )) tiles.append( updates + [Equal([lhs, new_pred])] ) else: if isOperand(rhs): tiles.append( [_expr] ) else: for tiling in all_tilings( rhs ): last = tiling.pop() # This is just a (temporary) symbol (output of one-to-last) one_to_last = tiling.pop() lhs, rhs = expr.get_children() one_to_last.set_children( 0, lhs ) # assign one-to-last to actual lhs of eq tiling.append( one_to_last ) tiles.append( tiling ) return tiles
def all_tilings( expr ): ongoing = [ [expr] ] while len( ongoing ) > 0: alg = ongoing.pop() to_tile = alg.pop() if isOperand( to_tile ): alg.append( to_tile ) yield alg continue to_tile = replace_all( copy.deepcopy( to_tile), grouping_rules ) for collection in reversed(instruction_set): matched_in_this_level = False ### These are just control vars ### to avoid redundancies for instr in collection: for node in to_tile.iterate_preorder(): # To avoid redundancies matched_this_node = [] ### if isinstance( instr, tuple ): # A way to deactivate some for quick development/debugging? continue for _m in instr.match( node ): matched_in_this_level = True ### #_T = TOS.new_temp() new = copy.deepcopy( to_tile ) #tile, new = instr.tile( new, _m, _T ) tile, new = instr.tile( new, node, _m ) lhs, rhs = tile.get_children() if rhs not in matched_this_node: ### matched_this_node.append( rhs ) ### ongoing.append( alg[:] + [tile, new] ) # Set size of new temporary lhs.children[0].size = rhs.get_size() else: # Aestetic. Simply to avoid missing T? values. TOS.push_back_temp( ) TOS._TOS.unset_operand( tile.children[0].children[0] ) if matched_in_this_level: ### break
def generate_predicate_before( self, pme, trav, linv, linv_obj): # [TODO] Cleanup, no need for linv AND linv_obj new = [copy.deepcopy(expr) for expr in itertools.chain(*linv)] # Repartition reparts = dict() repart_rules = [] for op in linv_obj.linv_operands: part = linv_obj.linv_operands_basic_part[op.get_name()] # [CHECK] _shape or not? Regular one needed for inheritance repart = repartition(op, part.shape, trav[op.get_name()]) # #repart_shape = {(1,1):(1,1), (1,2):(1,3), (2,1):(3,1), (2,2):(3,3)}[part.shape] #repart = repartition_shape( op, repart_shape ) #repart = repart_group( repart, repart_shape, trav[op.get_name()] ) # for part_op, repart_op in zip(itertools.chain(*part), itertools.chain(*repart)): repart_rules.append( RewriteRule(part_op, Replacement(repart_op))) reparts[op.get_name()] = repart # Apply repartitionings new = [replace(expr, repart_rules) for expr in new] # Explicit functions to BlockedExpression # First flatten args, then replace for expr in new: lhs, rhs = expr.get_children() if isinstance(rhs, Predicate): for i, arg in enumerate(rhs.get_children()): #rhs.set_children( i, flatten_blocked_operation(arg) ) rhs.set_children(i, flatten_blocked_operation_click(arg)) new = [replace(expr, known_pmes) for expr in new] # Operators applied to BlockedExpression, into BlockedExpressions for expr in new: if isinstance(expr, BlockedExpression): continue _, rhs = expr.get_children() #print( rhs ) # [TODO] Maybe "Sylv(...)"!!! #rhs = flatten_blocked_operation( rhs ) rhs = flatten_blocked_operation_click(rhs) expr.set_children(1, rhs) # Flatten left-hand sides of the previous type of expressions for expr in new: if isinstance(expr, BlockedExpression): continue lhs, rhs = expr.get_children() new_lhs = [] for out in lhs: if isinstance(out, Symbol): # this is a temporary one out.size = rhs.get_size() #part = partition_shape( out, rhs.shape ) part = partition_shape(out, tuple(rhs.shape)) new_lhs.append(part) else: new_lhs.append(out) lhs = BlockedExpression(map_thread(NList, new_lhs, 2), (0, 0), rhs.shape) expr.set_children(0, lhs) # Flatten the last type of expressions final = [] for expr in new: if isinstance(expr, BlockedExpression): final.extend([ simplify(to_canonical(eq)) for eq in itertools.chain(*expr) ]) else: lhs, rhs = expr.get_children() final.extend([ simplify(to_canonical(eq)) for eq in itertools.chain.from_iterable( map_thread(Equal, [lhs, rhs], 2)) ]) final = filter_zero_zero(final) # remove expressions of the type " B_10^T = ..." (e.g., in symv)" _final = final final = [] for expr in _final: lhs, rhs = expr.children lhs = lhs.children # [FIXME] == 1 only to make sure it does not affect other cases. # Just want to let them break and study them in the future if len(lhs) == 1 and (not isOperand(lhs[0]) or lhs[0].isZero()): continue final.append(expr) # # expand in terms of input parts # #expand_rules = list(itertools.chain(*self.expr_to_rule_lhs_rhs( final ))) #for expr in final: #expr.children[1] = simplify(to_canonical(replace_all(copy.deepcopy(expr.children[1]), expand_rules))) # # Print and return # for expr in final: print("* ", expr) return (reparts, final)
def expr_to_rule_rhs_lhs(self, predicates): rules = [] t = PatternStar("t") l = PatternStar("l") ld = PatternDot("ld") r = PatternStar("r") for p in predicates: pr = [] lhs, rhs = p.children if len(lhs.children) == 1: #lhs_sym = WrapOutBef( lhs.children[0] ) lhs_sym = lhs.children[0] if isinstance(rhs, Plus): # t___ + rhs -> t + lhs repl_f = (lambda lhs: lambda d: Plus(d["t"].children + [lhs]))(lhs_sym) pr.append( RewriteRule(Plus([t] + rhs.children), Replacement(repl_f))) # t___ + l___ rhs_i r___ + ... -> t + l lhs r repl_f = (lambda lhs: lambda d: Plus(d["t"].children + [ Times(d["l"].children + [lhs] + d["r"].children) ]))(lhs_sym) pr.append( RewriteRule( Plus([t] + [ Times([l] + [ch] + [r]) for ch in rhs.children ]), Replacement(repl_f))) repl_f = (lambda lhs: lambda d: Plus(d["t"].children + [ Times([simplify(to_canonical(Minus([lhs])))] + d["r"]. children) ]))(lhs_sym) pr.append( RewriteRule( Plus([t] + [ Times([simplify(to_canonical(Minus([ch])))] + [r]) for ch in rhs.children ]), Replacement(repl_f))) # A - B C in L B C R + -L A R (minus pushed all the way to the left, and whole thing negated) repl_f = (lambda lhs: lambda d: normalize_minus( Plus(d["t"].children + [ Times([d["ld"]] + d["l"].children + [Minus([lhs])] + d["r"].children) ])))(lhs_sym) pr.append( RewriteRule( Plus([t] + [ normalize_minus(Times([ld, l, Minus([ch]), r])) for ch in rhs.children ]), Replacement(repl_f))) # A - B C in -L B C R + L A R (minus pushed all the way to the left) repl_f = (lambda lhs: lambda d: Plus(d["t"].children + [ Times([d["ld"]] + d["l"].children + [lhs] + d["r"]. children) ]))(lhs_sym) pr.append( RewriteRule( Plus([t] + [ normalize_minus(Times([ld, l, ch, r])) for ch in rhs.children ]), Replacement(repl_f))) #repl_f = (lambda lhs: lambda d: Plus(d["t"].children + [Times([simplify(to_canonical(Minus(lhs.children)))] + d["r"].children)]))(lhs_sym) #pr.append( RewriteRule( Plus([t] + [ #Times([ Minus([ld]), l, ch, r]) if not isinstance(ch, Minus) \ #else Times([ l, ch.children[0], r]) \ #for ch in rhs.children ]), #Replacement(repl_f) ) ) repl_f = (lambda lhs: lambda d: Plus(d["t"].children + [ Times([ simplify(to_canonical(Minus([Transpose([lhs])]))) ] + d["r"].children) ]))(lhs_sym) pr.append( RewriteRule( Plus([t] + [ Times([ Minus([ld]), l, simplify(to_canonical(Transpose([ch]))), r]) if not isinstance(ch, Minus) \ else Times([ l, simplify(to_canonical(Transpose([ch]))), r]) \ for ch in rhs.children ]), Replacement(repl_f) ) ) elif isinstance(rhs, Times): repl_f = (lambda lhs: lambda d: Times(d[ "l"].children + [lhs] + d["r"].children))(lhs_sym) pr.append( RewriteRule(Times([l] + rhs.children + [r]), Replacement(repl_f))) repl_f = (lambda lhs: lambda d: Times(d[ "l"].children + [Transpose([lhs])] + d["r"].children) )(lhs_sym) pr.append( RewriteRule( Times([ l, simplify(to_canonical(Transpose([rhs]))), r ]), Replacement(repl_f))) # [TODO] Minus is a b*tch. Should go for -1 and remove the operator internally? repl_f = (lambda lhs: lambda d: Times([ simplify(to_canonical(Minus([Times([lhs])]))) ] + d["r"].children))(lhs_sym) pr.append( RewriteRule( Times([ simplify( to_canonical( Minus([Times(rhs.get_children())]))) ] + [r]), Replacement(repl_f))) repl_f = (lambda lhs: lambda d: Times([ simplify( to_canonical(Minus([Transpose([Times([lhs])])]))) ] + d["r"].children))(lhs_sym) pr.append( RewriteRule( Times([ simplify( to_canonical( Minus([ Transpose( [Times(rhs.get_children())]) ]))) ] + [r]), Replacement(repl_f))) else: pr.append(RewriteRule(rhs, Replacement(lhs_sym))) new_rhs = simplify(to_canonical(Transpose([rhs]))) if not isOperand(new_rhs): pr.append( RewriteRule( simplify(to_canonical(Transpose([rhs]))), Replacement(Transpose([lhs_sym])))) else: pr.append(RewriteRule(rhs, Replacement(lhs))) rules.append(pr) return rules
def is_feasible(self): pme = self.pme linv = self.expressions traversal_tuples = [[0] if shape == 1 else [1, -1] for shape in pme.part_tuple] feasible_traversals = [] # For peeling in slingen mode #self.iteration_rules = [] for traversal_dirs in itertools.product(*traversal_tuples): dims_to_part_shape = {} #for dims, shape in zip( self.operation.bound_dimensions, traversal_dirs ): for dims, shape in zip(self.linv_bound_dimensions, traversal_dirs): for dim in dims: dims_to_part_shape[dim] = shape initial_rules = [] final_rules = [] trav_shape = dict() #for operand in self.operation.operands: for operand in self.linv_operands: trav_shape[operand.get_name()] = ( dims_to_part_shape[operand.get_name() + "_r"], dims_to_part_shape[operand.get_name() + "_c"]) initial_rules.extend( #initial_rewrite(operand, pme.basic_partitionings[operand.get_name()], trav_shape[operand.get_name()]) initial_rewrite( operand, self.linv_operands_basic_part[operand.get_name()], trav_shape[operand.get_name()])) final_rules.extend( #final_rewrite(operand, pme.basic_partitionings[operand.get_name()], trav_shape[operand.get_name()]) final_rewrite( operand, self.linv_operands_basic_part[operand.get_name()], trav_shape[operand.get_name()])) pre = [] post = [] for expr in itertools.chain(*linv): new = copy.deepcopy(expr) pre.append(simplify(to_canonical(replace(new, initial_rules)))) new = copy.deepcopy(expr) post.append(simplify(to_canonical(replace(new, final_rules)))) # check if basic init basic_init = True for expr in pre: lhs, rhs = expr.get_children() if not all( op.isZero() for op in lhs ) and not \ isOperand( rhs ): basic_init = False break if not basic_init: continue # check if linv and not guard -> post #final_status = [ replace( copy.deepcopy(expr), self.op_to_implicit ) for expr in post ] final_status = post #rules1 = [] #rules2 = [] #neweq = replace( copy.deepcopy(self.operation.equation), [self.pme.known_ops[-1]] ) neweq = replace(copy.deepcopy(self.operation.equation), self.pme.known_ops) # [FIXME] Generalize implies_post = True if not neweq in final_status: implies_post = False continue feasible_traversals.append((trav_shape, pre, post)) # Store these states for use in loop peeling (LGenCode) #self.iteration_rules.append( (initial_rules, final_rules) ) if len(feasible_traversals) > 1: print("* More than one traversal for this LoopInvariant: %d" % len(feasible_traversals)) self.traversals = feasible_traversals return bool(feasible_traversals)