Using my caching algorithm, and resetting the cache inside the
timespacex sentence (using [cache=:2{.cache on the right hand side), I
see that your fft polynomial division approach is slightly over twice
as fast as my slightly optimized version of your long division
approach for taskorder 10 (or taskorderu 10). There's a bit of
variance here (2.2 times faster or 2.5 times faster), and it's slow
enough that I haven't run a lot of tests.I am also wondering if the fft division mechanism here can be optimized to take advantage of the rather small coefficients in these polynomials. Anyways, lots of tangents to explore. Thanks, -- Raul On Tue, Mar 1, 2022 at 11:19 AM 'Michael Day' via Programming <[email protected]> wrote: > > Raul Miller's and RE Boss's (revised) entries here refer: > http://rosettacode.org/wiki/Cyclotomic_polynomial#J > > I think I'm partly responsible for pDiv in this (otherwise!) nicely > concise and elegant > presentation of J routines to derive these polynomials. > Typically, > NB. (1+5x+10x^2+10x^3+5x^4+x^5 )%(1+3x+3x^2+x^3) = 1+2x+x^2 > 1 5 10 10 5 1 pDiv 1 3 3 1 > 1 2 1 > > pDiv is essentially elementary long division realised for polynomials > rather than numbers; > it's rather inefficient for high-order polynomials, and I was wondering > how to speed it up. > I found a paper by Madhu Sudan which addresses fast polynomial division: > http://people.csail.mit.edu/madhu/ST12/scribe/lect06.pdf > but couldn't understand his hints at an algorithm. I _think_ it > successively improves > approximations to the solution, working up from a constant term, then > modulo x^2, > then x^4 , but it's very muddled to my mind, and my mind couldn't see > how to set about it! > > Then I realised a compromise is to exploit polynomial multiplication > using Fast Fourier Transforms, > as described first for this purpose, I believe, by Roger Hui; Henry's > essay is to be found at > https://code.jsoftware.com/wiki/Essays/FFT > > That article desribes polynomial multiplication, where we multiply the > ffts of two > polynomials extended to an appropriate length, a suitable power of 2. > The inverse fft > is then applied to yield the required polynomial product. > If instead we divide one fft by another, and take the inverse fft, we > get the polynomial > quotient! > > So here's a crib of Raul's functions; I've merged cyclotomic and > cyclotomic000, dispensing > with "cache" and using the memoisation afforded by M. : > (OK in fixed width font) > > ctfft=: {{ assert.0<y > if. y = 1 do. _1 1 return. end. > 'q p'=. __ q: y > if. 1=#q do. > ,(y%*/q) {."0 q#1 > elseif.2={.q do. > ,(y%*/q) {."0 (* 1 _1 $~ #) ct */}.q > elseif. 1 e. 1 < p do. > ,(y%*/q) {."0 ct */q > else. > lgl =. {:$ ctlist =. ct "0 }:*/@>,{1,each q NB. ctlist is > 2-d table of polynomial divisors > lgd =. # dividend =. _1,(-y){.1 NB. (x^n) - 1, > and its size > lg =. >.&.(2&^.) lgl >. lgd NB. required > lengths of all polynomials for fft transforms > NB. really, "divisor" is the fft of the divisor! > divisor =. */ fft"1 lg{."1 ctlist NB. FFT article > doesn't deal with lists of multiplicands > unpad roundreal ifft"1 divisor %~ fft lg{.dividend NB. similar to > article's multiplication > end. > }} M. > > NB. fft, roundreal, ifft from FFT article. > > NB. Performance - poor for lower orders... > NB. taskorderu is adverbial form of taskorder with required verb as left > argument. > > timer'cyclotomic taskorderu 5' NB. timer returns elpased time, > before cache/memoisation established! > ┌────────┬───────────────────┐ > │1.163002│1 105 385 1365 1785│ > └────────┴───────────────────┘ > timer'ctfft taskorderu 5' NB. not too good here cf cyclotomic! > ┌─────────┬───────────────────┐ > │3.5719986│1 105 385 1365 1785│ > └─────────┴───────────────────┘ > NB. continuing with cache/memoisation as above > timer'cyclotomic taskorderu 10' > ┌───────────┬─────────────────────────────────────────────┐ > │5 7.8180008│1 105 385 1365 1785 2805 3135 6545 6545 10465│ > └───────────┴─────────────────────────────────────────────┘ > timer'ctfft taskorderu 10' NB. some improvement! > ┌────────┬─────────────────────────────────────────────┐ > │3 52.945│1 105 385 1365 1785 2805 3135 6545 6545 10465│ > └────────┴─────────────────────────────────────────────┘ > > So - not an order of magnitude effect, but of some interest, I hope! > > Mike > > On 20/02/2022 18:32, Raul Miller wrote: > > Oh, bleah... of course. > > > > y does not change. So that should be a test on {.x -- and that reveals > > that I was using the wrong values throughout that section of code. > > > > Here's a fixed version: > > > > pDiv=: {{ > > q=. $j=. 2 + x -&# y > > 'x y'=. x,:y > > while. j=. j-1 do. > > if. 0={.x do. j=. j-<:i=. 0 i.~ 0=x > > q=. q,i#0 > > x=. i |.!.0 x > > else. > > q=. q, r=. x %&{. y > > x=. 1 |.!.0 x - y*r > > end. > > end.q > > }} > > > > Thanks, > > > > > -- > This email has been checked for viruses by Avast antivirus software. > https://www.avast.com/antivirus > > ---------------------------------------------------------------------- > For information about J forums see http://www.jsoftware.com/forums.htm ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm
