OT Discourse Structure Analysis¶
Narrative peak and episode boundary detection in the Hebrew Old Testament, using the Longacre (1983) framework.
Terminology:
- PEAK — the climactic paragraph/episode, marked by dense wayyiqtol + speech
- EPISODE — a coherent narrative unit, separated by disjunctive/scene-setting clauses
- BACKBONE — the wayyiqtol chain that drives the main narrative forward
Peak score formula:
peak_score = 0.4 × wayyiqtol_density + 0.3 × speech_density + 0.3 × TTR
(all components normalised 0–1 within the book)
Questions this notebook answers:
- Where is the narrative peak of Genesis 22 (the Akedah)?
- How many episode boundaries are in Exodus 1–15?
- Which chapters of 1 Samuel have the highest wayyiqtol density?
- Where does direct speech cluster in Ruth?
Source: R. E. Longacre, The Grammar of Discourse (1983); MACULA Hebrew WLC dataset.
import sys
sys.path.insert(0, '../../../src')
from bible_grammar import (
ot_discourse_wayyiqtol_density, ot_discourse_speech_density,
ot_discourse_lexical_diversity, ot_discourse_peak_score,
ot_discourse_episode_boundaries, ot_discourse_narrative_profile,
print_ot_discourse_overview, print_ot_wayyiqtol_density,
print_ot_speech_density, print_ot_peak_score, print_ot_episode_boundaries,
ot_discourse_density_chart, ot_discourse_peak_chart,
)
import pandas as pd
1. Overview — Narrative Profile¶
# High-level summary for Genesis
print_ot_discourse_overview('Gen')
# Compare profiles across narrative books
for book in ['Gen', 'Exo', 'Rut', '1Sa', '2Sa', 'Jon']:
p = ot_discourse_narrative_profile(book)
print(f"{book:<5} tokens={p['total_tokens']:>6,} "
f"wyy%={p['wayyiqtol_pct']:>5.1f}% "
f"peak_ch={p['peak_chapter']} score={p['peak_score']}")
2. Wayyiqtol Density — The Narrative Backbone¶
Wayyiqtol (ויקטל) is the primary narrative tense in BH, forming the backbone of sequential narrative. High density indicates fast-moving action sequences; gaps often mark episode transitions.
print_ot_wayyiqtol_density('Gen')
# 1 Samuel — where does David's story intensify?
print_ot_wayyiqtol_density('1Sa')
# Chart: wayyiqtol vs. speech density for Ruth (short book, easy to see)
ot_discourse_density_chart('Rut')
# Chart for Genesis
ot_discourse_density_chart('Gen')
3. Speech Verb Density¶
Density of speech-reporting verbs (אָמַר, דָּבַר, נָאַם, קָרָא) as a proxy for direct speech. Longacre identifies elevated direct speech as a key narrative peak marker.
print_ot_speech_density('Gen')
# Ruth — a dialogue-heavy book
print_ot_speech_density('Rut')
# Jonah — four chapters, one prophet, lots of divine speech
print_ot_speech_density('Jon')
4. Narrative Peak Score¶
Composite score per chapter: 0.4 × wayyiqtol + 0.3 × speech + 0.3 × TTR
(all normalised 0–1 within the book). The crimson bar in the chart
marks the computed narrative peak.
print_ot_peak_score('Gen')
# Chart — Genesis
ot_discourse_peak_chart('Gen')
# Exodus — peak should be near the Exodus event / Red Sea crossing
print_ot_peak_score('Exo')
ot_discourse_peak_chart('Exo')
# 1 Samuel — expect peaks around Saul's rejection / David and Goliath (ch 17) / Saul's death (ch 31)
print_ot_peak_score('1Sa')
ot_discourse_peak_chart('1Sa')
5. Episode Boundary Detection¶
Episode boundaries are flagged when:
- A wayehi (וַיְהִי) scene-setting formula appears
- A wayyiqtol chain gap (≥3 verses without wayyiqtol) is followed by a qatal
print_ot_episode_boundaries('Gen')
# Ruth — four chapters, distinct episodes
print_ot_episode_boundaries('Rut')
# Exodus — episode count
boundaries = ot_discourse_episode_boundaries('Exo')
print(f"Exodus episode boundary signals: {len(boundaries)}")
boundaries.head(20)
6. Akedah Case Study — Genesis 22¶
Genesis 22 (the binding of Isaac) is a classic test case for narrative peak analysis. Longacre and others argue it is a tightly constructed narrative with the peak at vv. 9–12 (binding + angel stopping Abraham).
# Zoom into Gen 22 wayyiqtol density
wyy = ot_discourse_wayyiqtol_density('Gen')
print("Genesis 22 wayyiqtol density vs. surrounding chapters:")
wyy[wyy['chapter'].isin(range(20, 25))][['chapter', 'total_tokens', 'wayyiqtol_count', 'density']]
# Peak scores for Genesis 20–25
peaks = ot_discourse_peak_score('Gen')
peaks[peaks['chapter'].isin(range(20, 25))]
7. Ad-hoc Queries¶
# Which prophetic books still have wayyiqtol narrative sections?
for book in ['Isa', 'Jer', 'Eze', 'Hos', 'Amo', 'Jon', 'Mic']:
p = ot_discourse_narrative_profile(book)
print(f"{book:<5} wyy%={p['wayyiqtol_pct']:>5.1f}% "
f"peak_ch={str(p['peak_chapter']):>3} score={p['peak_score']}")
# Torah wayyiqtol density comparison
for book in ['Gen', 'Exo', 'Lev', 'Num', 'Deu']:
p = ot_discourse_narrative_profile(book)
bar = '█' * int(p['wayyiqtol_pct'] * 2)
print(f"{book:<5} {p['wayyiqtol_pct']:>5.1f}% {bar}")
# Custom: get the raw data for a specific chapter
sp = ot_discourse_speech_density('1Sa')
sp_sorted = sp.sort_values('density', ascending=False)
print("1 Samuel chapters with highest speech verb density:")
sp_sorted.head(10)