def join_empty_LHS(call,params,new_call2,new_params2,old_call2,old_params2,preds,empty2): # RHS: call + params # new top call: new_call2 + new_params2 # # first we find a mapping of internal parameters from the predicate "call" # to the internal parameters of the predicate "new_call2" # * internal call parameter (preds[call][0]) -> top level params (params) # -> new top level params (new_params2) -> internal new top call parameter (preds[new_call2][0]) # * internal parameter from the call equal to nil are translated into "nil-Xn" internal parameters of the new call call_p_map={} nil_pos=1 for i in range(len(preds[call][0])): if params[i]=="nil": call_p_map[preds[call][0][i]]="nil-X%i"%nil_pos if not ("nil-X%i"%nil_pos in preds[new_call2][0]): raise JoinFailed("JOIN: ERROR: this line should not be accesible") nil_pos=nil_pos+1 elif params[i] in new_params2: call_p_map[preds[call][0][i]]=preds[new_call2][0][new_params2.index(params[i])] elif params[i] in old_params2: # handle the param on which the join is applied if "to_remove was true" (-->this param is not part of new_params2) call_p_map[preds[call][0][i]]=preds[old_call2][0][old_params2.index(params[i])] else: raise JoinFailed("JOIN: ERROR: this line should not be accesible") # map the empty2 inside the rule. if not len(empty2)==1: raise JoinFailed("JOIN: not implemented") # we suppose that the equality contains only a single disjunct # the other situation is not implemented disj=empty2[0] equal=[] for conj in disj: new_conj=[] for x in conj: new_conj.append(preds[old_call2][0][old_params2.index(x)]) if x=="nil": new_conj.append("nil") equal.append(new_conj) equal1=[] for x in equal: equal1.append(input.remove_multiple_occurences(x)) equal1=input.join_equalities(equal1) new_rule_params=preds[new_call2][0] # in the forbid variable, we store parameters, which are checked for the following: # they must be existentially quantified # they must be used only in call and call2 forbid=[] # for each rule create a new rule new_rules=[] for (al,pt,cls,eq) in preds[call][1]: # the system of predicates must be forward connected, so call_p_map[al] must be defined ... alloc=call_p_map[al] # find representatives mapping={} for conj in equal1: if alloc in conj: repres=alloc else: tmp=input.intersect_lists(new_rule_params,conj) if tmp>1: # equality between formal parameters implemented only if they are equal to the allocated node if "nil" in conj: for x in conj: if x=="nil": pass else: if new_params2[new_rule_params.index(x)]=="nil": repres=x else: # add to the forbid to_forbid=new_params2[new_rule_params.index(x)] if not (to_forbid in forbid): forbid.append(to_forbid) else: raise JoinFailed("JOIN: not implemented") elif tmp==1: for p in new_rule_params: if p in conj: repres=dp else: repres=conj[0] for x in conj: mapping[x]=repres # the original rule is translated as folows: # first all variables are translated according to the "all_p_map" # every variable outside all_p_map is translated to an unique new name # second all variables are translated according to the "mapping" new_al=apply_maps(al,call_p_map,mapping,new_params2,0) new_pt=[] for x in pt: new_pt.append(apply_maps(x,call_p_map,mapping,new_params2,0)) new_cls=[] for (call_pred,call_par) in cls: new_call_par=[] for x in call_par: new_call_par.append(apply_maps(x,call_p_map,mapping,new_params2,0)) new_cls.append((call_pred,new_call_par)) new_eq=[] for x in eq: new_eq.append(apply_maps(x,call_p_map,mapping,new_params2,1)) for x in mapping.keys(): if mapping[x]==new_al and (not x in new_eq): new_eq.append(x) # pop alocated node fron the equality list - not needed if new_al in new_eq: new_eq.pop(new_eq.index(new_al)) new_rules.append((new_al,new_pt,new_cls,new_eq)) # add the newly created rules inside preds par,rules=preds[new_call2] rules=rules+new_rules preds[new_call2]=(par,rules) return forbid
def join(preds,top_calls,emptyheap_eq,ex_quantified): # it emptyheap_eq==[] then join sould not create some empty heap - assert in the furure work_with_emptyheap=(not emptyheap_eq==[]) while len(top_calls)>1: # pick the first call for the join call,params=top_calls.pop(0) if emptyheap_eq==[]: empty=[] else: empty=emptyheap_eq.pop(0) #find a second call for a join # maximal number of attempts is given by the number of top calls candidate="" count=0 while (candidate=="") and (count<len(top_calls)): count=count+1 find=0 for i in range(len(top_calls)): call2,params2=top_calls[i] if emptyheap_eq==[]: empty2=[] else: empty2=emptyheap_eq[i] p_intersect=create_intersection(params,params2) if not (p_intersect==[] or (len(p_intersect)==1 and "nil" in p_intersect)): top_calls.pop(i) if not emptyheap_eq==[]: emptyheap_eq.pop(i) find=1 break if find==0: raise JoinFailed("Join failed") # find the candidate variable # - the candidate must be allocated in head of one of the calls # - the candidate must be an existentially quantified variable # - the candidate must be a link only between these two calls candidate="" for par in p_intersect: if (input.alloc(call,params.index(par),preds)): candidate=par if candidate=="": # swap positions of call and call2 call_aux=call call=call2 call2=call_aux params_aux=params params=params2 params2=params_aux empty_aux=empty empty=empty2 empty2=empty_aux for par in p_intersect: if (input.alloc(call,params.index(par),preds)): candidate=par if candidate=="": # still no success, push call (originally call2) back to topcalls # swap back call2 to call # then we will try so other item from topcall as call2 top_calls.append((call,params)) if work_with_emptyheap: emptyheap_eq.append(empty) (call,params,empty)=(call2,params2,empty2) # check whether the candidate was found if candidate=="": raise JoinFailed("Join failed: impossible to join the input into a single predicate call (or bad strategy)") if candidate=="nil": raise JoinFailed("Something odd happened: nil taken as a candidate. nil existantially quantified in RootCall?") # create a list of other parameters (different from candidate and nil) shared between the two calls # pop the "candidate" p_intersect.pop(p_intersect.index(candidate)) # pop all "nil" variables while "nil" in p_intersect: p_intersect.pop(p_intersect.index("nil")) #the candidate is removed from the parameters after join # if is it existentially quantified and it is not a parameter of other top level call to_remove=candidate in ex_quantified for (callX,paramsX) in top_calls: if candidate in paramsX: to_remove=False #raise JoinFailed("Join failed: parameter %s is in more the two calls on top level"%candidate) (call,params,empty,forbid)=do_join(candidate,call,params,empty,call2,params2,empty2,preds,p_intersect,to_remove) # check that variables in forbid are no more part of top calls and forbid is ex_quantificated for x in forbid: if not x in ex_quantified: raise JoinFailed("JOIN: forbiden variable is not existentially quantified") for (c,p) in top_calls: if input.intersect_lists(p,forbid)>0: raise JoinFailed("JOIN: forbiden variable in other calls") # add the newly created top call top_calls.append((call,params)) if work_with_emptyheap: emptyheap_eq.append(empty) elif (not empty==[]): raise JoinFailed("JOIN: ERROR: created emptyheap from some non-empty stuff") root_rule,root_params=top_calls[0] if emptyheap_eq==[]: ret_empty=[] else: ret_empty=emptyheap_eq[0] return (root_rule,root_params,ret_empty)