예제 #1
0
파일: join.py 프로젝트: cathiec/CathTA
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
예제 #2
0
파일: join.py 프로젝트: cathiec/CathTA
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)