Skip to content

Tensor contraction? #9

@rreusser

Description

@rreusser

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.

Was 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. 😝

I'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…

What about actually allowing index notation? For example:

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:

{
  args: [ 'array(i,j,k)', 'array(k,l,m)', 'array(i,j,l,m)'],
  contractIndices: ['k'],
  beforeContract: function(a, b, c) { c = 0 },
  body: function(a, b, c) { c += a * b },
  afterContract: function(a, b, c) { }
}

contraction over two indices: Similar. beforeContract and afterContract go just outside the innermost contraction loops:

{
  args: [ 'array(i,j,k)', 'array(j,k,l)', 'array(i,l)' ],
  contractIndices: ['j','k'],
  beforeContract: function(a, b, c) { c = 0 },
  body: function(a, b, c) { c += a * b },
  afterContract: function(a, b, c) { }
}

Average over two of three dimensions: Here the notation gets unwieldy and it starts to feel like it's all falling apart.

{
  args: [ 'array(j)', 'array(i,j,k)', 'size' ],
  contractIndices: ['i', 'k'],
  pre: function( size ) { this.factor = 1 / size.i / size.k }
  beforeContract: function(a, b) { a = 0 },
  body: function(a, b) { a += b },
  afterContract: function(a, b) { b *= this.factor }
}

I 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.

It 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…

Then again, I might be aiming for something more complicated than the benefit derived from it…

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions