% Figure 14.4 A CLP(R) scheduling program for problems with precedence and resource % constraints. % Scheduling with CLP with limited resources schedule( BestSchedule, BestTime) :- tasks( TasksDurs), precedence_constr( TasksDurs, Schedule, FinTime), % Set up precedence inequalities initialise_bound, % Initialise bound on finishing time assign_processors( Schedule, FinTime), % Assign processors to tasks minimize( FinTime), update_bound( Schedule, FinTime), fail % Backtrack to find more schedules ; bestsofar( BestSchedule, BestTime). % Final best % precedence_constr( TasksDurs, Schedule, FinTime): % For given tasks and their durations, construct a structure Schedule % comprising start time variables. These variables and finishing time FinTime % are constrained by inequalities due to precedences. precedence_constr( [], [], FinTime). precedence_constr( [T/D | TDs], [T/Proc/Start/D | Rest], FinTime) :- Start >= 0, % Earliest start at 0 Start + D =< FinTime , % Must finish by FinTime precedence_constr( TDs, Rest, FinTime), prec_constr( T/Proc/Start/D, Rest). prec_constr( _, []). prec_constr( T/P/S/D, [T1/P1/S1/D1 | Rest]) :- ( prec( T, T1), !, { S+D =< S1} ; prec( T1, T), !, { S1+D1 =< S} ; true ), prec_constr( T/P/S/D, Rest). % assign_processors( Schedule, FinTime): % Assign processors to tasks in Schedule assign_processors( [], FinTime). assign_processors( [T/P/S/D | Rest], FinTime) :- assign_processors( Rest, FinTime), resource( T, Processors), % T can be executed by any of Processors member( P, Processors), % Choose one of suitable processors resource_constr( T/P/S/D, Rest), % Impose resource constraints bestsofar( _, BestTimeSoFar), { FinTime < BestTimeSoFar }. % New schedule better than best so far % resource_constr( ScheduledTask, TaskList): % Construct constraints to ensure no resource conflict % between ScheduledTask and TaskList resource_constr( _, []). resource_constr( Task, [Task1 | Rest]) :- no_conflict( Task, Task1), resource_constr( Task, Rest). no_conflict( T/P/S/D, T1/P1/S1/D1) :- P \== P1, ! % Different processors ; prec( T, T1), ! % Already constrained ; prec( T1, T), ! % Already constrained ; { S+D =< S1 % Same processor, no time overlap ; S1+D1 =< S}. initialise_bound :- retract(bestsofar(_,_)), fail ; assert( bestsofar( dummy_schedule, 9999)). % Assuming 9999 > any finishing time % update_bound( Schedule, FinTime): % update best schedule and time update_bound( Schedule, FinTime) :- retract( bestsofar( _, _)), !, assert( bestsofar( Schedule, FinTime)). % List of tasks to be scheduled tasks( [t1/4,t2/2,t3/2, t4/20, t5/20, t6/11, t7/11]). % Precedence constraints prec( t1, t4). prec( t1, t5). prec( t2, t4). prec( t2, t5). prec( t2, t6). prec( t3, t5). prec( t3, t6). prec( t3, t7). % resource( Task, Processors): % Any processor in Processors suitable for Task resource( _, [1,2,3]). % Three processors, all suitable for any task