{"action":"created","issue":{"url":"https://api.github.com/repos/scijs/ndarray-householder-qr/issues/6","labels_url":"https://api.github.com/repos/scijs/ndarray-householder-qr/issues/6/labels{/name}","comments_url":"https://api.github.com/repos/scijs/ndarray-householder-qr/issues/6/comments","events_url":"https://api.github.com/repos/scijs/ndarray-householder-qr/issues/6/events","html_url":"https://github.com/scijs/ndarray-householder-qr/pull/6","id":77853623,"number":6,"title":"Unroll slices to avoid garbage collection","user":{"login":"rreusser","id":572717,"avatar_url":"https://avatars.githubusercontent.com/u/572717?v=3","gravatar_id":"","url":"https://api.github.com/users/rreusser","html_url":"https://github.com/rreusser","followers_url":"https://api.github.com/users/rreusser/followers","following_url":"https://api.github.com/users/rreusser/following{/other_user}","gists_url":"https://api.github.com/users/rreusser/gists{/gist_id}","starred_url":"https://api.github.com/users/rreusser/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rreusser/subscriptions","organizations_url":"https://api.github.com/users/rreusser/orgs","repos_url":"https://api.github.com/users/rreusser/repos","events_url":"https://api.github.com/users/rreusser/events{/privacy}","received_events_url":"https://api.github.com/users/rreusser/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2015-05-18T23:40:23Z","updated_at":"2015-05-19T03:18:59Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/scijs/ndarray-householder-qr/pulls/6","html_url":"https://github.com/scijs/ndarray-householder-qr/pull/6","diff_url":"https://github.com/scijs/ndarray-householder-qr/pull/6.diff","patch_url":"https://github.com/scijs/ndarray-householder-qr/pull/6.patch"},"body":"@mikolalysenko — I was curious how I might optimize these linear algebra routines, so I tried out unrolling the slices so that it doesn't instantiate new ndarray slices on every inner loop iteration. Instead, it just calculates a single slice at the beginning and increments the offset. (I also just set `*.data[…]` directly in some spots since `.set(0,…)` is trivial — although this certainly doesn't amount to any speedup). I added tests using slices of high-dimensional arrays with weird steps as input, so I'm reasonably confident in the correctness. The result is significantly less maintainable but avoids lots of object allocation/garbage collection.\r\n\r\n**Question**: I'll profile to see if it has any affect, but at a glance, do you think this is a remotely reasonable approach once things have been developed and tested? I feel like the original version should be saved so that it's clear where this madness came from. It's basically the sort of thing cwise does, just by hand…\r\n\r\nHere's an example:\r\n\r\n```javascript\r\n  // Instantiate a single slice at the beginning:\r\n  Ajmj = A.pick(null,0)\r\n  Ajmi = A.pick(null,0)\r\n\r\n  // Figure out the offsets and increments:\r\n  var AjmjInc = A.stride[0] + A.stride[1]\r\n  var AjmiOff = Ajmi.offset\r\n  var AjmiInc1 = A.stride[0]\r\n  var AjmiInc2 = A.stride[1]\r\n  var dInc = d.stride[0]\r\n  var dOff = d.offset\r\n\r\n  for( j=0; j<n; j++, Ajmj.shape[0]--, Ajmj.offset+=AjmjInc, AjmiOff+=AjmiInc1, dOff+=dInc) {\r\n    s = blas.nrm2(Ajmj)\r\n    ajj = Ajmj.data[Ajmj.offset]\r\n    dj = ajj > 0 ? -s : s \r\n    d.data[dOff] = dj\r\n    s = Math.sqrt( s * (s + Math.abs(ajj)) )\r\n    if( s === 0 ) return false\r\n    Ajmj.data[Ajmj.offset] = ajj - dj\r\n    blas.scal( 1/s, Ajmj)\r\n\r\n    for(i=j+1, Ajmi.offset=AjmiOff + AjmiInc2*(j+1); i<n; i++, Ajmi.offset+=AjmiInc2) {\r\n      s = - blas.dot( Ajmj, Ajmi )\r\n      blas.axpy( s, Ajmj, Ajmi )\r\n    }   \r\n  }\r\n\r\n  return true\r\n}\r\n```"},"comment":{"url":"https://api.github.com/repos/scijs/ndarray-householder-qr/issues/comments/103315849","html_url":"https://github.com/scijs/ndarray-householder-qr/pull/6#issuecomment-103315849","issue_url":"https://api.github.com/repos/scijs/ndarray-householder-qr/issues/6","id":103315849,"user":{"login":"rreusser","id":572717,"avatar_url":"https://avatars.githubusercontent.com/u/572717?v=3","gravatar_id":"","url":"https://api.github.com/users/rreusser","html_url":"https://github.com/rreusser","followers_url":"https://api.github.com/users/rreusser/followers","following_url":"https://api.github.com/users/rreusser/following{/other_user}","gists_url":"https://api.github.com/users/rreusser/gists{/gist_id}","starred_url":"https://api.github.com/users/rreusser/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rreusser/subscriptions","organizations_url":"https://api.github.com/users/rreusser/orgs","repos_url":"https://api.github.com/users/rreusser/repos","events_url":"https://api.github.com/users/rreusser/events{/privacy}","received_events_url":"https://api.github.com/users/rreusser/received_events","type":"User","site_admin":false},"created_at":"2015-05-19T03:18:59Z","updated_at":"2015-05-19T03:18:59Z","body":"Upon thinking about this for a while, I've realized that in the first place, ndarrays are really only a thin (but effective!) wrapper around index logic, and that BLAS's support for strides and offsets are perfectly compatible. So in other words, it seems what I'm really working toward is either a simple macro layer to unroll these things (similar to cwise except designed to be integrated into algorithms like this) or just unrolling it and plugging it into *real* BLAS. Or just plugging ndarrays into LAPACK or something. Hmmm…"}}