@lucern/confidence 1.0.24 → 1.0.26
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/dist/index.js +37 -18
- package/dist/index.js.map +1 -1
- package/dist/proof-attestation.json +1 -1
- package/dist/v1/codec.js.map +1 -1
- package/dist/v1/index.js +37 -18
- package/dist/v1/index.js.map +1 -1
- package/dist/v1/operations/approximation.js +37 -18
- package/dist/v1/operations/approximation.js.map +1 -1
- package/dist/v1/operations/bridge/index.js.map +1 -1
- package/dist/v1/operations/canonical.js.map +1 -1
- package/dist/v1/operations/dynamics/cascade.js.map +1 -1
- package/dist/v1/operations/dynamics/decay.js.map +1 -1
- package/dist/v1/operations/dynamics/defeat.js +26 -9
- package/dist/v1/operations/dynamics/defeat.js.map +1 -1
- package/dist/v1/operations/dynamics/propagation.js +26 -9
- package/dist/v1/operations/dynamics/propagation.js.map +1 -1
- package/dist/v1/operations/dynamics/revision.js.map +1 -1
- package/dist/v1/operations/index.js.map +1 -1
- package/dist/v1/operations/lucern.js +26 -9
- package/dist/v1/operations/lucern.js.map +1 -1
- package/dist/v1/operations/scoring.js.map +1 -1
- package/dist/v1/operations/subjectiveLogic/index.js +37 -18
- package/dist/v1/operations/subjectiveLogic/index.js.map +1 -1
- package/dist/v1/operations/temporalDecay.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/v1/operations/subjectiveLogic/index.ts","../../../src/v1/operations/scoring.ts"],"names":["opinion"],"mappings":"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","file":"scoring.js","sourcesContent":["import type { SLOpinion } from \"../../types\";\n\nexport function opinion(\n belief: number,\n disbelief: number,\n uncertainty: number,\n baseRate: number\n): SLOpinion {\n const b = Number.isFinite(belief) ? Math.max(0, belief) : 0;\n const d = Number.isFinite(disbelief) ? Math.max(0, disbelief) : 0;\n const u = Number.isFinite(uncertainty) ? Math.max(0, uncertainty) : 0;\n const a = Math.max(0, Math.min(1, baseRate));\n const sum = b + d + u;\n\n if (sum === 0) {\n return { b: 0, d: 0, u: 1, a } as SLOpinion;\n }\n\n return {\n b: b / sum,\n d: d / sum,\n u: u / sum,\n a,\n } as SLOpinion;\n}\n\nexport function mkOpinion(\n belief: number,\n disbelief: number,\n uncertainty: number,\n baseRate: number\n): SLOpinion {\n return opinion(belief, disbelief, uncertainty, baseRate);\n}\n\nexport function vacuous(baseRate: number): SLOpinion {\n return mkOpinion(0, 0, 1, baseRate);\n}\n\nexport function dogmatic(probability: number, baseRate: number): SLOpinion {\n const p = Math.max(0, Math.min(1, probability));\n return mkOpinion(p, 1 - p, 0, baseRate);\n}\n\nexport function project(o: SLOpinion): number {\n return o.b + o.a * o.u;\n}\n\nexport function confidenceLevel(o: SLOpinion): \"high\" | \"medium\" | \"low\" {\n const projected = project(o);\n if (o.u > 0.5) {\n return \"low\";\n }\n if (projected >= 0.8 && o.u < 0.2) {\n return \"high\";\n }\n if (projected >= 0.6) {\n return \"medium\";\n }\n return \"low\";\n}\n\nexport function cumulativeFusion(left: SLOpinion, right: SLOpinion): SLOpinion {\n if (left.u === 0 && right.u === 0) {\n return opinion(\n (left.b + right.b) / 2,\n (left.d + right.d) / 2,\n 0,\n (left.a + right.a) / 2\n );\n }\n\n const k = left.u + right.u - left.u * right.u;\n if (k === 0) {\n return vacuous((left.a + right.a) / 2);\n }\n\n return opinion(\n (left.b * right.u + right.b * left.u) / k,\n (left.d * right.u + right.d * left.u) / k,\n (left.u * right.u) / k,\n (left.a + right.a) / 2\n );\n}\n\nexport function averagingFusion(left: SLOpinion, right: SLOpinion): SLOpinion {\n if (left.u === 0 && right.u === 0) {\n return opinion(\n (left.b + right.b) / 2,\n (left.d + right.d) / 2,\n 0,\n (left.a + right.a) / 2\n );\n }\n\n const k = left.u + right.u;\n if (k === 0) {\n return vacuous((left.a + right.a) / 2);\n }\n\n return opinion(\n (left.b * right.u + right.b * left.u) / k,\n (left.d * right.u + right.d * left.u) / k,\n (2 * left.u * right.u) / k,\n (left.a + right.a) / 2\n );\n}\n\nexport function trustDiscount(sourceOpinion: SLOpinion, trust: number): SLOpinion {\n const weight = Math.max(0, Math.min(1, Math.abs(trust)));\n return opinion(\n weight * sourceOpinion.b,\n weight * sourceOpinion.d,\n 1 - weight * (sourceOpinion.b + sourceOpinion.d),\n sourceOpinion.a\n );\n}\n\nconst EPSILON = 1e-9;\n\nfunction childBaseRateFallback(\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate: number | undefined\n): number {\n if (fallbackBaseRate !== undefined) {\n return Math.max(0, Math.min(1, fallbackBaseRate));\n }\n\n if (Math.abs(ifTrue.a - ifFalse.a) <= EPSILON) {\n return ifTrue.a;\n }\n\n return (ifTrue.a + ifFalse.a) / 2;\n}\n\nfunction computeConditionalDeductionBaseRate(\n opinionA: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate: number\n): number {\n const denominator =\n 1 - opinionA.a * ifTrue.u - (1 - opinionA.a) * ifFalse.u;\n\n if (ifTrue.u + ifFalse.u < 2 - EPSILON && Math.abs(denominator) > EPSILON) {\n const baseRate =\n (opinionA.a * ifTrue.b + (1 - opinionA.a) * ifFalse.b) / denominator;\n if (baseRate >= -EPSILON && baseRate <= 1 + EPSILON) {\n return Math.max(0, Math.min(1, baseRate));\n }\n }\n\n return fallbackBaseRate;\n}\n\nfunction safeCorrectionTerm(\n numerator: number,\n denominator: number\n): number | undefined {\n if (Math.abs(denominator) <= EPSILON) {\n return undefined;\n }\n\n const value = numerator / denominator;\n if (!Number.isFinite(value)) {\n return undefined;\n }\n\n return Math.max(0, value);\n}\n\nexport function conditionalDeduction(\n opinionA: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate?: number\n): SLOpinion {\n const fallbackChildBaseRate = childBaseRateFallback(\n ifTrue,\n ifFalse,\n fallbackBaseRate\n );\n const childBaseRate = computeConditionalDeductionBaseRate(\n opinionA,\n ifTrue,\n ifFalse,\n fallbackChildBaseRate\n );\n const projectedAntecedent = project(opinionA);\n const projectedAntecedentComplement = 1 - projectedAntecedent;\n const intermediateBelief =\n opinionA.b * ifTrue.b +\n opinionA.d * ifFalse.b +\n opinionA.u * (ifTrue.b * opinionA.a + ifFalse.b * (1 - opinionA.a));\n const intermediateDisbelief =\n opinionA.b * ifTrue.d +\n opinionA.d * ifFalse.d +\n opinionA.u * (ifTrue.d * opinionA.a + ifFalse.d * (1 - opinionA.a));\n const intermediateUncertainty =\n opinionA.b * ifTrue.u +\n opinionA.d * ifFalse.u +\n opinionA.u * (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));\n const projectedVacuousDeduction =\n ifTrue.b * opinionA.a +\n ifFalse.b * (1 - opinionA.a) +\n childBaseRate *\n (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));\n const projectedConditionalA =\n ifTrue.b + childBaseRate * (1 - ifTrue.b - ifTrue.d);\n let correction = 0;\n\n if (\n (ifTrue.b > ifFalse.b && ifTrue.d > ifFalse.d) ||\n (ifTrue.b <= ifFalse.b && ifTrue.d <= ifFalse.d)\n ) {\n correction = 0;\n } else if (ifTrue.b > ifFalse.b && ifTrue.d <= ifFalse.d) {\n const beliefGap = ifTrue.b - ifFalse.b;\n const disbeliefGap = ifFalse.d - ifTrue.d;\n\n if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateBelief - ifTrue.b),\n projectedAntecedent * childBaseRate\n ) ?? 0;\n } else if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent > opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d) * beliefGap,\n projectedAntecedentComplement * childBaseRate * disbeliefGap\n ) ?? 0;\n } else if (\n projectedVacuousDeduction > projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) *\n opinionA.u *\n (intermediateBelief - ifTrue.b) *\n disbeliefGap,\n projectedAntecedent * (1 - childBaseRate) * beliefGap\n ) ?? 0;\n } else {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) * opinionA.u * (intermediateDisbelief - ifTrue.d),\n projectedAntecedentComplement * (1 - childBaseRate)\n ) ?? 0;\n }\n } else {\n const beliefGap = ifFalse.b - ifTrue.b;\n const disbeliefGap = ifTrue.d - ifFalse.d;\n\n if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) *\n opinionA.u *\n (intermediateDisbelief - ifTrue.d) *\n beliefGap,\n projectedAntecedent * childBaseRate * disbeliefGap\n ) ?? 0;\n } else if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent > opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) * opinionA.u * (intermediateBelief - ifTrue.b),\n projectedAntecedentComplement * childBaseRate\n ) ?? 0;\n } else if (\n projectedVacuousDeduction > projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d),\n projectedAntecedent * (1 - childBaseRate)\n ) ?? 0;\n } else {\n correction =\n safeCorrectionTerm(\n opinionA.a *\n opinionA.u *\n (intermediateBelief - ifTrue.b) *\n disbeliefGap,\n projectedAntecedentComplement * (1 - childBaseRate) * beliefGap\n ) ?? 0;\n }\n }\n\n return opinion(\n intermediateBelief - childBaseRate * correction,\n intermediateDisbelief - (1 - childBaseRate) * correction,\n intermediateUncertainty + correction,\n childBaseRate\n );\n}\n\n/**\n * Abductive inference over a conditional.\n * Given an opinion on Y and conditionals P(Y|X), P(Y|~X), infer an opinion on X.\n */\nexport function conditionalAbduction(\n opinionY: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n baseRateX: number\n): SLOpinion {\n const priorX = Math.max(0, Math.min(1, baseRateX));\n const probabilityY = project(opinionY);\n const probabilityGivenTrue = project(ifTrue);\n const probabilityGivenFalse = project(ifFalse);\n\n const posteriorIfYDenominator =\n probabilityGivenTrue * priorX +\n probabilityGivenFalse * (1 - priorX);\n const posteriorIfY =\n posteriorIfYDenominator === 0\n ? priorX\n : (probabilityGivenTrue * priorX) / posteriorIfYDenominator;\n\n const posteriorIfNotYDenominator =\n (1 - probabilityGivenTrue) * priorX +\n (1 - probabilityGivenFalse) * (1 - priorX);\n const posteriorIfNotY =\n posteriorIfNotYDenominator === 0\n ? priorX\n : ((1 - probabilityGivenTrue) * priorX) / posteriorIfNotYDenominator;\n\n const projectedX =\n probabilityY * posteriorIfY + (1 - probabilityY) * posteriorIfNotY;\n const uncertainty = Math.max(\n opinionY.u * 0.5,\n probabilityY * ifTrue.u + (1 - probabilityY) * ifFalse.u\n );\n\n return opinion(\n projectedX * (1 - uncertainty),\n (1 - projectedX) * (1 - uncertainty),\n uncertainty,\n priorX\n );\n}\n\nexport function negate(o: SLOpinion): SLOpinion {\n return mkOpinion(o.d, o.b, o.u, 1 - o.a);\n}\n\nexport function constraintFusion(\n left: SLOpinion,\n right: SLOpinion,\n mode: \"pressure\" | \"redistribute\" = \"pressure\"\n): { o1: SLOpinion; o2: SLOpinion } {\n if (mode === \"redistribute\") {\n const leftProjected = project(left);\n const rightProjected = project(right);\n const total = leftProjected + rightProjected;\n\n if (total <= 1) {\n return { o1: left, o2: right };\n }\n\n const scale = 1 / total;\n return {\n o1: opinion(\n left.b * scale,\n left.d + left.b * (1 - scale),\n left.u,\n left.a\n ),\n o2: opinion(\n right.b * scale,\n right.d + right.b * (1 - scale),\n right.u,\n right.a\n ),\n };\n }\n\n const pressureLeft = right.b * 0.5;\n const pressureRight = left.b * 0.5;\n\n return {\n o1: opinion(\n left.b - pressureLeft * 0.3,\n left.d + pressureLeft * 0.3,\n left.u,\n left.a\n ),\n o2: opinion(\n right.b - pressureRight * 0.3,\n right.d + pressureRight * 0.3,\n right.u,\n right.a\n ),\n };\n}\n\nexport function evidenceBalance(o: SLOpinion): number {\n const total = o.b + o.d;\n if (total === 0) {\n return 0;\n }\n return (o.b - o.d) / total;\n}\n\nexport function areTensioned(left: SLOpinion, right: SLOpinion): boolean {\n return (\n project(left) > 0.5 &&\n project(right) > 0.5 &&\n (left.d > 0.2 || right.d > 0.2)\n );\n}\n\nexport function informationGain(o: SLOpinion): number {\n if (o.u === 0) {\n return 0;\n }\n if (o.u === 1) {\n return 1;\n }\n return o.u * (1 - Math.abs(o.b - o.d));\n}\n","import type { Opinion, SLOpinion, StoredOpinionFields } from \"../types\";\nimport { dogmatic, mkOpinion, vacuous } from \"./subjectiveLogic\";\n\nfunction finiteNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction requiredOpinionNumber(label: string, ...values: unknown[]): number {\n for (const value of values) {\n const numberValue = finiteNumber(value);\n if (numberValue !== undefined) {\n return numberValue;\n }\n }\n throw new Error(`Opinion record is missing required ${label}.`);\n}\n\nexport function clamp01(value: number): number {\n return Math.max(0, Math.min(1, value));\n}\n\nexport function confidenceFromOpinion(opinion: Opinion): number {\n return clamp01(opinion.b + opinion.a * opinion.u);\n}\n\nexport function confidenceFromSL(\n belief: number,\n _disbelief: number,\n uncertainty: number,\n baseRate: number\n): number {\n return confidenceFromOpinion({\n b: belief,\n d: _disbelief,\n u: uncertainty,\n a: baseRate,\n });\n}\n\nexport function toStoredOpinionFields(opinion: Opinion): StoredOpinionFields {\n return {\n belief: opinion.b,\n disbelief: opinion.d,\n uncertainty: opinion.u,\n baseRate: opinion.a,\n };\n}\n\nexport function readOpinionFromRecord(\n source: unknown\n): SLOpinion {\n const record =\n source && typeof source === \"object\"\n ? (source as Record<string, unknown>)\n : {};\n\n return mkOpinion(\n requiredOpinionNumber(\n \"belief\",\n record.b,\n record.belief,\n record.slBelief,\n record.opinion_b\n ),\n requiredOpinionNumber(\n \"disbelief\",\n record.d,\n record.disbelief,\n record.slDisbelief,\n record.opinion_d\n ),\n requiredOpinionNumber(\n \"uncertainty\",\n record.u,\n record.uncertainty,\n record.slUncertainty,\n record.opinion_u\n ),\n requiredOpinionNumber(\n \"baseRate\",\n record.a,\n record.baseRate,\n record.slBaseRate,\n record.opinion_a\n )\n );\n}\n\nexport type OpinionFromScalarMode =\n | \"base_rate\"\n | \"dogmatic\"\n | \"projected_with_u\";\n\nexport type OpinionFromScalarOptions =\n | { baseRate?: never; uncertainty?: never }\n | { baseRate: number; uncertainty?: never }\n | { baseRate: number; uncertainty: number };\n\nexport function opinionFromScalar(\n value: number,\n mode: \"base_rate\",\n options?: { baseRate?: never; uncertainty?: never }\n): SLOpinion;\nexport function opinionFromScalar(\n value: number,\n mode: \"dogmatic\",\n options: { baseRate: number; uncertainty?: never }\n): SLOpinion;\nexport function opinionFromScalar(\n value: number,\n mode: \"projected_with_u\",\n options: { baseRate: number; uncertainty: number }\n): SLOpinion;\nexport function opinionFromScalar(\n value: number,\n mode: OpinionFromScalarMode,\n options?: OpinionFromScalarOptions\n): SLOpinion {\n const clampedValue = clamp01(value);\n const baseRate =\n options?.baseRate === undefined ? undefined : clamp01(options.baseRate);\n\n switch (mode) {\n case \"base_rate\":\n return mkOpinion(0, 0, 1, clampedValue);\n case \"dogmatic\":\n if (baseRate === undefined) {\n throw new Error(\"opinionFromScalar(value, \\\"dogmatic\\\") requires options.baseRate.\");\n }\n return mkOpinion(clampedValue, 1 - clampedValue, 0, baseRate);\n case \"projected_with_u\": {\n if (baseRate === undefined) {\n throw new Error(\n \"opinionFromScalar(value, \\\"projected_with_u\\\") requires options.baseRate.\"\n );\n }\n const uncertainty = options?.uncertainty;\n if (uncertainty === undefined) {\n throw new Error(\n \"opinionFromScalar(value, \\\"projected_with_u\\\") requires options.uncertainty.\"\n );\n }\n const clampedUncertainty = clamp01(uncertainty);\n const evidenceWeight = 1 - clampedUncertainty;\n return mkOpinion(\n clampedValue * evidenceWeight,\n (1 - clampedValue) * evidenceWeight,\n clampedUncertainty,\n baseRate\n );\n }\n }\n\n throw new Error(`Unsupported opinionFromScalar mode: ${mode}`);\n}\n\n/**\n * @deprecated Use opinionFromScalar(value, \"dogmatic\", { baseRate }) instead.\n */\nexport function toDogmaticOpinion(\n confidence: number,\n baseRate: number\n): SLOpinion {\n return opinionFromScalar(confidence, \"dogmatic\", { baseRate });\n}\n\n/** Interpret p as a prior with no observed evidence. */\nexport function opinionFromBaseRate(probability: number): SLOpinion {\n return vacuous(clamp01(probability));\n}\n\n/** Interpret p as a certainty-equivalent projected probability. */\nexport function opinionFromDogmatic(\n probability: number,\n baseRate: number\n): SLOpinion {\n return dogmatic(clamp01(probability), clamp01(baseRate));\n}\n\n/**\n * Interpret p as a projected probability with an explicit uncertainty bucket.\n * The resulting opinion always projects back to p.\n */\nexport function opinionFromProjected(\n probability: number,\n uncertainty: number,\n baseRate: number\n): SLOpinion {\n const p = clamp01(probability);\n const u = clamp01(uncertainty);\n const remainingMass = 1 - u;\n return mkOpinion(p * remainingMass, (1 - p) * remainingMass, u, clamp01(baseRate));\n}\n\nexport function hasProjectedOpinionChanged(\n current: Opinion,\n next: Opinion,\n tolerance: number = 0.01\n): boolean {\n return Math.abs(confidenceFromOpinion(next) - confidenceFromOpinion(current)) >=\n tolerance;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/v1/operations/subjectiveLogic/index.ts","../../../src/v1/operations/scoring.ts"],"names":["opinion"],"mappings":"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","file":"scoring.js","sourcesContent":["import type { SLOpinion } from \"../../types\";\n\nexport function opinion(\n belief: number,\n disbelief: number,\n uncertainty: number,\n baseRate: number\n): SLOpinion {\n const b = Number.isFinite(belief) ? Math.max(0, belief) : 0;\n const d = Number.isFinite(disbelief) ? Math.max(0, disbelief) : 0;\n const u = Number.isFinite(uncertainty) ? Math.max(0, uncertainty) : 0;\n const a = Math.max(0, Math.min(1, baseRate));\n const sum = b + d + u;\n\n if (sum === 0) {\n return { b: 0, d: 0, u: 1, a } as SLOpinion;\n }\n\n return {\n b: b / sum,\n d: d / sum,\n u: u / sum,\n a,\n } as SLOpinion;\n}\n\nexport function mkOpinion(\n belief: number,\n disbelief: number,\n uncertainty: number,\n baseRate: number\n): SLOpinion {\n return opinion(belief, disbelief, uncertainty, baseRate);\n}\n\nexport function vacuous(baseRate: number): SLOpinion {\n return mkOpinion(0, 0, 1, baseRate);\n}\n\nexport function dogmatic(probability: number, baseRate: number): SLOpinion {\n const p = Math.max(0, Math.min(1, probability));\n return mkOpinion(p, 1 - p, 0, baseRate);\n}\n\nexport function project(o: SLOpinion): number {\n return o.b + o.a * o.u;\n}\n\nexport function confidenceLevel(o: SLOpinion): \"high\" | \"medium\" | \"low\" {\n const projected = project(o);\n if (o.u > 0.5) {\n return \"low\";\n }\n if (projected >= 0.8 && o.u < 0.2) {\n return \"high\";\n }\n if (projected >= 0.6) {\n return \"medium\";\n }\n return \"low\";\n}\n\nconst VACUOUS_IDENTITY_EPSILON = 1e-12;\n\n/**\n * Associative, vacuous-identity-preserving base rate for a fused opinion.\n *\n * The legacy `(left.a + right.a) / 2` arithmetic mean was the shared root of\n * RR.7 F1 (projected-confidence non-associativity) and F2 (a vacuous opinion of\n * a different base rate was not a fusion identity): averaging always pulled the\n * fused base rate toward the other operand even when that operand carried no\n * evidence. Subjective Logic requires every opinion over the same frame to share\n * one canonical base rate, so a correct fusion never *invents* a new base rate\n * from the operands' priors. We therefore:\n *\n * - return the informative operand's base rate when exactly one operand is\n * vacuous (the vacuous operand contributes no prior), making `vacuous(a)` a\n * true identity for any `a`; and\n * - require equal base rates otherwise (the canonical-frame contract). When\n * they coincide the result is that shared value — trivially associative.\n *\n * If two informative opinions carry genuinely different base rates they are not\n * opinions over the same frame and must be reconciled before fusion; we fall\n * back to the arithmetic mean ONLY in that ill-posed case to stay total, and the\n * property suite documents that this path is outside the order-independence\n * guarantee.\n */\nfunction fusedBaseRate(left: SLOpinion, right: SLOpinion): number {\n const leftVacuous = 1 - left.u <= VACUOUS_IDENTITY_EPSILON;\n const rightVacuous = 1 - right.u <= VACUOUS_IDENTITY_EPSILON;\n if (leftVacuous && !rightVacuous) {\n return right.a;\n }\n if (rightVacuous && !leftVacuous) {\n return left.a;\n }\n if (Math.abs(left.a - right.a) <= VACUOUS_IDENTITY_EPSILON) {\n return left.a;\n }\n return (left.a + right.a) / 2;\n}\n\nexport function cumulativeFusion(left: SLOpinion, right: SLOpinion): SLOpinion {\n const a = fusedBaseRate(left, right);\n\n // F2: a vacuous operand is the identity element of cumulative fusion. Return\n // the other operand verbatim (including its base rate) so fusion with the\n // vacuous opinion is a true no-op regardless of differing priors.\n if (1 - left.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion(right.b, right.d, right.u, a);\n }\n if (1 - right.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion(left.b, left.d, left.u, a);\n }\n\n // F4: dogmatic pair handled via the ε-limit of the cumulative rule rather than\n // the standalone `(b+d)/2` shortcut. As both uncertainties shrink at the same\n // rate, the cumulative formula's `(b_L·u_R + b_R·u_L)/k` term converges to the\n // arithmetic mean of the masses; deriving it from the same limit the interior\n // formula uses keeps mass-associativity intact (no special-case discontinuity).\n if (left.u <= VACUOUS_IDENTITY_EPSILON && right.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion((left.b + right.b) / 2, (left.d + right.d) / 2, 0, a);\n }\n\n const k = left.u + right.u - left.u * right.u;\n if (k === 0) {\n return vacuous(a);\n }\n\n return opinion(\n (left.b * right.u + right.b * left.u) / k,\n (left.d * right.u + right.d * left.u) / k,\n (left.u * right.u) / k,\n a\n );\n}\n\nexport function averagingFusion(left: SLOpinion, right: SLOpinion): SLOpinion {\n const a = fusedBaseRate(left, right);\n\n // F2: vacuous identity, mirroring cumulativeFusion.\n if (1 - left.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion(right.b, right.d, right.u, a);\n }\n if (1 - right.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion(left.b, left.d, left.u, a);\n }\n\n // F4: dogmatic pair via the ε-limit of the averaging rule.\n if (left.u <= VACUOUS_IDENTITY_EPSILON && right.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion((left.b + right.b) / 2, (left.d + right.d) / 2, 0, a);\n }\n\n const k = left.u + right.u;\n if (k === 0) {\n return vacuous(a);\n }\n\n return opinion(\n (left.b * right.u + right.b * left.u) / k,\n (left.d * right.u + right.d * left.u) / k,\n (2 * left.u * right.u) / k,\n a\n );\n}\n\nexport function trustDiscount(sourceOpinion: SLOpinion, trust: number): SLOpinion {\n const weight = Math.max(0, Math.min(1, Math.abs(trust)));\n return opinion(\n weight * sourceOpinion.b,\n weight * sourceOpinion.d,\n 1 - weight * (sourceOpinion.b + sourceOpinion.d),\n sourceOpinion.a\n );\n}\n\nconst EPSILON = 1e-9;\n\nfunction childBaseRateFallback(\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate: number | undefined\n): number {\n if (fallbackBaseRate !== undefined) {\n return Math.max(0, Math.min(1, fallbackBaseRate));\n }\n\n if (Math.abs(ifTrue.a - ifFalse.a) <= EPSILON) {\n return ifTrue.a;\n }\n\n return (ifTrue.a + ifFalse.a) / 2;\n}\n\nfunction computeConditionalDeductionBaseRate(\n opinionA: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate: number\n): number {\n const denominator =\n 1 - opinionA.a * ifTrue.u - (1 - opinionA.a) * ifFalse.u;\n\n if (ifTrue.u + ifFalse.u < 2 - EPSILON && Math.abs(denominator) > EPSILON) {\n const baseRate =\n (opinionA.a * ifTrue.b + (1 - opinionA.a) * ifFalse.b) / denominator;\n if (baseRate >= -EPSILON && baseRate <= 1 + EPSILON) {\n return Math.max(0, Math.min(1, baseRate));\n }\n }\n\n return fallbackBaseRate;\n}\n\nfunction safeCorrectionTerm(\n numerator: number,\n denominator: number\n): number | undefined {\n if (Math.abs(denominator) <= EPSILON) {\n return undefined;\n }\n\n const value = numerator / denominator;\n if (!Number.isFinite(value)) {\n return undefined;\n }\n\n return Math.max(0, value);\n}\n\nexport function conditionalDeduction(\n opinionA: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate?: number\n): SLOpinion {\n const fallbackChildBaseRate = childBaseRateFallback(\n ifTrue,\n ifFalse,\n fallbackBaseRate\n );\n const childBaseRate = computeConditionalDeductionBaseRate(\n opinionA,\n ifTrue,\n ifFalse,\n fallbackChildBaseRate\n );\n const projectedAntecedent = project(opinionA);\n const projectedAntecedentComplement = 1 - projectedAntecedent;\n const intermediateBelief =\n opinionA.b * ifTrue.b +\n opinionA.d * ifFalse.b +\n opinionA.u * (ifTrue.b * opinionA.a + ifFalse.b * (1 - opinionA.a));\n const intermediateDisbelief =\n opinionA.b * ifTrue.d +\n opinionA.d * ifFalse.d +\n opinionA.u * (ifTrue.d * opinionA.a + ifFalse.d * (1 - opinionA.a));\n const intermediateUncertainty =\n opinionA.b * ifTrue.u +\n opinionA.d * ifFalse.u +\n opinionA.u * (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));\n const projectedVacuousDeduction =\n ifTrue.b * opinionA.a +\n ifFalse.b * (1 - opinionA.a) +\n childBaseRate *\n (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));\n const projectedConditionalA =\n ifTrue.b + childBaseRate * (1 - ifTrue.b - ifTrue.d);\n let correction = 0;\n\n if (\n (ifTrue.b > ifFalse.b && ifTrue.d > ifFalse.d) ||\n (ifTrue.b <= ifFalse.b && ifTrue.d <= ifFalse.d)\n ) {\n correction = 0;\n } else if (ifTrue.b > ifFalse.b && ifTrue.d <= ifFalse.d) {\n const beliefGap = ifTrue.b - ifFalse.b;\n const disbeliefGap = ifFalse.d - ifTrue.d;\n\n if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateBelief - ifTrue.b),\n projectedAntecedent * childBaseRate\n ) ?? 0;\n } else if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent > opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d) * beliefGap,\n projectedAntecedentComplement * childBaseRate * disbeliefGap\n ) ?? 0;\n } else if (\n projectedVacuousDeduction > projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) *\n opinionA.u *\n (intermediateBelief - ifTrue.b) *\n disbeliefGap,\n projectedAntecedent * (1 - childBaseRate) * beliefGap\n ) ?? 0;\n } else {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) * opinionA.u * (intermediateDisbelief - ifTrue.d),\n projectedAntecedentComplement * (1 - childBaseRate)\n ) ?? 0;\n }\n } else {\n const beliefGap = ifFalse.b - ifTrue.b;\n const disbeliefGap = ifTrue.d - ifFalse.d;\n\n if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) *\n opinionA.u *\n (intermediateDisbelief - ifTrue.d) *\n beliefGap,\n projectedAntecedent * childBaseRate * disbeliefGap\n ) ?? 0;\n } else if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent > opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) * opinionA.u * (intermediateBelief - ifTrue.b),\n projectedAntecedentComplement * childBaseRate\n ) ?? 0;\n } else if (\n projectedVacuousDeduction > projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d),\n projectedAntecedent * (1 - childBaseRate)\n ) ?? 0;\n } else {\n correction =\n safeCorrectionTerm(\n opinionA.a *\n opinionA.u *\n (intermediateBelief - ifTrue.b) *\n disbeliefGap,\n projectedAntecedentComplement * (1 - childBaseRate) * beliefGap\n ) ?? 0;\n }\n }\n\n return opinion(\n intermediateBelief - childBaseRate * correction,\n intermediateDisbelief - (1 - childBaseRate) * correction,\n intermediateUncertainty + correction,\n childBaseRate\n );\n}\n\n/**\n * Abductive inference over a conditional.\n * Given an opinion on Y and conditionals P(Y|X), P(Y|~X), infer an opinion on X.\n */\nexport function conditionalAbduction(\n opinionY: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n baseRateX: number\n): SLOpinion {\n const priorX = Math.max(0, Math.min(1, baseRateX));\n const probabilityY = project(opinionY);\n const probabilityGivenTrue = project(ifTrue);\n const probabilityGivenFalse = project(ifFalse);\n\n const posteriorIfYDenominator =\n probabilityGivenTrue * priorX +\n probabilityGivenFalse * (1 - priorX);\n const posteriorIfY =\n posteriorIfYDenominator === 0\n ? priorX\n : (probabilityGivenTrue * priorX) / posteriorIfYDenominator;\n\n const posteriorIfNotYDenominator =\n (1 - probabilityGivenTrue) * priorX +\n (1 - probabilityGivenFalse) * (1 - priorX);\n const posteriorIfNotY =\n posteriorIfNotYDenominator === 0\n ? priorX\n : ((1 - probabilityGivenTrue) * priorX) / posteriorIfNotYDenominator;\n\n const projectedX =\n probabilityY * posteriorIfY + (1 - probabilityY) * posteriorIfNotY;\n const uncertainty = Math.max(\n opinionY.u * 0.5,\n probabilityY * ifTrue.u + (1 - probabilityY) * ifFalse.u\n );\n\n return opinion(\n projectedX * (1 - uncertainty),\n (1 - projectedX) * (1 - uncertainty),\n uncertainty,\n priorX\n );\n}\n\nexport function negate(o: SLOpinion): SLOpinion {\n return mkOpinion(o.d, o.b, o.u, 1 - o.a);\n}\n\nexport function constraintFusion(\n left: SLOpinion,\n right: SLOpinion,\n mode: \"pressure\" | \"redistribute\" = \"pressure\"\n): { o1: SLOpinion; o2: SLOpinion } {\n if (mode === \"redistribute\") {\n const leftProjected = project(left);\n const rightProjected = project(right);\n const total = leftProjected + rightProjected;\n\n if (total <= 1) {\n return { o1: left, o2: right };\n }\n\n const scale = 1 / total;\n return {\n o1: opinion(\n left.b * scale,\n left.d + left.b * (1 - scale),\n left.u,\n left.a\n ),\n o2: opinion(\n right.b * scale,\n right.d + right.b * (1 - scale),\n right.u,\n right.a\n ),\n };\n }\n\n const pressureLeft = right.b * 0.5;\n const pressureRight = left.b * 0.5;\n\n return {\n o1: opinion(\n left.b - pressureLeft * 0.3,\n left.d + pressureLeft * 0.3,\n left.u,\n left.a\n ),\n o2: opinion(\n right.b - pressureRight * 0.3,\n right.d + pressureRight * 0.3,\n right.u,\n right.a\n ),\n };\n}\n\nexport function evidenceBalance(o: SLOpinion): number {\n const total = o.b + o.d;\n if (total === 0) {\n return 0;\n }\n return (o.b - o.d) / total;\n}\n\nexport function areTensioned(left: SLOpinion, right: SLOpinion): boolean {\n return (\n project(left) > 0.5 &&\n project(right) > 0.5 &&\n (left.d > 0.2 || right.d > 0.2)\n );\n}\n\nexport function informationGain(o: SLOpinion): number {\n if (o.u === 0) {\n return 0;\n }\n if (o.u === 1) {\n return 1;\n }\n return o.u * (1 - Math.abs(o.b - o.d));\n}\n","import type { Opinion, SLOpinion, StoredOpinionFields } from \"../types\";\nimport { dogmatic, mkOpinion, vacuous } from \"./subjectiveLogic\";\n\nfunction finiteNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction requiredOpinionNumber(label: string, ...values: unknown[]): number {\n for (const value of values) {\n const numberValue = finiteNumber(value);\n if (numberValue !== undefined) {\n return numberValue;\n }\n }\n throw new Error(`Opinion record is missing required ${label}.`);\n}\n\nexport function clamp01(value: number): number {\n return Math.max(0, Math.min(1, value));\n}\n\nexport function confidenceFromOpinion(opinion: Opinion): number {\n return clamp01(opinion.b + opinion.a * opinion.u);\n}\n\nexport function confidenceFromSL(\n belief: number,\n _disbelief: number,\n uncertainty: number,\n baseRate: number\n): number {\n return confidenceFromOpinion({\n b: belief,\n d: _disbelief,\n u: uncertainty,\n a: baseRate,\n });\n}\n\nexport function toStoredOpinionFields(opinion: Opinion): StoredOpinionFields {\n return {\n belief: opinion.b,\n disbelief: opinion.d,\n uncertainty: opinion.u,\n baseRate: opinion.a,\n };\n}\n\nexport function readOpinionFromRecord(\n source: unknown\n): SLOpinion {\n const record =\n source && typeof source === \"object\"\n ? (source as Record<string, unknown>)\n : {};\n\n return mkOpinion(\n requiredOpinionNumber(\n \"belief\",\n record.b,\n record.belief,\n record.slBelief,\n record.opinion_b\n ),\n requiredOpinionNumber(\n \"disbelief\",\n record.d,\n record.disbelief,\n record.slDisbelief,\n record.opinion_d\n ),\n requiredOpinionNumber(\n \"uncertainty\",\n record.u,\n record.uncertainty,\n record.slUncertainty,\n record.opinion_u\n ),\n requiredOpinionNumber(\n \"baseRate\",\n record.a,\n record.baseRate,\n record.slBaseRate,\n record.opinion_a\n )\n );\n}\n\nexport type OpinionFromScalarMode =\n | \"base_rate\"\n | \"dogmatic\"\n | \"projected_with_u\";\n\nexport type OpinionFromScalarOptions =\n | { baseRate?: never; uncertainty?: never }\n | { baseRate: number; uncertainty?: never }\n | { baseRate: number; uncertainty: number };\n\nexport function opinionFromScalar(\n value: number,\n mode: \"base_rate\",\n options?: { baseRate?: never; uncertainty?: never }\n): SLOpinion;\nexport function opinionFromScalar(\n value: number,\n mode: \"dogmatic\",\n options: { baseRate: number; uncertainty?: never }\n): SLOpinion;\nexport function opinionFromScalar(\n value: number,\n mode: \"projected_with_u\",\n options: { baseRate: number; uncertainty: number }\n): SLOpinion;\nexport function opinionFromScalar(\n value: number,\n mode: OpinionFromScalarMode,\n options?: OpinionFromScalarOptions\n): SLOpinion {\n const clampedValue = clamp01(value);\n const baseRate =\n options?.baseRate === undefined ? undefined : clamp01(options.baseRate);\n\n switch (mode) {\n case \"base_rate\":\n return mkOpinion(0, 0, 1, clampedValue);\n case \"dogmatic\":\n if (baseRate === undefined) {\n throw new Error(\"opinionFromScalar(value, \\\"dogmatic\\\") requires options.baseRate.\");\n }\n return mkOpinion(clampedValue, 1 - clampedValue, 0, baseRate);\n case \"projected_with_u\": {\n if (baseRate === undefined) {\n throw new Error(\n \"opinionFromScalar(value, \\\"projected_with_u\\\") requires options.baseRate.\"\n );\n }\n const uncertainty = options?.uncertainty;\n if (uncertainty === undefined) {\n throw new Error(\n \"opinionFromScalar(value, \\\"projected_with_u\\\") requires options.uncertainty.\"\n );\n }\n const clampedUncertainty = clamp01(uncertainty);\n const evidenceWeight = 1 - clampedUncertainty;\n return mkOpinion(\n clampedValue * evidenceWeight,\n (1 - clampedValue) * evidenceWeight,\n clampedUncertainty,\n baseRate\n );\n }\n }\n\n throw new Error(`Unsupported opinionFromScalar mode: ${mode}`);\n}\n\n/**\n * @deprecated Use opinionFromScalar(value, \"dogmatic\", { baseRate }) instead.\n */\nexport function toDogmaticOpinion(\n confidence: number,\n baseRate: number\n): SLOpinion {\n return opinionFromScalar(confidence, \"dogmatic\", { baseRate });\n}\n\n/** Interpret p as a prior with no observed evidence. */\nexport function opinionFromBaseRate(probability: number): SLOpinion {\n return vacuous(clamp01(probability));\n}\n\n/** Interpret p as a certainty-equivalent projected probability. */\nexport function opinionFromDogmatic(\n probability: number,\n baseRate: number\n): SLOpinion {\n return dogmatic(clamp01(probability), clamp01(baseRate));\n}\n\n/**\n * Interpret p as a projected probability with an explicit uncertainty bucket.\n * The resulting opinion always projects back to p.\n */\nexport function opinionFromProjected(\n probability: number,\n uncertainty: number,\n baseRate: number\n): SLOpinion {\n const p = clamp01(probability);\n const u = clamp01(uncertainty);\n const remainingMass = 1 - u;\n return mkOpinion(p * remainingMass, (1 - p) * remainingMass, u, clamp01(baseRate));\n}\n\nexport function hasProjectedOpinionChanged(\n current: Opinion,\n next: Opinion,\n tolerance: number = 0.01\n): boolean {\n return Math.abs(confidenceFromOpinion(next) - confidenceFromOpinion(current)) >=\n tolerance;\n}\n"]}
|
|
@@ -41,44 +41,63 @@ function confidenceLevel(o) {
|
|
|
41
41
|
}
|
|
42
42
|
return "low";
|
|
43
43
|
}
|
|
44
|
+
var VACUOUS_IDENTITY_EPSILON = 1e-12;
|
|
45
|
+
function fusedBaseRate(left, right) {
|
|
46
|
+
const leftVacuous = 1 - left.u <= VACUOUS_IDENTITY_EPSILON;
|
|
47
|
+
const rightVacuous = 1 - right.u <= VACUOUS_IDENTITY_EPSILON;
|
|
48
|
+
if (leftVacuous && !rightVacuous) {
|
|
49
|
+
return right.a;
|
|
50
|
+
}
|
|
51
|
+
if (rightVacuous && !leftVacuous) {
|
|
52
|
+
return left.a;
|
|
53
|
+
}
|
|
54
|
+
if (Math.abs(left.a - right.a) <= VACUOUS_IDENTITY_EPSILON) {
|
|
55
|
+
return left.a;
|
|
56
|
+
}
|
|
57
|
+
return (left.a + right.a) / 2;
|
|
58
|
+
}
|
|
44
59
|
function cumulativeFusion(left, right) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
60
|
+
const a = fusedBaseRate(left, right);
|
|
61
|
+
if (1 - left.u <= VACUOUS_IDENTITY_EPSILON) {
|
|
62
|
+
return opinion(right.b, right.d, right.u, a);
|
|
63
|
+
}
|
|
64
|
+
if (1 - right.u <= VACUOUS_IDENTITY_EPSILON) {
|
|
65
|
+
return opinion(left.b, left.d, left.u, a);
|
|
66
|
+
}
|
|
67
|
+
if (left.u <= VACUOUS_IDENTITY_EPSILON && right.u <= VACUOUS_IDENTITY_EPSILON) {
|
|
68
|
+
return opinion((left.b + right.b) / 2, (left.d + right.d) / 2, 0, a);
|
|
52
69
|
}
|
|
53
70
|
const k = left.u + right.u - left.u * right.u;
|
|
54
71
|
if (k === 0) {
|
|
55
|
-
return vacuous(
|
|
72
|
+
return vacuous(a);
|
|
56
73
|
}
|
|
57
74
|
return opinion(
|
|
58
75
|
(left.b * right.u + right.b * left.u) / k,
|
|
59
76
|
(left.d * right.u + right.d * left.u) / k,
|
|
60
77
|
left.u * right.u / k,
|
|
61
|
-
|
|
78
|
+
a
|
|
62
79
|
);
|
|
63
80
|
}
|
|
64
81
|
function averagingFusion(left, right) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
const a = fusedBaseRate(left, right);
|
|
83
|
+
if (1 - left.u <= VACUOUS_IDENTITY_EPSILON) {
|
|
84
|
+
return opinion(right.b, right.d, right.u, a);
|
|
85
|
+
}
|
|
86
|
+
if (1 - right.u <= VACUOUS_IDENTITY_EPSILON) {
|
|
87
|
+
return opinion(left.b, left.d, left.u, a);
|
|
88
|
+
}
|
|
89
|
+
if (left.u <= VACUOUS_IDENTITY_EPSILON && right.u <= VACUOUS_IDENTITY_EPSILON) {
|
|
90
|
+
return opinion((left.b + right.b) / 2, (left.d + right.d) / 2, 0, a);
|
|
72
91
|
}
|
|
73
92
|
const k = left.u + right.u;
|
|
74
93
|
if (k === 0) {
|
|
75
|
-
return vacuous(
|
|
94
|
+
return vacuous(a);
|
|
76
95
|
}
|
|
77
96
|
return opinion(
|
|
78
97
|
(left.b * right.u + right.b * left.u) / k,
|
|
79
98
|
(left.d * right.u + right.d * left.u) / k,
|
|
80
99
|
2 * left.u * right.u / k,
|
|
81
|
-
|
|
100
|
+
a
|
|
82
101
|
);
|
|
83
102
|
}
|
|
84
103
|
function trustDiscount(sourceOpinion, trust) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/v1/operations/subjectiveLogic/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { SLOpinion } from \"../../types\";\n\nexport function opinion(\n belief: number,\n disbelief: number,\n uncertainty: number,\n baseRate: number\n): SLOpinion {\n const b = Number.isFinite(belief) ? Math.max(0, belief) : 0;\n const d = Number.isFinite(disbelief) ? Math.max(0, disbelief) : 0;\n const u = Number.isFinite(uncertainty) ? Math.max(0, uncertainty) : 0;\n const a = Math.max(0, Math.min(1, baseRate));\n const sum = b + d + u;\n\n if (sum === 0) {\n return { b: 0, d: 0, u: 1, a } as SLOpinion;\n }\n\n return {\n b: b / sum,\n d: d / sum,\n u: u / sum,\n a,\n } as SLOpinion;\n}\n\nexport function mkOpinion(\n belief: number,\n disbelief: number,\n uncertainty: number,\n baseRate: number\n): SLOpinion {\n return opinion(belief, disbelief, uncertainty, baseRate);\n}\n\nexport function vacuous(baseRate: number): SLOpinion {\n return mkOpinion(0, 0, 1, baseRate);\n}\n\nexport function dogmatic(probability: number, baseRate: number): SLOpinion {\n const p = Math.max(0, Math.min(1, probability));\n return mkOpinion(p, 1 - p, 0, baseRate);\n}\n\nexport function project(o: SLOpinion): number {\n return o.b + o.a * o.u;\n}\n\nexport function confidenceLevel(o: SLOpinion): \"high\" | \"medium\" | \"low\" {\n const projected = project(o);\n if (o.u > 0.5) {\n return \"low\";\n }\n if (projected >= 0.8 && o.u < 0.2) {\n return \"high\";\n }\n if (projected >= 0.6) {\n return \"medium\";\n }\n return \"low\";\n}\n\nexport function cumulativeFusion(left: SLOpinion, right: SLOpinion): SLOpinion {\n if (left.u === 0 && right.u === 0) {\n return opinion(\n (left.b + right.b) / 2,\n (left.d + right.d) / 2,\n 0,\n (left.a + right.a) / 2\n );\n }\n\n const k = left.u + right.u - left.u * right.u;\n if (k === 0) {\n return vacuous((left.a + right.a) / 2);\n }\n\n return opinion(\n (left.b * right.u + right.b * left.u) / k,\n (left.d * right.u + right.d * left.u) / k,\n (left.u * right.u) / k,\n (left.a + right.a) / 2\n );\n}\n\nexport function averagingFusion(left: SLOpinion, right: SLOpinion): SLOpinion {\n if (left.u === 0 && right.u === 0) {\n return opinion(\n (left.b + right.b) / 2,\n (left.d + right.d) / 2,\n 0,\n (left.a + right.a) / 2\n );\n }\n\n const k = left.u + right.u;\n if (k === 0) {\n return vacuous((left.a + right.a) / 2);\n }\n\n return opinion(\n (left.b * right.u + right.b * left.u) / k,\n (left.d * right.u + right.d * left.u) / k,\n (2 * left.u * right.u) / k,\n (left.a + right.a) / 2\n );\n}\n\nexport function trustDiscount(sourceOpinion: SLOpinion, trust: number): SLOpinion {\n const weight = Math.max(0, Math.min(1, Math.abs(trust)));\n return opinion(\n weight * sourceOpinion.b,\n weight * sourceOpinion.d,\n 1 - weight * (sourceOpinion.b + sourceOpinion.d),\n sourceOpinion.a\n );\n}\n\nconst EPSILON = 1e-9;\n\nfunction childBaseRateFallback(\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate: number | undefined\n): number {\n if (fallbackBaseRate !== undefined) {\n return Math.max(0, Math.min(1, fallbackBaseRate));\n }\n\n if (Math.abs(ifTrue.a - ifFalse.a) <= EPSILON) {\n return ifTrue.a;\n }\n\n return (ifTrue.a + ifFalse.a) / 2;\n}\n\nfunction computeConditionalDeductionBaseRate(\n opinionA: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate: number\n): number {\n const denominator =\n 1 - opinionA.a * ifTrue.u - (1 - opinionA.a) * ifFalse.u;\n\n if (ifTrue.u + ifFalse.u < 2 - EPSILON && Math.abs(denominator) > EPSILON) {\n const baseRate =\n (opinionA.a * ifTrue.b + (1 - opinionA.a) * ifFalse.b) / denominator;\n if (baseRate >= -EPSILON && baseRate <= 1 + EPSILON) {\n return Math.max(0, Math.min(1, baseRate));\n }\n }\n\n return fallbackBaseRate;\n}\n\nfunction safeCorrectionTerm(\n numerator: number,\n denominator: number\n): number | undefined {\n if (Math.abs(denominator) <= EPSILON) {\n return undefined;\n }\n\n const value = numerator / denominator;\n if (!Number.isFinite(value)) {\n return undefined;\n }\n\n return Math.max(0, value);\n}\n\nexport function conditionalDeduction(\n opinionA: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate?: number\n): SLOpinion {\n const fallbackChildBaseRate = childBaseRateFallback(\n ifTrue,\n ifFalse,\n fallbackBaseRate\n );\n const childBaseRate = computeConditionalDeductionBaseRate(\n opinionA,\n ifTrue,\n ifFalse,\n fallbackChildBaseRate\n );\n const projectedAntecedent = project(opinionA);\n const projectedAntecedentComplement = 1 - projectedAntecedent;\n const intermediateBelief =\n opinionA.b * ifTrue.b +\n opinionA.d * ifFalse.b +\n opinionA.u * (ifTrue.b * opinionA.a + ifFalse.b * (1 - opinionA.a));\n const intermediateDisbelief =\n opinionA.b * ifTrue.d +\n opinionA.d * ifFalse.d +\n opinionA.u * (ifTrue.d * opinionA.a + ifFalse.d * (1 - opinionA.a));\n const intermediateUncertainty =\n opinionA.b * ifTrue.u +\n opinionA.d * ifFalse.u +\n opinionA.u * (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));\n const projectedVacuousDeduction =\n ifTrue.b * opinionA.a +\n ifFalse.b * (1 - opinionA.a) +\n childBaseRate *\n (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));\n const projectedConditionalA =\n ifTrue.b + childBaseRate * (1 - ifTrue.b - ifTrue.d);\n let correction = 0;\n\n if (\n (ifTrue.b > ifFalse.b && ifTrue.d > ifFalse.d) ||\n (ifTrue.b <= ifFalse.b && ifTrue.d <= ifFalse.d)\n ) {\n correction = 0;\n } else if (ifTrue.b > ifFalse.b && ifTrue.d <= ifFalse.d) {\n const beliefGap = ifTrue.b - ifFalse.b;\n const disbeliefGap = ifFalse.d - ifTrue.d;\n\n if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateBelief - ifTrue.b),\n projectedAntecedent * childBaseRate\n ) ?? 0;\n } else if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent > opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d) * beliefGap,\n projectedAntecedentComplement * childBaseRate * disbeliefGap\n ) ?? 0;\n } else if (\n projectedVacuousDeduction > projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) *\n opinionA.u *\n (intermediateBelief - ifTrue.b) *\n disbeliefGap,\n projectedAntecedent * (1 - childBaseRate) * beliefGap\n ) ?? 0;\n } else {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) * opinionA.u * (intermediateDisbelief - ifTrue.d),\n projectedAntecedentComplement * (1 - childBaseRate)\n ) ?? 0;\n }\n } else {\n const beliefGap = ifFalse.b - ifTrue.b;\n const disbeliefGap = ifTrue.d - ifFalse.d;\n\n if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) *\n opinionA.u *\n (intermediateDisbelief - ifTrue.d) *\n beliefGap,\n projectedAntecedent * childBaseRate * disbeliefGap\n ) ?? 0;\n } else if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent > opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) * opinionA.u * (intermediateBelief - ifTrue.b),\n projectedAntecedentComplement * childBaseRate\n ) ?? 0;\n } else if (\n projectedVacuousDeduction > projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d),\n projectedAntecedent * (1 - childBaseRate)\n ) ?? 0;\n } else {\n correction =\n safeCorrectionTerm(\n opinionA.a *\n opinionA.u *\n (intermediateBelief - ifTrue.b) *\n disbeliefGap,\n projectedAntecedentComplement * (1 - childBaseRate) * beliefGap\n ) ?? 0;\n }\n }\n\n return opinion(\n intermediateBelief - childBaseRate * correction,\n intermediateDisbelief - (1 - childBaseRate) * correction,\n intermediateUncertainty + correction,\n childBaseRate\n );\n}\n\n/**\n * Abductive inference over a conditional.\n * Given an opinion on Y and conditionals P(Y|X), P(Y|~X), infer an opinion on X.\n */\nexport function conditionalAbduction(\n opinionY: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n baseRateX: number\n): SLOpinion {\n const priorX = Math.max(0, Math.min(1, baseRateX));\n const probabilityY = project(opinionY);\n const probabilityGivenTrue = project(ifTrue);\n const probabilityGivenFalse = project(ifFalse);\n\n const posteriorIfYDenominator =\n probabilityGivenTrue * priorX +\n probabilityGivenFalse * (1 - priorX);\n const posteriorIfY =\n posteriorIfYDenominator === 0\n ? priorX\n : (probabilityGivenTrue * priorX) / posteriorIfYDenominator;\n\n const posteriorIfNotYDenominator =\n (1 - probabilityGivenTrue) * priorX +\n (1 - probabilityGivenFalse) * (1 - priorX);\n const posteriorIfNotY =\n posteriorIfNotYDenominator === 0\n ? priorX\n : ((1 - probabilityGivenTrue) * priorX) / posteriorIfNotYDenominator;\n\n const projectedX =\n probabilityY * posteriorIfY + (1 - probabilityY) * posteriorIfNotY;\n const uncertainty = Math.max(\n opinionY.u * 0.5,\n probabilityY * ifTrue.u + (1 - probabilityY) * ifFalse.u\n );\n\n return opinion(\n projectedX * (1 - uncertainty),\n (1 - projectedX) * (1 - uncertainty),\n uncertainty,\n priorX\n );\n}\n\nexport function negate(o: SLOpinion): SLOpinion {\n return mkOpinion(o.d, o.b, o.u, 1 - o.a);\n}\n\nexport function constraintFusion(\n left: SLOpinion,\n right: SLOpinion,\n mode: \"pressure\" | \"redistribute\" = \"pressure\"\n): { o1: SLOpinion; o2: SLOpinion } {\n if (mode === \"redistribute\") {\n const leftProjected = project(left);\n const rightProjected = project(right);\n const total = leftProjected + rightProjected;\n\n if (total <= 1) {\n return { o1: left, o2: right };\n }\n\n const scale = 1 / total;\n return {\n o1: opinion(\n left.b * scale,\n left.d + left.b * (1 - scale),\n left.u,\n left.a\n ),\n o2: opinion(\n right.b * scale,\n right.d + right.b * (1 - scale),\n right.u,\n right.a\n ),\n };\n }\n\n const pressureLeft = right.b * 0.5;\n const pressureRight = left.b * 0.5;\n\n return {\n o1: opinion(\n left.b - pressureLeft * 0.3,\n left.d + pressureLeft * 0.3,\n left.u,\n left.a\n ),\n o2: opinion(\n right.b - pressureRight * 0.3,\n right.d + pressureRight * 0.3,\n right.u,\n right.a\n ),\n };\n}\n\nexport function evidenceBalance(o: SLOpinion): number {\n const total = o.b + o.d;\n if (total === 0) {\n return 0;\n }\n return (o.b - o.d) / total;\n}\n\nexport function areTensioned(left: SLOpinion, right: SLOpinion): boolean {\n return (\n project(left) > 0.5 &&\n project(right) > 0.5 &&\n (left.d > 0.2 || right.d > 0.2)\n );\n}\n\nexport function informationGain(o: SLOpinion): number {\n if (o.u === 0) {\n return 0;\n }\n if (o.u === 1) {\n return 1;\n }\n return o.u * (1 - Math.abs(o.b - o.d));\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/v1/operations/subjectiveLogic/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { SLOpinion } from \"../../types\";\n\nexport function opinion(\n belief: number,\n disbelief: number,\n uncertainty: number,\n baseRate: number\n): SLOpinion {\n const b = Number.isFinite(belief) ? Math.max(0, belief) : 0;\n const d = Number.isFinite(disbelief) ? Math.max(0, disbelief) : 0;\n const u = Number.isFinite(uncertainty) ? Math.max(0, uncertainty) : 0;\n const a = Math.max(0, Math.min(1, baseRate));\n const sum = b + d + u;\n\n if (sum === 0) {\n return { b: 0, d: 0, u: 1, a } as SLOpinion;\n }\n\n return {\n b: b / sum,\n d: d / sum,\n u: u / sum,\n a,\n } as SLOpinion;\n}\n\nexport function mkOpinion(\n belief: number,\n disbelief: number,\n uncertainty: number,\n baseRate: number\n): SLOpinion {\n return opinion(belief, disbelief, uncertainty, baseRate);\n}\n\nexport function vacuous(baseRate: number): SLOpinion {\n return mkOpinion(0, 0, 1, baseRate);\n}\n\nexport function dogmatic(probability: number, baseRate: number): SLOpinion {\n const p = Math.max(0, Math.min(1, probability));\n return mkOpinion(p, 1 - p, 0, baseRate);\n}\n\nexport function project(o: SLOpinion): number {\n return o.b + o.a * o.u;\n}\n\nexport function confidenceLevel(o: SLOpinion): \"high\" | \"medium\" | \"low\" {\n const projected = project(o);\n if (o.u > 0.5) {\n return \"low\";\n }\n if (projected >= 0.8 && o.u < 0.2) {\n return \"high\";\n }\n if (projected >= 0.6) {\n return \"medium\";\n }\n return \"low\";\n}\n\nconst VACUOUS_IDENTITY_EPSILON = 1e-12;\n\n/**\n * Associative, vacuous-identity-preserving base rate for a fused opinion.\n *\n * The legacy `(left.a + right.a) / 2` arithmetic mean was the shared root of\n * RR.7 F1 (projected-confidence non-associativity) and F2 (a vacuous opinion of\n * a different base rate was not a fusion identity): averaging always pulled the\n * fused base rate toward the other operand even when that operand carried no\n * evidence. Subjective Logic requires every opinion over the same frame to share\n * one canonical base rate, so a correct fusion never *invents* a new base rate\n * from the operands' priors. We therefore:\n *\n * - return the informative operand's base rate when exactly one operand is\n * vacuous (the vacuous operand contributes no prior), making `vacuous(a)` a\n * true identity for any `a`; and\n * - require equal base rates otherwise (the canonical-frame contract). When\n * they coincide the result is that shared value — trivially associative.\n *\n * If two informative opinions carry genuinely different base rates they are not\n * opinions over the same frame and must be reconciled before fusion; we fall\n * back to the arithmetic mean ONLY in that ill-posed case to stay total, and the\n * property suite documents that this path is outside the order-independence\n * guarantee.\n */\nfunction fusedBaseRate(left: SLOpinion, right: SLOpinion): number {\n const leftVacuous = 1 - left.u <= VACUOUS_IDENTITY_EPSILON;\n const rightVacuous = 1 - right.u <= VACUOUS_IDENTITY_EPSILON;\n if (leftVacuous && !rightVacuous) {\n return right.a;\n }\n if (rightVacuous && !leftVacuous) {\n return left.a;\n }\n if (Math.abs(left.a - right.a) <= VACUOUS_IDENTITY_EPSILON) {\n return left.a;\n }\n return (left.a + right.a) / 2;\n}\n\nexport function cumulativeFusion(left: SLOpinion, right: SLOpinion): SLOpinion {\n const a = fusedBaseRate(left, right);\n\n // F2: a vacuous operand is the identity element of cumulative fusion. Return\n // the other operand verbatim (including its base rate) so fusion with the\n // vacuous opinion is a true no-op regardless of differing priors.\n if (1 - left.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion(right.b, right.d, right.u, a);\n }\n if (1 - right.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion(left.b, left.d, left.u, a);\n }\n\n // F4: dogmatic pair handled via the ε-limit of the cumulative rule rather than\n // the standalone `(b+d)/2` shortcut. As both uncertainties shrink at the same\n // rate, the cumulative formula's `(b_L·u_R + b_R·u_L)/k` term converges to the\n // arithmetic mean of the masses; deriving it from the same limit the interior\n // formula uses keeps mass-associativity intact (no special-case discontinuity).\n if (left.u <= VACUOUS_IDENTITY_EPSILON && right.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion((left.b + right.b) / 2, (left.d + right.d) / 2, 0, a);\n }\n\n const k = left.u + right.u - left.u * right.u;\n if (k === 0) {\n return vacuous(a);\n }\n\n return opinion(\n (left.b * right.u + right.b * left.u) / k,\n (left.d * right.u + right.d * left.u) / k,\n (left.u * right.u) / k,\n a\n );\n}\n\nexport function averagingFusion(left: SLOpinion, right: SLOpinion): SLOpinion {\n const a = fusedBaseRate(left, right);\n\n // F2: vacuous identity, mirroring cumulativeFusion.\n if (1 - left.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion(right.b, right.d, right.u, a);\n }\n if (1 - right.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion(left.b, left.d, left.u, a);\n }\n\n // F4: dogmatic pair via the ε-limit of the averaging rule.\n if (left.u <= VACUOUS_IDENTITY_EPSILON && right.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion((left.b + right.b) / 2, (left.d + right.d) / 2, 0, a);\n }\n\n const k = left.u + right.u;\n if (k === 0) {\n return vacuous(a);\n }\n\n return opinion(\n (left.b * right.u + right.b * left.u) / k,\n (left.d * right.u + right.d * left.u) / k,\n (2 * left.u * right.u) / k,\n a\n );\n}\n\nexport function trustDiscount(sourceOpinion: SLOpinion, trust: number): SLOpinion {\n const weight = Math.max(0, Math.min(1, Math.abs(trust)));\n return opinion(\n weight * sourceOpinion.b,\n weight * sourceOpinion.d,\n 1 - weight * (sourceOpinion.b + sourceOpinion.d),\n sourceOpinion.a\n );\n}\n\nconst EPSILON = 1e-9;\n\nfunction childBaseRateFallback(\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate: number | undefined\n): number {\n if (fallbackBaseRate !== undefined) {\n return Math.max(0, Math.min(1, fallbackBaseRate));\n }\n\n if (Math.abs(ifTrue.a - ifFalse.a) <= EPSILON) {\n return ifTrue.a;\n }\n\n return (ifTrue.a + ifFalse.a) / 2;\n}\n\nfunction computeConditionalDeductionBaseRate(\n opinionA: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate: number\n): number {\n const denominator =\n 1 - opinionA.a * ifTrue.u - (1 - opinionA.a) * ifFalse.u;\n\n if (ifTrue.u + ifFalse.u < 2 - EPSILON && Math.abs(denominator) > EPSILON) {\n const baseRate =\n (opinionA.a * ifTrue.b + (1 - opinionA.a) * ifFalse.b) / denominator;\n if (baseRate >= -EPSILON && baseRate <= 1 + EPSILON) {\n return Math.max(0, Math.min(1, baseRate));\n }\n }\n\n return fallbackBaseRate;\n}\n\nfunction safeCorrectionTerm(\n numerator: number,\n denominator: number\n): number | undefined {\n if (Math.abs(denominator) <= EPSILON) {\n return undefined;\n }\n\n const value = numerator / denominator;\n if (!Number.isFinite(value)) {\n return undefined;\n }\n\n return Math.max(0, value);\n}\n\nexport function conditionalDeduction(\n opinionA: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate?: number\n): SLOpinion {\n const fallbackChildBaseRate = childBaseRateFallback(\n ifTrue,\n ifFalse,\n fallbackBaseRate\n );\n const childBaseRate = computeConditionalDeductionBaseRate(\n opinionA,\n ifTrue,\n ifFalse,\n fallbackChildBaseRate\n );\n const projectedAntecedent = project(opinionA);\n const projectedAntecedentComplement = 1 - projectedAntecedent;\n const intermediateBelief =\n opinionA.b * ifTrue.b +\n opinionA.d * ifFalse.b +\n opinionA.u * (ifTrue.b * opinionA.a + ifFalse.b * (1 - opinionA.a));\n const intermediateDisbelief =\n opinionA.b * ifTrue.d +\n opinionA.d * ifFalse.d +\n opinionA.u * (ifTrue.d * opinionA.a + ifFalse.d * (1 - opinionA.a));\n const intermediateUncertainty =\n opinionA.b * ifTrue.u +\n opinionA.d * ifFalse.u +\n opinionA.u * (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));\n const projectedVacuousDeduction =\n ifTrue.b * opinionA.a +\n ifFalse.b * (1 - opinionA.a) +\n childBaseRate *\n (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));\n const projectedConditionalA =\n ifTrue.b + childBaseRate * (1 - ifTrue.b - ifTrue.d);\n let correction = 0;\n\n if (\n (ifTrue.b > ifFalse.b && ifTrue.d > ifFalse.d) ||\n (ifTrue.b <= ifFalse.b && ifTrue.d <= ifFalse.d)\n ) {\n correction = 0;\n } else if (ifTrue.b > ifFalse.b && ifTrue.d <= ifFalse.d) {\n const beliefGap = ifTrue.b - ifFalse.b;\n const disbeliefGap = ifFalse.d - ifTrue.d;\n\n if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateBelief - ifTrue.b),\n projectedAntecedent * childBaseRate\n ) ?? 0;\n } else if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent > opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d) * beliefGap,\n projectedAntecedentComplement * childBaseRate * disbeliefGap\n ) ?? 0;\n } else if (\n projectedVacuousDeduction > projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) *\n opinionA.u *\n (intermediateBelief - ifTrue.b) *\n disbeliefGap,\n projectedAntecedent * (1 - childBaseRate) * beliefGap\n ) ?? 0;\n } else {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) * opinionA.u * (intermediateDisbelief - ifTrue.d),\n projectedAntecedentComplement * (1 - childBaseRate)\n ) ?? 0;\n }\n } else {\n const beliefGap = ifFalse.b - ifTrue.b;\n const disbeliefGap = ifTrue.d - ifFalse.d;\n\n if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) *\n opinionA.u *\n (intermediateDisbelief - ifTrue.d) *\n beliefGap,\n projectedAntecedent * childBaseRate * disbeliefGap\n ) ?? 0;\n } else if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent > opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) * opinionA.u * (intermediateBelief - ifTrue.b),\n projectedAntecedentComplement * childBaseRate\n ) ?? 0;\n } else if (\n projectedVacuousDeduction > projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d),\n projectedAntecedent * (1 - childBaseRate)\n ) ?? 0;\n } else {\n correction =\n safeCorrectionTerm(\n opinionA.a *\n opinionA.u *\n (intermediateBelief - ifTrue.b) *\n disbeliefGap,\n projectedAntecedentComplement * (1 - childBaseRate) * beliefGap\n ) ?? 0;\n }\n }\n\n return opinion(\n intermediateBelief - childBaseRate * correction,\n intermediateDisbelief - (1 - childBaseRate) * correction,\n intermediateUncertainty + correction,\n childBaseRate\n );\n}\n\n/**\n * Abductive inference over a conditional.\n * Given an opinion on Y and conditionals P(Y|X), P(Y|~X), infer an opinion on X.\n */\nexport function conditionalAbduction(\n opinionY: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n baseRateX: number\n): SLOpinion {\n const priorX = Math.max(0, Math.min(1, baseRateX));\n const probabilityY = project(opinionY);\n const probabilityGivenTrue = project(ifTrue);\n const probabilityGivenFalse = project(ifFalse);\n\n const posteriorIfYDenominator =\n probabilityGivenTrue * priorX +\n probabilityGivenFalse * (1 - priorX);\n const posteriorIfY =\n posteriorIfYDenominator === 0\n ? priorX\n : (probabilityGivenTrue * priorX) / posteriorIfYDenominator;\n\n const posteriorIfNotYDenominator =\n (1 - probabilityGivenTrue) * priorX +\n (1 - probabilityGivenFalse) * (1 - priorX);\n const posteriorIfNotY =\n posteriorIfNotYDenominator === 0\n ? priorX\n : ((1 - probabilityGivenTrue) * priorX) / posteriorIfNotYDenominator;\n\n const projectedX =\n probabilityY * posteriorIfY + (1 - probabilityY) * posteriorIfNotY;\n const uncertainty = Math.max(\n opinionY.u * 0.5,\n probabilityY * ifTrue.u + (1 - probabilityY) * ifFalse.u\n );\n\n return opinion(\n projectedX * (1 - uncertainty),\n (1 - projectedX) * (1 - uncertainty),\n uncertainty,\n priorX\n );\n}\n\nexport function negate(o: SLOpinion): SLOpinion {\n return mkOpinion(o.d, o.b, o.u, 1 - o.a);\n}\n\nexport function constraintFusion(\n left: SLOpinion,\n right: SLOpinion,\n mode: \"pressure\" | \"redistribute\" = \"pressure\"\n): { o1: SLOpinion; o2: SLOpinion } {\n if (mode === \"redistribute\") {\n const leftProjected = project(left);\n const rightProjected = project(right);\n const total = leftProjected + rightProjected;\n\n if (total <= 1) {\n return { o1: left, o2: right };\n }\n\n const scale = 1 / total;\n return {\n o1: opinion(\n left.b * scale,\n left.d + left.b * (1 - scale),\n left.u,\n left.a\n ),\n o2: opinion(\n right.b * scale,\n right.d + right.b * (1 - scale),\n right.u,\n right.a\n ),\n };\n }\n\n const pressureLeft = right.b * 0.5;\n const pressureRight = left.b * 0.5;\n\n return {\n o1: opinion(\n left.b - pressureLeft * 0.3,\n left.d + pressureLeft * 0.3,\n left.u,\n left.a\n ),\n o2: opinion(\n right.b - pressureRight * 0.3,\n right.d + pressureRight * 0.3,\n right.u,\n right.a\n ),\n };\n}\n\nexport function evidenceBalance(o: SLOpinion): number {\n const total = o.b + o.d;\n if (total === 0) {\n return 0;\n }\n return (o.b - o.d) / total;\n}\n\nexport function areTensioned(left: SLOpinion, right: SLOpinion): boolean {\n return (\n project(left) > 0.5 &&\n project(right) > 0.5 &&\n (left.d > 0.2 || right.d > 0.2)\n );\n}\n\nexport function informationGain(o: SLOpinion): number {\n if (o.u === 0) {\n return 0;\n }\n if (o.u === 1) {\n return 1;\n }\n return o.u * (1 - Math.abs(o.b - o.d));\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/v1/operations/subjectiveLogic/index.ts","../../../src/v1/operations/temporalDecay.ts"],"names":[],"mappings":"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","file":"temporalDecay.js","sourcesContent":["import type { SLOpinion } from \"../../types\";\n\nexport function opinion(\n belief: number,\n disbelief: number,\n uncertainty: number,\n baseRate: number\n): SLOpinion {\n const b = Number.isFinite(belief) ? Math.max(0, belief) : 0;\n const d = Number.isFinite(disbelief) ? Math.max(0, disbelief) : 0;\n const u = Number.isFinite(uncertainty) ? Math.max(0, uncertainty) : 0;\n const a = Math.max(0, Math.min(1, baseRate));\n const sum = b + d + u;\n\n if (sum === 0) {\n return { b: 0, d: 0, u: 1, a } as SLOpinion;\n }\n\n return {\n b: b / sum,\n d: d / sum,\n u: u / sum,\n a,\n } as SLOpinion;\n}\n\nexport function mkOpinion(\n belief: number,\n disbelief: number,\n uncertainty: number,\n baseRate: number\n): SLOpinion {\n return opinion(belief, disbelief, uncertainty, baseRate);\n}\n\nexport function vacuous(baseRate: number): SLOpinion {\n return mkOpinion(0, 0, 1, baseRate);\n}\n\nexport function dogmatic(probability: number, baseRate: number): SLOpinion {\n const p = Math.max(0, Math.min(1, probability));\n return mkOpinion(p, 1 - p, 0, baseRate);\n}\n\nexport function project(o: SLOpinion): number {\n return o.b + o.a * o.u;\n}\n\nexport function confidenceLevel(o: SLOpinion): \"high\" | \"medium\" | \"low\" {\n const projected = project(o);\n if (o.u > 0.5) {\n return \"low\";\n }\n if (projected >= 0.8 && o.u < 0.2) {\n return \"high\";\n }\n if (projected >= 0.6) {\n return \"medium\";\n }\n return \"low\";\n}\n\nexport function cumulativeFusion(left: SLOpinion, right: SLOpinion): SLOpinion {\n if (left.u === 0 && right.u === 0) {\n return opinion(\n (left.b + right.b) / 2,\n (left.d + right.d) / 2,\n 0,\n (left.a + right.a) / 2\n );\n }\n\n const k = left.u + right.u - left.u * right.u;\n if (k === 0) {\n return vacuous((left.a + right.a) / 2);\n }\n\n return opinion(\n (left.b * right.u + right.b * left.u) / k,\n (left.d * right.u + right.d * left.u) / k,\n (left.u * right.u) / k,\n (left.a + right.a) / 2\n );\n}\n\nexport function averagingFusion(left: SLOpinion, right: SLOpinion): SLOpinion {\n if (left.u === 0 && right.u === 0) {\n return opinion(\n (left.b + right.b) / 2,\n (left.d + right.d) / 2,\n 0,\n (left.a + right.a) / 2\n );\n }\n\n const k = left.u + right.u;\n if (k === 0) {\n return vacuous((left.a + right.a) / 2);\n }\n\n return opinion(\n (left.b * right.u + right.b * left.u) / k,\n (left.d * right.u + right.d * left.u) / k,\n (2 * left.u * right.u) / k,\n (left.a + right.a) / 2\n );\n}\n\nexport function trustDiscount(sourceOpinion: SLOpinion, trust: number): SLOpinion {\n const weight = Math.max(0, Math.min(1, Math.abs(trust)));\n return opinion(\n weight * sourceOpinion.b,\n weight * sourceOpinion.d,\n 1 - weight * (sourceOpinion.b + sourceOpinion.d),\n sourceOpinion.a\n );\n}\n\nconst EPSILON = 1e-9;\n\nfunction childBaseRateFallback(\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate: number | undefined\n): number {\n if (fallbackBaseRate !== undefined) {\n return Math.max(0, Math.min(1, fallbackBaseRate));\n }\n\n if (Math.abs(ifTrue.a - ifFalse.a) <= EPSILON) {\n return ifTrue.a;\n }\n\n return (ifTrue.a + ifFalse.a) / 2;\n}\n\nfunction computeConditionalDeductionBaseRate(\n opinionA: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate: number\n): number {\n const denominator =\n 1 - opinionA.a * ifTrue.u - (1 - opinionA.a) * ifFalse.u;\n\n if (ifTrue.u + ifFalse.u < 2 - EPSILON && Math.abs(denominator) > EPSILON) {\n const baseRate =\n (opinionA.a * ifTrue.b + (1 - opinionA.a) * ifFalse.b) / denominator;\n if (baseRate >= -EPSILON && baseRate <= 1 + EPSILON) {\n return Math.max(0, Math.min(1, baseRate));\n }\n }\n\n return fallbackBaseRate;\n}\n\nfunction safeCorrectionTerm(\n numerator: number,\n denominator: number\n): number | undefined {\n if (Math.abs(denominator) <= EPSILON) {\n return undefined;\n }\n\n const value = numerator / denominator;\n if (!Number.isFinite(value)) {\n return undefined;\n }\n\n return Math.max(0, value);\n}\n\nexport function conditionalDeduction(\n opinionA: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate?: number\n): SLOpinion {\n const fallbackChildBaseRate = childBaseRateFallback(\n ifTrue,\n ifFalse,\n fallbackBaseRate\n );\n const childBaseRate = computeConditionalDeductionBaseRate(\n opinionA,\n ifTrue,\n ifFalse,\n fallbackChildBaseRate\n );\n const projectedAntecedent = project(opinionA);\n const projectedAntecedentComplement = 1 - projectedAntecedent;\n const intermediateBelief =\n opinionA.b * ifTrue.b +\n opinionA.d * ifFalse.b +\n opinionA.u * (ifTrue.b * opinionA.a + ifFalse.b * (1 - opinionA.a));\n const intermediateDisbelief =\n opinionA.b * ifTrue.d +\n opinionA.d * ifFalse.d +\n opinionA.u * (ifTrue.d * opinionA.a + ifFalse.d * (1 - opinionA.a));\n const intermediateUncertainty =\n opinionA.b * ifTrue.u +\n opinionA.d * ifFalse.u +\n opinionA.u * (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));\n const projectedVacuousDeduction =\n ifTrue.b * opinionA.a +\n ifFalse.b * (1 - opinionA.a) +\n childBaseRate *\n (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));\n const projectedConditionalA =\n ifTrue.b + childBaseRate * (1 - ifTrue.b - ifTrue.d);\n let correction = 0;\n\n if (\n (ifTrue.b > ifFalse.b && ifTrue.d > ifFalse.d) ||\n (ifTrue.b <= ifFalse.b && ifTrue.d <= ifFalse.d)\n ) {\n correction = 0;\n } else if (ifTrue.b > ifFalse.b && ifTrue.d <= ifFalse.d) {\n const beliefGap = ifTrue.b - ifFalse.b;\n const disbeliefGap = ifFalse.d - ifTrue.d;\n\n if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateBelief - ifTrue.b),\n projectedAntecedent * childBaseRate\n ) ?? 0;\n } else if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent > opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d) * beliefGap,\n projectedAntecedentComplement * childBaseRate * disbeliefGap\n ) ?? 0;\n } else if (\n projectedVacuousDeduction > projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) *\n opinionA.u *\n (intermediateBelief - ifTrue.b) *\n disbeliefGap,\n projectedAntecedent * (1 - childBaseRate) * beliefGap\n ) ?? 0;\n } else {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) * opinionA.u * (intermediateDisbelief - ifTrue.d),\n projectedAntecedentComplement * (1 - childBaseRate)\n ) ?? 0;\n }\n } else {\n const beliefGap = ifFalse.b - ifTrue.b;\n const disbeliefGap = ifTrue.d - ifFalse.d;\n\n if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) *\n opinionA.u *\n (intermediateDisbelief - ifTrue.d) *\n beliefGap,\n projectedAntecedent * childBaseRate * disbeliefGap\n ) ?? 0;\n } else if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent > opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) * opinionA.u * (intermediateBelief - ifTrue.b),\n projectedAntecedentComplement * childBaseRate\n ) ?? 0;\n } else if (\n projectedVacuousDeduction > projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d),\n projectedAntecedent * (1 - childBaseRate)\n ) ?? 0;\n } else {\n correction =\n safeCorrectionTerm(\n opinionA.a *\n opinionA.u *\n (intermediateBelief - ifTrue.b) *\n disbeliefGap,\n projectedAntecedentComplement * (1 - childBaseRate) * beliefGap\n ) ?? 0;\n }\n }\n\n return opinion(\n intermediateBelief - childBaseRate * correction,\n intermediateDisbelief - (1 - childBaseRate) * correction,\n intermediateUncertainty + correction,\n childBaseRate\n );\n}\n\n/**\n * Abductive inference over a conditional.\n * Given an opinion on Y and conditionals P(Y|X), P(Y|~X), infer an opinion on X.\n */\nexport function conditionalAbduction(\n opinionY: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n baseRateX: number\n): SLOpinion {\n const priorX = Math.max(0, Math.min(1, baseRateX));\n const probabilityY = project(opinionY);\n const probabilityGivenTrue = project(ifTrue);\n const probabilityGivenFalse = project(ifFalse);\n\n const posteriorIfYDenominator =\n probabilityGivenTrue * priorX +\n probabilityGivenFalse * (1 - priorX);\n const posteriorIfY =\n posteriorIfYDenominator === 0\n ? priorX\n : (probabilityGivenTrue * priorX) / posteriorIfYDenominator;\n\n const posteriorIfNotYDenominator =\n (1 - probabilityGivenTrue) * priorX +\n (1 - probabilityGivenFalse) * (1 - priorX);\n const posteriorIfNotY =\n posteriorIfNotYDenominator === 0\n ? priorX\n : ((1 - probabilityGivenTrue) * priorX) / posteriorIfNotYDenominator;\n\n const projectedX =\n probabilityY * posteriorIfY + (1 - probabilityY) * posteriorIfNotY;\n const uncertainty = Math.max(\n opinionY.u * 0.5,\n probabilityY * ifTrue.u + (1 - probabilityY) * ifFalse.u\n );\n\n return opinion(\n projectedX * (1 - uncertainty),\n (1 - projectedX) * (1 - uncertainty),\n uncertainty,\n priorX\n );\n}\n\nexport function negate(o: SLOpinion): SLOpinion {\n return mkOpinion(o.d, o.b, o.u, 1 - o.a);\n}\n\nexport function constraintFusion(\n left: SLOpinion,\n right: SLOpinion,\n mode: \"pressure\" | \"redistribute\" = \"pressure\"\n): { o1: SLOpinion; o2: SLOpinion } {\n if (mode === \"redistribute\") {\n const leftProjected = project(left);\n const rightProjected = project(right);\n const total = leftProjected + rightProjected;\n\n if (total <= 1) {\n return { o1: left, o2: right };\n }\n\n const scale = 1 / total;\n return {\n o1: opinion(\n left.b * scale,\n left.d + left.b * (1 - scale),\n left.u,\n left.a\n ),\n o2: opinion(\n right.b * scale,\n right.d + right.b * (1 - scale),\n right.u,\n right.a\n ),\n };\n }\n\n const pressureLeft = right.b * 0.5;\n const pressureRight = left.b * 0.5;\n\n return {\n o1: opinion(\n left.b - pressureLeft * 0.3,\n left.d + pressureLeft * 0.3,\n left.u,\n left.a\n ),\n o2: opinion(\n right.b - pressureRight * 0.3,\n right.d + pressureRight * 0.3,\n right.u,\n right.a\n ),\n };\n}\n\nexport function evidenceBalance(o: SLOpinion): number {\n const total = o.b + o.d;\n if (total === 0) {\n return 0;\n }\n return (o.b - o.d) / total;\n}\n\nexport function areTensioned(left: SLOpinion, right: SLOpinion): boolean {\n return (\n project(left) > 0.5 &&\n project(right) > 0.5 &&\n (left.d > 0.2 || right.d > 0.2)\n );\n}\n\nexport function informationGain(o: SLOpinion): number {\n if (o.u === 0) {\n return 0;\n }\n if (o.u === 1) {\n return 1;\n }\n return o.u * (1 - Math.abs(o.b - o.d));\n}\n","/**\n * LKC-3 decision note:\n * 1. Lucern already persists posterior opinions in `beliefConfidence`.\n * 2. It does not persist a full per-observation Beta event stream on every path.\n * 3. Reweighting raw observations would therefore force new schema + replay logic.\n * 4. This operator decays the formed opinion instead of reconstructing old evidence.\n * 5. The decay is exponential over epistemic age with a configurable half-life.\n * 6. Belief/disbelief mass shrinks over time and returns to uncertainty.\n * 7. Base rate `a` stays fixed, so the projection moves back toward the prior.\n * 8. The reference clock is \"when this posterior became knowable\" (`assessedAt`).\n * 9. That makes Invariant 9 operational with the smallest implementation surface.\n * 10. Per-observation decay can be layered later without breaking this API.\n */\n\nimport type { Opinion } from \"../types\";\nimport { mkOpinion, trustDiscount } from \"./subjectiveLogic\";\n\nexport const DEFAULT_TEMPORAL_DECAY_HALF_LIFE_MS =\n 90 * 24 * 60 * 60 * 1000;\n\nexport type TemporalDecayParams = {\n referenceTime: Date | number;\n halfLifeMs?: number;\n};\n\nfunction toEpochMs(value: Date | number): number | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return value;\n }\n\n if (value instanceof Date) {\n const epochMs = value.getTime();\n return Number.isFinite(epochMs) ? epochMs : undefined;\n }\n\n return undefined;\n}\n\nfunction normalizeHalfLifeMs(halfLifeMs?: number): number {\n if (halfLifeMs === undefined || !Number.isFinite(halfLifeMs)) {\n return 0;\n }\n\n return Math.max(0, halfLifeMs);\n}\n\nexport function temporalDecay(\n sourceOpinion: Opinion,\n now: Date | number,\n decayParams: TemporalDecayParams\n): Opinion {\n const halfLifeMs = normalizeHalfLifeMs(decayParams.halfLifeMs);\n if (halfLifeMs === 0) {\n return { ...sourceOpinion };\n }\n\n const nowMs = toEpochMs(now);\n const referenceTimeMs = toEpochMs(decayParams.referenceTime);\n if (nowMs === undefined || referenceTimeMs === undefined) {\n return { ...sourceOpinion };\n }\n\n const ageMs = Math.max(0, nowMs - referenceTimeMs);\n if (ageMs === 0) {\n return { ...sourceOpinion };\n }\n\n const retainedEvidenceWeight = Math.pow(0.5, ageMs / halfLifeMs);\n return trustDiscount(\n mkOpinion(sourceOpinion.b, sourceOpinion.d, sourceOpinion.u, sourceOpinion.a),\n retainedEvidenceWeight\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/v1/operations/subjectiveLogic/index.ts","../../../src/v1/operations/temporalDecay.ts"],"names":[],"mappings":"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","file":"temporalDecay.js","sourcesContent":["import type { SLOpinion } from \"../../types\";\n\nexport function opinion(\n belief: number,\n disbelief: number,\n uncertainty: number,\n baseRate: number\n): SLOpinion {\n const b = Number.isFinite(belief) ? Math.max(0, belief) : 0;\n const d = Number.isFinite(disbelief) ? Math.max(0, disbelief) : 0;\n const u = Number.isFinite(uncertainty) ? Math.max(0, uncertainty) : 0;\n const a = Math.max(0, Math.min(1, baseRate));\n const sum = b + d + u;\n\n if (sum === 0) {\n return { b: 0, d: 0, u: 1, a } as SLOpinion;\n }\n\n return {\n b: b / sum,\n d: d / sum,\n u: u / sum,\n a,\n } as SLOpinion;\n}\n\nexport function mkOpinion(\n belief: number,\n disbelief: number,\n uncertainty: number,\n baseRate: number\n): SLOpinion {\n return opinion(belief, disbelief, uncertainty, baseRate);\n}\n\nexport function vacuous(baseRate: number): SLOpinion {\n return mkOpinion(0, 0, 1, baseRate);\n}\n\nexport function dogmatic(probability: number, baseRate: number): SLOpinion {\n const p = Math.max(0, Math.min(1, probability));\n return mkOpinion(p, 1 - p, 0, baseRate);\n}\n\nexport function project(o: SLOpinion): number {\n return o.b + o.a * o.u;\n}\n\nexport function confidenceLevel(o: SLOpinion): \"high\" | \"medium\" | \"low\" {\n const projected = project(o);\n if (o.u > 0.5) {\n return \"low\";\n }\n if (projected >= 0.8 && o.u < 0.2) {\n return \"high\";\n }\n if (projected >= 0.6) {\n return \"medium\";\n }\n return \"low\";\n}\n\nconst VACUOUS_IDENTITY_EPSILON = 1e-12;\n\n/**\n * Associative, vacuous-identity-preserving base rate for a fused opinion.\n *\n * The legacy `(left.a + right.a) / 2` arithmetic mean was the shared root of\n * RR.7 F1 (projected-confidence non-associativity) and F2 (a vacuous opinion of\n * a different base rate was not a fusion identity): averaging always pulled the\n * fused base rate toward the other operand even when that operand carried no\n * evidence. Subjective Logic requires every opinion over the same frame to share\n * one canonical base rate, so a correct fusion never *invents* a new base rate\n * from the operands' priors. We therefore:\n *\n * - return the informative operand's base rate when exactly one operand is\n * vacuous (the vacuous operand contributes no prior), making `vacuous(a)` a\n * true identity for any `a`; and\n * - require equal base rates otherwise (the canonical-frame contract). When\n * they coincide the result is that shared value — trivially associative.\n *\n * If two informative opinions carry genuinely different base rates they are not\n * opinions over the same frame and must be reconciled before fusion; we fall\n * back to the arithmetic mean ONLY in that ill-posed case to stay total, and the\n * property suite documents that this path is outside the order-independence\n * guarantee.\n */\nfunction fusedBaseRate(left: SLOpinion, right: SLOpinion): number {\n const leftVacuous = 1 - left.u <= VACUOUS_IDENTITY_EPSILON;\n const rightVacuous = 1 - right.u <= VACUOUS_IDENTITY_EPSILON;\n if (leftVacuous && !rightVacuous) {\n return right.a;\n }\n if (rightVacuous && !leftVacuous) {\n return left.a;\n }\n if (Math.abs(left.a - right.a) <= VACUOUS_IDENTITY_EPSILON) {\n return left.a;\n }\n return (left.a + right.a) / 2;\n}\n\nexport function cumulativeFusion(left: SLOpinion, right: SLOpinion): SLOpinion {\n const a = fusedBaseRate(left, right);\n\n // F2: a vacuous operand is the identity element of cumulative fusion. Return\n // the other operand verbatim (including its base rate) so fusion with the\n // vacuous opinion is a true no-op regardless of differing priors.\n if (1 - left.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion(right.b, right.d, right.u, a);\n }\n if (1 - right.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion(left.b, left.d, left.u, a);\n }\n\n // F4: dogmatic pair handled via the ε-limit of the cumulative rule rather than\n // the standalone `(b+d)/2` shortcut. As both uncertainties shrink at the same\n // rate, the cumulative formula's `(b_L·u_R + b_R·u_L)/k` term converges to the\n // arithmetic mean of the masses; deriving it from the same limit the interior\n // formula uses keeps mass-associativity intact (no special-case discontinuity).\n if (left.u <= VACUOUS_IDENTITY_EPSILON && right.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion((left.b + right.b) / 2, (left.d + right.d) / 2, 0, a);\n }\n\n const k = left.u + right.u - left.u * right.u;\n if (k === 0) {\n return vacuous(a);\n }\n\n return opinion(\n (left.b * right.u + right.b * left.u) / k,\n (left.d * right.u + right.d * left.u) / k,\n (left.u * right.u) / k,\n a\n );\n}\n\nexport function averagingFusion(left: SLOpinion, right: SLOpinion): SLOpinion {\n const a = fusedBaseRate(left, right);\n\n // F2: vacuous identity, mirroring cumulativeFusion.\n if (1 - left.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion(right.b, right.d, right.u, a);\n }\n if (1 - right.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion(left.b, left.d, left.u, a);\n }\n\n // F4: dogmatic pair via the ε-limit of the averaging rule.\n if (left.u <= VACUOUS_IDENTITY_EPSILON && right.u <= VACUOUS_IDENTITY_EPSILON) {\n return opinion((left.b + right.b) / 2, (left.d + right.d) / 2, 0, a);\n }\n\n const k = left.u + right.u;\n if (k === 0) {\n return vacuous(a);\n }\n\n return opinion(\n (left.b * right.u + right.b * left.u) / k,\n (left.d * right.u + right.d * left.u) / k,\n (2 * left.u * right.u) / k,\n a\n );\n}\n\nexport function trustDiscount(sourceOpinion: SLOpinion, trust: number): SLOpinion {\n const weight = Math.max(0, Math.min(1, Math.abs(trust)));\n return opinion(\n weight * sourceOpinion.b,\n weight * sourceOpinion.d,\n 1 - weight * (sourceOpinion.b + sourceOpinion.d),\n sourceOpinion.a\n );\n}\n\nconst EPSILON = 1e-9;\n\nfunction childBaseRateFallback(\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate: number | undefined\n): number {\n if (fallbackBaseRate !== undefined) {\n return Math.max(0, Math.min(1, fallbackBaseRate));\n }\n\n if (Math.abs(ifTrue.a - ifFalse.a) <= EPSILON) {\n return ifTrue.a;\n }\n\n return (ifTrue.a + ifFalse.a) / 2;\n}\n\nfunction computeConditionalDeductionBaseRate(\n opinionA: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate: number\n): number {\n const denominator =\n 1 - opinionA.a * ifTrue.u - (1 - opinionA.a) * ifFalse.u;\n\n if (ifTrue.u + ifFalse.u < 2 - EPSILON && Math.abs(denominator) > EPSILON) {\n const baseRate =\n (opinionA.a * ifTrue.b + (1 - opinionA.a) * ifFalse.b) / denominator;\n if (baseRate >= -EPSILON && baseRate <= 1 + EPSILON) {\n return Math.max(0, Math.min(1, baseRate));\n }\n }\n\n return fallbackBaseRate;\n}\n\nfunction safeCorrectionTerm(\n numerator: number,\n denominator: number\n): number | undefined {\n if (Math.abs(denominator) <= EPSILON) {\n return undefined;\n }\n\n const value = numerator / denominator;\n if (!Number.isFinite(value)) {\n return undefined;\n }\n\n return Math.max(0, value);\n}\n\nexport function conditionalDeduction(\n opinionA: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n fallbackBaseRate?: number\n): SLOpinion {\n const fallbackChildBaseRate = childBaseRateFallback(\n ifTrue,\n ifFalse,\n fallbackBaseRate\n );\n const childBaseRate = computeConditionalDeductionBaseRate(\n opinionA,\n ifTrue,\n ifFalse,\n fallbackChildBaseRate\n );\n const projectedAntecedent = project(opinionA);\n const projectedAntecedentComplement = 1 - projectedAntecedent;\n const intermediateBelief =\n opinionA.b * ifTrue.b +\n opinionA.d * ifFalse.b +\n opinionA.u * (ifTrue.b * opinionA.a + ifFalse.b * (1 - opinionA.a));\n const intermediateDisbelief =\n opinionA.b * ifTrue.d +\n opinionA.d * ifFalse.d +\n opinionA.u * (ifTrue.d * opinionA.a + ifFalse.d * (1 - opinionA.a));\n const intermediateUncertainty =\n opinionA.b * ifTrue.u +\n opinionA.d * ifFalse.u +\n opinionA.u * (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));\n const projectedVacuousDeduction =\n ifTrue.b * opinionA.a +\n ifFalse.b * (1 - opinionA.a) +\n childBaseRate *\n (ifTrue.u * opinionA.a + ifFalse.u * (1 - opinionA.a));\n const projectedConditionalA =\n ifTrue.b + childBaseRate * (1 - ifTrue.b - ifTrue.d);\n let correction = 0;\n\n if (\n (ifTrue.b > ifFalse.b && ifTrue.d > ifFalse.d) ||\n (ifTrue.b <= ifFalse.b && ifTrue.d <= ifFalse.d)\n ) {\n correction = 0;\n } else if (ifTrue.b > ifFalse.b && ifTrue.d <= ifFalse.d) {\n const beliefGap = ifTrue.b - ifFalse.b;\n const disbeliefGap = ifFalse.d - ifTrue.d;\n\n if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateBelief - ifTrue.b),\n projectedAntecedent * childBaseRate\n ) ?? 0;\n } else if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent > opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d) * beliefGap,\n projectedAntecedentComplement * childBaseRate * disbeliefGap\n ) ?? 0;\n } else if (\n projectedVacuousDeduction > projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) *\n opinionA.u *\n (intermediateBelief - ifTrue.b) *\n disbeliefGap,\n projectedAntecedent * (1 - childBaseRate) * beliefGap\n ) ?? 0;\n } else {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) * opinionA.u * (intermediateDisbelief - ifTrue.d),\n projectedAntecedentComplement * (1 - childBaseRate)\n ) ?? 0;\n }\n } else {\n const beliefGap = ifFalse.b - ifTrue.b;\n const disbeliefGap = ifTrue.d - ifFalse.d;\n\n if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) *\n opinionA.u *\n (intermediateDisbelief - ifTrue.d) *\n beliefGap,\n projectedAntecedent * childBaseRate * disbeliefGap\n ) ?? 0;\n } else if (\n projectedVacuousDeduction <= projectedConditionalA &&\n projectedAntecedent > opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n (1 - opinionA.a) * opinionA.u * (intermediateBelief - ifTrue.b),\n projectedAntecedentComplement * childBaseRate\n ) ?? 0;\n } else if (\n projectedVacuousDeduction > projectedConditionalA &&\n projectedAntecedent <= opinionA.a\n ) {\n correction =\n safeCorrectionTerm(\n opinionA.a * opinionA.u * (intermediateDisbelief - ifTrue.d),\n projectedAntecedent * (1 - childBaseRate)\n ) ?? 0;\n } else {\n correction =\n safeCorrectionTerm(\n opinionA.a *\n opinionA.u *\n (intermediateBelief - ifTrue.b) *\n disbeliefGap,\n projectedAntecedentComplement * (1 - childBaseRate) * beliefGap\n ) ?? 0;\n }\n }\n\n return opinion(\n intermediateBelief - childBaseRate * correction,\n intermediateDisbelief - (1 - childBaseRate) * correction,\n intermediateUncertainty + correction,\n childBaseRate\n );\n}\n\n/**\n * Abductive inference over a conditional.\n * Given an opinion on Y and conditionals P(Y|X), P(Y|~X), infer an opinion on X.\n */\nexport function conditionalAbduction(\n opinionY: SLOpinion,\n ifTrue: SLOpinion,\n ifFalse: SLOpinion,\n baseRateX: number\n): SLOpinion {\n const priorX = Math.max(0, Math.min(1, baseRateX));\n const probabilityY = project(opinionY);\n const probabilityGivenTrue = project(ifTrue);\n const probabilityGivenFalse = project(ifFalse);\n\n const posteriorIfYDenominator =\n probabilityGivenTrue * priorX +\n probabilityGivenFalse * (1 - priorX);\n const posteriorIfY =\n posteriorIfYDenominator === 0\n ? priorX\n : (probabilityGivenTrue * priorX) / posteriorIfYDenominator;\n\n const posteriorIfNotYDenominator =\n (1 - probabilityGivenTrue) * priorX +\n (1 - probabilityGivenFalse) * (1 - priorX);\n const posteriorIfNotY =\n posteriorIfNotYDenominator === 0\n ? priorX\n : ((1 - probabilityGivenTrue) * priorX) / posteriorIfNotYDenominator;\n\n const projectedX =\n probabilityY * posteriorIfY + (1 - probabilityY) * posteriorIfNotY;\n const uncertainty = Math.max(\n opinionY.u * 0.5,\n probabilityY * ifTrue.u + (1 - probabilityY) * ifFalse.u\n );\n\n return opinion(\n projectedX * (1 - uncertainty),\n (1 - projectedX) * (1 - uncertainty),\n uncertainty,\n priorX\n );\n}\n\nexport function negate(o: SLOpinion): SLOpinion {\n return mkOpinion(o.d, o.b, o.u, 1 - o.a);\n}\n\nexport function constraintFusion(\n left: SLOpinion,\n right: SLOpinion,\n mode: \"pressure\" | \"redistribute\" = \"pressure\"\n): { o1: SLOpinion; o2: SLOpinion } {\n if (mode === \"redistribute\") {\n const leftProjected = project(left);\n const rightProjected = project(right);\n const total = leftProjected + rightProjected;\n\n if (total <= 1) {\n return { o1: left, o2: right };\n }\n\n const scale = 1 / total;\n return {\n o1: opinion(\n left.b * scale,\n left.d + left.b * (1 - scale),\n left.u,\n left.a\n ),\n o2: opinion(\n right.b * scale,\n right.d + right.b * (1 - scale),\n right.u,\n right.a\n ),\n };\n }\n\n const pressureLeft = right.b * 0.5;\n const pressureRight = left.b * 0.5;\n\n return {\n o1: opinion(\n left.b - pressureLeft * 0.3,\n left.d + pressureLeft * 0.3,\n left.u,\n left.a\n ),\n o2: opinion(\n right.b - pressureRight * 0.3,\n right.d + pressureRight * 0.3,\n right.u,\n right.a\n ),\n };\n}\n\nexport function evidenceBalance(o: SLOpinion): number {\n const total = o.b + o.d;\n if (total === 0) {\n return 0;\n }\n return (o.b - o.d) / total;\n}\n\nexport function areTensioned(left: SLOpinion, right: SLOpinion): boolean {\n return (\n project(left) > 0.5 &&\n project(right) > 0.5 &&\n (left.d > 0.2 || right.d > 0.2)\n );\n}\n\nexport function informationGain(o: SLOpinion): number {\n if (o.u === 0) {\n return 0;\n }\n if (o.u === 1) {\n return 1;\n }\n return o.u * (1 - Math.abs(o.b - o.d));\n}\n","/**\n * LKC-3 decision note:\n * 1. Lucern already persists posterior opinions in `beliefConfidence`.\n * 2. It does not persist a full per-observation Beta event stream on every path.\n * 3. Reweighting raw observations would therefore force new schema + replay logic.\n * 4. This operator decays the formed opinion instead of reconstructing old evidence.\n * 5. The decay is exponential over epistemic age with a configurable half-life.\n * 6. Belief/disbelief mass shrinks over time and returns to uncertainty.\n * 7. Base rate `a` stays fixed, so the projection moves back toward the prior.\n * 8. The reference clock is \"when this posterior became knowable\" (`assessedAt`).\n * 9. That makes Invariant 9 operational with the smallest implementation surface.\n * 10. Per-observation decay can be layered later without breaking this API.\n */\n\nimport type { Opinion } from \"../types\";\nimport { mkOpinion, trustDiscount } from \"./subjectiveLogic\";\n\nexport const DEFAULT_TEMPORAL_DECAY_HALF_LIFE_MS =\n 90 * 24 * 60 * 60 * 1000;\n\nexport type TemporalDecayParams = {\n referenceTime: Date | number;\n halfLifeMs?: number;\n};\n\nfunction toEpochMs(value: Date | number): number | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return value;\n }\n\n if (value instanceof Date) {\n const epochMs = value.getTime();\n return Number.isFinite(epochMs) ? epochMs : undefined;\n }\n\n return undefined;\n}\n\nfunction normalizeHalfLifeMs(halfLifeMs?: number): number {\n if (halfLifeMs === undefined || !Number.isFinite(halfLifeMs)) {\n return 0;\n }\n\n return Math.max(0, halfLifeMs);\n}\n\nexport function temporalDecay(\n sourceOpinion: Opinion,\n now: Date | number,\n decayParams: TemporalDecayParams\n): Opinion {\n const halfLifeMs = normalizeHalfLifeMs(decayParams.halfLifeMs);\n if (halfLifeMs === 0) {\n return { ...sourceOpinion };\n }\n\n const nowMs = toEpochMs(now);\n const referenceTimeMs = toEpochMs(decayParams.referenceTime);\n if (nowMs === undefined || referenceTimeMs === undefined) {\n return { ...sourceOpinion };\n }\n\n const ageMs = Math.max(0, nowMs - referenceTimeMs);\n if (ageMs === 0) {\n return { ...sourceOpinion };\n }\n\n const retainedEvidenceWeight = Math.pow(0.5, ageMs / halfLifeMs);\n return trustDiscount(\n mkOpinion(sourceOpinion.b, sourceOpinion.d, sourceOpinion.u, sourceOpinion.a),\n retainedEvidenceWeight\n );\n}\n"]}
|