Alchemical Hands in the Hypnerotomachia Poliphili

Marginalia, Scholarship & Reception

← All Scripts

Build Signature Map

build_signature_map.py — 103 lines

Generates the 448-entry signature-to-folio concordance from the Aldine collation formula (a-z, A-G).

1"""Build the signature-to-folio mapping table for the 1499 Aldine HP.
2
3The 1499 Aldus Manutius edition uses the standard Aldine collation:
4  Quires a-z (skipping j, u, w) then A-G
5  Each quire has 8 leaves (quaternion format)
6  Each leaf has recto (r) and verso (v)
7
8Collation formula: a-y⁸ z⁴ A-F⁸ G⁴ = 234 leaves = 468 pages
9
10This produces a deterministic lookup: signature "a1r" = folio 1 recto,
11"a1v" = folio 1 verso, "b1r" = folio 9 recto, etc.
12"""
13
14import sqlite3
15from pathlib import Path
16
17BASE_DIR = Path(__file__).resolve().parent.parent
18DB_PATH = BASE_DIR / "db" / "hp.db"
19
20# Standard Aldine quire sequence for the 1499 HP
21# Lowercase quires: a through y, skipping j, u, w
22LOWERCASE_QUIRES = [c for c in 'abcdefghiklmnopqrstxyz']
23# Uppercase quires (for the second alphabet run): A through G
24UPPERCASE_QUIRES = list('ABCDEFG')
25
26# Leaves per quire - most are 8 (quaternion), but z and G are 4
27QUIRE_SIZES = {}
28for q in LOWERCASE_QUIRES:
29    QUIRE_SIZES[q] = 4 if q == 'z' else 8
30for q in UPPERCASE_QUIRES:
31    QUIRE_SIZES[q] = 4 if q == 'G' else 8
32
33
34def generate_signatures():
35    """Generate all signatures in order with their sequential folio numbers."""
36    all_quires = LOWERCASE_QUIRES + UPPERCASE_QUIRES
37    folio_num = 1
38    entries = []
39
40    for quire in all_quires:
41        leaves = QUIRE_SIZES[quire]
42        for leaf in range(1, leaves + 1):
43            for side in ('r', 'v'):
44                sig = f"{quire}{leaf}{side}"
45                entries.append({
46                    'signature': sig,
47                    'folio_number': folio_num,
48                    'side': side,
49                    'quire': quire,
50                    'leaf_in_quire': leaf,
51                })
52            folio_num += 1
53
54    return entries
55
56
57def main():
58    entries = generate_signatures()
59
60    conn = sqlite3.connect(DB_PATH)
61    cur = conn.cursor()
62
63    # Clear existing entries
64    cur.execute("DELETE FROM signature_map")
65
66    for e in entries:
67        cur.execute(
68            """INSERT INTO signature_map
69               (signature, folio_number, side, quire, leaf_in_quire)
70               VALUES (?, ?, ?, ?, ?)""",
71            (e['signature'], e['folio_number'], e['side'], e['quire'], e['leaf_in_quire'])
72        )
73
74    conn.commit()
75
76    # Summary
77    total = len(entries)
78    quire_count = len(LOWERCASE_QUIRES) + len(UPPERCASE_QUIRES)
79    max_folio = entries[-1]['folio_number']
80    print(f"Built signature map: {total} entries, {quire_count} quires, {max_folio} folios")
81    print(f"  First: {entries[0]['signature']} = folio {entries[0]['folio_number']}")
82    print(f"  Last:  {entries[-1]['signature']} = folio {entries[-1]['folio_number']}")
83
84    # Spot checks
85    print("\nSpot checks:")
86    cur.execute("SELECT signature, folio_number FROM signature_map WHERE signature = 'a1r'")
87    r = cur.fetchone()
88    print(f"  a1r -> folio {r[1]}" if r else "  a1r NOT FOUND")
89
90    cur.execute("SELECT signature, folio_number FROM signature_map WHERE signature = 'b1r'")
91    r = cur.fetchone()
92    print(f"  b1r -> folio {r[1]}" if r else "  b1r NOT FOUND")
93
94    cur.execute("SELECT signature, folio_number FROM signature_map WHERE signature = 'e1r'")
95    r = cur.fetchone()
96    print(f"  e1r -> folio {r[1]} (Russell's methodology boundary)" if r else "  e1r NOT FOUND")
97
98    conn.close()
99    print("\nDone.")
100
101
102if __name__ == "__main__":
103    main()