Open Source and Traditional Technical Computing Alan Edelman Massachusetts Institute of Technology Scilabtec10 June 16, 2010 How should octave Compete/cooperate with The 800 pound gorilla • Hard to beat that “first date” experience • Great numerical analyst Cleve Moler • People think MATLAB’s answer is right, even when it’s wrong • Incredible documentation • Years and years of experience • Tons of functionality, but it’s not the functionality … vs. the power of “download, next, agree, next, next, next, install” Critical: trust in the numerics but: • Typical user: In grade school, math was either right or wrong. Getting it “wrong” meant: bad boy/bad girl. (Very shameful!) • By extension, if a computer gets it wrong “Shame, Bad computer! Bad programmer!” Most of the world’s users don’t understand ill-conditioning, good/bad relative accuracy, forward/backward error. My personal hypothesis regarding the Pentium Bug of 1993: Bad division might have lead somebody to make money and somebody to lose money, but the affected parties were blissfully unaware! Time feels right to harness… Kahan But none of these… • Tons of Numerical Analysis Classes • Research from – Classical & IEEE numerical analysis – Algorithmic design – Function Encyclopedias and Software • Experience of libraries and computing environments – LAPACK, MATLAB®, Mathematica, Maple – scilab, python, R Teach a young library writer what to do… Misconceptions • There is a right and a wrong. • Computers are highly consistent: – In fact there are (poorly understood) tradeoffs. – Programs are remarkably idiosynchratic Back to Open source • With open source, we can “see” and critique the algorithms. • With private code we can only test • Math: Det(matrix of integers)=integer But is it right? • • a=sign(randn(27)),det(a) a= 1 -1 -1 -1 1 -1 1 -1 -1 -1 1 -1 1 -1 -1 1 1 1 -1 1 -1 -1 -1 1 1 1 1 1 -1 1 -1 1 1 -1 1 1 1 -1 1 1 1 1 -1 1 1 -1 -1 1 -1 1 -1 1 -1 -1 1 • ans = 839466457497601 -1 -1 1 1 1 -1 1 -1 -1 -1 -1 -1 -1 -1 1 -1 -1 -1 -1 -1 1 -1 1 1 1 1 1 1 -1 -1 -1 1 -1 -1 1 1 -1 -1 -1 1 1 -1 1 1 -1 1 -1 1 1 1 1 -1 1 -1 -1 1 -1 -1 1 -1 1 1 1 1 1 -1 1 -1 1 1 1 1 1 -1 -1 1 1 1 1 -1 -1 1 1 -1 -1 1 -1 1 1 -1 1 -1 -1 -1 1 -1 -1 -1 -1 -1 -1 -1 1 -1 -1 -1 -1 -1 -1 1 -1 -1 -1 1 -1 -1 -1 -1 -1 1 1 1 1 1 1 1 1 -1 1 1 -1 1 1 1 1 -1 1 1 -1 1 -1 -1 -1 -1 -1 -1 -1 1 1 -1 -1 1 -1 -1 -1 -1 1 -1 -1 1 1 1 -1 1 -1 1 -1 1 1 1 -1 -1 1 -1 -1 -1 -1 -1 1 -1 1 -1 -1 -1 1 1 -1 1 -1 -1 -1 -1 -1 -1 -1 1 -1 1 1 -1 -1 -1 -1 1 1 -1 -1 -1 -1 -1 1 -1 -1 1 -1 1 -1 1 -1 -1 1 1 -1 1 1 1 -1 -1 -1 1 -1 1 1 -1 1 1 1 -1 1 -1 -1 1 -1 1 -1 -1 1 1 -1 -1 1 1 -1 -1 1 1 1 -1 -1 -1 1 1 1 -1 1 -1 1 1 1 -1 -1 1 1 1 -1 1 1 1 1 -1 -1 -1 1 -1 -1 -1 1 1 1 1 1 -1 -1 1 1 -1 1 -1 1 -1 1 1 -1 1 1 1 1 -1 -1 1 -1 -1 1 -1 -1 1 -1 -1 1 1 -1 -1 1 -1 -1 1 1 -1 -1 1 -1 -1 -1 -1 -1 1 1 -1 -1 -1 1 -1 1 -1 -1 -1 -1 -1 1 1 1 -1 1 -1 -1 -1 1 1 1 1 -1 1 1 -1 -1 -1 -1 1 1 -1 1 1 1 -1 1 -1 1 -1 -1 -1 -1 -1 1 1 -1 1 -1 1 -1 -1 -1 -1 1 1 1 1 -1 -1 1 1 -1 1 -1 1 1 1 -1 1 -1 1 1 1 1 1 1 1 1 1 1 -1 1 1 -1 -1 -1 -1 1 -1 1 1 1 -1 -1 1 1 -1 -1 1 1 -1 1 1 -1 -1 -1 1 1 -1 -1 -1 -1 1 1 1 1 -1 -1 -1 -1 -1 -1 -1 1 -1 1 1 1 -1 -1 1 1 -1 1 1 -1 -1 -1 1 -1 -1 -1 -1 -1 1 1 1 -1 1 1 1 -1 -1 1 1 1 1 -1 1 -1 -1 1 -1 1 -1 -1 1 -1 1 1 1 -1 -1 1 1 -1 1 1 -1 1 1 1 -1 -1 -1 -1 1 1 1 1 -1 -1 1 -1 1 1 1 -1 -1 1 1 1 -1 1 1 1 -1 -1 -1 1 1 -1 -1 1 -1 -1 1 1 -1 1 -1 -1 1 -1 1 1 1 -1 1 1 -1 -1 -1 1 1 -1 1 -1 -1 1 1 -1 1 1 -1 1 1 -1 -1 -1 1 1 1 -1 1 1 -1 1 -1 1 1 1 1 -1 -1 -1 1 1 1 -1 -1 -1 -1 -1 1 1 -1 -1 -1 1 -1 1 1 -1 1 -1 1 -1 1 1 1 1 -1 -1 -1 1 -1 -1 1 1 1 1 1 -1 1 -1 -1 1 1 -1 1 1 -1 1 1 1 -1 1 -1 -1 1 -1 1 -1 1 1 -1 1 -1 -1 -1 1 -1 -1 -1 Continuity is a function property, not seen at a point octave:> atan(1+i*2^64*[1 1+eps])) ans = 1.5708 -1.5708 Sloppy? Okay? tan(x+pi) is tan(x) after all so is it okay to return atan(x) + pi * any integer Principle: Continuity is required even if special handling is required on branch cuts, stratifications, etc. What about QR? Some people argue it’s different, it’s okay to just produce a Q and R such that QR is nearly A Nonsense, continuity is required! Example 2: Continuity • Arctan: Analytic in complex plane ∞ – Except at usual branch cuts: ±i(1, ) – Undefined at ±i (Arguably NaN+i*Inf, but there’s another nightmare for another time) – Deserves to be continuous off the imaginary axis? • Example along real(z) = 1: octave:> atan(1+i*2^64*[1 1+eps])) ans = 1.5708 -1.5708 Sloppy? Okay? tan(x+pi) is tan(x) after all so is it okay to return atan(x) + pi * any integer Example1 : Numerical Accuracy • Statistics Function: “erfinv” (erfinv(erf)=“Identity function”) • >> erfinv([.6827 .9545 0.9973])*sqrt(2) ans = 1.0000 2.0000 3.0000 • In a sample of floating point numbers from [1,2) how unusual is it to be an integer? >> erfinv(1-eps) Exact: 5.8050186831934533001812 MATLAB: 5.805365688510648 erfinv(1-eps - eps/2) is exactly 5.77049185355333287054782 and erfinv(1-eps + eps/2) is exactly 5.86358474875516792720766 condition number is O(1e14) • Plain old “inv”: (inv(A) composed with A=“Identity”) • >> a=0; inv(a) Warning: Matrix is close to singular or badly scaled. . Possible Conclusions? • Bad Algorithm: should have had a small forward error • Bad MATLAB®: should have warned us • Good backward error so we need not worry? • The user was already in extremely bad shape or extremely good shape anyway: – Already “been hit by a truck”. (Think eigenvalues when pseudos!) – Somehow won’t matter. (Think preconditioning!) • Problem is too ridiculous (but this attitude always comes back to haunt you …) Speaking of QR • What about portability? • Need the Rosetta Stone Speaking of QR • What about portability? A=ones(4,4) Continuity is a function property, not seen at a point: QR • No different from atan • Good enough to take atan+pi*(random integer?) • Is it okay to take Q*diag(random(signs?))? – There is an argument to avoid gratuitous discontinuity! Just like atan – Many people take [Q,R]=qr(randn(n)) to get uniformly distributed orthogonal matrices! But broken because Q is only piecewise continuous. – Backward error analysis has a subtlety. We guarantee that [Q,R] is “a” QR decomposition of a nearby matrix, not “the” QR decomposition of a nearby matrix. Even without roundoff, there may be no algorithm specified that gives “THIS” QR for the rounded output. Example 3: Embeddings • log2(2^k)? log10(10^k)? • (double)^(integer)? • Integers are embedded in reals • Reals embedded in complexes • 2d arrays embedded in nd arrays Determinant: >> m=magic(6); [det(m) prod(svd(m)) prod(diag(lu(m)))]' ans = 1.0e-07 * 0 0.147868183627696 0.080494970688960 Opinion • I like the embedding concept • But the answer should be right, continuous, and monotonic without side affects • Terrible embedding: sort >> x=[-1 1 2] x= -1 1 2 >> sort(x) ans = -1 1 2 >> x=[-1 1 2*i] x= -1.0000 1.0000 >> sort(x) ans = 1.0000 -1.0000 >> 1 < (2*i) ans = 0 >> 1 > (2*i) ans = 1 >> max(1,i) ans = 1 >> min(1,i) ans = 1 >> max(i,1) ans = 0 + 1.0000i >> min(i,1) ans = 0 + 1.0000i Sorting 0 + 2.0000i 0 + 2.0000i >> x=[1 -1 i]'; y=[1;-1;-i]; [x y x-y] ans = 1.0000 1.0000 -1.0000 -1.0000 0 - 1.0000i 0 - 1.0000i >> [sort(x) sort(y)] ans = -1.0000 0 - 1.0000i 0 - 1.0000i 1.0000 1.0000 -1.0000 >> a=[-2 -1 1 2 3 ]; roots(poly(a))' ans = 3.0000 -2.0000 -1.0000 2.0000 1.0000 0 0 0 Lowering Friction between systems First Element Accuracy: Sine Function Extreme Argument sin(2^64)=0.0235985099044395586343659… One IEEE double ulp higher: sin(2^64+4096)=0.6134493700154282634382759… over 651 wavelengths higher. 2^64 is a good test case Maple 10 evalhf(sin(2^64)); 0.0235985099044395581 note evalf(sin(2^64)) does not accurately use 2^64 but rather computes evalf(sin(evalf(2^64,10))) Print[N[Sin[2^64]]]; Print[N[Sin[2^64],20]]; 0.312821* 0.023598509904439558634 MATLAB sin(2^64) 0.023598509904440 sin(single(2^64)) 0.0235985 Octave 2.1.72: sin(2^64) 0.312821314503348* python 2.5 numpy sin(2**64) 0.24726064630941769** R 2.4.0 format(sin(2^64),digits=17) 0.24726064630941769** Scilab format(25);sin(2^64) 0.0235985099044395581214 Mathematica 6.0 *Mathematica and python have been observed to give the correct answer on certain 64 bit linux machines. **The python and R above numbers listed here were taken with Windows XP. The .3128 number was seen with python on a 32 bit linux machine. The correct answer was seen with R on a sun4 machine. It’s very likely that default N in MMA, Octave, Python, and R pass thru to various libraries, such as LIBM, and MSVCRT.DLL. Notes: Maple and Mathematica use both hardware floating point and custom vpa MATLAB discloses use of FDLIBM. MATLAB and extra precision MAPLE and Mathematica can claim small forward error All others can claim small backward error Excel doesn’t compute 2^64 accurately and sin is an error. Google gives 0.312821315 Ruby on http://tryruby.hobix.com/ gives -0.35464… for Math.sin(2**64). On a sun4 the correct was given with Ruby. Relative Backward Error <= (2pi/2^64) = 3e-19 Relative Condition Number = abs(cos(2^64)dx/sin(2^64))/(dx/2^64) = 8e20 One can see accuracy drainage going back to around 2^21 or so, by powers of 2 Edge Case: Sine Function at Infinity • Maple: • • • • • • sin(infinity); undefined evalf(sin(infinity)); Float(undefined) Mathematica: Sin[Infinity] MATLAB: sin(inf) Octave: “ “ Numpy: “ “ R: sin(Inf) Scilab: sin(%inf) Interval[{-1., 1.}] NaN ““ -1.#IND NaN (and a warning) Nan Coverage: Erf Function Complex Support python/scipy is the only numerical package good • Maple: evalf(erf(I)); 1.650425759 I • Mathematica: N[Erf[I]] 0. + 1.65043 I • MATLAB: erf(i) ??? Input must be real. • Octave: “ “ error: • Python/Scipy: erf(1j) • R: pnorm(1i) erf: unable to handle complex argument 1.6504257588j Error in pnorm … Non-numeric argument • • Scilab: erf(%i) !--error 52 argument must be a real … Optimization • Would love to see the “Consumer Reports Style” Article Scorecard Approach Unique Opportunity • • • Raise the bar for all functions: – Linear Algebra! – Elementary Functions – Special Functions – Hard Functions: Optimization/Diff Eqs – Combinatorial and Set Functions What about – 0-d, 1-d, n-d arrays, empty arrays – Inf, Not Available (NaN) – Types (integer, double, complex) and embeddings • (real inside complex, matrices insidse n-d arrays) Methodology – Work in Progress: Create a web experience that guides and educates users in the amount of time that it takes to say Wikipedia – Futuristic?: The Semantic Web and Other Automations? Extra Slides • Extra Slides The Linear Algebra World • Some of the world’s best practices. • Still Inconsistent, still complicated. • Never go wrong reading a book authored by someone named Nick, a paper or key example by Velvel, all the good stuff in terms of error bounds of LAPACK and papers from our community Computing Environments: what’s appropriate? • “Good” numerics? – Who defines good? – How do we evaluate? • Seamless portability? – Rosetta stone? – “Consumer Reports?” • Easy to learn? • Good documentation? • Proprietary or Free? – “Download, next, next, next, enter, and compute?” Numerical Errors: What’s appropriate? • • • • • • • • • The exact answer? What MATLAB® gives! float(f(x))??? (e.g. some trig libraries) Small Forward Error Small Backward Error Nice Mathematical Properties What people expect, right or wrong Consistent? Nice mathematics? Coverage: Sine Function Complex Support • All packages seem good » » » » » » » » » Maple: evalf(sin(I)) Mathematica: N[Sin[I]] MATLAB: sin(i) Octave: “ “ Numpy: sin(1j) R: sin(1i) Ruby: require 'complex'; Complex::I; Math::sin(Complex::I) Scilab: sin(%i) EXCEL: =IMSIN(COMPLEX(0,1)) Note special command in excel Coverage: Erf Function Complex Support python/scipy is the only numerical package good • Maple: evalf(erf(I)); 1.650425759 I • Mathematica: N[Erf[I]] 0. + 1.65043 I • MATLAB: erf(i) ??? Input must be real. • Octave: “ “ error: • Python/Scipy: erf(1j) • R: pnorm(1i) erf: unable to handle complex argument 1.6504257588j Error in pnorm … Non-numeric argument • • Scilab: erf(%i) !--error 52 argument must be a real …