276 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
		
		
			
		
	
	
			276 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
|   | /*============================================================================== | ||
|  |  *	LPAD and CP-Logic reasoning suite | ||
|  |  *	File: montecarlo.pl | ||
|  |  *	Solves LPADs with Monte Carlo (main predicate: solve(Goals, Prob, Samples, ResTime, BddTime) | ||
|  |  *	Copyright (c) 2009, Stefano Bragaglia | ||
|  |  *============================================================================*/ | ||
|  |   | ||
|  | /* EXTERNAL FILE | ||
|  |  * ------------- | ||
|  |  * The following libraries are required by the program to work fine. | ||
|  |  */ | ||
|  | 
 | ||
|  | :- dynamic rule/4, def_rule/2, randx/1, randy/1, randz/1. | ||
|  | 
 | ||
|  | :- use_module(library(lists)). | ||
|  | :- use_module(library(random)). | ||
|  | :- use_module(library(ugraphs)). | ||
|  | :- use_module(params). | ||
|  | 
 | ||
|  | % :- source. | ||
|  | % :- yap_flag(single_var_warnings, on). | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* SOLVING PREDICATES | ||
|  |  * ------------------ | ||
|  |  * The predicates in this section solve any given problem with several class of  | ||
|  |  * algorithms. | ||
|  |  * | ||
|  |  * Note: the original predicates (no more need and eligible to be deleted) have  | ||
|  |  *       been moved to the end of the file. | ||
|  |  */ | ||
|  | 
 | ||
|  | /* Starting seed. */ | ||
|  | randx(1). | ||
|  | randy(1). | ||
|  | randz(1). | ||
|  | 
 | ||
|  | /* newsample | ||
|  |  * --------- | ||
|  |  * This predicate programmatically generates and sets a new seed for the  | ||
|  |  * algorithm. | ||
|  |  */ | ||
|  | newsample :- | ||
|  | 	retract(randx(X)), | ||
|  | 	randy(Y), | ||
|  | 	randz(Z), | ||
|  | 	(X =< 30269 -> | ||
|  | 		SuccX is X + 1, | ||
|  | 		assert(randx(SuccX)); | ||
|  | 		assert(randx(1)), | ||
|  | 		retract(randy(_)), | ||
|  | 		(Y =< 30307 -> | ||
|  | 			SuccY is Y + 1, | ||
|  | 			assert(randy(SuccY)); | ||
|  | 			assert(randy(1)), | ||
|  | 			retract(randz(_)), | ||
|  | 			(Z =< 30323 -> | ||
|  | 				SuccZ is Z + 1, | ||
|  | 				assert(randz(SuccZ)); | ||
|  | 				assert(randz(1))))), | ||
|  | 	setrand(rand(X, Y, Z)). | ||
|  | 
 | ||
|  | 
 | ||
|  | /* solve(Goals, Samples, Time, Lower, Prob, Upper) | ||
|  |  * ----------------------------------------------- | ||
|  |  * This predicate calls the Monte Carlo solving method for the current problem. | ||
|  |  * It requires the Goals to fulfil and returns the number of Samples considered, | ||
|  |  * the Time required, the extimated Probability and the Lower and Upper bounds. | ||
|  |  * | ||
|  |  * INPUT | ||
|  |  *  - Goals: given list of goals to fulfil. | ||
|  |  * | ||
|  |  * OUTPUT | ||
|  |  *  - Samples: number of samples considered to solve the problem. | ||
|  |  *  - Time: time required to solve the problem. | ||
|  |  *  - Lower: lower end of the confidence interval. | ||
|  |  *  - Prob: extimated probability. | ||
|  |  *  - Upper: upper end of the confidence interval. | ||
|  |  */ | ||
|  | solve(Goals, Samples, Time, Lower, Prob, Upper) :- | ||
|  | 	% Retrieving functional parameters... | ||
|  | 	setting(k, K), | ||
|  | 	setting(min_error, MinError), | ||
|  | 	% Resetting the clocks... | ||
|  | 	statistics(walltime, [_, _]),	 | ||
|  | 	% Performing resolution... | ||
|  | 	montecarlo(0, 0, Goals, K, MinError, Samples, Lower, Prob, Upper),	 | ||
|  | 	% Taking elapsed times... | ||
|  | 	statistics(walltime, [_, ElapTime]), | ||
|  | 	% Setting values... | ||
|  | 	Time is ElapTime/1000. | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* montecarlo(Count, Success, Goals, K, MinError, Samples, Lower, Prob, Upper) | ||
|  |  * --------------------------------------------------------------------------- | ||
|  |  * This tail recursive predicate solves the problem currently in memory with a | ||
|  |  * Monte Carlo approach.  | ||
|  |  * It requires the number of samples and successes so far (Count and Success), | ||
|  |  * the desired list of Goals to fulfil, the number K of samples to consider at | ||
|  |  * once and the threshold MinError for the binomial proportion confidence  | ||
|  |  * interval. | ||
|  |  * It returns the total number of Samples considered, the Lower and Upper ends  | ||
|  |  * of the the binomial proportion confidence interval and the extimated Prob. | ||
|  |  *  | ||
|  |  * INPUT | ||
|  |  *  - Count: number of samples considered so far. | ||
|  |  *  - Success: number of successfull samples considered so far. | ||
|  |  *  - Goals: list of goals to fulfil. | ||
|  |  *  - K: number of samples to consider at once. | ||
|  |  *  - MinError: threshold for the binomial proportion confidence interval. | ||
|  |  *  | ||
|  |  * OUTPUT | ||
|  |  *  - Samples: total number of samples considered. | ||
|  |  *  - Lower: lower end of the the binomial proportion confidence interval. | ||
|  |  *  - Prob: extimated probability. | ||
|  |  *  - Upper: upper end of the the binomial proportion confidence interval. | ||
|  |  * | ||
|  |  * NB: This method is based on the binomial proportion confidence interval and | ||
|  |  *     the Brown's rule of thumb to avoid the case the sample proportion is  | ||
|  |  *     exactly 0.0 or 1.0 and doesn't make use of BDDs. | ||
|  |  */ | ||
|  | montecarlo(Count, Success, Goals, K, MinError, Samples, Lower, Prob, Upper) :- | ||
|  | 	/* Decomment the following line if you want to test the algorithm with an | ||
|  | 	   incremental seed for each sample. | ||
|  | 	newsample, | ||
|  | 	*/ | ||
|  | 	main(Goals, [], _Explan, Valid), | ||
|  | 	N is Count + 1, | ||
|  | 	S is Success + Valid, | ||
|  | 	(N mod K =:= 0 -> | ||
|  | %		format("Advancement: ~t~d/~d~30+~n", [S, N]), | ||
|  | 		P is S / N, | ||
|  | 		D is N - S, | ||
|  | 		Semi is 2 * sqrt(P * (1 - P) / N), | ||
|  | 		Int is 2 * Semi, | ||
|  | 	/*   N * P > 5;   N * S / N > 5;   S > 5 | ||
|  | 	 *   N (1 - P) > 5;   N (1 - S / N) > 5;   N (N - S) / N > 5;   N - S > 5 | ||
|  | 	 */ | ||
|  | 		((S > 5, D > 5, (Int < MinError; Int =:= 0)) -> | ||
|  | 			Samples is N, | ||
|  | 			Lower is P - Semi, | ||
|  | 			Prob is P, | ||
|  | 			Upper is P + Semi; | ||
|  | 			montecarlo(N, S, Goals, K, MinError, Samples, Lower, Prob, Upper)); | ||
|  | 		montecarlo(N, S, Goals, K, MinError, Samples, Lower, Prob, Upper)). | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* null | ||
|  |  * ---- | ||
|  |  * This is dummy predicate to use sparingly when needed.  | ||
|  |  * Typical uses are as spying predicate during tracing or as dead branch in  | ||
|  |  * ( -> ; ) predicate. | ||
|  |  */	 | ||
|  | null. | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* main(Goals, Explan0, Explan1, Valid) | ||
|  |  * ------------------------------------ | ||
|  |  * This tail recursive predicate looks for a solution to the given Goals | ||
|  |  * starting from the given Explan0 and returns the final Explan and 1 (0 otherwise) if it is a  | ||
|  |  * Valid sample for Montecarlo. | ||
|  |  */ | ||
|  | main([], Explan, Explan, 1).  | ||
|  | 
 | ||
|  | main([\+ Goal|Tail], Explan0, Explan1, Valid) :- | ||
|  | 	builtin(Goal), !, | ||
|  | 	(call((\+ Goal)) -> | ||
|  | 		main(Tail, Explan0, Explan1, Valid); | ||
|  | 		Explan1 = Explan0, | ||
|  | 		Valid = 0). | ||
|  | 	 | ||
|  | main([Goal|Tail], Explan0, Explan1, Valid) :- | ||
|  | 	builtin(Goal), !, | ||
|  | 	(call(Goal) -> | ||
|  | 		main(Tail, Explan0, Explan1, Valid); | ||
|  | 		Explan1 = Explan0, | ||
|  | 		Valid = 0). | ||
|  | 
 | ||
|  | main([Goal|Tail], Explan0, Explan1, Valid) :- | ||
|  | 	findall((IsSample, Goals, Step), explore([Goal|Tail], Explan0, IsSample, Goals, Step), List),  | ||
|  | 	cycle(List, Explan0, Explan1, Valid). | ||
|  | 
 | ||
|  | 	 | ||
|  | 
 | ||
|  | /* explore([Goal|Tail], Explan, Valid, Goals, Step) | ||
|  |  * ------------------------------------------------ | ||
|  |  * This predicate looks for a Body and the Step to reach it from the given Goal  | ||
|  |  * and Explan and returns 1 (0 otherwise) if they are a Valid sample for | ||
|  |  * Montecarlo.  | ||
|  |  * Please note that Body and Step are meaningfull only when Valid is 1. | ||
|  |  * | ||
|  |  * This comment has to be fixed. | ||
|  |  */ | ||
|  | explore([Goal|Tail], _Explan, 1, Goals, []) :- | ||
|  | 	def_rule(Goal, Body), | ||
|  | 	append(Body, Tail, Goals). | ||
|  | 
 | ||
|  | explore([Goal|Tail], Explan, Valid, Goals, Step) :-  | ||
|  | 	findrule(Goal, Explan, Valid, Body, (HeadID, RuleID, Subst)), | ||
|  | 	append(Body, Tail, Goals), | ||
|  | 	(member_eq((HeadID, RuleID, Subst), Explan) -> | ||
|  | 		Step = []; | ||
|  | 		Step = [(HeadID, RuleID, Subst)]). | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* findrule(Goal, Explan, Valid, Body, (HeadID, RuleID, Subst)) | ||
|  |  * --------------------------------------------------------------- | ||
|  |  * This predicate finds a rule that matches with the given Goal and Explan and | ||
|  |  * returns 1 (0 otherwise) if it is a Valid sample for Montecarlo. | ||
|  |  * If the sample is Valid, the other return parameters are also meaningfull and | ||
|  |  * are the Body and (RuleID, Subst, HeadIS) of the rule that matches with the  | ||
|  |  * given Goal and Explan. | ||
|  |  * | ||
|  |  * This comment has to be fixed. | ||
|  |  */ | ||
|  | findrule(Goal, Explan, Valid, Body, (HeadId, RuleId, Subst)) :- | ||
|  | 	rule(Goal, _Prob, Required, RuleId, Subst, _Heads, HeadsList, Body), | ||
|  | 	sample(HeadsList, HeadId), | ||
|  | 	not_already_present_with_a_different_head(HeadId, RuleId, Subst, Explan), | ||
|  | 	(HeadId =:= Required -> | ||
|  | 		Valid = 1; | ||
|  | 		Valid = 0). | ||
|  | 	 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* sample(Heads, RuleId, HeadId, Subst) | ||
|  |  * ------------------------------------ | ||
|  |  * This tail recursive predicate samples a random head among the given Heads of | ||
|  |  * the given RuleId and returns its HeadId and Subst. | ||
|  |  */ | ||
|  | sample(HeadList, HeadId) :- | ||
|  | 	random(Prob),  | ||
|  | 	sample(HeadList, 0, 0, Prob, HeadId), !. | ||
|  | 
 | ||
|  | sample([_HeadTerm:HeadProb|Tail], Index, Prev, Prob, HeadId) :- | ||
|  | 	Succ is Index + 1, | ||
|  | 	Next is Prev + HeadProb, | ||
|  | 	(Prob =< Next -> | ||
|  | 		HeadId = Index; | ||
|  | 		sample(Tail, Succ, Next, Prob, HeadId)). | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /* cycle([(IsSample, Body, [Step])|Tail], Explan0, Explan1, Found) | ||
|  |  * ----------------------------------------------------------------- | ||
|  |  * This tail recursive predicate analyzes the given Body and Step to reach it | ||
|  |  * and returns 0 as it's not a Valid sample for Montecarlo.  | ||
|  |  * If it is Valid, it looks for a solution to the Body and the given Goals  | ||
|  |  * starting from the Step and the given Explan and returns 1 if it finds a | ||
|  |  * Valid one. | ||
|  |  * If it does not find it, it considers the next Body and Step and returns their | ||
|  |  * Valid value. | ||
|  |  * | ||
|  |  * NB: This comment needs to be updated. | ||
|  |  */ | ||
|  | cycle([], Explan, Explan, 0). | ||
|  | 
 | ||
|  | cycle([(0, _Goals, Step)|Tail], Explan0, Explan1, IsSample) :- !, | ||
|  | 	append(Step, Explan0, Explan2), | ||
|  | 	cycle(Tail, Explan2, Explan1, IsSample). | ||
|  | 
 | ||
|  | cycle([(1, Goals, Step)|Tail], Explan0, Explan1, IsSample) :-  | ||
|  | 	append(Step, Explan0, Explan), | ||
|  | 	main(Goals, Explan, Explan2, Valid), | ||
|  | 	(Valid == 1 -> | ||
|  | 		Explan1 = Explan2, | ||
|  | 		IsSample = 1; | ||
|  | 		cycle(Tail, Explan2, Explan1, IsSample)). |