diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 34bc6d2..0000000 --- a/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "plugins": ["@babel/plugin-transform-modules-commonjs"] -} diff --git a/.eslintrc.yml b/.eslintrc.yml deleted file mode 100644 index f40ac5c..0000000 --- a/.eslintrc.yml +++ /dev/null @@ -1,3 +0,0 @@ -extends: cheminfo -parserOptions: - sourceType: module diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml new file mode 100644 index 0000000..71e0af2 --- /dev/null +++ b/.github/workflows/nodejs.yml @@ -0,0 +1,14 @@ +name: Node.js CI + +on: + push: + branches: + - main + pull_request: + +jobs: + nodejs: + # Documentation: https://github.com/zakodium/workflows#nodejs-ci + uses: zakodium/workflows/.github/workflows/nodejs.yml@nodejs-v1 + with: + lint-check-types: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..7f5db58 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,16 @@ +name: Release + +on: + push: + branches: + - main + +jobs: + release: + # Documentation: https://github.com/zakodium/workflows#release + uses: zakodium/workflows/.github/workflows/release.yml@release-v1 + with: + npm: true + secrets: + github-token: ${{ secrets.BOT_TOKEN }} + npm-token: ${{ secrets.NPM_BOT_TOKEN }} diff --git a/.github/workflows/typedoc.yml b/.github/workflows/typedoc.yml new file mode 100644 index 0000000..ff91151 --- /dev/null +++ b/.github/workflows/typedoc.yml @@ -0,0 +1,32 @@ +name: Deploy TypeDoc on GitHub pages + +on: + workflow_dispatch: + release: + types: [published] + +env: + NODE_VERSION: 22.x + ENTRY_FILE: 'src/index.js' + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + - name: Install dependencies + run: npm install + - name: Build documentation + uses: zakodium/typedoc-action@v2 + with: + entry: ${{ env.ENTRY_FILE }} + - name: Deploy to GitHub pages + uses: JamesIves/github-pages-deploy-action@releases/v4 + with: + token: ${{ secrets.BOT_TOKEN }} + branch: gh-pages + folder: docs + clean: true diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..1b763b1 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +CHANGELOG.md diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..04ff376 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,7 @@ +{ + "arrowParens": "always", + "tabWidth": 2, + "singleQuote": true, + "semi": true, + "trailingComma": "all" +} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index fbc683e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: node_js -node_js: - - 12 - - 10 - - 8 -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/History.md b/CHANGELOG.md similarity index 67% rename from History.md rename to CHANGELOG.md index 39655dd..aacfbf8 100644 --- a/History.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +# Changelog + +## [3.0.0](https://github.com/mljs/sparse-matrix/compare/v2.1.0...v3.0.0) (2025-05-25) + + +### ⚠ BREAKING CHANGES + +* migrate to TypeScript and ESM + +### Bug Fixes + +* remove docs and build on gh-pages ([9197b3c](https://github.com/mljs/sparse-matrix/commit/9197b3c1eba1a9c2e2f894bdaa5b066563d047c9)) +* remove travis ([4ff4567](https://github.com/mljs/sparse-matrix/commit/4ff45677d1308976a52bc8f583f4772983a5a0f0)) + + +### Code Refactoring + +* migrate to TypeScript and ESM ([d197546](https://github.com/mljs/sparse-matrix/commit/d19754622b6b96afe3699553bbea8e7e939ce899)) + ## [2.1.0](https://github.com/mljs/sparse-matrix/compare/v2.0.0...v2.1.0) (2021-03-03) @@ -47,6 +66,3 @@ # 0.1.0 (2016-05-18) - - - diff --git a/README.md b/README.md index 733c224..f9aa845 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ -# sparse-matrix +# ml-sparse-matrix [![NPM version][npm-image]][npm-url] -[![build status][travis-image]][travis-url] [![coverage status][codecov-image]][codecov-url] [![npm download][download-image]][download-url] @@ -16,8 +15,14 @@ Sparse matrix library. ```js import { SparseMatrix } from 'ml-sparse-matrix'; -const matrix1 = new SparseMatrix([[1, 2], [3, 4]]); -const matrix2 = new SparseMatrix([[0, 5], [6, 7]]); +const matrix1 = new SparseMatrix([ + [1, 2], + [3, 4], +]); +const matrix2 = new SparseMatrix([ + [0, 5], + [6, 7], +]); const product = matrix1.kroneckerProduct(matrix2); ``` @@ -29,8 +34,6 @@ const product = matrix1.kroneckerProduct(matrix2); [npm-image]: https://img.shields.io/npm/v/ml-sparse-matrix.svg?style=flat-square [npm-url]: https://npmjs.org/package/ml-sparse-matrix -[travis-image]: https://img.shields.io/travis/mljs/sparse-matrix/master.svg?style=flat-square -[travis-url]: https://travis-ci.org/mljs/sparse-matrix [codecov-image]: https://codecov.io/github/mljs/sparse-matrix/coverage.svg?style=flat-square [codecov-url]: https://codecov.io/github/mljs/sparse-matrix [download-image]: https://img.shields.io/npm/dm/ml-sparse-matrix.svg?style=flat-square diff --git a/benchmark/denseMatrix.js b/benchmark/denseMatrix.js new file mode 100644 index 0000000..afab679 --- /dev/null +++ b/benchmark/denseMatrix.js @@ -0,0 +1,18 @@ +import { Matrix } from 'ml-matrix'; + +let size = 200; + +console.time('dense'); +const matrix = new Matrix(size, size).fill(1); +const matrix2 = new Matrix(size, size).fill(1); + +const product = matrix.mmul(matrix2); +// sum of all the elements +let sum = 0; +for (let i = 0; i < size; i++) { + for (let j = 0; j < size; j++) { + sum += product.get(i, j); + } +} +console.log(sum); +console.timeEnd('dense'); diff --git a/benchmark/sparseMatrix.byhand.js b/benchmark/sparseMatrix.byhand.js new file mode 100644 index 0000000..8261900 --- /dev/null +++ b/benchmark/sparseMatrix.byhand.js @@ -0,0 +1,41 @@ +import { SparseMatrix } from '../lib/index.js'; + +let size = 200; + +console.time('dense'); + +const matrix1 = new SparseMatrix(size, size); +fillSparseMatrix(matrix1); + +const matrix2 = new SparseMatrix(size, size); +fillSparseMatrix(matrix2); + +const product = new SparseMatrix(size, size); +for (let i = 0; i < size; i++) { + for (let j = 0; j < size; j++) { + for (let k = 0; k < size; k++) { + product.set( + i, + j, + product.get(i, j) + matrix1.get(i, k) * matrix2.get(k, j), + ); + } + } +} + +let sum = 0; +for (let i = 0; i < size; i++) { + for (let j = 0; j < size; j++) { + sum += product.get(i, j); + } +} +console.timeEnd('dense'); +console.log(sum); + +function fillSparseMatrix(matrix) { + for (let row = 0; row < matrix.rows; row++) { + for (let column = 0; column < matrix.columns; column++) { + matrix.set(row, column, 1); + } + } +} diff --git a/benchmark/sparseMatrix.js b/benchmark/sparseMatrix.js new file mode 100644 index 0000000..53b117e --- /dev/null +++ b/benchmark/sparseMatrix.js @@ -0,0 +1,30 @@ +import { SparseMatrix } from '../lib/index.js'; + +let size = 200; + +console.time('dense'); + +const matrix = new SparseMatrix(size, size); +fillSparseMatrix(matrix); + +const matrix2 = new SparseMatrix(size, size); +fillSparseMatrix(matrix2); + +const product = matrix.mmul(matrix2); +// sum of all the elements +let sum = 0; +for (let i = 0; i < size; i++) { + for (let j = 0; j < size; j++) { + sum += product.get(i, j); + } +} +console.timeEnd('dense'); +console.log(sum); + +function fillSparseMatrix(matrix) { + for (let row = 0; row < matrix.rows; row++) { + for (let column = 0; column < matrix.columns; column++) { + matrix.set(row, column, 1); + } + } +} diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..428560c --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,9 @@ +import { defineConfig, globalIgnores } from 'eslint/config'; +import ts from 'eslint-config-cheminfo-typescript/base'; + +export default defineConfig(globalIgnores(['lib']), ts, { + files: ['benchmark/**'], + rules: { + 'no-console': 'off', + }, +}); diff --git a/package.json b/package.json index 7a1621f..8137a69 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,25 @@ { "name": "ml-sparse-matrix", - "version": "2.1.0", + "version": "3.0.0", "description": "Sparse matrix library", - "main": "lib/index.js", - "module": "src/index.js", + "type": "module", + "exports": "./lib/index.js", "files": [ "lib", "src" ], "scripts": { - "compile": "rollup -c", - "eslint": "eslint src", + "check-types": "tsc --noEmit", + "clean": "rimraf lib", + "eslint": "eslint .", "eslint-fix": "npm run eslint -- --fix", - "prepublishOnly": "npm run compile", - "test": "npm run test-coverage && npm run eslint", - "test-only": "jest", - "test-coverage": "jest --coverage" + "prepack": "npm run tsc", + "prettier": "prettier --check .", + "prettier-write": "prettier --write .", + "test": "npm run test-only && npm run check-types && npm run eslint && npm run prettier", + "test-only": "vitest run --coverage", + "tsc": "npm run clean && npm run tsc-build", + "tsc-build": "tsc --project tsconfig.build.json" }, "repository": { "type": "git", @@ -28,20 +32,18 @@ "url": "https://github.com/mljs/sparse-matrix/issues" }, "homepage": "https://github.com/mljs/sparse-matrix#readme", - "jest": { - "testEnvironment": "node" - }, "dependencies": { "ml-hash-table": "^1.0.0" }, "devDependencies": { - "@babel/plugin-transform-modules-commonjs": "^7.13.8", - "eslint": "^7.21.0", - "eslint-config-cheminfo": "^5.2.3", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jest": "^24.1.5", - "jest": "^26.6.3", - "prettier": "^2.2.1", - "rollup": "^2.40.0" + "@types/node": "^22.15.21", + "@vitest/coverage-v8": "^3.1.4", + "eslint": "^9.27.0", + "eslint-config-cheminfo-typescript": "^18.0.1", + "ml-matrix": "^6.12.1", + "prettier": "^3.5.3", + "rimraf": "^6.0.1", + "typescript": "^5.8.3", + "vitest": "^3.1.4" } } diff --git a/rollup.config.js b/rollup.config.js deleted file mode 100644 index 8538f62..0000000 --- a/rollup.config.js +++ /dev/null @@ -1,9 +0,0 @@ -export default { - input: 'src/index.js', - output: { - format: 'cjs', - file: 'lib/index.js' - }, - external: ['ml-hash-table'] - }; - \ No newline at end of file diff --git a/src/__tests__/test.js b/src/__tests__/index.test.js similarity index 96% rename from src/__tests__/test.js rename to src/__tests__/index.test.js index 3e29942..0843eba 100644 --- a/src/__tests__/test.js +++ b/src/__tests__/index.test.js @@ -1,4 +1,6 @@ -import { SparseMatrix } from '..'; +import { describe, expect, it } from 'vitest'; + +import { SparseMatrix } from '../index.js'; describe('Sparse Matrix', () => { it('mmul', () => { diff --git a/src/index.js b/src/index.js index 2ee5ee6..e143758 100644 --- a/src/index.js +++ b/src/index.js @@ -86,7 +86,7 @@ export class SparseMatrix { /** * Search for the wither band in the main diagonals - * @return {number} + * @returns {number} */ bandWidth() { let min = this.columns; @@ -103,7 +103,7 @@ export class SparseMatrix { /** * Test if a matrix is consider banded using a threshold * @param {number} width - * @return {boolean} + * @returns {boolean} */ isBanded(width) { let bandWidth = this.bandWidth(); @@ -220,7 +220,7 @@ export class SparseMatrix { } /** - * @return {SparseMatrix} - New transposed sparse matrix + * @returns {SparseMatrix} - New transposed sparse matrix */ transpose() { let trans = new SparseMatrix(this.columns, this.rows, { @@ -337,7 +337,7 @@ for (const operator of operators) { let methods = [['~', 'not']]; -[ +for (const mathMethod of [ 'abs', 'acos', 'acosh', @@ -366,9 +366,9 @@ let methods = [['~', 'not']]; 'tan', 'tanh', 'trunc', -].forEach(function (mathMethod) { +]) { methods.push([`Math.${mathMethod}`, mathMethod]); -}); +} for (const method of methods) { for (let i = 1; i < method.length; i++) { @@ -386,7 +386,7 @@ for (const method of methods) { function fillTemplateFunction(template, values) { for (const i in values) { - template = template.replace(new RegExp(`%${i}%`, 'g'), values[i]); + template = template.replaceAll(new RegExp(`%${i}%`, 'g'), values[i]); } return template; } diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..5daa1ea --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["**/__tests__", "**/*.test.ts"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..be52d18 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "lib": ["ES2022", "WebWorker"], + "types": [], + "target": "ES2022", + "outDir": "lib", + "module": "NodeNext", + "strict": true, + "skipLibCheck": false, + "resolveJsonModule": false, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "checkJs": true, + "noImplicitAny": false, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "sourceMap": true, + "declaration": true, + "declarationMap": true + }, + "include": ["src"] +}