@hikae/jev-algorithms 0.1.0-rc.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.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +161 -0
  3. package/dist/adapters/memory.d.ts +10 -0
  4. package/dist/adapters/memory.d.ts.map +1 -0
  5. package/dist/adapters/memory.js +12 -0
  6. package/dist/adapters/memory.js.map +1 -0
  7. package/dist/adapters/typesafe.d.ts +15 -0
  8. package/dist/adapters/typesafe.d.ts.map +1 -0
  9. package/dist/adapters/typesafe.js +27 -0
  10. package/dist/adapters/typesafe.js.map +1 -0
  11. package/dist/adapters/workers-ai.d.ts +8 -0
  12. package/dist/adapters/workers-ai.d.ts.map +1 -0
  13. package/dist/adapters/workers-ai.js +11 -0
  14. package/dist/adapters/workers-ai.js.map +1 -0
  15. package/dist/algorithms/aggregate.d.ts +39 -0
  16. package/dist/algorithms/aggregate.d.ts.map +1 -0
  17. package/dist/algorithms/aggregate.js +100 -0
  18. package/dist/algorithms/aggregate.js.map +1 -0
  19. package/dist/algorithms/classify.d.ts +59 -0
  20. package/dist/algorithms/classify.d.ts.map +1 -0
  21. package/dist/algorithms/classify.js +65 -0
  22. package/dist/algorithms/classify.js.map +1 -0
  23. package/dist/algorithms/cluster.d.ts +30 -0
  24. package/dist/algorithms/cluster.d.ts.map +1 -0
  25. package/dist/algorithms/cluster.js +87 -0
  26. package/dist/algorithms/cluster.js.map +1 -0
  27. package/dist/algorithms/match.d.ts +16 -0
  28. package/dist/algorithms/match.d.ts.map +1 -0
  29. package/dist/algorithms/match.js +63 -0
  30. package/dist/algorithms/match.js.map +1 -0
  31. package/dist/algorithms/pairwise.d.ts +45 -0
  32. package/dist/algorithms/pairwise.d.ts.map +1 -0
  33. package/dist/algorithms/pairwise.js +165 -0
  34. package/dist/algorithms/pairwise.js.map +1 -0
  35. package/dist/algorithms/search.d.ts +25 -0
  36. package/dist/algorithms/search.d.ts.map +1 -0
  37. package/dist/algorithms/search.js +32 -0
  38. package/dist/algorithms/search.js.map +1 -0
  39. package/dist/client.d.ts +75 -0
  40. package/dist/client.d.ts.map +1 -0
  41. package/dist/client.js +35 -0
  42. package/dist/client.js.map +1 -0
  43. package/dist/index.d.ts +13 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +13 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/lib/chunk.d.ts +3 -0
  48. package/dist/lib/chunk.d.ts.map +1 -0
  49. package/dist/lib/chunk.js +12 -0
  50. package/dist/lib/chunk.js.map +1 -0
  51. package/dist/lib/unionFind.d.ts +12 -0
  52. package/dist/lib/unionFind.d.ts.map +1 -0
  53. package/dist/lib/unionFind.js +58 -0
  54. package/dist/lib/unionFind.js.map +1 -0
  55. package/docs/animations/cluster-by-relation.gif +0 -0
  56. package/docs/animations/find-first-true.gif +0 -0
  57. package/docs/animations/select-top-k.gif +0 -0
  58. package/docs/animations/sort-by-pairwise.gif +0 -0
  59. package/package.json +53 -0
@@ -0,0 +1,87 @@
1
+ import { noul } from "../client.js";
2
+ import { UnionFind } from "../lib/unionFind.js";
3
+ /** Total comparisons allowed before the pair set is sampled. */
4
+ export const DEFAULT_MAX_COMPARISONS = 2000;
5
+ /** Pairs per Jev request. */
6
+ export const DEFAULT_MAX_CLUSTER_PAIRS_PER_REQUEST = 40;
7
+ export function createRelationComparator(client, items, options) {
8
+ const { relation, stateOf, maxPairsPerRequest = DEFAULT_MAX_CLUSTER_PAIRS_PER_REQUEST, } = options;
9
+ return async (pairs) => {
10
+ const same = new Array(pairs.length).fill(0);
11
+ for (let start = 0; start < pairs.length; start += maxPairsPerRequest) {
12
+ const part = pairs.slice(start, start + maxPairsPerRequest);
13
+ const localIndex = new Map();
14
+ const candidates = [];
15
+ const localize = (i) => {
16
+ let local = localIndex.get(i);
17
+ if (local === undefined) {
18
+ local = candidates.length;
19
+ localIndex.set(i, local);
20
+ candidates.push(stateOf(items[i]));
21
+ }
22
+ return local;
23
+ };
24
+ const localPairs = part.map(([a, b]) => [localize(a), localize(b)]);
25
+ const questions = {};
26
+ localPairs.forEach(([a, b], k) => {
27
+ questions[`p${k}`] = noul(`Do \`candidates[${a}]\` and \`candidates[${b}]\` refer to the same ${relation}?`, {
28
+ true: `they are the same ${relation}`,
29
+ false: `they are different ${relation}s`,
30
+ });
31
+ });
32
+ const answers = await client.evaluate({
33
+ state: { candidates, pairs: localPairs },
34
+ questions,
35
+ });
36
+ localPairs.forEach((_, k) => {
37
+ const answer = answers[`p${k}`];
38
+ const probability = answer && "noul" in answer ? answer.noul : undefined;
39
+ if (typeof probability !== "number" || !Number.isFinite(probability)) {
40
+ throw new Error("cluster: Jev returned no answer for a pair");
41
+ }
42
+ same[start + k] = probability;
43
+ });
44
+ }
45
+ return same;
46
+ };
47
+ }
48
+ /** Union-find clustering over an injected equivalence comparator. */
49
+ export async function clusterWith(items, compare, options = {}) {
50
+ const { threshold = 0.5, maxComparisons = DEFAULT_MAX_COMPARISONS, random = Math.random, } = options;
51
+ const unionFind = new UnionFind(items.map((_, i) => i));
52
+ let pairs = [];
53
+ for (let i = 0; i < items.length; i++) {
54
+ for (let j = i + 1; j < items.length; j++) {
55
+ pairs.push([i, j]);
56
+ }
57
+ }
58
+ if (pairs.length > maxComparisons) {
59
+ // ponytail: sampled instead of exhaustive above the cap. Raise the cap or
60
+ // block candidates before clustering when recall matters.
61
+ pairs = shuffle(pairs, random).slice(0, maxComparisons);
62
+ }
63
+ const probabilities = await compare(pairs);
64
+ pairs.forEach(([i, j], k) => {
65
+ if ((probabilities[k] ?? 0) >= threshold)
66
+ unionFind.union(i, j);
67
+ });
68
+ return unionFind.groups().map((group) => group.map((i) => items[i]));
69
+ }
70
+ /** Cluster items by a Jev equivalence question, one request per 40 pairs. */
71
+ export async function clusterByRelation(client, items, options) {
72
+ const { threshold, maxComparisons, random } = options;
73
+ return clusterWith(items, createRelationComparator(client, items, options), {
74
+ threshold,
75
+ maxComparisons,
76
+ random,
77
+ });
78
+ }
79
+ function shuffle(items, random) {
80
+ const out = [...items];
81
+ for (let i = out.length - 1; i > 0; i--) {
82
+ const j = Math.floor(random() * (i + 1));
83
+ [out[i], out[j]] = [out[j], out[i]];
84
+ }
85
+ return out;
86
+ }
87
+ //# sourceMappingURL=cluster.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cluster.js","sourceRoot":"","sources":["../../src/algorithms/cluster.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { JevClient, JevState } from "../client.js";
2
+ /** Proposer-optimal stable matching (Gale-Shapley). */
3
+ export declare function stableMatching(proposers: readonly string[], receivers: readonly string[], proposerPrefs: Record<string, readonly string[]>, receiverPrefs: Record<string, readonly string[]>): Array<[string, string]>;
4
+ export interface BuildPreferencesOptions<C, D> {
5
+ /** Ranking goal woven into the question, e.g. "for this support ticket". */
6
+ task: string;
7
+ /** Build the Jev state for one chooser and one candidate. */
8
+ stateOf: (chooser: C, candidate: D) => JevState;
9
+ idOfChooser: (chooser: C) => string;
10
+ idOfCandidate: (candidate: D) => string;
11
+ maxPairsPerRequest?: number;
12
+ random?: () => number;
13
+ }
14
+ /** Rank every candidate for every chooser; one pairwise sort per chooser. */
15
+ export declare function buildPreferences<C, D>(client: JevClient, choosers: readonly C[], candidates: readonly D[], options: BuildPreferencesOptions<C, D>): Promise<Record<string, string[]>>;
16
+ //# sourceMappingURL=match.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.d.ts","sourceRoot":"","sources":["../../src/algorithms/match.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAOxD,uDAAuD;AACvD,wBAAgB,cAAc,CAC7B,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,EAChD,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,GAC9C,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CA+CzB;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC,EAAE,CAAC;IAC5C,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,QAAQ,CAAC;IAChD,WAAW,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,MAAM,CAAC;IACpC,aAAa,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,MAAM,CAAC;IACxC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;CACtB;AAED,6EAA6E;AAC7E,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAC1C,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,SAAS,CAAC,EAAE,EACtB,UAAU,EAAE,SAAS,CAAC,EAAE,EACxB,OAAO,EAAE,uBAAuB,CAAC,CAAC,EAAE,CAAC,CAAC,GACpC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAyBnC"}
@@ -0,0 +1,63 @@
1
+ import { createPairComparator, sortByPairwiseWith, } from "./pairwise.js";
2
+ /** Proposer-optimal stable matching (Gale-Shapley). */
3
+ export function stableMatching(proposers, receivers, proposerPrefs, receiverPrefs) {
4
+ // Rank of each proposer in each receiver's list, for O(1) comparisons.
5
+ const receiverRank = new Map();
6
+ for (const receiver of receivers) {
7
+ const ranks = new Map();
8
+ (receiverPrefs[receiver] ?? []).forEach((proposer, i) => ranks.set(proposer, i));
9
+ receiverRank.set(receiver, ranks);
10
+ }
11
+ const free = [...proposers];
12
+ const nextChoice = new Map();
13
+ const heldBy = new Map(); // receiver -> proposer
14
+ while (free.length > 0) {
15
+ const proposer = free.shift();
16
+ const prefs = proposerPrefs[proposer] ?? [];
17
+ let index = nextChoice.get(proposer) ?? 0;
18
+ if (index >= prefs.length)
19
+ continue; // proposer exhausted its list
20
+ const receiver = prefs[index];
21
+ nextChoice.set(proposer, index + 1);
22
+ // Skip partners that are not valid receivers, but keep the proposer
23
+ // free for its next choice instead of dropping it.
24
+ if (!receivers.includes(receiver)) {
25
+ free.push(proposer);
26
+ continue;
27
+ }
28
+ const current = heldBy.get(receiver);
29
+ if (current === undefined) {
30
+ heldBy.set(receiver, proposer);
31
+ continue;
32
+ }
33
+ const ranks = receiverRank.get(receiver);
34
+ const currentRank = ranks.get(current) ?? Number.POSITIVE_INFINITY;
35
+ const challengerRank = ranks.get(proposer) ?? Number.POSITIVE_INFINITY;
36
+ if (challengerRank < currentRank) {
37
+ heldBy.set(receiver, proposer);
38
+ free.push(current);
39
+ }
40
+ else {
41
+ free.push(proposer);
42
+ }
43
+ }
44
+ return [...heldBy.entries()].map(([receiver, proposer]) => [proposer, receiver]);
45
+ }
46
+ /** Rank every candidate for every chooser; one pairwise sort per chooser. */
47
+ export async function buildPreferences(client, choosers, candidates, options) {
48
+ const { task, stateOf, idOfChooser, idOfCandidate, maxPairsPerRequest, random, } = options;
49
+ const runtime = { random };
50
+ const prefs = {};
51
+ for (const chooser of choosers) {
52
+ const compare = createPairComparator(client, candidates, {
53
+ task,
54
+ stateOf: (candidate) => stateOf(chooser, candidate),
55
+ maxPairsPerRequest,
56
+ random,
57
+ });
58
+ const ordered = await sortByPairwiseWith(candidates, compare, runtime);
59
+ prefs[idOfChooser(chooser)] = ordered.map(idOfCandidate);
60
+ }
61
+ return prefs;
62
+ }
63
+ //# sourceMappingURL=match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.js","sourceRoot":"","sources":["../../src/algorithms/match.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import { type JevClient, type JevState } from "../client.js";
2
+ /** Pairs per Jev request. Bounds the prompt and the answer count. */
3
+ export declare const DEFAULT_MAX_PAIRS_PER_REQUEST = 40;
4
+ /** Hard cap on sort/selection rounds before falling back to the current order. */
5
+ export declare const DEFAULT_MAX_ROUNDS = 40;
6
+ export interface PairwiseOptions<T> {
7
+ /** Ranking goal woven into the question, e.g. "for replying first". */
8
+ task: string;
9
+ /** Map an item to the Jev state Jev compares. */
10
+ stateOf: (item: T) => JevState;
11
+ /** Pairs per request. Default {@link DEFAULT_MAX_PAIRS_PER_REQUEST}. */
12
+ maxPairsPerRequest?: number;
13
+ /** Injectable RNG for pivot choice. Default `Math.random`. */
14
+ random?: () => number;
15
+ /** Round cap. Default {@link DEFAULT_MAX_ROUNDS}. */
16
+ maxRounds?: number;
17
+ }
18
+ /** Answers one batch of pairs: true means `pairs[i][0]` outranks `pairs[i][1]`. */
19
+ export type PairComparator = (pairs: Array<[number, number]>) => Promise<boolean[]>;
20
+ /** Comparator asking Jev which of two items ranks higher, batched per request. */
21
+ export declare function createPairComparator<T>(client: JevClient, items: readonly T[], options: PairwiseOptions<T>): PairComparator;
22
+ /** Randomized quicksort, one recursion level per `compare` call. */
23
+ export declare function sortIndicesByPairwise(indices: readonly number[], compare: PairComparator, options?: {
24
+ random?: () => number;
25
+ maxRounds?: number;
26
+ }): Promise<number[]>;
27
+ export interface SortRuntimeOptions {
28
+ random?: () => number;
29
+ maxRounds?: number;
30
+ }
31
+ /** Sort items highest-first using an injected comparator. */
32
+ export declare function sortByPairwiseWith<T>(items: readonly T[], compare: PairComparator, options?: SortRuntimeOptions): Promise<T[]>;
33
+ /** Sort items highest-first using Jev as the pairwise oracle. */
34
+ export declare function sortByPairwise<T>(client: JevClient, items: readonly T[], options: PairwiseOptions<T>): Promise<T[]>;
35
+ /**
36
+ * Pick the top-k indices with quickselect: only the pivot side that can still
37
+ * contain the k-th item is explored, so this beats a full sort on comparisons.
38
+ * Returns the k winners (unordered).
39
+ */
40
+ export declare function selectTopKIndices(indices: readonly number[], k: number, compare: PairComparator, options?: SortRuntimeOptions): Promise<number[]>;
41
+ /** Pick the top-k items, ordered highest-first, using an injected comparator. */
42
+ export declare function selectTopKWith<T>(items: readonly T[], k: number, compare: PairComparator, options?: SortRuntimeOptions): Promise<T[]>;
43
+ /** Pick the top-k items, ordered highest-first, using Jev as the oracle. */
44
+ export declare function selectTopK<T>(client: JevClient, items: readonly T[], k: number, options: PairwiseOptions<T>): Promise<T[]>;
45
+ //# sourceMappingURL=pairwise.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pairwise.d.ts","sourceRoot":"","sources":["../../src/algorithms/pairwise.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,SAAS,EAAqB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAGtF,qEAAqE;AACrE,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAChD,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,MAAM,WAAW,eAAe,CAAC,CAAC;IACjC,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,QAAQ,CAAC;IAC/B,wEAAwE;IACxE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IACtB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,mFAAmF;AACnF,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;AAEpF,kFAAkF;AAClF,wBAAgB,oBAAoB,CAAC,CAAC,EACrC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,GACzB,cAAc,CA0DhB;AAUD,oEAAoE;AACpE,wBAAsB,qBAAqB,CAC1C,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,OAAO,EAAE,cAAc,EACvB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACzD,OAAO,CAAC,MAAM,EAAE,CAAC,CA8CnB;AASD,MAAM,WAAW,kBAAkB;IAClC,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,6DAA6D;AAC7D,wBAAsB,kBAAkB,CAAC,CAAC,EACzC,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,OAAO,EAAE,cAAc,EACvB,OAAO,GAAE,kBAAuB,GAC9B,OAAO,CAAC,CAAC,EAAE,CAAC,CAOd;AAED,iEAAiE;AACjE,wBAAsB,cAAc,CAAC,CAAC,EACrC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,GACzB,OAAO,CAAC,CAAC,EAAE,CAAC,CAEd;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACtC,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,CAAC,EAAE,MAAM,EACT,OAAO,EAAE,cAAc,EACvB,OAAO,GAAE,kBAAuB,GAC9B,OAAO,CAAC,MAAM,EAAE,CAAC,CAuCnB;AAED,iFAAiF;AACjF,wBAAsB,cAAc,CAAC,CAAC,EACrC,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,CAAC,EAAE,MAAM,EACT,OAAO,EAAE,cAAc,EACvB,OAAO,GAAE,kBAAuB,GAC9B,OAAO,CAAC,CAAC,EAAE,CAAC,CASd;AAED,4EAA4E;AAC5E,wBAAsB,UAAU,CAAC,CAAC,EACjC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,CAAC,EAAE,MAAM,EACT,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,GACzB,OAAO,CAAC,CAAC,EAAE,CAAC,CAEd"}
@@ -0,0 +1,165 @@
1
+ import { noul } from "../client.js";
2
+ /** Pairs per Jev request. Bounds the prompt and the answer count. */
3
+ export const DEFAULT_MAX_PAIRS_PER_REQUEST = 40;
4
+ /** Hard cap on sort/selection rounds before falling back to the current order. */
5
+ export const DEFAULT_MAX_ROUNDS = 40;
6
+ /** Comparator asking Jev which of two items ranks higher, batched per request. */
7
+ export function createPairComparator(client, items, options) {
8
+ const { task, stateOf, maxPairsPerRequest = DEFAULT_MAX_PAIRS_PER_REQUEST, } = options;
9
+ return async (pairs) => {
10
+ const decisions = new Array(pairs.length).fill(false);
11
+ for (let start = 0; start < pairs.length; start += maxPairsPerRequest) {
12
+ const part = pairs.slice(start, start + maxPairsPerRequest);
13
+ // Only the items referenced by this chunk travel in the state.
14
+ const localIndex = new Map();
15
+ const candidates = [];
16
+ const localize = (i) => {
17
+ let local = localIndex.get(i);
18
+ if (local === undefined) {
19
+ local = candidates.length;
20
+ localIndex.set(i, local);
21
+ candidates.push(stateOf(items[i]));
22
+ }
23
+ return local;
24
+ };
25
+ const localPairs = part.map(([a, b]) => [localize(a), localize(b)]);
26
+ const questions = {};
27
+ localPairs.forEach(([a, b], k) => {
28
+ questions[`c${k}`] = noul(`Does \`candidates[${a}]\` rank higher than \`candidates[${b}]\` ${task}? ` +
29
+ `Answer true only if \`candidates[${a}]\` should come first.`, {
30
+ true: `candidates[${a}] comes first`,
31
+ false: `candidates[${b}] comes first, or the two tie`,
32
+ });
33
+ });
34
+ const answers = await client.evaluate({
35
+ state: { candidates, pairs: localPairs },
36
+ questions,
37
+ });
38
+ localPairs.forEach((_, k) => {
39
+ const value = answers[`c${k}`];
40
+ const probability = value && "noul" in value ? value.noul : undefined;
41
+ if (typeof probability !== "number" || !Number.isFinite(probability)) {
42
+ throw new Error("pairwise: Jev returned no answer for a comparison");
43
+ }
44
+ decisions[start + k] = probability >= 0.5;
45
+ });
46
+ }
47
+ return decisions;
48
+ };
49
+ }
50
+ /** Randomized quicksort, one recursion level per `compare` call. */
51
+ export async function sortIndicesByPairwise(indices, compare, options = {}) {
52
+ const { random = Math.random, maxRounds = DEFAULT_MAX_ROUNDS } = options;
53
+ if (indices.length <= 1)
54
+ return [...indices];
55
+ const root = { ids: [...indices] };
56
+ let frontier = [root];
57
+ let rounds = 0;
58
+ while (frontier.length > 0 && rounds < maxRounds) {
59
+ const pairs = [];
60
+ const pending = [];
61
+ for (const node of frontier) {
62
+ if (node.ids.length <= 1)
63
+ continue;
64
+ const pivot = node.ids[Math.floor(random() * node.ids.length)];
65
+ const others = node.ids.filter((id) => id !== pivot);
66
+ node.pivot = pivot;
67
+ pending.push({ node, others });
68
+ for (const other of others)
69
+ pairs.push([other, pivot]);
70
+ }
71
+ if (pairs.length === 0)
72
+ break;
73
+ const decisions = await compare(pairs);
74
+ let cursor = 0;
75
+ const next = [];
76
+ for (const { node, others } of pending) {
77
+ const high = [];
78
+ const low = [];
79
+ for (const other of others) {
80
+ (decisions[cursor++] ? high : low).push(other);
81
+ }
82
+ if (high.length > 0) {
83
+ node.high = { ids: high };
84
+ next.push(node.high);
85
+ }
86
+ if (low.length > 0) {
87
+ node.low = { ids: low };
88
+ next.push(node.low);
89
+ }
90
+ }
91
+ frontier = next;
92
+ rounds++;
93
+ }
94
+ return flatten(root);
95
+ }
96
+ /** In-order walk: high subtree first, so the result is highest-ranked first. */
97
+ function flatten(node) {
98
+ if (!node)
99
+ return [];
100
+ if (node.pivot === undefined)
101
+ return node.ids;
102
+ return [...flatten(node.high), node.pivot, ...flatten(node.low)];
103
+ }
104
+ /** Sort items highest-first using an injected comparator. */
105
+ export async function sortByPairwiseWith(items, compare, options = {}) {
106
+ const order = await sortIndicesByPairwise(items.map((_, i) => i), compare, options);
107
+ return order.map((i) => items[i]);
108
+ }
109
+ /** Sort items highest-first using Jev as the pairwise oracle. */
110
+ export async function sortByPairwise(client, items, options) {
111
+ return sortByPairwiseWith(items, createPairComparator(client, items, options), options);
112
+ }
113
+ /**
114
+ * Pick the top-k indices with quickselect: only the pivot side that can still
115
+ * contain the k-th item is explored, so this beats a full sort on comparisons.
116
+ * Returns the k winners (unordered).
117
+ */
118
+ export async function selectTopKIndices(indices, k, compare, options = {}) {
119
+ const { random = Math.random, maxRounds = DEFAULT_MAX_ROUNDS } = options;
120
+ if (k <= 0)
121
+ return [];
122
+ if (k >= indices.length)
123
+ return sortIndicesByPairwise(indices, compare, options);
124
+ const confirmed = [];
125
+ let candidates = [...indices];
126
+ let rounds = 0;
127
+ while (confirmed.length < k && candidates.length > 0) {
128
+ const remaining = k - confirmed.length;
129
+ if (candidates.length <= remaining) {
130
+ confirmed.push(...candidates);
131
+ break;
132
+ }
133
+ if (rounds >= maxRounds) {
134
+ // Adversarial or noisy answers: stop probing and keep the rest.
135
+ confirmed.push(...candidates);
136
+ break;
137
+ }
138
+ const pivot = candidates[Math.floor(random() * candidates.length)];
139
+ const others = candidates.filter((id) => id !== pivot);
140
+ const decisions = await compare(others.map((id) => [id, pivot]));
141
+ const high = [];
142
+ const low = [];
143
+ others.forEach((id, i) => (decisions[i] ? high : low).push(id));
144
+ if (high.length >= remaining) {
145
+ candidates = high; // pivot and low are below the top k
146
+ }
147
+ else {
148
+ confirmed.push(...high, pivot);
149
+ candidates = low;
150
+ }
151
+ rounds++;
152
+ }
153
+ return confirmed.slice(0, k);
154
+ }
155
+ /** Pick the top-k items, ordered highest-first, using an injected comparator. */
156
+ export async function selectTopKWith(items, k, compare, options = {}) {
157
+ const indices = await selectTopKIndices(items.map((_, i) => i), k, compare, options);
158
+ const ordered = await sortIndicesByPairwise(indices, compare, options);
159
+ return ordered.map((i) => items[i]);
160
+ }
161
+ /** Pick the top-k items, ordered highest-first, using Jev as the oracle. */
162
+ export async function selectTopK(client, items, k, options) {
163
+ return selectTopKWith(items, k, createPairComparator(client, items, options), options);
164
+ }
165
+ //# sourceMappingURL=pairwise.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pairwise.js","sourceRoot":"","sources":["../../src/algorithms/pairwise.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { type JevClient, type JevState } from "../client.js";
2
+ export interface FindFirstTrueOptions<T> {
3
+ /** Map an item to the Jev state the question inspects. */
4
+ stateOf: (item: T) => JevState;
5
+ /** Question about the single candidate under the cursor. */
6
+ instruction: string;
7
+ criteria?: {
8
+ true?: string;
9
+ false?: string;
10
+ };
11
+ }
12
+ export interface FindFirstTrueResult<T> {
13
+ /** Index of the first item the predicate is true for, or `items.length`. */
14
+ index: number;
15
+ /** That item, or null when the predicate is never true. */
16
+ item: T | null;
17
+ /** Jev calls spent (one binary-search step each). */
18
+ steps: number;
19
+ }
20
+ /**
21
+ * Binary search for the first item a Jev predicate is true for.
22
+ * `items` must be ordered so the predicate is monotone. One call per step.
23
+ */
24
+ export declare function findFirstTrue<T>(client: JevClient, items: readonly T[], options: FindFirstTrueOptions<T>): Promise<FindFirstTrueResult<T>>;
25
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/algorithms/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEnE,MAAM,WAAW,oBAAoB,CAAC,CAAC;IACtC,0DAA0D;IAC1D,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,QAAQ,CAAC;IAC/B,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAED,MAAM,WAAW,mBAAmB,CAAC,CAAC;IACrC,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACf,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,CAAC,EACpC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,OAAO,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAC9B,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CA4BjC"}
@@ -0,0 +1,32 @@
1
+ import { noul } from "../client.js";
2
+ /**
3
+ * Binary search for the first item a Jev predicate is true for.
4
+ * `items` must be ordered so the predicate is monotone. One call per step.
5
+ */
6
+ export async function findFirstTrue(client, items, options) {
7
+ const { stateOf, instruction, criteria } = options;
8
+ let low = 0;
9
+ let high = items.length;
10
+ let steps = 0;
11
+ while (low < high) {
12
+ const mid = low + Math.floor((high - low) / 2);
13
+ const answers = await client.evaluate({
14
+ state: { candidate: stateOf(items[mid]) },
15
+ questions: { is_true: noul(instruction, criteria) },
16
+ });
17
+ steps++;
18
+ const answer = answers.is_true;
19
+ const probability = answer && "noul" in answer ? answer.noul : undefined;
20
+ if (typeof probability !== "number" || !Number.isFinite(probability)) {
21
+ throw new Error("findFirstTrue: Jev returned no answer");
22
+ }
23
+ if (probability >= 0.5) {
24
+ high = mid;
25
+ }
26
+ else {
27
+ low = mid + 1;
28
+ }
29
+ }
30
+ return { index: low, item: low < items.length ? items[low] : null, steps };
31
+ }
32
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/algorithms/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAiC,MAAM,cAAc,CAAC;AAmBnE;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAClC,MAAiB,EACjB,KAAmB,EACnB,OAAgC;IAEhC,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IACnD,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC;IACxB,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,OAAO,GAAG,GAAG,IAAI,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/C,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC;YACrC,KAAK,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE;YACzC,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE;SACnD,CAAC,CAAC;QACH,KAAK,EAAE,CAAC;QAER,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,MAAM,WAAW,GAAG,MAAM,IAAI,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QACzE,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YACtE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,WAAW,IAAI,GAAG,EAAE,CAAC;YACxB,IAAI,GAAG,GAAG,CAAC;QACZ,CAAC;aAAM,CAAC;YACP,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;QACf,CAAC;IACF,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;AAC5E,CAAC"}
@@ -0,0 +1,75 @@
1
+ /** The Jev client contract: one state, many typed questions, typed answers. */
2
+ /** Any JSON value Jev can read as shared state. */
3
+ export type JevState = string | number | boolean | null | JevState[] | {
4
+ [key: string]: JevState;
5
+ };
6
+ /** Is this true? Answers with `noul`, the probability the answer is yes. */
7
+ export interface NoulQuestion {
8
+ type: "noul";
9
+ instructions: string;
10
+ criteria?: {
11
+ true?: string;
12
+ false?: string;
13
+ };
14
+ }
15
+ /** Which of these options? Answers with one key from `criteria`. */
16
+ export interface ChoiceQuestion {
17
+ type: "choice";
18
+ instructions: string;
19
+ /** Option key -> description. */
20
+ criteria: Record<string, string>;
21
+ }
22
+ /** Where on this ordered scale? Answers with an interpolated `score`. */
23
+ export interface ScoreQuestion {
24
+ type: "score";
25
+ instructions: string;
26
+ /** At least two ordered labels, lowest first. */
27
+ criteria: string[];
28
+ }
29
+ export type JevQuestion = NoulQuestion | ChoiceQuestion | ScoreQuestion;
30
+ export type JevQuestions = Record<string, JevQuestion>;
31
+ export interface NoulAnswer {
32
+ type?: "noul";
33
+ /** Probability the answer is yes, 0–1. */
34
+ noul: number;
35
+ }
36
+ export interface ChoiceAnswer {
37
+ type?: "choice";
38
+ choice: string;
39
+ confidence?: number;
40
+ probabilities?: Record<string, number>;
41
+ }
42
+ export interface ScoreAnswer {
43
+ type?: "score";
44
+ /** Interpolated position on the scale, 0..criteria.length-1. */
45
+ score: number;
46
+ confidence?: number;
47
+ legend?: Record<string, string>;
48
+ probabilities?: Record<string, number>;
49
+ }
50
+ export type JevAnswer = NoulAnswer | ChoiceAnswer | ScoreAnswer;
51
+ export type JevAnswers = Record<string, JevAnswer>;
52
+ export interface JevEvaluation {
53
+ state: JevState;
54
+ questions: JevQuestions;
55
+ }
56
+ export interface JevClient {
57
+ /** Evaluate one state against many questions in a single round trip. */
58
+ evaluate(input: JevEvaluation): Promise<JevAnswers>;
59
+ }
60
+ /** Build a Noul question. `criteria` sharpens what true and false mean. */
61
+ export declare function noul(instructions: string, criteria?: {
62
+ true?: string;
63
+ false?: string;
64
+ }): NoulQuestion;
65
+ /** Build a Choice question from an option map. */
66
+ export declare function choice(instructions: string, criteria: Record<string, string>): ChoiceQuestion;
67
+ /** Build a Score question from ordered labels, lowest first. */
68
+ export declare function score(instructions: string, criteria: string[]): ScoreQuestion;
69
+ /** Read a Noul answer as a probability, or null if Jev did not answer it. */
70
+ export declare function readNoul(answers: JevAnswers, id: string): number | null;
71
+ /** Read a Choice answer, or null if Jev did not answer it. */
72
+ export declare function readChoice(answers: JevAnswers, id: string): ChoiceAnswer | null;
73
+ /** Read a Score answer, or null if Jev did not answer it. */
74
+ export declare function readScore(answers: JevAnswers, id: string): ScoreAnswer | null;
75
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js ADDED
@@ -0,0 +1,35 @@
1
+ /** The Jev client contract: one state, many typed questions, typed answers. */
2
+ /** Build a Noul question. `criteria` sharpens what true and false mean. */
3
+ export function noul(instructions, criteria) {
4
+ return criteria ? { type: "noul", instructions, criteria } : { type: "noul", instructions };
5
+ }
6
+ /** Build a Choice question from an option map. */
7
+ export function choice(instructions, criteria) {
8
+ return { type: "choice", instructions, criteria };
9
+ }
10
+ /** Build a Score question from ordered labels, lowest first. */
11
+ export function score(instructions, criteria) {
12
+ if (criteria.length < 2) {
13
+ throw new Error("score() needs at least two criteria labels");
14
+ }
15
+ return { type: "score", instructions, criteria };
16
+ }
17
+ /** Read a Noul answer as a probability, or null if Jev did not answer it. */
18
+ export function readNoul(answers, id) {
19
+ const answer = answers[id];
20
+ if (!answer || !("noul" in answer))
21
+ return null;
22
+ const value = answer.noul;
23
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
24
+ }
25
+ /** Read a Choice answer, or null if Jev did not answer it. */
26
+ export function readChoice(answers, id) {
27
+ const answer = answers[id];
28
+ return answer && "choice" in answer ? answer : null;
29
+ }
30
+ /** Read a Score answer, or null if Jev did not answer it. */
31
+ export function readScore(answers, id) {
32
+ const answer = answers[id];
33
+ return answer && "score" in answer ? answer : null;
34
+ }
35
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAwE/E,2EAA2E;AAC3E,MAAM,UAAU,IAAI,CACnB,YAAoB,EACpB,QAA4C;IAE5C,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;AAC7F,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,MAAM,CACrB,YAAoB,EACpB,QAAgC;IAEhC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;AACnD,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,KAAK,CAAC,YAAoB,EAAE,QAAkB;IAC7D,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC;AAClD,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,QAAQ,CAAC,OAAmB,EAAE,EAAU;IACvD,MAAM,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3B,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAChD,MAAM,KAAK,GAAI,MAAqB,CAAC,IAAI,CAAC;IAC1C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3E,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,UAAU,CAAC,OAAmB,EAAE,EAAU;IACzD,MAAM,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3B,OAAO,MAAM,IAAI,QAAQ,IAAI,MAAM,CAAC,CAAC,CAAE,MAAuB,CAAC,CAAC,CAAC,IAAI,CAAC;AACvE,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,SAAS,CAAC,OAAmB,EAAE,EAAU;IACxD,MAAM,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3B,OAAO,MAAM,IAAI,OAAO,IAAI,MAAM,CAAC,CAAC,CAAE,MAAsB,CAAC,CAAC,CAAC,IAAI,CAAC;AACrE,CAAC"}
@@ -0,0 +1,13 @@
1
+ export * from "./client.js";
2
+ export * from "./adapters/typesafe.js";
3
+ export * from "./adapters/workers-ai.js";
4
+ export * from "./adapters/memory.js";
5
+ export * from "./algorithms/pairwise.js";
6
+ export * from "./algorithms/search.js";
7
+ export * from "./algorithms/aggregate.js";
8
+ export * from "./algorithms/cluster.js";
9
+ export * from "./algorithms/classify.js";
10
+ export * from "./algorithms/match.js";
11
+ export * from "./lib/chunk.js";
12
+ export * from "./lib/unionFind.js";
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAE5B,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AAErC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AAEtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC"}