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

implement Whitaker smoother and all the utilities to be used outside #292

Merged
merged 18 commits into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
2269e18
feat: add sparse cholesky solver and cuthill-mckee
jobo322 Feb 18, 2025
895cf1a
feat: add utilities to build a weighted least squared fit/smooth of 1…
jobo322 Feb 18, 2025
ca47c9f
feat: add xWhitakerSmoother
jobo322 Feb 18, 2025
ebff243
chore: rename updateSystemMatrix
jobo322 Feb 18, 2025
cc16419
chore: improve documentation of createSystemMatrix
jobo322 Feb 18, 2025
f52f546
feat: update addWeights function to modify left and right hand sides …
jobo322 Feb 19, 2025
a9e2521
chore: remove addWeights from exports in utils and snapshots
jobo322 Feb 19, 2025
05437cf
refactor: modify createSystemMatrix to return upper triangular non-ze…
jobo322 Feb 19, 2025
06129e2
test: add unit test for xWhitakerSmoother with sine baseline and outl…
jobo322 Feb 19, 2025
f46f465
test: add unit test for matrixCholeskySolver with weighted least squa…
jobo322 Feb 19, 2025
144e447
chore(matrixCholeskySolver): returns the mapping
jobo322 Feb 19, 2025
b3fb82c
test: add unit test for matrixCuthillMckee to verify bandwidth reduction
jobo322 Feb 19, 2025
cc899e4
test: enhance matrixCholeskySolver tests with permutation encoding fr…
jobo322 Feb 19, 2025
3cae445
feat: enhance UpdateWeightsOptions interface with weights and control…
jobo322 Feb 20, 2025
667e94c
chore: improve function name and make pure function
jobo322 Feb 20, 2025
083ffb9
docs: update calculateAdaptiveWeights function documentation to clari…
jobo322 Feb 21, 2025
cbca184
Update src/utils/calculateAdaptiveWeights.ts
jobo322 Feb 21, 2025
4ccf921
refactor: rename UpdateWeightsOptions to CalculateAdaptiveWeightsOpti…
jobo322 Feb 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/__tests__/__snapshots__/index.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ exports[`test existence of exported functions 1`] = `
"xSum",
"xUniqueSorted",
"xVariance",
"xWhitakerSmoother",
"xyAlign",
"xyCheck",
"xyCovariance",
Expand Down Expand Up @@ -140,9 +141,11 @@ exports[`test existence of exported functions 1`] = `
"matrixBoxPlot",
"matrixCenterZMean",
"matrixCheck",
"matrixCholeskySolver",
"matrixClone",
"matrixColumnsCorrelation",
"matrixCreateEmpty",
"matrixCuthillMckee",
"matrixHistogram",
"matrixMaxAbsoluteZ",
"matrixMedian",
Expand All @@ -167,5 +170,6 @@ exports[`test existence of exported functions 1`] = `
"nextPowerOfTwo",
"recursiveResolve",
"stringify",
"calculateAdaptiveWeights",
]
`;
51 changes: 51 additions & 0 deletions src/matrix/__tests__/matrixCholeskySolver.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { NumberArray } from 'cheminfo-types';
import { expect, test } from 'vitest';

import { addWeights } from '../../utils/addWeights';
import { createSystemMatrix } from '../../utils/createSystemMatrix';
import { xSequentialFillFromTo } from '../../x';
import { matrixCholeskySolver } from '../matrixCholeskySolver';
import { matrixCuthillMckee } from '../matrixCuthillMckee';

type Func = (b: NumberArray) => NumberArray;
test('solve a least square system', () => {
const x = xSequentialFillFromTo({ from: 0, to: Math.PI, size: 101 });
const noise = x.map(() => Math.random() * 0.1 - 0.05);
const y = x.map((value, index) => Math.cos(value) + noise[index]);
const weights = new Float64Array(y.length).fill(1);
y[50] = 0.9; // add outliers

const lambda = 20;
const dimension = x.length;
const upperTriangularNonZeros = createSystemMatrix(dimension, lambda);

const weighted = addWeights(upperTriangularNonZeros, y, weights);

const cho = matrixCholeskySolver(weighted.leftHandSide, dimension) as Func;
expect(cho).not.toBeNull();
const smoothed = cho(weighted.rightHandSide);
expect(smoothed[50]).toBeLessThan(0.2);
expect(smoothed[50]).toBeGreaterThan(-0.2);

//ignore the outlier, it implicates the smooth should pass closer to zero.
weights[50] = 0;
const weighted2 = addWeights(upperTriangularNonZeros, y, weights);
const cho2 = matrixCholeskySolver(weighted.leftHandSide, dimension) as Func;
expect(cho2).not.toBeNull();
const smoothed2 = cho2(weighted2.rightHandSide);
expect(smoothed2[50]).toBeLessThan(smoothed[50]);

const permutationEncodedArray = matrixCuthillMckee(
upperTriangularNonZeros,
dimension,
);
const cho3 = matrixCholeskySolver(
weighted2.leftHandSide,
dimension,
permutationEncodedArray,
) as Func;

expect(cho3).not.toBeNull();
const smoothed3 = cho2(weighted2.rightHandSide);
expect(smoothed3[50]).toEqual(smoothed3[50]);
});
67 changes: 67 additions & 0 deletions src/matrix/__tests__/matrixCuthillMckee.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import type { NumberArray } from 'cheminfo-types';
import { expect, test } from 'vitest';

import { matrixCuthillMckee } from '../matrixCuthillMckee';

test('permutation to reduce bandwidth', () => {
const dimension = 10;
const matrix = [
[2, 2, 1.5],
[1, 1, 1],
[1, 4, 0.02],
[5, 5, 1.2],
[7, 7, 1.6],
[4, 4, 2.6],
[3, 3, 1.1],
[4, 7, 0.09],
[4, 6, 0.16],
[0, 0, 1.7],
[4, 8, 0.52],
[0, 8, 0.13],
[6, 6, 1.3],
[7, 8, 0.11],
[4, 9, 0.53],
[8, 8, 1.4],
[9, 9, 3.1],
[1, 9, 0.01],
[6, 9, 0.56],
];

const permutationEncodedArray = matrixCuthillMckee(matrix, dimension);

const reducedBandwidthMatrix = permut(
matrix,
permutationEncodedArray,
dimension,
);
expect(bandwidth(reducedBandwidthMatrix)).toBeLessThan(bandwidth(matrix));
});

function permut(
nonZerosArray: NumberArray[],
permutationEncoded: NumberArray,
dimension: number,
) {
const pinv = new Array(dimension);
for (let k = 0; k < dimension; k++) {
pinv[permutationEncoded[k]] = k;
}
const mt: NumberArray[] = new Array(nonZerosArray.length);
for (let a = 0; a < nonZerosArray.length; ++a) {
const [r, c, value] = nonZerosArray[a];
const [ar, ac] = [pinv[r], pinv[c]];
mt[a] = ac < ar ? [ac, ar, value] : [ar, ac, value];
}
return mt;
}

function bandwidth(matrix: NumberArray[]) {
let bandwidth = 0;
for (const [i, j] of matrix) {
const distance = Math.abs(i - j);
if (distance > bandwidth) {
bandwidth = distance;
}
}
return bandwidth;
}
2 changes: 2 additions & 0 deletions src/matrix/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ export * from './matrixAutoCorrelation';
export * from './matrixBoxPlot';
export * from './matrixCenterZMean';
export * from './matrixCheck';
export * from './matrixCholeskySolver';
export * from './matrixClone';
export * from './matrixColumnsCorrelation';
export * from './matrixCreateEmpty';
export * from './matrixCuthillMckee';
export * from './matrixHistogram';
export * from './matrixMaxAbsoluteZ';
export * from './matrixMedian';
Expand Down
Loading
Loading