def compute_signature(preds): # for each predicate, compute signatures --- # i.e. each formal parameter is assigned to one of the following categories # sig_fw: forward local edge is passed via this parameter # sig_bw: backward local edge is passed via this parameter # sig_eq: "extra edge" is passed via this parameter (NOT YET IMPLEMENTED) sig = {} for p in preds.keys(): (params, rules) = preds[p] sig_fw = [] sig_bw = [] sig_eq = [] for k in range(0, len(params)): if params[k] == '': continue if alloc(p, k, preds) and fw_edge(p, k, preds): sig_fw.append(k) if points_to(p, k, preds) and bw_edge(p, k, preds): sig_bw.append(k) if not(k in sig_fw or k in sig_bw): #raise InputError("Extra edges are not allowed") sig_eq.append(k) sig[p] = (sig_fw, sig_bw, sig_eq) return sig
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 (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 (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 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)