#!/usr/bin/env node
/**
* Build Euclid's Elements Book I discourse JSON and Mermaid.
* Dependencies from David E. Joyce, Clark University:
* https://mathcs.clarku.edu/~djoyce/java/elements/bookI/bookI.html
*/
const fs = require('fs');
const path = require('path');
const PROPOSITIONS = [
{ n: 1, short: "Equilateral triangle on given line", full: "To construct an equilateral triangle on a given finite straight line" },
{ n: 2, short: "Place line equal to given at point", full: "To place a straight line equal to a given straight line with one end at a given point" },
{ n: 3, short: "Cut off from greater segment equal to less", full: "To cut off from the greater of two given unequal straight lines a straight line equal to the less" },
{ n: 4, short: "SAS congruence", full: "If two triangles have two sides equal to two sides respectively, and the angles contained equal, then bases and remaining angles equal" },
{ n: 5, short: "Base angles of isosceles equal", full: "In isosceles triangles the angles at the base equal one another" },
{ n: 6, short: "Sides opposite equal angles equal", full: "If in a triangle two angles equal one another, then the sides opposite the equal angles also equal one another" },
{ n: 7, short: "Uniqueness of triangle from ends", full: "Given two lines from ends of a line meeting at a point, no other such pair from same ends on same side" },
{ n: 8, short: "SSS congruence", full: "If two triangles have two sides equal to two sides respectively, and the base equal to the base, then the angles contained are equal" },
{ n: 9, short: "Bisect angle", full: "To bisect a given rectilinear angle" },
{ n: 10, short: "Bisect line", full: "To bisect a given finite straight line" },
{ n: 11, short: "Perpendicular from point on line", full: "To draw a straight line at right angles to a given straight line from a given point on it" },
{ n: 12, short: "Perpendicular from point not on line", full: "To draw a straight line perpendicular to a given infinite straight line from a given point not on it" },
{ n: 13, short: "Angles on line sum to two right", full: "If a straight line stands on a straight line, it makes either two right angles or angles whose sum equals two right angles" },
{ n: 14, short: "If angles sum to two right, straight line", full: "If with any straight line, at a point, two lines not on same side make adjacent angles equal to two right, they are in a straight line" },
{ n: 15, short: "Vertical angles equal", full: "If two straight lines cut one another, they make the vertical angles equal to one another" },
{ n: 16, short: "Exterior angle > interior opposite", full: "In any triangle, if one side is produced, the exterior angle is greater than either interior opposite angle" },
{ n: 17, short: "Sum of two angles < two right", full: "In any triangle the sum of any two angles is less than two right angles" },
{ n: 18, short: "Angle opposite greater side greater", full: "In any triangle the angle opposite the greater side is greater" },
{ n: 19, short: "Side opposite greater angle greater", full: "In any triangle the side opposite the greater angle is greater" },
{ n: 20, short: "Triangle inequality", full: "In any triangle the sum of any two sides is greater than the remaining one" },
{ n: 21, short: "Lines from ends within triangle", full: "If from ends of one side two lines meet within the triangle, their sum < sum of other two sides" },
{ n: 22, short: "Construct triangle from three lines", full: "To construct a triangle out of three straight lines which equal three given straight lines" },
{ n: 23, short: "Construct angle equal to given", full: "To construct a rectilinear angle equal to a given rectilinear angle on a given straight line" },
{ n: 24, short: "SAS for greater angle => greater base", full: "If two triangles have two sides equal but one contained angle greater, the base is greater" },
{ n: 25, short: "SAS for greater base => greater angle", full: "If two triangles have two sides equal but base greater, the contained angle is greater" },
{ n: 26, short: "AAS congruence", full: "If two triangles have two angles equal and one side equal, the remaining sides and angle equal" },
{ n: 27, short: "Alternate angles equal => parallel", full: "If a line falling on two lines makes alternate angles equal, the lines are parallel" },
{ n: 28, short: "Exterior = interior opposite => parallel", full: "If exterior angle equals interior opposite, or interior same-side sum to two right, lines parallel" },
{ n: 29, short: "Parallel => alternate angles equal", full: "A line falling on parallel lines makes alternate angles equal, exterior = interior opposite" },
{ n: 30, short: "Transitivity of parallel", full: "Straight lines parallel to the same straight line are also parallel to one another" },
{ n: 31, short: "Draw parallel through point", full: "To draw a straight line through a given point parallel to a given straight line" },
{ n: 32, short: "Exterior angle = sum interior opposite", full: "In any triangle, exterior angle equals sum of two interior opposite; three angles = two right" },
{ n: 33, short: "Joining ends of equal parallel lines", full: "Straight lines which join the ends of equal and parallel straight lines in same directions are equal and parallel" },
{ n: 34, short: "Parallelogram properties", full: "In parallelogrammic areas the opposite sides and angles equal one another, diameter bisects" },
{ n: 35, short: "Parallelograms same base equal", full: "Parallelograms which are on the same base and in the same parallels equal one another" },
{ n: 36, short: "Parallelograms equal bases equal", full: "Parallelograms which are on equal bases and in the same parallels equal one another" },
{ n: 37, short: "Triangles same base equal", full: "Triangles which are on the same base and in the same parallels equal one another" },
{ n: 38, short: "Triangles equal bases equal", full: "Triangles which are on equal bases and in the same parallels equal one another" },
{ n: 39, short: "Equal triangles same base same side", full: "Equal triangles on same base and same side are in the same parallels" },
{ n: 40, short: "Equal triangles equal bases same side", full: "Equal triangles on equal bases and same side are in the same parallels" },
{ n: 41, short: "Parallelogram = 2× triangle", full: "If a parallelogram has same base with triangle and same parallels, parallelogram is double the triangle" },
{ n: 42, short: "Construct parallelogram = triangle", full: "To construct a parallelogram equal to a given triangle in a given rectilinear angle" },
{ n: 43, short: "Complements of parallelogram", full: "In any parallelogram the complements of the parallelograms about the diameter equal one another" },
{ n: 44, short: "Apply parallelogram to line", full: "To a given straight line in a given angle, to apply a parallelogram equal to a given triangle" },
{ n: 45, short: "Construct parallelogram = rectilinear figure", full: "To construct a parallelogram equal to a given rectilinear figure in a given rectilinear angle" },
{ n: 46, short: "Construct square on line", full: "To describe a square on a given straight line" },
{ n: 47, short: "Pythagorean theorem", full: "In right-angled triangles the square on the side opposite the right angle equals the sum of the squares on the sides containing the right angle" },
{ n: 48, short: "Converse Pythagorean", full: "If in a triangle the square on one side equals the sum of squares on the other two, the angle contained by those sides is right" }
];
// Joyce dependency table: { prop: [deps] }
const DEPS = {
1: ["P1", "P3"],
2: ["Prop1", "P1", "P2", "P3"],
3: ["Prop2", "P3"],
4: ["CN4", "CN5"],
5: ["Prop3", "Prop4"],
6: ["Prop3", "Prop4"],
7: ["Prop5"],
8: ["Prop7"],
9: ["Prop1", "Prop3", "Prop8"],
10: ["Prop1", "Prop4", "Prop9"],
11: ["Prop1", "Prop3", "Prop8"],
12: ["Prop8", "Prop10"],
13: ["Prop11"],
14: ["Prop13"],
15: ["Prop13"],
16: ["Prop3", "Prop4", "Prop10", "Prop15"],
17: ["Prop13", "Prop16"],
18: ["Prop3", "Prop5", "Prop16"],
19: ["Prop5", "Prop18"],
20: ["Prop3", "Prop5", "Prop19"],
21: ["Prop16", "Prop20"],
22: ["Prop3", "Prop20"],
23: ["Prop8", "Prop22"],
24: ["Prop3", "Prop4", "Prop5", "Prop19", "Prop23"],
25: ["Prop4", "Prop24"],
26: ["Prop3", "Prop4", "Prop16"],
27: ["Prop16"],
28: ["Prop13", "Prop15", "Prop27"],
29: ["Prop13", "Prop15", "Prop27", "P5"],
30: ["Prop29"],
31: ["Prop23", "Prop27"],
32: ["Prop13", "Prop29", "Prop31"],
33: ["Prop4", "Prop27", "Prop29"],
34: ["Prop4", "Prop26", "Prop29"],
35: ["Prop4", "Prop29", "Prop34"],
36: ["Prop33", "Prop34", "Prop35"],
37: ["Prop31", "Prop34", "Prop35"],
38: ["Prop31", "Prop34", "Prop36"],
39: ["Prop31", "Prop37"],
40: ["Prop31", "Prop38"],
41: ["Prop34", "Prop37"],
42: ["Prop10", "Prop23", "Prop31", "Prop38", "Prop41"],
43: ["Prop34"],
44: ["Prop15", "Prop29", "Prop31", "Prop42", "Prop43"],
45: ["Prop14", "Prop29", "Prop30", "Prop33", "Prop34", "Prop42", "Prop44"],
46: ["Prop3", "Prop11", "Prop29", "Prop31", "Prop34"],
47: ["Prop4", "Prop14", "Prop31", "Prop41", "Prop46"],
48: ["Prop3", "Prop8", "Prop11", "Prop47"]
};
const discourse = {
schemaVersion: "1.0",
discourse: {
id: "euclid-elements-book-i",
name: "Euclid's Elements, Book I",
subject: "geometry",
variant: "classical",
description: "The 48 propositions of Book I with dependencies on postulates (P1–P5), common notions (CN1–CN5), and prior propositions. Source: David E. Joyce, Clark University.",
structure: { books: 1, propositions: 48, foundationTypes: ["postulate", "commonNotion"] }
},
metadata: {
created: "2026-03-15",
lastUpdated: "2026-03-15",
version: "1.0.0",
license: "CC BY 4.0",
authors: ["Welz, G."],
methodology: "Programming Framework",
citation: "Welz, G. (2026). Euclid's Elements Book I Dependency Graph. Programming Framework.",
keywords: ["Euclid", "Elements", "Book I", "plane geometry", "constructions", "Pythagorean theorem"]
},
sources: [
{ id: "joyce", type: "digital", authors: "Joyce, David E.", title: "Euclid's Elements, Book I", year: "1996", url: "https://mathcs.clarku.edu/~djoyce/java/elements/bookI/bookI.html", notes: "Clark University; dependency table from Guide" },
{ id: "euclid-heath", type: "primary", authors: "Heath, T.L.", title: "The Thirteen Books of Euclid's Elements", year: "1908", edition: "2nd", publisher: "Cambridge University Press", url: "https://archive.org/details/euclidheath00heatiala", notes: "Standard English translation" }
],
nodes: [],
edges: [],
colorScheme: {
postulate: { fill: "#e74c3c", stroke: "#c0392b" },
commonNotion: { fill: "#9b59b6", stroke: "#8e44ad" },
proposition: { fill: "#1abc9c", stroke: "#16a085" }
}
};
// Add postulates and common notions
const postulates = [
{ id: "P1", label: "Draw a straight line from any point to any point", shortLabel: "Post. 1" },
{ id: "P2", label: "Produce a finite straight line continuously in a straight line", shortLabel: "Post. 2" },
{ id: "P3", label: "Describe a circle with any center and radius", shortLabel: "Post. 3" },
{ id: "P4", label: "All right angles equal one another", shortLabel: "Post. 4" },
{ id: "P5", label: "Parallel postulate: if interior angles < two right, lines meet", shortLabel: "Post. 5" }
];
const commonNotions = [
{ id: "CN1", label: "Things equal to the same thing are equal to each other", shortLabel: "CN 1" },
{ id: "CN2", label: "If equals are added to equals, the wholes are equal", shortLabel: "CN 2" },
{ id: "CN3", label: "If equals are subtracted from equals, the remainders are equal", shortLabel: "CN 3" },
{ id: "CN4", label: "Things coinciding with one another are equal", shortLabel: "CN 4" },
{ id: "CN5", label: "The whole is greater than the part", shortLabel: "CN 5" }
];
for (const p of postulates) {
discourse.nodes.push({ id: p.id, type: "postulate", label: p.label, shortLabel: p.shortLabel, book: 1, number: parseInt(p.id.slice(1)), colorClass: "postulate" });
}
for (const c of commonNotions) {
discourse.nodes.push({ id: c.id, type: "commonNotion", label: c.label, shortLabel: c.shortLabel, book: 1, number: parseInt(c.id.slice(2)), colorClass: "commonNotion" });
}
// Add propositions
for (const prop of PROPOSITIONS) {
discourse.nodes.push({
id: `Prop${prop.n}`,
type: "proposition",
label: prop.full,
shortLabel: `Prop. I.${prop.n}`,
short: prop.short,
book: 1,
number: prop.n,
colorClass: "proposition"
});
for (const dep of DEPS[prop.n] || []) {
discourse.edges.push({ from: dep, to: `Prop${prop.n}` });
}
}
// Write JSON
const dataDir = path.join(__dirname, "..", "data");
const outPath = path.join(dataDir, "euclid-elements-book-i.json");
fs.mkdirSync(dataDir, { recursive: true });
fs.writeFileSync(outPath, JSON.stringify(discourse, null, 2), "utf8");
console.log("Wrote", outPath);
// Generate Mermaid (full graph - may be large)
function toMermaid(filter) {
const nodes = filter ? discourse.nodes.filter(filter) : discourse.nodes;
const nodeIds = new Set(nodes.map(n => n.id));
const edges = discourse.edges.filter(e => nodeIds.has(e.from) && nodeIds.has(e.to));
const lines = ["graph TD"];
for (const n of nodes) {
const desc = n.short || (n.label.length > 35 ? n.label.slice(0, 32) + "..." : n.label);
const lbl = (n.shortLabel || n.id) + "\\n" + desc;
lines.push(` ${n.id}["${lbl.replace(/"/g, '\\"')}"]`);
}
for (const e of edges) {
lines.push(` ${e.from} --> ${e.to}`);
}
lines.push(" classDef postulate fill:#e74c3c,color:#fff,stroke:#c0392b");
lines.push(" classDef commonNotion fill:#9b59b6,color:#fff,stroke:#8e44ad");
lines.push(" classDef proposition fill:#1abc9c,color:#fff,stroke:#16a085");
const postIds = nodes.filter(n => n.type === "postulate").map(n => n.id).join(",");
const cnIds = nodes.filter(n => n.type === "commonNotion").map(n => n.id).join(",");
const propIds = nodes.filter(n => n.type === "proposition").map(n => n.id).join(",");
lines.push(` class ${postIds} postulate`);
lines.push(` class ${cnIds} commonNotion`);
lines.push(` class ${propIds} proposition`);
return lines.join("\n");
}
// Full graph
const fullMermaid = toMermaid();
const mermaidPath = path.join(dataDir, "euclid-elements-book-i.mmd");
fs.writeFileSync(mermaidPath, fullMermaid, "utf8");
console.log("Wrote", mermaidPath);
// Subgraphs: include foundations + props in range + all their dependencies (transitive)
function closure(propMin, propMax) {
const needed = new Set();
for (let i = propMin; i <= propMax; i++) needed.add(`Prop${i}`);
let changed = true;
while (changed) {
changed = false;
for (const e of discourse.edges) {
if (needed.has(e.to) && !needed.has(e.from)) { needed.add(e.from); changed = true; }
}
}
return n => n.type !== "proposition" || needed.has(n.id);
}
function toMermaidWithCounts(filter) {
const nodes = filter ? discourse.nodes.filter(filter) : discourse.nodes;
const nodeIds = new Set(nodes.map(n => n.id));
const edges = discourse.edges.filter(e => nodeIds.has(e.from) && nodeIds.has(e.to));
return { mermaid: toMermaid(filter), nodes: nodes.length, edges: edges.length };
}
const subgraphData = [];
const sections = [
{ name: "props-1-10", min: 1, max: 10, title: "Propositions 1–10", desc: "Foundations, SAS, SSS, bisections, perpendiculars" },
{ name: "props-11-20", min: 11, max: 20, title: "Propositions 11–20", desc: "Right angles, straight lines, vertical angles, triangle exterior, triangle inequality" },
{ name: "props-21-30", min: 21, max: 30, title: "Propositions 21–30", desc: "Lines within triangle, construct triangle/angle, parallel lines" },
{ name: "props-31-41", min: 31, max: 41, title: "Propositions 31–41", desc: "Parallelograms, triangles, areas" },
{ name: "props-42-48", min: 42, max: 48, title: "Propositions 42–48", desc: "Constructions, Pythagorean theorem" }
];
for (const s of sections) {
const { mermaid: sub, nodes: n, edges: e } = toMermaidWithCounts(closure(s.min, s.max));
subgraphData.push({ ...s, mermaid: sub, nodes: n, edges: e });
const subPath = path.join(dataDir, `euclid-elements-book-i-${s.name}.mmd`);
fs.writeFileSync(subPath, sub, "utf8");
console.log("Wrote", subPath);
}
// Generate HTML pages for Mathematics Processes Database
const MATH_DB = process.env.MATH_DB || "/home/gdubs/copernicus-web-public/huggingface-space/mathematics-processes-database";
const GEOM_DIR = path.join(MATH_DB, "processes", "geometry_topology");
function htmlTemplate(title, subtitle, mermaid, nodes, edges) {
const mermaidEscaped = mermaid.replace(//g, ">");
return `
${title} - Mathematics Process
Dependency Flowchart
Note: Arrows mean "depends on" (tail → head). Edge crossing can create illusions of connections between adjacent nodes—e.g., I.47 and I.40 have no direct dependency; both depend on I.31 among others.
${mermaidEscaped}
Statistics
- Nodes: ${nodes}
- Edges: ${edges}
Keywords
- Euclid
- Elements
- Book I
- axioms
- postulates
- propositions
- geometry
- Pythagorean theorem
`;
}
if (fs.existsSync(GEOM_DIR)) {
for (const d of subgraphData) {
const html = htmlTemplate(
`Euclid's Elements Book I — ${d.title}`,
`Dependency graph for ${d.title} of Euclid's Elements Book I. ${d.desc}. Shows how propositions depend on postulates (P1–P5), common notions (CN1–CN5), and prior propositions.`,
d.mermaid,
d.nodes,
d.edges
);
const fileName = "geometry_topology-euclid-elements-book-i-" + d.name;
fs.writeFileSync(path.join(GEOM_DIR, fileName + ".html"), html, "utf8");
console.log("Wrote", path.join(GEOM_DIR, fileName + ".html"));
}
// Index page
const indexHtml = `
Euclid's Elements Book I - Mathematics Process
Euclid's Elements, Book I
Full dependency graph of all 48 propositions. Dependencies from David E. Joyce, Clark University. Split into five views for clarity.
Propositions 1–10 — Foundations, SAS, SSS, bisections, perpendiculars
Propositions 11–20 — Right angles, straight lines, vertical angles, triangle exterior, triangle inequality
Propositions 21–30 — Lines within triangle, construct triangle/angle, parallel lines
Propositions 31–41 — Parallelograms, triangles, areas
Propositions 42–48 — Constructions, Pythagorean theorem
`;
fs.writeFileSync(path.join(GEOM_DIR, "geometry_topology-euclid-elements-book-i.html"), indexHtml, "utf8");
console.log("Wrote", path.join(GEOM_DIR, "geometry_topology-euclid-elements-book-i.html"));
} else {
console.log("MATH_DB not found at", GEOM_DIR, "- skipping HTML generation. Set MATH_DB or ensure copernicus-web-public is available.");
}
console.log("Done. Nodes:", discourse.nodes.length, "Edges:", discourse.edges.length);