def _rewrite_concat(self, node: saldag.Concat): """ Concat nodes with more than 1 child can be forked into multiple Concats. """ if node.requires_mpc(): node.is_mpc = True if len(node.children) > 1 and node.is_boundary(): fork_node(node)
def _rewrite_concat(self, node: saldag.Concat): """ Concats are always reversible, only need to know if we are dealing with a boundary node (in which case it can be computed outside of MPC). """ if node.is_lower_boundary(): out_stored_with = node.out_rel.stored_with for par in node.parents: if not par.is_root(): par.out_rel.stored_with = copy.copy(out_stored_with) node.is_mpc = False
def fork_node(node: saldag.Concat): """ Concat nodes are often MPC boundaries. This method forks a Concat node that has more than one child node into a separate Concat node for each of it's children. """ # we can skip the first child child_it = enumerate(copy.copy(node.get_sorted_children())) next(child_it) # clone node for each of the remaining children for idx, child in child_it: # create clone and rename output relation to # avoid identical relation names for different nodes clone = copy.deepcopy(node) clone.out_rel.rename(node.out_rel.name + "_" + str(idx)) clone.parents = copy.copy(node.parents) warnings.warn("hacky fork_node") clone.ordered = copy.copy(node.ordered) clone.children = {child} for parent in clone.parents: parent.children.add(clone) node.children.remove(child) # make cloned node the child's new parent child.replace_parent(node, clone) child.update_op_specific_cols()
def _generate_concat(self, concat_op: saldag.Concat): """ Generate code for concat operations. """ in_rel_str = ", ".join( [in_rel.dbg_str() for in_rel in concat_op.get_in_rels()]) return "CONCAT{} [{}] AS {}\n".format( "MPC" if concat_op.is_mpc else "", in_rel_str, concat_op.out_rel.dbg_str())
def _rewrite_concat(self, node: saldag.Concat): """ Insert a Close op above a Concat node if it's parent's stored_with sets do not match it's own. """ assert (not node.is_lower_boundary()) out_stored_with = node.out_rel.stored_with ordered_pars = node.get_sorted_parents() for parent in ordered_pars: par_stored_with = parent.out_rel.stored_with if par_stored_with != out_stored_with: out_rel = copy.deepcopy(parent.out_rel) out_rel.rename(out_rel.name + "_close") out_rel.stored_with = copy.copy(out_stored_with) # create and insert close node store_op = saldag.Close(out_rel, None) store_op.is_mpc = True saldag.insert_between(parent, node, store_op)
def _rewrite_concat(self, node: saldag.Concat): """ Push down collusion sets for a Concat node. """ # Copy over columns from existing relation out_rel_cols = node.out_rel.columns # Combine per-column collusion sets for idx, col in enumerate(out_rel_cols): columns_at_idx = [ in_rel.columns[idx] for in_rel in node.get_in_rels() ] col.coll_sets = utils.coll_sets_from_columns(columns_at_idx)
def _generate_concat(self, concat_op: saldag.Concat): """ Generate code for Concat operations. """ all_rels = concat_op.get_in_rels() test = len(all_rels[0].columns) assert (all(test == len(rel.columns) for rel in all_rels)) store_code = '' if concat_op.is_leaf(): store_code += self._generate_store(concat_op) template = open( "{0}/{1}.tmpl".format(self.template_directory, 'concat'), 'r').read() data = { 'INRELS': ', '.join(r.name for r in concat_op.get_in_rels()), 'OUTREL': concat_op.out_rel.name, 'CACHE_VAR': cache_var(concat_op) } return pystache.render(template, data) + store_code
def _generate_concat(self, concat_op: ccdag.Concat): """ Generate code for Concat operations. """ in_rel_str = " + ".join( [in_rel.name for in_rel in concat_op.get_in_rels()]) return "{}{} = {}\n".format(self.space, concat_op.out_rel.name, in_rel_str)