supplement-02-a.gp
\\ Encoding strings as vectors of numbers, and decoding vectors of \\ numbers to strings. encode(s)= { local(u); u=Vec(Vecsmall(s)); if((vecmin(u) < 96) || (vecmax(u) > 122), error("input should only contain a-z");); return(u-vector(length(u),x,97)); } decode(u)= { if ((vecmin(u) < -1) || (vecmax(u) > 25), error("input should be in the range [0, .., 25]")); return(Strchr(u+vector(length(u),x,97))); } \\ Helper functions. wrappedapply(f,s)=decode(apply(f, encode(s))); caesar(k,s)=wrappedapply(x->(x+k)%26, s); decaesar(k,s)=caesar(-k,s); vigenere(k,s)= { local(i,u,v); v=encode(s); u=vector(length(v)); for(i=1,length(v), if(k[((i-1)%length(k))+1]==26, u[i] = -1, u[i] = (v[i]+k[((i-1)%length(k))+1])%26)); return(decode(u)); } devigenere(k,s)=vigenere(vector(length(k),i,-k[i]), s); invertpermutation(k)= { my(u,v); u = encode(k); v = vector(26, i, -1); for(i=1,length(u), if(u[i] != -1, v[u[i]+1] = i-1)); return(decode(v)); } substitution(k, s)= { my(v); v = encode(k); wrappedapply(x -> v[x+1], s); } desubstitution(k,s)=substitution(invertpermutation(k), s); subsequence(v,i,n)= { return(vector(floor(length(v)/n),j,v[i+(j-1)*n])); } frequency(v)= { local(i,j,u,r); u=vecsort(v); i = 1; r = []; while(i <= length(u), j=i+1; while(j <= length(u), if(u[j] != u[i], break); j = j+1); r = concat(r, [[u[i], j-i]]); i = j); return(vecsort(r,2,4)); } keyguesses(v)= { local(i,k,u,s); u = frequency(v); for(i=1,5, k=(u[i][2]-4)%26; print(k, " <-> ", decode(vector(5, j, (u[j][2]-k)%26)))); } IC(v)= { local(fr); fr=frequency(v); return(1.0/(length(v)*(length(v)-1))*sum(i=1,26,fr[i][3]*(fr[i][3]-1))); } makepermutation(pairs)= { local(u,i); u=vector(26, i, -1); for(i=1,length(pairs), a=Vec(pairs[i]); b=encode(a[1])[1]; c=encode(a[2])[1]; u[b+1] = c); return(decode(u)); } digrams(s)= { local(u,v,i); u=Vec(s); return(vector(length(u)-1, i, Str(u[i], u[i+1]))); } trigrams(s)= { local(u,v,i); u=Vec(s); return(vector(length(u)-2, i, Str(u[i], u[i+1], u[i+2]))); }