about summary refs log blame commit diff stats
path: root/picat/planner.pi
blob: 8cca7b21fba65878218dd7f8530146b99ca89b63 (plain) (tree)































































































































































































































































































































                                                                                                                 
 module planner.

% best_plan(S,Limit,Plan) => best_plan(S,Limit,Plan).
% best_plan(S,Limit,Plan,PlanCost) => best_plan(S,Limit,Plan,PlanCost).
% best_plan(S,Plan,PlanCost) => best_plan(S,Plan,PlanCost).
% best_plan(S,Plan) => best_plan(S,Plan).
% best_plan_bin(S,Limit,Plan) => best_plan_bin(S,Limit,Plan).
% best_plan_bin(S,Limit,Plan,PlanCost) => best_plan_bin(S,Limit,Plan,PlanCost).
% best_plan_bin(S,Plan,PlanCost) => best_plan_bin(S,Plan,PlanCost).
% best_plan_bin(S,Plan) => best_plan_bin(S,Plan).
% best_plan_bb(S,Limit,Plan) => best_plan_bb(S,Limit,Plan).
% best_plan_bb(S,Plan,PlanCost) => best_plan_bb(S,Plan,PlanCost).
% best_plan_bb(S,Limit,Plan,PlanCost) => best_plan_bb(S,Limit,Plan,PlanCost).
% best_plan_bb(S,Plan) => best_plan_bb(S,Plan).
% best_plan_nondet(S,Limit,Plan) => best_plan_nondet(S,Limit,Plan).
% best_plan_nondet(S,Plan,PlanCost) => best_plan_nondet(S,Plan,PlanCost).
% best_plan_nondet(S,Limit,Plan,PlanCost) => best_plan_nondet(S,Limit,Plan,PlanCost).
% best_plan_nondet(S,Plan) => best_plan_nondet(S,Plan).
% best_plan_unbounded(S,Limit,Plan) => best_plan_unbounded(S,Limit,Plan).
% best_plan_unbounded(S,Plan,PlanCost) => best_plan_unbounded(S,Plan,PlanCost).
% best_plan_unbounded(S,Limit,Plan,PlanCost) => best_plan_unbounded(S,Limit,Plan,PlanCost).
% best_plan_unbounded(S,Plan) => best_plan_unbounded(S,Plan).
% current_plan() = current_plan().
% current_resource() = current_resource().
% current_resource_plan(Amount,Plan) => current_resource_plan(Amount,Plan).
% current_resource_plan_cost(Amount,Plan,Cost) => current_resource_plan_cost(Amount,Plan,Cost).
% insert_state_list(StateL,Elm) = insert_state_list(StateL,Elm).
% is_tabled_state(S) => is_tabled_state(S).
% new_state_list(List) = new_state_list(List).
% plan(S,Limit,Plan) => plan(S,Limit,Plan).
% plan(S,Plan,PlanCost) => plan(S,Plan,PlanCost).
% plan(S,Limit,Plan,PlanCost) => plan(S,Limit,Plan,PlanCost).
% plan(S,Plan) => plan(S,Plan).
% plan_unbounded(S,Limit,Plan) => plan_unbounded(S,Limit,Plan).
% plan_unbounded(S,Plan,PlanCost) => plan_unbounded(S,Plan,PlanCost).
% plan_unbounded(S,Limit,Plan,PlanCost) => plan_unbounded(S,Limit,Plan,PlanCost).
% plan_unbounded(S,Plan) => plan_unbounded(S,Plan).

% A state-list is an ordered list, where the ordering of symbols is determined 
% by the addresses of the symbols in the symbol table, not by the characters that
% constitute the symbols. This ordering allows for efficient ordering of symbols. 
% Note that this ordering is different from lexicographical ordering, which is used by sort(). 

new_state_list(List) = SList => new_state_list_aux(List,[],SList).

new_state_list_aux([],SList0,SList) => SList = SList0.
new_state_list_aux([E|List],SList0,SList) => 
    bp.b_INSERT_STATE_LIST_ccf(SList0,E,SList1),
    new_state_list_aux(List,SList1,SList).

insert_state_list(SList0, Elm) = SList => bp.b_INSERT_STATE_LIST_ccf(SList0,Elm,SList).

%%%
current_resource() = Amount =>
    bp.b_PLANNER_CURR_RPC_fff(Amount,_Plan,_Cost).

current_plan() = Plan =>
    bp.b_PLANNER_CURR_RPC_fff(_Amount,Plan,_Cost).

current_resource_plan(Amount,Plan) =>
    bp.b_PLANNER_CURR_RPC_fff(Amount,Plan,_Cost).

current_resource_plan_cost(Amount,Plan,Cost) =>
    bp.b_PLANNER_CURR_RPC_fff(Amount,Plan,Cost).

%%%
plan(S,Plan), var(Plan) =>
    bp.picat_plan(S,268435455,Plan,_).    % the limit is assumed to be 268435455
plan(_S,Plan) =>
    throw_plan_arg_error(1,Plan,_,plan).

plan(S,Limit,Plan), var(Plan), integer(Limit), Limit >= 0 =>
    bp.picat_plan(S,Limit,Plan,_). 
plan(S,Plan,PlanCost), var(Plan), var(PlanCost) =>
    bp.picat_plan(S,268435455,Plan,PlanCost). 
plan(_S,Limit,Plan) =>
    throw_plan_arg_error(Limit,Plan,_,plan).

plan(S,Limit,Plan,PlanCost), var(Plan), var(PlanCost), integer(Limit), Limit >= 0 =>
    bp.picat_plan(S,Limit,Plan,PlanCost). 
plan(_S,Limit,Plan,PlanCost) =>
    throw_plan_arg_error(Limit,Plan,PlanCost,plan).

plan(S,Limit,Plan,PlanCost,FinS), var(Plan), var(PlanCost), integer(Limit), Limit >= 0 =>
    bp.picat_plan(S,Limit,Plan,PlanCost,FinS). 
plan(_S,Limit,Plan,PlanCost,_FinS) =>
    throw_plan_arg_error(Limit,Plan,PlanCost,plan).

%%%
plan_unbounded(S,Plan), var(Plan) =>
    bp.picat_plan_unbounded(S,268435455,Plan,_).    % the limit is assumed to be 268435455
plan_unbounded(_S,Plan) =>
    throw_plan_arg_error(1,Plan,_,plan_unbounded).

plan_unbounded(S,Limit,Plan), var(Plan), integer(Limit), Limit >= 0 =>
    bp.picat_plan_unbounded(S,Limit,Plan,_). 
plan_unbounded(S,Plan,PlanCost), var(Plan), var(PlanCost) =>
    bp.picat_plan_unbounded(S,268435455,Plan,PlanCost). 
plan_unbounded(_S,Limit,Plan) =>
    throw_plan_arg_error(Limit,Plan,_,plan_unbounded).

plan_unbounded(S,Limit,Plan,PlanCost), var(Plan), var(PlanCost), integer(Limit), Limit >= 0 =>
    bp.picat_plan_unbounded(S,Limit,Plan,PlanCost). 
plan_unbounded(_S,Limit,Plan,PlanCost) =>
    throw_plan_arg_error(Limit,Plan,PlanCost,plan_unbounded).


%%%
%%% iterative deepening
best_plan(S,Plan), var(Plan) =>
    best_plan_downward(S,0,268435455,Plan,_,_).
best_plan(_S,Plan) =>
    throw_plan_arg_error(1,Plan,_,best_plan).

best_plan(S,Limit,Plan), var(Plan), integer(Limit), Limit >= 0 =>
    best_plan_downward(S,0,Limit,Plan,_,_).
best_plan(S,Plan,PlanCost), var(Plan), var(PlanCost) =>
    best_plan_downward(S,0,268435455,Plan,PlanCost,_).
best_plan(_S,Limit,Plan) =>
    throw_plan_arg_error(Limit,Plan,_,best_plan).

best_plan(S,Limit,Plan,PlanCost), var(Plan), var(PlanCost), integer(Limit), Limit >= 0 =>
    best_plan_downward(S,0,Limit,Plan,PlanCost,_).
best_plan(_S,Limit,Plan,PlanCost) =>
    throw_plan_arg_error(Limit,Plan,PlanCost,best_plan).

best_plan(S,Limit,Plan,PlanCost,FinS), var(Plan), var(PlanCost), integer(Limit), Limit >= 0 =>
    best_plan_downward(S,0,Limit,Plan,PlanCost,FinS).
best_plan(_S,Limit,Plan,PlanCost,_FinS) =>
    throw_plan_arg_error(Limit,Plan,PlanCost,best_plan).

%%%
best_plan_downward(S,Level,_Limit,_Plan,_PlanCost,_FinS) ?=>
    (bp.global_get('_$picat_log',0, 1) -> printf("%% Searching with the bound %d\n",Level); true),
    call_picat_plan(S,Level),
    fail.
best_plan_downward(S,_Level,_Limit,Plan,PlanCost,FinS),
    Map = get_table_map('_$planner'),
    Map.has_key($current_best_plan(S))
 =>
    Map.get($current_best_plan(S)) = Plan,
    Map.get($current_best_plan_cost(S)) = PlanCost,
    Map.get($current_best_plan_fin_state(S)) = FinS.
best_plan_downward(S,Level,Limit,Plan,PlanCost,FinS) =>
    bp.global_get('_$planner_explored_depth',0,Depth),
    (Depth == 268435455 -> Level1 = Level+1; Level1 = Depth),
    Level1 =< Limit,
    best_plan_downward(S,Level1,Limit,Plan,PlanCost,FinS).

%%% iterative deeping and binary search
best_plan_bin(S,Plan), var(Plan) =>
    best_plan_downward_bin(S,0,268435455,Plan,_,_).
best_plan_bin(_S,Plan) =>
    throw_plan_arg_error(1,Plan,_,best_plan).

best_plan_bin(S,Limit,Plan), var(Plan), integer(Limit), Limit >= 0 =>
    best_plan_downward_bin(S,0,Limit,Plan,_,_).
best_plan_bin(S,Plan,PlanCost), var(Plan), var(PlanCost) =>
    best_plan_downward_bin(S,0,268435455,Plan,PlanCost,_).
best_plan_bin(_S,Limit,Plan) =>
    throw_plan_arg_error(Limit,Plan,_,best_plan).

best_plan_bin(S,Limit,Plan,PlanCost), var(Plan), var(PlanCost), integer(Limit), Limit >= 0 =>
    best_plan_downward_bin(S,0,Limit,Plan,PlanCost,_).
best_plan_bin(_S,Limit,Plan,PlanCost) =>
    throw_plan_arg_error(Limit,Plan,PlanCost,best_plan).

best_plan_bin(S,Limit,Plan,PlanCost,FinS), var(Plan), var(PlanCost), integer(Limit), Limit >= 0 =>
    best_plan_downward_bin(S,0,Limit,Plan,PlanCost,FinS).
best_plan_bin(_S,Limit,Plan,PlanCost,_FinS) =>
    throw_plan_arg_error(Limit,Plan,PlanCost,best_plan).

%%%
best_plan_downward_bin(S,Level,Limit,Plan,PlanCost,FinS) =>
    Map = get_table_map('_$planner'),
    loop_best_plan_downward_bin(S,Level,Limit,Plan,PlanCost,FinS,Map).

loop_best_plan_downward_bin(S,Level,Limit,_Plan,_PlanCost,_FinS,_Map) ?=>
    Level =< Limit,
    (bp.global_get('_$picat_log',0, 1) -> printf("%% Searching with the bound %d\n",Level); true),
    call_picat_plan(S,Level),
    fail.
loop_best_plan_downward_bin(S,_Level,_Limit,Plan,PlanCost,_FinS,Map),
    Map.has_key($current_best_plan(S))
 =>
    Lower = Map.get($current_lower_bound(S), 0),
    Upper = Map.get($current_best_plan_cost(S))-1,
    loop_best_plan_bin(S,Map,Lower,Upper,Plan,PlanCost).
loop_best_plan_downward_bin(S,Level,Limit,Plan,PlanCost,FinS,Map) =>
    bp.global_get('_$planner_explored_depth',0,Depth),
%    writeln(depth=Depth),
    (Depth == 268435455 -> Lower = Level+1; Lower = Depth),
    Map.put($current_lower_bound(S), Lower),
    Lower < Limit,
    Level1 = 2*Lower,
    NewLevel = cond(Level1 > Limit, Limit, Level1),
    loop_best_plan_downward_bin(S,NewLevel,Limit,Plan,PlanCost,FinS,Map).

% binary search
loop_best_plan_bin(S,Map,Lower,Upper,Plan,PlanCost),
    Lower =< Upper
 =>
    NewLimit = Lower + (Upper-Lower) div 2,
    (bp.global_get('_$picat_log',0, 1) -> printf("%% Searching with the bound %d\n",NewLimit); true),
    if call_picat_plan(S,NewLimit) then
        NewUpper = Map.get($current_best_plan_cost(S))-1,
        loop_best_plan_bin(S,Map,Lower,NewUpper,Plan,PlanCost)
    else
        NewLower = NewLimit+1,
        loop_best_plan_bin(S,Map,NewLower,Upper,Plan,PlanCost)
    end.
loop_best_plan_bin(S,Map,_Lower,_Upper,Plan,PlanCost) =>
    Map.has_key($current_best_plan(S)),
    Map.get($current_best_plan(S)) = Plan,
    Map.get($current_best_plan_cost(S)) = PlanCost.

%%%
best_plan_nondet(S,Plan), var(Plan) =>
    best_plan_nondet_aux(S,268435455,Plan,_).
best_plan_nondet(_S,Plan) =>
    throw_plan_arg_error(1,Plan,_,best_plan_nondet).

best_plan_nondet(S,Limit,Plan), var(Plan), integer(Limit), Limit >= 0 =>
    best_plan_nondet_aux(S,Limit,Plan,_).
best_plan_nondet(S,Plan,PlanCost), var(Plan), var(PlanCost) =>
    best_plan_nondet_aux(S,268435455,Plan,PlanCost).
best_plan_nondet(_S,Limit,Plan) =>
    throw_plan_arg_error(Limit,Plan,_,best_plan_nondet).

best_plan_nondet(S,Limit,Plan,PlanCost), var(Plan), var(PlanCost), integer(Limit), Limit >= 0 =>
    best_plan_nondet_aux(S,Limit,Plan,PlanCost).
best_plan_nondet(_S,Limit,Plan,PlanCost) =>
    throw_plan_arg_error(Limit,Plan,PlanCost,best_plan_nondet).

best_plan_nondet_aux(S,Limit,Plan,PlanCost) =>
    not not (M = get_global_map(),
             M.put('_first_best_plan',[]),
             best_plan_downward(S,0,Limit,Plan0,PlanCost0,_),     % use tabled search to find the first best plan
             M.put('_first_best_plan', (Plan0,PlanCost0))),
    get_global_map().get('_first_best_plan') = (Plan0,PlanCost),
    (    Plan = Plan0
    ;
        bp.picat_best_plan_nondet_nontabled_search(S,Plan,PlanCost),
        Plan0 != Plan
    ).

%%% Branch-and-Bound
best_plan_bb(S,Plan), var(Plan) =>
    loop_best_plan_bb(S,268435455,Plan,_).
best_plan_bb(_S,Plan) =>
    throw_plan_arg_error(1,Plan,_,best_plan_bb).

best_plan_bb(S,Limit,Plan), var(Plan), integer(Limit), Limit >= 0 =>
    loop_best_plan_bb(S,Limit,Plan,_PlanCost).
best_plan_bb(S,Plan,PlanCost), var(Plan), var(PlanCost) =>
    loop_best_plan_bb(S,268435455,Plan,PlanCost).
best_plan_bb(_S,Limit,Plan) =>
    throw_plan_arg_error(Limit,Plan,_,best_plan_bb).

best_plan_bb(S,Limit,Plan,PlanCost), var(Plan), var(PlanCost), integer(Limit), Limit >= 0 =>
    loop_best_plan_bb(S,Limit,Plan,PlanCost).
best_plan_bb(_S,Limit,Plan,PlanCost) =>
    throw_plan_arg_error(Limit,Plan,PlanCost,best_plan_bb).

loop_best_plan_bb(S,Limit,Plan,PlanCost),
    (bp.global_get('_$picat_log',0, 1) -> printf("%% Searching with the bound %d\n",Limit); true),
    call_picat_plan(S,Limit)        
 =>
    get_table_map('_$planner').get($current_best_plan_cost(S)) = PlanCost1,    
    loop_best_plan_bb(S,PlanCost1-1,Plan,PlanCost).
loop_best_plan_bb(S,_Limit,Plan,PlanCost) =>
    Map = get_table_map('_$planner'),
    Map.has_key($current_best_plan(S)),
    Map.get($current_best_plan(S)) = Plan,
    Map.get($current_best_plan_cost(S)) = PlanCost.

call_picat_plan(S,Limit) =>
    bp.global_set('_$planner_explored_depth',0,268435455),
    not not call_picat_plan_aux(S,Limit).   % discard exception catchers created by picat_plan

call_picat_plan_aux(S,Limit) =>
    bp.picat_plan(S,Limit,Plan,PlanCost,FinS),
    Map = get_table_map('_$planner'),
    Map.put($current_best_plan(S), Plan),
    Map.put($current_best_plan_cost(S), PlanCost),
    Map.put($current_best_plan_fin_state(S), FinS).

%%%
best_plan_unbounded(S,Plan), var(Plan) =>
    bp.picat_best_plan_unbounded(S,Plan,_).
best_plan_unbounded(_S,Plan) =>
    throw_plan_arg_error(1,Plan,_,best_plan_unbounded).

best_plan_unbounded(S,Limit,Plan), var(Plan), integer(Limit), Limit >= 0 =>
    bp.picat_best_plan_unbounded(S,Plan,PlanCost),
    PlanCost =< Limit.
best_plan_unbounded(S,Plan,PlanCost), var(Plan), var(PlanCost) =>
    bp.picat_best_plan_unbounded(S,Plan,PlanCost).
best_plan_unbounded(_S,Limit,Plan) =>
    throw_plan_arg_error(Limit,Plan,_,best_plan_unbounded).    

best_plan_unbounded(S,Limit,Plan,PlanCost), var(Plan), var(PlanCost), integer(Limit), Limit >= 0 =>
    bp.picat_best_plan_unbounded(S,Plan,PlanCost),
    PlanCost =< Limit.
best_plan_unbounded(_S,Limit,Plan,PlanCost) =>
    throw_plan_arg_error(Limit,Plan,PlanCost,best_plan_unbounded).    

%%%
is_tabled_state(S) =>
    bp.b_IS_PLANNER_STATE_c(S).

throw_plan_arg_error(_Limit,Plan,_PlanCost,Source), nonvar(Plan) =>
    handle_exception($var_expected(Plan), Source).
throw_plan_arg_error(_Limit,_Plan,PlanCost,Source), nonvar(PlanCost) =>
    handle_exception($var_expected(PlanCost), Source).
throw_plan_arg_error(Limit,_Plan,_PlanCost,Source), integer(Limit) =>
    handle_exception($nonnegative_integer_expected(Limit), Source).
throw_plan_arg_error(Limit,_Plan,_PlanCost,Source) =>
    handle_exception($integer_expected(Limit), Source).