@compstats/core 0.3.0 → 0.4.0
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/CHANGELOG.md +71 -0
- package/README.md +117 -116
- package/dist/3d.js +1120 -122
- package/dist/3d.js.map +16 -9
- package/dist/core/arith.d.ts.map +1 -1
- package/dist/core/linalg/cov.d.ts +50 -0
- package/dist/core/linalg/cov.d.ts.map +1 -0
- package/dist/core/linalg/eigen.d.ts +53 -0
- package/dist/core/linalg/eigen.d.ts.map +1 -0
- package/dist/core/linalg/lm.d.ts +78 -0
- package/dist/core/linalg/lm.d.ts.map +1 -0
- package/dist/core/linalg/lu.d.ts +154 -0
- package/dist/core/linalg/lu.d.ts.map +1 -0
- package/dist/core/linalg/matrix.d.ts +131 -0
- package/dist/core/linalg/matrix.d.ts.map +1 -0
- package/dist/core/linalg/modelMatrix.d.ts +69 -0
- package/dist/core/linalg/modelMatrix.d.ts.map +1 -0
- package/dist/core/linalg/namedVector.d.ts +37 -0
- package/dist/core/linalg/namedVector.d.ts.map +1 -0
- package/dist/core/linalg/ops.d.ts +120 -0
- package/dist/core/linalg/ops.d.ts.map +1 -0
- package/dist/core/linalg/prcomp.d.ts +66 -0
- package/dist/core/linalg/prcomp.d.ts.map +1 -0
- package/dist/core/linalg/qr.d.ts +134 -0
- package/dist/core/linalg/qr.d.ts.map +1 -0
- package/dist/core/linalg/vector.d.ts +68 -0
- package/dist/core/linalg/vector.d.ts.map +1 -0
- package/dist/core/moderation.d.ts +6 -3
- package/dist/core/moderation.d.ts.map +1 -1
- package/dist/core/ols.d.ts +4 -7
- package/dist/core/ols.d.ts.map +1 -1
- package/dist/data/moderationData.d.ts +2 -2
- package/dist/data/pcaDegenerate.d.ts +1 -1
- package/dist/index.js +1455 -863
- package/dist/index.js.map +16 -10
- package/dist/linalg.d.ts +36 -0
- package/dist/linalg.d.ts.map +1 -0
- package/dist/linalg.js +1860 -0
- package/dist/linalg.js.map +24 -0
- package/dist/plot/moderation3d.d.ts +1 -1
- package/dist/plot/scatter3d.d.ts +1 -1
- package/package.json +7 -2
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The elementary matrix operations, named as R names them.
|
|
3
|
+
*
|
|
4
|
+
* `t()`, `%*%` (`matmul`), `crossprod()`, `tcrossprod()`, `cbind()`,
|
|
5
|
+
* `rbind()` and `diag()`. Each takes matrices (and, where R allows it, plain
|
|
6
|
+
* vectors) and returns a new matrix; nothing here modifies its input.
|
|
7
|
+
*
|
|
8
|
+
* A bare vector in a product takes the shape R gives it, which is not
|
|
9
|
+
* always the one that would conform (fixtures 1g and 1h probe the rules).
|
|
10
|
+
* In `%*%`, a left vector is a row when its length matches the rows of the
|
|
11
|
+
* right factor and otherwise a column; a right vector is a column when its
|
|
12
|
+
* length matches the columns of the left factor and otherwise a row; two
|
|
13
|
+
* vectors give their inner product. In `crossprod` a vector `x` is always
|
|
14
|
+
* a column, and a vector `y` is a column when its length matches the rows
|
|
15
|
+
* of `x` and otherwise a row. In `tcrossprod` a vector `x` is a row when
|
|
16
|
+
* its length matches the columns of a matrix `y` and otherwise a column,
|
|
17
|
+
* and a vector `y` is a row only when `x` has one row; two vectors are both
|
|
18
|
+
* columns, the outer product.
|
|
19
|
+
*
|
|
20
|
+
* Dimnames travel as they do in R: a transpose swaps them, a product keeps
|
|
21
|
+
* the row names of the left factor and the column names of the right, and
|
|
22
|
+
* binding stacks them, with `""` for a bare vector joined to a named matrix.
|
|
23
|
+
*
|
|
24
|
+
* The product follows the reference BLAS `dgemm` that R ships: the loop
|
|
25
|
+
* over `i` innermost walks each column of the left factor in order, and each
|
|
26
|
+
* product is rounded once into its running sum with `fusedMultiplyAdd`,
|
|
27
|
+
* because the build the conformance fixtures come from contracts
|
|
28
|
+
* `C + A * B` into one instruction (the fixture README records this; the LU
|
|
29
|
+
* and QR here already follow it). Index loops throughout: a product
|
|
30
|
+
* addresses entries by position. (CLAUDE.md allows an index loop with a
|
|
31
|
+
* stated reason; that is the reason.)
|
|
32
|
+
*/
|
|
33
|
+
import { type Matrix } from "./matrix";
|
|
34
|
+
import type { Vector } from "./vector";
|
|
35
|
+
/** A matrix, or a vector R would treat as a one-column matrix. */
|
|
36
|
+
export type MatrixOrVector = Matrix | Vector;
|
|
37
|
+
/** R's `t()`. Also exported as `transpose`, for an app whose `t` is already taken. */
|
|
38
|
+
export declare function t(m: Matrix): Matrix;
|
|
39
|
+
/** R's `t()`, under a name that does not collide with an i18n `t`. */
|
|
40
|
+
export declare const transpose: typeof t;
|
|
41
|
+
/**
|
|
42
|
+
* R's `x %*% y`.
|
|
43
|
+
*
|
|
44
|
+
* @param x The left factor. A vector is a row when its length matches the
|
|
45
|
+
* rows of `y`, else a column when `y` has one row.
|
|
46
|
+
* @param y The right factor. A vector is a column when its length matches
|
|
47
|
+
* the columns of `x`, else a row when `x` has one column. Two vectors of
|
|
48
|
+
* one length give their inner product as a 1 x 1 matrix.
|
|
49
|
+
* @returns The product, with the row names of `x` and the column names of
|
|
50
|
+
* `y`.
|
|
51
|
+
* @throws RangeError If the inner extents differ: R's "non-conformable
|
|
52
|
+
* arguments".
|
|
53
|
+
*/
|
|
54
|
+
export declare function matmul(x: MatrixOrVector, y: MatrixOrVector): Matrix;
|
|
55
|
+
/**
|
|
56
|
+
* R's `crossprod(x, y)`: `t(x) %*% y`, with `crossprod(x)` for `t(x) %*% x`.
|
|
57
|
+
* A bare vector `x` is a column; a bare vector `y` is a column when its
|
|
58
|
+
* length matches the rows of `x`, else a row (fixture 1h).
|
|
59
|
+
*
|
|
60
|
+
* @throws RangeError If the row counts differ.
|
|
61
|
+
*/
|
|
62
|
+
export declare function crossprod(x: MatrixOrVector, y?: MatrixOrVector): Matrix;
|
|
63
|
+
/**
|
|
64
|
+
* R's `tcrossprod(x, y)`: `x %*% t(y)`, with `tcrossprod(x)` for
|
|
65
|
+
* `x %*% t(x)`. A bare vector `x` is a row when its length matches the
|
|
66
|
+
* columns of a matrix `y`, else a column; a bare vector `y` is a row only
|
|
67
|
+
* when `x` has one row, and two bare vectors are both columns (fixture 1h).
|
|
68
|
+
*
|
|
69
|
+
* @throws RangeError If the column counts differ.
|
|
70
|
+
*/
|
|
71
|
+
export declare function tcrossprod(x: MatrixOrVector, y?: MatrixOrVector): Matrix;
|
|
72
|
+
/**
|
|
73
|
+
* Tell a matrix from a vector by shape, and refuse anything else — a typed
|
|
74
|
+
* array or a stray object — with a TypeError rather than a wrong shape.
|
|
75
|
+
*
|
|
76
|
+
* @internal Shared with the other linalg modules; not part of the entry.
|
|
77
|
+
*/
|
|
78
|
+
export declare function isMatrix(value: MatrixOrVector): value is Matrix;
|
|
79
|
+
/**
|
|
80
|
+
* R's `cbind()`: join matrices and vectors side by side.
|
|
81
|
+
*
|
|
82
|
+
* @param parts Matrices, and vectors taken as columns. At least one.
|
|
83
|
+
* @returns The joined matrix. Row names come from the first part that has
|
|
84
|
+
* them. Column names are kept when any part has them, with `""` for a part
|
|
85
|
+
* that does not, as R names a bare vector.
|
|
86
|
+
* @throws RangeError If the row counts differ, in R's words for a matrix
|
|
87
|
+
* part and for a vector part. R recycles a short vector with a warning;
|
|
88
|
+
* the port refuses.
|
|
89
|
+
*/
|
|
90
|
+
export declare function cbind(...parts: readonly MatrixOrVector[]): Matrix;
|
|
91
|
+
/**
|
|
92
|
+
* R's `rbind()`: stack matrices and vectors.
|
|
93
|
+
*
|
|
94
|
+
* @param parts Matrices, and vectors taken as rows. At least one.
|
|
95
|
+
* @returns The stacked matrix, with names as `cbind` carries them, rows and
|
|
96
|
+
* columns exchanged.
|
|
97
|
+
* @throws RangeError If the column counts differ.
|
|
98
|
+
*/
|
|
99
|
+
export declare function rbind(...parts: readonly MatrixOrVector[]): Matrix;
|
|
100
|
+
/**
|
|
101
|
+
* R's `diag()` in its three forms: a vector gives the diagonal matrix of it,
|
|
102
|
+
* a count gives the identity of that order, and a matrix gives its diagonal.
|
|
103
|
+
*
|
|
104
|
+
* The form is chosen by type, not by length, which is R's own gotcha
|
|
105
|
+
* removed: `diag([5])` is the 1 x 1 matrix `[5]` where R's `diag(c(5))` is
|
|
106
|
+
* the 5 x 5 identity, and `diag(2.5)` refuses where R truncates to 2 x 2.
|
|
107
|
+
* The diagonal of a matrix comes back as a plain array; R names it when the
|
|
108
|
+
* row and column names agree, which the port will do once a named vector
|
|
109
|
+
* exists (plan Q11).
|
|
110
|
+
*/
|
|
111
|
+
export declare function diag(values: Vector): Matrix;
|
|
112
|
+
export declare function diag(order: number): Matrix;
|
|
113
|
+
export declare function diag(m: Matrix): number[];
|
|
114
|
+
/**
|
|
115
|
+
* The identity matrix of the given order. R's `diag(n)`.
|
|
116
|
+
*
|
|
117
|
+
* @throws RangeError If the order is not a non-negative integer.
|
|
118
|
+
*/
|
|
119
|
+
export declare function identity(order: number): Matrix;
|
|
120
|
+
//# sourceMappingURL=ops.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ops.d.ts","sourceRoot":"","sources":["../../../src/core/linalg/ops.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,kEAAkE;AAClE,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC;AAE7C,sFAAsF;AACtF,wBAAgB,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAWnC;AAED,sEAAsE;AACtE,eAAO,MAAM,SAAS,UAAI,CAAC;AAE3B;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,MAAM,CASnE;AAkBD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,GAAE,cAAkB,GAAG,MAAM,CAS1E;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,GAAE,cAAkB,GAAG,MAAM,CAc3E;AA0CD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,KAAK,IAAI,MAAM,CAc/D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,KAAK,CAAC,GAAG,KAAK,EAAE,SAAS,cAAc,EAAE,GAAG,MAAM,CA8BjE;AAED;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,GAAG,KAAK,EAAE,SAAS,cAAc,EAAE,GAAG,MAAM,CAejE;AAcD;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;AAC7C,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;AAC5C,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;AAmB1C;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAS9C"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* R's `prcomp()`: principal components of a matrix or a data frame, any
|
|
3
|
+
* number of variables.
|
|
4
|
+
*
|
|
5
|
+
* R centers (and optionally scales) the columns and takes the singular
|
|
6
|
+
* value decomposition of the result. The port centers and scales the same
|
|
7
|
+
* way and then decomposes the covariance matrix with `eigenSymmetric`: the
|
|
8
|
+
* standard deviations are the square roots of its eigenvalues, the rotation
|
|
9
|
+
* its eigenvectors, and the scores the centered data times the rotation.
|
|
10
|
+
* The two routes agree to a relative `1e-12` on the standard deviations and
|
|
11
|
+
* up to the sign of each component on the rest (plan Q1), which the SVD
|
|
12
|
+
* leaves arbitrary as well; the port's sign rule is `eigenSymmetric`'s.
|
|
13
|
+
* Verified in `prcomp.test.ts`, including agreement with the two-variable
|
|
14
|
+
* `principalComponents` of `pca.ts` on the bundled `pcaDegenerate` points.
|
|
15
|
+
*
|
|
16
|
+
* As `pca.ts` does, the port returns one component per variable and never
|
|
17
|
+
* reduces the rank: a collinear input reports a near-zero standard
|
|
18
|
+
* deviation rather than a shorter result. R's `prcomp` returns `min(n, p)`
|
|
19
|
+
* components, which is the same unless there are fewer rows than columns.
|
|
20
|
+
*/
|
|
21
|
+
import type { DataFrame } from "../frame";
|
|
22
|
+
import { type Matrix } from "./matrix";
|
|
23
|
+
import type { Vector } from "./vector";
|
|
24
|
+
export interface PrcompOptions {
|
|
25
|
+
/** Subtract the column means first. True by default, as R's is. */
|
|
26
|
+
readonly center?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Divide each column by its root mean square after centering — its
|
|
29
|
+
* standard deviation, when centered. False by default, as R's is.
|
|
30
|
+
*/
|
|
31
|
+
readonly scale?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/** R's `prcomp` result. */
|
|
34
|
+
export interface Prcomp {
|
|
35
|
+
/** The standard deviation along each component, largest first. */
|
|
36
|
+
readonly sdev: Vector;
|
|
37
|
+
/**
|
|
38
|
+
* The loadings: one row per variable, one column per component, named
|
|
39
|
+
* `PC1`, `PC2`, … with the variable names as row names when the input
|
|
40
|
+
* has column names.
|
|
41
|
+
*/
|
|
42
|
+
readonly rotation: Matrix;
|
|
43
|
+
/** The value subtracted from each column; zeros when not centered. */
|
|
44
|
+
readonly center: Vector;
|
|
45
|
+
/** The value each column was divided by, or null when not scaled. */
|
|
46
|
+
readonly scale: Vector | null;
|
|
47
|
+
/**
|
|
48
|
+
* The scores: the centered, scaled data in component coordinates, with
|
|
49
|
+
* the row names of the input and `PC1`, `PC2`, … as column names, as R's
|
|
50
|
+
* are (fixture 5e).
|
|
51
|
+
*/
|
|
52
|
+
readonly x: Matrix;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Compute the principal components, as R's `prcomp()` does.
|
|
56
|
+
*
|
|
57
|
+
* @param input A matrix with one column per variable, or a data frame whose
|
|
58
|
+
* numeric columns are the variables.
|
|
59
|
+
* @param options Whether to center and whether to scale.
|
|
60
|
+
* @returns The standard deviations, the rotation, the centering and scaling
|
|
61
|
+
* applied, and the scores.
|
|
62
|
+
* @throws RangeError If any value is missing or infinite (R's `svd` refuses
|
|
63
|
+
* the same), or if a column to be scaled is constant, in R's words.
|
|
64
|
+
*/
|
|
65
|
+
export declare function prcomp(input: Matrix | DataFrame, options?: PrcompOptions): Prcomp;
|
|
66
|
+
//# sourceMappingURL=prcomp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prcomp.d.ts","sourceRoot":"","sources":["../../../src/core/linalg/prcomp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG1C,OAAO,EAAmB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC;AAExD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,MAAM,WAAW,aAAa;IAC5B,mEAAmE;IACnE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,2BAA2B;AAC3B,MAAM,WAAW,MAAM;IACrB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAwDrF"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The QR factorization, R's `qr()` with `LAPACK = FALSE`.
|
|
3
|
+
*
|
|
4
|
+
* R factors a design with LINPACK's `dqrdc2`, a Householder QR with a
|
|
5
|
+
* limited column-pivoting rule: a column whose norm has collapsed against
|
|
6
|
+
* the columns to its left is moved to the right edge and its coefficient is
|
|
7
|
+
* reported as `NA`. That rule is what makes `lm()` and `glm()` report an
|
|
8
|
+
* aliased coefficient instead of dividing by a near-zero pivot. This module
|
|
9
|
+
* reproduces it and exposes R's result — the compact `qr` matrix, `qraux`,
|
|
10
|
+
* `pivot` and `rank` — and R's readers of it: `qr.coef`, `qr.fitted`,
|
|
11
|
+
* `qr.resid`, `qr.qy`, `qr.qty`, `qr.Q` and `qr.R`. Verified against R in
|
|
12
|
+
* `qr.test.ts`; `leastSquares` in `../ols.ts` is a wrapper over it.
|
|
13
|
+
*
|
|
14
|
+
* Designs here are small — two columns for logit, four for a moderation
|
|
15
|
+
* surface — so the code follows the LINPACK routines plainly rather than
|
|
16
|
+
* blocking or vectorizing them. Index loops throughout: a factorization
|
|
17
|
+
* addresses single entries by position, and this one follows `dqrdc2` and
|
|
18
|
+
* `dqrsl` step for step so that the fixtures pin bit for bit.
|
|
19
|
+
*/
|
|
20
|
+
import { type Matrix } from "./matrix";
|
|
21
|
+
import type { Vector } from "./vector";
|
|
22
|
+
/** R's `qr()` result. */
|
|
23
|
+
export interface QrDecomposition {
|
|
24
|
+
/**
|
|
25
|
+
* The compact factorization, R's `qr$qr`: `R` on and above the diagonal,
|
|
26
|
+
* the Householder vectors below it, columns in pivot order. Column names
|
|
27
|
+
* follow the pivot, as R's do.
|
|
28
|
+
*/
|
|
29
|
+
readonly qr: Matrix;
|
|
30
|
+
/**
|
|
31
|
+
* R's `qr$qraux`: for each reflected column, the leading entry of its
|
|
32
|
+
* Householder reflector; for a column never reflected — the trailing
|
|
33
|
+
* column of a square or wide design, or an aliased column — its remaining
|
|
34
|
+
* norm, which is what R reports there (fixtures 2b, 2c, 2g).
|
|
35
|
+
*/
|
|
36
|
+
readonly qraux: Vector;
|
|
37
|
+
/**
|
|
38
|
+
* The column order after pivoting, R's `qr$pivot` **zero-based**:
|
|
39
|
+
* `pivot[k]` is the original index of the column now at position `k`.
|
|
40
|
+
* The aliased columns are at the end.
|
|
41
|
+
*/
|
|
42
|
+
readonly pivot: readonly number[];
|
|
43
|
+
/** The number of columns the factorization could identify. */
|
|
44
|
+
readonly rank: number;
|
|
45
|
+
}
|
|
46
|
+
export interface QrOptions {
|
|
47
|
+
/**
|
|
48
|
+
* How far a column's norm may collapse before it is aliased: the column is
|
|
49
|
+
* moved to the end when its remaining norm falls below this fraction of
|
|
50
|
+
* its original norm. The default is R's `qr()` and `lm.fit()` default.
|
|
51
|
+
* `glm.fit()` passes `min(1e-7, epsilon / 1000)`. Zero aliases nothing,
|
|
52
|
+
* as R's `tol = 0` does; a negative or NaN value is refused, where R
|
|
53
|
+
* would pass it through — a deliberate narrowing.
|
|
54
|
+
*/
|
|
55
|
+
readonly tolerance?: number;
|
|
56
|
+
}
|
|
57
|
+
/** The rank tolerance of R's `qr()` and `lm.fit()`. */
|
|
58
|
+
export declare const DEFAULT_QR_TOLERANCE = 1e-7;
|
|
59
|
+
/**
|
|
60
|
+
* Factor a matrix, as R's `qr(x, LAPACK = FALSE)` does.
|
|
61
|
+
*
|
|
62
|
+
* @param x The matrix. The function does not modify it. Row names travel
|
|
63
|
+
* onto the compact form; column names follow the pivot.
|
|
64
|
+
* @param options The rank tolerance.
|
|
65
|
+
* @returns The compact factorization, `qraux`, the pivot, and the rank.
|
|
66
|
+
* @throws RangeError If the tolerance is negative or NaN, or if an entry is
|
|
67
|
+
* not finite — R's "NA/NaN/Inf in foreign function call (arg 1)". NaN is
|
|
68
|
+
* this library's missing value; a caller drops incomplete rows first, as
|
|
69
|
+
* `modelMatrix` does.
|
|
70
|
+
* @throws TypeError If `x` is not a matrix.
|
|
71
|
+
*/
|
|
72
|
+
export declare function qr(x: Matrix, options?: QrOptions): QrDecomposition;
|
|
73
|
+
/**
|
|
74
|
+
* Solve for the coefficients, R's `qr.coef(qr, y)`.
|
|
75
|
+
*
|
|
76
|
+
* @param q The factorization.
|
|
77
|
+
* @param y The response, one value per row — or a matrix with one response
|
|
78
|
+
* per column, as R also takes.
|
|
79
|
+
* @returns One coefficient per column of the factored matrix, **in the
|
|
80
|
+
* original column order**, with null for an aliased column (R's `NA`).
|
|
81
|
+
* For a matrix `y`, a matrix with one column per response, the factored
|
|
82
|
+
* matrix's column names as row names and `y`'s column names as column
|
|
83
|
+
* names; an aliased column reads NaN there, since a matrix holds no null.
|
|
84
|
+
* @throws RangeError If `y` has the wrong number of rows.
|
|
85
|
+
*/
|
|
86
|
+
export declare function qrCoef(q: QrDecomposition, y: Vector): (number | null)[];
|
|
87
|
+
export declare function qrCoef(q: QrDecomposition, y: Matrix): Matrix;
|
|
88
|
+
/**
|
|
89
|
+
* The fitted values, R's `qr.fitted(qr, y)`: `Q` applied to the first `rank`
|
|
90
|
+
* entries of `Qᵀy`, the rest set to zero. A matrix `y` gives a matrix with
|
|
91
|
+
* its column names.
|
|
92
|
+
*
|
|
93
|
+
* @throws RangeError If `y` has the wrong number of rows.
|
|
94
|
+
*/
|
|
95
|
+
export declare function qrFitted(q: QrDecomposition, y: Vector): number[];
|
|
96
|
+
export declare function qrFitted(q: QrDecomposition, y: Matrix): Matrix;
|
|
97
|
+
/**
|
|
98
|
+
* The residuals, R's `qr.resid(qr, y)`: `Q` applied to `Qᵀy` with its first
|
|
99
|
+
* `rank` entries set to zero. A matrix `y` gives a matrix with its column
|
|
100
|
+
* names.
|
|
101
|
+
*
|
|
102
|
+
* @throws RangeError If `y` has the wrong number of rows.
|
|
103
|
+
*/
|
|
104
|
+
export declare function qrResid(q: QrDecomposition, y: Vector): number[];
|
|
105
|
+
export declare function qrResid(q: QrDecomposition, y: Matrix): Matrix;
|
|
106
|
+
/**
|
|
107
|
+
* `Qᵀy`, R's `qr.qty(qr, y)`: the reflectors applied first to last. A
|
|
108
|
+
* matrix `y` gives a matrix with its column names.
|
|
109
|
+
*
|
|
110
|
+
* @throws RangeError If `y` has the wrong number of rows.
|
|
111
|
+
*/
|
|
112
|
+
export declare function qrQty(q: QrDecomposition, y: Vector): number[];
|
|
113
|
+
export declare function qrQty(q: QrDecomposition, y: Matrix): Matrix;
|
|
114
|
+
/**
|
|
115
|
+
* `Qy`, R's `qr.qy(qr, y)`: the reflectors applied last to first. A matrix
|
|
116
|
+
* `y` gives a matrix with its column names.
|
|
117
|
+
*
|
|
118
|
+
* @throws RangeError If `y` has the wrong number of rows.
|
|
119
|
+
*/
|
|
120
|
+
export declare function qrQy(q: QrDecomposition, y: Vector): number[];
|
|
121
|
+
export declare function qrQy(q: QrDecomposition, y: Matrix): Matrix;
|
|
122
|
+
/**
|
|
123
|
+
* The orthogonal factor, R's `qr.Q(qr)`: `n` rows by `min(n, p)` columns —
|
|
124
|
+
* `Q` applied to the leading columns of the identity. It carries no names,
|
|
125
|
+
* as R's does not.
|
|
126
|
+
*/
|
|
127
|
+
export declare function qrQ(q: QrDecomposition): Matrix;
|
|
128
|
+
/**
|
|
129
|
+
* The triangular factor, R's `qr.R(qr)`: `min(n, p)` rows by `p` columns,
|
|
130
|
+
* the upper triangle of the compact form, with the leading row names and
|
|
131
|
+
* the column names in pivot order.
|
|
132
|
+
*/
|
|
133
|
+
export declare function qrR(q: QrDecomposition): Matrix;
|
|
134
|
+
//# sourceMappingURL=qr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qr.d.ts","sourceRoot":"","sources":["../../../src/core/linalg/qr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC;AAE5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,yBAAyB;AACzB,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,uDAAuD;AACvD,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAEzC;;;;;;;;;;;;GAYG;AACH,wBAAgB,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,SAAc,GAAG,eAAe,CAgCtE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;AACzE,wBAAgB,MAAM,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;AA0C9D;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;AAClE,wBAAgB,QAAQ,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;AAOhE;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;AACjE,wBAAgB,OAAO,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;AAO/D;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;AAC/D,wBAAgB,KAAK,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;AAK7D;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;AAC9D,wBAAgB,IAAI,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;AA6C5D;;;;GAIG;AACH,wBAAgB,GAAG,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CAU9C;AAED;;;;GAIG;AACH,wBAAgB,GAAG,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CAY9C"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* R's operators over vectors, by name.
|
|
3
|
+
*
|
|
4
|
+
* R vectors are not objects with methods: `a + 1`, `a * b` and `sum(a * b)`
|
|
5
|
+
* are functions over plain vectors, with a scalar recycled to the length of
|
|
6
|
+
* the other argument. This module is those functions with the operator
|
|
7
|
+
* spelled out — `add(a, 1)`, `mul(a, b)`, `dot(a, b)` — over `Vector`,
|
|
8
|
+
* which is `Vector` and nothing more: a bare array is a vector
|
|
9
|
+
* (plan Q11, Q12).
|
|
10
|
+
*
|
|
11
|
+
* R recycles any shorter vector, with a warning when the lengths do not
|
|
12
|
+
* divide. The port recycles a scalar only and refuses every other mismatch:
|
|
13
|
+
* a silent recycle lets a typo fit the wrong model.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* A numeric vector: R's atomic double vector, which here is a plain array of
|
|
17
|
+
* numbers. `NaN` is the missing value, as `NA_real_` is in R.
|
|
18
|
+
*
|
|
19
|
+
* The name is erased at compile time and structural, not nominal. Any
|
|
20
|
+
* `number[]` is a `Vector` and any `Vector` is an array, with nothing to wrap
|
|
21
|
+
* at either end. It names the concept in a signature and carries this note to
|
|
22
|
+
* every place one is taken; it constrains nothing, and in particular it does
|
|
23
|
+
* not check a length.
|
|
24
|
+
*
|
|
25
|
+
* A function *takes* a `Vector` and *returns* a fresh `number[]` — R's
|
|
26
|
+
* copy-on-modify, and the reason there is no mutable counterpart to this
|
|
27
|
+
* name. A vector is never an object with methods (plan Q12).
|
|
28
|
+
*/
|
|
29
|
+
export type Vector = readonly number[];
|
|
30
|
+
/** A vector, or a scalar to recycle to the vector's length. */
|
|
31
|
+
export type VectorOrScalar = Vector | number;
|
|
32
|
+
/** R's `a + b`. */
|
|
33
|
+
export declare function add(a: Vector, b: VectorOrScalar): number[];
|
|
34
|
+
/** R's `a - b`. */
|
|
35
|
+
export declare function sub(a: Vector, b: VectorOrScalar): number[];
|
|
36
|
+
/** R's `a * b`. With a scalar, `2 * a`. */
|
|
37
|
+
export declare function mul(a: Vector, b: VectorOrScalar): number[];
|
|
38
|
+
/** R's `a / b`. */
|
|
39
|
+
export declare function div(a: Vector, b: VectorOrScalar): number[];
|
|
40
|
+
/** R's `a^2`. */
|
|
41
|
+
export declare function square(a: Vector): number[];
|
|
42
|
+
/**
|
|
43
|
+
* R's `sum(a * b)`: the inner product.
|
|
44
|
+
*
|
|
45
|
+
* @throws RangeError If the lengths differ.
|
|
46
|
+
*/
|
|
47
|
+
export declare function dot(a: Vector, b: Vector): number;
|
|
48
|
+
/**
|
|
49
|
+
* R's `sqrt(sum(a^2))`: the Euclidean length.
|
|
50
|
+
*
|
|
51
|
+
* Written as a sum, not `Math.hypot(...a)`: the spread overflows the call
|
|
52
|
+
* stack on a long vector, and the sum is the form R computes, so the two
|
|
53
|
+
* round the same way.
|
|
54
|
+
*/
|
|
55
|
+
export declare function norm(a: Vector): number;
|
|
56
|
+
/**
|
|
57
|
+
* The cosine of the angle between two vectors: `dot(a, b) / (norm(a) * norm(b))`.
|
|
58
|
+
*
|
|
59
|
+
* Computed in exactly that order, which is the order a reader writes it in
|
|
60
|
+
* R, so the port and R land on the same double — including
|
|
61
|
+
* `cosine(a, a) = 1.0000000000000002` for a vector whose norm does not
|
|
62
|
+
* square back to its sum of squares. A zero vector gives NaN, as `0 / 0` does
|
|
63
|
+
* in R.
|
|
64
|
+
*
|
|
65
|
+
* @throws RangeError If the lengths differ.
|
|
66
|
+
*/
|
|
67
|
+
export declare function cosine(a: Vector, b: Vector): number;
|
|
68
|
+
//# sourceMappingURL=vector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector.d.ts","sourceRoot":"","sources":["../../../src/core/linalg/vector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;AAEvC,+DAA+D;AAC/D,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC;AAsB7C,mBAAmB;AACnB,wBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,MAAM,EAAE,CAE1D;AAED,mBAAmB;AACnB,wBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,MAAM,EAAE,CAE1D;AAED,2CAA2C;AAC3C,wBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,MAAM,EAAE,CAE1D;AAED,mBAAmB;AACnB,wBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,cAAc,GAAG,MAAM,EAAE,CAE1D;AAED,iBAAiB;AACjB,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAE1C;AAED;;;;GAIG;AACH,wBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAGhD;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnD"}
|
|
@@ -19,8 +19,11 @@
|
|
|
19
19
|
* **The design follows R's model matrix, not the option order.** R's
|
|
20
20
|
* `model.matrix` puts every main effect before any interaction, whatever
|
|
21
21
|
* order the formula was typed in, so `y ~ x + z + w + x:z` gives the columns
|
|
22
|
-
* `(Intercept), x, z, w, x:z`. This module
|
|
23
|
-
*
|
|
22
|
+
* `(Intercept), x, z, w, x:z`. This module names the terms and hands them to
|
|
23
|
+
* `linalg/lm`, which is `model.matrix()` followed by `lm.fit()` and puts the
|
|
24
|
+
* columns in that order, so a caller can read the coefficients next to R's.
|
|
25
|
+
* Going through `lm` also makes the fitted values `y` minus the residuals of
|
|
26
|
+
* the factorization, which is R's own definition, rather than `X · β`.
|
|
24
27
|
*
|
|
25
28
|
* **Controls are held at their mean, and only numbers are accepted.** R's
|
|
26
29
|
* `hold_value()` also handles factors (first level), characters (first in
|
|
@@ -28,7 +31,7 @@
|
|
|
28
31
|
* column and no doc example uses one, so this port supports the numeric
|
|
29
32
|
* branch alone and refuses the rest, rather than shipping three rules nothing
|
|
30
33
|
* exercises. The other rules are recorded in
|
|
31
|
-
* `.claude/plans/moderation-fixtures.md` section 4 if they are ever wanted.
|
|
34
|
+
* `.claude/plans/001-PLAN-port/moderation-fixtures.md` section 4 if they are ever wanted.
|
|
32
35
|
*
|
|
33
36
|
* **Missing values leave the fit, as R's do.** `lm()` drops incomplete rows
|
|
34
37
|
* through `na.omit` and `hold_value()` averages with `na.rm = TRUE`; this
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"moderation.d.ts","sourceRoot":"","sources":["../../src/core/moderation.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"moderation.d.ts","sourceRoot":"","sources":["../../src/core/moderation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAGH,OAAO,EAAmC,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAS1E,oCAAoC;AACpC,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED,4CAA4C;AAC5C,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,kDAAkD;AAClD,MAAM,WAAW,iBAAiB;IAChC,mDAAmD;IACnD,QAAQ,CAAC,YAAY,EAAE,SAAS,cAAc,EAAE,CAAC;IACjD;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAClD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,iBAAiB,GACzB,iBAAiB,CAyGnB"}
|
package/dist/core/ols.d.ts
CHANGED
|
@@ -5,14 +5,11 @@
|
|
|
5
5
|
* every step of `glm.fit()`'s IRLS loop. R factors the design with `dqrdc2`,
|
|
6
6
|
* a Householder QR with a limited column-pivoting rule: a column whose norm
|
|
7
7
|
* has collapsed against the columns to its left is moved to the right edge
|
|
8
|
-
* and its coefficient is reported as `NA`.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* and its coefficient is reported as `NA`. That factorization lives in
|
|
9
|
+
* `linalg/qr.ts` as R's `qr()`; this module is the `lm.wfit()` wrapper over
|
|
10
|
+
* it — the square-root weighting, the row-array interface the fitting
|
|
11
|
+
* functions use, and the fitted values as `X · β`. Verified against R in
|
|
11
12
|
* `ols.test.ts`.
|
|
12
|
-
*
|
|
13
|
-
* Designs here are tiny — two columns for logit, four for a moderation
|
|
14
|
-
* surface — so the code follows the LINPACK routine plainly rather than
|
|
15
|
-
* blocking or vectorizing it.
|
|
16
13
|
*/
|
|
17
14
|
/**
|
|
18
15
|
* The result of a fit.
|
package/dist/core/ols.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ols.d.ts","sourceRoot":"","sources":["../../src/core/ols.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ols.d.ts","sourceRoot":"","sources":["../../src/core/ols.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAClD,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,uDAAuD;IACvD,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,4CAA4C;AAC5C,eAAO,MAAM,+BAA+B,OAAO,CAAC;AAEpD;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,EACtC,CAAC,EAAE,SAAS,MAAM,EAAE,EACpB,OAAO,GAAE,mBAAwB,GAChC,eAAe,CAyDjB"}
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
* regenerated** — the draw used `set.seed(42)` under R's own generator, so a
|
|
21
21
|
* JavaScript regeneration would produce different numbers and silently change
|
|
22
22
|
* every default demo. Source of the printed values:
|
|
23
|
-
* `.claude/plans/moderation-data.tsv`, checked against the column checksums of
|
|
24
|
-
* `.claude/plans/moderation-fixtures.md` in `moderationData.test.ts`.
|
|
23
|
+
* `.claude/plans/001-PLAN-port/moderation-data.tsv`, checked against the column checksums of
|
|
24
|
+
* `.claude/plans/001-PLAN-port/moderation-fixtures.md` in `moderationData.test.ts`.
|
|
25
25
|
*
|
|
26
26
|
* The columns are in the order of the R data frame — `y, x, z, w`, not
|
|
27
27
|
* alphabetical and not `x, y, z`. That order is load-bearing: `plot_scatter3d()`
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* (`../compstatslib/data/pca_degenerate.rda`), printed at 17 significant
|
|
11
11
|
* digits, which round-trips an IEEE-754 double. **Exported from R, never
|
|
12
12
|
* regenerated** — a JavaScript regeneration would silently change the demo.
|
|
13
|
-
* Source of the printed values: `.claude/plans/pca-fixtures.md`, section F1.
|
|
13
|
+
* Source of the printed values: `.claude/plans/001-PLAN-port/pca-fixtures.md`, section F1.
|
|
14
14
|
*/
|
|
15
15
|
import type { Point } from "../core/regression";
|
|
16
16
|
/** The 16 rows of the R `pca_degenerate` data frame, in file order. */
|