
/* Implementation of a sparse tree of Multidimensional matrix elements.
*/

10 # SparseTreeGet({},_tree) <-- tree;
20 # SparseTreeGet(_key,_tree) <--
[
  SparseTreeGet2(Tail(key),Assoc(Head(key),tree));
];
10 # SparseTreeGet2(_key,Empty) <-- 0;
20 # SparseTreeGet2(_key,_item) <-- SparseTreeGet(key,Head(Tail(item)));

10 # SparseTreeSet({_i},_tree,_newvalue)
   <--
[
  Local(Current,assoc,result);
  Set(assoc,Assoc(i,tree));
  if(assoc=Empty)
  [
    Set(Current,0);
    Set(result,Eval(newvalue));
    AddSparseTrees(1,tree,CreateSparseTree({i},result));
  ]
  else
  [
    Set(Current,assoc[2]);
    Set(result,Eval(newvalue));
    assoc[2] := result;
  ];
  result;
];
20 # SparseTreeSet(_key,_tree,_newvalue) <--
[
  SparseTreeSet2(Tail(key),Assoc(Head(key),tree));
];
10 # SparseTreeSet2(_key,Empty) <-- 0;
20 # SparseTreeSet2(_key,_item)
   <-- SparseTreeSet(key,Head(Tail(item)),newvalue);
UnFence("SparseTreeSet",3);
UnFence("SparseTreeSet2",2);


LocalSymbols(SparseTreeMap2,SparseTreeScan2,Muaddterm,MuMuaddterm,
              meradd,meraddmap) [

10 # CreateSparseTree({},_fact) <-- fact;

20 # CreateSparseTree(_coefs,_fact) 
    <-- CreateSparseTree(Head(coefs),Tail(coefs),fact);
10 # CreateSparseTree(_first,{},_fact) <-- {{first,fact}};
20 # CreateSparseTree(_first,_coefs,_fact)
    <-- {{first,CreateSparseTree(Head(coefs),Tail(coefs),fact)}};

10 # SparseTreeMap(_op,_depth,_list) <-- SparseTreeMap2(list,depth,{});
10 # SparseTreeMap2(_list,1,_coefs)  
   <-- 
   ForEach(item,list)
   [
     item[2] := ApplyPure(op,{Concat(coefs,{item[1]}),item[2]});
   ];
20 # SparseTreeMap2(_list,_depth,_coefs) 
   <--
   ForEach(item,list)
   [
     SparseTreeMap2(item[2],MathAdd(depth,-1),Concat(coefs,{item[1]}));
   ];
UnFence("SparseTreeMap", 3);
[Local(fn);fn:=String(SparseTreeMap2);`UnFence(@fn,3);];

10 # SparseTreeScan(_op,_depth,_list) <-- SparseTreeScan2(list,depth,{});
10 # SparseTreeScan2(_list,0,_coefs)  <-- ApplyPure(op,{coefs,list});
20 # SparseTreeScan2(_list,_depth,_coefs) 
   <--
   ForEach(item,list)
   [
     SparseTreeScan2(item[2],MathAdd(depth,-1),Concat(coefs,{item[1]}));
   ];
UnFence("SparseTreeScan", 3);
[Local(fn);fn:=String(SparseTreeScan2);`UnFence(@fn,3);];



5  # AddSparseTrees(0,_x,_y) <-- x+y;
10 # AddSparseTrees(_depth,_x,_y) <-- 
[
  Local(i,t1,t2,inspt);
  Set(t1,x);
  Set(i,1);
  Set(t2,y);
  Set(inspt,{});
  While(t1 != {} And t2 != {})
  [
    Muaddterm(Head(t1),Head(t2));
  ];  
  While(t2 != {})
  [
    Set(x,DestructiveAppend(x,Head(t2)));
    Set(t2,Tail(t2));
  ];  
  While(inspt != {})
  [
    Set(i,Head(inspt));
    Set(x,DestructiveInsert(x,i[2],i[1]));
    Set(inspt,Tail(inspt));
  ];
  x;
];

10 # Muaddterm({_pow,_list1},{_pow,_list2}) <--
[
  if(depth=1)
    [ t1[1][2] := list1+list2; ]
  else
    [ t1[1][2] := AddSparseTrees(MathAdd(depth,-1),list1,list2);];
  Set(t2,Tail(t2));
];
20 # Muaddterm(_h1,_h2)_(h1[1]<h2[1]) <--
[
  Set(inspt,{h2,i}:inspt);
  Set(t2,Tail(t2));
];
30 # Muaddterm(_h1,_h2)<--
[
  Set(t1,Tail(t1));
  Set(i,MathAdd(i,1));
];
[Local(fn);fn:=String(Muaddterm);`UnFence(@fn,2);];

5  # MultiplyAddSparseTrees(0,_x,_y,{},_fact) <-- x+fact*y;
10 # MultiplyAddSparseTrees(_depth,_x,_y,_coefs,_fact)
    <--
[
  Local(i,t1,t2,inspt,term);
  Set(t1,x);
  Set(i,1);
  Set(t2,y);
  Set(inspt,{});
  While(t1 != {} And t2 != {})
  [
    MuMuaddterm(Head(t1),Head(t2),coefs);
  ];  

  While(t2 != {})
  [
    Set(term,Head(t2));
    Set(x,DestructiveAppend(x,meradd(Head(t2),coefs)));
    Set(t2,Tail(t2));
  ];  
  While(inspt != {})
  [
    Set(i,Head(inspt));
    Set(x,DestructiveInsert(x,i[2],i[1]));
    Set(inspt,Tail(inspt));
  ];
  x;
];

10 # meradd({_ord,rest_IsList},_coefs) <-- 
[
  Local(head);
  Set(head,Head(coefs));
  Set(coefs,Tail(coefs));
  {ord+head,meraddmap(rest,coefs)};
];
20 # meradd({_ord,_rest},_coefs) <-- 
[
   {ord+Head(coefs),rest*fact};
];

10 # meraddmap(list_IsList,_coefs) <-- 
[
  Local(result);
  Set(result,{});
  ForEach(item,list)
  [
    DestructiveAppend(result,meradd(item,coefs));
  ];
  result;
];
[Local(fn);fn:=String(meradd);`UnFence(@fn,2);];
[Local(fn);fn:=String(meraddmap);`UnFence(@fn,2);];

10 # MuMuaddterm({_pow1,_list1},{_pow2,_list2},_coefs)_(pow1=pow2+coefs[1]) <--
[
  if(depth=1)
    [ t1[1][2] := list1+fact*list2; ]
  else
    [ 
      t1[1] := {pow1,MultiplyAddSparseTrees(MathAdd(depth,-1),list1,list2,Tail(coefs),fact)};
    ];
  Set(t2,Tail(t2));
];
20 # MuMuaddterm(_h1,_h2,_coefs)_(h1[1]<h2[1]+coefs[1]) <--
[
//Echo({"inspt ",h1,h2,coefs});
  Set(inspt,{meradd(Head(t2),coefs),i}:inspt);
  Set(t2,Tail(t2));
];
30 # MuMuaddterm(_h1,_h2,_coefs)<--
[
  Set(t1,Tail(t1));
  Set(i,MathAdd(i,1));
];
[Local(fn);fn:=String(MuMuaddterm);`UnFence(@fn,3);];


]; // LocalSymbols
