with(plots):
with(plottools):
with(ImageTools):
loadlib("AllocLA"):
loadlib("TensMaps"):
loadlib("Stats"):
loadlib("ColMaps");

#loading csv files from the main data directory
DataTools := module()
option package;
export tonest,denest,loadcsv,randframe,plotmats,drawrange,rowmap,buffmap,tobuff;
local rowmap_code,colorlist;

    denest := proc(xn)
        if(type(xn,'list')) then
            ans := [];
            for x in xn do
                ans := [op(ans),op(procname(eval(x)))];
            end do;
            return ans;
        end if;
        return [xn];
    end proc;

    tonest := proc(xl,proto)
        if(type(proto,'list')) then
            n := nops(proto);
            k := 0;
            ml := map(nopsnest,proto);
            ans := [];
            for i from 1 to n do
                yn,m := proto[i],ml[i];
                xn := tonest(xl[k+1..k+m],yn);
                k := k+m;
                ans := [op(ans),xn];
            end do;
            return ans;
        else
            return xl[1];
        end if;
    end proc;

    loadcsv := proc(fn)
        A := Import(cat(datadir,"/"/fn));
        A := convert(A,'Matrix');
        ans := matf(A);
        return ans;
    end proc;

#random unitary frame of n vectors in R^m
    randframe := proc(n,m)
        B := matf(n,m);
        Sample(Normal(0,1),B);
        Q,R := QRDecomposition(B);
        return Q;
    end proc;

    drawrange := proc(A,h:=0.0)
        N,m := Dimension(A);
        rng := [];
        for j from 1 to m do
            a := min([seq(A[i,j],i=1..N)]);
            b := max([seq(A[i,j],i=1..N)]);
            rng := [op(rng),a-h..b+h];
        end do;
        return rng;
    end proc;

    colorlist := proc(n)
        cols := ["black","green","red","blue","brown","purple","orange","pink","yellow"];
        if(n>nops(cols)) then
            error;
        end if;
        return cols[1..n];
    end proc;

    plotmats := proc()
    uses plots,plottools;
        d := min(Dimension(args[1])[2],3);
        ans := [];
        cols := colorlist(nargs);
        for i from 1 to nargs do
            if(type(args[i],'Matrix')) then
                A := args[i];
                N := Dimension(A)[1];
                col := cols[i];
                ans := [op(ans),seq(point([seq(A[k,j],j=1..d)],symbol=solidcircle,symbolsize=5,color=col),k=1..N)];
            else
                A,cl := op(args[i]);
                N := Dimension(A);
                ans := [op(ans),seq(point([seq(A[k,j],j=1..d)],symbol=solidcircle,symbolsize=3,color=cl[k]),k=1..N)];
            end if;
        end do;
        if(type(procname,indexed)) then
            return display(ans,op(procname));
        else
            return display(ans);
        end if;
    end proc;

    buffmap := proc(F_to)
        targ1 := args[2..nargs];
        F_buff := proc()
            F_to(args,targ1);
            return targ1;
        end proc;
        return F_buff;
    end proc;

    rowmap_code := proc(source,targ)
    option remember;
        code0 := "proc(F";
        code2 := "";
        k1,k2,k3 := 0,0,0;
        flag := false;
        code3 := cat("for i from 1 to ",N," do\n");
        code1 := "";
        code5 := "F(";
        for typ in source do
            if(numelems(code5)<>2) then
                code5 := cat(code5,",");
            end if;
            if(typ=2) then
                k1 := k1+1;
                if(not flag) then
                    flag := true;
                    code1 := cat(code1,"N := Dimension(A",k1,")[1];\n");
                end if;
                code0 := cat(code0,",A",k1);
                code1 := cat(code1,"n",k1," := Dimension(A",k1,")[2];\n");
                code2 := cat(code2,"xx",k1,":=Vector(n",k1,",datatype=float[8]);\n");
                code3 := cat(code3,"getrow_c(A",k1,",i,xx",k1,",n",k1,");\n");
                code5 := cat(code5,"xx",k1);
            elif(typ=1) then
                k2 := k2+1;
                if(not flag) then
                    flag := true;
                    code1 := cat(code1,"N := Dimension(U",k2,");\n");
                end if;
                code0 := cat(code0,",U",k2);
                code5 := cat(code5,"U",k2,"[i]");
            elif(typ=0) then
                k3 := k3+1;
                code0 := cat(code0,",c",k3);
                code5 := cat(code5,"c",k3);
            else
                error;
            end if;
        end do;
        code5 := cat(code5,");\n");
        l1,l2,l3 := 0,0,0;
        code4 := "";
        code6 := "";
        for typ in targ do
            if(numelems(code4)<>0) then
                code4 := cat(code4,",");
            end if;
            if(typ=2) then
                l1 := l1+1;
                code0 := cat(code0,",B",l1);
                code1 := cat(code1,"m",l1," := Dimension(B",l1,")[2];\n");
                code4 := cat(code4,"yy",l1);
                code6 := cat(code6,"setrow_c(B",l1,",i,yy",l1,",m",l1,");\n");
            elif(typ=1) then
                l2 := l2+1;
                code0 := cat(code0,",V",l2);
                code4 := cat(code4,"V",l2,"[i]");
            else
                error;
            end if;
        end do;
        code4 := cat(code4," := ");
        code0 := cat(code0,")\nuses AllocLA;\n");
        code6 := cat(code6,"end do;\n");
        code := cat(code0,code1,code2,code3,code4,code5,code6,"end proc;");
        F1 := parse(code);
        return F1;
    end proc;

    rowmap_typ := proc(A)
        if(type(A,'Matrix')) then
            return 2;
        elif(type(A,'Vector')) then
            return 1;
        else
            return 0;
        end if;
    end proc;

    rowmap := proc(F,source,targ)
        source1 := denest(source);
        N := 0;
        for A in source1 do
            if(type(A,'Matrix') or type(A,'Vector')) then
                N := Dimension(A)[1];
                break;
            end if;
        end do;
        if(nargs=3) then
            targ1 := denest(targ);
        else
            argl := [];
            for A in source do
                if(type(A,'Matrix') or type(A,'Vector')) then
                    argl := [op(argl),A[1]];
                else
                    argl := [op(argl),A];
                end if;
            end do;
            Vl := [F(op(argl))];
            targ1 := [];
            for V in Vl do
                if(type(V,'Vector')) then
                    d := Dimension(V);
                    targ1 := [op(targ1),Matrix(N,d,datatype=float[8])];
                else
                    targ1 := [op(targ1),Vector(N,datatype=float[8])];
                end if;
            end do;
        end if;
        F1 := rowmap_code(map(rowmap_typ,source1),map(rowmap_typ,targ1));
        F1(F,op(source1),op(targ1));
        return op(targ1);
    end proc;

end module;
