def test_synthesizer_count_5s(): libSynth = getLib() tr1_1_28_28 = mkRealTensorSort([1, 1, 28, 28]) tr1_1 = mkRealTensorSort([1, 1]) tb1_1 = mkBoolTensorSort([1, 1]) libSynth.addItems([ PPLibItem('recog_5', func(tr1_1_28_28, tb1_1), None), ]) fn_sort = func(lst(tr1_1_28_28), tr1_1) synth = SymbolicSynthesizer(libSynth, fn_sort) I = 10000 i = 0 for prog, unkMap in synth.genProgs(): i = i + 1 if i > I: break if i % 100 == 0: print(i) unks = ASTUtils.getUnks(prog) if len(unks) > 1: continue for unk in unks: if ASTUtils.isAbstract(unk.sort): continue print(repr_py_ann(prog))
def renameSortVars(libItemSort, term): i = 0 svs = ASTUtils.getSortVars(libItemSort) for sv in svs: newsv = getSortVarNotInTerm(sv, term) libItemSort = ASTUtils.replaceAllSubTerms(libItemSort, sv, newsv) return libItemSort
def renameDimVars(libItemSort, term): i = 0 dvs = ASTUtils.getDimVars(libItemSort) for dv in dvs: newdv = mkDimVarNotInTerm(dv, term) libItemSort = ASTUtils.replaceAllSubTerms(libItemSort, dv, newdv) return libItemSort
def substOne(a: PPSortOrDimVar, b: PPSortOrDim, sortTerm: PPSort) -> PPSort: """ substitute b for all the occurrences of variable a in sortTerm """ term1 = ASTUtils.applyTd(sortTerm, lambda x: type(x) == PPSortVar, lambda x: b if x == a else x) term2 = ASTUtils.applyTd(term1, lambda x: type(x) == PPDimVar, lambda x: b if x == a else x) return term2
def getProgsAndUnkSortWithUniqueNames(self, progs): res = [] for prog in progs: assert (not ASTUtils.isOpen(prog)) unkSortMap = {} if ASTUtils.hasUnk(prog): prog = self._giveUniqueNamesToUnks(prog) unkSortMap = ASTUtils.getUnkNameSortMap(prog) res.append((prog, unkSortMap)) return res
def expandToUnk(term: PPTerm, ntId: int) -> Optional[PPTerm]: """ Generate a new term by replacing a "ntId"th NT from a "term" with a PPTermUnk """ nt = ASTUtils.getNthNT(term, ntId) # Avoid generating Unk of type PPDimConst, PPDimVar, PPEumSort, or PPInt() if isinstance(nt.sort, PPDimConst) or isinstance(nt.sort, PPDimVar) or isinstance(nt.sort, PPEnumSort) or \ isinstance(nt.sort, PPInt): return None unk = ASTDSL.mkUnk(nt.sort) # subst = unifyOne(unk.sort, nt.sort) # # if subst != []: # print("non empty subst") # # termExpanded = None # if subst is not None: # termUnified = applySubst(subst, term) # termExpanded = ReprUtils.replaceNthNT(termUnified, ntId, unk) termNew = ReprUtils.replaceNthNT(term, ntId, unk) return termNew
def testProgTreeSize(): lib = mkDefaultLib() # region #+ Add recogFive to library inType = mkRealTensorSort([1, 1, 28, 28]) outType = mkBoolTensorSort([1, 1]) recogDigitType = mkFuncSort(inType, outType) lib.addItem(PPLibItem('recogFive', recogDigitType, None)) # endregion inType = mkListSort(mkRealTensorSort([1, 1, 28, 28])) outType = mkRealTensorSort([1, 1]) sort = mkFuncSort(inType, outType) prog = \ PPFuncApp(fn=PPVar(name='lib.compose'), args=[PPFuncApp(fn=PPVar(name='lib.fold_l'), args=[PPTermUnk(name='nn_fun_x_906', sort=PPFuncSort( args=[PPTensorSort(param_sort=PPReal(), shape=[PPDimConst(value=1), PPDimConst(value=1)]), PPTensorSort(param_sort=PPBool(), shape=[PPDimConst(value=1), PPDimConst(value=1)])], rtpe=PPTensorSort(param_sort=PPReal(), shape=[PPDimConst(value=1), PPDimConst(value=1)]))), PPFuncApp(fn=PPVar(name='lib.zeros'), args=[PPIntConst(value=1)])]), PPFuncApp(fn=PPVar(name='lib.map_l'), args=[PPVar(name='lib.recogFive')])]) size = ASTUtils.progTreeSize(prog) assert size == 7
def print_progs_e(fn_sort, libSynth, targetSize): synth = SymbolicSynthesizer(libSynth, fn_sort) cnt = 1 ecnt = 1 for prog, unkMap in synth.genProgs(): sz = ASTUtils.getSize2(prog) if sz > targetSize: break res, code = NeuralSynthesizer.is_evaluable(prog, fn_sort) if res: if 'lib.compose(lib.repeat(10, lib.conv_g(lib.nn_relax))' in repr_py( prog): print('.', cnt, sz, repr_py(prog), ecnt) ecnt += 1 else: if 'lib.compose(lib.repeat(10, lib.conv_g(lib.nn_relax))' in repr_py( prog): print("#", cnt, sz, repr_py(prog), code) test = False if test: res, code = NeuralSynthesizer.is_evaluable(prog, fn_sort) # print(cnt, sz, prog) cnt += 1 print(cnt)
def expandToFuncApp(lib: FnLibrary, term: PPTerm, ntId: int, fname: str) -> Optional[PPTerm]: resTerm = None # Not needed now as there are no lambda terms # libItem = ScopeUtils.getAVarInScope(lib, term, ntId, fname) libItem = lib.getWithLibPrefix(fname) assert libItem nt = ASTUtils.getNthNT(term, ntId) libItem = alphaConvertLibItem(libItem, term) # TODO: expandToVar passed nt.sort as second argument subst = unifyOne(nt.sort, libItem.sort.rtpe) if not gUseTypes: if subst is None: subst = [] if subst is not None: nts = [PPTermNT('Z', arg_sort) for arg_sort in libItem.sort.args] fnApp = PPFuncApp(PPVar(libItem.name), nts) termUnified = applySubst(subst, term) fnAppUnified = applySubst(subst, fnApp) resTerm = ReprUtils.replaceNthNT(termUnified, ntId, fnAppUnified) return resTerm
def getActionsAllNts(self, st: PPTerm) -> List[Action]: # This results in duplicate programs. numNts = ASTUtils.getNumNTs(st) actions = [] for ntId in range(1, numNts + 1): for ruleId in range(Rules.numRules): actions.append(Action(ntId, ruleId)) return actions
def _giveUniqueNamesToUnks(self, st: PPTerm): def rename(nt: PPTermUnk): if nt.name == 'Unk': return PPTermUnk("nn_fun_%s_%d" % (self.nnprefix, self._ntNameGen()), nt.sort) else: # Renaming not required. return nt return ASTUtils.applyTd(st, ASTUtils.isUnk, rename)
def getSortVarNotInTerm(sv, term): """ get a sv that is not in term """ i = 0 while ASTUtils.exists(term, lambda x: x == sv): i = i + 1 newsv = PPSortVar(sv.name + '_' + str(i)) sv = newsv return sv
def mkDimVarNotInTerm(dv, term): """ get a dv that is not in term """ i = 0 while ASTUtils.exists(term, lambda x: x == dv): i = i + 1 newdv = PPDimVar(dv.name + '_' + str(i)) dv = newdv return dv
def expandDimConst(term: PPTerm, ntId: int) -> Optional[PPTerm]: """ Expand dimension constant to integer constants (Required for fold zeros) """ nt = ASTUtils.getNthNT(term, ntId) if type(nt.sort) != PPDimConst: return None subTerm = PPIntConst(nt.sort.value) termExpanded = ReprUtils.replaceNthNT(term, ntId, subTerm) return termExpanded
def print_progs(fn_sort, libSynth, targetSize): synth = SymbolicSynthesizer(libSynth, fn_sort) cnt = 0 for prog, unkMap in synth.genProgs(): sz = ASTUtils.getSize2(prog) if sz > targetSize: break cnt += 1 print(cnt, sz, repr_py(prog)) # print(cnt, sz, prog) print(cnt)
def applyExpandEnum(lib: FnLibrary, term: PPTerm, ntId: int) -> List[PPTerm]: res = [] nt = ASTUtils.getNthNT(term, ntId) if type(nt.sort) != PPEnumSort: return res for i in range(nt.sort.start, nt.sort.end + 1): subTerm = PPIntConst(i) nxtTerm = expandEnum(term, ntId, subTerm) if nxtTerm is not None: res.append(nxtTerm) return res
def test_synthesizer_sum_digits(): libSynth = getLib() input_type = mkListSort(mkRealTensorSort([1, 1, 28, 28])) output_type = mkRealTensorSort([1, 1]) fn_sort = mkFuncSort(input_type, output_type) tr1_1_28_28 = mkRealTensorSort([1, 1, 28, 28]) tb_1_10 = mkBoolTensorSort([1, 10]) classify_digit = mkFuncSort(tr1_1_28_28, tb_1_10) libSynth.addItems([ PPLibItem('classify_digit', classify_digit, None), ]) synth = SymbolicSynthesizer(libSynth, fn_sort) I = 10000 i = 0 for prog, unkMap in synth.genProgs(): i = i + 1 if i > I: break if i % 100 == 0: print(i) unks = ASTUtils.getUnks(prog) if len(unks) > 1: continue for unk in unks: if ASTUtils.isAbstract(unk.sort): continue print(repr_py_ann(prog))
def _processProg(prog, cmts): newProgs = [] sortVars = ASTUtils.getSortVars(prog) if sortVars: sortVar = sortVars[0] progress = True for cmt in cmts: newProg = substOne(sortVar, cmt, prog) newProgs.append(newProg) else: # Add the program as it is progress = False newProgs.append(prog) return newProgs, progress
def genProg(self, sort: PPSort, maxDepth: int) -> Optional[PPTerm]: state = PPTermNT('Z', sort) di = 0 while di < maxDepth: nxtState = self.getNextRandomSt(state) if nxtState is None: return None elif not ASTUtils.isOpen(nxtState): return nxtState else: # isOpen state = nxtState di += 1 return None
def update_library(self, lib: FnLibrary, task_result_single: TaskResultSingle, taskid): if self.seq_settings.update_library: # Add learned modules to the library top_solution = task_result_single.get_top_solution_details() if top_solution is not None: prog, resDict = top_solution unk_sort_map: Dict[str, PPSort] = ASTUtils.getUnkNameSortMap(prog) lib_items = [ PPLibItem(unk, unk_sort, resDict['new_fns_dict'][unk]) for unk, unk_sort in unk_sort_map.items() ] if lib_items.__len__() > 0: lib.addItems(lib_items) # Save the library. lib.save1(self.getLibLocation(), taskid)
def traverse(iterm: PPTerm, ivars: Dict[str, PPVarDecl]): nonlocal count, varDecls, found if type(iterm) == PPTermNT: count += 1 if count == n: varDecls = ivars found = True elif type(iterm) == PPLambda: iVarsNew = ivars.copy() for param in iterm.params: iVarsNew[param.name] = param traverse(iterm.body, iVarsNew) else: for c in ASTUtils.deconstruct(iterm): if found: break traverse(c, ivars)
def genProgs(self) -> Iterable[Tuple[PPTerm, Dict[str, PPSort]]]: for prog in self.genTerms(): if self.isOpen(prog): continue if self.concreteTypes: maxSortVarsToBeInstantiated = 2 eprogs = instantiateSortVar(prog, self.concreteTypes, maxSortVarsToBeInstantiated) else: eprogs = [prog] for eprog in eprogs: unkSortMap = {} if self.hasUnk(eprog): eprog = self._giveUniqueNamesToUnks(eprog) unkSortMap = ASTUtils.getUnkNameSortMap(eprog) yield eprog, unkSortMap
def expandToVar(lib: FnLibrary, term: PPTerm, ntId: int, vname: str) -> Optional[PPTerm]: """ Generate a new term by replacing a "ntId"th NT from a "term" with a variable (in scope) with name "fname" """ nt = ASTUtils.getNthNT(term, ntId) # libItem = ScopeUtils.getAVarInScope(lib, term, ntId, vname) libItem = lib.getWithLibPrefix(vname) assert libItem libItem = alphaConvertLibItem(libItem, term) subst = unifyOne(libItem.sort, nt.sort) if not gUseTypes: if subst is None: subst = [] termExpanded = None if subst is not None: termUnified = applySubst(subst, term) termExpanded = ReprUtils.replaceNthNT(termUnified, ntId, PPVar(libItem.name)) return termExpanded
def isOpen(self, st: PPTerm) -> bool: return ASTUtils.isOpen(st)
def is_evaluable(st, ns) -> Tuple[bool, int]: # The program should not be open (no non-terminals). if ASTUtils.isOpen(st): return False, 1 unks = ASTUtils.getUnks(st) # At most 3 unks for now. if len(unks) > 3: return False, 2 # return False, 3 # print(repr_py(st)) number_of_mlp_nns = 0 for unk in unks: # type variables and dimension variables not allowed. if ASTUtils.isAbstract(unk.sort): return False, 3 # Only function types allowed if type(unk.sort) != PPFuncSort: return False, 4 # ******* INPUTS ******* : # An input to a function can't be a function if any([type(arg_sort) == PPFuncSort for arg_sort in unk.sort.args]): return False, 11 fn_input_sort = unk.sort.args[0] fn_output_sort = unk.sort.rtpe # No more than 2 arguments num_input_arguments = unk.sort.args.__len__() if num_input_arguments > 1: in1_is_2d_tensor = type( unk.sort.args[0] ) == PPTensorSort and unk.sort.args[0].shape.__len__() == 2 in2_is_2d_tensor = type( unk.sort.args[1] ) == PPTensorSort and unk.sort.args[1].shape.__len__() == 2 out_is_2d_tensor = type( unk.sort.rtpe) == PPTensorSort and unk.sort.rtpe.shape.__len__( ) == 2 # If a function takes 2 inputs, they'll be concatenated. Thus, we need them to be 2 dimensional tensors if num_input_arguments == 2 and in1_is_2d_tensor and in2_is_2d_tensor and out_is_2d_tensor: continue else: return False, 5 # If the NN's input is a list, it should be: List<2dTensor> -> 2dTensor # (as seq-to-seq models aren't supported) # We support List<2dTensor> -> 2dTensor if type(unk.sort.args[0]) == PPListSort: in_is_list_of_2d_tensors = type( unk.sort.args[0].param_sort) == PPTensorSort and len( unk.sort.args[0].param_sort.shape) == 2 out_is_2d_tensor = type( unk.sort.rtpe) == PPTensorSort and unk.sort.rtpe.shape.__len__( ) == 2 if in_is_list_of_2d_tensors and out_is_2d_tensor: continue else: return False, 6 # If the input to the NN is an image: cnn_feature_dim = 64 input_is_image = type( fn_input_sort) == PPTensorSort and fn_input_sort.shape.__len__( ) == 4 if input_is_image: # if the input is of size [batch_size, _, 28, 28], the output must be of size [batch_size, 32, 4, 4] cond0a1 = fn_input_sort.shape[ 2].value == 28 and fn_input_sort.shape[3].value == 28 cond0a2 = type(fn_output_sort) == PPTensorSort and fn_output_sort.shape.__len__() == 4 and \ fn_output_sort.shape[1].value == cnn_feature_dim \ and fn_output_sort.shape[2].value == 4 and fn_output_sort.shape[3].value == 4 # if the input is of size [batch_size, 32, 4, 4], the output must be two dimensional cond0b1 = fn_input_sort.shape[1].value == cnn_feature_dim \ and fn_input_sort.shape[2].value == 4 and fn_input_sort.shape[3].value == 4 cond0b2 = type( fn_output_sort ) == PPTensorSort and fn_output_sort.shape.__len__() == 2 if not ((cond0a1 and cond0a2) or (cond0b1 and cond0b2)): return False, 50 if cond0b1 and cond0b2: number_of_mlp_nns += 1 continue # if the input is a 2d tensor: in_is_2d_tensor = type( unk.sort.args[0] ) == PPTensorSort and unk.sort.args[0].shape.__len__() == 2 out_is_2d_tensor = type( unk.sort.rtpe) == PPTensorSort and unk.sort.rtpe.shape.__len__( ) == 2 if in_is_2d_tensor: if out_is_2d_tensor: number_of_mlp_nns += 1 else: return False, 51 return False, 52 lib_names = get_lib_names(st) # don't allow multiple repeats, as we could just keep on stacking these. if lib_names.count("repeat") > 1: return False, 15 # lib_names = self.interpreter for lib_name in lib_names: # TODO: check if the functions is part of graph convolution, but is used outside of a conv_g operator. if type(ns.lib.items[lib_name].obj) == NetMLP: number_of_mlp_nns += 1 # don't allow for multiple MLPs, as we can just keep on stacking them # (thus going into architecture search, which is out of scope) if number_of_mlp_nns > 1: return False, 16 return True, 0
def getActionCost(self, st: PPTerm, action: Action) -> float: return ASTUtils.getSize(st)
def expandNthNT(term: PPTerm, ntId: int, expand: Callable[[PPTermNT], PPTerm]) -> PPTerm: newTerm = ASTUtils.applyTdOnce(term, ASTUtils.isNthNT(ntId), expand) return newTerm
def hasUnk(self, st: PPTerm) -> bool: return ASTUtils.hasUnk(st)
def replaceNthNT(term: PPTerm, ntId: int, newSubTerm: PPTerm) -> PPTerm: newTerm = ASTUtils.applyTdOnce(term, ASTUtils.isNthNT(ntId), lambda nt: newSubTerm) return newTerm
def expandEnum(term: PPTerm, ntId: int, subTerm: PPTerm) -> Optional[PPTerm]: nt = ASTUtils.getNthNT(term, ntId) termExpanded = ReprUtils.replaceNthNT(term, ntId, subTerm) return termExpanded