Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ src/
semantics/
propositional/
evaluationEngine.ts # PropositionalEvaluationEngine — truth tables, classification
dialectic/
dialecticTypes.ts # Argument, ContentiousClaim, ArgumentTarget, ArgumentStance,
# EntailmentStrength, ClaimRelation, ArgumentEvaluation,
# ArgumentTension, DialecticalMapResult
dialecticalMap.ts # DialecticalMap — evaluation engine (validity, claim relation, tensions)
dialecticalMapBuilder.ts # DialecticalMapBuilder — fluent builder
index.ts

test/
language/
Expand Down Expand Up @@ -137,6 +144,9 @@ test/
syntaxTreePrinter.spec.ts
propositional/syntaxEngine.spec.ts
semantics/propositional/evaluationEngine.spec.ts
dialectic/
dialecticalMap.spec.ts
dialecticalMapBuilder.spec.ts
```

### TypeScript Config Split
Expand Down Expand Up @@ -179,6 +189,8 @@ test/
| `ConsistencyResult<V>` | Outcome of a consistency check: witness or failed valuations (`V` defaults to `boolean`, quantificational uses `DomainElement`) |
| `ProofNode` | Node in a structured proof tree |
| `Theory<F, V>` | Interface all formal theories must implement (`V` is the valuation value type) |
| `PairwiseRelation` | `'INCONSISTENT' \| 'EQUIVALENT' \| 'ENTAILS_LEFT' \| 'ENTAILS_RIGHT' \| 'CONSISTENT'` — `ENTAILS_LEFT` means s1 ⊨ s2 (no case where s1=T and s2=F); `ENTAILS_RIGHT` is the mirror |
| `PairwiseSentenceRelation<F>` | `{ a, b, relation }` — typed record returned by `Theory.pairwiseRelations()` |

## Propositional Logic — What's Implemented

Expand All @@ -200,6 +212,7 @@ test/
- `buildProofTree()` — structured `ProofNode` tree of the consistency result
- `printProof()` — prints the proof tree to the console with box-drawing characters
- `printGraph()` — prints pairwise logical relations (consistent / entails / equivalent / inconsistent) and shared-variable edges
- `pairwiseRelations()` — returns all C(n,2) pairwise `PairwiseSentenceRelation<WFF>[]` as typed data (the same computation underlying `printGraph()`, now accessible programmatically)

**`PropositionalTheoryBuilder`** — fluent builder:

Expand Down Expand Up @@ -245,6 +258,7 @@ theory.printGraph();
**`QuantificationalTheory`** — implements `Theory<QFF, DomainElement>`:
- `checkConsistency()` — exhaustive `|D|^n` assignment enumeration
- `buildProofTree()`, `printProof()`, `printGraph()` — same structure as propositional
- `pairwiseRelations()` — returns `PairwiseSentenceRelation<QFF>[]`

**`QuantificationalTheoryBuilder`** — fluent builder with `domain()`, `variable()`, `predicate()`, `sentence()`, `build()`.

Expand Down Expand Up @@ -295,6 +309,7 @@ Five concrete `ModalSystemSpec` objects are provided:
- `checkConsistency()` — exhaustive 2^(|P|×|W|) enumeration; witness keyed as `prop@world`
- `buildProofTree()` — includes Kripke frame node (worlds, accessibility pairs, designated world) and per-world valuation table; distinct from propositional/quantificational proof trees which show variable assignments
- `printProof()`, `printGraph()` — same interface as other theories; system name appears in header
- `pairwiseRelations()` — returns `PairwiseSentenceRelation<MFF>[]`

**`ModalTheoryBuilder`** — fluent builder: `system()` (default `SystemK`), `worlds()`, `accessibility()`, `designatedWorld()`, `proposition()`, `sentence()`, `build()`. `build()` calls `system.validateFrame()` before constructing the theory — throws with a descriptive message if the frame violates the system's conditions.

Expand Down Expand Up @@ -425,6 +440,45 @@ The `kind` discriminator maps directly to a protobuf `oneof`. `PhraseLabel` and
- `truthTable(formulaString): TruthTable` — `{ variables, rows: { assignment, value }[] }`.
- `printTruthTable(formulaString): void` — formatted console output with box-drawing separator.

## Dialectical Map — What's Implemented

The dialectical map (`src/engine/dialectic/`) provides formal evaluation of multi-argument discourse around a central contention. All evaluation is propositional.

### Core types (`dialecticTypes.ts`)

- **`ContentiousClaim`** — `{ claim: AlethicAssertoric, label: string }` — the focal claim under dispute.
- **`ArgumentTarget`** — discriminated union: `{ kind: 'claim' }` | `{ kind: 'argument', argumentId }` | `{ kind: 'premise', argumentId, premiseIndex }`. An argument can target the central claim, another argument's sub-conclusion, or a specific premise within another argument.
- **`ArgumentStance`** — `'supports' | 'attacks' | 'qualifies' | 'undermines' | 'concedes'` — how the argument relates to its target.
- **`Argument`** — `{ id, label, premises, subConclusion, target, stance }`.
- **`EntailmentStrength`** — `'valid' | 'consistent' | 'inconsistent' | 'undetermined'` — formal validity of the argument's internal inference.
- **`ClaimRelation`** — `'entails' | 'entailed-by' | 'equivalent' | 'contradicts' | 'consistent' | 'undetermined'` — how the sub-conclusion relates to the central claim.
- **`ArgumentEvaluation`** — `{ argumentId, internalValidity, claimRelation, strength }`.
- **`ArgumentTension`** — `{ argumentIdA, argumentIdB, conclusionRelation: PairwiseRelation }` — pairwise formal relation between two arguments' sub-conclusions.
- **`DialecticalMapResult`** — `{ claim, arguments, evaluations, tensions }` — full output of `evaluate()`.

### `DialecticalMap` (`dialecticalMap.ts`)

Stateless evaluation class constructed from a `ContentiousClaim` and `Argument[]`. Construct via `DialecticalMapBuilder`.

**`evaluate(): DialecticalMapResult`** — for each argument:

1. Translates all sentences (premises + sub-conclusion) through `FormalAnnotator` → `FormalTranslator` → `PropositionalSyntaxEngine` with a shared variable registry.
2. Synthesises a premise-conjunction formula string: `"(f1) & (f2) & ..."`.
3. Builds a 2-sentence `PropositionalTheory` `[premise-conjunction, sub-conclusion]` and calls `pairwiseRelations()` to determine `internalValidity`.
4. Builds a 2-sentence theory `[sub-conclusion, claim]` to determine `claimRelation`.
5. Builds a 2-sentence theory for every argument pair to determine `conclusionRelation` in `tensions`.
6. Computes `strength = avg(premise.confidence) × validityWeight` (1.0 / 0.5 / 0.0 for valid / consistent / otherwise).

**`printReport(): void`** — formatted console output listing each argument with its validity, claim relation, strength, and the pairwise tension matrix.

### `DialecticalMapBuilder` (`dialecticalMapBuilder.ts`)

Fluent builder: `.claim(sentence, label)`, `.argument(arg)`, `.build()`. Throws if `.build()` is called without setting a claim.

### Important note on `ENTAILS_LEFT` / `ENTAILS_RIGHT`

The condition that produces `ENTAILS_LEFT` is `!s1TrueS2False` (no case where s1=T and s2=F), which means **s1 ⊨ s2** (the left sentence entails the right). `ENTAILS_RIGHT` is the mirror. The comments in the original theory files have this backwards; `PairwiseRelation` in `shared/theory.ts` has the correct semantics documented.

## What Is Not Yet Implemented

- Quantificational function symbols (e.g., `f(x)`)
Expand Down
152 changes: 152 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,158 @@ const theory = new PropositionalTheoryBuilder().fromSentenceSet(result.sentenceS
theory.printProof();
```

## Dialectical Map

`DialecticalMap` organises an unbounded collection of structured `Argument` entities around a central `ContentiousClaim` and formally evaluates each argument's inferential relationship to the claim and to every other argument.

Unlike `ArgumentAnalyser` (which works over flat sentence lists), the dialectical map treats each argument as an independent unit with its own internal premise → conclusion structure and an explicit target.

### Core types

```ts
interface ContentiousClaim {
claim: AlethicAssertoric;
label: string;
}

interface Argument {
id: string;
label: string;
premises: AlethicAssertoric[];
subConclusion: AlethicAssertoric;
target: ArgumentTarget; // { kind: 'claim' } | { kind: 'argument', argumentId } | { kind: 'premise', argumentId, premiseIndex }
stance: ArgumentStance; // 'supports' | 'attacks' | 'qualifies' | 'undermines' | 'concedes'
}
```

### Building a dialectical map

```ts
import { DialecticalMapBuilder } from 'logic-engine';

const map = new DialecticalMapBuilder()
.claim({ raw: 'Capital punishment is justified', confidence: 1.0 }, 'Central Claim')
.argument({
id: 'deterrence',
label: 'The Deterrence Argument',
premises: [
{ raw: 'Capital punishment deters violent crime', confidence: 0.8 },
{ raw: 'Deterring crime saves innocent lives', confidence: 0.9 },
],
subConclusion: { raw: 'Capital punishment saves innocent lives', confidence: 0.85 },
target: { kind: 'claim' },
stance: 'supports',
})
.argument({
id: 'irreversibility',
label: 'The Irreversibility Objection',
premises: [
{ raw: 'Wrongful executions cannot be undone', confidence: 0.95 },
{ raw: 'The justice system makes errors', confidence: 0.90 },
],
subConclusion: { raw: 'Capital punishment risks irreversible injustice', confidence: 0.85 },
target: { kind: 'claim' },
stance: 'attacks',
})
.argument({
id: 'rebuttal',
label: 'Rebuttal to Deterrence',
premises: [
{ raw: 'Empirical studies show no deterrent effect', confidence: 0.75 },
],
subConclusion: { raw: 'The deterrence premise is false', confidence: 0.70 },
target: { kind: 'premise', argumentId: 'deterrence', premiseIndex: 0 },
stance: 'undermines',
})
.build();
```

Arguments can target the central claim, another argument's sub-conclusion, or a specific premise within another argument.

### Evaluating

```ts
const result = map.evaluate();
```

`evaluate()` returns a `DialecticalMapResult`:

```ts
interface DialecticalMapResult {
claim: ContentiousClaim;
arguments: Argument[];
evaluations: ArgumentEvaluation[]; // one per argument
tensions: ArgumentTension[]; // C(n,2) pairwise pairs
}
```

Each `ArgumentEvaluation` contains:

```ts
interface ArgumentEvaluation {
argumentId: string;
internalValidity: EntailmentStrength; // 'valid' | 'consistent' | 'inconsistent' | 'undetermined'
claimRelation: ClaimRelation; // 'entails' | 'entailed-by' | 'equivalent' | 'contradicts' | 'consistent' | 'undetermined'
strength: number; // avg(premise.confidence) × validity weight ∈ [0, 1]
}
```

- **`internalValidity`** — whether the argument's premise-conjunction formally entails its sub-conclusion (`valid`), is consistent with it, or inconsistent.
- **`claimRelation`** — how the sub-conclusion relates to the central claim under propositional evaluation.
- **`strength`** — `avg(premise.confidence) × weight` where `weight` is `1.0` (valid), `0.5` (consistent), or `0.0` (otherwise).

Each `ArgumentTension` gives the pairwise formal relation between two arguments' sub-conclusions:

```ts
interface ArgumentTension {
argumentIdA: string;
argumentIdB: string;
conclusionRelation: PairwiseRelation; // 'INCONSISTENT' | 'EQUIVALENT' | 'ENTAILS_LEFT' | 'ENTAILS_RIGHT' | 'CONSISTENT'
}
```

### Printing a report

```ts
map.printReport();
```

```text
DIALECTICAL MAP REPORT
══════════════════════════════════════════════════

Central Claim [Central Claim]
"Capital punishment is justified"
confidence: 1.00

Arguments (3):

[deterrence] The Deterrence Argument (supports → claim)
Premises:
• "Capital punishment deters violent crime" (confidence: 0.80)
• "Deterring crime saves innocent lives" (confidence: 0.90)
Sub-conclusion: "Capital punishment saves innocent lives"
Validity: consistent Claim relation: consistent Strength: 0.425

[irreversibility] The Irreversibility Objection (attacks → claim)
Premises:
• "Wrongful executions cannot be undone" (confidence: 0.95)
• "The justice system makes errors" (confidence: 0.90)
Sub-conclusion: "Capital punishment risks irreversible injustice"
Validity: consistent Claim relation: consistent Strength: 0.463

[rebuttal] Rebuttal to Deterrence (undermines → premise[0] of deterrence)
Premises:
• "Empirical studies show no deterrent effect" (confidence: 0.75)
Sub-conclusion: "The deterrence premise is false"
Validity: consistent Claim relation: consistent Strength: 0.375

Pairwise tensions (sub-conclusions):
The Deterrence Argument ↔ The Irreversibility Objection consistent
The Deterrence Argument ↔ Rebuttal to Deterrence consistent
The Irreversibility Objection ↔ Rebuttal to Deterrence consistent
```

## Evaluation Engine

`PropositionalEvaluationEngine` provides truth-table generation and semantic classification.
Expand Down
133 changes: 133 additions & 0 deletions src/engine/dialectic/dialecticTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { AlethicAssertoric } from '../../language/shared/types';
import { PairwiseRelation } from '../../language/shared/theory';

// ─── Argument targeting ───────────────────────────────────────────────────────

/**
* What an argument's sub-conclusion is directed at.
*
* - claim — targets the central contention directly
* - argument — targets another argument's sub-conclusion
* - premise — targets a specific premise within another argument
*/
export type ArgumentTarget =
| { kind: 'claim' }
| { kind: 'argument'; argumentId: string }
| { kind: 'premise'; argumentId: string; premiseIndex: number };

// ─── Argument stance ──────────────────────────────────────────────────────────

/**
* How an argument relates to its target.
*
* - supports — sub-conclusion establishes or corroborates the target
* - attacks — sub-conclusion entails the negation of the target
* - qualifies — narrows or conditions the target (reduces scope or strength)
* - undermines — attacks a presupposition of the target without directly
* negating it
* - concedes — grants the target but limits its downstream implications
*/
export type ArgumentStance =
| 'supports'
| 'attacks'
| 'qualifies'
| 'undermines'
| 'concedes';

// ─── Argument ─────────────────────────────────────────────────────────────────

/**
* A single structured argument — a set of premises leading to a
* sub-conclusion, directed at a target with a declared stance.
*/
export interface Argument {
/** Unique identifier for this argument within the dialectical map. */
id: string;
/** Human-readable name for display (e.g. "The Deterrence Argument"). */
label: string;
/** The premises that ground this argument. May be empty. */
premises: AlethicAssertoric[];
/** The claim this argument establishes. */
subConclusion: AlethicAssertoric;
/** What this argument is directed at. */
target: ArgumentTarget;
/** How this argument relates to its target. */
stance: ArgumentStance;
}

// ─── ContentiousClaim ────────────────────────────────────────────────────────

/** The central claim under dispute around which all arguments are organised. */
export interface ContentiousClaim {
claim: AlethicAssertoric;
label: string;
}

// ─── Evaluation output types ─────────────────────────────────────────────────

/**
* How strongly the premises formally support the sub-conclusion.
*
* - valid — premises ⊨ sub-conclusion (ENTAILS_RIGHT)
* - consistent — premises are consistent with sub-conclusion but do not entail it
* - inconsistent — premises are inconsistent with sub-conclusion
* - undetermined — zero premises or the NLP pipeline produced no usable formula
*/
export type EntailmentStrength =
| 'valid'
| 'consistent'
| 'inconsistent'
| 'undetermined';

/**
* How the sub-conclusion relates to the central claim.
*
* - entails — sub-conclusion ⊨ claim
* - entailed-by — claim ⊨ sub-conclusion
* - equivalent — sub-conclusion ⟺ claim
* - contradicts — sub-conclusion and claim cannot both be true
* - consistent — can both be true, no entailment in either direction
* - undetermined — no shared propositions or NLP produced no usable formula
*/
export type ClaimRelation =
| 'entails'
| 'entailed-by'
| 'equivalent'
| 'contradicts'
| 'consistent'
| 'undetermined';

/** Formal evaluation of a single argument. */
export interface ArgumentEvaluation {
/** The id of the argument this evaluation applies to. */
argumentId: string;
/** Whether the premises formally entail the sub-conclusion. */
internalValidity: EntailmentStrength;
/** How the sub-conclusion relates to the central claim. */
claimRelation: ClaimRelation;
/**
* Aggregate strength score in [0, 1].
*
* Computed as: mean(premise.confidence) × validityWeight
* where validityWeight is 1.0 (valid), 0.5 (consistent), 0.0 (otherwise).
*/
strength: number;
}

/** Pairwise formal tension between two arguments' sub-conclusions. */
export interface ArgumentTension {
argumentIdA: string;
argumentIdB: string;
/** The pairwise logical relation between the two sub-conclusions. */
conclusionRelation: PairwiseRelation;
}

/** Full output of DialecticalMap.evaluate(). */
export interface DialecticalMapResult {
claim: ContentiousClaim;
arguments: Argument[];
/** One evaluation per argument, in input order. */
evaluations: ArgumentEvaluation[];
/** C(n, 2) pairwise tension records for n arguments, in (i, j) order. */
tensions: ArgumentTension[];
}
Loading
Loading