math_ext.sa


Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
 

class ARRAY_EXT{ELT}

class ARRAY_EXT{ELT} is delete_at(i:INT, ar:ARRAY{ELT}):ARRAY{ELT} is --a::=ar.copy; --if i<a.size-1 then a.copy(i,a.size-1-i, i+1,a); end; --a:=a.resize(a.size-1); --return a; a:ARRAY{ELT}:=#(ar.size-1); if 0<i then a.copy(0,i,ar); end; if i<ar.size-1 then a.copy(i,ar.size-i-1,i+1,ar); end; return a; end; insert_at(i:INT, ar:ARRAY{ELT}, e:ELT):ARRAY{ELT} pre (0<=i)and(i<=ar.size) is if i=0 then res:ARRAY{ELT}:=#(ar.size+1); res[0]:=e; res.copy(1,ar); return res; elsif i=ar.size then return ar.append(|e|); else res:ARRAY{ELT}:=#(ar.size+1); res.copy(0,i,ar); res[i]:=e; res.copy(i+1,ar.size-i,i,ar); return res; end; end; insert_at(i:INT,ar0:ARRAY{ELT},ar1:ARRAY{ELT}):ARRAY{ELT} pre (0<=i)and(i<=ar0.size) is if i=0 then return ar1.append(ar0); elsif i=ar0.size then return ar0.append(ar1); else res:ARRAY{ELT}:=#(ar0.size+ar1.size); res.copy(0,i,ar0); res.copy(i,ar1); res.copy(i+ar1.size,ar0.size-i,i,ar0); return res; end; end; end;

class ARRAY_SORT{ELT}

class ARRAY_SORT{ELT} is sorted_insert(ar:ARRAY{ELT}, e:ELT):ARRAY{ELT} is -- assume ar is sorted by increasing order "<". i1:INT:=ar.size; if i1=0 then return |e|; end; i0:INT:=0; i2:INT; loop until!(i0+1=i1); -- binary search i2:=(i0+i1)/2; if ar[i2]>e then i1:=i2; else i0:=i2; end; end; if ar[i0]>e then i1:=i0; end; res::=ARRAY_EXT{ELT}::insert_at(i1,ar,e); -- assert res.is_sorted; return res; end; sorted_rev_insert(ar:ARRAY{ELT}, e:ELT):ARRAY{ELT} is -- assume ar is sorted by decreasing order ">". i1:INT:=ar.size; if i1=0 then return |e|; end; i0:INT:=0; i2:INT; loop until!(i0+1=i1); -- binary search i2:=(i0+i1)/2; if ar[i2]<e then i1:=i2; else i0:=i2; end; end; if ar[i0]<e then i1:=i0; end; res::=ARRAY_EXT{ELT}::insert_at(i1,ar,e); -- res:=res.reverse; assert res.is_sorted; res:=res.reverse; return res; end; insertion_sort(inout ar:ARRAY{ELT}) is -- stable sort. if void(ar) then return; end; insertion_sort_range(inout ar,0,ar.size-1); end; insertion_sort_range(inout ar:ARRAY{ELT},l,u:INT) is -- stable sort. -- sort by increasing order "<". i0,i1:INT; loop i::=(l+1).upto!(u); e:ELT:=ar[i]; i1:=i-1; if e<ar[i1] then ; -- is_lt if e<ar[l] then i1:=l; -- is_lt else i0:=l; loop until!(i0+1=i1); i2::=(i0+i1)/2; -- binary search if e<ar[i2] then i1:=i2; else i0:=i2; end; -- is_lt end; end; loop j::=i.downto!(i1+1); ar[j]:=ar[j-1]; end; ar[i1]:=e; --insertion end; end; end; ---------- Quick sort from Sather libraly. --------- private const quicksort_limit:INT:=20; -- When to stop the -- quicksort recursion and switch to insertion sort. quicksort_range(inout ar:ARRAY{ELT},l,u:INT) pre ~void(ar) and l.is_bet(0,ar.size-1) and u.is_bet(l,ar.size-1) is -- Use quicksort to sort the elements of self from `l' to `u' -- inclusive according to `elt_lt'. if u-l>quicksort_limit then r::=RND::int(l,u); t::=ar[r]; ar[r]:=ar[l]; ar[l]:=t; m::=l; loop i::=(l+1).upto!(u); if ar[i]<t then m:=m+1; s::=ar[m]; ar[m]:=ar[i]; ar[i]:=s; end; end; t:=ar[l]; ar[l]:=ar[m]; ar[m]:=t; if l < m-1 then quicksort_range(inout ar,l,m-1); end; if m+1 < u then quicksort_range(inout ar,m+1,u); end; else insertion_sort_range(inout ar, l,u); end; end; quick_sort(inout ar:ARRAY{ELT}) -- post ar.is_sorted is -- Use quicksort to permute the elements of self so that -- it is sorted with respect to `elt_lt'. Self may be void. if ~void(ar) then quicksort_range(inout ar, 0,ar.size-1) end; end; end;

class INTI_EXT

class INTI_EXT is --------------------- primes ------------------- is_spsp(x,a:INTI):BOOL is -- is prime or strong pseudo prime of base "a"? s:INT:=0; d:INTI:=x-1.inti; loop while!(d.is_even); s:=s+1; d:=d/2.inti; end; ad:INTI:=1.inti; -- ad=(a**d)%x loop while!(d.is_pos); if d.is_odd then ad:=(ad*a)%x; end; d:=d/2.inti; a:=(a*a)%x; end; if ad=1.inti then return true; end; loop r::=0.upto!(s-1); if ad=(x-1.inti) then return true; end; ad:=(ad*ad)%x; -- ad=a**(d*2**r) end; return false; end; is_fpsp(x,a:INTI):BOOL is -- is prime or Fermat's pseudo prime of base "a"? -- return (a^(x-1.inti)%x=1.inti); d:INTI:=x-1.inti; ad:INTI:=1.inti; an:INTI:=a; loop while!(d.is_pos); if d.is_odd then ad:=(ad*an)%x; end; d:=d/2.inti; an:=(an*an)%x; end; return ad=1.inti; end; is_prime(x:INTI):BOOL is -- Is __x__ prime? if x.is_even then if x=2.inti then return true; else return false; end; elsif 3.inti.evenly_divides(x) then if x=3.inti then return true; else return false; end; elsif 5.inti.evenly_divides(x) then if x=5.inti then return true; else return false; end; elsif 7.inti.evenly_divides(x) then if x=7.inti then return true;else return false; end; elsif 11.inti.evenly_divides(x) then if x=11.inti then return true; else return false; end; elsif 13.inti.evenly_divides(x) then if x=13.inti then return true;else return false; end; elsif x<2.inti then return false; end; -- Check if spsp or fpsp. if (x>1000000000.inti)and(~is_fpsp(x,13.inti)) then return false; end; d:INTI:=x.sqrt; -- r1:=5; r2:=7; -- \pm 1 (mod 6) -- r1:=11; r2:=13; r1:INTI:=17.inti; r2:INTI:=19.inti; loop while!(r1<=d); if r1.evenly_divides(x) then return false; elsif r2.evenly_divides(x) then return false; end; r1:=r1+6.inti; r2:=r2+6.inti; end; return true; end; next_prime(n:INTI):INTI is -- prime next to n. (minimum prime >n) if n<2.inti then return 2.inti; end; k::=n+1.inti; if k.is_even then k:=k+1.inti; end; loop until!(is_prime(k)); k:=k+2.inti; end; return k; end; ------------ multi GCD --------------- gcd(i,j:INTI):INTI is a:INTI:=i.abs; b:INTI:=j.abs; -- x:SAME:=one; y:SAME:=zero; u:SAME:=zero; v:SAME:=one; x:INTI:=#(1); y:INTI:=#(0); u:INTI:=#(0); v:INTI:=#(1); loop if b.is_zero then return a; end; -- a.divmod(b,out q, out a); a:=a%b; if a.is_zero then return b; end; -- b.divmod(a,out q, out b); b:=b%a; end; end; gcd(a:ARRAY{INTI}):INTI is -- multi GCD. return GCD of elements of a[]. g:INTI:=0.inti; loop g:=gcd(a.elt!, g); end; return g; end; extended_gcd(i,j:INTI, out f1: INTI, out f2:INTI):INTI is -- gcd = i*f1 + j*f2 -- x:SAME:=one; y:SAME:=zero; u:SAME:=zero; v:SAME:=one; a,b,q:INTI; x:INTI:=#(1); y:INTI:=#(0); u:INTI:=#(0); v:INTI:=#(1); if i.is_neg then x:=-x; a:=-i; else a:=i; end; if j.is_neg then y:=-y; b:=-j; else b:=j; end; loop if b.is_zero then f1:=x; f2:=y; return a; end; -- a.divmod(b,out q, out a); q:=a/b; a:=a-q*b; x:=x-q*u; y:=y-q*v; if a.is_zero then f1:=u; f2:=v; return b; end; -- b.divmod(a,out q, out b); q:=b/a; b:=b-q*a; u:=u-q*x; v:=v-q*y; end; end; extended_gcd(a:ARRAY{INTI}, out factor:ARRAY{INTI}):INTI is -- multi GCD. return GCD g. g = a . factor factor:=#(a.size); f1,f2:INTI; g:INTI:=0.inti; loop i:INT:=a.ind!; g:=extended_gcd(a[i],g,out f1,out f2); loop j::=0.upto!(i-1); factor[j]:=factor[j]*f2; end; factor[i]:=f1; end; return g; end; inv(p,g:INTI):INTI is -- inverse of g as finite field Zp. -- i.e. p:prime. g*inv(p,g)=1 (mod p). f1,f2:INTI; g:=g%p; -- make "g>0" gcd::=extended_gcd(g, p, out f1, out f2); return f1; end; factorize(n:INTI):ARRAY{INTI} is -- return array of factors with duplication n:=n.abs; f:ARRAY{INTI}:=#; r1::=2.inti; loop while!((n%r1).is_zero); f:=f.append(|r1|); n:=n/r1; end; r1:=3.inti; loop while!((n%r1).is_zero); f:=f.append(|r1|); n:=n/r1; end; r1:=5.inti; r2::=7.inti; --r=\pm 1 (mod 6). So, step s is \pm 2(mod 6). d::=n.sqrt; loop while!(r1<=d); if (n%r1).is_zero then loop while!((n%r1).is_zero); f:=f.append(|r1|); n:=n/r1; end; d:=n.sqrt; end; if (n%r2).is_zero then loop while!((n%r2).is_zero); f:=f.append(|r2|); n:=n/r2; end; d:=n.sqrt; end; r1:=r1+6.inti; r2:=r2+6.inti; end; if (n /= 1)or(f.size=0) then f:=f.append(|n|); end; return f; end; private getDivisorsS(i:INT, divisor:INTI, factors:ARRAY{INTI}, factord:ARRAY{INT}):ARRAY{INTI} is if i>=factors.size then return |divisor|; end; divisors:ARRAY{INTI}:=#; loop j::=0.upto!(factord[i]); divisors:= divisors.append(getDivisorsS(i+1,divisor,factors,factord)); divisor:=divisor*factors[i]; end; return divisors; end; getDivisors(n:INTI):ARRAY{INTI} is -- get all divisors of n factors:ARRAY{INTI}:=factorize(n); factord:ARRAY{INT}:=|1|; i:INT:=0; loop while!(i<factors.size); if factors[i]=factors[i+1] then factord[i]:=factord[i]+1; factors:=ARRAY_EXT{INTI}::delete_at(i+1,factors); else i:=i+1; factord[i]:=1; end; end; return getDivisorsS(0,1.inti,factors,factord); end; checkDivZ(a0,b0,p:INTI):BOOL is -- true if exist "k" s.t. (b+k*prime)|a in Z a::=a0.abs; b::=b0.abs%p; if b.is_zero then return (a%p).is_zero; end; loop while!( (a%p).is_zero); a:=a/p; end; -- x=b or x=-b mod p <=> (x-b)(x+b)=0 mod p <=> x^2=b^2 mod p b2::=(b*b)%p; if a<2500.inti then if ((a*a)%p)=b2 then return true; end; -- (b+k*prime)=-a/2 then k=(-a/2-b)/p, -- (b+k*prime)=a/2 then k=(a/2-b)/p loop k:INTI:=((-a/2.inti-b)/p).upto!((a/2.inti-b)/p); if (a%(b+k*p)).is_zero then return true; end; end; return false; elsif a<1000000.inti then sqrt_i::=a.sqrt; d::=1.inti+(a%2.inti); i:INTI:=1.inti; loop while!(i<=sqrt_i); if (a%i).is_zero then if (i*i)%p=b2 then return true; end; ai::=a/i; if (ai*ai)%p=b2 then return true; end; end; i:=i+d; end; else dv::=getDivisors(a); loop i::=0.upto!(dv.size-1); d::=dv[i]; if (d*d)%p = b2 then return true; end; end; end; return false; end; end;

class PERMUTATION

class PERMUTATION is parity(perm:ARRAY{INT}):INT is -- parity of premutation j:INT; w:ARRAY{INT}:=#(perm.size); loop i:INT:=w.ind!; w[perm[i]]:=i; end; p::=1; loop i:INT:=0.upto!(perm.size-2); j:=perm[i]; if j/=i then perm[w[i]]:=j; w[j]:=w[i]; p:=-p; end; end; return p; end; end;

class VEC_ALG

class VEC_ALG is atn2(x,y:FLT):FLT is -- similar to atan2. return 0<=atn2<4 while 0<=arg(x,y)<2pi s:FLT; if (x=0.0)and(y=0.0) then return 0.0; end; s:=y.abs/(x.abs+y.abs); if (y>=0.0) then if x>=0.0 then return s; else return 2.0-s; end; else if x>=0.0 then return 4.0-s; else return 2.0+s; end; end; end; rotation(x0, y0, x1, y1, x2, y2:INT):INT is -- rotational order of 3-vector p0, p1, p2. -- rotation of 3-pts. p0, p1, p2 = -1,0,1. -- 1: p0-p1-p2 run anti-clockwise. -- -1: p0-p1-p2 run clockwise. -- 0: singular case. r,px0,py0:INT; t0,t1,t2:FLT; if (x0=0)and(y0=0) then return 0; end; if (x1=0)and(y1=0) then return 0; end; if (x2=0)and(y2=0) then return 0; end; --px0:=INT(x0); py0:=INT(y0); --r:=(INT(x1)-px0)*(INT(y2)-py0)-(INT(y1)-py0)*(INT(x2)-px0); --if r>0 then return 1; elsif r<0 then return -1; else return 0; end; t0:=atn2(x0.flt,y0.flt); t1:=atn2(x1.flt,y1.flt); if t1<t0 then t1:=t1+4.0; end; t2:=atn2(x2.flt,y2.flt); if t2<t0 then t2:=t2+4.0; end; if (t0=t1)or(t0=t2)or(t1=t2) then return 0; elsif t1<t2 then return -1; else return 1; end; end; sLength(inout x, inout y:INT, d:INT) is -- change length of the vector(x,y) to d. I assume length(x,y)/=0 vx::=x; vy::=y; l::=vx*vx+vy*vy; if l/=0 then l:=l.flt.sqrt.round.int; x:=(vx*d)/l; y:=(vy*d)/l; end; end; end;