Primary and Secondary

This commit is contained in:
Oxy8
2026-02-10 17:38:54 -03:00
parent 022da71e6a
commit f3db6af958
9 changed files with 20636 additions and 200264 deletions

View File

@@ -2,15 +2,25 @@
* Random Tree Generator
*
* Generates a random tree with 1MAX_CHILDREN children per node.
* Exports a function that returns the tree data in memory.
* Splits edges into primary (depth ≤ PRIMARY_DEPTH) and secondary.
*
* Usage: npx tsx scripts/generate_tree.ts
*/
import { writeFileSync } from "fs";
import { join, dirname } from "path";
import { fileURLToPath } from "url";
const __dirname = dirname(fileURLToPath(import.meta.url));
const PUBLIC_DIR = join(__dirname, "..", "public");
// ══════════════════════════════════════════════════════════
// Configuration
// ══════════════════════════════════════════════════════════
const TARGET_NODES = 100000; // Approximate number of nodes to generate
const MAX_CHILDREN = 3; // Each node gets 1..MAX_CHILDREN children
const TARGET_NODES = 10000; // Approximate number of nodes to generate
const MAX_CHILDREN = 4; // Each node gets 1..MAX_CHILDREN children
const PRIMARY_DEPTH = 3; // Nodes at depth ≤ this form the primary skeleton
// ══════════════════════════════════════════════════════════
// Tree data types
@@ -21,6 +31,10 @@ export interface TreeData {
nodeCount: number;
childrenOf: Map<number, number[]>;
parentOf: Map<number, number>;
depthOf: Map<number, number>;
primaryNodes: Set<number>; // all nodes at depth ≤ PRIMARY_DEPTH
primaryEdges: Array<[number, number]>; // [child, parent] edges within primary
secondaryEdges: Array<[number, number]>;// remaining edges
}
// ══════════════════════════════════════════════════════════
@@ -30,14 +44,17 @@ export interface TreeData {
export function generateTree(): TreeData {
const childrenOf = new Map<number, number[]>();
const parentOf = new Map<number, number>();
const depthOf = new Map<number, number>();
const root = 0;
depthOf.set(root, 0);
let nextId = 1;
const queue: number[] = [root];
let head = 0;
while (head < queue.length && nextId < TARGET_NODES) {
const parent = queue[head++];
const parentDepth = depthOf.get(parent)!;
const nKids = 1 + Math.floor(Math.random() * MAX_CHILDREN); // 1..MAX_CHILDREN
const kids: number[] = [];
@@ -45,17 +62,71 @@ export function generateTree(): TreeData {
const child = nextId++;
kids.push(child);
parentOf.set(child, parent);
depthOf.set(child, parentDepth + 1);
queue.push(child);
}
childrenOf.set(parent, kids);
}
console.log(`Generated tree: ${nextId} nodes, ${parentOf.size} edges, root=${root}`);
// Classify edges and nodes by depth
const primaryNodes = new Set<number>();
const primaryEdges: Array<[number, number]> = [];
const secondaryEdges: Array<[number, number]> = [];
// Root is always primary
primaryNodes.add(root);
for (const [child, parent] of parentOf) {
const childDepth = depthOf.get(child)!;
if (childDepth <= PRIMARY_DEPTH) {
primaryNodes.add(child);
primaryNodes.add(parent);
primaryEdges.push([child, parent]);
} else {
secondaryEdges.push([child, parent]);
}
}
console.log(
`Generated tree: ${nextId} nodes, ` +
`${primaryEdges.length} primary edges (depth ≤ ${PRIMARY_DEPTH}), ` +
`${secondaryEdges.length} secondary edges`
);
return {
root,
nodeCount: nextId,
childrenOf,
parentOf,
depthOf,
primaryNodes,
primaryEdges,
secondaryEdges,
};
}
// ══════════════════════════════════════════════════════════
// Run if executed directly
// ══════════════════════════════════════════════════════════
if (import.meta.url === `file://${process.argv[1]}`) {
const data = generateTree();
// Write primary_edges.csv
const pLines: string[] = ["source,target"];
for (const [child, parent] of data.primaryEdges) {
pLines.push(`${child},${parent}`);
}
const pPath = join(PUBLIC_DIR, "primary_edges.csv");
writeFileSync(pPath, pLines.join("\n") + "\n");
console.log(`Wrote ${data.primaryEdges.length} edges to ${pPath}`);
// Write secondary_edges.csv
const sLines: string[] = ["source,target"];
for (const [child, parent] of data.secondaryEdges) {
sLines.push(`${child},${parent}`);
}
const sPath = join(PUBLIC_DIR, "secondary_edges.csv");
writeFileSync(sPath, sLines.join("\n") + "\n");
console.log(`Wrote ${data.secondaryEdges.length} edges to ${sPath}`);
}