anchor.diff:  -export([test/0]).
   
   %%------------------------------------------------------------------------------
  -%% This transformation module transforms wheredim identifiers into hidden 
  -%% dimensions (e.g: t -> {dim, t}) and references to these identifiers as 
  -%% constant queries to the context ({'?', {dim, t}}).
  +%% This transformation module transforms wheredim identifiers into hidden
  +%% dimensions (e.g: t -> {dim, {Pos,Idx}, t}) and references to these
  +%% identifiers to references to the hidden dimensions (e.g: t ->
  +%% {dim, {Pos,Idx}, t}).
   %%
  -%% Transformed expressions are wheredim, wherevar, intension abstractions, 
  +%% Transformed expressions are wheredim, wherevar, intension abstractions,
   %% intension applications, base and value abstractions / applications.
   %%------------------------------------------------------------------------------
   
  +transform1(E) ->
  +  transform1(E, root_expr_pos(), []).
  +
   %%------------------------------------------------------------------------------
   %% Constants
   %%------------------------------------------------------------------------------
  -transform1(Const, _H) when is_number(Const) orelse is_boolean(Const) ->
  +transform1(Const, _P, _H) when is_number(Const) orelse is_boolean(Const) ->
     Const;
   
  -transform1({string, Str}, _H) ->
  +transform1({string, Str}, _P, _H) ->
     {string, Str};
   
   %%------------------------------------------------------------------------------
   %% Primop
   %%------------------------------------------------------------------------------
  -transform1({primop, F, Eis}, H) ->
  -  {primop, F, lists:map(fun (Ei) -> transform1(Ei, H) end, Eis)};
  +transform1({primop, F, Eis}, P, H) ->
  +  Ns = lists:seq(1, length(Eis)), %% 1,2,...
  +  NewEis =
  +    lists:map(
  +      fun({Ei, N}) ->
  +          transform1(Ei, subexpr_pos(N,P), H) %% Pos 1,2,...
  +      end,
  +      lists:zip(Eis, Ns)),
  +  {primop, F, NewEis};
   
   %%------------------------------------------------------------------------------
   %% Tuple Expression
   %%------------------------------------------------------------------------------
  -transform1({t, E0E1is}, H) ->
  -  {t, lists:map(fun ({E0,E1}) -> {transform1(E0,H),transform1(E1,H)} end, E0E1is)};
  +transform1({t, E0E1is}, P, H) ->
  +  Ns = lists:seq(1, length(E0E1is)), %% 1,2,...
  +  NewE0E1is =
  +    lists:map(
  +      fun({{E0,E1}, N}) ->
  +          {transform1(E0, subexpr_pos(N*2  ,P), H), %% Pos 2,4,...
  +           transform1(E1, subexpr_pos(N*2+1,P), H)} %% Pos 3,5,...
  +      end,
  +      lists:zip(E0E1is, Ns)),
  +  {t, NewE0E1is};
   
   %%------------------------------------------------------------------------------
   %% Context Perturbation
   %%------------------------------------------------------------------------------
  -transform1({'@', E0, E1}, H) ->
  -  {'@', transform1(E0, H), transform1(E1, H)};
  +transform1({'@', E0, E1}, P, H) ->
  +  {'@',
  +   transform1(E0, subexpr_pos(0,P), H),
  +   transform1(E1, subexpr_pos(1,P), H)};
   
   %%------------------------------------------------------------------------------
   %% Conditional
   %%------------------------------------------------------------------------------
  -transform1({'if', E0, E1, E2}, H) ->
  -  {'if', transform1(E0, H), transform1(E1, H), transform1(E2, H)};
  +transform1({'if', E0, E1, E2}, P, H) ->
  +  {'if',
  +   transform1(E0, subexpr_pos(0,P), H),
  +   transform1(E1, subexpr_pos(1,P), H),
  +   transform1(E2, subexpr_pos(2,P), H)};
   
   %%------------------------------------------------------------------------------
   %% Dimensional Query
   %%------------------------------------------------------------------------------
  -transform1({'#', E0}, H) ->
  -  {'#', transform1(E0, H)};
  -
  -%%------------------------------------------------------------------------------
  -%% Base Abstraction
  -%%------------------------------------------------------------------------------
  -transform1({b_abs, Is, Params, E, P}, H) ->
  -  Dims = [{dim, Param} || Param <- Params],
  -  %% Here we expect P to be a runtime assigned constant
  -  {b_abs, tset:union(H, [transform1(I, H) || I <- Is]),
  -   Dims,
  -   transform1(E, tset:union(H, Dims)),
  -   P};
  -
  -transform1({b_apply, E0, E1}, H) ->
  -  {b_apply, transform1(E0, H), transform1(E1, H)};
  -
  -%%------------------------------------------------------------------------------
  -%% Value Abstraction
  -%%------------------------------------------------------------------------------
  -transform1({v_abs, Is, Params, E}, H) ->
  -  Dims = [{dim, Param} || Param <- Params],
  -  {v_abs, tset:union(H, [transform1(I, H) || I <- Is]),
  -   Dims,
  -   transform1(E, tset:union(H, Dims))};
  -
  -transform1({v_apply, E0, E1}, H) ->
  -  {v_apply, transform1(E0, H), transform1(E1, H)};
  -
  -%%------------------------------------------------------------------------------
  -%% Intension Abstraction
  -%%------------------------------------------------------------------------------
  -transform1({i_abs, Is, E}, H) ->
  -  {i_abs, tset:union(H, [transform1(I, H) || I <- Is]),
  -   transform1(E, H)};
  -
  -transform1({i_apply, E}, H) ->
  -  {i_apply, transform1(E, H)};
  +transform1({'#', E0}, P, H) ->
  +  {'#', transform1(E0, P, H)};
  +
  +%% %%------------------------------------------------------------------------------
  +%% %% Base Abstraction
  +%% %%------------------------------------------------------------------------------
  +%% %% TODO
  +%% transform1({b_abs, Is, Params, E, P}, H) ->
  +%%   Dims = [{dim, Param} || Param <- Params],
  +%%   %% Here we expect P to be a runtime assigned constant
  +%%   {b_abs, tset:union(H, [transform1(I, H) || I <- Is]),
  +%%    Dims,
  +%%    transform1(E, tset:union(H, Dims)),
  +%%    P};
  +
  +%% transform1({b_apply, E0, E1}, H) ->
  +%%   {b_apply, transform1(E0, H), transform1(E1, H)};
  +
  +%% %%------------------------------------------------------------------------------
  +%% %% Value Abstraction
  +%% %%------------------------------------------------------------------------------
  +%% %% TODO
  +%% transform1({v_abs, Is, Params, E}, H) ->
  +%%   Dims = [{dim, Param} || Param <- Params],
  +%%   {v_abs, tset:union(H, [transform1(I, H) || I <- Is]),
  +%%    Dims,
  +%%    transform1(E, tset:union(H, Dims))};
  +
  +%% transform1({v_apply, E0, E1}, H) ->
  +%%   {v_apply, transform1(E0, H), transform1(E1, H)};
  +
  +%% %%------------------------------------------------------------------------------
  +%% %% Intension Abstraction
  +%% %%------------------------------------------------------------------------------
  +%% transform1({i_abs, Is, E}, H) ->
  +%%   {i_abs, tset:union(H, [transform1(I, H) || I <- Is]),
  +%%    transform1(E, H)};
  +
  +%% transform1({i_apply, E}, H) ->
  +%%   {i_apply, transform1(E, H)};
   
   %%------------------------------------------------------------------------------
   %% Wherevar
   %%------------------------------------------------------------------------------
  -transform1({wherevar, E0, XiEis}, H) ->
  -  {wherevar, transform1(E0, H),
  -   [{Xi, transform1(Ei, H)} || {Xi, Ei} <- XiEis]};
  +transform1({wherevar, E0, XiEis}, P, H) ->
  +  Ns = lists:seq(1, length(XiEis)), %% 1,2,...
  +  NewXiEis =
  +    [{Xi, transform1(Ei, subexpr_pos(N,P), H)} %% Pos 1,2,...
  +     || {{Xi, Ei}, N} <- lists:zip(XiEis, Ns)],
  +  {wherevar, transform1(E0, subexpr_pos(0,P), H),
  +   NewXiEis};
   
   %%------------------------------------------------------------------------------
   %% Wheredim
   %%------------------------------------------------------------------------------
  -transform1({wheredim, E0, XiEis}, H) ->
  -  DimsEis = [{{dim, Xi}, transform1(Ei, H)} || {Xi, Ei} <- XiEis],
  +transform1({wheredim, E0, XiEis}, P, H) ->
  +  Ns = lists:seq(1, length(XiEis)),
  +  DimsEis =
  +    [{ {dim, hidden_dim(N,P), Xi},
  +       transform1(Ei, subexpr_pos(N,P), H) }
  +     || {{Xi, Ei}, N} <- lists:zip(XiEis, Ns)],
     Dims = [Dim || {Dim, _} <- DimsEis],
  -  {wheredim, transform1(E0, tset:union(H, Dims)),
  +  HWoShadowedDims = %% e.g. nested wheredims with same local dim identifier
  +    lists:filter(fun({dim, _, Xi}) -> not lists:keymember(Xi, 3, Dims) end, H),
  +  NewE0 = transform1(E0, subexpr_pos(0,P), tset:union(HWoShadowedDims, Dims)),
  +  {wheredim, NewE0,
      DimsEis};
   
   %%------------------------------------------------------------------------------
   %% Identifiers
   %%------------------------------------------------------------------------------
  -transform1(Xi, H) when is_list(Xi) orelse is_atom(Xi) ->
  -  case lists:keyfind(Xi, 2, H) of
  -    {dim, Xi} ->
  -      {'?', {dim, Xi}};
  -    _ ->
  +%% FIXME Not distinguishing between variable identifier and "dimension
  +%% identifier" leads to variable identifiers with same name of hidden
  +%% dimension being replaced with {dim,...}
  +transform1(Xi, _P, H) when is_list(Xi) orelse is_atom(Xi) ->
  +  case lists:keyfind(Xi, 3, H) of
  +    {dim, _, Xi} = DimXi ->
  +      DimXi;
  +    false ->
         Xi
     end.
  +
  +%%-------------------------------------------------------------------------------------
  +%% Internal - Deterministic generation of hidden dimensions using
  +%% position of expression in evaluation tree
  +%%-------------------------------------------------------------------------------------
  +-type n() :: non_neg_integer().
  +-type pos() :: [n()].
  +
  +-type index() :: pos_integer().
  +-type hidden_dim() :: {pos(), index()}.
  +
  +%%-------------------------------------------------------------------------------------
  +%% @doc Return position of the root expression in the evaluation tree.
  +%% @private
  +%%-------------------------------------------------------------------------------------
  +-spec root_expr_pos() -> RootP :: pos().
  +root_expr_pos() ->
  +  [].
  +
  +%%-------------------------------------------------------------------------------------
  +%% @doc Return position of subexpression N while in position P.
  +%% @private
  +%%-------------------------------------------------------------------------------------
  +-spec subexpr_pos(N :: n(), P :: pos()) -> SubP :: pos().
  +subexpr_pos(N, P) ->
  +  [N | P].
  +
  +%%-------------------------------------------------------------------------------------
  +%% @doc Return I-th hidden dimension in position P.
  +%% @private
  +%%-------------------------------------------------------------------------------------
  +-spec hidden_dim(I :: index(), P :: pos()) -> HD :: hidden_dim().
  +hidden_dim(I, P) ->
  +  {P, I}.
  +
   
   %%------------------------------------------------------------------------------
   %% Insta-test
  
positive.code: 
  test() ->
    R = ttransform0:transform0(d1_tournament()),
    transform1(R, []).
  
  
  nested_wheredims_test() ->
  
negative.code:   Expected =
      {wheredim,
       {wheredim,
        {'#',{dim,{[0],1},"t"}},
        [ {{dim,{[0],1},"t"},58} ]},
       [ {{dim,{[],1},"t"},46} ]},
    ?assertEqual(Expected, transform1(R)).
  
  wheredim_with_string_dim_id_test() ->
    T =
      {where,
       "t",
       [{dim,"t",46},{var,"t",58}]},
    R = ttransform0:transform0(T),
    Expected =
      {wheredim,
       {wherevar,
        {dim,{[],1},"t"}, %% FIXME var id shall not be replaced
        [ {"t",58} ]},
       [ {{dim,{[],1},"t"},46} ]},
    ?assertEqual(Expected, transform1(R)).
  