@mark1russell7/strategy-space 0.0.0-stage → 0.0.2
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 +51 -2
- package/build/claim.d.ts +10 -0
- package/build/claim.d.ts.map +1 -0
- package/build/distinct.d.ts +49 -0
- package/build/distinct.d.ts.map +1 -0
- package/build/distinct.js +61 -0
- package/build/distinct.js.map +1 -0
- package/build/index.d.ts +7 -0
- package/build/index.js +6 -0
- package/build/operators.d.ts +55 -0
- package/build/operators.d.ts.map +1 -0
- package/build/operators.js +95 -0
- package/build/operators.js.map +1 -0
- package/build/space-walk.js +48 -0
- package/build/space-walk.js.map +1 -0
- package/build/strategy-options.d.ts +189 -0
- package/build/strategy-options.d.ts.map +1 -0
- package/build/strategy-options.js +211 -0
- package/build/strategy-options.js.map +1 -0
- package/build/strategy-space.d.ts +261 -0
- package/build/strategy-space.d.ts.map +1 -0
- package/build/strategy-space.js +1034 -0
- package/build/strategy-space.js.map +1 -0
- package/build/terms.d.ts +89 -0
- package/build/terms.d.ts.map +1 -0
- package/build/terms.js +256 -0
- package/build/terms.js.map +1 -0
- package/package.json +60 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mark Russell
|
|
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
CHANGED
|
@@ -1,3 +1,52 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @mark1russell7/strategy-space
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Layout strategies as data. A strategy space gives the stages of an engine, the options of each stage and the ranges of their params. The functions of this package check a space and its configs, and give the id of a config. They also count the space and make grids and seeded samples.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { checkSpace, configId, enumerateSpace, spaceSize, type StrategySpace } from "@mark1russell7/strategy-space";
|
|
7
|
+
|
|
8
|
+
const space: StrategySpace = {
|
|
9
|
+
schema: "strategy-space/1",
|
|
10
|
+
engine: "pack",
|
|
11
|
+
version: "0.0.1",
|
|
12
|
+
stages: [
|
|
13
|
+
{ name: "order", options: [{ id: "area", params: [] }, { id: "height", params: [] }] },
|
|
14
|
+
{ name: "placement", options: [{ id: "shelf", params: [{ name: "gap", kind: "int", min: 0, max: 8, default: 2 }] }] },
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
checkSpace(space); // [] : the space is good
|
|
19
|
+
spaceSize(space, { levels: 3 }).base; // 6n : 2 orders, 3 levels of gap
|
|
20
|
+
const configs = enumerateSpace(space, { mode: "sample", n: 4, seed: 7 });
|
|
21
|
+
configId(space, configs[0]!); // the first 16 hex characters of a SHA-256
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## What the package has
|
|
25
|
+
|
|
26
|
+
| Area | Functions |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| The checks | `checkSpace`, `checkConfig`, `paramProblem` |
|
|
29
|
+
| The id of a config | `canonicalConfig`, `configId` |
|
|
30
|
+
| The count | `spaceSize`, `paramLevels`, `spaceShapeKinds` |
|
|
31
|
+
| The configs | `enumerateSpace` (the modes `grid` and `sample`, the draws `uniform` and `walk`, fixed options) |
|
|
32
|
+
| Two spaces as one | `productSpace`, `joinConfigs`, `splitConfig` |
|
|
33
|
+
| The option schema of a strategy | `listOptions`, `optionDefaults`, `checkOptions`, `clampOptions`, `checkSchema` |
|
|
34
|
+
| The sweeps of the options | `sweepValues`, `sweepOf`, `sweepGrid` |
|
|
35
|
+
| The distinctness gate | `distinctness`, `distinctCount` |
|
|
36
|
+
| The operators of a space | `checkOperators`, `countOperators` |
|
|
37
|
+
| The combinators and the count to a depth | `COMBINATORS`, `checkTerm`, `termDepth`, `canonicalTerm`, `countSpace` |
|
|
38
|
+
|
|
39
|
+
[`docs/STRATEGY-SPACE.md`](../../docs/STRATEGY-SPACE.md) tells the schema `strategy-space/1` and the rules of each function. [`docs/DISTINCT.md`](../../docs/DISTINCT.md) tells the gate, and [`docs/OPERATORS.md`](../../docs/OPERATORS.md) tells the operators and the combinators.
|
|
40
|
+
|
|
41
|
+
## Shape kinds
|
|
42
|
+
|
|
43
|
+
An option can give the shape kinds that it supports, as tags. The option `kinds` gives the list of the known tags. Without `kinds`, each string with text is a kind.
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
checkSpace(space, { kinds: ["rect", "circle"] });
|
|
47
|
+
spaceSize(space, { levels: 3, shapes: ["circle"], kinds: ["rect", "circle"] });
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## The same ids as `layout-contract`
|
|
51
|
+
|
|
52
|
+
The schema, the ids and the samples come from `layout-contract` 0.6.1 with no change. A config has the same `configId`, and a seed gives the same sample. The hash and the random numbers come from `@mark1russell7/rigor-generators`.
|
package/build/claim.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** One broken claim, with the ids of the inputs that break it. `layout-contract` uses the same form for the checks of a corpus. */
|
|
2
|
+
export interface ClaimBreak {
|
|
3
|
+
/** The name of the claim, for example `schema`, `unknown`, `shape` or `members`. */
|
|
4
|
+
readonly claim: string;
|
|
5
|
+
/** The text of the break. */
|
|
6
|
+
readonly detail: string;
|
|
7
|
+
/** The ids of the inputs that break the claim. The list is empty when the break has no input. */
|
|
8
|
+
readonly inputs: readonly string[];
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=claim.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claim.d.ts","names":[],"sources":["../src/claim.ts"],"mappings":";iBAGiB;;WAEN;;WAEA;;WAEA"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** The hashes of the outputs of one strategy: one hash for each input, by the id of the input. `probeHash` of `layout-contract` gives one hash. */
|
|
2
|
+
export interface OutputHashes {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly stage: string;
|
|
5
|
+
readonly outputs: Readonly<Record<string, string>>;
|
|
6
|
+
}
|
|
7
|
+
/** The options of the gate. */
|
|
8
|
+
export interface DistinctOptions {
|
|
9
|
+
/** The ids of the inputs of the set. Each variant needs a hash on each of them. */
|
|
10
|
+
readonly inputs: readonly string[];
|
|
11
|
+
/** The hash that a strategy gives for an input that it refuses, for example `REFUSED_PROBE` of `layout-contract`. A refused input is not a difference. */
|
|
12
|
+
readonly refused?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The verdict of the gate on one variant.
|
|
16
|
+
* `distinct`: on at least one input, its output differs from the output of each operator of its stage.
|
|
17
|
+
* `same`: an operator of its stage has the same hash on each input of the set.
|
|
18
|
+
* `no-read`: the gate cannot decide. An input has no hash, or no input shows a difference from an operator that is not the same.
|
|
19
|
+
*/
|
|
20
|
+
export type DistinctVerdict = "distinct" | "same" | "no-read";
|
|
21
|
+
/** The row of the gate for one variant. */
|
|
22
|
+
export interface DistinctRow {
|
|
23
|
+
readonly id: string;
|
|
24
|
+
readonly stage: string;
|
|
25
|
+
readonly verdict: DistinctVerdict;
|
|
26
|
+
/** The first id of the variants with the same hash on each input. A variant with a different id is a duplicate of it. */
|
|
27
|
+
readonly canonical: string;
|
|
28
|
+
/** The operators with the same hash on each input. */
|
|
29
|
+
readonly sameAs: readonly string[];
|
|
30
|
+
/** The operators with no difference on a compared input, and no equal hash on each input. */
|
|
31
|
+
readonly undecided: readonly string[];
|
|
32
|
+
/** The inputs of the set with no hash for this variant. */
|
|
33
|
+
readonly missing: readonly string[];
|
|
34
|
+
/** The first input where the outputs differ from each operator, by the id of the operator. */
|
|
35
|
+
readonly differsOn: Readonly<Record<string, string>>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* This function gives the verdict of the gate on each variant, sorted by id.
|
|
39
|
+
* It compares a variant only with the operators of its stage. A stage with no operator gives `distinct` to each complete variant.
|
|
40
|
+
*
|
|
41
|
+
* @param operators - The hashes of the existing operators.
|
|
42
|
+
* @param variants - The hashes of the variants that the gate examines.
|
|
43
|
+
* @param options - The inputs of the set and the refused hash.
|
|
44
|
+
* @throws Error when an id is in the operators or in the variants more than once, or when the set has no input.
|
|
45
|
+
*/
|
|
46
|
+
export declare function distinctness(operators: readonly OutputHashes[], variants: readonly OutputHashes[], options: DistinctOptions): DistinctRow[];
|
|
47
|
+
/** This function gives the count of the distinct variants: the canonical variants with the verdict `distinct`. A duplicate does not count. */
|
|
48
|
+
export declare function distinctCount(rows: readonly DistinctRow[]): number;
|
|
49
|
+
//# sourceMappingURL=distinct.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"distinct.d.ts","names":[],"sources":["../src/distinct.ts"],"mappings":";iBAIiB;WACN;WACA;WACA,SAAS,SAAS;;;iBAIZ;;WAEN;;WAEA;;;;;;;;YASC;;iBAGK;WACN;WACA;WACA,SAAS;;WAET;;WAEA;;WAEA;;WAEA;;WAEA,WAAW,SAAS;;;;;;;;;;;wBAuBf,aAAa,oBAAoB,gBAAgB,mBAAmB,gBAAgB,SAAS,kBAAkB;;wBAiC/G,cAAc,eAAe"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// src/distinct.ts
|
|
2
|
+
/** This function gives the key of the hashes of a strategy on the inputs, in the order of the inputs. */
|
|
3
|
+
function vectorKey(s, inputs) {
|
|
4
|
+
return JSON.stringify(inputs.map((b) => s.outputs[b] ?? null));
|
|
5
|
+
}
|
|
6
|
+
/** This function gives the ids that are in the list more than once. */
|
|
7
|
+
function repeated(ids) {
|
|
8
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9
|
+
return [...new Set(ids.filter((id) => seen.has(id) || !seen.add(id)))];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* This function gives the verdict of the gate on each variant, sorted by id.
|
|
13
|
+
* It compares a variant only with the operators of its stage. A stage with no operator gives `distinct` to each complete variant.
|
|
14
|
+
*
|
|
15
|
+
* @param operators - The hashes of the existing operators.
|
|
16
|
+
* @param variants - The hashes of the variants that the gate examines.
|
|
17
|
+
* @param options - The inputs of the set and the refused hash.
|
|
18
|
+
* @throws Error when an id is in the operators or in the variants more than once, or when the set has no input.
|
|
19
|
+
*/
|
|
20
|
+
function distinctness(operators, variants, options) {
|
|
21
|
+
const { inputs, refused } = options;
|
|
22
|
+
if (inputs.length === 0) throw new Error("The gate has no input.");
|
|
23
|
+
const twice = repeated([...operators.map((o) => o.id), ...variants.map((v) => v.id)]);
|
|
24
|
+
if (twice.length > 0) throw new Error(`These ids are not unique: ${twice.join(", ")}.`);
|
|
25
|
+
const canonical = /* @__PURE__ */ new Map();
|
|
26
|
+
for (const v of [...variants].sort((a, b) => a.id < b.id ? -1 : 1)) {
|
|
27
|
+
const key = `${v.stage}\u0000${vectorKey(v, inputs)}`;
|
|
28
|
+
if (!canonical.has(key)) canonical.set(key, v.id);
|
|
29
|
+
}
|
|
30
|
+
const compared = (a, b) => a !== void 0 && b !== void 0 && a !== refused && b !== refused;
|
|
31
|
+
return [...variants].sort((a, b) => a.id < b.id ? -1 : 1).map((v) => {
|
|
32
|
+
const missing = inputs.filter((b) => v.outputs[b] === void 0);
|
|
33
|
+
const sameAs = [];
|
|
34
|
+
const undecided = [];
|
|
35
|
+
const differsOn = {};
|
|
36
|
+
for (const op of operators.filter((o) => o.stage === v.stage).sort((a, b) => a.id < b.id ? -1 : 1)) {
|
|
37
|
+
const input = inputs.find((b) => compared(v.outputs[b], op.outputs[b]) && v.outputs[b] !== op.outputs[b]);
|
|
38
|
+
if (input !== void 0) differsOn[op.id] = input;
|
|
39
|
+
else if (missing.length === 0 && inputs.every((b) => op.outputs[b] === v.outputs[b])) sameAs.push(op.id);
|
|
40
|
+
else undecided.push(op.id);
|
|
41
|
+
}
|
|
42
|
+
const verdict = missing.length > 0 ? "no-read" : sameAs.length > 0 ? "same" : undecided.length > 0 ? "no-read" : "distinct";
|
|
43
|
+
return {
|
|
44
|
+
id: v.id,
|
|
45
|
+
stage: v.stage,
|
|
46
|
+
verdict,
|
|
47
|
+
canonical: canonical.get(`${v.stage}\u0000${vectorKey(v, inputs)}`),
|
|
48
|
+
sameAs,
|
|
49
|
+
undecided,
|
|
50
|
+
missing,
|
|
51
|
+
differsOn
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/** This function gives the count of the distinct variants: the canonical variants with the verdict `distinct`. A duplicate does not count. */
|
|
56
|
+
function distinctCount(rows) {
|
|
57
|
+
return rows.filter((r) => r.verdict === "distinct" && r.canonical === r.id).length;
|
|
58
|
+
}
|
|
59
|
+
export { distinctCount, distinctness };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=distinct.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"distinct.js","names":[],"sources":["../src/distinct.ts"],"sourcesContent":["// The distinctness gate (`docs/DISTINCT.md`). A variant counts only when its output differs from each operator of its stage on at least one input.\n// The caller gives the hash of the output of each strategy on each input of a fixed set. The gate came from `highways` 27b40c8.\n\n/** The hashes of the outputs of one strategy: one hash for each input, by the id of the input. `probeHash` of `layout-contract` gives one hash. */\nexport interface OutputHashes {\n readonly id: string;\n readonly stage: string;\n readonly outputs: Readonly<Record<string, string>>;\n}\n\n/** The options of the gate. */\nexport interface DistinctOptions {\n /** The ids of the inputs of the set. Each variant needs a hash on each of them. */\n readonly inputs: readonly string[];\n /** The hash that a strategy gives for an input that it refuses, for example `REFUSED_PROBE` of `layout-contract`. A refused input is not a difference. */\n readonly refused?: string;\n}\n\n/**\n * The verdict of the gate on one variant.\n * `distinct`: on at least one input, its output differs from the output of each operator of its stage.\n * `same`: an operator of its stage has the same hash on each input of the set.\n * `no-read`: the gate cannot decide. An input has no hash, or no input shows a difference from an operator that is not the same.\n */\nexport type DistinctVerdict = \"distinct\" | \"same\" | \"no-read\";\n\n/** The row of the gate for one variant. */\nexport interface DistinctRow {\n readonly id: string;\n readonly stage: string;\n readonly verdict: DistinctVerdict;\n /** The first id of the variants with the same hash on each input. A variant with a different id is a duplicate of it. */\n readonly canonical: string;\n /** The operators with the same hash on each input. */\n readonly sameAs: readonly string[];\n /** The operators with no difference on a compared input, and no equal hash on each input. */\n readonly undecided: readonly string[];\n /** The inputs of the set with no hash for this variant. */\n readonly missing: readonly string[];\n /** The first input where the outputs differ from each operator, by the id of the operator. */\n readonly differsOn: Readonly<Record<string, string>>;\n}\n\n/** This function gives the key of the hashes of a strategy on the inputs, in the order of the inputs. */\nfunction vectorKey(s: OutputHashes, inputs: readonly string[]): string {\n return JSON.stringify(inputs.map((b) => s.outputs[b] ?? null));\n}\n\n/** This function gives the ids that are in the list more than once. */\nfunction repeated(ids: readonly string[]): string[] {\n const seen = new Set<string>();\n return [...new Set(ids.filter((id) => seen.has(id) || !seen.add(id)))];\n}\n\n/**\n * This function gives the verdict of the gate on each variant, sorted by id.\n * It compares a variant only with the operators of its stage. A stage with no operator gives `distinct` to each complete variant.\n *\n * @param operators - The hashes of the existing operators.\n * @param variants - The hashes of the variants that the gate examines.\n * @param options - The inputs of the set and the refused hash.\n * @throws Error when an id is in the operators or in the variants more than once, or when the set has no input.\n */\nexport function distinctness(operators: readonly OutputHashes[], variants: readonly OutputHashes[], options: DistinctOptions): DistinctRow[] {\n const { inputs, refused } = options;\n if (inputs.length === 0) throw new Error(\"The gate has no input.\");\n const twice = repeated([...operators.map((o) => o.id), ...variants.map((v) => v.id)]);\n if (twice.length > 0) throw new Error(`These ids are not unique: ${twice.join(\", \")}.`);\n\n // The first id of each class of variants with the same hashes.\n const canonical = new Map<string, string>();\n for (const v of [...variants].sort((a, b) => (a.id < b.id ? -1 : 1))) {\n const key = `${v.stage}\\u0000${vectorKey(v, inputs)}`;\n if (!canonical.has(key)) canonical.set(key, v.id);\n }\n\n const compared = (a: string | undefined, b: string | undefined): boolean => a !== undefined && b !== undefined && a !== refused && b !== refused;\n return [...variants]\n .sort((a, b) => (a.id < b.id ? -1 : 1))\n .map((v) => {\n const missing = inputs.filter((b) => v.outputs[b] === undefined);\n const sameAs: string[] = [];\n const undecided: string[] = [];\n const differsOn: Record<string, string> = {};\n for (const op of operators.filter((o) => o.stage === v.stage).sort((a, b) => (a.id < b.id ? -1 : 1))) {\n const input = inputs.find((b) => compared(v.outputs[b], op.outputs[b]) && v.outputs[b] !== op.outputs[b]);\n if (input !== undefined) differsOn[op.id] = input;\n else if (missing.length === 0 && inputs.every((b) => op.outputs[b] === v.outputs[b])) sameAs.push(op.id);\n else undecided.push(op.id);\n }\n const verdict: DistinctVerdict = missing.length > 0 ? \"no-read\" : sameAs.length > 0 ? \"same\" : undecided.length > 0 ? \"no-read\" : \"distinct\";\n return { id: v.id, stage: v.stage, verdict, canonical: canonical.get(`${v.stage}\\u0000${vectorKey(v, inputs)}`)!, sameAs, undecided, missing, differsOn };\n });\n}\n\n/** This function gives the count of the distinct variants: the canonical variants with the verdict `distinct`. A duplicate does not count. */\nexport function distinctCount(rows: readonly DistinctRow[]): number {\n return rows.filter((r) => r.verdict === \"distinct\" && r.canonical === r.id).length;\n}\n"],"mappings":";;AA4CA,SAAS,UAAU,GAAiB,QAAmC;CACrE,OAAO,KAAK,UAAU,OAAO,KAAK,MAAM,EAAE,QAAQ,MAAM,IAAI,CAAC;AAC/D;;AAGA,SAAS,SAAS,KAAkC;CAClD,MAAM,uBAAO,IAAI,IAAY;CAC7B,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,QAAQ,OAAO,KAAK,IAAI,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;AACvE;;;;;;;;;;AAWA,SAAgB,aAAa,WAAoC,UAAmC,SAAyC;CAC3I,MAAM,EAAE,QAAQ,YAAY;CAC5B,IAAI,OAAO,WAAW,GAAG,MAAM,IAAI,MAAM,wBAAwB;CACjE,MAAM,QAAQ,SAAS,CAAC,GAAG,UAAU,KAAK,MAAM,EAAE,EAAE,GAAG,GAAG,SAAS,KAAK,MAAM,EAAE,EAAE,CAAC,CAAC;CACpF,IAAI,MAAM,SAAS,GAAG,MAAM,IAAI,MAAM,6BAA6B,MAAM,KAAK,IAAI,EAAE,EAAE;CAGtF,MAAM,4BAAY,IAAI,IAAoB;CAC1C,KAAK,MAAM,KAAK,CAAC,GAAG,QAAQ,CAAC,CAAC,MAAM,GAAG,MAAO,EAAE,KAAK,EAAE,KAAK,KAAK,CAAE,GAAG;EACpE,MAAM,MAAM,GAAG,EAAE,MAAM,QAAQ,UAAU,GAAG,MAAM;EAClD,IAAI,CAAC,UAAU,IAAI,GAAG,GAAG,UAAU,IAAI,KAAK,EAAE,EAAE;CAClD;CAEA,MAAM,YAAY,GAAuB,MAAmC,MAAM,KAAA,KAAa,MAAM,KAAA,KAAa,MAAM,WAAW,MAAM;CACzI,OAAO,CAAC,GAAG,QAAQ,CAAC,CACjB,MAAM,GAAG,MAAO,EAAE,KAAK,EAAE,KAAK,KAAK,CAAE,CAAC,CACtC,KAAK,MAAM;EACV,MAAM,UAAU,OAAO,QAAQ,MAAM,EAAE,QAAQ,OAAO,KAAA,CAAS;EAC/D,MAAM,SAAmB,CAAC;EAC1B,MAAM,YAAsB,CAAC;EAC7B,MAAM,YAAoC,CAAC;EAC3C,KAAK,MAAM,MAAM,UAAU,QAAQ,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,MAAM,GAAG,MAAO,EAAE,KAAK,EAAE,KAAK,KAAK,CAAE,GAAG;GACpG,MAAM,QAAQ,OAAO,MAAM,MAAM,SAAS,EAAE,QAAQ,IAAI,GAAG,QAAQ,EAAE,KAAK,EAAE,QAAQ,OAAO,GAAG,QAAQ,EAAE;GACxG,IAAI,UAAU,KAAA,GAAW,UAAU,GAAG,MAAM;QACvC,IAAI,QAAQ,WAAW,KAAK,OAAO,OAAO,MAAM,GAAG,QAAQ,OAAO,EAAE,QAAQ,EAAE,GAAG,OAAO,KAAK,GAAG,EAAE;QAClG,UAAU,KAAK,GAAG,EAAE;EAC3B;EACA,MAAM,UAA2B,QAAQ,SAAS,IAAI,YAAY,OAAO,SAAS,IAAI,SAAS,UAAU,SAAS,IAAI,YAAY;EAClI,OAAO;GAAE,IAAI,EAAE;GAAI,OAAO,EAAE;GAAO;GAAS,WAAW,UAAU,IAAI,GAAG,EAAE,MAAM,QAAQ,UAAU,GAAG,MAAM,GAAG;GAAI;GAAQ;GAAW;GAAS;EAAU;CAC1J,CAAC;AACL;;AAGA,SAAgB,cAAc,MAAsC;CAClE,OAAO,KAAK,QAAQ,MAAM,EAAE,YAAY,cAAc,EAAE,cAAc,EAAE,EAAE,CAAC,CAAC;AAC9E"}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ClaimBreak } from "./claim.js";
|
|
2
|
+
import { DistinctOptions, DistinctRow, DistinctVerdict, OutputHashes, distinctCount, distinctness } from "./distinct.js";
|
|
3
|
+
import { OPERATOR_SCHEMA, OPERATOR_SOURCES, Operator, OperatorCount, OperatorSet, OperatorSource, checkOperators, countOperators, needsOperator } from "./operators.js";
|
|
4
|
+
import { AnyOption, BooleanOption, DeclaredStrategy, EnumOption, ListItem, NoDefault, NoDefaultReason, NumberOption, OptionDeclaration, OptionIssue, OptionScale, OptionSchema, OptionSetting, SweepOptions, ValueOption, checkOptions, checkSchema, clampOptions, declarationIssues, listOptions, optionDefaults, optionIssue, sweepGrid, sweepOf, sweepValues } from "./strategy-options.js";
|
|
5
|
+
import { EnumerateOptions, GridOptions, KindOptions, MemberRule, OptionRef, OptionSupports, ParamKind, ParamValue, ParamWhen, STRATEGY_SPACE_SCHEMA, SampleOptions, ShapeFilter, SpaceConstraint, SpaceParam, SpaceSize, SpaceSizeOptions, SpaceStage, StageChoice, StageOption, StrategyConfig, StrategySpace, canonicalConfig, checkConfig, checkSpace, configId, enumerateSpace, joinConfigs, paramActive, paramLevels, paramProblem, paramValue, productSpace, spaceShapeKinds, spaceSize, splitConfig } from "./strategy-space.js";
|
|
6
|
+
import { BUDGET_KEYS, COMBINATORS, Combinator, CountOptions, StrategyTerm, TermCount, canonicalTerm, checkCombinators, checkTerm, countSpace, dispatchIndex, termDepth } from "./terms.js";
|
|
7
|
+
export { AnyOption, BUDGET_KEYS, BooleanOption, COMBINATORS, type ClaimBreak, Combinator, CountOptions, DeclaredStrategy, DistinctOptions, DistinctRow, DistinctVerdict, EnumOption, EnumerateOptions, GridOptions, KindOptions, ListItem, MemberRule, NoDefault, NoDefaultReason, NumberOption, OPERATOR_SCHEMA, OPERATOR_SOURCES, Operator, OperatorCount, OperatorSet, OperatorSource, OptionDeclaration, OptionIssue, OptionRef, OptionScale, OptionSchema, OptionSetting, OptionSupports, OutputHashes, ParamKind, ParamValue, ParamWhen, STRATEGY_SPACE_SCHEMA, SampleOptions, ShapeFilter, SpaceConstraint, SpaceParam, SpaceSize, SpaceSizeOptions, SpaceStage, StageChoice, StageOption, StrategyConfig, StrategySpace, StrategyTerm, SweepOptions, TermCount, ValueOption, canonicalConfig, canonicalTerm, checkCombinators, checkConfig, checkOperators, checkOptions, checkSchema, checkSpace, checkTerm, clampOptions, configId, countOperators, countSpace, declarationIssues, dispatchIndex, distinctCount, distinctness, enumerateSpace, joinConfigs, listOptions, needsOperator, optionDefaults, optionIssue, paramActive, paramLevels, paramProblem, paramValue, productSpace, spaceShapeKinds, spaceSize, splitConfig, sweepGrid, sweepOf, sweepValues, termDepth };
|
package/build/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { distinctCount, distinctness } from "./distinct.js";
|
|
2
|
+
import { OPERATOR_SCHEMA, OPERATOR_SOURCES, checkOperators, countOperators, needsOperator } from "./operators.js";
|
|
3
|
+
import { checkOptions, checkSchema, clampOptions, declarationIssues, listOptions, optionDefaults, optionIssue, sweepGrid, sweepOf, sweepValues } from "./strategy-options.js";
|
|
4
|
+
import { STRATEGY_SPACE_SCHEMA, canonicalConfig, checkConfig, checkSpace, configId, enumerateSpace, joinConfigs, paramActive, paramLevels, paramProblem, paramValue, productSpace, spaceShapeKinds, spaceSize, splitConfig } from "./strategy-space.js";
|
|
5
|
+
import { BUDGET_KEYS, COMBINATORS, canonicalTerm, checkCombinators, checkTerm, countSpace, dispatchIndex, termDepth } from "./terms.js";
|
|
6
|
+
export { BUDGET_KEYS, COMBINATORS, OPERATOR_SCHEMA, OPERATOR_SOURCES, STRATEGY_SPACE_SCHEMA, canonicalConfig, canonicalTerm, checkCombinators, checkConfig, checkOperators, checkOptions, checkSchema, checkSpace, checkTerm, clampOptions, configId, countOperators, countSpace, declarationIssues, dispatchIndex, distinctCount, distinctness, enumerateSpace, joinConfigs, listOptions, needsOperator, optionDefaults, optionIssue, paramActive, paramLevels, paramProblem, paramValue, productSpace, spaceShapeKinds, spaceSize, splitConfig, sweepGrid, sweepOf, sweepValues, termDepth };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { ClaimBreak } from "./claim.js";
|
|
2
|
+
import { StageOption, StrategySpace } from "./strategy-space.js";
|
|
3
|
+
/** The schema of a set of operators. */
|
|
4
|
+
export declare const OPERATOR_SCHEMA = "strategy-operators/1";
|
|
5
|
+
/** The sources of an operator: a method from a paper or a book, a method of this project, or a change of a parent operator. */
|
|
6
|
+
export declare const OPERATOR_SOURCES: readonly ["literature", "ours", "mutation"];
|
|
7
|
+
/** The source of an operator. */
|
|
8
|
+
export type OperatorSource = (typeof OPERATOR_SOURCES)[number];
|
|
9
|
+
/** The declaration of one operator: one mechanism at one stage of a space. A param value of an option is not an operator. */
|
|
10
|
+
export interface Operator {
|
|
11
|
+
/** The id of the option of the stage that this operator is. */
|
|
12
|
+
readonly id: string;
|
|
13
|
+
/** The name of the stage of the operator. */
|
|
14
|
+
readonly stage: string;
|
|
15
|
+
readonly source: OperatorSource;
|
|
16
|
+
/** The id of the operator of the same stage that this operator changes. A `mutation` has a parent. The other sources can have one. */
|
|
17
|
+
readonly parent?: string;
|
|
18
|
+
/** The reference of a `literature` operator, for example the authors, the year and the title. */
|
|
19
|
+
readonly cite?: string;
|
|
20
|
+
/** The path of the test file or the test folder of the operator, from the root of its repository, or a list of these paths. */
|
|
21
|
+
readonly test: string | readonly string[];
|
|
22
|
+
/** The text that tells the mechanism of the operator. */
|
|
23
|
+
readonly summary: string;
|
|
24
|
+
}
|
|
25
|
+
/** The operators of one space. */
|
|
26
|
+
export interface OperatorSet {
|
|
27
|
+
readonly schema: typeof OPERATOR_SCHEMA;
|
|
28
|
+
/** The `engine` of the space. */
|
|
29
|
+
readonly engine: string;
|
|
30
|
+
readonly operators: readonly Operator[];
|
|
31
|
+
}
|
|
32
|
+
/** The count of the operators of a set, by stage and by source. */
|
|
33
|
+
export interface OperatorCount {
|
|
34
|
+
readonly total: number;
|
|
35
|
+
readonly byStage: Readonly<Record<string, number>>;
|
|
36
|
+
readonly bySource: Readonly<Record<OperatorSource, number>>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* This function gives the breaks of a set of operators against its space. An empty list tells that the set is good.
|
|
40
|
+
* The claims are `schema`, `engine`, `unknown`, `duplicate`, `source`, `parent`, `cycle`, `cite`, `test`, `summary`, `undeclared` and `not-operator`.
|
|
41
|
+
* An option that `needsOperator` accepts and that has no operator gives the claim `undeclared`. An operator of another option gives `not-operator`.
|
|
42
|
+
* The `inputs` of each break have the stage and the id.
|
|
43
|
+
*/
|
|
44
|
+
/**
|
|
45
|
+
* This function tells if an option is its own mechanism, so it needs an operator. An identity option needs none.
|
|
46
|
+
* A meta option with `chooses: true` needs none. A meta option that changes the output of its members needs one.
|
|
47
|
+
*/
|
|
48
|
+
export declare function needsOperator(option: StageOption): boolean;
|
|
49
|
+
export declare function checkOperators(space: StrategySpace, set: OperatorSet): ClaimBreak[];
|
|
50
|
+
/**
|
|
51
|
+
* This function gives the count of the operators of a set, by stage and by source. It counts each operator of the set.
|
|
52
|
+
* `checkOperators` refuses an operator of an option that `needsOperator` refuses. So a good set counts only the mechanisms.
|
|
53
|
+
*/
|
|
54
|
+
export declare function countOperators(set: OperatorSet): OperatorCount;
|
|
55
|
+
//# sourceMappingURL=operators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operators.d.ts","names":[],"sources":["../src/operators.ts"],"mappings":";;;qBAKa;;qBAGA;;YAGD,yBAAyB;;iBAGpB;;WAEN;;WAEA;WACA,QAAQ;;WAER;;WAEA;;WAEA;;WAEA;;;iBAIM;WACN,eAAe;;WAEf;WACA,oBAAoB;;;iBAId;WACN;WACA,SAAS,SAAS;WAClB,UAAU,SAAS,OAAO;;;;;;;;;;;;wBAerB,cAAc,QAAQ;wBAKtB,eAAe,OAAO,eAAe,KAAK,cAAc;;;;;wBAmDxD,eAAe,KAAK,cAAc"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// src/operators.ts
|
|
2
|
+
/** The schema of a set of operators. */
|
|
3
|
+
const OPERATOR_SCHEMA = "strategy-operators/1";
|
|
4
|
+
/** The sources of an operator: a method from a paper or a book, a method of this project, or a change of a parent operator. */
|
|
5
|
+
const OPERATOR_SOURCES = [
|
|
6
|
+
"literature",
|
|
7
|
+
"ours",
|
|
8
|
+
"mutation"
|
|
9
|
+
];
|
|
10
|
+
const isText = (value) => typeof value === "string" && value.trim() !== "";
|
|
11
|
+
/**
|
|
12
|
+
* This function gives the breaks of a set of operators against its space. An empty list tells that the set is good.
|
|
13
|
+
* The claims are `schema`, `engine`, `unknown`, `duplicate`, `source`, `parent`, `cycle`, `cite`, `test`, `summary`, `undeclared` and `not-operator`.
|
|
14
|
+
* An option that `needsOperator` accepts and that has no operator gives the claim `undeclared`. An operator of another option gives `not-operator`.
|
|
15
|
+
* The `inputs` of each break have the stage and the id.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* This function tells if an option is its own mechanism, so it needs an operator. An identity option needs none.
|
|
19
|
+
* A meta option with `chooses: true` needs none. A meta option that changes the output of its members needs one.
|
|
20
|
+
*/
|
|
21
|
+
function needsOperator(option) {
|
|
22
|
+
if (option.identity === true) return false;
|
|
23
|
+
return option.members?.chooses !== true;
|
|
24
|
+
}
|
|
25
|
+
function checkOperators(space, set) {
|
|
26
|
+
const out = [];
|
|
27
|
+
const add = (claim, detail, inputs = []) => {
|
|
28
|
+
out.push({
|
|
29
|
+
claim,
|
|
30
|
+
detail,
|
|
31
|
+
inputs
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
if (set.schema !== "strategy-operators/1") add("schema", `the schema is ${JSON.stringify(set.schema)}, not ${OPERATOR_SCHEMA}`);
|
|
35
|
+
if (set.engine !== space.engine) add("engine", `the set is for the engine ${JSON.stringify(set.engine)}, not ${space.engine}`);
|
|
36
|
+
const seen = /* @__PURE__ */ new Map();
|
|
37
|
+
for (const o of set.operators) {
|
|
38
|
+
const key = `${o.stage}.${o.id}`;
|
|
39
|
+
const stage = space.stages.find((s) => s.name === o.stage);
|
|
40
|
+
const option = stage?.options.find((x) => x.id === o.id);
|
|
41
|
+
if (stage === void 0) add("unknown", `the operator ${key} names the unknown stage ${o.stage}`, [key]);
|
|
42
|
+
else if (option === void 0) add("unknown", `the operator ${key} is not an option of the stage ${o.stage}`, [key]);
|
|
43
|
+
else if (!needsOperator(option)) add("not-operator", `the option ${key} is an identity option or only chooses a member, so it is not an operator`, [key]);
|
|
44
|
+
if (seen.has(key)) add("duplicate", `the set has the operator ${key} two times`, [key]);
|
|
45
|
+
else seen.set(key, o);
|
|
46
|
+
if (!OPERATOR_SOURCES.includes(o.source)) add("source", `the operator ${key} has the source ${JSON.stringify(o.source)}, not one of ${OPERATOR_SOURCES.join(", ")}`, [key]);
|
|
47
|
+
if (o.source === "mutation" && o.parent === void 0) add("parent", `the mutation ${key} has no parent`, [key]);
|
|
48
|
+
if (o.source === "literature" && !isText(o.cite)) add("cite", `the literature operator ${key} has no cite`, [key]);
|
|
49
|
+
const tests = Array.isArray(o.test) ? o.test : [o.test];
|
|
50
|
+
if (tests.length === 0 || !tests.every(isText)) add("test", `the operator ${key} has no test file or test folder`, [key]);
|
|
51
|
+
if (!isText(o.summary)) add("summary", `the operator ${key} has no summary`, [key]);
|
|
52
|
+
}
|
|
53
|
+
for (const o of seen.values()) {
|
|
54
|
+
if (o.parent === void 0) continue;
|
|
55
|
+
const key = `${o.stage}.${o.id}`;
|
|
56
|
+
if (!seen.has(`${o.stage}.${o.parent}`)) {
|
|
57
|
+
add("parent", `the parent ${o.parent} of the operator ${key} is not an operator of the stage ${o.stage}`, [key]);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const path = /* @__PURE__ */ new Set([o.id]);
|
|
61
|
+
for (let p = seen.get(`${o.stage}.${o.parent}`); p?.parent !== void 0; p = seen.get(`${o.stage}.${p.parent}`)) {
|
|
62
|
+
if (path.has(p.id)) {
|
|
63
|
+
add("cycle", `the parents of the operator ${key} make a cycle`, [key]);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
path.add(p.id);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
for (const s of space.stages) for (const option of s.options) if (needsOperator(option) && !seen.has(`${s.name}.${option.id}`)) add("undeclared", `the option ${s.name}.${option.id} has no operator`, [`${s.name}.${option.id}`]);
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* This function gives the count of the operators of a set, by stage and by source. It counts each operator of the set.
|
|
74
|
+
* `checkOperators` refuses an operator of an option that `needsOperator` refuses. So a good set counts only the mechanisms.
|
|
75
|
+
*/
|
|
76
|
+
function countOperators(set) {
|
|
77
|
+
const byStage = {};
|
|
78
|
+
const bySource = {
|
|
79
|
+
literature: 0,
|
|
80
|
+
ours: 0,
|
|
81
|
+
mutation: 0
|
|
82
|
+
};
|
|
83
|
+
for (const o of set.operators) {
|
|
84
|
+
byStage[o.stage] = (byStage[o.stage] ?? 0) + 1;
|
|
85
|
+
bySource[o.source] += 1;
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
total: set.operators.length,
|
|
89
|
+
byStage,
|
|
90
|
+
bySource
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export { OPERATOR_SCHEMA, OPERATOR_SOURCES, checkOperators, countOperators, needsOperator };
|
|
94
|
+
|
|
95
|
+
//# sourceMappingURL=operators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operators.js","names":[],"sources":["../src/operators.ts"],"sourcesContent":["// The operators of a strategy space (`docs/OPERATORS.md`): the declaration of each mechanism at one stage, with its source and its parent.\nimport type { ClaimBreak } from \"./claim.ts\";\nimport type { StageOption, StrategySpace } from \"./strategy-space.ts\";\n\n/** The schema of a set of operators. */\nexport const OPERATOR_SCHEMA = \"strategy-operators/1\";\n\n/** The sources of an operator: a method from a paper or a book, a method of this project, or a change of a parent operator. */\nexport const OPERATOR_SOURCES = [\"literature\", \"ours\", \"mutation\"] as const;\n\n/** The source of an operator. */\nexport type OperatorSource = (typeof OPERATOR_SOURCES)[number];\n\n/** The declaration of one operator: one mechanism at one stage of a space. A param value of an option is not an operator. */\nexport interface Operator {\n /** The id of the option of the stage that this operator is. */\n readonly id: string;\n /** The name of the stage of the operator. */\n readonly stage: string;\n readonly source: OperatorSource;\n /** The id of the operator of the same stage that this operator changes. A `mutation` has a parent. The other sources can have one. */\n readonly parent?: string;\n /** The reference of a `literature` operator, for example the authors, the year and the title. */\n readonly cite?: string;\n /** The path of the test file or the test folder of the operator, from the root of its repository, or a list of these paths. */\n readonly test: string | readonly string[];\n /** The text that tells the mechanism of the operator. */\n readonly summary: string;\n}\n\n/** The operators of one space. */\nexport interface OperatorSet {\n readonly schema: typeof OPERATOR_SCHEMA;\n /** The `engine` of the space. */\n readonly engine: string;\n readonly operators: readonly Operator[];\n}\n\n/** The count of the operators of a set, by stage and by source. */\nexport interface OperatorCount {\n readonly total: number;\n readonly byStage: Readonly<Record<string, number>>;\n readonly bySource: Readonly<Record<OperatorSource, number>>;\n}\n\nconst isText = (value: unknown): value is string => typeof value === \"string\" && value.trim() !== \"\";\n\n/**\n * This function gives the breaks of a set of operators against its space. An empty list tells that the set is good.\n * The claims are `schema`, `engine`, `unknown`, `duplicate`, `source`, `parent`, `cycle`, `cite`, `test`, `summary`, `undeclared` and `not-operator`.\n * An option that `needsOperator` accepts and that has no operator gives the claim `undeclared`. An operator of another option gives `not-operator`.\n * The `inputs` of each break have the stage and the id.\n */\n/**\n * This function tells if an option is its own mechanism, so it needs an operator. An identity option needs none.\n * A meta option with `chooses: true` needs none. A meta option that changes the output of its members needs one.\n */\nexport function needsOperator(option: StageOption): boolean {\n if (option.identity === true) return false;\n return option.members?.chooses !== true;\n}\n\nexport function checkOperators(space: StrategySpace, set: OperatorSet): ClaimBreak[] {\n const out: ClaimBreak[] = [];\n const add = (claim: string, detail: string, inputs: readonly string[] = []): void => {\n out.push({ claim, detail, inputs });\n };\n if (set.schema !== OPERATOR_SCHEMA) add(\"schema\", `the schema is ${JSON.stringify(set.schema)}, not ${OPERATOR_SCHEMA}`);\n if (set.engine !== space.engine) add(\"engine\", `the set is for the engine ${JSON.stringify(set.engine)}, not ${space.engine}`);\n const seen = new Map<string, Operator>();\n for (const o of set.operators) {\n const key = `${o.stage}.${o.id}`;\n const stage = space.stages.find((s) => s.name === o.stage);\n const option = stage?.options.find((x) => x.id === o.id);\n if (stage === undefined) add(\"unknown\", `the operator ${key} names the unknown stage ${o.stage}`, [key]);\n else if (option === undefined) add(\"unknown\", `the operator ${key} is not an option of the stage ${o.stage}`, [key]);\n else if (!needsOperator(option)) add(\"not-operator\", `the option ${key} is an identity option or only chooses a member, so it is not an operator`, [key]);\n if (seen.has(key)) add(\"duplicate\", `the set has the operator ${key} two times`, [key]);\n else seen.set(key, o);\n if (!(OPERATOR_SOURCES as readonly string[]).includes(o.source)) add(\"source\", `the operator ${key} has the source ${JSON.stringify(o.source)}, not one of ${OPERATOR_SOURCES.join(\", \")}`, [key]);\n if (o.source === \"mutation\" && o.parent === undefined) add(\"parent\", `the mutation ${key} has no parent`, [key]);\n if (o.source === \"literature\" && !isText(o.cite)) add(\"cite\", `the literature operator ${key} has no cite`, [key]);\n const tests: readonly unknown[] = Array.isArray(o.test) ? o.test : [o.test];\n if (tests.length === 0 || !tests.every(isText)) add(\"test\", `the operator ${key} has no test file or test folder`, [key]);\n if (!isText(o.summary)) add(\"summary\", `the operator ${key} has no summary`, [key]);\n }\n for (const o of seen.values()) {\n if (o.parent === undefined) continue;\n const key = `${o.stage}.${o.id}`;\n if (!seen.has(`${o.stage}.${o.parent}`)) {\n add(\"parent\", `the parent ${o.parent} of the operator ${key} is not an operator of the stage ${o.stage}`, [key]);\n continue;\n }\n // A walk up the parents finds a cycle when it comes back to an operator that it saw.\n const path = new Set<string>([o.id]);\n for (let p = seen.get(`${o.stage}.${o.parent}`); p?.parent !== undefined; p = seen.get(`${o.stage}.${p.parent}`)) {\n if (path.has(p.id)) {\n add(\"cycle\", `the parents of the operator ${key} make a cycle`, [key]);\n break;\n }\n path.add(p.id);\n }\n }\n for (const s of space.stages)\n for (const option of s.options)\n if (needsOperator(option) && !seen.has(`${s.name}.${option.id}`)) add(\"undeclared\", `the option ${s.name}.${option.id} has no operator`, [`${s.name}.${option.id}`]);\n return out;\n}\n\n/**\n * This function gives the count of the operators of a set, by stage and by source. It counts each operator of the set.\n * `checkOperators` refuses an operator of an option that `needsOperator` refuses. So a good set counts only the mechanisms.\n */\nexport function countOperators(set: OperatorSet): OperatorCount {\n const byStage: Record<string, number> = {};\n const bySource: Record<OperatorSource, number> = { literature: 0, ours: 0, mutation: 0 };\n for (const o of set.operators) {\n byStage[o.stage] = (byStage[o.stage] ?? 0) + 1;\n bySource[o.source] += 1;\n }\n return { total: set.operators.length, byStage, bySource };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// src/space-walk.ts
|
|
2
|
+
const refMatches = (ref, choices) => (choices.get(ref.stage) ?? null) === ref.option;
|
|
3
|
+
/** This function tells if the option choices keep a constraint. */
|
|
4
|
+
function holds(c, choices) {
|
|
5
|
+
if (!refMatches(c.if, choices)) return true;
|
|
6
|
+
return "not" in c.then ? !refMatches(c.then.not, choices) : refMatches(c.then, choices);
|
|
7
|
+
}
|
|
8
|
+
const otherStage = (c) => "not" in c.then ? c.then.not.stage : c.then.stage;
|
|
9
|
+
/** This function tells if an option of a stage keeps each constraint between that stage and the stages that a walk has fixed. */
|
|
10
|
+
function fitsWalk(constraints, fixed, stage, id) {
|
|
11
|
+
fixed.set(stage, id);
|
|
12
|
+
const ok = constraints.every((c) => !fixed.has(c.if.stage === stage ? otherStage(c) : c.if.stage) || holds(c, fixed));
|
|
13
|
+
fixed.delete(stage);
|
|
14
|
+
return ok;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* This function gives the plan of a walk. Stages of equal size keep the order of the space.
|
|
18
|
+
* The stages of `first` go first, for example the stages of the sample option `fixed`. Thus the other stages draw only from the options that keep the constraints with them.
|
|
19
|
+
*/
|
|
20
|
+
function walkPlan(stages, lists, constraints, n, first = /* @__PURE__ */ new Set()) {
|
|
21
|
+
return {
|
|
22
|
+
stages,
|
|
23
|
+
lists,
|
|
24
|
+
n,
|
|
25
|
+
order: stages.map((_, k) => k).sort((a, b) => Number(first.has(stages[b].name)) - Number(first.has(stages[a].name)) || lists[b].length - lists[a].length || a - b),
|
|
26
|
+
naming: stages.map((s) => constraints.filter((c) => c.if.stage === s.name || otherStage(c) === s.name))
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* This function gives the options of one point of a walk. It fixes the largest stage first. Thus that stage keeps its equal strata, and the constraints limit only the smaller stages.
|
|
31
|
+
* The value `picks[k][i]` is the stratum of the stage `k` for the point `i`. A stage with no open option gets `null`, and the caller rejects that point.
|
|
32
|
+
* The argument `fits` lets a test give a fault. The default is `fitsWalk`.
|
|
33
|
+
*/
|
|
34
|
+
function walkPoint(plan, picks, i, fits = fitsWalk) {
|
|
35
|
+
const fixed = /* @__PURE__ */ new Map();
|
|
36
|
+
const out = /* @__PURE__ */ new Map();
|
|
37
|
+
for (const k of plan.order) {
|
|
38
|
+
const s = plan.stages[k];
|
|
39
|
+
const open = plan.lists[k].filter((o) => fits(plan.naming[k], fixed, s.name, o?.id ?? null));
|
|
40
|
+
const o = open[Math.floor(picks[k][i] * open.length / plan.n)] ?? null;
|
|
41
|
+
fixed.set(s.name, o?.id ?? null);
|
|
42
|
+
out.set(s.name, o);
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
export { fitsWalk, holds, walkPlan, walkPoint };
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=space-walk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"space-walk.js","names":[],"sources":["../src/space-walk.ts"],"sourcesContent":["// The walk draw of a sample of a strategy space (`docs/STRATEGY-SPACE.md`). The package root does not export this file.\nimport type { OptionRef, SpaceConstraint, SpaceStage, StageOption } from \"./strategy-space.ts\";\n\nconst refMatches = (ref: OptionRef, choices: ReadonlyMap<string, string | null>): boolean => (choices.get(ref.stage) ?? null) === ref.option;\n\n/** This function tells if the option choices keep a constraint. */\nexport function holds(c: SpaceConstraint, choices: ReadonlyMap<string, string | null>): boolean {\n if (!refMatches(c.if, choices)) return true;\n return \"not\" in c.then ? !refMatches(c.then.not, choices) : refMatches(c.then, choices);\n}\n\nconst otherStage = (c: SpaceConstraint): string => (\"not\" in c.then ? c.then.not.stage : c.then.stage);\n\n/** This function tells if an option of a stage keeps each constraint between that stage and the stages that a walk has fixed. */\nexport function fitsWalk(constraints: readonly SpaceConstraint[], fixed: Map<string, string | null>, stage: string, id: string | null): boolean {\n fixed.set(stage, id);\n const ok = constraints.every((c) => !fixed.has(c.if.stage === stage ? otherStage(c) : c.if.stage) || holds(c, fixed));\n fixed.delete(stage);\n return ok;\n}\n\n/** The order of the stages of a walk, and the constraints that name each stage. */\nexport interface WalkPlan {\n /** The stages of the space. */\n readonly stages: readonly SpaceStage[];\n /** The options of each stage for a draw. */\n readonly lists: readonly (readonly (StageOption | null)[])[];\n /** The indexes of the stages. The stages of `first` come first, in the order of the space. The others follow, from the largest stage to the smallest. */\n readonly order: readonly number[];\n /** The constraints that name each stage. */\n readonly naming: readonly (readonly SpaceConstraint[])[];\n /** The count of points of a round. */\n readonly n: number;\n}\n\n/**\n * This function gives the plan of a walk. Stages of equal size keep the order of the space.\n * The stages of `first` go first, for example the stages of the sample option `fixed`. Thus the other stages draw only from the options that keep the constraints with them.\n */\nexport function walkPlan(\n stages: readonly SpaceStage[],\n lists: readonly (readonly (StageOption | null)[])[],\n constraints: readonly SpaceConstraint[],\n n: number,\n first: ReadonlySet<string> = new Set(),\n): WalkPlan {\n return {\n stages,\n lists,\n n,\n order: stages.map((_, k) => k).sort((a, b) => Number(first.has(stages[b]!.name)) - Number(first.has(stages[a]!.name)) || lists[b]!.length - lists[a]!.length || a - b),\n naming: stages.map((s) => constraints.filter((c) => c.if.stage === s.name || otherStage(c) === s.name)),\n };\n}\n\n/**\n * This function gives the options of one point of a walk. It fixes the largest stage first. Thus that stage keeps its equal strata, and the constraints limit only the smaller stages.\n * The value `picks[k][i]` is the stratum of the stage `k` for the point `i`. A stage with no open option gets `null`, and the caller rejects that point.\n * The argument `fits` lets a test give a fault. The default is `fitsWalk`.\n */\nexport function walkPoint(plan: WalkPlan, picks: readonly (readonly number[])[], i: number, fits: typeof fitsWalk = fitsWalk): Map<string, StageOption | null> {\n const fixed = new Map<string, string | null>();\n const out = new Map<string, StageOption | null>();\n for (const k of plan.order) {\n const s = plan.stages[k]!;\n const open = plan.lists[k]!.filter((o) => fits(plan.naming[k]!, fixed, s.name, o?.id ?? null));\n const o = open[Math.floor((picks[k]![i]! * open.length) / plan.n)] ?? null;\n fixed.set(s.name, o?.id ?? null);\n out.set(s.name, o);\n }\n return out;\n}\n"],"mappings":";AAGA,MAAM,cAAc,KAAgB,aAA0D,QAAQ,IAAI,IAAI,KAAK,KAAK,UAAU,IAAI;;AAGtI,SAAgB,MAAM,GAAoB,SAAsD;CAC9F,IAAI,CAAC,WAAW,EAAE,IAAI,OAAO,GAAG,OAAO;CACvC,OAAO,SAAS,EAAE,OAAO,CAAC,WAAW,EAAE,KAAK,KAAK,OAAO,IAAI,WAAW,EAAE,MAAM,OAAO;AACxF;AAEA,MAAM,cAAc,MAAgC,SAAS,EAAE,OAAO,EAAE,KAAK,IAAI,QAAQ,EAAE,KAAK;;AAGhG,SAAgB,SAAS,aAAyC,OAAmC,OAAe,IAA4B;CAC9I,MAAM,IAAI,OAAO,EAAE;CACnB,MAAM,KAAK,YAAY,OAAO,MAAM,CAAC,MAAM,IAAI,EAAE,GAAG,UAAU,QAAQ,WAAW,CAAC,IAAI,EAAE,GAAG,KAAK,KAAK,MAAM,GAAG,KAAK,CAAC;CACpH,MAAM,OAAO,KAAK;CAClB,OAAO;AACT;;;;;AAoBA,SAAgB,SACd,QACA,OACA,aACA,GACA,wBAA6B,IAAI,IAAI,GAC3B;CACV,OAAO;EACL;EACA;EACA;EACA,OAAO,OAAO,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,OAAO,MAAM,IAAI,OAAO,EAAE,CAAE,IAAI,CAAC,IAAI,OAAO,MAAM,IAAI,OAAO,EAAE,CAAE,IAAI,CAAC,KAAK,MAAM,EAAE,CAAE,SAAS,MAAM,EAAE,CAAE,UAAU,IAAI,CAAC;EACrK,QAAQ,OAAO,KAAK,MAAM,YAAY,QAAQ,MAAM,EAAE,GAAG,UAAU,EAAE,QAAQ,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC;CACxG;AACF;;;;;;AAOA,SAAgB,UAAU,MAAgB,OAAuC,GAAW,OAAwB,UAA2C;CAC7J,MAAM,wBAAQ,IAAI,IAA2B;CAC7C,MAAM,sBAAM,IAAI,IAAgC;CAChD,KAAK,MAAM,KAAK,KAAK,OAAO;EAC1B,MAAM,IAAI,KAAK,OAAO;EACtB,MAAM,OAAO,KAAK,MAAM,EAAE,CAAE,QAAQ,MAAM,KAAK,KAAK,OAAO,IAAK,OAAO,EAAE,MAAM,GAAG,MAAM,IAAI,CAAC;EAC7F,MAAM,IAAI,KAAK,KAAK,MAAO,MAAM,EAAE,CAAE,KAAM,KAAK,SAAU,KAAK,CAAC,MAAM;EACtE,MAAM,IAAI,EAAE,MAAM,GAAG,MAAM,IAAI;EAC/B,IAAI,IAAI,EAAE,MAAM,CAAC;CACnB;CACA,OAAO;AACT"}
|