def list2FunctionNode(l, style="atis"): """ Takes a list *l* of lambda arguments and maps it to a function node. The *style* of lambda arguments could be "atis", "scheme", etc. """ if isinstance(l, list): if len(l) == 0: return None elif style is 'atis': rec = lambda x: list2FunctionNode( x, style=style) # a wrapper to my recursive self if l[0] == 'lambda': return FunctionNode('FUNCTION', 'lambda', [rec(l[3])], generation_probability=0.0, bv_type=l[1], bv_args=None) # TOOD: HMM WHAT IS THE BV? else: return FunctionNode(l[0], l[0], map(rec, l[1:]), generation_probability=0.0) elif style is 'scheme': raise NotImplementedError else: # for non-list return l
def compose_and_reduce(*args): """ ((args[0] args[1]) args[2]) .. This copies each arg, so you don't have to """ assert len(args) > 1 fn = FunctionNode(None, 'EXPR', 'apply_', [copy(args[0]), copy(args[1])]) for i in xrange(2, len(args)): fn = FunctionNode(fn, 'EXPR', 'apply_', [fn, copy(args[i])]) try: return lambda_reduce(fn) except RuntimeError: return None
def compose_and_reduce(*args): """ ((args[0] args[1]) args[2]) .. This copies each arg, so you don't have to """ ## TODO: UGH THIS CIRCULAR IMPORT from LOTlib.FunctionNode import FunctionNode assert len(args) > 1 fn = FunctionNode('EXPR', 'apply_', [copy(args[0]), copy(args[1])]) for i in xrange(2,len(args)): fn = FunctionNode('EXPR', 'apply_', [fn, copy(args[i])]) try: return lambda_reduce(fn) except RuntimeError: return None
def generate(self, x='*USE_START*', d=0): """ RealValueGrammar.generate may create gaussians or uniforms when given "*gaussian*" and "*uniform*" as the nonterminal type. Otherwise, this is identical to LOTlib.Grammar """ if x == '*USE_START*': x = self.start if x=='*gaussian*': # TODO: HIGHLY EXPERIMENTAL!! # Wow this is really terrible for mixing... v = np.random.normal() gp = normlogpdf(v, 0.0, 1.0) return FunctionNode(returntype=x, name=str(v), args=None, generation_probability=gp, ruleid=0, resample_p=CONSTANT_RESAMPLE_P ) ##TODO: FIX THE ruleid elif x=='*uniform*': v = np.random.rand() gp = 0.0 return FunctionNode(returntype=x, name=str(v), args=None, generation_probability=gp, ruleid=0, resample_p=CONSTANT_RESAMPLE_P ) ##TODO: FIX THE ruleid else: # Else call normal generation Grammar.generate(self,x,d=d)
def make(cls, make_h0, data, grammar, **args): """ This is the initializer we use to create this from a grammar, creating children for each way grammar.start can expand """ h0 = make_h0(value=None) ## For each nonterminal, find out how much (in the prior) we pay for a hole that size hole_penalty = dict() dct = defaultdict(list) # make a lit of the log_probabilities below for _ in xrange(1000): # generate this many trees t = grammar.generate() for fn in t: dct[fn.returntype].append(grammar.log_probability(fn)) hole_penalty = {nt: sum(dct[nt]) / len(dct[nt]) for nt in dct} #We must modify the grammar to include one more nonterminal here mynt = "<hsmake>" myr = GrammarRule(mynt, '', [grammar.start], p=1.0) grammar.rules[mynt].append(myr) return cls(make_h0( value=FunctionNode(None, mynt, '', [grammar.start], rule=myr)), data, grammar, hole_penalty=hole_penalty, parent=None, **args) # the top state
def propose_tree(self, t): """ Delete: - find an apply - take the interior of the lambdathunk and sub it in for the lambdaarg everywhere, remove the apply Insert: - Find a node - Find a subnode s - Remove all repetitions of s, create a lambda thunk - and add an apply with the appropriate machinery """ newt = copy(t) f, b = 0.0, 0.0 success = False #acts to tell us if we found and replaced anything def is_extractable(n): # We must check that this doesn't contain any bound variables of outer lambdas introduced_bvs = set( ) # the bvs that are introduced below n (and are thus okay) for ni in n: if ni.ruleid < 0 and ni.name not in introduced_bvs: # If it's a bv return False elif ni.islambda() and ni.bv_name is not None: introduced_bvs.add(ni.bv_name) return True def is_apply(x): return (x.name == 'apply_') and ( len(x.args) == 2) and x.args[0].islambda() and not x.args[1].islambda() # ------------------ if random() < 0.5: #INSERT MOVE # sample a node for ni, di, resample_p, Z in self.grammar.sample_node_via_iterate( newt): # Sample a subnode -- NOTE: we must use copy(ni) here since we modify this tree, and so all hell breaks loose otherwise for s, sdi, sresample_p, sZ in self.grammar.sample_node_via_iterate( copy(ni), predicate=is_extractable): success = True below = copy(ni) varname = 'Y' + str(di + 1) # replace with the variables # TODO: FIX THE RID HERE -- HOW DO WE TREAT IT? below.replace_subnodes( s, FunctionNode(s.returntype, varname, None, ruleid=-999)) # create a new node, the lambda abstraction fn = FunctionNode(below.returntype, 'apply_', [ \ FunctionNode('LAMBDAARG', 'lambda', [ below ], bv_prefix='Y', bv_name=varname, bv_type=s.returntype, bv_args=[] ),\ s ] ) # Now convert into a lambda abstraction ni.setto(fn) f += (log(resample_p) - log(Z)) + (log(sresample_p) - log(sZ)) else: # DELETE MOVE resample_p = None for ni, di, resample_p, Z in self.grammar.sample_node_via_iterate( newt, predicate=is_apply): success = True ## what does the variable look like? Here a thunk with bv_name var = FunctionNode(ni.args[0].bv_type, ni.args[0].bv_name, None) assert len(ni.args) == 2 assert len(ni.args[0].args) == 1 newni = ni.args[0].args[0] # may be able to optimize away? ## and remove newni.replace_subnodes(var, ni.args[1]) ##print ":", newni ni.setto(newni) f += (log(resample_p) - log(Z)) if resample_p is None: return [newt, 0.0] #newZ = self.grammar.resample_normalizer(newt, predicate=is_replacetype) ##to go back, must choose the #b += log(resample_p) - log(newZ) # newt.fix_bound_variables() ## TODO: I think these are just from old versions # newt.reset_function() # make sure we update the function if not success: return [copy(t), 0.0] else: return [newt, f - b]