loadlib("AlphaCosim");
#loadlib("AlphaCos");
loadlib("PlotData");
loadlib("LoadData");

NeuroSci := module()
option package;
export centrows,rnrows,centcols,rncols,pnrows,pncols,activerows,actsphere,blendtimes,vorcell;

    centrows_c := proc(A::Array(datatype=float[8]),m::integer[4],n::integer[4])
        for i from 1 to m do
            c := 0.0;
            for j from 1 to n do
                c := c+A[i,j];
            end do;
            c := c/evalf(n);
            for j from 1 to n do
                A[i,j] := A[i,j]-c;
            end do;
        end do;
        return;
    end proc;

    centrows_c := Compiler:-Compile(centrows_c);

    centrows := proc(A)
        centrows_c(A,Dimension(A));
    end proc;

    rnrows_c := proc(A::Array(datatype=float[8]),r1::float[8],m::integer[4],n::integer[4])
        for i from 1 to m do
            r := 0.0;
            for j from 1 to n do
                r := r+A[i,j]^2;
            end do;
            r := sqrt(r);
            for j from 1 to n do
                A[i,j] := A[i,j]*r1/r;
            end do;
        end do;
        return;
    end proc;

    rnrows_c := Compiler:-Compile(rnrows_c);

    rnrows := proc(A,r:=1.0)
        rnrows_c(A,r,Dimension(A));
    end proc;

    pnrows_c := proc(A::Array(datatype=float[8]),m::integer[4],n::integer[4])
        for i from 1 to m do
            c := 0.0;
            for j from 1 to n do
                c := c+A[i,j];
            end do;
            for j from 1 to n do
                A[i,j] := A[i,j]/c;
            end do;
        end do;
        return;
    end proc;

    pnrows_c := Compiler:-Compile(pnrows_c);

    pnrows := proc(A)
        pnrows_c(A,Dimension(A));
    end proc;

    pncols_c := proc(A::Array(datatype=float[8]),m::integer[4],n::integer[4])
        for j from 1 to n do
            c := 0.0;
            for i from 1 to m do
                c := c+A[i,j];
            end do;
            for i from 1 to m do
                A[i,j] := A[i,j]/c;
            end do;
        end do;
        return;
    end proc;

    pncols_c := Compiler:-Compile(pncols_c);

    pncols := proc(A)
        pncols_c(A,Dimension(A));
    end proc;

    centcols_c := proc(A::Array(datatype=float[8]),m::integer[4],n::integer[4])
        for j from 1 to n do
            c := 0.0;
            for i from 1 to m do
                c := c+A[i,j];
            end do;
            c := c/evalf(m);
            for i from 1 to m do
                A[i,j] := A[i,j]-c;
            end do;
        end do;
        return;
    end proc;

    centcols_c := Compiler:-Compile(centcols_c);

    centcols := proc(A)
        centcols_c(A,Dimension(A));
    end proc;

    rncols_c := proc(A::Array(datatype=float[8]),r1::float[8],m::integer[4],n::integer[4])
        for j from 1 to n do
            r := 0.0;
            for i from 1 to m do
                r := r+A[i,j]^2;
            end do;
            r := sqrt(r);
            for i from 1 to m do
                A[i,j] := A[i,j]*r1/r;
            end do;
        end do;
        return;
    end proc;

    rncols_c := Compiler:-Compile(rncols_c);

    rncols := proc(A,r:=1.0)
        rncols_c(A,r,Dimension(A));
    end proc;

#top N most "active" points on A, according to biggest radius
    actsphere := proc(A,N)
        M,d := Dimension(A);
        xx,rads := allocla[float[8]](d,M);
        for i from 1 to M do
            getrowc(A,i,xx,d);
            rads[i] := sqrt(l2nn(xx));
        end do;
        inds := sort(rads,`>`,output=permutation)[1..N];
        A1 := A[inds];
        rads1 := rads[inds];
        inds1 := veci(inds);
        for i from 1 to N do
            r := rads1[i];
            for j from 1 to d do
                A1[i,j] := A1[i,j]/r;
            end do;
        end do;
        return A1,rads1,inds1;
    end proc;

    activerows := proc(A,N)
        M,d := Dimension(A);
        xx,R := allocla[float[8]](d,M);
        for i from 1 to M do
            getrowc(A,i,xx,d);
            R[i] := convert(xx,`+`);
        end do;
        inds := sort(R,`>`,output=permutation)[1..N];
        return inds;
    end proc;

    activerows := proc(A,N,k:=1)
        M,d := Dimension(A);
        M1 := floor(M/k);
        A1,R1,xx,R := allocla[float[8]]([N,d],N,d,M1);
        for i from 1 to M1 do
            getrowc(A,k*(i-1)+1,xx,d);
            R[i] := add(x^2,x=xx);
            #R[i] := convert(xx,`+`); used in the original paper
        end do;
        inds := veci(sort(R,`>`,output=permutation)[1..N]);
        for i from 1 to N do
            i1 := inds[i];
            r := R[i1];
            for j from 1 to d do
                A1[i,j] := A[k*(i1-1)+1,j];
                R1[i] := r;
            end do;
        end do;
        sig := sort(inds,output=permutation);
        for i from 1 to N do
            inds[i] := k*(inds[i]-1)+1;
        end do;
        return A1[sig],R1[sig],inds[sig];
    end proc;

    blendtimes_c := proc(A::Array(datatype=float[8]),N::integer[4],d::integer[4])
        for k from 1 to N-1 do
            k1 := N-k+1;
            for j from 1 to d do
                A[k1,j] := .5*(A[k1,j]+A[k1-1,j]);
            end do;
        end do;
        for j from 1 to d do
            A[1,j] := .5*A[1,j];
        end do;
    end proc;

    blendtimes_c := Compiler:-Compile(blendtimes_c);

    blendtimes := proc(A,nsteps)
        N,d := Dimension(A);
        for k from 1 to nsteps do
            print(k,nsteps);
            blendtimes_c(A,N,d);
        end do;
        return;
    end proc;

    vorcell_c := proc(A::Array(datatype=float[8]),S::Array(datatype=float[8]),k::integer[4],inds::Array(datatype=integer[4]),N::integer[4],n::integer[4],d::integer[4])
        m := 0;
        for i1 from 1 to N do
            r1 := Float(infinity);
            k1 := 0;
            for i2 from 1 to n do
                r := 0.0;
                for j from 1 to d do
                    r := r+(A[i1,j]-S[i2,j])^2;
                end do;
                if(r<r1) then
                    r1 := r;
                    k1 := i2;
                end if;
            end do;
            if(k1=k) then
                m := m+1;
                inds[m] := i1;
            end if;
        end do;
        return m;
    end proc;

    vorcell_c := Compiler:-Compile(vorcell_c);

    vorcell := proc(A,S,k)
        N,d := Dimension(A);
        n := Dimension(S)[1];
        inds := veci(N);
        m := vorcell_c(A,S,k,inds,N,n,d);
        return inds[1..m];
    end proc;

end module;
