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)).
							 |