@lapxo/obligations 0.4.0 → 0.4.1

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 (47) hide show
  1. package/README.md +32 -2
  2. package/TARGET.bound +78 -30
  3. package/dist/measures/capacity.d.ts +302 -0
  4. package/dist/measures/capacity.js +168 -0
  5. package/dist/measures/coincidence.d.ts +111 -0
  6. package/dist/measures/coincidence.js +81 -0
  7. package/dist/measures/error-events.js +23 -4
  8. package/dist/measures/fitting.d.ts +1 -1
  9. package/dist/measures/index.d.ts +6 -0
  10. package/dist/measures/index.js +3 -0
  11. package/dist/measures/unanimity-fit.d.ts +156 -0
  12. package/dist/measures/unanimity-fit.js +133 -0
  13. package/docs/img/cell.svg +28 -0
  14. package/docs/img/logo-fork.svg +6 -0
  15. package/docs/img/logo.svg +6 -0
  16. package/docs/img/price.svg +28 -0
  17. package/docs/img/thermometer.svg +28 -0
  18. package/docs/img/withdrawal.svg +28 -0
  19. package/docs/learn/in-phase.md +46 -0
  20. package/docs/learn/price.md +52 -0
  21. package/docs/learn/signature.md +50 -0
  22. package/docs/learn/thermometer.md +58 -0
  23. package/docs/learn/withdrawal.md +51 -0
  24. package/docs/measures.md +48 -0
  25. package/docs/paper.md +233 -0
  26. package/docs/reference.md +495 -0
  27. package/package.json +1 -1
  28. package/receipts.bound +113 -70
  29. package/samples/measures/capacity.json +71 -0
  30. package/samples/measures/coincidence.json +624 -0
  31. package/samples/measures/decisions.json +66 -0
  32. package/samples/measures/unanimity-fit.json +166 -0
  33. package/samples/no/installed-artifact.json +14 -2
  34. package/samples/yes/installed-artifact.json +32 -5
  35. package/vectors/measures/capacity.cli.json +97 -0
  36. package/vectors/measures/coincidence.cli.json +97 -0
  37. package/vectors/measures/decisions.cli.json +97 -0
  38. package/vectors/measures/descent.cli.json +19 -70
  39. package/vectors/measures/implementation.json +82 -0
  40. package/vectors/measures/installed-artifact.cli.json +28 -8
  41. package/vectors/measures/m3.cli.json +19 -70
  42. package/vectors/measures/observations.cli.json +19 -70
  43. package/vectors/measures/spectrum.cli.json +18 -69
  44. package/vectors/measures/unanimity-fit.cli.json +97 -0
  45. package/vectors/measures/unanimity.cli.json +19 -70
  46. package/samples/measures/m3-reader.mjs +0 -732
  47. package/samples/measures/reader.mjs +0 -424
@@ -1,9 +1,11 @@
1
1
  export function errorMatrix(rows, policy, requested) {
2
- if (!Number.isSafeInteger(policy.minCells) || policy.minCells < 2)
2
+ if (!policy || !Number.isSafeInteger(policy.minCells) || policy.minCells < 2)
3
3
  throw new Error('REFUSE·measure invalid minimum cells');
4
+ if (!Array.isArray(rows) || (requested !== undefined && !Array.isArray(requested)))
5
+ throw new Error('REFUSE·measure invalid event population');
4
6
  const cells = new Map();
5
7
  for (const row of rows) {
6
- if (!row.event || !row.origin || (row.error !== 0 && row.error !== 1))
8
+ if (!row || typeof row.event !== 'string' || !row.event || typeof row.origin !== 'string' || !row.origin || (row.error !== 0 && row.error !== 1))
7
9
  throw new Error('REFUSE·measure invalid error event');
8
10
  const at = cells.get(row.event) ?? new Map();
9
11
  if (at.has(row.origin) && at.get(row.origin) !== row.error)
@@ -12,7 +14,7 @@ export function errorMatrix(rows, policy, requested) {
12
14
  cells.set(row.event, at);
13
15
  }
14
16
  const origins = [...new Set(requested ?? rows.map(row => row.origin))].sort();
15
- if (origins.some(origin => !origin))
17
+ if (origins.some(origin => typeof origin !== 'string' || !origin))
16
18
  throw new Error('REFUSE·measure invalid origin');
17
19
  const events = [...cells.keys()].filter(event => origins.some(origin => cells.get(event).has(origin))).sort();
18
20
  if (events.length < policy.minCells || !origins.length)
@@ -22,10 +24,15 @@ export function errorMatrix(rows, policy, requested) {
22
24
  return { status: 'measured', origins, events, matrix: events.map(event => origins.map(origin => cells.get(event).get(origin))) };
23
25
  }
24
26
  export function covariance(reading) {
27
+ if (!reading || (reading.status !== 'measured' && reading.status !== 'unmeasured'))
28
+ throw new Error('REFUSE·measure invalid error matrix reading');
25
29
  if (reading.status === 'unmeasured')
26
30
  return reading;
31
+ if (!Array.isArray(reading.events) || !Array.isArray(reading.origins) || !Array.isArray(reading.matrix))
32
+ throw new Error('REFUSE·measure invalid error matrix');
27
33
  const n = reading.events.length, m = reading.origins.length;
28
- if (!n || !m || reading.matrix.length !== n || reading.matrix.some(row => row.length !== m || row.some(x => x !== 0 && x !== 1)) || new Set(reading.events).size !== n || new Set(reading.origins).size !== m)
34
+ if (!n || !m || reading.events.some(event => typeof event !== 'string' || !event) || reading.origins.some(origin => typeof origin !== 'string' || !origin) ||
35
+ reading.matrix.length !== n || reading.matrix.some(row => !Array.isArray(row) || row.length !== m || row.some(x => x !== 0 && x !== 1)) || new Set(reading.events).size !== n || new Set(reading.origins).size !== m)
29
36
  throw new Error('REFUSE·measure invalid error matrix');
30
37
  const mean = reading.origins.map((_, i) => reading.matrix.reduce((sum, row) => sum + row[i], 0) / n);
31
38
  const matrix = Array.from({ length: m }, (_, i) => Array.from({ length: m }, (_, j) => reading.matrix.reduce((sum, row) => sum + (row[i] - mean[i]) * (row[j] - mean[j]), 0) / n));
@@ -33,8 +40,20 @@ export function covariance(reading) {
33
40
  }
34
41
  export const errorCovariance = (rows, policy) => covariance(errorMatrix(rows, policy));
35
42
  export function participationRatio(reading) {
43
+ if (!reading || (reading.status !== 'measured' && reading.status !== 'unmeasured'))
44
+ throw new Error('REFUSE·measure invalid covariance reading');
36
45
  if (reading.status === 'unmeasured')
37
46
  return reading;
47
+ const n = reading.origins?.length;
48
+ if (!n || !Array.isArray(reading.matrix) || reading.matrix.length !== n || reading.matrix.some(row => !Array.isArray(row) || row.length !== n || row.some(value => !Number.isFinite(value))))
49
+ throw new Error('REFUSE·measure invalid covariance matrix');
50
+ for (let i = 0; i < n; i++) {
51
+ if (reading.matrix[i][i] < 0)
52
+ throw new Error('REFUSE·measure negative covariance diagonal');
53
+ for (let j = 0; j < n; j++)
54
+ if (reading.matrix[i][j] !== reading.matrix[j][i])
55
+ throw new Error('REFUSE·measure nonsymmetric covariance');
56
+ }
38
57
  const trace = reading.matrix.reduce((sum, row, i) => sum + row[i], 0);
39
58
  const square = reading.matrix.reduce((sum, row) => sum + row.reduce((n, value) => n + value * value, 0), 0);
40
59
  if (square === 0)
@@ -165,7 +165,7 @@ export declare function fitM3(rows: readonly ErrorEvent[], structure: FitStructu
165
165
  procedure: "constrained-log-least-squares/active-set@1";
166
166
  } | {
167
167
  bootstrap: {
168
- status: "unmeasured" | "measured";
168
+ status: "measured" | "unmeasured";
169
169
  cause: string | undefined;
170
170
  words: number;
171
171
  replicates: ({
@@ -16,3 +16,9 @@ export { experimentM3 } from './m3-experiment.ts';
16
16
  export type { M3ExperimentPolicy } from './m3-experiment.ts';
17
17
  export { fitM3 } from './fitting.ts';
18
18
  export type { FitStructure, FitPolicy } from './fitting.ts';
19
+ export { capacityBound, capacityP0, mutualInformation, unanimityNoFactor, decisionInformation } from './capacity.ts';
20
+ export type { CapacityModel, LogarithmPolicy, CapacityPolicy, DecisionRule } from './capacity.ts';
21
+ export { fitUnanimityModel } from './unanimity-fit.ts';
22
+ export type { UnanimityCount, UnanimityGroup, UnanimityCurve, UnanimityFitPolicy } from './unanimity-fit.ts';
23
+ export { coincidenceExcess } from './coincidence.ts';
24
+ export type { ValueReading, TruthReading, CoincidenceReference, CoincidencePolicy } from './coincidence.ts';
@@ -7,3 +7,6 @@ export { roundHalfEven } from "./rational.js";
7
7
  export { identifyM3 } from "./identification.js";
8
8
  export { experimentM3 } from "./m3-experiment.js";
9
9
  export { fitM3 } from "./fitting.js";
10
+ export { capacityBound, capacityP0, mutualInformation, unanimityNoFactor, decisionInformation } from "./capacity.js";
11
+ export { fitUnanimityModel } from "./unanimity-fit.js";
12
+ export { coincidenceExcess } from "./coincidence.js";
@@ -0,0 +1,156 @@
1
+ import { type RationalInput } from './rational.ts';
2
+ export type UnanimityCount = Readonly<{
3
+ k: number;
4
+ unanimous: number;
5
+ trials: number;
6
+ }>;
7
+ export type UnanimityGroup = Readonly<{
8
+ id: string;
9
+ outcomes: readonly Readonly<{
10
+ k: number;
11
+ unanimous: boolean;
12
+ }>[];
13
+ }>;
14
+ export type UnanimityCurve = Readonly<{
15
+ n: number;
16
+ lineage: string;
17
+ counts: readonly UnanimityCount[];
18
+ groups?: readonly UnanimityGroup[];
19
+ }>;
20
+ export type UnanimityFitPolicy = Readonly<{
21
+ procedure: 'exact-c-slices-on-declared-p-grid@1';
22
+ p: readonly RationalInput[];
23
+ tolerance: RationalInput;
24
+ budget: string;
25
+ bootstrap: Readonly<{
26
+ B: number;
27
+ seed: number;
28
+ prng: 'xorshift32';
29
+ randomWords: number;
30
+ }>;
31
+ }>;
32
+ export declare function fitUnanimityModel(curve: UnanimityCurve, policy: UnanimityFitPolicy): {
33
+ status: "unmeasured";
34
+ cause: string;
35
+ required: string;
36
+ model: "single-dominant-factor@1";
37
+ lineage: string;
38
+ cardinality: number;
39
+ policy: Readonly<{
40
+ procedure: "exact-c-slices-on-declared-p-grid@1";
41
+ p: readonly RationalInput[];
42
+ tolerance: RationalInput;
43
+ budget: string;
44
+ bootstrap: Readonly<{
45
+ B: number;
46
+ seed: number;
47
+ prng: "xorshift32";
48
+ randomWords: number;
49
+ }>;
50
+ }>;
51
+ meaning: "compatible with (c,p) under the declared model, on the declared p slices only";
52
+ workUnit: "rational-bit-and-group-bound";
53
+ } | {
54
+ compatible: {
55
+ p: Readonly<{
56
+ numerator: string;
57
+ denominator: string;
58
+ }>;
59
+ c: {
60
+ lo: Readonly<{
61
+ numerator: string;
62
+ denominator: string;
63
+ }>;
64
+ hi: Readonly<{
65
+ numerator: string;
66
+ denominator: string;
67
+ }>;
68
+ };
69
+ residuals: {
70
+ k: number;
71
+ at: "slice-midpoint";
72
+ predicted: Readonly<{
73
+ numerator: string;
74
+ denominator: string;
75
+ }>;
76
+ observed: Readonly<{
77
+ numerator: string;
78
+ denominator: string;
79
+ }>;
80
+ residual: Readonly<{
81
+ numerator: string;
82
+ denominator: string;
83
+ }>;
84
+ }[];
85
+ }[];
86
+ identification: {
87
+ status: "unmeasured";
88
+ cause: string;
89
+ diagnostics: string[];
90
+ };
91
+ uncertainty: {
92
+ status: "unmeasured";
93
+ cause: string;
94
+ words: number;
95
+ procedure?: undefined;
96
+ replicas?: undefined;
97
+ interpretation?: undefined;
98
+ } | {
99
+ status: "measured";
100
+ procedure: "paired-group-bootstrap-regions@1";
101
+ replicas: {
102
+ p: Readonly<{
103
+ numerator: string;
104
+ denominator: string;
105
+ }>;
106
+ c: {
107
+ lo: Readonly<{
108
+ numerator: string;
109
+ denominator: string;
110
+ }>;
111
+ hi: Readonly<{
112
+ numerator: string;
113
+ denominator: string;
114
+ }>;
115
+ };
116
+ residuals: {
117
+ k: number;
118
+ at: "slice-midpoint";
119
+ predicted: Readonly<{
120
+ numerator: string;
121
+ denominator: string;
122
+ }>;
123
+ observed: Readonly<{
124
+ numerator: string;
125
+ denominator: string;
126
+ }>;
127
+ residual: Readonly<{
128
+ numerator: string;
129
+ denominator: string;
130
+ }>;
131
+ }[];
132
+ }[][];
133
+ words: number;
134
+ interpretation: "empirical replicate regions; not a guaranteed confidence set";
135
+ cause?: undefined;
136
+ };
137
+ cause?: string | undefined;
138
+ status: "measured" | "unmeasured";
139
+ model: "single-dominant-factor@1";
140
+ lineage: string;
141
+ cardinality: number;
142
+ policy: Readonly<{
143
+ procedure: "exact-c-slices-on-declared-p-grid@1";
144
+ p: readonly RationalInput[];
145
+ tolerance: RationalInput;
146
+ budget: string;
147
+ bootstrap: Readonly<{
148
+ B: number;
149
+ seed: number;
150
+ prng: "xorshift32";
151
+ randomWords: number;
152
+ }>;
153
+ }>;
154
+ meaning: "compatible with (c,p) under the declared model, on the declared p slices only";
155
+ workUnit: "rational-bit-and-group-bound";
156
+ };
@@ -0,0 +1,133 @@
1
+ import { add, sub, mul, div, q, pow, zero, one, pack, probability } from "./rational.js";
2
+ const refuse = (cause) => { throw new Error('REFUSE·unanimity-fit ' + cause); };
3
+ const compare = (a, b) => a[0] * b[1] < b[0] * a[1] ? -1 : a[0] * b[1] > b[0] * a[1] ? 1 : 0;
4
+ function privateRate(k, n, p) {
5
+ return add(pow(sub(one, p), k), div(pow(p, k), pow(q(BigInt(n - 1)), k - 1)));
6
+ }
7
+ function slices(counts, n, grid, tolerance) {
8
+ return grid.flatMap(p => {
9
+ let lo = zero, hi = one;
10
+ for (const row of counts) {
11
+ const observed = q(BigInt(row.unanimous), BigInt(row.trials)), a = privateRate(row.k, n, p), b = sub(one, a);
12
+ if (b[0] === 0n) {
13
+ if (compare(observed, sub(one, tolerance)) < 0)
14
+ return [];
15
+ continue;
16
+ }
17
+ const lower = div(sub(sub(observed, tolerance), a), b), upper = div(sub(add(observed, tolerance), a), b);
18
+ if (compare(lower, lo) > 0)
19
+ lo = lower;
20
+ if (compare(upper, hi) < 0)
21
+ hi = upper;
22
+ if (compare(lo, hi) > 0)
23
+ return [];
24
+ }
25
+ const midpoint = div(add(lo, hi), q(2n));
26
+ return [{ p: pack(p), c: { lo: pack(lo), hi: pack(hi) }, residuals: counts.map(row => {
27
+ const predicted = add(midpoint, mul(sub(one, midpoint), privateRate(row.k, n, p)));
28
+ return { k: row.k, at: 'slice-midpoint', predicted: pack(predicted),
29
+ observed: pack(q(BigInt(row.unanimous), BigInt(row.trials))),
30
+ residual: pack(sub(q(BigInt(row.unanimous), BigInt(row.trials)), predicted)) };
31
+ }) }];
32
+ });
33
+ }
34
+ export function fitUnanimityModel(curve, policy) {
35
+ if (!curve || !Number.isSafeInteger(curve.n) || curve.n < 2 || typeof curve.lineage !== 'string' || !curve.lineage ||
36
+ !Array.isArray(curve.counts) || !curve.counts.length)
37
+ refuse('one declared lineage, cardinality and counts required');
38
+ if (curve.counts.some(row => !row || !Number.isSafeInteger(row.k) || row.k < 1 || !Number.isSafeInteger(row.trials) || row.trials < 1 ||
39
+ !Number.isSafeInteger(row.unanimous) || row.unanimous < 0 || row.unanimous > row.trials))
40
+ refuse('invalid size counts');
41
+ const counts = [...curve.counts].sort((a, b) => a.k - b.k);
42
+ if (new Set(counts.map(row => row.k)).size !== counts.length)
43
+ refuse('invalid or duplicate size counts');
44
+ if (!policy || policy.procedure !== 'exact-c-slices-on-declared-p-grid@1' || !Array.isArray(policy.p) || !policy.p.length ||
45
+ typeof policy.budget !== 'string' || !/^\d+$/.test(policy.budget))
46
+ refuse('declared fitting procedure and budget required');
47
+ const grid = policy.p.map(probability).sort(compare), tolerance = probability(policy.tolerance), bootstrap = policy.bootstrap;
48
+ if (new Set(grid.map(p => p.join('/'))).size !== grid.length)
49
+ refuse('duplicate p slice');
50
+ if (!bootstrap || bootstrap.prng !== 'xorshift32' || !Number.isInteger(bootstrap.seed) || bootstrap.seed < 1 || bootstrap.seed > 0xffffffff ||
51
+ !Number.isSafeInteger(bootstrap.B) || bootstrap.B < 0 || !Number.isSafeInteger(bootstrap.randomWords) || bootstrap.randomWords < 0)
52
+ refuse('invalid bootstrap declaration');
53
+ const work = grid.reduce((sum, p) => sum + counts.reduce((total, row) => total + BigInt(row.k) *
54
+ (BigInt(p[1].toString(2).length) + BigInt(BigInt(curve.n - 1).toString(2).length) + 2n), 0n), 0n) * (BigInt(bootstrap.B) + 1n) +
55
+ BigInt(curve.groups?.length ?? 0) * (BigInt(counts.length) + 1n) * (BigInt(bootstrap.B) + 1n);
56
+ const metadata = { model: 'single-dominant-factor@1', lineage: curve.lineage, cardinality: curve.n, policy,
57
+ meaning: 'compatible with (c,p) under the declared model, on the declared p slices only',
58
+ workUnit: 'rational-bit-and-group-bound' };
59
+ if (work > BigInt(policy.budget))
60
+ return { ...metadata, status: 'unmeasured', cause: 'unanimity-fit/budget', required: String(work) };
61
+ const compatible = slices(counts, curve.n, grid, tolerance);
62
+ let groups;
63
+ if (curve.groups !== undefined) {
64
+ if (!Array.isArray(curve.groups) || !curve.groups.length || curve.groups.some(group => !group) || new Set(curve.groups.map(group => group.id)).size !== curve.groups.length)
65
+ refuse('invalid or duplicate sampling groups');
66
+ for (const group of curve.groups) {
67
+ if (!group || typeof group.id !== 'string' || !group.id || !Array.isArray(group.outcomes) || group.outcomes.length !== counts.length ||
68
+ group.outcomes.some((item) => !item || typeof item.unanimous !== 'boolean' || !counts.some(row => row.k === item.k)) ||
69
+ new Set(group.outcomes.map((item) => item.k)).size !== counts.length)
70
+ refuse('complete paired size outcomes required');
71
+ }
72
+ groups = [...curve.groups].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
73
+ for (const row of counts)
74
+ if (row.trials !== groups.length || row.unanimous !== groups.filter(group => group.outcomes.find(item => item.k === row.k).unanimous).length)
75
+ refuse('group outcomes do not reproduce counts');
76
+ }
77
+ const causes = [];
78
+ if (counts.filter(row => row.k > 1).length < 2)
79
+ causes.push('too few informative sizes');
80
+ if (counts.every(row => row.unanimous === row.trials))
81
+ causes.push('perfect unanimity cannot distinguish p=0 from c=1');
82
+ if (curve.n === 2 && compatible.some(slice => compatible.some(other => compare(add([BigInt(slice.p.numerator), BigInt(slice.p.denominator)], [BigInt(other.p.numerator), BigInt(other.p.denominator)]), one) === 0 &&
83
+ slice.p.numerator + '/' + slice.p.denominator !== other.p.numerator + '/' + other.p.denominator)))
84
+ causes.push('binary p versus 1-p ambiguity');
85
+ if (!compatible.length)
86
+ causes.push('no compatible parameter slice under the declared tolerance');
87
+ const replicas = [], wordsLimit = bootstrap.randomWords;
88
+ let x = bootstrap.seed >>> 0, words = 0;
89
+ const exhausted = Symbol('unanimity-fit/random-words');
90
+ function index(N) {
91
+ const limit = Math.floor(4294967296 / N) * N;
92
+ for (;;) {
93
+ if (words >= wordsLimit)
94
+ throw exhausted;
95
+ words++;
96
+ x ^= x << 13;
97
+ x ^= x >>> 17;
98
+ x ^= x << 5;
99
+ const value = x >>> 0;
100
+ if (value < limit)
101
+ return value % N;
102
+ }
103
+ }
104
+ let uncertaintyCause;
105
+ if (!groups || bootstrap.B === 0)
106
+ uncertaintyCause = groups ? 'bootstrap not requested' : 'sampling groups not handed; size dependence unknown';
107
+ else {
108
+ if (groups.length > 4294967296)
109
+ refuse('sampling population exceeds declared PRNG index range');
110
+ try {
111
+ for (let b = 0; b < bootstrap.B; b++) {
112
+ const hits = counts.map(() => 0);
113
+ for (let i = 0; i < groups.length; i++) {
114
+ const group = groups[index(groups.length)];
115
+ counts.forEach((row, j) => { if (group.outcomes.find(item => item.k === row.k).unanimous)
116
+ hits[j]++; });
117
+ }
118
+ replicas.push(slices(counts.map((row, i) => ({ ...row, unanimous: hits[i] })), curve.n, grid, tolerance));
119
+ }
120
+ }
121
+ catch (error) {
122
+ if (error !== exhausted)
123
+ throw error;
124
+ uncertaintyCause = 'unanimity-fit/random-words';
125
+ }
126
+ }
127
+ return { ...metadata, status: causes.length ? 'unmeasured' : 'measured',
128
+ ...(causes.length ? { cause: causes.join('; ') } : {}), compatible,
129
+ identification: { status: 'unmeasured', cause: 'finite slices do not certify continuous parameter identification', diagnostics: causes },
130
+ uncertainty: uncertaintyCause ? { status: 'unmeasured', cause: uncertaintyCause, words } :
131
+ { status: 'measured', procedure: 'paired-group-bootstrap-regions@1', replicas, words,
132
+ interpretation: 'empirical replicate regions; not a guaranteed confidence set' } };
133
+ }
@@ -0,0 +1,28 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 178" width="640" height="178" role="img" aria-labelledby="title desc">
2
+ <title id="title">A cell</title>
3
+ <desc id="desc">Two origins on one scale: a claims 2 to 9 and b claims 5 to 12; what they hold together runs from a floor of 5 to a ceiling of 9.</desc>
4
+ <style>
5
+ text{font:14px ui-sans-serif,-apple-system,"Segoe UI",Helvetica,Arial,sans-serif;fill:#59636e}
6
+ .claim{fill:#8c959f}.held{fill:#2da44e}.pole{fill:#2da44e;font-weight:600}.axis,.tick{stroke:#8c959f;stroke-width:1}.touch{stroke:#2da44e;stroke-width:1;stroke-dasharray:3 3}
7
+ @media (prefers-color-scheme:dark){text{fill:#9198a1}}
8
+ </style>
9
+ <line class="touch" x1="269.3" y1="12" x2="269.3" y2="126"/>
10
+ <line class="touch" x1="442.7" y1="12" x2="442.7" y2="126"/>
11
+ <text x="82" y="32" text-anchor="end">a</text>
12
+ <rect class="claim" x="139.3" y="18" width="303.4" height="18" rx="4"/>
13
+ <text x="82" y="66" text-anchor="end">b</text>
14
+ <rect class="claim" x="269.3" y="52" width="303.4" height="18" rx="4"/>
15
+ <text x="82" y="100" text-anchor="end">held</text>
16
+ <rect class="held" x="269.3" y="86" width="173.4" height="18" rx="4"/>
17
+ <line class="axis" x1="96" y1="126" x2="616" y2="126"/>
18
+ <line class="tick" x1="139.3" y1="126" x2="139.3" y2="131"/>
19
+ <text x="139.3" y="148" text-anchor="middle">2</text>
20
+ <line class="tick" x1="269.3" y1="126" x2="269.3" y2="131"/>
21
+ <text x="269.3" y="148" text-anchor="middle">5</text>
22
+ <line class="tick" x1="442.7" y1="126" x2="442.7" y2="131"/>
23
+ <text x="442.7" y="148" text-anchor="middle">9</text>
24
+ <line class="tick" x1="572.7" y1="126" x2="572.7" y2="131"/>
25
+ <text x="572.7" y="148" text-anchor="middle">12</text>
26
+ <text class="pole" x="269.3" y="168" text-anchor="middle">floor</text>
27
+ <text class="pole" x="442.7" y="168" text-anchor="middle">ceiling</text>
28
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64" role="img" aria-labelledby="title">
2
+ <title id="title">2 origins and the bond where they touch</title>
3
+ <path d="M32 17.58 A17 17 0 0 1 32 46.42 A17 17 0 0 1 32 17.58 Z" fill="#cf222e"/>
4
+ <path d="M32 17.58 A17 17 0 1 0 32 46.42" fill="none" stroke="#8c959f" stroke-width="4" stroke-linecap="round"/>
5
+ <path d="M32 17.58 A17 17 0 1 1 32 46.42" fill="none" stroke="#8c959f" stroke-width="4" stroke-linecap="round"/>
6
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64" role="img" aria-labelledby="title">
2
+ <title id="title">2 origins and the bond where they touch</title>
3
+ <path d="M32 17.58 A17 17 0 0 1 32 46.42 A17 17 0 0 1 32 17.58 Z" fill="#2da44e"/>
4
+ <path d="M32 17.58 A17 17 0 1 0 32 46.42" fill="none" stroke="#8c959f" stroke-width="4" stroke-linecap="round"/>
5
+ <path d="M32 17.58 A17 17 0 1 1 32 46.42" fill="none" stroke="#8c959f" stroke-width="4" stroke-linecap="round"/>
6
+ </svg>
@@ -0,0 +1,28 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 178" width="640" height="178" role="img" aria-labelledby="title desc">
2
+ <title id="title">A cell</title>
3
+ <desc id="desc">Two origins on one scale: seller claims 2 to 9 and buyer claims 5 to 12; what they hold together runs from a floor of 5 to a ceiling of 9.</desc>
4
+ <style>
5
+ text{font:14px ui-sans-serif,-apple-system,"Segoe UI",Helvetica,Arial,sans-serif;fill:#59636e}
6
+ .claim{fill:#8c959f}.held{fill:#2da44e}.pole{fill:#2da44e;font-weight:600}.axis,.tick{stroke:#8c959f;stroke-width:1}.touch{stroke:#2da44e;stroke-width:1;stroke-dasharray:3 3}
7
+ @media (prefers-color-scheme:dark){text{fill:#9198a1}}
8
+ </style>
9
+ <line class="touch" x1="269.3" y1="12" x2="269.3" y2="126"/>
10
+ <line class="touch" x1="442.7" y1="12" x2="442.7" y2="126"/>
11
+ <text x="82" y="32" text-anchor="end">seller</text>
12
+ <rect class="claim" x="139.3" y="18" width="303.4" height="18" rx="4"/>
13
+ <text x="82" y="66" text-anchor="end">buyer</text>
14
+ <rect class="claim" x="269.3" y="52" width="303.4" height="18" rx="4"/>
15
+ <text x="82" y="100" text-anchor="end">held</text>
16
+ <rect class="held" x="269.3" y="86" width="173.4" height="18" rx="4"/>
17
+ <line class="axis" x1="96" y1="126" x2="616" y2="126"/>
18
+ <line class="tick" x1="139.3" y1="126" x2="139.3" y2="131"/>
19
+ <text x="139.3" y="148" text-anchor="middle">2</text>
20
+ <line class="tick" x1="269.3" y1="126" x2="269.3" y2="131"/>
21
+ <text x="269.3" y="148" text-anchor="middle">5</text>
22
+ <line class="tick" x1="442.7" y1="126" x2="442.7" y2="131"/>
23
+ <text x="442.7" y="148" text-anchor="middle">9</text>
24
+ <line class="tick" x1="572.7" y1="126" x2="572.7" y2="131"/>
25
+ <text x="572.7" y="148" text-anchor="middle">12</text>
26
+ <text class="pole" x="269.3" y="168" text-anchor="middle">floor</text>
27
+ <text class="pole" x="442.7" y="168" text-anchor="middle">ceiling</text>
28
+ </svg>
@@ -0,0 +1,28 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 228" width="640" height="228" role="img" aria-labelledby="title desc">
2
+ <title id="title">A cell</title>
3
+ <desc id="desc">Four origins on one scale: a claims 19.8 to 20.2, b claims 19.9 to 20.3, c claims 19.7 to 20.1 and d claims 24 to 24.4; their claims do not meet.</desc>
4
+ <style>
5
+ text{font:14px ui-sans-serif,-apple-system,"Segoe UI",Helvetica,Arial,sans-serif;fill:#59636e}
6
+ .claim{fill:#8c959f}.held{fill:#2da44e}.pole{fill:#2da44e;font-weight:600}.axis,.tick{stroke:#8c959f;stroke-width:1}.touch{stroke:#2da44e;stroke-width:1;stroke-dasharray:3 3}
7
+ @media (prefers-color-scheme:dark){text{fill:#9198a1}}
8
+ </style>
9
+ <text x="82" y="32" text-anchor="end">a</text>
10
+ <rect class="claim" x="181.4" y="18" width="31" height="18" rx="4"/>
11
+ <text x="82" y="66" text-anchor="end">b</text>
12
+ <rect class="claim" x="189.1" y="52" width="31.1" height="18" rx="4"/>
13
+ <text x="82" y="100" text-anchor="end">c</text>
14
+ <rect class="claim" x="173.6" y="86" width="31.1" height="18" rx="4"/>
15
+ <text x="82" y="134" text-anchor="end">d</text>
16
+ <rect class="claim" x="507.3" y="120" width="31.1" height="18" rx="4"/>
17
+ <text x="82" y="168" text-anchor="end">held</text>
18
+ <text x="96" y="168">their claims do not meet</text>
19
+ <line class="axis" x1="96" y1="194" x2="616" y2="194"/>
20
+ <line class="tick" x1="173.6" y1="194" x2="173.6" y2="199"/>
21
+ <text x="173.6" y="216" text-anchor="middle">19.7</text>
22
+ <line class="tick" x1="204.7" y1="194" x2="204.7" y2="199"/>
23
+ <text x="204.7" y="216" text-anchor="middle">20.1</text>
24
+ <line class="tick" x1="507.3" y1="194" x2="507.3" y2="199"/>
25
+ <text x="507.3" y="216" text-anchor="middle">24</text>
26
+ <line class="tick" x1="538.4" y1="194" x2="538.4" y2="199"/>
27
+ <text x="538.4" y="216" text-anchor="middle">24.4</text>
28
+ </svg>
@@ -0,0 +1,28 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 178" width="640" height="178" role="img" aria-labelledby="title desc">
2
+ <title id="title">A cell</title>
3
+ <desc id="desc">Two origins on one scale: a claims 2 to 9 and b claims 5 to 12; what they hold together runs from a floor of 5 to a ceiling of 9.</desc>
4
+ <style>
5
+ text{font:14px ui-sans-serif,-apple-system,"Segoe UI",Helvetica,Arial,sans-serif;fill:#59636e}
6
+ .claim{fill:#8c959f}.held{fill:#2da44e}.pole{fill:#2da44e;font-weight:600}.axis,.tick{stroke:#8c959f;stroke-width:1}.touch{stroke:#2da44e;stroke-width:1;stroke-dasharray:3 3}
7
+ @media (prefers-color-scheme:dark){text{fill:#9198a1}}
8
+ </style>
9
+ <line class="touch" x1="269.3" y1="12" x2="269.3" y2="126"/>
10
+ <line class="touch" x1="442.7" y1="12" x2="442.7" y2="126"/>
11
+ <text x="82" y="32" text-anchor="end">a</text>
12
+ <rect class="claim" x="139.3" y="18" width="303.4" height="18" rx="4"/>
13
+ <text x="82" y="66" text-anchor="end">b</text>
14
+ <rect class="claim" x="269.3" y="52" width="303.4" height="18" rx="4"/>
15
+ <text x="82" y="100" text-anchor="end">held</text>
16
+ <rect class="held" x="269.3" y="86" width="173.4" height="18" rx="4"/>
17
+ <line class="axis" x1="96" y1="126" x2="616" y2="126"/>
18
+ <line class="tick" x1="139.3" y1="126" x2="139.3" y2="131"/>
19
+ <text x="139.3" y="148" text-anchor="middle">2</text>
20
+ <line class="tick" x1="269.3" y1="126" x2="269.3" y2="131"/>
21
+ <text x="269.3" y="148" text-anchor="middle">5</text>
22
+ <line class="tick" x1="442.7" y1="126" x2="442.7" y2="131"/>
23
+ <text x="442.7" y="148" text-anchor="middle">9</text>
24
+ <line class="tick" x1="572.7" y1="126" x2="572.7" y2="131"/>
25
+ <text x="572.7" y="148" text-anchor="middle">12</text>
26
+ <text class="pole" x="269.3" y="168" text-anchor="middle">floor</text>
27
+ <text class="pole" x="442.7" y="168" text-anchor="middle">ceiling</text>
28
+ </svg>
@@ -0,0 +1,46 @@
1
+ # In phase
2
+
3
+ A claim carries a size and a direction, how much it narrows and the turn it landed on, and a withdrawal is the same size the other way: two hundred claims in phase make the square of their number and the same two hundred strewn make its order, while a write and its withdrawal at one epoch leave nothing and at different epochs do not cancel.
4
+
5
+ ## Run it
6
+
7
+ ```ts
8
+ import { coherence, interfere } from '@lapxo/obligations/views/field';
9
+
10
+ const span = { lo: 0, hi: 0 };
11
+ let held = 11;
12
+ const next = (): number => { held = (held * 1103515245 + 12345) % 2147483648; return held / 2147483648; };
13
+ const together = Array.from({ length: 32 }, (_, i) => ({ origin: `o${i}`, epoch: 8, span }));
14
+ const strewn = Array.from({ length: 32 }, (_, i) => ({ origin: `o${i}`, epoch: Math.floor(next() * 8), span }));
15
+
16
+ console.log('in phase ', interfere(together, 8), 'coherence', coherence(together, 8).toFixed(2));
17
+ console.log('strewn ', interfere(strewn, 8).toFixed(0), 'coherence', coherence(strewn, 8).toFixed(2));
18
+ console.log('their number is 32, and its square is', 32 ** 2);
19
+ console.log('why claims that land at one turn of the period add as the square of their number, and the same claims strewn across it add as its order');
20
+ ```
21
+
22
+ ```
23
+ in phase 1024 coherence 1.00
24
+ strewn 50 coherence 0.22
25
+ their number is 32, and its square is 1024
26
+ why claims that land at one turn of the period add as the square of their number, and the same claims strewn across it add as its order
27
+ ```
28
+
29
+ Its origins meet.
30
+
31
+ ## What it rests on
32
+
33
+ ```mermaid
34
+ flowchart LR
35
+ c0["coherence"]
36
+ c1["interfere"]
37
+ l0(["amplitude has sign and phase"])
38
+ c0 --> l0
39
+ c1 --> l0
40
+ classDef shown fill:#2da44e,color:#ffffff,stroke:#2da44e
41
+ class l0 shown
42
+ ```
43
+
44
+ ## Source
45
+
46
+ [Its source](../../examples/release/in-phase.ts) is one of the examples of obligations, and it runs as it is written, against the built package, with nothing compiled for it.
@@ -0,0 +1,52 @@
1
+ # Price
2
+
3
+ <p align="center"><img src="../img/price.svg" alt="Two origins on one scale: seller claims 2 to 9 and buyer claims 5 to 12; what they hold together runs from a floor of 5 to a ceiling of 9." width="640"></p>
4
+
5
+ A claim from one origin is potential; a cell is information only where two independent origins touch it and their intervals meet.
6
+
7
+ ## Run it
8
+
9
+ ```ts
10
+ import { chain, disagree, freedom, meetAt, origins, point, unit } from '@lapxo/obligations';
11
+
12
+ const said = (cell: Parameters<typeof meetAt>[0]): string =>
13
+ (origins(cell) < 2 ? 'grey' : disagree(cell) ? 'split' : 'agreed');
14
+
15
+ const price = point('price', 0, [
16
+ { origin: 'seller', span: { lo: 2, hi: 9 } },
17
+ { origin: 'buyer', span: { lo: 5, hi: 12 } },
18
+ ]);
19
+ const scale = chain(Array.from({ length: 16 }, (_, i) => `l${i}`));
20
+
21
+ console.log('verdict ', said(price));
22
+ console.log('they hold ', JSON.stringify(meetAt(price)));
23
+ console.log('still free', freedom(scale, unit('price', { floor: 'l5', ceiling: 'l9' })).toFixed(2), 'bits');
24
+ console.log('why a seller and a buyer are two origins; where their marks meet is a price, and what is left between the marks is what nobody has decided yet');
25
+ ```
26
+
27
+ ```
28
+ verdict agreed
29
+ they hold {"lo":5,"hi":9}
30
+ still free 2.32 bits
31
+ why a seller and a buyer are two origins; where their marks meet is a price, and what is left between the marks is what nobody has decided yet
32
+ ```
33
+
34
+ Its origins meet.
35
+
36
+ ## What it rests on
37
+
38
+ ```mermaid
39
+ flowchart LR
40
+ c0["point"]
41
+ c1["unit"]
42
+ l0(["encounter"])
43
+ l1(["debit in bits"])
44
+ c0 --> l0
45
+ c1 --> l1
46
+ classDef shown fill:#2da44e,color:#ffffff,stroke:#2da44e
47
+ class l0 shown
48
+ ```
49
+
50
+ ## Source
51
+
52
+ [Its source](../../examples/release/price.ts) is one of the examples of obligations, and it runs as it is written, against the built package, with nothing compiled for it.