%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % a complex Elevator simulator for golog % written by: Stephan Schiffel % % domain: % elevator that has a capacity of some people (5) % requests to bring people from some floor to specific other one (one request for each person) % each request has a unique id, the number of requests is bounded % elevator may go up or down to some floor, open/close the door and invite people with some request id % elevator remembers its last direction, such that no persons enter that want to go down, if elevator will in fact go up % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% :- ['goflux.pl']. run :- init(Z0),interpret(control,Z0,Z1), term_string(Z1,S), write('final state: '), write(S), nl. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % DECLARATIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Actions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % prim_action(?Action): Action is a primitive action and it can be executed prim_action(invite(_)). % invite person with specific id and clear appropriate request prim_action(open). % Open elevator door -> all persons destined for this floor leave prim_action(close). % Close elevator door. prim_action(up(_)). % Move elevator up to floor X. prim_action(down(_)). % Move elevator down to floor X. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Fluents %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % prim_fluent(?Fluent): Fluent is a primitive fluent % prim_fluent(?Fluent) must fully instantiate Fluent prim_fluent(request(Id, From, To)) :- request_id(Id), floor(From), floor(To). prim_fluent(currentFloor). prim_fluent(capacity). prim_fluent(carries(To)) :- floor(To). prim_fluent(last_direction). prim_fluent(doorClosed). initial_capacity(5). request_id(Id) :- member(Id,[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 , 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 , 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 , 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 , 41, 42, 43, 44, 45, 46, 47, 48, 49, 50 , 51, 52, 53, 54, 55, 56, 57, 58, 59, 60 , 61, 62, 63, 64, 65, 66, 67, 68, 69, 70 , 71, 72, 73, 74, 75, 76, 77, 78, 79, 80 , 81, 82, 83, 84, 85, 86, 87, 88, 89, 90 , 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]). floor(X) :- member(X,[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Effect axioms %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % causes_val(+Action, +Fluent, +Value, +Cond): When Cond holds, doing % Action causes Fluent to have Value causes_val(up(M), currentFloor, M, true). causes_val(down(M), currentFloor, M, true). causes_val(up(_), last_direction, up, true). causes_val(down(_), last_direction, up, true). causes_val(invite(Id), request(Id,From,To), false, request(Id,From,To)=true). causes_val(open, carries(To), 0, currentFloor=To). causes_val(invite(Id), carries(To), M, and(request(Id,From,To),M is carries(To)+1)). causes_val(open, capacity, M, M is capacity+carries(currentFloor)). causes_val(invite(Id), capacity, M, and(capacity=N,M is N-1)). causes_val(open, doorClosed, false, true). causes_val(close, doorClosed, true, true). % Effect axioms transformed to flux state update axioms % and functional fluents transformed to relational fluents % e.g. f(a,b)=v -> f=(v,a,b) % % state_update(Z1,A,Z2): Doing action A in state Z1 results in state Z2 state_update(Z1,up(N),Z3) :- holds(currentFloor(M),Z1), update(Z1,[currentFloor(N)],[currentFloor(M)],Z2), (holds(last_direction(down),Z1) -> update(Z2,[last_direction(up)],[last_direction(down)],Z3) ; Z3=Z2) . state_update(Z1,down(N),Z3) :- holds(currentFloor(M),Z1), update(Z1,[currentFloor(N)],[currentFloor(M)],Z2), (holds(last_direction(up),Z1) -> update(Z2,[last_direction(down)],[last_direction(up)],Z3) ; Z3=Z2) . state_update(Z1,open,Z3) :- holds(currentFloor(Pos),Z1), (holds(capacity(C),Z1), holds(carries(Pos,N),Z1), N>0 -> Cp is C+N, update(Z1,[capacity(Cp), carries(Pos,0)],[capacity(C),carries(Pos,N)],Z2) ; Z2=Z1), update(Z2, [doorClosed(false)], [doorClosed(true)], Z3) . state_update(Z1,invite(Id),Z2) :- holds(currentFloor(Pos),Z1), holds(request(Id, Pos, To, true), Z1), holds(capacity(C),Z1), Cp is C-1, holds(carries(To,N),Z1), Np is N+1, update(Z1,[capacity(Cp), carries(To,Np)],[capacity(C), carries(To,N), request(Id,_,_,true)],Z2) . state_update(Z1,close,Z2) :- update(Z1, [doorClosed(true)], [doorClosed(false)], Z2). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Preconditions of prim actions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % poss(+Action, +Condition): When Condition is true, Action is possible poss(up(N), and(doorClosed,currentFloorN)). poss(open, doorClosed). poss(close, neg(doorClosed)). poss(invite(Id), and(neg(doorClosed),and(capacity>0,some(to,request(Id,currentFloor,to))))). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Initial state %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % initially(+Fluent, +Value): Fluent has Value at S0, the initial situation % There are 100 random requests in the initial situation initially(request(Id,From,To),true) :- member((Id,From,To),[ (1,18,12), (2,16,13), (3,12,9), (4,8,7), (5,14,1), (6,1,14), (7,13,14), (8,6,18), (9,12,1), (10,12,15) , (11,3,14), (12,7,14), (13,16,3), (14,5,2), (15,3,16), (16,13,14), (17,16,1), (18,3,1), (19,5,2), (20,11,7) , (21,1,18), (22,6,2), (23,15,4), (24,10,13), (25,19,10), (26,8,13), (27,6,12), (28,3,11), (29,8,3), (30,16,4) , (31,4,9), (32,12,7), (33,11,3), (34,7,8), (35,14,9), (36,6,11), (37,0,11), (38,12,13), (39,11,1), (40,18,3) , (41,7,6), (42,18,13), (43,19,17), (44,16,4), (45,15,13), (46,6,11), (47,11,12), (48,10,8), (49,10,15), (50,7,4) , (51,10,2), (52,2,0), (53,0,10), (54,6,18), (55,8,2), (56,4,17), (57,2,10), (58,9,10), (59,2,18), (60,13,17) , (61,1,15), (62,6,2), (63,13,2), (64,19,12), (65,8,15), (66,5,16), (67,5,14), (68,1,18), (69,18,14), (70,10,16) , (71,0,11), (72,18,1), (73,16,15), (74,6,11), (75,13,14), (76,9,18), (77,10,9), (78,6,5), (79,3,5), (80,2,9) , (81,2,15), (82,17,1), (83,1,10), (84,4,5), (85,6,18), (86,6,15), (87,2,18), (88,0,16), (89,0,17), (90,11,4) , (91,16,13), (92,17,8), (93,13,15), (94,1,16), (95,11,2), (96,6,10), (97,10,5), (98,1,15), (99,6,7), (100,17,10)]). initially(currentFloor,0). initially(doorClosed, false). initially(last_direction, none). initially(capacity,C) :- initial_capacity(C). initially(carries(To),0) :- floor(To). % -> transformed to flux initial state init(Z0) :- initial_capacity(C), Z0=[currentFloor(0), doorClosed(false), last_direction(none), capacity(C), carries(0,0), carries(1,0), carries(2,0), carries(3,0), carries(4,0), carries(5,0), carries(6,0), carries(7,0), carries(8,0), carries(9,0) , carries(10,0), carries(11,0), carries(12,0), carries(13,0), carries(14,0), carries(15,0), carries(16,0), carries(17,0), carries(18,0), carries(19,0) , request(1,18,12,true), request(2,16,13,true), request(3,12,9,true), request(4,8,7,true), request(5,14,1,true) , request(6,1,14,true),request(7,13,14,true), request(8,6,18,true), request(9,12,1,true), request(10,12,15,true) , request(11,3,14,true), request(12,7,14,true), request(13,16,3,true), request(14,5,2,true), request(15,3,16,true) , request(16,13,14,true), request(17,16,1,true), request(18,3,1,true), request(19,5,2,true), request(20,11,7,true) , request(21,1,18,true), request(22,6,2,true), request(23,15,4,true), request(24,10,13,true), request(25,19,10,true) , request(26,8,13,true), request(27,6,12,true), request(28,3,11,true), request(29,8,3,true), request(30,16,4,true) , request(31,4,9,true), request(32,12,7,true), request(33,11,3,true), request(34,7,8,true), request(35,14,9,true) , request(36,6,11,true), request(37,0,11,true), request(38,12,13,true), request(39,11,1,true), request(40,18,3,true) , request(41,7,6,true), request(42,18,13,true), request(43,19,17,true), request(44,16,4,true), request(45,15,13,true) , request(46,6,11,true), request(47,11,12,true), request(48,10,8,true), request(49,10,15,true), request(50,7,4,true) , request(51,10,2,true), request(52,2,0,true), request(53,0,10,true), request(54,6,18,true), request(55,8,2,true) , request(56,4,17,true), request(57,2,10,true), request(58,9,10,true), request(59,2,18,true), request(60,13,17,true) , request(61,1,15,true), request(62,6,2,true), request(63,13,2,true), request(64,19,12,true), request(65,8,15,true) , request(66,5,16,true), request(67,5,14,true), request(68,1,18,true), request(69,18,14,true), request(70,10,16,true) , request(71,0,11,true), request(72,18,1,true), request(73,16,15,true), request(74,6,11,true), request(75,13,14,true) , request(76,9,18,true), request(77,10,9,true), request(78,6,5,true), request(79,3,5,true), request(80,2,9,true) , request(81,2,15,true), request(82,17,1,true), request(83,1,10,true), request(84,4,5,true), request(85,6,18,true) , request(86,6,15,true), request(87,2,18,true), request(88,0,16,true), request(89,0,17,true), request(90,11,4,true) , request(91,16,13,true), request(92,17,8,true), request(93,13,15,true), request(94,1,16,true), request(95,11,2,true) , request(96,6,10,true), request(97,10,5,true), request(98,1,15,true), request(99,6,7,true), request(100,17,10,true)]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Golog PROGRAM %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Definitions of complex conditions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% proc(nearer(A,B,C), abs(A-C)0)). proc(in_direction(L,D), or(and(L>currentFloor,D=up),and(L0, and(capacity>0, some(id, some(to, request(id, L, to)))))). proc(next_in_direction(F1,D,F2), and( or( and(F2 is F1+1, or(D=none, D=up)), and(F2 is F1-1, or(D=none, D=down)) ), floor(F2) ) ). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Definitions of complex actions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% proc(goFloor(N), ndet(ndet(?(currentFloor=N),up(N)),down(N))). proc(goto_next_floor(F,D), if(something_to_do_at(F), [close,goFloor(F),open], pi(next_floor,[?(next_in_direction(F, D, next_floor)), goto_next_floor(next_floor,D)]) ) ). proc(goto_next_floor(D), pi(next_floor,[ ?(next_in_direction(currentFloor, D, next_floor)), goto_next_floor(next_floor,D) ]) ). proc(invite_someone(D), pi(id,[ ?(and(capacity>0,some(to,and(request(id,currentFloor,to), in_direction(to,D) )))), invite(id) ])). proc(serve, search( pi(next_direction,[ if(carries_something, [?(and(carries(F)>0, in_direction(F,next_direction)))], if(last_direction=none, ndet(?(next_direction=up),?(next_direction=down)), ndet( ?(next_direction=last_direction), if(last_direction=up,?(next_direction=down),?(next_direction=up)) ) ) ), ndet( invite_someone(next_direction), goto_next_floor(next_direction) ) ]) ) ). proc(park, if(currentFloor=0, [], [close, down(0), open])). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Main Routine %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /* control is the main loop. So long as there is an active request it serves one. When all buttons are off, it parks the elevator. */ proc(control, [while(or(exists_request, carries_something), serve), park]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % predicates called by the interpreter %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % initialize: Perform any application dependent initialization initialize :- true. % finalize: Application dependent wrap-up finalize :- true. % execute_golog(+Action, +History, -SensingResult): Execute Action returning % SensingResult. Current action History is supplied for debugging % purposes in case something goes wrong % % this is called by the Golog interpreter, original name was just "execute", % but that name exists already in the Flux kernel, therefore you have to rename % it in your Golog interpreter execute_golog(Action, _, []) :- write('Executing action: '), write(Action), nl. % called by the Flux kernel on execution of Action perform(Action) :- execute_golog(Action,_,_). % used by the Golog interpreter to check for exogenous actions exog_occurs([]). % no exogenous actions