pragmastat 3.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +134 -0
- package/dist/estimators.d.ts +52 -0
- package/dist/estimators.d.ts.map +1 -0
- package/dist/estimators.js +128 -0
- package/dist/estimators.js.map +1 -0
- package/dist/fastCenter.d.ts +18 -0
- package/dist/fastCenter.d.ts.map +1 -0
- package/dist/fastCenter.js +183 -0
- package/dist/fastCenter.js.map +1 -0
- package/dist/fastSpread.d.ts +18 -0
- package/dist/fastSpread.d.ts.map +1 -0
- package/dist/fastSpread.js +201 -0
- package/dist/fastSpread.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/utils.d.ts +17 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +42 -0
- package/dist/utils.js.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Andrey Akinshin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Pragmastat TypeScript Implementation
|
|
2
|
+
|
|
3
|
+
[](https://doi.org/10.5281/zenodo.17236778)
|
|
4
|
+
|
|
5
|
+
This is the TypeScript implementation of Pragmastat, a pragmatic statistical toolkit designed for analyzing real-world data.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install pragmastat
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import {
|
|
17
|
+
center,
|
|
18
|
+
spread,
|
|
19
|
+
relSpread,
|
|
20
|
+
shift,
|
|
21
|
+
ratio,
|
|
22
|
+
avgSpread,
|
|
23
|
+
disparity
|
|
24
|
+
} from 'pragmastat';
|
|
25
|
+
|
|
26
|
+
// One-sample estimators
|
|
27
|
+
const data = [1, 2, 3, 4, 5];
|
|
28
|
+
console.log('Center:', center(data));
|
|
29
|
+
console.log('Spread:', spread(data));
|
|
30
|
+
console.log('RelSpread:', relSpread(data));
|
|
31
|
+
|
|
32
|
+
// Two-sample estimators
|
|
33
|
+
const x = [1, 2, 3];
|
|
34
|
+
const y = [4, 5, 6];
|
|
35
|
+
console.log('Shift:', shift(x, y));
|
|
36
|
+
console.log('Ratio:', ratio(x, y));
|
|
37
|
+
console.log('AvgSpread:', avgSpread(x, y));
|
|
38
|
+
console.log('Disparity:', disparity(x, y));
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Estimators
|
|
42
|
+
|
|
43
|
+
### One-Sample Estimators
|
|
44
|
+
|
|
45
|
+
- **center**: Hodges-Lehmann location estimator - robust measure of average
|
|
46
|
+
- **spread**: Shamos scale estimator - robust measure of dispersion
|
|
47
|
+
- **relSpread**: Relative dispersion measure - spread normalized by center
|
|
48
|
+
|
|
49
|
+
### Two-Sample Estimators
|
|
50
|
+
|
|
51
|
+
- **shift**: Hodges-Lehmann shift estimator - robust measure of location difference
|
|
52
|
+
- **ratio**: Robust ratio estimator - median of all pairwise ratios
|
|
53
|
+
- **avgSpread**: Pooled spread estimator - combined measure of dispersion
|
|
54
|
+
- **disparity**: Effect size measure - normalized difference between samples
|
|
55
|
+
|
|
56
|
+
## Development
|
|
57
|
+
|
|
58
|
+
### Building
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Build TypeScript to JavaScript
|
|
62
|
+
npm run build
|
|
63
|
+
|
|
64
|
+
# Or use the build script
|
|
65
|
+
./build.sh build
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Testing
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Run all tests
|
|
72
|
+
npm test
|
|
73
|
+
|
|
74
|
+
# Run tests with coverage
|
|
75
|
+
npm run test:coverage
|
|
76
|
+
|
|
77
|
+
# Run tests in watch mode
|
|
78
|
+
npm run test:watch
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Code Quality
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Run ESLint
|
|
85
|
+
npm run lint
|
|
86
|
+
|
|
87
|
+
# Format code with Prettier
|
|
88
|
+
npm run format
|
|
89
|
+
|
|
90
|
+
# Check formatting
|
|
91
|
+
npm run format:check
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Build Script
|
|
95
|
+
|
|
96
|
+
The `build.sh` script provides convenient commands:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
./build.sh test # Run all tests
|
|
100
|
+
./build.sh build # Build TypeScript to JavaScript
|
|
101
|
+
./build.sh check # Run linting and format checking
|
|
102
|
+
./build.sh clean # Clean build artifacts
|
|
103
|
+
./build.sh format # Format code with Prettier
|
|
104
|
+
./build.sh install # Install npm dependencies
|
|
105
|
+
./build.sh coverage # Run tests with coverage report
|
|
106
|
+
./build.sh watch # Run tests in watch mode
|
|
107
|
+
./build.sh all # Run all tasks
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Project Structure
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
ts/
|
|
114
|
+
├── src/ # Source code
|
|
115
|
+
│ ├── index.ts # Main entry point
|
|
116
|
+
│ ├── estimators.ts # Estimator implementations
|
|
117
|
+
│ └── utils.ts # Utility functions
|
|
118
|
+
├── tests/ # Test files
|
|
119
|
+
│ ├── estimators.test.ts # Unit tests
|
|
120
|
+
│ ├── invariance.test.ts # Mathematical invariance tests
|
|
121
|
+
│ └── reference.test.ts # Reference tests against JSON data
|
|
122
|
+
├── dist/ # Compiled JavaScript (generated)
|
|
123
|
+
├── package.json # NPM package configuration
|
|
124
|
+
├── tsconfig.json # TypeScript configuration
|
|
125
|
+
├── jest.config.js # Jest test configuration
|
|
126
|
+
├── .eslintrc.js # ESLint configuration
|
|
127
|
+
├── .prettierrc # Prettier configuration
|
|
128
|
+
├── build.sh # Build script
|
|
129
|
+
└── README.md # This file
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pragmastat estimators implementation
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Calculate the Center - median of all pairwise averages (x[i] + x[j])/2
|
|
6
|
+
* Uses fast O(n log n) algorithm.
|
|
7
|
+
* @param x Array of sample values
|
|
8
|
+
* @returns The center estimate
|
|
9
|
+
*/
|
|
10
|
+
export declare function center(x: number[]): number;
|
|
11
|
+
/**
|
|
12
|
+
* Calculate the Spread - median of all pairwise absolute differences |x[i] - x[j]|
|
|
13
|
+
* Uses fast O(n log n) algorithm.
|
|
14
|
+
* @param x Array of sample values
|
|
15
|
+
* @returns The spread estimate
|
|
16
|
+
*/
|
|
17
|
+
export declare function spread(x: number[]): number;
|
|
18
|
+
/**
|
|
19
|
+
* Calculate the RelSpread - ratio of Spread to absolute Center
|
|
20
|
+
* @param x Array of sample values
|
|
21
|
+
* @returns The relative spread estimate
|
|
22
|
+
*/
|
|
23
|
+
export declare function relSpread(x: number[]): number;
|
|
24
|
+
/**
|
|
25
|
+
* Calculate the Shift - median of all pairwise differences (x[i] - y[j])
|
|
26
|
+
* @param x First sample
|
|
27
|
+
* @param y Second sample
|
|
28
|
+
* @returns The shift estimate
|
|
29
|
+
*/
|
|
30
|
+
export declare function shift(x: number[], y: number[]): number;
|
|
31
|
+
/**
|
|
32
|
+
* Calculate the Ratio - median of all pairwise ratios (x[i] / y[j])
|
|
33
|
+
* @param x First sample
|
|
34
|
+
* @param y Second sample
|
|
35
|
+
* @returns The ratio estimate
|
|
36
|
+
*/
|
|
37
|
+
export declare function ratio(x: number[], y: number[]): number;
|
|
38
|
+
/**
|
|
39
|
+
* Calculate the AvgSpread - weighted average of spreads: (n*Spread(x) + m*Spread(y))/(n+m)
|
|
40
|
+
* @param x First sample
|
|
41
|
+
* @param y Second sample
|
|
42
|
+
* @returns The combined spread estimate
|
|
43
|
+
*/
|
|
44
|
+
export declare function avgSpread(x: number[], y: number[]): number;
|
|
45
|
+
/**
|
|
46
|
+
* Calculate the Disparity - Shift / AvgSpread
|
|
47
|
+
* @param x First sample
|
|
48
|
+
* @param y Second sample
|
|
49
|
+
* @returns The disparity estimate
|
|
50
|
+
*/
|
|
51
|
+
export declare function disparity(x: number[], y: number[]): number;
|
|
52
|
+
//# sourceMappingURL=estimators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"estimators.d.ts","sourceRoot":"","sources":["../src/estimators.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAE1C;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAE1C;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAa7C;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAgBtD;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAqBtD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAa1D;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAa1D"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Pragmastat estimators implementation
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.center = center;
|
|
7
|
+
exports.spread = spread;
|
|
8
|
+
exports.relSpread = relSpread;
|
|
9
|
+
exports.shift = shift;
|
|
10
|
+
exports.ratio = ratio;
|
|
11
|
+
exports.avgSpread = avgSpread;
|
|
12
|
+
exports.disparity = disparity;
|
|
13
|
+
const utils_1 = require("./utils");
|
|
14
|
+
const fastCenter_1 = require("./fastCenter");
|
|
15
|
+
const fastSpread_1 = require("./fastSpread");
|
|
16
|
+
/**
|
|
17
|
+
* Calculate the Center - median of all pairwise averages (x[i] + x[j])/2
|
|
18
|
+
* Uses fast O(n log n) algorithm.
|
|
19
|
+
* @param x Array of sample values
|
|
20
|
+
* @returns The center estimate
|
|
21
|
+
*/
|
|
22
|
+
function center(x) {
|
|
23
|
+
return (0, fastCenter_1.fastCenter)(x);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Calculate the Spread - median of all pairwise absolute differences |x[i] - x[j]|
|
|
27
|
+
* Uses fast O(n log n) algorithm.
|
|
28
|
+
* @param x Array of sample values
|
|
29
|
+
* @returns The spread estimate
|
|
30
|
+
*/
|
|
31
|
+
function spread(x) {
|
|
32
|
+
return (0, fastSpread_1.fastSpread)(x);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Calculate the RelSpread - ratio of Spread to absolute Center
|
|
36
|
+
* @param x Array of sample values
|
|
37
|
+
* @returns The relative spread estimate
|
|
38
|
+
*/
|
|
39
|
+
function relSpread(x) {
|
|
40
|
+
if (x.length === 0) {
|
|
41
|
+
throw new Error('Input array cannot be empty');
|
|
42
|
+
}
|
|
43
|
+
const s = spread(x);
|
|
44
|
+
const c = center(x);
|
|
45
|
+
if (c === 0) {
|
|
46
|
+
throw new Error('RelSpread is undefined when Center equals zero');
|
|
47
|
+
}
|
|
48
|
+
return s / Math.abs(c);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Calculate the Shift - median of all pairwise differences (x[i] - y[j])
|
|
52
|
+
* @param x First sample
|
|
53
|
+
* @param y Second sample
|
|
54
|
+
* @returns The shift estimate
|
|
55
|
+
*/
|
|
56
|
+
function shift(x, y) {
|
|
57
|
+
const nx = x.length;
|
|
58
|
+
const ny = y.length;
|
|
59
|
+
if (nx === 0 || ny === 0) {
|
|
60
|
+
throw new Error('Input arrays cannot be empty');
|
|
61
|
+
}
|
|
62
|
+
const pairwiseDifferences = [];
|
|
63
|
+
for (let i = 0; i < nx; i++) {
|
|
64
|
+
for (let j = 0; j < ny; j++) {
|
|
65
|
+
pairwiseDifferences.push(x[i] - y[j]);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return (0, utils_1.median)(pairwiseDifferences);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Calculate the Ratio - median of all pairwise ratios (x[i] / y[j])
|
|
72
|
+
* @param x First sample
|
|
73
|
+
* @param y Second sample
|
|
74
|
+
* @returns The ratio estimate
|
|
75
|
+
*/
|
|
76
|
+
function ratio(x, y) {
|
|
77
|
+
const nx = x.length;
|
|
78
|
+
const ny = y.length;
|
|
79
|
+
if (nx === 0 || ny === 0) {
|
|
80
|
+
throw new Error('Input arrays cannot be empty');
|
|
81
|
+
}
|
|
82
|
+
// Check that all y values are strictly positive
|
|
83
|
+
if (y.some((val) => val <= 0)) {
|
|
84
|
+
throw new Error('All values in y must be strictly positive');
|
|
85
|
+
}
|
|
86
|
+
const pairwiseRatios = [];
|
|
87
|
+
for (let i = 0; i < nx; i++) {
|
|
88
|
+
for (let j = 0; j < ny; j++) {
|
|
89
|
+
pairwiseRatios.push(x[i] / y[j]);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return (0, utils_1.median)(pairwiseRatios);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Calculate the AvgSpread - weighted average of spreads: (n*Spread(x) + m*Spread(y))/(n+m)
|
|
96
|
+
* @param x First sample
|
|
97
|
+
* @param y Second sample
|
|
98
|
+
* @returns The combined spread estimate
|
|
99
|
+
*/
|
|
100
|
+
function avgSpread(x, y) {
|
|
101
|
+
const nx = x.length;
|
|
102
|
+
const ny = y.length;
|
|
103
|
+
if (nx === 0 || ny === 0) {
|
|
104
|
+
throw new Error('Input arrays cannot be empty');
|
|
105
|
+
}
|
|
106
|
+
// Calculate weighted average of individual spreads
|
|
107
|
+
const spreadX = spread(x);
|
|
108
|
+
const spreadY = spread(y);
|
|
109
|
+
return (nx * spreadX + ny * spreadY) / (nx + ny);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Calculate the Disparity - Shift / AvgSpread
|
|
113
|
+
* @param x First sample
|
|
114
|
+
* @param y Second sample
|
|
115
|
+
* @returns The disparity estimate
|
|
116
|
+
*/
|
|
117
|
+
function disparity(x, y) {
|
|
118
|
+
if (x.length === 0 || y.length === 0) {
|
|
119
|
+
throw new Error('Input arrays cannot be empty');
|
|
120
|
+
}
|
|
121
|
+
const shiftVal = shift(x, y);
|
|
122
|
+
const combinedSpread = avgSpread(x, y);
|
|
123
|
+
if (combinedSpread === 0) {
|
|
124
|
+
return Infinity;
|
|
125
|
+
}
|
|
126
|
+
return shiftVal / combinedSpread;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=estimators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"estimators.js","sourceRoot":"","sources":["../src/estimators.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fast O(n log n) implementation of the Center (Hodges-Lehmann) estimator.
|
|
3
|
+
* Based on Monahan's Algorithm 616 (1984).
|
|
4
|
+
*
|
|
5
|
+
* Internal implementation - not part of public API.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Compute the median of all pairwise averages (xi + xj)/2 efficiently.
|
|
9
|
+
*
|
|
10
|
+
* Time complexity: O(n log n) expected
|
|
11
|
+
* Space complexity: O(n)
|
|
12
|
+
*
|
|
13
|
+
* @param values Array of numeric values
|
|
14
|
+
* @returns The center estimate (Hodges-Lehmann estimator)
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
export declare function fastCenter(values: number[]): number;
|
|
18
|
+
//# sourceMappingURL=fastCenter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastCenter.d.ts","sourceRoot":"","sources":["../src/fastCenter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAmMnD"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Fast O(n log n) implementation of the Center (Hodges-Lehmann) estimator.
|
|
4
|
+
* Based on Monahan's Algorithm 616 (1984).
|
|
5
|
+
*
|
|
6
|
+
* Internal implementation - not part of public API.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.fastCenter = fastCenter;
|
|
10
|
+
/**
|
|
11
|
+
* Compute the median of all pairwise averages (xi + xj)/2 efficiently.
|
|
12
|
+
*
|
|
13
|
+
* Time complexity: O(n log n) expected
|
|
14
|
+
* Space complexity: O(n)
|
|
15
|
+
*
|
|
16
|
+
* @param values Array of numeric values
|
|
17
|
+
* @returns The center estimate (Hodges-Lehmann estimator)
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
function fastCenter(values) {
|
|
21
|
+
const n = values.length;
|
|
22
|
+
if (n === 0) {
|
|
23
|
+
throw new Error('Input array cannot be empty');
|
|
24
|
+
}
|
|
25
|
+
if (n === 1) {
|
|
26
|
+
return values[0];
|
|
27
|
+
}
|
|
28
|
+
if (n === 2) {
|
|
29
|
+
return (values[0] + values[1]) / 2;
|
|
30
|
+
}
|
|
31
|
+
// Sort the values
|
|
32
|
+
const sortedValues = [...values].sort((a, b) => a - b);
|
|
33
|
+
// Calculate target median rank(s) among all pairwise sums
|
|
34
|
+
const totalPairs = Math.floor((n * (n + 1)) / 2);
|
|
35
|
+
const medianRankLow = Math.floor((totalPairs + 1) / 2); // 1-based rank
|
|
36
|
+
const medianRankHigh = Math.floor((totalPairs + 2) / 2);
|
|
37
|
+
// Initialize search bounds for each row (1-based indexing)
|
|
38
|
+
const leftBounds = Array.from({ length: n }, (_, i) => i + 1);
|
|
39
|
+
const rightBounds = Array(n).fill(n);
|
|
40
|
+
// Start with a good pivot: sum of middle elements
|
|
41
|
+
let pivot = sortedValues[Math.floor((n - 1) / 2)] + sortedValues[Math.floor(n / 2)];
|
|
42
|
+
let activeSetSize = totalPairs;
|
|
43
|
+
let previousCount = 0;
|
|
44
|
+
while (true) {
|
|
45
|
+
// === PARTITION STEP ===
|
|
46
|
+
let countBelowPivot = 0;
|
|
47
|
+
let currentColumn = n;
|
|
48
|
+
const partitionCounts = [];
|
|
49
|
+
for (let row = 1; row <= n; row++) {
|
|
50
|
+
// Move left from current column until we find sums < pivot
|
|
51
|
+
while (currentColumn >= row &&
|
|
52
|
+
sortedValues[row - 1] + sortedValues[currentColumn - 1] >= pivot) {
|
|
53
|
+
currentColumn--;
|
|
54
|
+
}
|
|
55
|
+
// Count elements in this row that are < pivot
|
|
56
|
+
const elementsBelow = currentColumn >= row ? currentColumn - row + 1 : 0;
|
|
57
|
+
partitionCounts.push(elementsBelow);
|
|
58
|
+
countBelowPivot += elementsBelow;
|
|
59
|
+
}
|
|
60
|
+
// === CONVERGENCE CHECK ===
|
|
61
|
+
if (countBelowPivot === previousCount) {
|
|
62
|
+
let minActiveSum = Infinity;
|
|
63
|
+
let maxActiveSum = -Infinity;
|
|
64
|
+
for (let i = 0; i < n; i++) {
|
|
65
|
+
if (leftBounds[i] > rightBounds[i]) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const rowValue = sortedValues[i];
|
|
69
|
+
const smallestInRow = sortedValues[leftBounds[i] - 1] + rowValue;
|
|
70
|
+
const largestInRow = sortedValues[rightBounds[i] - 1] + rowValue;
|
|
71
|
+
minActiveSum = Math.min(minActiveSum, smallestInRow);
|
|
72
|
+
maxActiveSum = Math.max(maxActiveSum, largestInRow);
|
|
73
|
+
}
|
|
74
|
+
pivot = (minActiveSum + maxActiveSum) / 2;
|
|
75
|
+
if (pivot <= minActiveSum || pivot > maxActiveSum) {
|
|
76
|
+
pivot = maxActiveSum;
|
|
77
|
+
}
|
|
78
|
+
if (minActiveSum === maxActiveSum || activeSetSize <= 2) {
|
|
79
|
+
return pivot / 2;
|
|
80
|
+
}
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
// === TARGET CHECK ===
|
|
84
|
+
const atTargetRank = countBelowPivot === medianRankLow || countBelowPivot === medianRankHigh - 1;
|
|
85
|
+
if (atTargetRank) {
|
|
86
|
+
let largestBelowPivot = -Infinity;
|
|
87
|
+
let smallestAtOrAbovePivot = Infinity;
|
|
88
|
+
for (let i = 0; i < n; i++) {
|
|
89
|
+
const countInRow = partitionCounts[i];
|
|
90
|
+
const rowValue = sortedValues[i];
|
|
91
|
+
const totalInRow = n - i;
|
|
92
|
+
// Find largest sum in this row that's < pivot
|
|
93
|
+
if (countInRow > 0) {
|
|
94
|
+
const lastBelowIndex = i + countInRow;
|
|
95
|
+
const lastBelowValue = rowValue + sortedValues[lastBelowIndex - 1];
|
|
96
|
+
largestBelowPivot = Math.max(largestBelowPivot, lastBelowValue);
|
|
97
|
+
}
|
|
98
|
+
// Find smallest sum in this row that's >= pivot
|
|
99
|
+
if (countInRow < totalInRow) {
|
|
100
|
+
const firstAtOrAboveIndex = i + countInRow + 1;
|
|
101
|
+
const firstAtOrAboveValue = rowValue + sortedValues[firstAtOrAboveIndex - 1];
|
|
102
|
+
smallestAtOrAbovePivot = Math.min(smallestAtOrAbovePivot, firstAtOrAboveValue);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Calculate final result
|
|
106
|
+
if (medianRankLow < medianRankHigh) {
|
|
107
|
+
// Even total: average the two middle values
|
|
108
|
+
return (smallestAtOrAbovePivot + largestBelowPivot) / 4;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
// Odd total: return the single middle value
|
|
112
|
+
const needLargest = countBelowPivot === medianRankLow;
|
|
113
|
+
return (needLargest ? largestBelowPivot : smallestAtOrAbovePivot) / 2;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// === UPDATE BOUNDS ===
|
|
117
|
+
if (countBelowPivot < medianRankLow) {
|
|
118
|
+
// Too few values below pivot - search higher
|
|
119
|
+
for (let i = 0; i < n; i++) {
|
|
120
|
+
leftBounds[i] = i + partitionCounts[i] + 1;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
// Too many values below pivot - search lower
|
|
125
|
+
for (let i = 0; i < n; i++) {
|
|
126
|
+
rightBounds[i] = i + partitionCounts[i];
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// === PREPARE NEXT ITERATION ===
|
|
130
|
+
previousCount = countBelowPivot;
|
|
131
|
+
// Recalculate active set size
|
|
132
|
+
activeSetSize = 0;
|
|
133
|
+
for (let i = 0; i < n; i++) {
|
|
134
|
+
const rowSize = rightBounds[i] - leftBounds[i] + 1;
|
|
135
|
+
if (rowSize > 0) {
|
|
136
|
+
activeSetSize += rowSize;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Choose next pivot
|
|
140
|
+
if (activeSetSize > 2) {
|
|
141
|
+
// Use randomized row median strategy
|
|
142
|
+
const targetIndex = Math.floor(Math.random() * activeSetSize);
|
|
143
|
+
let cumulativeSize = 0;
|
|
144
|
+
let selectedRow = 0;
|
|
145
|
+
for (let i = 0; i < n; i++) {
|
|
146
|
+
const rowSize = rightBounds[i] - leftBounds[i] + 1;
|
|
147
|
+
if (rowSize > 0) {
|
|
148
|
+
if (targetIndex < cumulativeSize + rowSize) {
|
|
149
|
+
selectedRow = i;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
cumulativeSize += rowSize;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Use median element of the selected row as pivot
|
|
156
|
+
const medianColumnInRow = Math.floor((leftBounds[selectedRow] + rightBounds[selectedRow]) / 2);
|
|
157
|
+
pivot = sortedValues[selectedRow] + sortedValues[medianColumnInRow - 1];
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
// Few elements remain - use midrange strategy
|
|
161
|
+
let minRemainingSum = Infinity;
|
|
162
|
+
let maxRemainingSum = -Infinity;
|
|
163
|
+
for (let i = 0; i < n; i++) {
|
|
164
|
+
if (leftBounds[i] > rightBounds[i]) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const rowValue = sortedValues[i];
|
|
168
|
+
const minInRow = sortedValues[leftBounds[i] - 1] + rowValue;
|
|
169
|
+
const maxInRow = sortedValues[rightBounds[i] - 1] + rowValue;
|
|
170
|
+
minRemainingSum = Math.min(minRemainingSum, minInRow);
|
|
171
|
+
maxRemainingSum = Math.max(maxRemainingSum, maxInRow);
|
|
172
|
+
}
|
|
173
|
+
pivot = (minRemainingSum + maxRemainingSum) / 2;
|
|
174
|
+
if (pivot <= minRemainingSum || pivot > maxRemainingSum) {
|
|
175
|
+
pivot = maxRemainingSum;
|
|
176
|
+
}
|
|
177
|
+
if (minRemainingSum === maxRemainingSum) {
|
|
178
|
+
return pivot / 2;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=fastCenter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastCenter.js","sourceRoot":"","sources":["../src/fastCenter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fast O(n log n) implementation of the Spread (Shamos) estimator.
|
|
3
|
+
* Based on Monahan's selection algorithm adapted for pairwise differences.
|
|
4
|
+
*
|
|
5
|
+
* Internal implementation - not part of public API.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Compute the median of all pairwise absolute differences |xi - xj| efficiently.
|
|
9
|
+
*
|
|
10
|
+
* Time complexity: O(n log n) expected
|
|
11
|
+
* Space complexity: O(n)
|
|
12
|
+
*
|
|
13
|
+
* @param values Array of numeric values
|
|
14
|
+
* @returns The spread estimate (Shamos estimator)
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
export declare function fastSpread(values: number[]): number;
|
|
18
|
+
//# sourceMappingURL=fastSpread.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastSpread.d.ts","sourceRoot":"","sources":["../src/fastSpread.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CA2MnD"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Fast O(n log n) implementation of the Spread (Shamos) estimator.
|
|
4
|
+
* Based on Monahan's selection algorithm adapted for pairwise differences.
|
|
5
|
+
*
|
|
6
|
+
* Internal implementation - not part of public API.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.fastSpread = fastSpread;
|
|
10
|
+
/**
|
|
11
|
+
* Compute the median of all pairwise absolute differences |xi - xj| efficiently.
|
|
12
|
+
*
|
|
13
|
+
* Time complexity: O(n log n) expected
|
|
14
|
+
* Space complexity: O(n)
|
|
15
|
+
*
|
|
16
|
+
* @param values Array of numeric values
|
|
17
|
+
* @returns The spread estimate (Shamos estimator)
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
function fastSpread(values) {
|
|
21
|
+
const n = values.length;
|
|
22
|
+
if (n === 0) {
|
|
23
|
+
throw new Error('Input array cannot be empty');
|
|
24
|
+
}
|
|
25
|
+
if (n === 1) {
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
if (n === 2) {
|
|
29
|
+
return Math.abs(values[1] - values[0]);
|
|
30
|
+
}
|
|
31
|
+
// Sort the values
|
|
32
|
+
const a = [...values].sort((a, b) => a - b);
|
|
33
|
+
// Total number of pairwise differences with i < j
|
|
34
|
+
const N = Math.floor((n * (n - 1)) / 2);
|
|
35
|
+
const kLow = Math.floor((N + 1) / 2); // 1-based rank of lower middle
|
|
36
|
+
const kHigh = Math.floor((N + 2) / 2); // 1-based rank of upper middle
|
|
37
|
+
// Per-row active bounds over columns j (0-based indices)
|
|
38
|
+
// Row i allows j in [i+1, n-1] initially
|
|
39
|
+
const L = Array.from({ length: n }, (_, i) => Math.min(i + 1, n));
|
|
40
|
+
const R = Array(n).fill(n - 1);
|
|
41
|
+
for (let i = 0; i < n; i++) {
|
|
42
|
+
if (L[i] > R[i]) {
|
|
43
|
+
L[i] = 1;
|
|
44
|
+
R[i] = 0; // mark empty
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const rowCounts = Array(n).fill(0);
|
|
48
|
+
// Initial pivot: a central gap
|
|
49
|
+
let pivot = a[Math.floor(n / 2)] - a[Math.floor((n - 1) / 2)];
|
|
50
|
+
let prevCountBelow = -1;
|
|
51
|
+
while (true) {
|
|
52
|
+
// === PARTITION: count how many differences are < pivot ===
|
|
53
|
+
let countBelow = 0;
|
|
54
|
+
let largestBelow = -Infinity;
|
|
55
|
+
let smallestAtOrAbove = Infinity;
|
|
56
|
+
let j = 1; // global two-pointer (non-decreasing across rows)
|
|
57
|
+
for (let i = 0; i < n - 1; i++) {
|
|
58
|
+
if (j < i + 1) {
|
|
59
|
+
j = i + 1;
|
|
60
|
+
}
|
|
61
|
+
while (j < n && a[j] - a[i] < pivot) {
|
|
62
|
+
j++;
|
|
63
|
+
}
|
|
64
|
+
const cntRow = Math.max(0, j - (i + 1));
|
|
65
|
+
rowCounts[i] = cntRow;
|
|
66
|
+
countBelow += cntRow;
|
|
67
|
+
// boundary elements for this row
|
|
68
|
+
if (cntRow > 0) {
|
|
69
|
+
const candBelow = a[j - 1] - a[i];
|
|
70
|
+
largestBelow = Math.max(largestBelow, candBelow);
|
|
71
|
+
}
|
|
72
|
+
if (j < n) {
|
|
73
|
+
const candAtOrAbove = a[j] - a[i];
|
|
74
|
+
smallestAtOrAbove = Math.min(smallestAtOrAbove, candAtOrAbove);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// === TARGET CHECK ===
|
|
78
|
+
const atTarget = countBelow === kLow || countBelow === kHigh - 1;
|
|
79
|
+
if (atTarget) {
|
|
80
|
+
if (kLow < kHigh) {
|
|
81
|
+
// Even N: average the two central order stats
|
|
82
|
+
return 0.5 * (largestBelow + smallestAtOrAbove);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// Odd N: pick the single middle
|
|
86
|
+
const needLargest = countBelow === kLow;
|
|
87
|
+
return needLargest ? largestBelow : smallestAtOrAbove;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// === STALL HANDLING ===
|
|
91
|
+
if (countBelow === prevCountBelow) {
|
|
92
|
+
let minActive = Infinity;
|
|
93
|
+
let maxActive = -Infinity;
|
|
94
|
+
let active = 0;
|
|
95
|
+
for (let i = 0; i < n - 1; i++) {
|
|
96
|
+
const Li = L[i];
|
|
97
|
+
const Ri = R[i];
|
|
98
|
+
if (Li > Ri) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const rowMin = a[Li] - a[i];
|
|
102
|
+
const rowMax = a[Ri] - a[i];
|
|
103
|
+
minActive = Math.min(minActive, rowMin);
|
|
104
|
+
maxActive = Math.max(maxActive, rowMax);
|
|
105
|
+
active += Ri - Li + 1;
|
|
106
|
+
}
|
|
107
|
+
if (active <= 0) {
|
|
108
|
+
if (kLow < kHigh) {
|
|
109
|
+
return 0.5 * (largestBelow + smallestAtOrAbove);
|
|
110
|
+
}
|
|
111
|
+
return countBelow >= kLow ? largestBelow : smallestAtOrAbove;
|
|
112
|
+
}
|
|
113
|
+
if (maxActive <= minActive) {
|
|
114
|
+
return minActive;
|
|
115
|
+
}
|
|
116
|
+
const mid = 0.5 * (minActive + maxActive);
|
|
117
|
+
pivot = mid > minActive && mid <= maxActive ? mid : maxActive;
|
|
118
|
+
prevCountBelow = countBelow;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
// === SHRINK ACTIVE WINDOW ===
|
|
122
|
+
if (countBelow < kLow) {
|
|
123
|
+
// Need larger differences: discard all strictly below pivot
|
|
124
|
+
for (let i = 0; i < n - 1; i++) {
|
|
125
|
+
const newL = i + 1 + rowCounts[i];
|
|
126
|
+
if (newL > L[i]) {
|
|
127
|
+
L[i] = newL;
|
|
128
|
+
}
|
|
129
|
+
if (L[i] > R[i]) {
|
|
130
|
+
L[i] = 1;
|
|
131
|
+
R[i] = 0;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// Too many below: keep only those strictly below pivot
|
|
137
|
+
for (let i = 0; i < n - 1; i++) {
|
|
138
|
+
const newR = i + rowCounts[i];
|
|
139
|
+
if (newR < R[i]) {
|
|
140
|
+
R[i] = newR;
|
|
141
|
+
}
|
|
142
|
+
if (R[i] < i + 1) {
|
|
143
|
+
L[i] = 1;
|
|
144
|
+
R[i] = 0;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
prevCountBelow = countBelow;
|
|
149
|
+
// === CHOOSE NEXT PIVOT FROM ACTIVE SET ===
|
|
150
|
+
let activeSize = 0;
|
|
151
|
+
for (let i = 0; i < n - 1; i++) {
|
|
152
|
+
if (L[i] <= R[i]) {
|
|
153
|
+
activeSize += R[i] - L[i] + 1;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (activeSize <= 2) {
|
|
157
|
+
// Few candidates left: return midrange of remaining
|
|
158
|
+
let minRem = Infinity;
|
|
159
|
+
let maxRem = -Infinity;
|
|
160
|
+
for (let i = 0; i < n - 1; i++) {
|
|
161
|
+
if (L[i] > R[i]) {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
const lo = a[L[i]] - a[i];
|
|
165
|
+
const hi = a[R[i]] - a[i];
|
|
166
|
+
minRem = Math.min(minRem, lo);
|
|
167
|
+
maxRem = Math.max(maxRem, hi);
|
|
168
|
+
}
|
|
169
|
+
if (activeSize <= 0) {
|
|
170
|
+
if (kLow < kHigh) {
|
|
171
|
+
return 0.5 * (largestBelow + smallestAtOrAbove);
|
|
172
|
+
}
|
|
173
|
+
return countBelow >= kLow ? largestBelow : smallestAtOrAbove;
|
|
174
|
+
}
|
|
175
|
+
if (kLow < kHigh) {
|
|
176
|
+
return 0.5 * (minRem + maxRem);
|
|
177
|
+
}
|
|
178
|
+
return Math.abs(kLow - 1 - countBelow) <= Math.abs(countBelow - kLow) ? minRem : maxRem;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
// Weighted random row selection
|
|
182
|
+
const t = Math.floor(Math.random() * activeSize);
|
|
183
|
+
let acc = 0;
|
|
184
|
+
let row = 0;
|
|
185
|
+
for (row = 0; row < n - 1; row++) {
|
|
186
|
+
if (L[row] > R[row]) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const size = R[row] - L[row] + 1;
|
|
190
|
+
if (t < acc + size) {
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
acc += size;
|
|
194
|
+
}
|
|
195
|
+
// Median column of the selected row
|
|
196
|
+
const col = Math.floor((L[row] + R[row]) / 2);
|
|
197
|
+
pivot = a[col] - a[row];
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=fastSpread.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fastSpread.js","sourceRoot":"","sources":["../src/fastSpread.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pragmastat: Unified Statistical Toolkit
|
|
3
|
+
*
|
|
4
|
+
* A collection of robust statistical estimators for real-world data analysis.
|
|
5
|
+
*/
|
|
6
|
+
export { center, spread, relSpread, shift, ratio, avgSpread, disparity } from './estimators';
|
|
7
|
+
export { median } from './utils';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE7F,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Pragmastat: Unified Statistical Toolkit
|
|
4
|
+
*
|
|
5
|
+
* A collection of robust statistical estimators for real-world data analysis.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.median = exports.disparity = exports.avgSpread = exports.ratio = exports.shift = exports.relSpread = exports.spread = exports.center = void 0;
|
|
9
|
+
var estimators_1 = require("./estimators");
|
|
10
|
+
Object.defineProperty(exports, "center", { enumerable: true, get: function () { return estimators_1.center; } });
|
|
11
|
+
Object.defineProperty(exports, "spread", { enumerable: true, get: function () { return estimators_1.spread; } });
|
|
12
|
+
Object.defineProperty(exports, "relSpread", { enumerable: true, get: function () { return estimators_1.relSpread; } });
|
|
13
|
+
Object.defineProperty(exports, "shift", { enumerable: true, get: function () { return estimators_1.shift; } });
|
|
14
|
+
Object.defineProperty(exports, "ratio", { enumerable: true, get: function () { return estimators_1.ratio; } });
|
|
15
|
+
Object.defineProperty(exports, "avgSpread", { enumerable: true, get: function () { return estimators_1.avgSpread; } });
|
|
16
|
+
Object.defineProperty(exports, "disparity", { enumerable: true, get: function () { return estimators_1.disparity; } });
|
|
17
|
+
var utils_1 = require("./utils");
|
|
18
|
+
Object.defineProperty(exports, "median", { enumerable: true, get: function () { return utils_1.median; } });
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,2CAA6F;AAApF,oGAAA,MAAM,OAAA;AAAE,oGAAA,MAAM,OAAA;AAAE,uGAAA,SAAS,OAAA;AAAE,mGAAA,KAAK,OAAA;AAAE,mGAAA,KAAK,OAAA;AAAE,uGAAA,SAAS,OAAA;AAAE,uGAAA,SAAS,OAAA;AAEtE,iCAAiC;AAAxB,+FAAA,MAAM,OAAA"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for statistical calculations
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Calculate the median of an array of numbers
|
|
6
|
+
* @param values Array of numbers
|
|
7
|
+
* @returns The median value
|
|
8
|
+
*/
|
|
9
|
+
export declare function median(values: number[]): number;
|
|
10
|
+
/**
|
|
11
|
+
* Generate all pairwise combinations of indices
|
|
12
|
+
* @param n Number of elements
|
|
13
|
+
* @param includeDiagonal Whether to include pairs (i, i)
|
|
14
|
+
* @returns Array of index pairs [i, j]
|
|
15
|
+
*/
|
|
16
|
+
export declare function getPairs(n: number, includeDiagonal?: boolean): [number, number][];
|
|
17
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAa/C;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,eAAe,GAAE,OAAc,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAWvF"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Utility functions for statistical calculations
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.median = median;
|
|
7
|
+
exports.getPairs = getPairs;
|
|
8
|
+
/**
|
|
9
|
+
* Calculate the median of an array of numbers
|
|
10
|
+
* @param values Array of numbers
|
|
11
|
+
* @returns The median value
|
|
12
|
+
*/
|
|
13
|
+
function median(values) {
|
|
14
|
+
if (values.length === 0) {
|
|
15
|
+
return 0;
|
|
16
|
+
}
|
|
17
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
18
|
+
const mid = Math.floor(sorted.length / 2);
|
|
19
|
+
if (sorted.length % 2 === 0) {
|
|
20
|
+
return (sorted[mid - 1] + sorted[mid]) / 2;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
return sorted[mid];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Generate all pairwise combinations of indices
|
|
28
|
+
* @param n Number of elements
|
|
29
|
+
* @param includeDiagonal Whether to include pairs (i, i)
|
|
30
|
+
* @returns Array of index pairs [i, j]
|
|
31
|
+
*/
|
|
32
|
+
function getPairs(n, includeDiagonal = true) {
|
|
33
|
+
const pairs = [];
|
|
34
|
+
for (let i = 0; i < n; i++) {
|
|
35
|
+
const startJ = includeDiagonal ? i : i + 1;
|
|
36
|
+
for (let j = startJ; j < n; j++) {
|
|
37
|
+
pairs.push([i, j]);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return pairs;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAOH,wBAaC;AAQD,4BAWC;AArCD;;;;GAIG;AACH,SAAgB,MAAM,CAAC,MAAgB;IACrC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACjD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE1C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7C,CAAC;SAAM,CAAC;QACN,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAgB,QAAQ,CAAC,CAAS,EAAE,kBAA2B,IAAI;IACjE,MAAM,KAAK,GAAuB,EAAE,CAAC;IAErC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC3C,KAAK,IAAI,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAChC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pragmastat",
|
|
3
|
+
"version": "3.1.10",
|
|
4
|
+
"description": "Pragmastat: Pragmatic Statistical Toolkit",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"test": "jest",
|
|
10
|
+
"test:watch": "jest --watch",
|
|
11
|
+
"test:coverage": "jest --coverage",
|
|
12
|
+
"lint": "eslint src tests --ext .ts",
|
|
13
|
+
"format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
14
|
+
"format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
15
|
+
"clean": "rm -rf dist coverage",
|
|
16
|
+
"prepublishOnly": "npm run clean && npm run build && npm run test"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"statistics",
|
|
20
|
+
"robust",
|
|
21
|
+
"estimators",
|
|
22
|
+
"median",
|
|
23
|
+
"hodges-lehmann"
|
|
24
|
+
],
|
|
25
|
+
"author": "Andrey Akinshin",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/jest": "^29.5.0",
|
|
29
|
+
"@types/node": "^20.0.0",
|
|
30
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
31
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
32
|
+
"eslint": "^8.0.0",
|
|
33
|
+
"jest": "^29.5.0",
|
|
34
|
+
"prettier": "^3.0.0",
|
|
35
|
+
"ts-jest": "^29.1.0",
|
|
36
|
+
"typescript": "^5.0.0"
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"LICENSE",
|
|
41
|
+
"README.md"
|
|
42
|
+
],
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "https://github.com/AndreyAkinshin/pragmastat.git"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://pragmastat.dev",
|
|
48
|
+
"doi": "10.5281/zenodo.17236778"
|
|
49
|
+
}
|