Primary and Secondary
This commit is contained in:
@@ -2,15 +2,25 @@
|
||||
* Random Tree Generator
|
||||
*
|
||||
* Generates a random tree with 1–MAX_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}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user