Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply function row/column-wise #154

Open
npiccolotto opened this issue Sep 1, 2022 · 3 comments
Open

Apply function row/column-wise #154

npiccolotto opened this issue Sep 1, 2022 · 3 comments

Comments

@npiccolotto
Copy link

Hello,

thanks for the great library, I use it quite often in my work. Something I didn't find in the API and thus copy around my projects is an apply function? Like R's apply or numpy's apply_along_axis.

It seems like a simple function, my implementation is basically

function apply(M, fun, axis = 1) {
  // axis = 0: apply and collapse along cols (= output length is # rows)
  // axis = 1: apply and collapse along rows (= output length is # cols)
  const collapseRows = axis === 1;
  const n = collapseRows ? M.columns : M.rows;
  const result = [];
  for (let i = 0; i < n; i++) {
    const x = collapseRows ? M.getColumn(i) : M.getRow(i);
    result.push(fun(x));
  }
  return Matrix.rowVector(result); // NOTE could also be columnVector depending on `axis`, I just never wanted one...
}

Would this be something that you would consider adding to your library?

@targos
Copy link
Member

targos commented Sep 8, 2022

This seems like a useful feature. Pull request welcome (please add test cases and update matrix.d.ts)!

We suggest the following signature:

class Matrix {
  applyAlongAxis(
    callback: (vector: number[], index: number) => number,
    by: MatrixDimension
  ): Matrix
}

@Dimava
Copy link
Contributor

Dimava commented Nov 5, 2022

class MatrixExt extends Matrix {
	mapColumns(fun: (column: number[], rowIndex: number, matrix: this) => number | number[]): Matrix {
		const n = this.columns;
		const result = Array();
		for (let i = 0; i < n; i++) {
			const x = this.getColumn(i)
			result.push(fun(x, i, this));
		}
		if (Array.isArray(result[0])) {
			return new Matrix(result).transpose()
		} else {
			return Matrix.rowVector(result);
		}
	}
}

let m = new MatrixExt([
	[1, 2, 3],
	[4, 5, 6],
	[7, 8, 9]
])

console.log(
	m,
	/**
	 * Matrix {
	 *   [
	 *     147      258      369     
	 *   ]
	 */
	m.mapColumns(
		(row, i, a) => row.reduce((r, x) => r * 10 + x)
	),
	/**
	 * Matrix {
	 *  [
	 *    1        2        3       
	 *    11       22       33      
	 *    4        5        6
	 *    44       55       66
	 *    7        8        9
	 *    77       88       99
	 *  ]
	 */
	m.mapColumns(
		(row, i, a) => row.flatMap(x => [x, x * 11])
	),
)

Here's implementation of an extended variant

What part of it is technically usable?

@npiccolotto
Copy link
Author

Hi, sorry for the late reply, I have actually no idea where the notifications go, if they go somewhere at all.

@Dimava: I like your approach because it's more flexible regarding the resulting matrix dimensions.

@targos: What do you think about it? Should it rather match what exists in other libraries / languages?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants