Skip to content

Commit

Permalink
feat: migrate to typescript (#19)
Browse files Browse the repository at this point in the history
* refactor: setup project for typescript

* chore: update test cases

* chore: remove old .d.ts

* feat: adapt functions

* chore: fix prettier

* chore: set skipLibCheck as true

* chore: export types from each file

* chore: set default branch

Co-authored-by: Michaël Zasso <targos@protonmail.com>

* chore: empty line at the end of the file

Co-authored-by: Michaël Zasso <targos@protonmail.com>

* chore: empty line at the end of .gitignore

Co-authored-by: Michaël Zasso <targos@protonmail.com>

* chore: remove types from jsdoc

* chore: fix input types in compressTree

* chore: add missing test case

* chore: only tree accepted in compressTree

---------

Co-authored-by: Michaël Zasso <targos@protonmail.com>
  • Loading branch information
jobo322 and targos authored Feb 15, 2024
1 parent 226db00 commit 6634fd0
Show file tree
Hide file tree
Showing 21 changed files with 184 additions and 150 deletions.
3 changes: 0 additions & 3 deletions .babelrc.json

This file was deleted.

2 changes: 1 addition & 1 deletion .eslintrc.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
extends: cheminfo
extends: cheminfo-typescript
parserOptions:
sourceType: module
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ jobs:
nodejs:
# Documentation: https://github.com/zakodium/workflows#nodejs-ci
uses: zakodium/workflows/.github/workflows/nodejs.yml@nodejs-v1
with:
lint-check-types: true
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ jspm_packages
# Optional REPL history
.node_repl_history

lib
lib
lib-esm
4 changes: 4 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
"presets": ["@babel/preset-typescript"],
"plugins": ["@babel/plugin-transform-modules-commonjs"]
}
26 changes: 16 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,27 @@
"name": "ml-tree-similarity",
"version": "2.1.0",
"description": "Compares two spectra using a tree similarity",
"main": "lib/index.js",
"module": "src/index.js",
"types": "tree-similarity.d.ts",
"main": "./lib/index.js",
"module": "./lib-esm/index.js",
"types": "./lib/index.d.ts",
"files": [
"lib",
"src",
"tree-similarity.d.ts"
"lib-esm"
],
"scripts": {
"compile": "rollup -c",
"check-types": "tsc --noEmit",
"clean": "rimraf lib lib-esm",
"eslint": "eslint src",
"eslint-fix": "npm run eslint -- --fix",
"prepack": "npm run compile",
"prepack": "npm run tsc",
"prettier": "prettier --check src",
"prettier-write": "prettier --write src",
"test": "npm run test-only && npm run eslint && npm run prettier",
"test-only": "vitest run --coverage"
"test": "npm run test-only && npm run eslint && npm run prettier && npm run check-types",
"test-only": "vitest run --coverage",
"tsc": "npm run clean && npm run tsc-cjs && npm run tsc-esm",
"tsc-cjs": "tsc --project tsconfig.cjs.json",
"tsc-esm": "tsc --project tsconfig.esm.json"
},
"repository": {
"type": "git",
Expand All @@ -33,11 +37,13 @@
"homepage": "https://github.com/mljs/tree-similarity#readme",
"devDependencies": {
"@babel/plugin-transform-modules-commonjs": "^7.23.3",
"@babel/preset-typescript": "^7.23.3",
"@vitest/coverage-v8": "^1.2.2",
"eslint": "^8.56.0",
"eslint-config-cheminfo": "^9.1.1",
"eslint-config-cheminfo-typescript": "^12.2.0",
"prettier": "^3.2.5",
"rollup": "^4.9.6",
"rimraf": "^5.0.5",
"typescript": "^5.3.3",
"vitest": "^1.2.2"
},
"dependencies": {
Expand Down
8 changes: 0 additions & 8 deletions rollup.config.mjs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { test, expect } from 'vitest';

import { compressTree } from '../compressTree';
import { createTree } from '../createTree';
import { Tree, createTree } from '../createTree';

test('compressTree', () => {
let x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let y = [0, 1, 2, 3, 0, 0, 0, 1, 0, 0, 0];
let tree = createTree({ x, y });
const x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const y = [0, 1, 2, 3, 0, 0, 0, 1, 0, 0, 0];
const tree = createTree({ x, y }) as Tree;

expect(compressTree(tree, { fixed: 3 })).toStrictEqual({
sum: 7,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,51 +1,55 @@
import { describe, it, expect } from 'vitest';

import { createTree } from '../createTree';
import { Tree, createTree } from '../createTree';

describe('simple trees', () => {
it('two peaks, same height', () => {
let x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let y = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0];
let tree = createTree({ x, y });
const x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const y = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0];
const tree = createTree({ x, y }) as Tree;

expect(tree.center).toBe(5);
expect(tree.sum).toBe(2);

let left = tree.left;
const left = tree.left as Tree;
expect(left).not.toBe(null);
expect(left.center).toBe(3);
expect(left.sum).toBe(1);
expect(left.left).toStrictEqual(null);
expect(left.right).toStrictEqual(null);

let right = tree.right;
const right = tree.right as Tree;
expect(right).not.toBe(null);
expect(right.center).toBe(7);
expect(right.sum).toBe(1);
expect(right.left).toStrictEqual(null);
expect(right.right).toStrictEqual(null);
});

it('two peaks, same height (higher)', () => {
let x = new Array(101);
let y = new Array(101);
const x = new Array(101);
const y = new Array(101);
for (let i = 0; i < 101; i++) {
x[i] = i;
y[i] = 0;
}
y[20] = 20;
y[80] = 20;

let tree = createTree({ x, y });
const tree = createTree({ x, y }) as Tree;

expect(tree.center).toBe(50);
expect(tree.sum).toBe(40);

let left = tree.left;
const left = tree.left as Tree;
expect(left).not.toBe(null);
expect(left.center).toBe(20);
expect(left.sum).toBe(20);
expect(left.left).toStrictEqual(null);
expect(left.right).toStrictEqual(null);

let right = tree.right;
const right = tree.right as Tree;
expect(right).not.toBe(null);
expect(right.center).toBe(80);
expect(right.sum).toBe(20);
expect(right.left).toStrictEqual(null);
Expand Down
7 changes: 6 additions & 1 deletion src/__tests__/tree.test.js → src/__tests__/tree.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest';

import { createTree, treeSimilarity } from '../index';
import { Tree, createTree, treeSimilarity } from '../index';

const a = {
x: [1, 2, 3, 4, 5, 6, 7],
Expand All @@ -18,4 +18,9 @@ describe('Tree similarity', () => {
4,
);
});
it('should throw with wrong input', () => {
expect(() => treeSimilarity(createTree(a), {} as Tree)).toThrow(
'tree similarity expects tree as inputs',
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { treeSimilarity } from '../treeSimilarity';

describe('simple trees', () => {
it('same tree', () => {
let x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let y = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0];
let tree1 = createTree({ x, y });
let tree2 = createTree({ x, y });
const x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const y = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0];
const tree1 = createTree({ x, y });
const tree2 = createTree({ x, y });

expect(treeSimilarity(tree1, tree2, { beta: 1 })).toBe(1);
});
Expand Down
15 changes: 9 additions & 6 deletions src/compressTree.js → src/compressTree.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { Tree } from './createTree';

/**
* Destructive compression in which we reduce the number of decimals
* @param {object} tree
* @param {object} [options={}]
* @param {number} [options.fixed=undefined] - number of decimal ot keep
* @returns
*/

export function compressTree(tree, options = {}) {
export function compressTree(
tree: Tree,
options: {
// number of decimal ot keep
fixed?: number;
} = {},
): Tree {
const { fixed } = options;
return JSON.parse(
JSON.stringify(tree, (key, value) => {
Expand Down
52 changes: 41 additions & 11 deletions src/createTree.js → src/createTree.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,49 @@
import binarySearch from 'binary-search';
import { DataXY } from 'cheminfo-types';

/**
* @typedef {import("../tree-similarity").Tree} Tree
* @typedef {import("../tree-similarity").CreateTreeOptions} CreateTreeOptions
* @typedef {import("../tree-similarity").Spectrum} Spectrum
*/
export interface Tree {
sum: number;
center: number;
/**
* left and right have the same structure than the parent,
* or are null if they are leaves
*/
left: Tree | null;
right: Tree | null;
}

export interface CreateTreeOptions {
/**
* low limit of the tree
* @default x[0]
*/
from?: number;
/**
* high limit of the tree
* @default x.at(-1)
*/
to?: number;
/**
* minimal sum value to accept a node
* @default 0.01
*/
threshold?: number;
/**
* minimal window width to create a node
* @default 0.16
*/
minWindow?: number;
}

/**
* Function that creates the tree
* @param {Spectrum} spectrum
* @param {CreateTreeOptions} [options]
* @return { Tree | null }
*/
export function createTree(spectrum, options = {}) {
const { x, y } = spectrum;

export function createTree(
dataXY: DataXY,
options: CreateTreeOptions = {},
): Tree | null {
const { x, y } = dataXY;
const {
minWindow = 0.16,
threshold = 0.01,
Expand All @@ -30,7 +60,7 @@ function mainCreateTree(x, y, from, to, minWindow, threshold) {
}

// search first point
let start = binarySearch(x, from, (a, b) => a - b);
let start = binarySearch(x, from, (a: number, b: number) => a - b);
if (start < 0) {
start = ~start;
}
Expand Down
3 changes: 0 additions & 3 deletions src/index.js

This file was deleted.

3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './treeSimilarity';
export * from './createTree';
export { compressTree } from './compressTree';
42 changes: 0 additions & 42 deletions src/treeSimilarity.js

This file was deleted.

47 changes: 47 additions & 0 deletions src/treeSimilarity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Tree } from './createTree';

export interface TreeSimilarityOptions {
alpha?: number;
beta?: number;
gamma?: number;
}

/**
* Similarity between two nodes
* @return similarity measure between tree nodes
*/
export function treeSimilarity(
treeA: Tree | null,
treeB: Tree | null,
options: TreeSimilarityOptions = {},
): number {
const { alpha = 0.1, beta = 0.33, gamma = 0.001 } = options;

if (treeA === null || treeB === null) {
return 0;
}

if (!isTree(treeA) || !isTree(treeB)) {
throw new Error('tree similarity expects tree as inputs');
}

if (treeA.sum === 0 && treeB.sum === 0) {
return 1;
}

const C =
(alpha * Math.min(treeA.sum, treeB.sum)) / Math.max(treeA.sum, treeB.sum) +
(1 - alpha) * Math.exp(-gamma * Math.abs(treeA.center - treeB.center));

return (
beta * C +
((1 - beta) *
(treeSimilarity(treeA.left, treeB.left, options) +
treeSimilarity(treeA.right, treeB.right, options))) /
2
);
}

function isTree(tree: object): tree is Tree {
return ['sum', 'center', 'left', 'right'].every((key) => key in tree);
}
Loading

0 comments on commit 6634fd0

Please sign in to comment.