diff options
Diffstat (limited to 'appl/math')
| -rw-r--r-- | appl/math/ack.b | 43 | ||||
| -rw-r--r-- | appl/math/crackerbarrel.b | 133 | ||||
| -rw-r--r-- | appl/math/doc.txt | 48 | ||||
| -rw-r--r-- | appl/math/factor.b | 180 | ||||
| -rw-r--r-- | appl/math/ffts.b | 639 | ||||
| -rw-r--r-- | appl/math/fibonacci.b | 59 | ||||
| -rw-r--r-- | appl/math/fit.b | 264 | ||||
| -rw-r--r-- | appl/math/genprimes.b | 64 | ||||
| -rw-r--r-- | appl/math/geodesy.b | 849 | ||||
| -rw-r--r-- | appl/math/gr.b | 557 | ||||
| -rw-r--r-- | appl/math/graph0.b | 84 | ||||
| -rw-r--r-- | appl/math/hist0.b | 99 | ||||
| -rw-r--r-- | appl/math/linalg.b | 197 | ||||
| -rw-r--r-- | appl/math/linbench.b | 197 | ||||
| -rw-r--r-- | appl/math/mersenne.b | 99 | ||||
| -rw-r--r-- | appl/math/mkfile | 43 | ||||
| -rw-r--r-- | appl/math/parts.b | 125 | ||||
| -rw-r--r-- | appl/math/perms.b | 131 | ||||
| -rw-r--r-- | appl/math/pi.b | 405 | ||||
| -rw-r--r-- | appl/math/polyfill.b | 440 | ||||
| -rw-r--r-- | appl/math/polyhedra.b | 195 | ||||
| -rw-r--r-- | appl/math/powers.b | 672 | ||||
| -rw-r--r-- | appl/math/primes.b | 228 | ||||
| -rw-r--r-- | appl/math/sieve.b | 220 |
24 files changed, 5971 insertions, 0 deletions
diff --git a/appl/math/ack.b b/appl/math/ack.b new file mode 100644 index 00000000..cbed6fdd --- /dev/null +++ b/appl/math/ack.b @@ -0,0 +1,43 @@ +implement Ackermann; + +include "sys.m"; + sys: Sys; +include "draw.m"; + draw: Draw; + +Ackermann: module +{ + init: fn(ctxt: ref Draw->Context, argv: list of string); +}; + +init(nil: ref Draw->Context, argv: list of string) +{ + sys = load Sys Sys->PATH; + draw = load Draw Draw->PATH; + argv = tl argv; # remove program name + m := n := 0; + if(argv != nil){ + m = int hd argv; + argv = tl argv; + } + if(m < 0) + m = 0; + if(argv != nil) + n = int hd argv; + if(n < 0) + n = 0; + t0 := sys->millisec(); + a := ack(m, n); + t1 := sys->millisec(); + sys->print("A(%d, %d) = %d (t = %d ms)\n", m, n, a, t1-t0); +} + +ack(m, n: int) : int +{ + if(m == 0) + return n+1; + else if(n == 0) + return ack(m-1, 1); + else + return ack(m-1, ack(m, n-1)); +} diff --git a/appl/math/crackerbarrel.b b/appl/math/crackerbarrel.b new file mode 100644 index 00000000..e5e1357b --- /dev/null +++ b/appl/math/crackerbarrel.b @@ -0,0 +1,133 @@ +implement CBPuzzle; + +# Cracker Barrel Puzzle +# +# Holes are drilled in a triangular arrangement into which all but one +# are seated pegs. A 6th order puzzle appears in the diagram below. +# Note, the hole in the lower left corner of the triangle is empty. +# +# V +# V V +# V V V +# V V V V +# V V V V V +# O V V V V V +# +# Pegs are moved by jumping over a neighboring peg thereby removing the +# jumped peg. A peg can only be moved if a neighboring hole contains a +# peg and the hole on the other side of the neighbor is empty. The last +# peg cannot be removed. +# +# The object is to remove as many pegs as possible. + +include "sys.m"; + sys: Sys; +include "draw.m"; + +CBPuzzle: module { + init: fn(nil: ref Draw->Context, args: list of string); +}; + +ORDER: con 6; + +Move: adt { + x, y: int; +}; + +valid:= array[] of {Move (1,0), (0,1), (-1,1), (-1,0), (0,-1), (1,-1)}; + +board:= array[ORDER*ORDER] of int; +pegs, minpegs: int; + +puzzle(): int +{ + if (pegs < minpegs) + minpegs = pegs; + + if (pegs == 1) + return 1; + + # Check each row of puzzle + for (r := 0; r < ORDER; r += 1) + # Check each column + for (c := 0; c < ORDER-r; c += 1) { + fromx := r*ORDER + c; + # Is a peg in this hole? + if (board[fromx]) + # Check valid moves from this hole + for (m := 0; m < len valid; m += 1) { + tor := r + 2*valid[m].y; + toc := c + 2*valid[m].x; + + # Is new location still on the board? + if (tor + toc < ORDER && tor >= 0 && toc >= 0) { + jumpr := r + valid[m].y; + jumpc := c + valid[m].x; + jumpx := jumpr*ORDER + jumpc; + + # Is neighboring hole occupied? + if (board[jumpx]) { + # Is new location empty? + tox := tor*ORDER + toc; + + if (! board[tox]) { + # Jump neighboring hole + board[fromx] = 0; + board[jumpx] = 0; + board[tox] = 1; + pegs -= 1; + + # Try solving puzzle from here + if (puzzle()) { + #sys->print("(%d,%d) - (%d,%d)\n", r, c, tor, toc); + return 1; + } + # Dead end, put pegs back and try another move + board[fromx] = 1; + board[jumpx] = 1; + board[tox] = 0; + pegs += 1; + } # empty location + } # occupied neighbor + } # still on board + } # valid moves + } + return 0; +} + +solve(): int +{ + minpegs = pegs = (ORDER+1)*ORDER/2 - 1; + + # Put pegs on board + for (r := 0; r < ORDER; r += 1) + for (c := 0; c < ORDER - r; c += 1) + board[r*ORDER + c] = 1; + + # Remove one peg + board[0] = 0; + + return puzzle(); +} + +init(nil: ref Draw->Context, args: list of string) +{ + sys = load Sys Sys->PATH; + + TRIALS: int; + if (len args < 2) + TRIALS = 1; + else + TRIALS = int hd tl args; + + start := sys->millisec(); + for (trials := 0; trials < TRIALS; trials += 1) + solved := solve(); + end := sys->millisec(); + + sys->print("%d ms\n", end - start); + + if (! solved) + sys->print("No solution\n"); + sys->print("Minimum pegs: %d\n", minpegs); +} diff --git a/appl/math/doc.txt b/appl/math/doc.txt new file mode 100644 index 00000000..821e3a22 --- /dev/null +++ b/appl/math/doc.txt @@ -0,0 +1,48 @@ +==========graph.b, gr.b================ + +I believe scientific authors and readers are best served by a +minimalist approach that makes all plots look boringly alike, except +for the data content. Here is a library that does the task of +accumulating data to find a bounding box and then draws the curves, +points, and text surrounded by readable axes. + +The command appl/math/graph.dis is meant to be launched from wm and +then provided a file containing (x,y) pairs. There are no options. + +The library version, appl/math/gr.b, is a little more flexible. + +Include gr.m and call p := GR->open(). To draw a curve, call + p.graph(x,y) +where x and y are of real arrays. To add the string s at a point (u,v), call + p.text(j,s,u,v) +where j is LJUST, CENTER, or RJUST to indicate whether the left, middle, +or right of the string should be at (u,v) plus one of HIGH, MED, BASE, or LOW +to indicate where the baseline of the text should be relative to (u,v). +To get text running in the y direction, add UP. To enforce the +same scaling in x and y, call p.equalxy(). + +To change from the default solid line, call + p.pen(j) where j is one +of the symbols: DASHED, DOTTED, REFERENCE, SOLID, +CIRCLE, CROSS, or INVIS. A CIRCLE and CROSS +"pen" just puts markers at the points, and doesn't connect with line +segments. A REFERENCE line is lighter than other lines. DASHED +curve follows the curve even within one dash, and preserves arclength of +dashes and spaces. An INVIS line is sometimes handy as "strut" for +maintaining a consistent scale across a series of plots. + +Finally, call + p.out(p,"xlabel","xunit","ylabel","yunit") +to put out the curves and text in PostScript on standard output. +Axes are produced with "Guggenheim slash notation," in which the user +variable is divided by scaled units to get dimensionless numbers of +reasonable magnitude. + +The function + name := p.getfilename(); +opens a dialog box to get a filename from the user and update the titlebar; + p.bye(); +pauses until the user clicks the "X" exit button in the titlebar. + + +<ehg@bell-labs.com> 16 May 1996 diff --git a/appl/math/factor.b b/appl/math/factor.b new file mode 100644 index 00000000..5f2aa775 --- /dev/null +++ b/appl/math/factor.b @@ -0,0 +1,180 @@ +# +# initially generated by c2l +# + +implement Factor; + +include "draw.m"; + +Factor: module +{ + init: fn(nil: ref Draw->Context, argl: list of string); +}; + +include "sys.m"; + sys: Sys; +include "bufio.m"; + bufio: Bufio; + Iobuf: import bufio; +include "math.m"; + maths: Math; + modf: import maths; + +init(nil: ref Draw->Context, argl: list of string) +{ + sys = load Sys Sys->PATH; + bufio = load Bufio Bufio->PATH; + maths = load Math Math->PATH; + main(len argl, argl); +} + +WHLEN: con 48; +wheel := array[WHLEN] of { + real 2, + real 10, + real 2, + real 4, + real 2, + real 4, + real 6, + real 2, + real 6, + real 4, + real 2, + real 4, + real 6, + real 6, + real 2, + real 6, + real 4, + real 2, + real 6, + real 4, + real 6, + real 8, + real 4, + real 2, + real 4, + real 2, + real 4, + real 8, + real 6, + real 4, + real 6, + real 2, + real 4, + real 6, + real 2, + real 6, + real 6, + real 4, + real 2, + real 4, + real 6, + real 2, + real 6, + real 4, + real 2, + real 4, + real 2, + real 10, +}; +bin: ref Iobuf; + +main(argc: int, argv: list of string) +{ + n: real; + i: int; + l: string; + + if(argc > 1){ + argv = tl argv; + for(i = 1; i < argc; i++){ + n = real hd argv; + factor(n); + argv = tl argv; + } + exit; + } + bin = bufio->fopen(sys->fildes(0), Sys->OREAD); + for(;;){ + l = bin.gets('\n'); + if(l == nil) + break; + n = real l; + if(n <= real 0) + break; + factor(n); + } + exit; +} + +factor(n: real) +{ + quot, d, s: real; + i: int; + + sys->print("%d\n", int n); + if(n == real 0) + return; + s = maths->sqrt(n)+real 1; + for(;;){ + (iquot, frac) := modf(n/real 2); + if(frac != real 0) + break; + quot = real iquot; + sys->print(" 2\n"); + n = quot; + s = maths->sqrt(n)+real 1; + } + for(;;){ + (iquot, frac) := modf(n/real 3); + if(frac != real 0) + break; + quot = real iquot; + sys->print(" 3\n"); + n = quot; + s = maths->sqrt(n)+real 1; + } + for(;;){ + (iquot, frac) := modf(n/real 5); + if(frac != real 0) + break; + quot = real iquot; + sys->print(" 5\n"); + n = quot; + s = maths->sqrt(n)+real 1; + } + for(;;){ + (iquot, frac) := modf(n/real 7); + if(frac != real 0) + break; + quot = real iquot; + sys->print(" 7\n"); + n = quot; + s = maths->sqrt(n)+real 1; + } + d = real 1; + for(i = 1;;){ + d += wheel[i]; + for(;;){ + (iquot, frac) := modf(n/d); + if(frac != real 0) + break; + quot = real iquot; + sys->print(" %d\n", int d); + n = quot; + s = maths->sqrt(n)+real 1; + } + i++; + if(i >= WHLEN){ + i = 0; + if(d > s) + break; + } + } + if(n > real 1) + sys->print(" %d\n", int n); + sys->print("\n"); +} + diff --git a/appl/math/ffts.b b/appl/math/ffts.b new file mode 100644 index 00000000..e6132289 --- /dev/null +++ b/appl/math/ffts.b @@ -0,0 +1,639 @@ +implement FFTs; +include "sys.m"; + sys: Sys; + print: import sys; +include "math.m"; + math: Math; + cos, sin, Degree, Pi: import math; +include "ffts.m"; + +# by r. c. singleton, stanford research institute, sept. 1968 +# translated to limbo by eric grosse, jan 1997 +# arrays at(maxf), ck(maxf), bt(maxf), sk(maxf), and np(maxp) +# are used for temporary storage. if the available storage +# is insufficient, the program exits. +# maxf must be >= the maximum prime factor of n. +# maxp must be > the number of prime factors of n. +# in addition, if the square-free portion k of n has two or +# more prime factors, then maxp must be >= k-1. +# array storage in nfac for a maximum of 15 prime factors of n. +# if n has more than one square-free factor, the product of the +# square-free factors must be <= 210 + +ffts(a,b:array of real, ntot,n,nspan,isn:int){ + maxp: con 209; + i,ii,inc,j,jc,jf,jj,k,k1,k2,k3,k4,kk:int; + ks,kspan,kspnn,kt,m,maxf,nn,nt:int; + aa,aj,ajm,ajp,ak,akm,akp,bb,bj,bjm,bjp,bk,bkm,bkp:real; + c1,c2,c3,c72,cd,rad,radf,s1,s2,s3,s72,s120,sd:real; + maxf = 23; + if(math == nil){ + sys = load Sys Sys->PATH; + math = load Math Math->PATH; + } + nfac := array[12] of int; + np := array[maxp] of int; + at := array[23] of real; + ck := array[23] of real; + bt := array[23] of real; + sk := array[23] of real; + + if(n<2) return; + inc = isn; + c72 = cos(72.*Degree); + s72 = sin(72.*Degree); + s120 = sin(120.*Degree); + rad = 2.*Pi; + if(isn<0){ + s72 = -s72; + s120 = -s120; + rad = -rad; + inc = -inc; + } + nt = inc*ntot; + ks = inc*nspan; + kspan = ks; + nn = nt-inc; + jc = ks/n; + radf = rad*real(jc)*0.5; + i = 0; + jf = 0; + + # determine the factors of n + m = 0; + k = n; + while(k==k/16*16){ + m = m+1; + nfac[m] = 4; + k = k/16; + } + j = 3; + jj = 9; + for(;;) + if(k%jj==0){ + m = m+1; + nfac[m] = j; + k = k/jj; + }else{ + j = j+2; + jj = j*j; + if(jj>k) + break; + } + if(k<=4){ + kt = m; + nfac[m+1] = k; + if(k!=1) + m = m+1; + }else{ + if(k==k/4*4){ + m = m+1; + nfac[m] = 2; + k = k/4; + } + kt = m; + j = 2; + do{ + if(k%j==0){ + m = m+1; + nfac[m] = j; + k = k/j; + } + j = ((j+1)/2)*2+1; + }while(j<=k); + } + if(kt!=0){ + j = kt; + do{ + m = m+1; + nfac[m] = nfac[j]; + j = j-1; + }while(j!=0); + } + + for(;;){ # compute fourier transform + sd = radf/real(kspan); + cd = sin(sd); + cd = 2.0*cd*cd; + sd = sin(sd+sd); + kk = 1; + i = i+1; + if(nfac[i]==2){ # transform for factor of 2 (including rotation factor) + kspan = kspan/2; + k1 = kspan+2; + for(;;){ + k2 = kk+kspan; + ak = a[k2-1]; + bk = b[k2-1]; + a[k2-1] = a[kk-1]-ak; + b[k2-1] = b[kk-1]-bk; + a[kk-1] = a[kk-1]+ak; + b[kk-1] = b[kk-1]+bk; + kk = k2+kspan; + if(kk>nn){ + kk = kk-nn; + if(kk>jc) + break; + } + } + if(kk>kspan) + break; + do{ + c1 = 1.0-cd; + s1 = sd; + for(;;){ + k2 = kk+kspan; + ak = a[kk-1]-a[k2-1]; + bk = b[kk-1]-b[k2-1]; + a[kk-1] = a[kk-1]+a[k2-1]; + b[kk-1] = b[kk-1]+b[k2-1]; + a[k2-1] = c1*ak-s1*bk; + b[k2-1] = s1*ak+c1*bk; + kk = k2+kspan; + if(kk>=nt){ + k2 = kk-nt; + c1 = -c1; + kk = k1-k2; + if(kk<=k2){ + ak = c1-(cd*c1+sd*s1); + s1 = (sd*c1-cd*s1)+s1; + c1 = 2.0-(ak*ak+s1*s1); + s1 = c1*s1; + c1 = c1*ak; + kk = kk+jc; + if(kk>=k2) + break; + } + } + } + k1 = k1+inc+inc; + kk = (k1-kspan)/2+jc; + }while(kk<=jc+jc); + }else{ # transform for factor of 4 + if(nfac[i]!=4){ + # transform for odd factors + k = nfac[i]; + kspnn = kspan; + kspan = kspan/k; + if(k==3) + for(;;){ + # transform for factor of 3 (optional code) + k1 = kk+kspan; + k2 = k1+kspan; + ak = a[kk-1]; + bk = b[kk-1]; + aj = a[k1-1]+a[k2-1]; + bj = b[k1-1]+b[k2-1]; + a[kk-1] = ak+aj; + b[kk-1] = bk+bj; + ak = -0.5*aj+ak; + bk = -0.5*bj+bk; + aj = (a[k1-1]-a[k2-1])*s120; + bj = (b[k1-1]-b[k2-1])*s120; + a[k1-1] = ak-bj; + b[k1-1] = bk+aj; + a[k2-1] = ak+bj; + b[k2-1] = bk-aj; + kk = k2+kspan; + if(kk>=nn){ + kk = kk-nn; + if(kk>kspan) + break; + } + } + else if(k==5){ + # transform for factor of 5 (optional code) + c2 = c72*c72-s72*s72; + s2 = 2.0*c72*s72; + for(;;){ + k1 = kk+kspan; + k2 = k1+kspan; + k3 = k2+kspan; + k4 = k3+kspan; + akp = a[k1-1]+a[k4-1]; + akm = a[k1-1]-a[k4-1]; + bkp = b[k1-1]+b[k4-1]; + bkm = b[k1-1]-b[k4-1]; + ajp = a[k2-1]+a[k3-1]; + ajm = a[k2-1]-a[k3-1]; + bjp = b[k2-1]+b[k3-1]; + bjm = b[k2-1]-b[k3-1]; + aa = a[kk-1]; + bb = b[kk-1]; + a[kk-1] = aa+akp+ajp; + b[kk-1] = bb+bkp+bjp; + ak = akp*c72+ajp*c2+aa; + bk = bkp*c72+bjp*c2+bb; + aj = akm*s72+ajm*s2; + bj = bkm*s72+bjm*s2; + a[k1-1] = ak-bj; + a[k4-1] = ak+bj; + b[k1-1] = bk+aj; + b[k4-1] = bk-aj; + ak = akp*c2+ajp*c72+aa; + bk = bkp*c2+bjp*c72+bb; + aj = akm*s2-ajm*s72; + bj = bkm*s2-bjm*s72; + a[k2-1] = ak-bj; + a[k3-1] = ak+bj; + b[k2-1] = bk+aj; + b[k3-1] = bk-aj; + kk = k4+kspan; + if(kk>=nn){ + kk = kk-nn; + if(kk>kspan) + break; + } + } + }else{ + if(k!=jf){ + jf = k; + s1 = rad/real(k); + c1 = cos(s1); + s1 = sin(s1); + if(jf>maxf){ + sys->fprint(sys->fildes(2),"too many primes for fft"); + exit; + } + ck[jf-1] = 1.0; + sk[jf-1] = 0.0; + j = 1; + do{ + ck[j-1] = ck[k-1]*c1+sk[k-1]*s1; + sk[j-1] = ck[k-1]*s1-sk[k-1]*c1; + k = k-1; + ck[k-1] = ck[j-1]; + sk[k-1] = -sk[j-1]; + j = j+1; + }while(j<k); + } + for(;;){ + k1 = kk; + k2 = kk+kspnn; + aa = a[kk-1]; + bb = b[kk-1]; + ak = aa; + bk = bb; + j = 1; + k1 = k1+kspan; + do{ + k2 = k2-kspan; + j = j+1; + at[j-1] = a[k1-1]+a[k2-1]; + ak = at[j-1]+ak; + bt[j-1] = b[k1-1]+b[k2-1]; + bk = bt[j-1]+bk; + j = j+1; + at[j-1] = a[k1-1]-a[k2-1]; + bt[j-1] = b[k1-1]-b[k2-1]; + k1 = k1+kspan; + }while(k1<k2); + a[kk-1] = ak; + b[kk-1] = bk; + k1 = kk; + k2 = kk+kspnn; + j = 1; + do{ + k1 = k1+kspan; + k2 = k2-kspan; + jj = j; + ak = aa; + bk = bb; + aj = 0.0; + bj = 0.0; + k = 1; + do{ + k = k+1; + ak = at[k-1]*ck[jj-1]+ak; + bk = bt[k-1]*ck[jj-1]+bk; + k = k+1; + aj = at[k-1]*sk[jj-1]+aj; + bj = bt[k-1]*sk[jj-1]+bj; + jj = jj+j; + if(jj>jf) + jj = jj-jf; + }while(k<jf); + k = jf-j; + a[k1-1] = ak-bj; + b[k1-1] = bk+aj; + a[k2-1] = ak+bj; + b[k2-1] = bk-aj; + j = j+1; + }while(j<k); + kk = kk+kspnn; + if(kk>nn){ + kk = kk-nn; + if(kk>kspan) + break; + } + } + } + # multiply by rotation factor (except for factors of 2 and 4) + if(i==m) + break; + kk = jc+1; + do{ + c2 = 1.0-cd; + s1 = sd; + do{ + c1 = c2; + s2 = s1; + kk = kk+kspan; + for(;;){ + ak = a[kk-1]; + a[kk-1] = c2*ak-s2*b[kk-1]; + b[kk-1] = s2*ak+c2*b[kk-1]; + kk = kk+kspnn; + if(kk>nt){ + ak = s1*s2; + s2 = s1*c2+c1*s2; + c2 = c1*c2-ak; + kk = kk-nt+kspan; + if(kk>kspnn) + break; + } + } + c2 = c1-(cd*c1+sd*s1); + s1 = s1+(sd*c1-cd*s1); + c1 = 2.0-(c2*c2+s1*s1); + s1 = c1*s1; + c2 = c1*c2; + kk = kk-kspnn+jc; + }while(kk<=kspan); + kk = kk-kspan+jc+inc; + }while(kk<=jc+jc); + }else{ + kspnn = kspan; + kspan = kspan/4; + do{ + c1 = 1.; + s1 = 0.; + for(;;){ + k1 = kk+kspan; + k2 = k1+kspan; + k3 = k2+kspan; + akp = a[kk-1]+a[k2-1]; + akm = a[kk-1]-a[k2-1]; + ajp = a[k1-1]+a[k3-1]; + ajm = a[k1-1]-a[k3-1]; + a[kk-1] = akp+ajp; + ajp = akp-ajp; + bkp = b[kk-1]+b[k2-1]; + bkm = b[kk-1]-b[k2-1]; + bjp = b[k1-1]+b[k3-1]; + bjm = b[k1-1]-b[k3-1]; + b[kk-1] = bkp+bjp; + bjp = bkp-bjp; + do10 := 0; + if(isn<0){ + akp = akm+bjm; + akm = akm-bjm; + bkp = bkm-ajm; + bkm = bkm+ajm; + if(s1!=0.) do10 = 1; + }else{ + akp = akm-bjm; + akm = akm+bjm; + bkp = bkm+ajm; + bkm = bkm-ajm; + if(s1!=0.) do10 = 1; + } + if(do10){ + a[k1-1] = akp*c1-bkp*s1; + b[k1-1] = akp*s1+bkp*c1; + a[k2-1] = ajp*c2-bjp*s2; + b[k2-1] = ajp*s2+bjp*c2; + a[k3-1] = akm*c3-bkm*s3; + b[k3-1] = akm*s3+bkm*c3; + kk = k3+kspan; + if(kk<=nt) + continue; + }else{ + a[k1-1] = akp; + b[k1-1] = bkp; + a[k2-1] = ajp; + b[k2-1] = bjp; + a[k3-1] = akm; + b[k3-1] = bkm; + kk = k3+kspan; + if(kk<=nt) + continue; + } + c2 = c1-(cd*c1+sd*s1); + s1 = (sd*c1-cd*s1)+s1; + c1 = 2.0-(c2*c2+s1*s1); + s1 = c1*s1; + c1 = c1*c2; + c2 = c1*c1-s1*s1; + s2 = 2.0*c1*s1; + c3 = c2*c1-s2*s1; + s3 = c2*s1+s2*c1; + kk = kk-nt+jc; + if(kk>kspan) + break; + } + kk = kk-kspan+inc; + }while(kk<=jc); + if(kspan==jc) + break; + } + } + } # end "compute fourier transform" + + # permute the results to normal order---done in two stages + # permutation for square factors of n + np[0] = ks; + if(kt!=0){ + k = kt+kt+1; + if(m<k) + k = k-1; + j = 1; + np[k] = jc; + do{ + np[j] = np[j-1]/nfac[j]; + np[k-1] = np[k]*nfac[j]; + j = j+1; + k = k-1; + }while(j<k); + k3 = np[k]; + kspan = np[1]; + kk = jc+1; + k2 = kspan+1; + j = 1; + if(n!=ntot){ + for(;;){ + # permutation for multivariate transform + k = kk+jc; + do{ + ak = a[kk-1]; + a[kk-1] = a[k2-1]; + a[k2-1] = ak; + bk = b[kk-1]; + b[kk-1] = b[k2-1]; + b[k2-1] = bk; + kk = kk+inc; + k2 = k2+inc; + }while(kk<k); + kk = kk+ks-jc; + k2 = k2+ks-jc; + if(kk>=nt){ + k2 = k2-nt+kspan; + kk = kk-nt+jc; + if(k2>=ks) + permm: for(;;){ + k2 = k2-np[j-1]; + j = j+1; + k2 = np[j]+k2; + if(k2<=np[j-1]){ + j = 1; + do{ + if(kk<k2) + break permm; + kk = kk+jc; + k2 = kspan+k2; + }while(k2<ks); + if(kk>=ks) + break permm; + } + } + } + } + jc = k3; + }else{ + for(;;){ + # permutation for single-variate transform (optional code) + ak = a[kk-1]; + a[kk-1] = a[k2-1]; + a[k2-1] = ak; + bk = b[kk-1]; + b[kk-1] = b[k2-1]; + b[k2-1] = bk; + kk = kk+inc; + k2 = kspan+k2; + if(k2>=ks) + perms: for(;;){ + k2 = k2-np[j-1]; + j = j+1; + k2 = np[j]+k2; + if(k2<=np[j-1]){ + j = 1; + do{ + if(kk<k2) + break perms; + kk = kk+inc; + k2 = kspan+k2; + }while(k2<ks); + if(kk>=ks) + break perms; + } + } + } + jc = k3; + } + } + if(2*kt+1>=m) + return; + kspnn = np[kt]; + # permutation for square-free factors of n + j = m-kt; + nfac[j+1] = 1; + do{ + nfac[j] = nfac[j]*nfac[j+1]; + j = j-1; + }while(j!=kt); + kt = kt+1; + nn = nfac[kt]-1; + if(nn<=maxp){ + jj = 0; + j = 0; + for(;;){ + k2 = nfac[kt]; + k = kt+1; + kk = nfac[k]; + j = j+1; + if(j>nn) + break; + for(;;){ + jj = kk+jj; + if(jj<k2) + break; + jj = jj-k2; + k2 = kk; + k = k+1; + kk = nfac[k]; + } + np[j-1] = jj; + } + # determine the permutation cycles of length greater than 1 + j = 0; + for(;;){ + j = j+1; + kk = np[j-1]; + if(kk>=0) + if(kk==j){ + np[j-1] = -j; + if(j==nn) + break; + }else{ + do{ + k = kk; + kk = np[k-1]; + np[k-1] = -kk; + }while(kk!=j); + k3 = kk; + } + } + maxf = inc*maxf; + for(;;){ + j = k3+1; + nt = nt-kspnn; + ii = nt-inc+1; + if(nt<0) + break; + for(;;){ + j = j-1; + if(np[j-1]>=0){ + jj = jc; + do{ + kspan = jj; + if(jj>maxf) + kspan = maxf; + jj = jj-kspan; + k = np[j-1]; + kk = jc*k+ii+jj; + k1 = kk+kspan; + k2 = 0; + do{ + k2 = k2+1; + at[k2-1] = a[k1-1]; + bt[k2-1] = b[k1-1]; + k1 = k1-inc; + }while(k1!=kk); + do{ + k1 = kk+kspan; + k2 = k1-jc*(k+np[k-1]); + k = -np[k-1]; + do{ + a[k1-1] = a[k2-1]; + b[k1-1] = b[k2-1]; + k1 = k1-inc; + k2 = k2-inc; + }while(k1!=kk); + kk = k2; + }while(k!=j); + k1 = kk+kspan; + k2 = 0; + do{ + k2 = k2+1; + a[k1-1] = at[k2-1]; + b[k1-1] = bt[k2-1]; + k1 = k1-inc; + }while(k1!=kk); + }while(jj!=0); + if(j==1) + break; + } + } + } + } +} diff --git a/appl/math/fibonacci.b b/appl/math/fibonacci.b new file mode 100644 index 00000000..af4e769c --- /dev/null +++ b/appl/math/fibonacci.b @@ -0,0 +1,59 @@ +implement Fibonacci; + +include "sys.m"; +include "draw.m"; + +Fibonacci: module +{ + init: fn(nil: ref Draw->Context, argv: list of string); +}; + +init(nil: ref Draw->Context, nil: list of string) +{ + sys := load Sys Sys->PATH; + for(i := 0; ; i++){ + f := fibonacci(i); + if(f < 0) + break; + sys->print("F(%d) = %d\n", i, f); + } +} + +FIB: exception(int, int); +HELP: con "help"; + +NOVAL: con -1000000000; + +fibonacci(n: int): int +{ + { + fib(1, n, 1, 1); + } + exception e{ + FIB => + (x, nil) := e; + return x; + * => + return NOVAL; + } + return NOVAL; +} + +fib(n: int, m: int, x: int, y: int) raises (FIB) +{ + if(n >= m) + raise FIB(x, y); + + { + fib(n+1, m, x, y); + } + exception e{ + FIB => + (x, y) = e; + x = x+y; + y = x-y; + raise FIB(x, y); + * => + raise HELP; + } +} diff --git a/appl/math/fit.b b/appl/math/fit.b new file mode 100644 index 00000000..b512c13b --- /dev/null +++ b/appl/math/fit.b @@ -0,0 +1,264 @@ +# fit a polynomial to a set of points +# fit -dn [-v] +# where n is the degree of the polynomial + +implement Fit; + +include "sys.m"; + sys: Sys; +include "draw.m"; +include "math.m"; + maths: Math; +include "bufio.m"; + bufio: Bufio; +include "arg.m"; + +Fit: module +{ + init: fn(nil: ref Draw->Context, argv: list of string); +}; + +MAXPTS: con 512; +MAXDEG: con 16; +EPS: con 0.0000005; + +init(nil: ref Draw->Context, argv: list of string) +{ + sys = load Sys Sys->PATH; + maths = load Math Math->PATH; + if(maths == nil) + fatal(sys->sprint("cannot load maths library")); + bufio = load Bufio Bufio->PATH; + if(bufio == nil) + fatal(sys->sprint("cannot load bufio")); + main(argv); +} + +isn(r: real, n: int): int +{ + s := r - real n; + if(s < 0.0) + s = -s; + return s < EPS; +} + +fact(n: int): real +{ + f := 1.0; + for(i := 1; i <= n; i++) + f *= real i; + return f; +} + +comb(n: int, r: int): real +{ + f := 1.0; + for(i := 0; i < r; i++) + f *= real (n-i); + return f/fact(r); +} + +matalloc(n: int): array of array of real +{ + mat := array[n] of array of real; + for(i := 0; i < n; i++) + mat[i] = array[n] of real; + return mat; +} + +matsalloc(n: int): array of array of array of real +{ + mats := array[n+1] of array of array of real; + for(i := 0; i <= n; i++) + mats[i] = matalloc(i); + return mats; +} + +det(mat: array of array of real, n: int, mats: array of array of array of real): real +{ + # easy cases first + if(n == 0) + return 1.0; + if(n == 1) + return mat[0][0]; + if(n == 2) + return mat[0][0]*mat[1][1]-mat[0][1]*mat[1][0]; + d := 0.0; + s := 1; + m := mats[n-1]; + for(k := 0; k < n; k++){ + for(i := 0; i < n-1; i++){ + for(j := 0; j < n-1; j++){ + if(j < k) + m[i][j] = mat[i+1][j]; + else + m[i][j] = mat[i+1][j+1]; + } + } + d += (real s)*mat[0][k]*det(m, n-1, mats); + s = -s; + } + return d; +} + +main(argv: list of string) +{ + i, j: int; + x, y, z: real; + fb: ref Bufio->Iobuf; + + n := 0; + p := 1; + arg := load Arg Arg->PATH; + if(arg == nil) + fatal(sys->sprint("cannot load %s: %r", Arg->PATH)); + arg->init(argv); + verbose := 0; + while((o := arg->opt()) != 0) + case o{ + 'd' => + p = int arg->arg(); + 'v' => + verbose = 1; + * => + fatal(sys->sprint("bad option %c", o)); + } + args := arg->argv(); + arg = nil; + if(args != nil){ + s := hd args; + fb = bufio->open(s, bufio->OREAD); + if(fb == nil) + fatal(sys->sprint("cannot open %s", s)); + } + else{ + fb = bufio->open("/dev/cons", bufio->OREAD); + if(fb == nil) + fatal(sys->sprint("missing data file name")); + } + a := array[p+1] of real; + b := array[p+1] of real; + sx := array[2*p+1] of real; + sxy := array[p+1] of real; + xd := array[MAXPTS] of real; + yd := array[MAXPTS] of real; + while(1){ + xs := ss(bufio->fb.gett(" \t\r\n")); + if(xs == nil) + break; + ys := ss(bufio->fb.gett(" \t\r\n")); + if(ys == nil) + fatal(sys->sprint("missing value")); + if(n >= MAXPTS) + fatal(sys->sprint("too many points")); + xd[n] = real xs; + yd[n] = real ys; + n++; + } + if(p < 0) + fatal(sys->sprint("negative power")); + if(p > MAXDEG) + fatal(sys->sprint("power too large")); + if(n < p+1) + fatal(sys->sprint("not enough points")); + # use x-xbar, y-ybar to avoid overflow + for(i = 0; i <= p; i++) + sxy[i] = 0.0; + for(i = 0; i <= 2*p; i++) + sx[i] = 0.0; + xbar := ybar := 0.0; + for(i = 0; i < n; i++){ + xbar += xd[i]; + ybar += yd[i]; + } + xbar = xbar/(real n); + ybar = ybar/(real n); + for(i = 0; i < n; i++){ + x = xd[i]-xbar; + y = yd[i]-ybar; + for(j = 0; j <= p; j++) + sxy[j] += y*x**j; + for(j = 0; j <= 2*p; j++) + sx[j] += x**j; + } + mats := matsalloc(p+1); + mat := mats[p+1]; + for(i = 0; i <= p; i++) + for(j = 0; j <= p; j++) + mat[i][j] = sx[i+j]; + d := det(mat, p+1, mats); + if(isn(d, 0)) + fatal(sys->sprint("points not independent")); + for(j = 0; j <= p; j++){ + for(i = 0; i <= p; i++) + mat[i][j] = sxy[i]; + a[j] = det(mat, p+1, mats)/d; + for(i = 0; i <= p; i++) + mat[i][j] = sx[i+j]; + } + if(verbose) + sys->print("\npt actual x actual y predicted y\n"); + e := 0.0; + for(i = 0; i < n; i++){ + x = xd[i]-xbar; + y = yd[i]-ybar; + z = 0.0; + for(j = 0; j <= p; j++) + z += a[j]*x**j; + z += ybar; + e += (z-yd[i])*(z-yd[i]); + if(verbose) + sys->print("%d. %f %f %f\n", i+1, xd[i], yd[i], z); + } + if(verbose) + sys->print("root mean squared error = %f\n", maths->sqrt(e/(real n))); + for(i = 0; i <= p; i++) + b[i] = 0.0; + b[0] += ybar; + for(i = 0; i <= p; i++) + for(j = 0; j <= i; j++) + b[j] += a[i]*comb(i, j)*(-xbar)**(i-j); + pr := 0; + sys->print("y = "); + for(i = p; i >= 0; i--){ + if(!isn(b[i], 0) || (i == 0 && pr == 0)){ + if(b[i] < 0.0){ + sys->print("-"); + b[i] = -b[i]; + } + else if(pr) + sys->print("+"); + pr = 1; + if(i == 0) + sys->print("%f", b[i]); + else{ + if(!isn(b[i], 1)) + sys->print("%f*", b[i]); + sys->print("x"); + if(i > 1) + sys->print("^%d", i); + } + } + } + sys->print("\n"); +} + +ss(s: string): string +{ + l := len s; + while(l > 0 && (s[0] == ' ' || s[0] == '\t' || s[0] == '\r' || s[0] == '\n')){ + s = s[1: ]; + l--; + } + while(l > 0 && (s[l-1] == ' ' || s[l-1] == '\t' || s[l-1] == '\r' || s[l-1] == '\n')){ + s = s[0: l-1]; + l--; + } + return s; +} + +fatal(s: string) +{ + sys->fprint(sys->fildes(2), "fit: %s\n", s); + exit; +} diff --git a/appl/math/genprimes.b b/appl/math/genprimes.b new file mode 100644 index 00000000..19c32938 --- /dev/null +++ b/appl/math/genprimes.b @@ -0,0 +1,64 @@ +implement Primes; + +include "draw.m"; + +Primes: module +{ + init: fn(nil: ref Draw->Context, argl: list of string); +}; + +include "sys.m"; + sys: Sys; +include "arg.m"; + arg: Arg; + +LIM: con 1729; +MAX: con 1000000; +BUFSZ: con 256; + +init(nil: ref Draw->Context, argl: list of string) +{ + sys = load Sys Sys->PATH; + arg = load Arg Arg->PATH; + arg->init(argl); + quiet := 0; + lim := LIM; + while((ch := arg->opt()) != 0){ + case (ch){ + 'q' => + quiet = 1; + * => + ; + } + } + argv := arg->argv(); + if(argv != nil) + lim = int hd argv; + if(lim < 2) + lim = 2; + if(lim > MAX) + lim = MAX; + c := chan[BUFSZ] of int; + spawn prime(c, !quiet); + for(n := 2; n <= lim; n++) + c <-= n; + c <-= 1; +} + +prime(c: chan of int, pr: int) +{ + p := <-c; + if(p == 1) + exit; + if(pr) + sys->print("%d\n", p); + nc := chan[BUFSZ] of int; + spawn prime(nc, pr); + for(;;){ + n := <-c; + if(n%p) + nc <-= n; + if(n == 1) + exit; + } +} diff --git a/appl/math/geodesy.b b/appl/math/geodesy.b new file mode 100644 index 00000000..7c4cd152 --- /dev/null +++ b/appl/math/geodesy.b @@ -0,0 +1,849 @@ +implement Geodesy; + +include "sys.m"; + sys: Sys; +include "math.m"; + maths: Math; + Pi: import Math; + sin, cos, tan, asin, acos, atan, atan2, sqrt, fabs: import maths; +include "math/geodesy.m"; + +Approx: con 0; + +Epsilon: con 0.000001; +Mperft: con 0.3048; +Earthrad: con 10800.0/Pi*6076.115*Mperft; # in feet (about 4000 miles) : now metres +Δt: con 16.0; # now-1989 + +# lalo0: con "53:57:45N 01:04:55W"; +# os0: con "SE6022552235"; + +# ellipsoids +Airy1830, Airy1830m, Int1924, GRS80: con iota; + +Ngrid: con 100000; # in metres + +Vector: adt{ + x, y, z: real; +}; + +Latlong: adt{ + la: real; # -Pi to Pi + lo: real; # -Pi to Pi + x: real; + y: real; +}; + +Ellipsoid: adt{ + name: string; + a: real; + b: real; +}; + +Datum: adt{ + name: string; + e: int; + # X, Y, Z axes etc +}; + +Mercator: adt{ + name: string; + F0: real; + φ0λ0: string; + E0: real; + N0: real; + e: int; +}; + +Helmert: adt{ + tx, ty, tz: real; # metres + s: real; # ppm + rx, ry, rz: real; # secs +}; + +Format: adt{ + dat: int; # datum + cdat: int; # converting datum + prj: int; # projection + tmp: ref Mercator; # actual projection + orig: Lalo; # origin of above projection + zone: int; # UTM zone +}; + +# ellipsoids +ells := array[] of { + Airy1830 => Ellipsoid("Airy1830", 6377563.396, 6356256.910), + Airy1830m => Ellipsoid("Airy1830 modified", 6377340.189, 6356034.447), + Int1924 => Ellipsoid("International 1924", 6378388.000, 6356911.946), + GRS80 => Ellipsoid("GRS80", 6378137.000, 6356752.3141), + }; + +# datums +dats := array[] of { + OSGB36 => Datum("OSGB36", Airy1830), + Ireland65 => Datum("Ireland65", Airy1830m), + ED50 => Datum("ED50", Int1924), + WGS84 => Datum("WGS84", GRS80), + ITRS2000 => Datum("ITRS2000", GRS80), + ETRS89 => Datum("ETRS89", GRS80), + }; + +# transverse Mercator projections +tmps := array[] of { + Natgrid => Mercator("National Grid", 0.9996012717, "49:00:00N 02:00:00W", real(4*Ngrid), real(-Ngrid), Airy1830), + IrishNatgrid => Mercator("Irish National Grid", 1.000035, "53:30:00N 08:00:00W", real(2*Ngrid), real(5*Ngrid/2), Airy1830m), + UTMEur => Mercator("UTM Europe", 0.9996, nil, real(5*Ngrid), real(0), Int1924), + UTM => Mercator("UTM", 0.9996, nil, real(5*Ngrid), real(0), GRS80), + }; + +# Helmert tranformations +HT_WGS84_OSGB36: con Helmert(-446.448, 125.157, -542.060, 20.4894, -0.1502, -0.2470, -0.8421); +HT_ITRS2000_ETRS89: con Helmert(0.054, 0.051, -0.048, 0.0, 0.000081*Δt, 0.00049*Δt, -0.000792*Δt); + +# Helmert matrices +HM_WGS84_OSGB36, HM_OSGB36_WGS84, HM_ITRS2000_ETRS89, HM_ETRS89_ITRS2000, HM_ETRS89_OSGB36, HM_OSGB36_ETRS89, HM_IDENTITY: array of array of real; + +fmt: ref Format; + +# latlong: ref Latlong; + +init(d: int, t: int, z: int) +{ + sys = load Sys Sys->PATH; + maths = load Math Math->PATH; + + helmertinit(); + format(d, t, z); + # (nil, (la, lo)) := str2lalo(lalo0); + # (nil, (E, N)) := os2en(os0); + # latlong = ref Latlong(la, lo, real E, real N); +} + +format(d: int, t: int, z: int) +{ + if(fmt == nil) + fmt = ref Format(WGS84, 0, Natgrid, nil, (0.0, 0.0), 30); + if(d >= 0 && d <= ETRS89) + fmt.dat = d; + if(t >= 0 && t <= UTM) + fmt.prj = t; + if(z >= 1 && z <= 60) + fmt.zone = z; + fmt.cdat = fmt.dat; + fmt.tmp = ref Mercator(tmps[fmt.prj]); + if(fmt.tmp.φ0λ0 == nil) + fmt.orig = utmlaloz(fmt.zone); + else + (nil, fmt.orig) = str2lalo(fmt.tmp.φ0λ0); + e := fmt.tmp.e; + if(e != dats[fmt.dat].e){ + for(i := 0; i <= ETRS89; i++) + if(e == dats[i].e){ + fmt.cdat = i; + break; + } + } +} + +str2en(s: string): (int, Eano) +{ + s = trim(s, " \t\n\r"); + if(s == nil) + return (0, (0.0, 0.0)); + os := s[0] >= 'A' && s[0] <= 'Z' || strchrs(s, "NSEW:") < 0; + en: Eano; + if(os){ + (ok, p) := os2en(s); + if(!ok) + return (0, (0.0, 0.0)); + en = p; + } + else{ + (ok, lalo) := str2lalo(s); + if(!ok) + return (0, (0.0, 0.0)); + en = lalo2en(lalo); + } + return (1, en); +} + +str2ll(s: string, pos: int, neg: int): (int, real) +{ + (n, ls) := sys->tokenize(s, ": \t"); + if(n < 1 || n > 3) + return (0, 0.0); + t := hd ls; ls = tl ls; + v := real t; + if(ls != nil){ + t = hd ls; ls = tl ls; + v += (real t)/60.0; + } + if(ls != nil){ + t = hd ls; ls = tl ls; + v += (real t)/3600.0; + } + c := t[len t-1]; + if(c == pos) + ; + else if(c == neg) + v = -v; + else + return (0, 0.0); + return (1, norm(deg2rad(v))); +} + +str2lalo(s: string): (int, Lalo) +{ + s = trim(s, " \t\n\r"); + p := strchr(s, 'N'); + if(p < 0) + p = strchr(s, 'S'); + if(p < 0) + return (0, (0.0, 0.0)); + (ok1, la) := str2ll(s[0: p+1], 'N', 'S'); + (ok2, lo) := str2ll(s[p+1: ], 'E', 'W'); + if(!ok1 || !ok2 || la < -Pi/2.0 || la > Pi/2.0) + return (0, (0.0, 0.0)); + return (1, (la, lo)); +} + +ll2str(ll: int, dir: string): string +{ + d := ll/360000; + ll -= 360000*d; + m := ll/6000; + ll -= 6000*m; + s := ll/100; + ll -= 100*s; + return d2(d) + ":" + d2(m) + ":" + d2(s) + "." + d2(ll) + dir; +} + +lalo2str(lalo: Lalo): string +{ + la := int(360000.0*rad2deg(lalo.la)); + lo := int(360000.0*rad2deg(lalo.lo)); + lad := "N"; + lod := "E"; + if(la < 0){ + lad = "S"; + la = -la; + } + if(lo < 0){ + lod = "W"; + lo = -lo; + } + return ll2str(la, lad) + " " + ll2str(lo, lod); +} + +en2os(p: Eano): string +{ + E := trunc(p.e); + N := trunc(p.n); + es := E/Ngrid; + ns := N/Ngrid; + e := E-Ngrid*es; + n := N-Ngrid*ns; + d1 := 5*(4-ns/5)+es/5+'A'-3; + d2 := 5*(4-ns%5)+es%5+'A'; + # now account for 'I' missing + if(d1 >= 'I') + d1++; + if(d2 >= 'I') + d2++; + return sys->sprint("%c%c%5.5d%5.5d", d1, d2, e, n); +} + +os2en(s: string): (int, Eano) +{ + s = trim(s, " \t\n\r"); + if((m := len s) != 4 && m != 6 && m != 8 && m != 10 && m != 12) + return (0, (0.0, 0.0)); + m = m/2-1; + u := Ngrid/10**m; + d1 := s[0]; + d2 := s[1]; + if(d1 < 'A' || d2 < 'A' || d1 > 'Z' || d2 > 'Z'){ + # error(sys->sprint("bad os reference %s", s)); + e := u*int s[0: 1+m]; + n := u*int s[1+m: 2+2*m]; + return (1, (real e, real n)); + } + e := u*int s[2: 2+m]; + n := u*int s[2+m: 2+2*m]; + if(d1 >= 'I') + d1--; + if(d2 >= 'I') + d2--; + d1 -= 'A'-3; + d2 -= 'A'; + es := 5*(d1%5)+d2%5; + ns := 5*(4-d1/5)+4-d2/5; + return (1, (real(Ngrid*es+e), real(Ngrid*ns+n))); +} + +utmlalo(lalo: Lalo): Lalo +{ + (nil, zn) := utmzone(lalo); + return utmlaloz(zn); +} + +utmlaloz(zn: int): Lalo +{ + return (0.0, deg2rad(real(6*zn-183))); +} + +utmzone(lalo: Lalo): (int, int) +{ + (la, lo) := lalo; + la = rad2deg(la); + lo = rad2deg(lo); + zlo := trunc(lo+180.0)/6+1; + if(la < -80.0) + zla := 'B'; + else if(la >= 84.0) + zla = 'Y'; + else if(la >= 72.0) + zla = 'X'; + else{ + zla = trunc(la+80.0)/8+'C'; + if(zla >= 'I') + zla++; + if(zla >= 'O') + zla++; + } + return (zla, zlo); +} + +helmertinit() +{ + (HM_WGS84_OSGB36, HM_OSGB36_WGS84) = helminit(HT_WGS84_OSGB36); + (HM_ITRS2000_ETRS89, HM_ETRS89_ITRS2000) = helminit(HT_ITRS2000_ETRS89); + HM_ETRS89_OSGB36 = mulmm(HM_WGS84_OSGB36, HM_ETRS89_ITRS2000); + HM_OSGB36_ETRS89 = mulmm(HM_ITRS2000_ETRS89, HM_OSGB36_WGS84); + HM_IDENTITY = m := matrix(3, 4); + m[0][0] = m[1][1] = m[2][2] = 1.0; + # mprint(HM_WGS84_OSGB36); + # mprint(HM_OSGB36_WGS84); +} + +helminit(h: Helmert): (array of array of real, array of array of real) +{ + m := matrix(3, 4); + + s := 1.0+h.s/1000000.0; + rx := sec2rad(h.rx); + ry := sec2rad(h.ry); + rz := sec2rad(h.rz); + + m[0][0] = s; + m[0][1] = -rz; + m[0][2] = ry; + m[0][3] = h.tx; + m[1][0] = rz; + m[1][1] = s; + m[1][2] = -rx; + m[1][3] = h.ty; + m[2][0] = -ry; + m[2][1] = rx; + m[2][2] = s; + m[2][3] = h.tz; + + return (m, inv(m)); +} + +trans(f: int, t: int): array of array of real +{ + case(f){ + WGS84 => + case(t){ + WGS84 => + return HM_IDENTITY; + OSGB36 => + return HM_WGS84_OSGB36; + ITRS2000 => + return HM_IDENTITY; + ETRS89 => + return HM_ITRS2000_ETRS89; + } + OSGB36 => + case(t){ + WGS84 => + return HM_OSGB36_WGS84; + OSGB36 => + return HM_IDENTITY; + ITRS2000 => + return HM_OSGB36_WGS84; + ETRS89 => + return HM_OSGB36_ETRS89; + } + ITRS2000 => + case(t){ + WGS84 => + return HM_IDENTITY; + OSGB36 => + return HM_WGS84_OSGB36; + ITRS2000 => + return HM_IDENTITY; + ETRS89 => + return HM_ITRS2000_ETRS89; + } + ETRS89 => + case(t){ + WGS84 => + return HM_ETRS89_ITRS2000; + OSGB36 => + return HM_ETRS89_OSGB36; + ITRS2000 => + return HM_ETRS89_ITRS2000; + ETRS89 => + return HM_IDENTITY; + } + } + return HM_IDENTITY; # Ireland65, ED50 not done +} + +datum2datum(lalo: Lalo, f: int, t: int): Lalo +{ + if(f == t) + return lalo; + (la, lo) := lalo; + v := laloh2xyz(la, lo, 0.0, dats[f].e); + v = mulmv(trans(f, t), v); + (la, lo, nil) = xyz2laloh(v, dats[t].e); + return (la, lo); +} + +laloh2xyz(φ: real, λ: real, H: real, e: int): Vector +{ + a := ells[e].a; + b := ells[e].b; + e2 := 1.0-(b/a)**2; + + s := sin(φ); + c := cos(φ); + + ν := a/sqrt(1.0-e2*s*s); + x := (ν+H)*c*cos(λ); + y := (ν+H)*c*sin(λ); + z := ((1.0-e2)*ν+H)*s; + + return (x, y, z); +} + +xyz2laloh(v: Vector, e: int): (real, real, real) +{ + x := v.x; + y := v.y; + z := v.z; + + a := ells[e].a; + b := ells[e].b; + e2 := 1.0-(b/a)**2; + + λ := atan2(y, x); + + p := sqrt(x*x+y*y); + φ := φ1 := atan(z/(p*(1.0-e2))); + ν := 0.0; + do{ + φ = φ1; + s := sin(φ); + ν = a/sqrt(1.0-e2*s*s); + φ1 = atan((z+e2*ν*s)/p); + }while(!small(fabs(φ-φ1))); + + φ = φ1; + H := p/cos(φ)-ν; + + return (φ, λ, H); +} + +lalo2en(lalo: Lalo): Eano +{ + (φ, λ) := lalo; + if(fmt.cdat != fmt.dat) + (φ, λ) = datum2datum(lalo, fmt.dat, fmt.cdat); + + s := sin(φ); + c := cos(φ); + t2 := tan(φ)**2; + + (nil, F0, φ0λ0, E0, N0, e) := *fmt.tmp; + a := ells[e].a; + b := ells[e].b; + e2 := 1.0-(b/a)**2; + + if(φ0λ0 == nil) # UTM + (φ0, λ0) := utmlalo((φ, λ)); # don't use fmt.zone here + else + (φ0, λ0) = fmt.orig; + + n := (a-b)/(a+b); + ν := a*F0/sqrt(1.0-e2*s*s); + ρ := ν*(1.0-e2)/(1.0-e2*s*s); + η2 := ν/ρ-1.0; + + φ1 := φ-φ0; + φ2 := φ+φ0; + M := b*F0*((1.0+n*(1.0+1.25*n*(1.0+n)))*φ1 - (3.0*n*(1.0+n*(1.0+0.875*n)))*sin(φ1)*cos(φ2) + 1.875*n*n*(1.0+n)*sin(2.0*φ1)*cos(2.0*φ2) - 35.0/24.0*n**3*sin(3.0*φ1)*cos(3.0*φ2)); + + I := M+N0; + II := ν*s*c/2.0; + III := ν*s*c**3*(5.0-t2+9.0*η2)/24.0; + IIIA := ν*s*c**5*(61.0+t2*(t2-58.0))/720.0; + IV := ν*c; + V := ν*c**3*(ν/ρ-t2)/6.0; + VI := ν*c**5*(5.0+14.0*η2+t2*(t2-18.0-58.0*η2))/120.0; + + λ -= λ0; + λ2 := λ*λ; + N := I+λ2*(II+λ2*(III+IIIA*λ2)); + E := E0+λ*(IV+λ2*(V+VI*λ2)); + + # if(E < 0.0 || E >= real(7*Ngrid)) + # E = 0.0; + # if(N < 0.0 || N >= real(13*Ngrid)) + # N = 0.0; + return (E, N); +} + +en2lalo(en: Eano): Lalo +{ + E := en.e; + N := en.n; + + (nil, F0, nil, E0, N0, e) := *fmt.tmp; + a := ells[e].a; + b := ells[e].b; + e2 := 1.0-(b/a)**2; + + (φ0, λ0) := fmt.orig; + + n := (a-b)/(a+b); + + M0 := 1.0+n*(1.0+1.25*n*(1.0+n)); + M1 := 3.0*n*(1.0+n*(1.0+0.875*n)); + M2 := 1.875*n*n*(1.0+n); + M3 := 35.0/24.0*n**3; + + N -= N0; + M := 0.0; + φ := φold := φ0; + do{ + φ = (N-M)/(a*F0)+φold; + φ1 := φ-φ0; + φ2 := φ+φ0; + M = b*F0*(M0*φ1 - M1*sin(φ1)*cos(φ2) + M2*sin(2.0*φ1)*cos(2.0*φ2) - M3*sin(3.0*φ1)*cos(3.0*φ2)); + φold = φ; + }while(fabs(N-M) >= 0.01); + + s := sin(φ); + c := cos(φ); + t := tan(φ); + t2 := t*t; + + ν := a*F0/sqrt(1.0-e2*s*s); + ρ := ν*(1.0-e2)/(1.0-e2*s*s); + η2 := ν/ρ-1.0; + + VII := t/(2.0*ρ*ν); + VIII := VII*(5.0+η2+3.0*t2*(1.0-3.0*η2))/(12.0*ν*ν); + IX := VII*(61.0+45.0*t2*(2.0+t2))/(360.0*ν**4); + X := 1.0/(ν*c); + XI := X*(ν/ρ+2.0*t2)/(6.0*ν*ν); + XII := X*(5.0+4.0*t2*(7.0+6.0*t2))/(120.0*ν**4); + XIIA := X*(61.0+2.0*t2*(331.0+60.0*t2*(11.0+6.0*t2)))/(5040.0*ν**6); + + E -= E0; + E2 := E*E; + φ = φ-E2*(VII-E2*(VIII-E2*IX)); + λ := λ0+E*(X-E2*(XI-E2*(XII-E2*XIIA))); + + if(fmt.cdat != fmt.dat) + (φ, λ) = datum2datum((φ, λ), fmt.cdat, fmt.dat); + return (φ, λ); +} + +mulmm(m1: array of array of real, m2: array of array of real): array of array of real +{ + m := matrix(3, 4); + mul3x3(m, m1, m2); + for(i := 0; i < 3; i++){ + sum := 0.0; + for(k := 0; k < 3; k++) + sum += m1[i][k]*m2[k][3]; + m[i][3] = sum+m1[i][3]; + } + return m; +} + +mulmv(m: array of array of real, v: Vector): Vector +{ + x := v.x; + y := v.y; + z := v.z; + v.x = m[0][0]*x + m[0][1]*y + m[0][2]*z + m[0][3]; + v.y = m[1][0]*x + m[1][1]*y + m[1][2]*z + m[1][3]; + v.z = m[2][0]*x + m[2][1]*y + m[2][2]*z + m[2][3]; + return v; +} + +inv(m: array of array of real): array of array of real +{ + n := matrix(3, 4); + inv3x3(m, n); + (n[0][3], n[1][3], n[2][3]) = mulmv(n, (-m[0][3], -m[1][3], -m[2][3])); + return n; +} + +mul3x3(m: array of array of real, m1: array of array of real, m2: array of array of real) +{ + for(i := 0; i < 3; i++){ + for(j := 0; j < 3; j++){ + sum := 0.0; + for(k := 0; k < 3; k++) + sum += m1[i][k]*m2[k][j]; + m[i][j] = sum; + } + } +} + +inv3x3(m: array of array of real, n: array of array of real) +{ + t00 := m[0][0]; + t01 := m[0][1]; + t02 := m[0][2]; + t10 := m[1][0]; + t11 := m[1][1]; + t12 := m[1][2]; + t20 := m[2][0]; + t21 := m[2][1]; + t22 := m[2][2]; + + n[0][0] = t11*t22-t12*t21; + n[1][0] = t12*t20-t10*t22; + n[2][0] = t10*t21-t11*t20; + n[0][1] = t02*t21-t01*t22; + n[1][1] = t00*t22-t02*t20; + n[2][1] = t01*t20-t00*t21; + n[0][2] = t01*t12-t02*t11; + n[1][2] = t02*t10-t00*t12; + n[2][2] = t00*t11-t01*t10; + + d := t00*n[0][0]+t01*n[1][0]+t02*n[2][0]; + for(i := 0; i < 3; i++) + for(j := 0; j < 3; j++) + n[i][j] /= d; +} + +matrix(rows: int, cols: int): array of array of real +{ + m := array[rows] of array of real; + for(i := 0; i < rows; i++) + m[i] = array[cols] of { * => 0.0 }; + return m; +} + +vprint(v: Vector) +{ + sys->print(" %f %f %f\n", v.x, v.y, v.z); +} + +mprint(m: array of array of real) +{ + for(i := 0; i < len m; i++){ + for(j := 0; j < len m[i]; j++) + sys->print(" %f", m[i][j]); + sys->print("\n"); + } +} + +# lalo2xy(la: real, lo: real, lalo: ref Latlong): Eano +# { +# x, y: real; +# +# la0 := lalo.la; +# lo0 := lalo.lo; +# if(Approx){ +# x = Earthrad*cos(la0)*(lo-lo0)+lalo.x; +# y = Earthrad*(la-la0)+lalo.y; +# } +# else{ +# x = Earthrad*cos(la)*sin(lo-lo0)+lalo.x; +# y = Earthrad*(sin(la)*cos(la0)-sin(la0)*cos(la)*cos(lo-lo0))+lalo.y; +# } +# return (x, y); +# } + +# lalo2xyz(la: real, lo: real, lalo: ref Latlong): (int, int, int) +# { +# z: real; +# +# la0 := lalo.la; +# lo0 := lalo.lo; +# (x, y) := lalo2xy(la, lo, lalo); +# if(Approx) +# z = Earthrad; +# else +# z = Earthrad*(sin(la)*sin(la0)+cos(la)*cos(la0)*cos(lo-lo0)); +# return (x, y, int z); +# } + +# xy2lalo(p: Eano, lalo: ref Latlong): (real, real) +# { +# la, lo: real; +# +# x := p.e; +# y := p.n; +# la0 := lalo.la; +# lo0 := lalo.lo; +# if(Approx){ +# la = la0 + (y-lalo.y)/Earthrad; +# lo = lo0 + (x-lalo.x)/(Earthrad*cos(la0)); +# } +# else{ +# a, b, c, d, bestd, r, r1, r2, lat, lon, tmp: real; +# i, n: int; +# +# bestd = -1.0; +# la = lo = 0.0; +# a = (x-lalo.x)/Earthrad; +# b = (y-lalo.y)/Earthrad; +# (n, r1, r2) = quad(1.0, -2.0*b*cos(la0), (a*a-1.0)*sin(la0)*sin(la0)+b*b); +# if(n == 0) +# return (la, lo); +# while(--n >= 0){ +# if(n == 1) +# r = r2; +# else +# r = r1; +# if(fabs(r) <= 1.0){ +# lat = asin(r); +# c = cos(lat); +# if(small(c)) +# tmp = 0.0; # lat = +90, -90, lon = lo0 +# else +# tmp = a/c; +# if(fabs(tmp) <= 1.0){ +# for(i = 0; i < 2; i++){ +# if(i == 0) +# lon = norm(asin(tmp)+lo0); +# else +# lon = norm(Pi-asin(tmp)+lo0); +# (X, Y, Z) := lalo2xyz(lat, lon, lalo); +# # eliminate non-roots by d, root on other side of earth by Z +# d = (real X-x)**2+(real Y-y)**2; +# if(Z >= 0 && (bestd < 0.0 || d < bestd)){ +# bestd = d; +# la = lat; +# lo = lon; +# } +# } +# } +# } +# } +# } +# return (la, lo); +# } + +# quad(a: real, b: real, c: real): (int, real, real) +# { +# r1, r2: real; +# +# D := b*b-4.0*a*c; +# if(small(a)){ +# if(small(b)) +# return (0, r1, r2); +# r1 = r2 = -c/b; +# return (1, r1, r2); +# } +# if(D < 0.0) +# return (0, r1, r2); +# D = sqrt(D); +# r1 = (-b+D)/(2.0*a); +# r2 = (-b-D)/(2.0*a); +# if(small(D)) +# return (1, r1, r2); +# else +# return (2, r1, r2); +# } + +d2(v: int): string +{ + s := string v; + if(v < 10) + s = "0" + s; + return s; +} + +trim(s: string, t: string): string +{ + while(s != nil && strchr(t, s[0]) >= 0) + s = s[1: ]; + while(s != nil && strchr(t, s[len s-1]) >= 0) + s = s[0: len s-1]; + return s; +} + +strchrs(s: string, t: string): int +{ + for(i := 0; i < len t; i++){ + p := strchr(s, t[i]); + if(p >= 0) + return p; + } + return -1; +} + +strchr(s: string, c: int): int +{ + for(i := 0; i < len s; i++) + if(s[i] == c) + return i; + return -1; +} + +deg2rad(d: real): real +{ + return d*Pi/180.0; +} + +rad2deg(r: real): real +{ + return r*180.0/Pi; +} + +sec2rad(s: real): real +{ + return deg2rad(s/3600.0); +} + +norm(r: real): real +{ + while(r > Pi) + r -= 2.0*Pi; + while(r < -Pi) + r += 2.0*Pi; + return r; +} + +small(r: real): int +{ + return r > -Epsilon && r < Epsilon; +} + +trunc(r: real): int +{ + # down : assumes r >= 0 + i := int r; + if(real i > r) + i--; + return i; +} + +abs(x: int): int +{ + if(x < 0) + return -x; + return x; +} diff --git a/appl/math/gr.b b/appl/math/gr.b new file mode 100644 index 00000000..46899353 --- /dev/null +++ b/appl/math/gr.b @@ -0,0 +1,557 @@ +implement GR; + +include "sys.m"; + sys: Sys; + print, sprint: import sys; +include "math.m"; + math: Math; + ceil, fabs, floor, Infinity, log10, pow10, sqrt: import math; +include "draw.m"; + screen: ref Draw->Screen; +include "tk.m"; + tk: Tk; + Toplevel: import tk; +include "tkclient.m"; + tkclient: Tkclient; +include "gr.m"; + +gr_cfg := array[] of { + "frame .fc", + "frame .fc.b", + "label .fc.b.xy -text {0 0} -anchor e", + "pack .fc.b.xy -fill x", + "pack .fc.b -fill both -expand 1", + "canvas .fc.c -relief sunken -bd 2 -width 600 -height 480 -bg white"+ + " -font /fonts/lucidasans/unicode.8.font", + "pack .fc.c -fill both -expand 1", + "pack .Wm_t -fill x", + "pack .fc -fill both -expand 1", + "pack propagate . 0", + "bind .fc.c <ButtonPress-1> {send grcmd down1,%x,%y}", +}; + +TkCmd(t: ref Toplevel, arg: string): string +{ + rv := tk->cmd(t,arg); + if(rv!=nil && rv[0]=='!') + print("tk->cmd(%s): %s\n",arg,rv); + return rv; +} + + +open(ctxt: ref Draw->Context, title: string): ref Plot +{ + if(sys==nil){ + sys = load Sys Sys->PATH; + math = load Math Math->PATH; + tk = load Tk Tk->PATH; + tkclient = load Tkclient Tkclient->PATH; + tkclient->init(); + } + textsize := 8.; # textsize is in points, if no user transform + (t, tb) := tkclient->toplevel(ctxt, "", title, Tkclient->Appl); + cc := chan of string; + tk->namechan(t, cc, "grcmd"); + p := ref Plot(nil, Infinity,-Infinity,Infinity,-Infinity, textsize, t, tb, cc); + for (i:=0; i<len gr_cfg; i++) + tk->cmd(p.t,gr_cfg[i]); + tkclient->onscreen(p.t, nil); + tkclient->startinput(p.t, "kbd"::"ptr"::nil); + return p; +} + +Plot.bye(p: self ref Plot) +{ + cmdloop: for(;;) alt { + s := <-p.t.ctxt.kbd => + tk->keyboard(p.t, s); + s := <-p.t.ctxt.ptr => + tk->pointer(p.t, *s); + s := <-p.t.ctxt.ctl or + s = <-p.t.wreq or + s = <-p.titlechan => + if(s == "exit") + break cmdloop; + tkclient->wmctl(p.t, s); + case s{ + "size" => + canvw := int TkCmd(p.t, ".fc.c cget -width"); + canvh := int TkCmd(p.t, ".fc.c cget -height"); + TkCmd(p.t,".fc.b.xy configure -text {"+sprint("%d %d",canvw,canvh)+"}"); + } + press := <-p.canvaschan => + (nil,cmds) := sys->tokenize(press,","); + if(cmds==nil) continue; + case hd cmds { + "down1" => + xpos := real(hd tl cmds); + ypos := real(hd tl tl cmds); + x := (xpos-bx)/ax; + y := -(ypos-tky+by)/ay; + TkCmd(p.t,".fc.b.xy configure -text {"+sprint("%.3g %.3g",x,y)+"}"); + } + } + TkCmd(p.t,"destroy .;update"); + p.t = nil; +} + +Plot.equalxy(p: self ref Plot) +{ + r := 0.; + if( r < p.xmax - p.xmin ) r = p.xmax - p.xmin; + if( r < p.ymax - p.ymin ) r = p.ymax - p.ymin; + m := (p.xmax + p.xmin)/2.; + p.xmax = m + r/2.; + p.xmin = m - r/2.; + m = (p.ymax + p.ymin)/2.; + p.ymax = m + r/2.; + p.ymin = m - r/2.; +} + +Plot.graph(p: self ref Plot, x, y: array of real) +{ + n := len x; + op := OP(GR->GRAPH, n, array[n] of real, array[n] of real, nil); + while(n--){ + t := x[n]; + op.x[n] = t; + if(t < p.xmin) + p.xmin = t; + if(t > p.xmax) + p.xmax = t; + t = y[n]; + op.y[n] = t; + if(t < p.ymin) + p.ymin = t; + if(t > p.ymax) + p.ymax = t; + } + p.op = op :: p.op; +} + +Plot.text(p: self ref Plot, justify: int, s: string, x, y: real) +{ + op := OP(GR->TEXT, justify, array[1] of real, array[1] of real, s); + op.x[0] = x; + op.y[0] = y; + p.op = op :: p.op; +} + +Plot.pen(p: self ref Plot, nib: int) +{ + p.op = OP(GR->PEN, nib, nil, nil, nil) :: p.op; +} + + +#--------------------------------------------------------- +# The rest of this file is concerned with sending the "display list" +# to Tk. The only interesting parts of the problem are picking axes +# and drawing dashed lines properly. + +ax, bx, ay, by: real; # transform user to pixels +tky: con 630.; # Tk_y = tky - y +nseg: int; # how many segments in current stroke path +pendown: int; # is pen currently drawing? +xoff := array[] of{"w","","e"}; # LJUST, CENTER, RJUST +yoff := array[] of{"n","","s","s"}; # HIGH, MED, BASE, LOW +linewidth: real; +toplevel: ref Toplevel; # p.t +tkcmd: string; + +mv(x, y: real) +{ + tkcmd = sprint(".fc.c create line %.1f %.1f", ax*x+bx, tky-(ay*y+by)); +} + +stroke() +{ + if(pendown){ + tkcmd += " -width 3"; # -capstyle round -joinstyle round + TkCmd(toplevel,tkcmd); + tkcmd = nil; + pendown = 0; + nseg = 0; + } +} + +vec(x, y: real) +{ + tkcmd += sprint(" %.1f %.1f", ax*x+bx, tky-(ay*y+by)); + pendown = 1; + nseg++; + if(nseg>1000){ + stroke(); + mv(x,y); + } +} + +circle(u, v, radius: real) +{ + x := ax*u+bx; + y := tky-(ay*v+by); + r := radius*(ax+ay)/2.; + tkcmd = sprint(".fc.c create oval %.1f %.1f %.1f %.1f -width 3", + x-r, y-r, x+r, y+r); + TkCmd(toplevel,tkcmd); + tkcmd = nil; +} + +text(s: string, x, y: real, xoff, yoff: string) +{ + # rot = rotation in degrees. 90 is used for y-axis + # x,y are in PostScript coordinate system, not user + anchor := yoff + xoff; + if(anchor!="") + anchor = "-anchor " + anchor + " "; + tkcmd = sprint(".fc.c create text %.1f %.1f %s-text '%s", + ax*x+bx, + tky-(ay*y+by), anchor, s); + TkCmd(toplevel,tkcmd); + tkcmd = nil; +} + +datarange(xmin, xmax, margin: real): (real,real) +{ + r := 1.e-30; + if( r < 0.001*fabs(xmin) ) + r = 0.001*fabs(xmin); + if( r < 0.001*fabs(xmax) ) + r = 0.001*fabs(xmax); + if( r < xmax-xmin ) + r = xmax-xmin; + r *= 1.+2.*margin; + x0 :=(xmin+xmax)/2. - r/2.; + return ( x0, x0 + r); +} + +dashed(ndash: int, x, y: array of real) +{ + cx, cy: real; # current position + d: real; # length undone in p[i],p[i+1] + t: real; # length undone in current dash + n := len x; + if(n!=len y || n<=0) + return; + + # choose precise dashlen + s := 0.; + for(i := 0; i < n - 1; i += 1){ + u := x[i+1] - x[i]; + v := y[i+1] - y[i]; + s += sqrt(u*u + v*v); + } + i = int floor(real ndash * s); + if(i < 2) + i = 2; + dashlen := s / real(2 * i - 1); + + t = dashlen; + ink := 1; + mv(x[0], y[0]); + cx = x[0]; + cy = y[0]; + for(i = 0; i < n - 1; i += 1){ + u := x[i+1] - x[i]; + v := y[i+1] - y[i]; + d = sqrt(u * u + v * v); + if(d > 0.){ + u /= d; + v /= d; + while(t <= d){ + cx += t * u; + cy += t * v; + if(ink){ + vec(cx, cy); + stroke(); + }else{ + mv(cx, cy); + } + d -= t; + t = dashlen; + ink = 1 - ink; + } + cx = x[i+1]; + cy = y[i+1]; + if(ink){ + vec(cx, cy); + }else{ + mv(cx, cy); + } + t -= d; + } + } + stroke(); +} + +labfmt(x:real): string +{ + lab := sprint("%.6g",x); + if(len lab>2){ + if(lab[0]=='0' && lab[1]=='.') + lab = lab[1:]; + else if(lab[0]=='-' && len lab>3 && lab[1]=='0' && lab[2]=='.') + lab = "-"+lab[2:]; + } + return lab; +} + +Plot.paint(p: self ref Plot, xlabel, xunit, ylabel, yunit: string) +{ + oplist: list of OP; + + # tunable parameters for dimensions of graph (fraction of box side) + margin: con 0.075; # separation of data from box boundary + ticksize := 0.02; + sep := ticksize; # separation of text from box boundary + + # derived coordinates of various feature points... + x0, x1, y0, y1: real; # box corners, in original coord + # radius := 0.2*p.textsize; # radius for circle marker + radius := 0.8*p.textsize; # radius for circle marker + + Pen := SOLID; + width := SOLID; + linewidth = 2.; + nseg = 0; + pendown = 0; + + if(xunit=="") xunit = nil; + if(yunit=="") yunit = nil; + + (x0,x1) = datarange(p.xmin,p.xmax,margin); + ax = (400.-2.*p.textsize)/((x1-x0)*(1.+2.*sep)); + bx = 506.-ax*x1; + (y0,y1) = datarange(p.ymin,p.ymax,margin); + ay = (400.-2.*p.textsize)/((y1-y0)*(1.+2.*sep)); + by = 596.-ay*y1; + # PostScript version + # magic numbers here come from BoundingBox: 106 196 506 596 + # (x0,x1) = datarange(p.xmin,p.xmax,margin); + # ax = (400.-2.*p.textsize)/((x1-x0)*(1.+2.*sep)); + # bx = 506.-ax*x1; + # (y0,y1) = datarange(p.ymin,p.ymax,margin); + # ay = (400.-2.*p.textsize)/((y1-y0)*(1.+2.*sep)); + # by = 596.-ay*y1; + + # convert from fraction of box to PostScript units + ticksize *= ax*(x1-x0); + sep *= ax*(x1-x0); + + # revert to original drawing order + log := p.op; + oplist = nil; + while(log!=nil){ + oplist = hd log :: oplist; + log = tl log; + } + p.op = oplist; + + toplevel = p.t; + #------------send display list to Tk----------------- + while(oplist!=nil){ + op := hd oplist; + n := op.n; + case op.code{ + GRAPH => + if(Pen == DASHED){ + dashed(17, op.x, op.y); + }else if(Pen == DOTTED){ + dashed(85, op.x, op.y); + }else{ + for(i:=0; i<n; i++){ + xx := op.x[i]; + yy := op.y[i]; + if(Pen == CIRCLE){ + circle(xx, yy, radius/(ax+ay)); + }else if(Pen == CROSS){ + mv(xx-radius/ax, yy); + vec(xx+radius/ax, yy); + stroke(); + mv(xx, yy-radius/ay); + vec(xx, yy+radius/ay); + stroke(); + }else if(Pen == INVIS){ + }else{ + if(i==0){ + mv(xx, yy); + }else{ + vec(xx, yy); + } + } + } + stroke(); + } + TEXT => + angle := 0.; + if(op.n&UP) angle = 90.; + text(op.t,op.x[0],op.y[0],xoff[n&7],yoff[(n>>3)&7]); + PEN => + Pen = n; + if( Pen==SOLID && width!=SOLID ){ + linewidth = 2.; + width=SOLID; + }else if( Pen==REFERENCE && width!=REFERENCE ){ + linewidth = 0.8; + width=REFERENCE; + } + } + oplist = tl oplist; + } + + #--------------------now add axes----------------------- + mv(x0,y0); + vec(x1,y0); + vec(x1,y1); + vec(x0,y1); + vec(x0,y0); + stroke(); + + # x ticks + (lab1,labn,labinc,k,u,s) := mytic(x0,x1); + for (i := lab1; i <= labn; i += labinc){ + r := real i*s*u; + mv(r,y0); + vec(r,y0+ticksize/ay); + stroke(); + mv(r,y1); + vec(r,y1-ticksize/ay); + stroke(); + text(labfmt(real i*s),r,y0-sep/ay,"","n"); + } + yy := y0-(2.*sep+p.textsize)/ay; + labelstr := ""; + if(xlabel!=nil) + labelstr = xlabel; + if(k!=0||xunit!=nil) + labelstr += " /"; + if(k!=0) + labelstr += " ₁₀"+ string k; + if(xunit!=nil) + labelstr += " " + xunit; + text(labelstr,(x0+x1)/2.,yy,"","n"); + + # y ticks + (lab1,labn,labinc,k,u,s) = mytic(y0,y1); + for (i = lab1; i <= labn; i += labinc){ + r := real i*s*u; + mv(x0,r); + vec(x0+ticksize/ax,r); + stroke(); + mv(x1,r); + vec(x1-ticksize/ax,r); + stroke(); + text(labfmt(real i*s),x0-sep/ax,r,"e",""); + } + xx := x0-(4.*sep+p.textsize)/ax; + labelstr = ""; + if(ylabel!=nil) + labelstr = ylabel; + if(k!=0||yunit!=nil) + labelstr += " /"; + if(k!=0) + labelstr += " ₁₀"+ string k; + if(yunit!=nil) + labelstr += " " + yunit; + text(labelstr,xx,(y0+y1)/2.,"e",""); + + TkCmd(p.t, "update"); +} + + + +# automatic tic choice Eric Grosse 9 Dec 84 +# Input: low and high endpoints of expanded data range +# Output: lab1, labn, labinc, k, u, s where the tics are +# (lab1*s, (lab1+labinc)*s, ..., labn*s) * 10^k +# and u = 10^k. k is metric, i.e. k=0 mod 3. + +max3(a, b, c: real): real +{ + if(a<b) a=b; + if(a<c) a=c; + return(a); +} + +my_mod(i, n: int): int +{ + while(i< 0) i+=n; + while(i>=n) i-=n; + return(i); +} + +mytic(l, h: real): (int,int,int,int,real,real) +{ + lab1, labn, labinc, k, nlab, j, ndig, t1, tn: int; + u, s: real; + eps := .0001; + k = int floor( log10((h-l)/(3.+eps)) ); + u = pow10(k); + t1 = int ceil(l/u-eps); + tn = int floor(h/u+eps); + lab1 = t1; + labn = tn; + labinc = 1; + nlab = labn - lab1 + 1; + if( nlab>5 ){ + lab1 = t1 + my_mod(-t1,2); + labn = tn - my_mod( tn,2); + labinc = 2; + nlab = (labn-lab1)/labinc + 1; + if( nlab>5 ){ + lab1 = t1 + my_mod(-t1,5); + labn = tn - my_mod( tn,5); + labinc = 5; + nlab = (labn-lab1)/labinc + 1; + if( nlab>5 ){ + u *= 10.; + k++; + lab1 = int ceil(l/u-eps); + labn = int floor(h/u+eps); + nlab = labn - lab1 + 1; + labinc = 1; + } else if( nlab<3 ){ + lab1 = t1 + my_mod(-t1,4); + labn = tn - my_mod( tn,4); + labinc = 4; + nlab = (labn-lab1)/labinc + 1; + } + } + } + ndig = int(1.+floor(log10(max3(fabs(real lab1),fabs(real labn),1.e-30)))); + if( ((k<=0)&&(k>=-ndig)) # no zeros have to be added + || ((k<0)&&(k>=-3)) + || ((k>0)&&(ndig+k<=4)) ){ # even with zeros, label is small + s = u; + k = 0; + u = 1.; + }else if(k>0){ + s = 1.; + j = ndig; + while(k%3!=0){ + k--; + u/=10.; + s*=10.; + j++; + } + if(j-3>0){ + k+=3; + u*=1000.; + s/=1000.; + } + }else{ # k<0 + s = 1.; + j = ndig; + while(k%3!=0){ + k++; + u*=10.; + s/=10.; + j--; + } + if(j<0){ + k-=3; + u/=1000.; + s*=1000.; + } + } + return (lab1, labn, labinc, k, u, s); +} diff --git a/appl/math/graph0.b b/appl/math/graph0.b new file mode 100644 index 00000000..1e016b51 --- /dev/null +++ b/appl/math/graph0.b @@ -0,0 +1,84 @@ +implement Graph0; + +include "sys.m"; + sys: Sys; + print: import sys; + +include "draw.m"; +include "tk.m"; + tk: Tk; + +include "bufio.m"; + bufio: Bufio; + Iobuf: import bufio; + +include "gr.m"; + gr: GR; + Plot: import gr; + +Graph0: module{ + init: fn(nil: ref Draw->Context, argv: list of string); +}; + + +plotfile(ctxt: ref Draw->Context, nil: list of string, filename: string){ + p := gr->open(ctxt,filename); + input := bufio->open(filename,bufio->OREAD); + if(input==nil){ + print("can't read %s",filename); + exit; + } + + n := 0; + maxn := 100; + x := array[maxn] of real; + y := array[maxn] of real; + while(1){ + xn := input.gett(" \t\n\r"); + if(xn==nil) + break; + yn := input.gett(" \t\n\r"); + if(yn==nil){ + print("after reading %d pairs, saw singleton\n",n); + exit; + } + if(n>=maxn){ + maxn *= 2; + newx := array[maxn] of real; + newy := array[maxn] of real; + for(i:=0; i<n; i++){ + newx[i] = x[i]; + newy[i] = y[i]; + } + x = newx; + y = newy; + } + x[n] = real xn; + y[n] = real yn; + n++; + } + if(n==0){ + print("empty input\n"); + exit; + } + + p.graph(x[0:n],y[0:n]); + p.pen(GR->CIRCLE); + p.graph(x[0:n],y[0:n]); + p.paint("",nil,"",nil); + p.bye(); +} + +init(ctxt: ref Draw->Context, argv: list of string){ + sys = load Sys Sys->PATH; + tk = load Tk Tk->PATH; + bufio = load Bufio Bufio->PATH; + if((gr = load GR GR->PATH) == nil){ + sys->print("%s: Can't load gr\n",hd argv); + exit; + } + + argv = tl argv; + if(argv!=nil) + plotfile(ctxt,argv,hd argv); +} diff --git a/appl/math/hist0.b b/appl/math/hist0.b new file mode 100644 index 00000000..0484c98b --- /dev/null +++ b/appl/math/hist0.b @@ -0,0 +1,99 @@ +implement Hist0; + +include "sys.m"; + sys: Sys; + print: import sys; +include "math.m"; + math: Math; + fmin: import math; + +include "draw.m"; +include "tk.m"; + tk: Tk; + +include "bufio.m"; + bufio: Bufio; + Iobuf: import bufio; + +include "gr.m"; + gr: GR; + Plot: import gr; + +Hist0: module{ + init: fn(nil: ref Draw->Context, argv: list of string); +}; + + +plotfile(ctxt: ref Draw->Context, nil: list of string, filename: string){ + p := gr->open(ctxt,filename); + input := bufio->open(filename,bufio->OREAD); + if(input==nil){ + print("can't read %s",filename); + exit; + } + + n := 0; + maxn := 100; + x := array[maxn] of real; + y := array[maxn] of real; + while(1){ + xn := input.gett(" \t\n\r"); + if(xn==nil) + break; + yn := input.gett(" \t\n\r"); + if(yn==nil){ + print("after reading %d pairs, saw singleton\n",n); + exit; + } + if(n>=maxn){ + maxn *= 2; + newx := array[maxn] of real; + newy := array[maxn] of real; + for(i:=0; i<n; i++){ + newx[i] = x[i]; + newy[i] = y[i]; + } + x = newx; + y = newy; + } + x[n] = real xn; + y[n] = real yn; + n++; + } + if(n==0){ + print("empty input\n"); + exit; + } + + for(i:=0; i<n; i++){ + h := 0.2; + if(i==0) h *= x[i+1]-x[i]; + else if(i==n-1) h *= x[i]-x[i-1]; + else h *= fmin(x[i+1]-x[i],x[i]-x[i-1]); + barx := array[] of{x[i]-h,x[i]-h,x[i]+h,x[i]+h,x[i]-h}; + bary := array[] of{0.,y[i],y[i],0.,0.}; + p.graph(barx,bary); + } + p.paint("",nil,"",nil); + p.bye(); +} + +init(ctxt: ref Draw->Context, argv: list of string){ + sys = load Sys Sys->PATH; + math = load Math Math->PATH; + tk = load Tk Tk->PATH; + bufio = load Bufio Bufio->PATH; + if((gr = load GR GR->PATH) == nil){ + sys->print("%s: Can't load gr\n",hd argv); + exit; + } + + tkargs := ""; + argv = tl argv; + if(argv != nil) { + tkargs = hd argv; + argv = tl argv; + } + if(argv!=nil) + plotfile(ctxt,argv,hd argv); +} diff --git a/appl/math/linalg.b b/appl/math/linalg.b new file mode 100644 index 00000000..5477c4ca --- /dev/null +++ b/appl/math/linalg.b @@ -0,0 +1,197 @@ +implement LinAlg; + +include "sys.m"; +sys: Sys; +print: import sys; + +include "math.m"; +math: Math; +ceil, fabs, floor, Infinity, log10, pow10, sqrt: import math; +dot, gemm, iamax: import math; + +include "linalg.m"; + +# print a matrix in MATLAB-compatible format +printmat(label:string, a:array of real, lda, m, n:int) +{ + if(m>30 || n>10) + return; + if(sys==nil){ + sys = load Sys Sys->PATH; + math = load Math Math->PATH; + } + print("%% %d by %d matrix\n",m,n); + print("%s = [",label); + for(i:=0; i<m; i++){ + print("%.4g",a[i]); + for(j:=1; j<n; j++) + print(", %.4g",a[i+lda*j]); + if(i==m-1) + print("]\n"); + else + print(";\n"); + } +} + + +# Constant times a vector plus a vector. +daxpy(da:real, dx:array of real, dy:array of real) +{ + n := len dx; + gemm('N','N',n,1,n,da,nil,0,dx,n,1.,dy,n); +} + +# Scales a vector by a constant. +dscal(da:real, dx:array of real) +{ + n := len dx; + gemm('N','N',n,1,n,0.,nil,0,nil,0,da,dx,n); +} + +# gaussian elimination with partial pivoting +# dgefa factors a double precision matrix by gaussian elimination. +# dgefa is usually called by dgeco, but it can be called +# directly with a saving in time if rcond is not needed. +# (time for dgeco) = (1 + 9/n)*(time for dgefa) . +# on entry +# a REAL precision[n][lda] +# the matrix to be factored. +# lda integer +# the leading dimension of the array a . +# n integer +# the order of the matrix a . +# on return +# a an upper triangular matrix and the multipliers +# which were used to obtain it. +# the factorization can be written a = l*u where +# l is a product of permutation and unit lower +# triangular matrices and u is upper triangular. +# ipvt integer[n] +# an integer vector of pivot indices. +# info integer +# = 0 normal value. +# = k if u[k][k] .eq. 0.0 . this is not an error +# condition for this subroutine, but it does +# indicate that dgesl or dgedi will divide by zero +# if called. use rcond in dgeco for a reliable +# indication of singularity. +dgefa(a:array of real, lda, n:int, ipvt:array of int): int +{ + if(sys==nil){ + sys = load Sys Sys->PATH; + math = load Math Math->PATH; + } + info := 0; + nm1 := n - 1; + if(nm1 >= 0) + for(k := 0; k < nm1; k++){ + kp1 := k + 1; + ldak := lda*k; + + # find l = pivot index + l := iamax(a[ldak+k:ldak+n]) + k; + ipvt[k] = l; + + # zero pivot implies this column already triangularized + if(a[ldak+l]!=0.){ + + # interchange if necessary + if(l!=k){ + t := a[ldak+l]; + a[ldak+l] = a[ldak+k]; + a[ldak+k] = t; + } + + # compute multipliers + t := -1./a[ldak+k]; + dscal(t,a[ldak+k+1:ldak+n]); + + # row elimination with column indexing + for(j := kp1; j < n; j++){ + ldaj := lda*j; + t = a[ldaj+l]; + if(l!=k){ + a[ldaj+l] = a[ldaj+k]; + a[ldaj+k] = t; + } + daxpy(t,a[ldak+k+1:ldak+n],a[ldaj+k+1:ldaj+n]); + } + }else + info = k; + } + ipvt[n-1] = n-1; + if(a[lda*(n-1)+(n-1)] == 0.) + info = n-1; + return info; +} + + +# dgesl solves the double precision system +# a * x = b or trans(a) * x = b +# using the factors computed by dgeco or dgefa. +# on entry +# a double precision[n][lda] +# the output from dgeco or dgefa. +# lda integer +# the leading dimension of the array a . +# n integer +# the order of the matrix a . +# ipvt integer[n] +# the pivot vector from dgeco or dgefa. +# b double precision[n] +# the right hand side vector. +# job integer +# = 0 to solve a*x = b , +# = nonzero to solve trans(a)*x = b where +# trans(a) is the transpose. +# on return +# b the solution vector x . +# error condition +# a division by zero will occur if the input factor contains a +# zero on the diagonal. technically this indicates singularity +# but it is often caused by improper arguments or improper +# setting of lda. +dgesl(a:array of real, lda, n:int, ipvt:array of int, b:array of real, job:int) +{ + nm1 := n - 1; + if(job == 0){ # job = 0 , solve a * x = b + # first solve l*y = b + if(nm1 >= 1) + for(k := 0; k < nm1; k++){ + l := ipvt[k]; + t := b[l]; + if(l!=k){ + b[l] = b[k]; + b[k] = t; + } + daxpy(t,a[lda*k+k+1:lda*k+n],b[k+1:n]); + } + + # now solve u*x = y + for(kb := 0; kb < n; kb++){ + k = n - (kb + 1); + b[k] = b[k]/a[lda*k+k]; + t := -b[k]; + daxpy(t,a[lda*k:lda*k+k],b[0:k]); + } + }else{ # job = nonzero, solve trans(a) * x = b + # first solve trans(u)*y = b + for(k := 0; k < n; k++){ + t := dot(a[lda*k:lda*k+k],b[0:k]); + b[k] = (b[k] - t)/a[lda*k+k]; + } + + # now solve trans(l)*x = y + if(nm1 >= 1) + for(kb := 1; kb < nm1; kb++){ + k = n - (kb+1); + b[k] += dot(a[lda*k+k+1:lda*k+n],b[k+1:n]); + l := ipvt[k]; + if(l!=k){ + t := b[l]; + b[l] = b[k]; + b[k] = t; + } + } + } +} diff --git a/appl/math/linbench.b b/appl/math/linbench.b new file mode 100644 index 00000000..1857093a --- /dev/null +++ b/appl/math/linbench.b @@ -0,0 +1,197 @@ +# Translated to Limbo by Eric Grosse <ehg@netlib.bell-labs.com> 3/96 +# Translated to Java by Reed Wade (wade@cs.utk.edu) 2/96 +# Translated to C by Bonnie Toy 5/88 +# Will Menninger, 10/93 +# Jack Dongarra, linpack, 3/11/78. +# Cleve Moler, linpack, 08/14/78 + +implement linbench; + +include "sys.m"; + sys: Sys; + print: import sys; +include "math.m"; + math: Math; + dot, fabs, gemm, iamax: import math; +include "draw.m"; + draw: Draw; + Rect, Screen, Display, Image: import draw; +include "tk.m"; + tk: Tk; + Toplevel: import tk; +include "tkclient.m"; + tkclient: Tkclient; +include "bufio.m"; + bufio: Bufio; + Iobuf: import bufio; +include "linalg.m"; + linalg: LinAlg; + dgefa, dgesl, printmat: import linalg; + +ctxt: ref Draw->Context; +top: ref Tk->Toplevel; +buttonlist: string; + + +linbench: module +{ + init: fn(nil: ref Draw->Context, argv: list of string); +}; + +tkcmd(arg: string): string{ + rv := tk->cmd(top,arg); + if(rv!=nil && rv[0]=='!') + print("tk->cmd(%s): %s\n",arg,rv); + return rv; +} + +init(xctxt: ref Draw->Context, nil: list of string) +{ + sys = load Sys Sys->PATH; + math = load Math Math->PATH; + draw = load Draw Draw->PATH; + tk = load Tk Tk->PATH; + tkclient = load Tkclient Tkclient->PATH; + linalg = load LinAlg LinAlg->PATH; + if(linalg==nil) print("couldn't load LinAlg\n"); + sys->pctl(Sys->NEWPGRP, nil); + tkclient->init(); + ctxt = xctxt; + menubut: chan of string; + (top, menubut) = tkclient->toplevel(ctxt, "", + "Linpack in Limbo", Tkclient->Appl); + cmd := chan of string; + tk->namechan(top, cmd, "cmd"); + + tkcmd("pack .Wm_t -fill x"); + tkcmd("frame .b"); + tkcmd("button .b.Run -text Run -command {send cmd run}"); + tkcmd("entry .b.N -width 10w"); tkcmd(".b.N insert 0 200"); + tkcmd("pack .b.Run .b.N -side left"); + tkcmd("pack .b -anchor w"); + tkcmd("frame .d"); + tkcmd("listbox .d.f -width 35w -height 150 -selectmode single -yscrollcommand {.d.fscr set}"); + tkcmd("scrollbar .d.fscr -command {.d.f yview}"); + tkcmd("pack .d.f .d.fscr -expand 1 -fill y -side right"); + tkcmd("pack .d -side top"); + tkcmd("focus .b.N"); + tkcmd("pack propagate . 0;update"); + tkclient->onscreen(top, nil); + tkclient->startinput(top, "kbd"::"ptr"::nil); + + for(;;) alt { + s := <-top.ctxt.kbd => + tk->keyboard(top, s); + s := <-top.ctxt.ptr => + tk->pointer(top, *s); + s := <-top.ctxt.ctl or + s = <-top.wreq or + s = <-menubut => + tkclient->wmctl(top, s); + press := <-cmd => + case press { + "run" => + tkcmd("cursor -bitmap cursor.wait; update"); + nstr := tkcmd(".b.N get"); + n := int nstr; + (mflops,secs) := benchmark(n); + result := sys->sprint("%8.2f Mflops %8.1f secs",mflops,secs); + tkcmd("cursor -default"); + tkcmd(".d.f insert end {" + result + "}"); + tkcmd(".d.f yview moveto 1; update"); + } + } +} + +benchmark(n: int): (real,real) +{ + math = load Math Math->PATH; + + time := array [2] of real; + lda := 201; + if(n>lda) lda = n; + a := array [lda*n] of real; + b := array [n] of real; + x := array [n] of real; + ipvt := array [n] of int; + ops := (2*n*n*n)/3 + 2*n*n; + + norma := matgen(a,lda,n,b); + printmat("a",a,lda,n,n); + printmat("b",b,lda,n,1); + t1 := second(); + dgefa(a,lda,n,ipvt); + time[0] = second() - t1; + printmat("a",a,lda,n,n); + t1 = second(); + dgesl(a,lda,n,ipvt,b,0); + time[1] = second() - t1; + total := time[0] + time[1]; + + for(i := 0; i < n; i++) { + x[i] = b[i]; + } + printmat("x",x,lda,n,1); + norma = matgen(a,lda,n,b); + for(i = 0; i < n; i++) { + b[i] = -b[i]; + } + dmxpy(b,x,a,lda); + resid := 0.; + normx := 0.; + for(i = 0; i < n; i++){ + if(resid<fabs(b[i])) resid = fabs(b[i]); + if(normx<fabs(x[i])) normx = fabs(x[i]); + } + + eps_result := math->MachEps; + residn_result := (real n)*norma*normx*eps_result; + if(residn_result!=0.) + residn_result = resid/residn_result; + else + print("can't scale residual."); + if(residn_result>math->sqrt(real n)) + print("resid/MachEps=%.3g\n",residn_result); + time_result := total; + mflops_result := 0.; + if(total!=0.) + mflops_result = real ops/(1e6*total); + else + print("can't measure time\n"); + return (mflops_result,time_result); +} + + +# multiply matrix m times vector x and add the r_result to vector y. +dmxpy(y, x, m:array of real, ldm: int) +{ + n1 := len y; + n2 := len x; + gemm('N','N',n1,1,n2,1.,m,ldm,x,n2,1.,y,n1); +} + +second(): real +{ + return(real sys->millisec()/1000.); +} + + +# generate a (fixed) random matrix and right hand side +# a[i][j] => a[lda*i+j] +matgen(a: array of real, lda, n: int, b: array of real): real +{ + seed := 1325; + norma := 0.; + for(j := 0; j < n; j++) + for(i := 0; i < n; i++){ + seed = 3125*seed % 65536; + a[lda*j+i] = (real seed - 32768.0)/16384.0; + if(norma < a[lda*j+i]) norma = a[lda*j+i]; + } + for (i = 0; i < n; i++) + b[i] = 0.; + for (j = 0; j < n; j++) + for (i = 0; i < n; i++) + b[i] += a[lda*j+i]; + return norma; +} diff --git a/appl/math/mersenne.b b/appl/math/mersenne.b new file mode 100644 index 00000000..c90254b0 --- /dev/null +++ b/appl/math/mersenne.b @@ -0,0 +1,99 @@ +implement Mersenne; + +include "sys.m"; + sys : Sys; +include "draw.m"; +include "keyring.m"; + keyring: Keyring; + IPint: import keyring; + +# Test primality of Mersenne numbers + +Mersenne: module +{ + init: fn(nil: ref Draw->Context, argv: list of string); +}; + +init(nil: ref Draw->Context, argv: list of string) +{ + sys = load Sys Sys->PATH; + keyring = load Keyring Keyring->PATH; + p := 3; + if(tl argv != nil) + p = int hd tl argv; + if(isprime(p) && (p == 2 || lucas(p))) + s := ""; + else + s = "not "; + sys->print("2^%d-1 is %sprime\n", p, s); +} + +# s such that s^2 <= n +sqrt(n: int): int +{ + v := n; + r := 0; + for(t := 1<<30; t; t >>= 2){ + if(t+r <= v){ + v -= t+r; + r = (r>>1)|t; + } + else + r = r>>1; + } + return r; +} + +isprime(n: int): int +{ + if(n < 2) + return 0; + if(n == 2) + return 1; + if((n&1) == 0) + return 0; + s := sqrt(n); + for(i := 3; i <= s; i += 2) + if(n%i == 0) + return 0; + return 1; +} + +pow(b : ref IPint, n : int): ref IPint +{ + zero := IPint.inttoip(0); + one := IPint.inttoip(1); + if((b.cmp(zero) == 0 && n != 0) || b.cmp(one) == 0 || n == 1) + return b; + if(n == 0) + return one; + c := b; + b = one; + while(n){ + while(!(n & 1)){ + n >>= 1; + c = c.mul(c); + } + n--; + b = c.mul(b); + } + return b; +} + +lucas(p: int): int +{ + zero := IPint.inttoip(0); + one := IPint.inttoip(1); + two := IPint.inttoip(2); + bigp := pow(two, p).sub(one); + u := IPint.inttoip(4); + for(i := 2; i < p; i++){ + u = u.mul(u); + if(u.cmp(two) <= 0) + u = two.sub(u); + else + u = u.sub(two).expmod(one, bigp); + } + return u.cmp(zero) == 0; +} + diff --git a/appl/math/mkfile b/appl/math/mkfile new file mode 100644 index 00000000..7d21050a --- /dev/null +++ b/appl/math/mkfile @@ -0,0 +1,43 @@ +<../../mkconfig + +TARG=\ + ack.dis\ + crackerbarrel.dis\ + factor.dis\ + ffts.dis\ + fibonacci.dis\ + fit.dis\ + genprimes.dis\ + geodesy.dis\ + graph0.dis\ + gr.dis\ + hist0.dis\ + linalg.dis\ + linbench.dis\ + mersenne.dis\ + parts.dis\ + perms.dis\ + pi.dis\ + polyfill.dis\ + polyhedra.dis\ + powers.dis\ + primes.dis\ + sieve.dis\ + +MODULES= + +SYSMODULES=\ + math.m\ + gr.m\ + linalg.m\ + draw.m\ + sys.m\ + tk.m\ + wmlib.m\ + bufio.m\ + math/polyfill.m\ + math/polyhedra.m\ + +DISBIN=$ROOT/dis/math + +<$ROOT/mkfiles/mkdis diff --git a/appl/math/parts.b b/appl/math/parts.b new file mode 100644 index 00000000..36c36d8e --- /dev/null +++ b/appl/math/parts.b @@ -0,0 +1,125 @@ +implement Partitions; + +include "sys.m"; + sys : Sys; +include "draw.m"; +include "keyring.m"; + keyring: Keyring; + IPint: import keyring; + +# +# the number p(n) of partitions of n +# based upon the formula :- +# p(n) = p(n-1)+p(n-2)-p(n-5)-p(n-7)+p(n-12)+p(n-15)-p(n-22)-p(n-26)+..... +# where p[0] = 1 and p[m] = 0 for m < 0 +# + +aflag := 0; +cflag := 0; + +Partitions: module +{ + init: fn(nil: ref Draw->Context, argv: list of string); +}; + +init(nil: ref Draw->Context, argv: list of string) +{ + sys = load Sys Sys->PATH; + keyring = load Keyring Keyring->PATH; + argv = tl argv; + while(argv != nil){ + s := hd argv; + if(s != nil && s[0] == '-'){ + for(i := 1; i < len s; i++){ + case s[i]{ + 'a' => aflag = 1; + 'c' => cflag = 1; + } + } + } + else + parts(int s); + argv = tl argv; + } +} + +parts(m : int) +{ + if (aflag) + sys->print("n p(n)\n"); + if (m <= 0) { + p := 0; + if (m == 0) + p = 1; + if (aflag) + sys->print("%d %d\n", m, p); + else + sys->print("p[%d] = %d\n", m, p); + return; + } + p := array[m+1] of ref IPint; + if (p == nil) + return; + p[0] = IPint.inttoip(1); + for (i := 1; i <= m; i++) { + k := i; + s := 1; + n := IPint.inttoip(0); + for (j := 1; ; j++) { + k -= 2*j-1; + if (k < 0) + break; + if (s == 1) + n = n.add(p[k]); + else + n = n.sub(p[k]); + k -= j; + if (k < 0) + break; + if (s == 1) + n = n.add(p[k]); + else + n = n.sub(p[k]); + s = -s; + } + if (aflag) + sys->print("%d %s\n", i, n.iptostr(10)); + p[i] = n; + } + if (!aflag) + sys->print("p[%d] = %s\n", m, p[m].iptostr(10)); + if (cflag) + check(m, p); +} + +# +# given p[0]..p[m], search for congruences of the form +# p[ni+j] = r mod i +# +check(m : int, p : array of ref IPint) +{ + one := IPint.inttoip(1); + for (i := 2; i < m/3; i++) { + ip := IPint.inttoip(i); + for (j := 0; j < i; j++) { + k := j; + r := p[k].expmod(one, ip).iptoint(); + s := 1; + for (;;) { + k += i; + if (k > m) + break; + if (p[k].expmod(one, ip).iptoint() != r) { + r = -1; + break; + } + s++; + } + if (r >= 0) + if (j == 0) + sys->print("p(%dm) = %d mod %d ?\n", i, r, i); + else + sys->print("p(%dm+%d) = %d mod %d ?\n", i, j, r, i); + } + } +} diff --git a/appl/math/perms.b b/appl/math/perms.b new file mode 100644 index 00000000..23c5e52b --- /dev/null +++ b/appl/math/perms.b @@ -0,0 +1,131 @@ +# +# initially generated by c2l +# + +implement Perms; + +include "draw.m"; + +Perms: module +{ + init: fn(nil: ref Draw->Context, argl: list of string); +}; + +include "sys.m"; + sys: Sys; + +init(nil: ref Draw->Context, argl: list of string) +{ + sys = load Sys Sys->PATH; + main(len argl, argl); +} + +# +# * generate permutations of N elements +# * from ``On Programming, an interim report on the SETL project'', +# * Jacob T Schwartz (ed), New York University +# +Seq: adt{ + nel: int; + el: array of int; +}; + +origin: int = 1; + +main(argc: int, argv: list of string): int +{ + n: int; + + if(argc > 1 && (as := hd tl argv)[0] == '-'){ + origin = int (as[1: ]); + argc--; + argv = tl argv; + } + if(argc != 2){ + sys->fprint(sys->fildes(2), "Usage: perms #elements\n"); + exit; + } + n = int hd tl argv; + if(n > 0) + perms(n); + exit; +} + + +perms(n: int) +{ + seq: ref Seq; + + seq = newseq(n); + do + putseq(seq); + while(eperm(seq) != nil); +} + +putseq(seq: ref Seq) +{ + k: int; + + for(k = 0; k < seq.nel; k++) + sys->print(" %d", seq.el[k]+origin); + sys->print("\n"); +} + +eperm(seq: ref Seq): ref Seq +{ + j, k, n: int; + + n = seq.nel; + # if sequence is monotone decreasing, there are no more + # permutations. Otherwise, find last point of increase + hit := 0; + for(j = n-2; j >= 0; j--) + if(seq.el[j] < seq.el[j+1]){ + hit = 1; + break; + } + if(!hit) + return nil; + # then find the last seq[k] which exceeds seq[j] and swop + for(k = seq.nel-1; k > j; k--) + if(seq.el[k] > seq.el[j]){ + { + t: int; + + t = seq.el[k]; + seq.el[k] = seq.el[j]; + seq.el[j] = t; + } + ; + break; + } + # then re-arrange all the elements from seq[j+1] into + # increasing order + for(k = j+1; k < (n+j+1)/2; k++){ + kk: int; + + kk = n-k+j; + { + t: int; + + t = seq.el[k]; + seq.el[k] = seq.el[kk]; + seq.el[kk] = t; + } + ; + } + return seq; +} + +newseq(n: int): ref Seq +{ + seq: ref Seq; + k: int; + + seq = ref Seq; + seq.nel = n; + seq.el = array[n] of int; + for(k = 0; k < n; k++) + seq.el[k] = k; + return seq; +} diff --git a/appl/math/pi.b b/appl/math/pi.b new file mode 100644 index 00000000..2ddd1a14 --- /dev/null +++ b/appl/math/pi.b @@ -0,0 +1,405 @@ +implement Pi; + +include "sys.m"; + sys: Sys; +include "draw.m"; +include "math.m"; + math: Math; + log: import math; +include "daytime.m"; + daytime: Daytime; + +LBASE: con 3; # 4 +BASE: con 1000; # 10000 + +stderr: ref Sys->FD; + +# spawn process for each series ? + +Pi: module +{ + init: fn(nil: ref Draw->Context, argv: list of string); +}; + +init(nil: ref Draw->Context, argv: list of string) +{ + sys = load Sys Sys->PATH; + math = load Math Math->PATH; + daytime = load Daytime Daytime->PATH; + + stderr = sys->fildes(2); + dp := 1000; + argv = tl argv; + if(argv != nil){ + if(tl argv != nil){ + picmp(hd argv, hd tl argv); + exit; + } + dp = int hd argv; + } + if(dp <= 0) + exit; + # t1 := daytime->now(); + p2 := pi2(dp+1); + # t2 := daytime->now(); + prpi(p2); + p1 := pi1(dp+1); + # t3 := daytime->now(); + # sys->print("%d %d\n", t2-t1, t3-t2); + if(p1 == nil && p2 == nil) + fatal("too many dp: reduce dp or source base"); + else if(p1 == nil) + p1 = p2; + else if(p2 == nil) + p2 = p1; + n1 := len p1; + n2 := len p2; + if(n1 != n2) + fatal(sys->sprint("lens differ %d %d", n1, n2)); + f := array[10] of { * => 0 }; + for(i := 0; i < n1; i++){ + if(p1[i] != p2[i]) + fatal(sys->sprint("arrays differ %d/%d: %d %d", i, n1, p1[i], p2[i])); + if(p1[i] < 0 || p1[i] >= BASE) + fatal(sys->sprint("bad array element %d: %d", i, p1[i])); + if(0){ + p := p1[i]; + for(j := 0; j < LBASE; j++){ + f[p%10]++; + p /= 10; + } + } + } + # prpi(p1); + if(0){ + t := 0; + for(i = 0; i < 10; i++){ + sys->print("%d %d\n", i, f[i]); + t += f[i]; + } + sys->print("T %d\n", t); + } +} + +terms(dp: int, f: int, v: int): (int, int) +{ + p := dp; + t := 0; + for(;;){ + t = 2 + int ((real p*log(real 10)+log(real v))/log(real f)); + if(!(t&1)) + t++; + e := int (log(real (v*(t+1)/2))/log(real 10))+1; + if(dp <= p-e) + break; + p += e; + } + # sys->fprint(stderr, "dp=%d p=%d f=%d v=%d terms=%d\n", dp, p, f, v, t); + if(t < f*f) + k := f*f; + else + k = t; + m := BASE*k; + if(m < 0 || m < BASE || m < k || m/BASE != k || m/k != BASE) + return (-1, -1); + return (t, p); +} + +prpi(p: array of int) +{ + n := len p; + sys->print("π ≅ "); + m := BASE/10; + sys->print("%d.%.*d", p[0]/m, LBASE-1, p[0]%m); + for(i := 1; i < n; i++) + sys->print("%.*d", LBASE, p[i]); + sys->print("\n"); +} + +memcmp(b1: array of byte, b2: array of byte, n: int): (int, int, int) +{ + for(i := 0; i < n; i++) + if(b1[i] != b2[i]) + return (i, int b1[i], int b2[i]); + return (-1, 0, 0); +} + +picmp(f1: string, f2: string) +{ + fd1 := sys->open(f1, Sys->OREAD); + fd2 := sys->open(f2, Sys->OREAD); + if(fd1 == nil || fd2 == nil) + fatal(sys->sprint("cannot open %s or %s", f1, f2)); + b1 := array[Sys->ATOMICIO] of byte; + b2 := array[Sys->ATOMICIO] of byte; + t := 0; + shouldexit := 0; + for(;;){ + n1 := sys->read(fd1, b1, len b1); + n2 := sys->read(fd2, b2, len b2); + if(n1 <= 0 || n2 <= 0) + return; + if(shouldexit) + fatal("bad picmp"); + if(n1 < n2) + (d, v1, v2) := memcmp(b1, b2, n1); + else + (d, v1, v2) = memcmp(b1, b2, n2); + if(d >= 0){ + if(v1 == '\n' || v2 == '\n') + shouldexit = 1; + else + fatal(sys->sprint("%s %s differ at byte %d(%c %c)", f1, f2, t+d, v1, v2)); + } + t += n1; + if(n1 != n2) + shouldexit = 1; + } +} + +roundup(n: int, m: int): (int, int) +{ + r := m*((n+m-1)/m); + return (r, r/m); +} + +pi1(dp: int): array of int +{ + fs := array[2] of { 5, 239 }; + vs := array[2] of { 16, 4 }; + ss := array[2] of { 1, -1 }; + # sys->fprint(stderr, "π1\n"); + return pi(dp, fs, vs, ss); +} + +pi2(dp: int): array of int +{ + fs := array[3] of { 18, 57, 239 }; + vs := array[3] of { 48, 32, 20 }; + ss := array[3] of { 1, 1, -1 }; + # sys->fprint(stderr, "π2\n"); + return pi(dp, fs, vs, ss); +} + +pi3(dp: int): array of int +{ + fs := array[4] of { 57, 239, 682, 12943 }; + vs := array[4] of { 176, 28, 48, 96 }; + ss := array[4] of { 1, 1, -1, 1 }; + # sys->fprint(stderr, "π3\n"); + return pi(dp, fs, vs, ss); +} + +pi(dp: int, fs: array of int, vs: array of int, ss: array of int): array of int +{ + k := len fs; + n := cn := adp := 0; + (dp, n) = roundup(dp, LBASE); + cdp := dp; + m := array[k] of int; + for(i := 0; i < k; i++){ + (m[i], adp) = terms(dp+1, fs[i], vs[i]); + if(m[i] < 0) + return nil; + if(adp > cdp) + cdp = adp; + } + (cdp, cn) = roundup(cdp, LBASE); + a := array[cn] of int; + p := array[cn] of int; + for(i = 0; i < cn; i++) + p[i] = 0; + for(i = 0; i < k; i++){ + series(m[i], cn, fs[i], (vs[i]*BASE)/10, ss[i], a, p); + # sys->fprint(stderr, "term %d done\n", i+1); + } + return p[0: n]; +} + +series(m: int, n: int, f: int, v: int, s: int, a: array of int, p: array of int) +{ + i, j, k, q, r, r1, r2, n0: int; + + v *= f; + f *= f; + for(j = 0; j < n; j++) + a[j] = 0; + a[0] = v; + + if(s == 1) + series1(m, n, f, v, a, p); + else + series2(m, n, f, v, a, p); + return; + + # following code now split + n0 = 0; # reaches n when very close to m so no check needed + for(i = 1; i <= m; i += 2){ + r1 = r2 = 0; + for(j = n0; j < n; j++){ + v = a[j]+r1; + q = v/f; + r1 = (v-q*f)*BASE; + a[j] = q; + v = q+r2; + q = v/i; + r2 = (v-q*i)*BASE; + for(k = j; q > 0; k--){ + r = p[k]+s*q; + if(r >= BASE){ + p[k] = r-BASE; + q = 1; + } + else if(r < 0){ + p[k] = r+BASE; + q = 1; + } + else{ + p[k] = r; + q = 0; + } + } + } + for(j = n0; j < n; j++){ + if(a[j] == 0) + n0++; + else + break; + } + s = -s; + } +} + +series1(m: int, n: int, f: int, v: int, a: array of int, p: array of int) +{ + i, j, k, q, r, r1, r2, n0: int; + + n0 = 0; + for(i = 1; i <= m; i += 2){ + r1 = r2 = 0; + for(j = n0; j < n; j++){ + v = a[j]+r1; + q = v/f; + r1 = (v-q*f)*BASE; + a[j] = q; + v = q+r2; + q = v/i; + r2 = (v-q*i)*BASE; + for(k = j; q > 0; k--){ + r = p[k]+q; + if(r >= BASE){ + p[k] = r-BASE; + q = 1; + } + else{ + p[k] = r; + q = 0; + } + } + } + for(j = n0; j < n; j++){ + if(a[j] == 0) + n0++; + else + break; + } + i += 2; + r1 = r2 = 0; + for(j = n0; j < n; j++){ + v = a[j]+r1; + q = v/f; + r1 = (v-q*f)*BASE; + a[j] = q; + v = q+r2; + q = v/i; + r2 = (v-q*i)*BASE; + for(k = j; q > 0; k--){ + r = p[k]-q; + if(r < 0){ + p[k] = r+BASE; + q = 1; + } + else{ + p[k] = r; + q = 0; + } + } + } + for(j = n0; j < n; j++){ + if(a[j] == 0) + n0++; + else + break; + } + } +} + +series2(m: int, n: int, f: int, v: int, a: array of int, p: array of int) +{ + i, j, k, q, r, r1, r2, n0: int; + + n0 = 0; + for(i = 1; i <= m; i += 2){ + r1 = r2 = 0; + for(j = n0; j < n; j++){ + v = a[j]+r1; + q = v/f; + r1 = (v-q*f)*BASE; + a[j] = q; + v = q+r2; + q = v/i; + r2 = (v-q*i)*BASE; + for(k = j; q > 0; k--){ + r = p[k]-q; + if(r < 0){ + p[k] = r+BASE; + q = 1; + } + else{ + p[k] = r; + q = 0; + } + } + } + for(j = n0; j < n; j++){ + if(a[j] == 0) + n0++; + else + break; + } + i += 2; + r1 = r2 = 0; + for(j = n0; j < n; j++){ + v = a[j]+r1; + q = v/f; + r1 = (v-q*f)*BASE; + a[j] = q; + v = q+r2; + q = v/i; + r2 = (v-q*i)*BASE; + for(k = j; q > 0; k--){ + r = p[k]+q; + if(r >= BASE){ + p[k] = r-BASE; + q = 1; + } + else{ + p[k] = r; + q = 0; + } + } + } + for(j = n0; j < n; j++){ + if(a[j] == 0) + n0++; + else + break; + } + } +} + +fatal(e: string) +{ + sys->print("%s\n", e); + exit; +} diff --git a/appl/math/polyfill.b b/appl/math/polyfill.b new file mode 100644 index 00000000..c799d3db --- /dev/null +++ b/appl/math/polyfill.b @@ -0,0 +1,440 @@ +implement Polyfill; + +include "sys.m"; + sys: Sys; +include "draw.m"; + draw: Draw; + Point, Rect, Image, Endsquare: import draw; +include "math/polyfill.m"; + +∞: con 16r7fffffff; + +init() +{ + sys = load Sys Sys->PATH; + draw = load Draw Draw->PATH; +} + +initzbuf(r: Rect): ref Zstate +{ + if(sys == nil) + init(); + s := ref Zstate; + s.r = r; + s.xlen = r.dx(); + s.ylen = r.dy(); + s.xylen = s.xlen*s.ylen; + s.zbuf0 = array[s.xylen] of int; + s.zbuf1 = array[s.xylen] of int; + return s; +} + +clearzbuf(s: ref Zstate) +{ + b0 := s.zbuf0; + b1 := s.zbuf1; + n := s.xylen; + for(i := 0; i < n; i++) + b0[i] = b1[i] = ∞; +} + +setzbuf(s: ref Zstate, zd: int) +{ + b0 := s.zbuf0; + b1 := s.zbuf1; + n := s.xylen; + for(i := 0; i < n; i++) + b0[i] = b1[i] = zd; +} + +Seg: adt +{ + p0: Point; + p1: Point; + num: int; + den: int; + dz: int; + dzrem: int; + z: int; + zerr: int; + d: int; +}; + +fillline(dst: ref Image, left: int, right: int, y: int, src: ref Image, p: Point) +{ + p.x += left; + p.y += y; + dst.line((left, y), (right, y), Endsquare, Endsquare, 0, src, p); +} + +filllinez(dst: ref Image, left: int, right: int, y: int, z: int, e: int, dx: int, k: int, zbuf0: array of int, zbuf1: array of int, src: ref Image, p: Point) +{ + prevx := ∞; + for(x := left; x <= right; x++){ + if(z+e < zbuf0[k] || (z-e <= zbuf1[k] && x != right && prevx != ∞)){ + zbuf0[k] = z-e; + zbuf1[k] = z+e; + if(prevx == ∞) + prevx = x; + } + else if(prevx != ∞){ + fillline(dst, prevx, x-1, y, src, p); + prevx = ∞; + } + z += dx; + k++; + } + if(prevx != ∞) + fillline(dst, prevx, right, y, src, p); +} + +fillpoly(dst: ref Image, vert: array of Point, w: int, src: ref Image, sp: Point, zstate: ref Zstate, dc: int, dx: int, dy: int) +{ + p0: Point; + i: int; + + nvert := len vert; + if(nvert == 0) + return; + fixshift := 0; + seg := array[nvert+2] of ref Seg; + if(seg == nil) + return; + segtab := array[nvert+1] of ref Seg; + if(segtab == nil) + return; + + sp.x = (sp.x - vert[0].x) >> fixshift; + sp.y = (sp.y - vert[0].y) >> fixshift; + p0 = vert[nvert-1]; + if(!fixshift) { + p0.x <<= 1; + p0.y <<= 1; + } + for(i = 0; i < nvert; i++) { + segtab[i] = ref Seg; + segtab[i].p0 = p0; + p0 = vert[i]; + if(!fixshift) { + p0.x <<= 1; + p0.y <<= 1; + } + segtab[i].p1 = p0; + segtab[i].d = 1; + } + if(!fixshift) + fixshift = 1; + + xscan(dst, seg, segtab, nvert, w, src, sp, zstate, dc, dx, dy, fixshift); +} + +mod(x: int, y: int): int +{ + z: int; + + z = x%y; + if((z^y) > 0 || z == 0) + return z; + return z + y; +} + +sdiv(x: int, y: int): int +{ + if((x^y) >= 0 || x == 0) + return x/y; + return (x+((y>>30)|1))/y-1; +} + +smuldivmod(x: int, y: int, z: int): (int, int) +{ + mod: int; + vx: int; + + if(x == 0 || y == 0) + return (0, 0); + vx = x; + vx *= y; + mod = vx % z; + if(mod < 0) + mod += z; + if((vx < 0) == (z < 0)) + return (vx/z, mod); + return (-((-vx)/z), mod); +} + +xscan(dst: ref Image, seg: array of ref Seg, segtab: array of ref Seg, nseg: int, wind: int, src: ref Image, spt: Point, zstate: ref Zstate, dc: int, dx: int, dy: int, fixshift: int) +{ + y, maxy, x, x2, onehalf: int; + ep, next, p, q, s: int; + n, i, iy, cnt, ix, ix2, minx, maxx, zinc, k, zv: int; + pt: Point; + sp: ref Seg; + + er := (abs(dx)+abs(dy)+1)/2; + zr := zstate.r; + xlen := zstate.xlen; + zbuf0 := zstate.zbuf0; + zbuf1 := zstate.zbuf1; + s = 0; + p = 0; + for(i=0; i<nseg; i++) { + sp = seg[p] = segtab[s]; + if(sp.p0.y == sp.p1.y){ + s++; + continue; + } + if(sp.p0.y > sp.p1.y) { + pt = sp.p0; + sp.p0 = sp.p1; + sp.p1 = pt; + sp.d = -sp.d; + } + sp.num = sp.p1.x - sp.p0.x; + sp.den = sp.p1.y - sp.p0.y; + sp.dz = sdiv(sp.num, sp.den) << fixshift; + sp.dzrem = mod(sp.num, sp.den) << fixshift; + sp.dz += sdiv(sp.dzrem, sp.den); + sp.dzrem = mod(sp.dzrem, sp.den); + p++; + s++; + } + n = p; + if(n == 0) + return; + seg[p] = nil; + qsortycompare(seg, p); + + onehalf = 0; + if(fixshift) + onehalf = 1 << (fixshift-1); + + minx = dst.clipr.min.x; + maxx = dst.clipr.max.x; + + y = seg[0].p0.y; + if(y < (dst.clipr.min.y << fixshift)) + y = dst.clipr.min.y << fixshift; + iy = (y + onehalf) >> fixshift; + y = (iy << fixshift) + onehalf; + maxy = dst.clipr.max.y << fixshift; + k = (iy-zr.min.y)*xlen; + zv = dc+iy*dy; + + ep = next = 0; + + while(y<maxy) { + for(q = p = 0; p < ep; p++) { + sp = seg[p]; + if(sp.p1.y < y) + continue; + sp.z += sp.dz; + sp.zerr += sp.dzrem; + if(sp.zerr >= sp.den) { + sp.z++; + sp.zerr -= sp.den; + if(sp.zerr < 0 || sp.zerr >= sp.den) + sys->print("bad ratzerr1: %d den %d dzrem %d\n", sp.zerr, sp.den, sp.dzrem); + } + seg[q] = sp; + q++; + } + + for(p = next; seg[p] != nil; p++) { + sp = seg[p]; + if(sp.p0.y >= y) + break; + if(sp.p1.y < y) + continue; + sp.z = sp.p0.x; + (zinc, sp.zerr) = smuldivmod(y - sp.p0.y, sp.num, sp.den); + sp.z += zinc; + if(sp.zerr < 0 || sp.zerr >= sp.den) + sys->print("bad ratzerr2: %d den %d ratdzrem %d\n", sp.zerr, sp.den, sp.dzrem); + seg[q] = sp; + q++; + } + ep = q; + next = p; + + if(ep == 0) { + if(seg[next] == nil) + break; + iy = (seg[next].p0.y + onehalf) >> fixshift; + y = (iy << fixshift) + onehalf; + k = (iy-zr.min.y)*xlen; + zv = dc+iy*dy; + continue; + } + + zsort(seg, ep); + + for(p = 0; p < ep; p++) { + sp = seg[p]; + cnt = 0; + x = sp.z; + ix = (x + onehalf) >> fixshift; + if(ix >= maxx) + break; + if(ix < minx) + ix = minx; + cnt += sp.d; + p++; + sp = seg[p]; + for(;;) { + if(p == ep) { + sys->print("xscan: fill to infinity"); + return; + } + cnt += sp.d; + if((cnt&wind) == 0) + break; + p++; + sp = seg[p]; + } + x2 = sp.z; + ix2 = (x2 + onehalf) >> fixshift; + if(ix2 <= minx) + continue; + if(ix2 > maxx) + ix2 = maxx; + filllinez(dst, ix, ix2, iy, zv+ix*dx, er, dx, k+ix-zr.min.x, zbuf0, zbuf1, src, spt); + } + y += (1<<fixshift); + iy++; + k += xlen; + zv += dy; + } +} + +zsort(seg: array of ref Seg, ep: int) +{ + done: int; + s: ref Seg; + q, p: int; + + if(ep < 20) { + # bubble sort by z - they should be almost sorted already + q = ep; + do { + done = 1; + q--; + for(p = 0; p < q; p++) { + if(seg[p].z > seg[p+1].z) { + s = seg[p]; + seg[p] = seg[p+1]; + seg[p+1] = s; + done = 0; + } + } + } while(!done); + } else { + q = ep-1; + for(p = 0; p < q; p++) { + if(seg[p].z > seg[p+1].z) { + qsortzcompare(seg, ep); + break; + } + } + } +} + +ycompare(s0: ref Seg, s1: ref Seg): int +{ + y0, y1: int; + + y0 = s0.p0.y; + y1 = s1.p0.y; + + if(y0 < y1) + return -1; + if(y0 == y1) + return 0; + return 1; +} + +zcompare(s0: ref Seg, s1: ref Seg): int +{ + z0, z1: int; + + z0 = s0.z; + z1 = s1.z; + + if(z0 < z1) + return -1; + if(z0 == z1) + return 0; + return 1; +} + +qsortycompare(a : array of ref Seg, n : int) +{ + i, j : int; + t : ref Seg; + + while(n > 1) { + i = n>>1; + t = a[0]; a[0] = a[i]; a[i] = t; + i = 0; + j = n; + for(;;) { + do + i++; + while(i < n && ycompare(a[i], a[0]) < 0); + do + j--; + while(j > 0 && ycompare(a[j], a[0]) > 0); + if(j < i) + break; + t = a[i]; a[i] = a[j]; a[j] = t; + } + t = a[0]; a[0] = a[j]; a[j] = t; + n = n-j-1; + if(j >= n) { + qsortycompare(a, j); + a = a[j+1:]; + } else { + qsortycompare(a[j+1:], n); + n = j; + } + } +} + +qsortzcompare(a : array of ref Seg, n : int) +{ + i, j : int; + t : ref Seg; + + while(n > 1) { + i = n>>1; + t = a[0]; a[0] = a[i]; a[i] = t; + i = 0; + j = n; + for(;;) { + do + i++; + while(i < n && zcompare(a[i], a[0]) < 0); + do + j--; + while(j > 0 && zcompare(a[j], a[0]) > 0); + if(j < i) + break; + t = a[i]; a[i] = a[j]; a[j] = t; + } + t = a[0]; a[0] = a[j]; a[j] = t; + n = n-j-1; + if(j >= n) { + qsortzcompare(a, j); + a = a[j+1:]; + } else { + qsortzcompare(a[j+1:], n); + n = j; + } + } +} + +abs(n: int): int +{ + if(n < 0) + return -n; + return n; +} diff --git a/appl/math/polyhedra.b b/appl/math/polyhedra.b new file mode 100644 index 00000000..e7a51d6c --- /dev/null +++ b/appl/math/polyhedra.b @@ -0,0 +1,195 @@ +implement Polyhedra; + +include "sys.m"; + sys: Sys; +include "bufio.m"; + bufio: Bufio; + Iobuf: import bufio; +include "math/polyhedra.m"; + +scanpolyhedra(f: string): (int, ref Polyhedron, ref Iobuf) +{ + first, last: ref Polyhedron; + D: int; + + if(sys == nil) + sys = load Sys Sys->PATH; + if(bufio == nil) + bufio = load Bufio Bufio->PATH; + b := bufio->open(f, Sys->OREAD); + if(b == nil) + return (0, nil, nil); + n := 0; + for(;;){ + s := getstring(b); + if(s == nil) + break; + n++; + p := ref Polyhedron; + if(first == nil) + first = p; + else{ + last.nxt = p; + p.prv = last; + } + last = p; + p.name = s; + p.dname = getstring(b); + b.gets('\n'); + (p.allf, p.adj) = scanvc(getstring(b)); + b.gets('\n'); + b.gets('\n'); + b.gets('\n'); + l := getstring(b); + (p.indx, l) = getint(l); + (p.V, l) = getint(l); + (p.E, l) = getint(l); + (p.F, l) = getint(l); + (nil, l) = getint(l); + (D, l) = getint(l); + (p.anti, l) = getint(l); + p.concave = D != 1 || p.allf; + p.offset = b.offset(); + tot := 2*p.V+2*p.F; + for(i := 0; i < tot; i++) + b.gets('\n'); + if(p.indx < 58 || p.indx == 59 || p.indx == 66 || p.indx == 67) + p.inc = 0.1; + else + p.inc = 0.0; + # sys->print("%d: %d %d %d %d %s\n", p.indx, p.allf, D != 1, p.anti, p.concave, vc); + } + first.prv = last; + last.nxt = first; + return (n, first, b); +} + +getpolyhedra(p: ref Polyhedron, b: ref Iobuf) +{ + q := p; + do{ + getpolyhedron(q, b); + q = q.nxt; + }while(q != p); +} + +getpolyhedron(p: ref Polyhedron, b: ref Iobuf) +{ + if(p.v != nil) + return; + b.seek(p.offset, Bufio->SEEKSTART); + p.v = array[p.V] of Vector; + for(i := 0; i < p.V; i++) + p.v[i] = getvector(b); + p.f = array[p.F] of Vector; + for(i = 0; i < p.F; i++) + p.f[i] = getvector(b); + p.fv = array[p.F] of array of int; + for(i = 0; i < p.F; i++) + p.fv[i] = getarray(b, p.adj); + p.vf = array[p.V] of array of int; + for(i = 0; i < p.V; i++) + p.vf[i] = getarray(b, p.adj); +} + +getstring(b: ref Iobuf): string +{ + s := b.gets('\n'); + if(s == nil) + return nil; + if(s[0] == '#') + return getstring(b); + if(s[len s - 1] == '\n') + return s[0: len s - 1]; + return s; +} + +getvector(b: ref Iobuf): Vector +{ + v: Vector; + + s := getstring(b); + (v.x, s) = getreal(s); + (v.y, s) = getreal(s); + (v.z, s) = getreal(s); + return v; +} + +getarray(b: ref Iobuf, adj: int): array of int +{ + n, d: int; + + s := getstring(b); + (n, s) = getint(s); + a := array[n+2] of int; + a[0] = n; + for(i := 1; i <= n; i++) + (a[i], s) = getint(s); + (d, s) = getint(s); + if(d == 0 || d == n-1 || adj) + d = 1; + a[n+1] = d; + return a; +} + +getint(s: string): (int, string) +{ + n := int s; + for(i := 0; i < len s && s[i] == ' '; i++) + ; + for( ; i < len s; i++) + if(s[i] == ' ') + return (n, s[i+1:]); + return (n, nil); +} + +getreal(s: string): (real, string) +{ + r := real s; + for(i := 0; i < len s && s[i] == ' '; i++) + ; + for( ; i < len s; i++) + if(s[i] == ' ') + return (r, s[i+1:]); + return (r, nil); +} + +vftab := array[] of { 0, 0, 0, 2, 3, 3, 5, 0, 3, 0, 3 }; + +scanvc(s: string): (int, int) +{ + af := 0; + ad := 0; + fd := ld := 1; + ln := len s; + if(ln > 0 && s[0] == '('){ + s = s[1:]; + ln--; + } + while(ln > 0 && s[ln-1] != ')'){ + s = s[0: ln-1]; + ln--; + } + (m, lst) := sys->tokenize(s, "."); + for(l := lst ; l != nil; l = tl l){ + (m, lst) = sys->tokenize(hd l, "/"); + if(m == 1) + (n, d) := (int hd lst, 1); + else if(m == 2) + (n, d) = (int hd lst, int hd tl lst); + else + sys->print("vc error\n"); + if(d != 1 && d == vftab[n]) + af = 1; + if(d == n-1) + d = 1; + if(l == lst) + fd = d; + else if(ld != 1 && d != 1) + ad = 1; + ld = d; + } + if(ld != 1 && fd != 1) + ad = 1; + return (af, ad); +} diff --git a/appl/math/powers.b b/appl/math/powers.b new file mode 100644 index 00000000..d9c5259c --- /dev/null +++ b/appl/math/powers.b @@ -0,0 +1,672 @@ +implement Powers; + +include "sys.m"; + sys: Sys; +include "draw.m"; +include "arg.m"; +include "lock.m"; + lockm: Lock; + Semaphore: import lockm; + +Powers: module +{ + init: fn(nil: ref Draw->Context, nil: list of string); +}; + +MAXNODES: con (1<<20)/4; + +verbose: int; + +# Doing +# powers -p 3 +# gives +# [2] 1729 = 1**3 + 12**3 = 9**3 + 10**3 +# [2] 4104 = 2**3 + 16**3 = 9**3 + 15**3 + +# ie 1729 can be written in two ways as the sum of 2 cubes as can 4104. + +# The options are + +# -p the power to use - default 2 +# -n the number of powers summed - default 2 +# -f the minimum number of ways found before reporting it - default 2 +# -l the least number to consider - default 0 +# -m the greatest number to consider - default 8192 + +# Thus +# pow -p 4 -n 3 -f 3 -l 0 -m 1000000 +# gives +# [3] 811538 = 12**4 + 17**4 + 29**4 = 7**4 + 21**4 + 28**4 = 4**4 + 23**4 + 27**4 + +# ie fourth powers, 3 in each sum, minimum of 3 representations, numbers from 0-1000000. + +# [2] 25 +# [3] 325 +# [4] 1105 +# [5] 4225 +# [6] 5525 +# [7] 203125 +# [8] 27625 +# [9] 71825 +# [10] 138125 +# [11] 2640625 +# [12] 160225 +# [13] 17850625 +# [14] 1221025 +# [15] 1795625 +# [16] 801125 +# [18] 2082925 +# [20] 4005625 +# [23] 30525625 +# [24] 5928325 +# [32] 29641625 + +# [24] 5928325 = 63**2 + 2434**2 = 94**2 + 2433**2 = 207**2 + 2426**2 = 294**2 + 2417**2 = 310**2 + 2415**2 = 465**2 + 2390**2 = 490**2 + 2385**2 = 591**2 + 2362**2 = 690**2 + 2335**2 = 742**2 + 2319**2 = 849**2 + 2282**2 = 878**2 + 2271**2 = 959**2 + 2238**2 = 1039**2 + 2202**2 = 1062**2 + 2191**2 = 1201**2 + 2118**2 = 1215**2 + 2110**2 = 1290**2 + 2065**2 = 1410**2 + 1985**2 = 1454**2 + 1953**2 = 1535**2 + 1890**2 = 1614**2 + 1823**2 = 1633**2 + 1806**2 = 1697**2 + 1746**2 + +# [32] 29641625 = 67**2 + 5444**2 = 124**2 + 5443**2 = 284**2 + 5437**2 = 320**2 + 5435**2 = 515**2 + 5420**2 = 584**2 + 5413**2 = 835**2 + 5380**2 = 955**2 + 5360**2 = 1180**2 + 5315**2 = 1405**2 + 5260**2 = 1460**2 + 5245**2 = 1648**2 + 5189**2 = 1795**2 + 5140**2 = 1829**2 + 5128**2 = 1979**2 + 5072**2 = 2012**2 + 5059**2 = 2032**2 + 5051**2 = 2245**2 + 4960**2 = 2308**2 + 4931**2 = 2452**2 + 4861**2 = 2560**2 + 4805**2 = 2621**2 + 4772**2 = 2840**2 + 4645**2 = 3005**2 + 4540**2 = 3035**2 + 4520**2 = 3320**2 + 4315**2 = 3365**2 + 4280**2 = 3517**2 + 4156**2 = 3544**2 + 4133**2 = 3664**2 + 4027**2 = 3715**2 + 3980**2 = 3803**2 + 3896**2 + +# [2] 1729 = 1**3 + 12**3 = 9**3 + 10**3 +# [2] 4104 = 2**3 + 16**3 = 9**3 + 15**3 +# [3] 87539319 = 167**3 + 436**3 = 228**3 + 423**3 = 255**3 + 414**3 + +# [2] 635318657 = 59**4 + 158**4 = 133**4 + 134**4 +# [2] 3262811042 = 7**4 + 239**4 = 157**4 + 227**4 +# [2] 8657437697 = 193**4 + 292**4 = 256**4 + 257**4 +# [2] 68899596497 = 271**4 + 502**4 = 298**4 + 497**4 +# [2] 86409838577 = 103**4 + 542**4 = 359**4 + 514**4 +# [2] 160961094577 = 222**4 + 631**4 = 503**4 + 558**4 +# [2] 2094447251857 = 76**4 + 1203**4 = 653**4 + 1176**4 +# [2] 4231525221377 = 878**4 + 1381**4 = 997**4 + 1342**4 +# [2] 26033514998417 = 1324**4 + 2189**4 = 1784**4 + 1997**4 +# [2] 37860330087137 = 1042**4 + 2461**4 = 2026**4 + 2141**4 +# [2] 61206381799697 = 248**4 + 2797**4 = 2131**4 + 2524**4 +# [2] 76773963505537 = 1034**4 + 2949**4 = 1797**4 + 2854**4 +# [2] 109737827061041 = 1577**4 + 3190**4 = 2345**4 + 2986**4 +# [2] 155974778565937 = 1623**4 + 3494**4 = 2338**4 + 3351**4 +# [2] 156700232476402 = 661**4 + 3537**4 = 2767**4 + 3147**4 +# [2] 621194785437217 = 2694**4 + 4883**4 = 3966**4 + 4397**4 +# [2] 652057426144337 = 604**4 + 5053**4 = 1283**4 + 5048**4 +# [2] 680914892583617 = 3364**4 + 4849**4 = 4288**4 + 4303**4 +# [2] 1438141494155441 = 2027**4 + 6140**4 = 4840**4 + 5461**4 +# [2] 1919423464573697 = 274**4 + 6619**4 = 5093**4 + 5942**4 +# [2] 2089568089060657 = 498**4 + 6761**4 = 5222**4 + 6057**4 +# [2] 2105144161376801 = 2707**4 + 6730**4 = 3070**4 + 6701**4 +# [2] 3263864585622562 = 1259**4 + 7557**4 = 4661**4 + 7269**4 +# [2] 4063780581008977 = 5181**4 + 7604**4 = 6336**4 + 7037**4 +# [2] 6315669699408737 = 1657**4 + 8912**4 = 7432**4 + 7559**4 +# [2] 6884827518602786 = 635**4 + 9109**4 = 3391**4 + 9065**4 +# [2] 7191538859126257 = 4903**4 + 9018**4 = 6842**4 + 8409**4 +# [2] 7331928977565937 = 1104**4 + 9253**4 = 5403**4 + 8972**4 +# [2] 7362748995747617 = 5098**4 + 9043**4 = 6742**4 + 8531**4 +# [2] 7446891977980337 = 1142**4 + 9289**4 = 4946**4 + 9097**4 +# [2] 7532132844821777 = 173**4 + 9316**4 = 4408**4 + 9197**4 +# [2] 7985644522300177 = 6262**4 + 8961**4 = 7234**4 + 8511**4 + +# 5, 6, 7, 8, 9, 10, 11 none + +Btree: adt{ + sum: big; + left: cyclic ref Btree; + right: cyclic ref Btree; +}; + +Dtree: adt{ + sum: big; + freq: int; + lst: list of array of int; + left: cyclic ref Dtree; + right: cyclic ref Dtree; +}; + +nCr(n: int, r: int): int +{ + if(r > n-r) + r = n-r; + + # f := g := 1; + # for(i := 0; i < r; i++){ + # f *= n-i; + # g *= i+1; + # } + # return f/g; + + num := array[r] of int; + den := array[r] of int; + for(i := 0; i < r; i++){ + num[i] = n-i; + den[i] = i+1; + } + for(i = 0; i < r; i++){ + for(j := 0; den[i] != 1; j++){ + if(num[j] == 1) + continue; + k := hcf(num[j], den[i]); + if(k != 1){ + num[j] /= k; + den[i] /= k; + } + } + } + f := 1; + for(i = 0; i < r; i++) + f *= num[i]; + return f; +} + +nHr(n: int, r: int): int +{ + if(n == 0) + return 0; + return nCr(n+r-1, r); +} + +nSr(n: int, i: int, j: int): int +{ + return nHr(j, n)-nHr(i, n); + # s := 0; + # for(k := i; k < j; k++) + # s += nHr(k+1, n-1); + # return s; +} + +nSrmax(n: int, i: int, m: int): int +{ + s := 0; + for(k := i; ; k++){ + s += nHr(k+1, n-1); + if(s > m) + break; + } + if(k == i) + return i+1; + return k; +} + +kth(c: array of int, n: int, i: int, j: int, k: int) +{ + l, u: int; + + m := nSr(n, i, j); + if(k < 0) + k = 0; + if(k >= m) + k = m-1; + p := 0; + for(q := 0; q < n; q++){ + if(q == 0){ + l = i; + u = j-1; + } + else{ + l = 0; + u = c[q-1]; + } + for(x := l; x <= u; x++){ + m = nHr(x+1, n-q-1); + p += m; + if(p > k){ + p -= m; + break; + } + } + c[q] = x; + } +} + +pos(c: array of int, n: int): int +{ + p := 0; + for(q := 0; q < n; q++) + p += nSr(n-q, 0, c[q]); + return p; +} + +min(c: array of int, n: int, p: int): big +{ + s := big(0); + for(i := 0; i < n; i++) + s += big(c[i])**p; + m := s; + for(i = n-1; i > 0; i--){ + s -= big(c[i])**p; + s -= big(c[i-1])**p; + c[i]--; + c[i-1]++; + s += big(c[i-1])**p; + if(s < m) + m = s; + } + c[0]--; + c[n-1]++; + # m--; + return m; +} + +hcf(a, b: int): int +{ + if(b == 0) + return a; + for(;;){ + if(a == 0) + break; + if(a < b) + (a, b) = (b, a); + a %= b; + # a -= (a/b)*b; + } + return b; +} + +gcd(l: list of array of int): int +{ + g := (hd l)[0]; + for(; l != nil; l = tl l){ + d := hd l; + n := len d; + for(i := 0; i < n; i++) + g = hcf(d[i], g); + } + return g; +} + +adddup(s: big, root: ref Dtree): int +{ + n, p, lp: ref Dtree; + + p = root; + while(p != nil){ + if(s == p.sum) + return ++p.freq; + lp = p; + if(s < p.sum) + p = p.left; + else + p = p.right; + } + n = ref Dtree(s, 2, nil, nil, nil); + if(s < lp.sum) + lp.left = n; + else + lp.right = n; + return n.freq; +} + +cp(c: array of int): array of int +{ + n := len c; + m := 0; + for(i := 0; i < n; i++) + if(c[i] != 0) + m++; + nc := array[m] of int; + nc[0: ] = c[0: m]; + return nc; +} + +finddup(s: big, c: array of int, root: ref Dtree, f: int) +{ + p: ref Dtree; + + p = root; + while(p != nil){ + if(s == p.sum){ + if(p.freq >= f) + p.lst = cp(c) :: p.lst; + return; + } + if(s < p.sum) + p = p.left; + else + p = p.right; + } +} + +printdup(p: ref Dtree, pow: int, ix: int) +{ + if(p == nil) + return; + printdup(p.left, pow, ix); + if((l := p.lst) != nil){ + if(gcd(l) == 1){ + min1 := min2 := 16r7fffffff; + for(; l != nil; l = tl l){ + n := len hd l; + if(n < min1){ + min2 = min1; + min1 = n; + } + else if(n < min2) + min2 = n; + } + i := min1+min2-pow; + if(i <= ix){ + sys->print("[%d, %d] %bd", i, p.freq, p.sum); + for(l = p.lst; l != nil; l = tl l){ + d := hd l; + n := len d; + sys->print(" = "); + for(j := n-1; j >= 0; j--){ + sys->print("%d**%d", d[j], pow); + if(j > 0) + sys->print(" + "); + } + } + sys->print("\n"); + if(i < 0){ + sys->print("****************\n"); + exit; + } + } + } + } + printdup(p.right, pow, ix); +} + +addsum(s: big, root: ref Btree, root1: ref Dtree): int +{ + n, p, lp: ref Btree; + + p = root; + while(p != nil){ + if(s == p.sum) + return adddup(s, root1); + lp = p; + if(s < p.sum) + p = p.left; + else + p = p.right; + } + n = ref Btree(s, nil, nil); + if(s < lp.sum) + lp.left = n; + else + lp.right = n; + return 1; +} + +oiroot(x: big, p: int): int +{ + for(i := 0; ; i++){ + n := big(i)**p; + if(n > x) + break; + } + return i-1; +} + +iroot(x: big, p: int): int +{ + m: big; + + if(x == big(0) || x == big(1)) + return int x; + v := x; + n := 0; + for(i := 32; i > 0; i >>= 1){ + m = ((big(1)<<i)-big(1))<<i; + if((v&m) != big(0)){ + n += i; + v >>= i; + } + } + a := big(1) << (n/p); + b := a<<1; + while(a < b){ + m = (a+b+big(1))/big(2); + y := m**p; + if(y > x) + b = m-big(1); + else if(y < x) + a = m; + else + a = b = m; + } + if(a**p <= x && (a+big(1))**p > x) + ; + else{ + sys->print("fatal: %bd %d -> %bd\n", x, p, a); + exit; + } + return int a; +} + +initval(c: array of int, n: int, p: int, v: int): big +{ + for(i := 0; i < n; i++) + c[i] = 0; + c[0] = v; + return big(v)**p; +} + +nxtval(c: array of int, n: int, p: int, s: big): big +{ + for(k := n-1; k >= 0; k--){ + s -= big(c[k])**p; + c[k]++; + if(k == 0){ + s += big(c[k])**p; + break; + } + else{ + if(c[k] <= c[k-1]){ + s += big(c[k])**p; + break; + } + c[k] = 0; + } + } + return s; +} + +powers(p: int, n: int, f: int, ix: int, lim0: big, lim: big, ch: chan of int, lock: ref Semaphore) +{ + root := ref Btree(big(-1), nil, nil); + root1 := ref Dtree(big(-1), 0, nil, nil, nil); + + min := max := lim0; + + c := array[n] of int; + + for(;;){ + imin := iroot((min+big(n-1))/big(n), p); + imax := nSrmax(n, imin, MAXNODES); + max = big(imax)**p - big(1); + while(max <= min){ # could do better + imax++; + max = big(imax)**p - big(1); + } + if(max > lim){ + max = lim; + imax = iroot(max, p)+1; + } + + if(verbose) + sys->print("searching in %d-%d(%bd-%bd)\n", imin, imax, min, max); + + m := mm := 0; + maxf := 0; + s := initval(c, n, p, imin); + for(;;){ + mm++; + if(s >= min && s < max){ + fr := addsum(s, root, root1); + if(fr > maxf) + maxf = fr; + m++; + } + s = nxtval(c, n, p, s); + if(c[0] == imax) + break; + } + + root.left = root.right = nil; + + if(maxf >= f){ + if(verbose) + sys->print("finding duplicates\n"); + + s = initval(c, n, p, imin); + for(;;){ + if(s >= min && s < max) + finddup(s, c, root1, f); + s = nxtval(c, n, p, s); + if(c[0] == imax) + break; + } + + if(lock != nil) + lock.obtain(); + printdup(root1, p, ix); + if(lock != nil) + lock.release(); + + root1.left = root1.right = nil; + } + + if(verbose) + sys->print("%d(%d) nodes searched\n", m, mm); + + if(mm != nSr(n, imin, imax)){ + sys->print("**fatal**\n"); + exit; + } + + min = max; + if(min >= lim) + break; + } + if(ch != nil) + ch <-= 0; +} + +usage() +{ + sys->print("usage: powers -p power -n number -f frequency -i index -l minimum -m maximum -s procs -v\n"); + exit; +} + +partition(p: int, n: int, l: big, m: big, s: int): array of big +{ + a := array[s+1] of big; + a[0] = big(iroot(l, p))**n; + a[s] = (big(iroot(m, p))+big(1))**n; + nn := a[s]-a[0]; + q := nn/big(s); + r := nn-q*big(s); + t := big(0); + lb := a[0]; + for(i := 0; i < s; i++){ + ub := lb+q; + t += r; + if(t >= big(s)){ + ub++; + t -= big(s); + } + a[i+1] = ub; + lb = ub; + } + if(a[s] != a[0]+nn){ + sys->print("fatal: a[s]\n"); + exit; + } + for(i = 0; i < s; i++){ + # sys->print("%bd %bd\n", a[i], a[i]**p); + a[i] = big(iroot(a[i], n))**p; + } + a[0] = l; + a[s] = m; + while(a[0] >= a[1]){ + a[1] = a[0]; + a = a[1: ]; + --s; + } + while(a[s] <= a[s-1]){ + a[s-1] = a[s]; + a = a[0: s]; + --s; + } + return a; +} + +init(nil: ref Draw->Context, args: list of string) +{ + sys = load Sys Sys->PATH; + arg := load Arg Arg->PATH; + lockm = load Lock Lock->PATH; + + lockm->init(); + lock := Semaphore.new(); + + p := n := f := 2; + ix := 1<<30; + l := m := big(0); + s := 1; + + arg->init(args); + while((c := arg->opt()) != 0){ + case c { + 'p' => + p = int arg->arg(); + 'n' => + n = int arg->arg(); + 'f' => + f = int arg->arg(); + 'i' => + ix = int arg->arg(); + 'l' => + l = big(arg->arg()); + 'm' => + m = big(arg->arg())+big(1); + 's' => + s = int arg->arg(); + 'v' => + verbose = 1; + * => + usage(); + } + } + if(arg->argv() != nil) + usage(); + + if(p < 2){ + p = 2; + sys->print("setting p = %d\n", p); + } + if(n < 2){ + n = 2; + sys->print("setting n = %d\n", n); + } + if(f < 2){ + f = 2; + sys->print("setting f = %d\n", f); + } + if(l < big(0)){ + l = big(0); + sys->print("setting l = %bd\n", l); + } + if(m <= big(0)){ + m = big((1<<13)+1); + sys->print("setting m = %bd\n", m-big(1)); + } + if(l >= m) + exit; + + if(s <= 1) + powers(p, n, f, ix, l, m, nil, nil); + else{ + nproc := 0; + ch := chan of int; + a := partition(p, n, l, m, s); + lb := a[0]; + for(i := 0; i < s; i++){ + ub := a[i+1]; + if(lb < ub){ + nproc++; + spawn powers(p, n, f, ix, lb, ub, ch, lock); + } + lb = ub; + } + for( ; nproc != 0; nproc--) + <- ch; + } +} diff --git a/appl/math/primes.b b/appl/math/primes.b new file mode 100644 index 00000000..70bbc651 --- /dev/null +++ b/appl/math/primes.b @@ -0,0 +1,228 @@ +implement Primes; + +# +# primes starting [ending] +# +# Subject to the Lucent Public License 1.02 +# + +include "draw.m"; + +Primes: module +{ + init: fn(nil: ref Draw->Context, argl: list of string); +}; + +include "sys.m"; + sys: Sys; +include "math.m"; + maths: Math; + +bigx: con 9.007199254740992e15; +pt := array[] of { + 2, + 3, + 5, + 7, + 11, + 13, + 17, + 19, + 23, + 29, + 31, + 37, + 41, + 43, + 47, + 53, + 59, + 61, + 67, + 71, + 73, + 79, + 83, + 89, + 97, + 101, + 103, + 107, + 109, + 113, + 127, + 131, + 137, + 139, + 149, + 151, + 157, + 163, + 167, + 173, + 179, + 181, + 191, + 193, + 197, + 199, + 211, + 223, + 227, + 229, +}; +wheel := array[] of { + 10.0, + 2.0, + 4.0, + 2.0, + 4.0, + 6.0, + 2.0, + 6.0, + 4.0, + 2.0, + 4.0, + 6.0, + 6.0, + 2.0, + 6.0, + 4.0, + 2.0, + 6.0, + 4.0, + 6.0, + 8.0, + 4.0, + 2.0, + 4.0, + 2.0, + 4.0, + 8.0, + 6.0, + 4.0, + 6.0, + 2.0, + 4.0, + 6.0, + 2.0, + 6.0, + 6.0, + 4.0, + 2.0, + 4.0, + 6.0, + 2.0, + 6.0, + 4.0, + 2.0, + 4.0, + 2.0, + 10.0, + 2.0, +}; +BITS: con 8; +TABLEN: con 1000; +table := array[TABLEN] of byte; +bittab := array[8] of { + byte 1, + byte 2, + byte 4, + byte 8, + byte 16, + byte 32, + byte 64, + byte 128, +}; + +init(nil: ref Draw->Context, args: list of string) +{ + sys = load Sys Sys->PATH; + maths = load Math Math->PATH; + + if(len args <= 1){ + sys->fprint(sys->fildes(2), "usage: primes starting [ending]\n"); + raise "fail:usage"; + } + args = tl args; + nn := real hd args; + limit := bigx; + if(tl args != nil){ + limit = real hd tl args; + if(limit < nn) + exit; + if(limit > bigx) + ouch(); + } + if(nn < 0.0 || nn > bigx) + ouch(); + if(nn == 0.0) + nn = 1.0; + if(nn < 230.0){ + for(i := 0; i < len pt; i++){ + r := real pt[i]; + if(r < nn) + continue; + if(r > limit) + exit; + sys->print("%d\n", pt[i]); + if(limit >= bigx) + exit; + } + nn = 230.0; + } + (t, nil) := maths->modf(nn/2.0); + nn = 2.0*real t+1.0; + for(;;){ + # + # clear the sieve table. + # + for(i := 0; i < len table; i++) + table[i] = byte 0; + # + # run the sieve + # + v := maths->sqrt(nn+real (TABLEN*BITS)); + mark(nn, 3); + mark(nn, 5); + mark(nn, 7); + i = 0; + for(k := 11.0; k <= v; k += wheel[i]){ + mark(nn, int k); + i++; + if(i >= len wheel) + i = 0; + } + # + # now get the primes from the table and print them + # + for(i = 0; i < TABLEN*BITS; i += 2){ + if(int table[i>>3]&int bittab[i&8r7]) + continue; + temp := nn+real i; + if(temp > limit) + exit; + sys->print("%d\n", int temp); + if(limit >= bigx) + exit; + } + nn += real (TABLEN*BITS); + } +} + +mark(nn: real, k: int) +{ + (it1, nil) := maths->modf(nn/real k); + j := int (real k*real it1-nn); + if(j < 0) + j += k; + for(; j < len table*BITS; j += k) + table[j>>3] |= bittab[j&8r7]; +} + +ouch() +{ + sys->fprint(sys->fildes(2), "primes: limits exceeded\n"); + raise "fail:ouch"; +} + diff --git a/appl/math/sieve.b b/appl/math/sieve.b new file mode 100644 index 00000000..25d4b0f1 --- /dev/null +++ b/appl/math/sieve.b @@ -0,0 +1,220 @@ +implement Sieve; + +include "sys.m"; + sys: Sys; +include "draw.m"; +include "arg.m"; + arg: Arg; + +M: con 16*1024*1024; +N: con 8*M; +T: con 2*1024*1024; + +limit := array[5] of { M, N, 2*N, 3*N, 15*(N/4) }; + +Sieve: module +{ + init: fn(nil: ref Draw->Context, argv: list of string); +}; + +init(nil: ref Draw->Context, argv: list of string) +{ + sys = load Sys Sys->PATH; + arg = load Arg Arg->PATH; + + np := 0; + alg := 3; + arg->init(argv); + while((c := arg->opt()) != 0){ + case (c){ + 'a' => + alg = int arg->arg(); + } + } + if(alg < 0 || alg > 4) + alg = 3; + lim := limit[alg]; + argv = arg->argv(); + if(argv != nil) + lim = int hd argv; + if(lim < 0 || lim > limit[alg]) + lim = limit[alg]; + if(lim < 6){ + if(lim > 2){ + sys->print("2\n"); + np++; + } + if(lim > 3){ + sys->print("3\n"); + np++; + } + } + else{ + case (alg){ + 0 => np = init0(lim); + 1 => np = init1(lim); + 2 => np = init2(lim); + 3 => np = init3(lim); + 4 => np = init4(lim); + } + } + sys->print("%d primes < %d\n", np, lim); +} + +init0(lim: int): int +{ + p := array[lim] of byte; + for(i := 0; i < lim; i++) + p[i] = byte 1; + p[0] = p[1] = byte 0; + np := 0; + for(i = 0; i < lim; i++){ + if(p[i] == byte 1){ + np++; + sys->print("%d\n", i); + for(j := i+i; j < lim; j += i) + p[j] = byte 0; + } + } + return np; +} + +init1(lim: int): int +{ + n := (lim+31)/32; + p := array[n] of int; + for(i := 0; i < n; i++) + p[i] = int 16rffffffff; + p[0] = int 16rfffffffc; + np := 0; + for(i = 0; i < lim; i++){ + if(p[i>>5] & (1<<(i&31))){ + np++; + sys->print("%d\n", i); + for(j := i+i; j < lim; j += i) + p[j>>5] &= ~(1<<(j&31)); + } + } + return np; +} + +init2(lim: int): int +{ + n := ((lim+1)/2+31)/32; + p := array[n] of int; + for(i := 0; i < n; i++) + p[i] = int 16rffffffff; + p[0] = int 16rfffffffe; + np := 1; + sys->print("%d\n", 2); + for(i = 1; i < lim; i += 2){ + k := (i-1)>>1; + if(p[k>>5] & (1<<(k&31))){ + np++; + sys->print("%d\n", i); + inc := i+i; + for(j := i+i+i; j < lim; j += inc){ + k = (j-1)>>1; + p[k>>5] &= ~(1<<(k&31)); + } + } + } + return np; +} + +init3(lim: int): int +{ + n := ((lim+2)/3+31)/32; + p := array[n] of int; + for(i := 0; i < n; i++) + p[i] = int 16rffffffff; + p[0] = int 16rfffffffe; + np := 2; + sys->print("%d\n", 2); + sys->print("%d\n", 3); + d := 2; + for(i = 1; i < lim; i += d){ + k := (i-1)/3; + if(p[k>>5] & (1<<(k&31))){ + np++; + sys->print("%d\n", i); + inc := 6*i; + for(j := 5*i; j > 0 && j < lim; j += inc){ + k = (j-1)/3; + p[k>>5] &= ~(1<<(k&31)); + } + for(j = 7*i; j > 0 && j < lim; j += inc){ + k = (j-1)/3; + p[k>>5] &= ~(1<<(k&31)); + } + } + d = 6-d; + } + return np; +} + +init4(lim: int): int +{ + n := (4*((lim+14)/15)+31)/32; + p := array[n] of int; + for(i := 0; i < n; i++) + p[i] = int 16rffffffff; + p[0] = int 16rfffffffe; + np := 3; + sys->print("%d\n", 2); + sys->print("%d\n", 3); + sys->print("%d\n", 5); + m := -1; + d := array[8] of { 6, 4, 2, 4, 2, 4, 6, 2 }; + for(i = 1; i < lim; i += d[m]){ + k := (17*(i%30-1))/60+8*(i/30); + if(p[k>>5] & (1<<(k&31))){ + np++; + sys->print("%d\n", i); + inc := 30*i; + for(j := 7*i; j > 0 && j < lim; j += inc){ + k = (17*(j%30-1))/60+8*(j/30); + p[k>>5] &= ~(1<<(k&31)); + } + for(j = 11*i; j > 0 && j < lim; j += inc){ + k = (17*(j%30-1))/60+8*(j/30); + p[k>>5] &= ~(1<<(k&31)); + } + for(j = 13*i; j > 0 && j < lim; j += inc){ + k = (17*(j%30-1))/60+8*(j/30); + p[k>>5] &= ~(1<<(k&31)); + } + for(j = 17*i; j > 0 && j < lim; j += inc){ + k = (17*(j%30-1))/60+8*(j/30); + p[k>>5] &= ~(1<<(k&31)); + } + for(j = 19*i; j > 0 && j < lim; j += inc){ + k = (17*(j%30-1))/60+8*(j/30); + p[k>>5] &= ~(1<<(k&31)); + } + for(j = 23*i; j > 0 && j < lim; j += inc){ + k = (17*(j%30-1))/60+8*(j/30); + p[k>>5] &= ~(1<<(k&31)); + } + for(j = 29*i; j > 0 && j < lim; j += inc){ + k = (17*(j%30-1))/60+8*(j/30); + p[k>>5] &= ~(1<<(k&31)); + } + for(j = 31*i; j > 0 && j < lim; j += inc){ + k = (17*(j%30-1))/60+8*(j/30); + p[k>>5] &= ~(1<<(k&31)); + } + } + m++; + if(m == 8) + m = 0; + } + return np; +} + +init5(lim: int): int +{ + # you must be joking + lim = 0; + return 0; +} |
