{"action":"created","issue":{"url":"https://api.github.com/repos/scijs/cwise/issues/9","labels_url":"https://api.github.com/repos/scijs/cwise/issues/9/labels{/name}","comments_url":"https://api.github.com/repos/scijs/cwise/issues/9/comments","events_url":"https://api.github.com/repos/scijs/cwise/issues/9/events","html_url":"https://github.com/scijs/cwise/issues/9","id":101306434,"number":9,"title":"Tensor contraction?","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":3,"created_at":"2015-08-16T22:45:54Z","updated_at":"2015-08-17T13:11:01Z","closed_at":null,"body":"Following up here on my ill-advised rreusser/ndarray-awise-prototype#1 since this is starting to seem more like a extension or fork of cwise than a use of cwise.\r\n\r\nWas trying to figure out how to express reduce operations in a general manner but fell way short. Your response \"there are probably better ways to do this but hey, more than one way to skin a cat\" is way too kind. :stuck_out_tongue_closed_eyes:\r\n\r\nI'm currently thinking about what it'd mean to reorder dimensions within cwise. Expressing this seems the most immediately challenging part while the rest is an exercise for the implementer…\r\n\r\nWhat about actually allowing index notation? For example:\r\n\r\n**contraction over one index**: In other words, matrix multiplication. The `k` loop goes on the inside with its `pre`/`post` just outside it. The scope of `this` would be only over a `k` loop, but you could use c directly. Would have to think about a syntax that would actually allow gemm-style block-wise multiplications. Represented as:\r\n```javascript\r\n{\r\n  args: [ 'array(i,j,k)', 'array(k,l,m)', 'array(i,j,l,m)'],\r\n  contractIndices: ['k'],\r\n  beforeContract: function(a, b, c) { c = 0 },\r\n  body: function(a, b, c) { c += a * b },\r\n  afterContract: function(a, b, c) { }\r\n}\r\n```\r\n\r\n**contraction over two indices**: Similar. `beforeContract` and `afterContract` go just outside the innermost contraction loops:\r\n\r\n```javascript\r\n{\r\n  args: [ 'array(i,j,k)', 'array(j,k,l)', 'array(i,l)' ],\r\n  contractIndices: ['j','k'],\r\n  beforeContract: function(a, b, c) { c = 0 },\r\n  body: function(a, b, c) { c += a * b },\r\n  afterContract: function(a, b, c) { }\r\n}\r\n```\r\n\r\n**Average over two of three dimensions**: Here the notation gets unwieldy and it starts to feel like it's all falling apart.\r\n\r\n```javascript\r\n{\r\n  args: [ 'array(j)', 'array(i,j,k)', 'size' ],\r\n  contractIndices: ['i', 'k'],\r\n  pre: function( size ) { this.factor = 1 / size.i / size.k }\r\n  beforeContract: function(a, b) { a = 0 },\r\n  body: function(a, b) { a += b },\r\n  afterContract: function(a, b) { b *= this.factor }\r\n}\r\n```\r\n\r\nI think this is logically consistent and can be optimized within reason (or at least reduces to cwise if unused). It seems possible but probably too invasive to work into cwise which seems more oriented toward image processing. Features like `blockIndices` and `offset` are great, but it might add factorial complexity to get all combinations of cases to play well together.\r\n\r\nIt sounded like you've thought about this before. I think what I've described is a thing that *could* exist; I just don't know if it's a thing that *should* exist…\r\n\r\nThen again, I might be aiming for something more complicated than the benefit derived from it…"},"comment":{"url":"https://api.github.com/repos/scijs/cwise/issues/comments/131813362","html_url":"https://github.com/scijs/cwise/issues/9#issuecomment-131813362","issue_url":"https://api.github.com/repos/scijs/cwise/issues/9","id":131813362,"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-08-17T13:11:01Z","updated_at":"2015-08-17T13:11:01Z","body":"Clarification: not so much advocating different forks, just a separation of declaration of the operation from internal representation of the operation, as you've suggested."}}