neural/inf/rs/cli/src/main.rs

//! The `inf` command-line tool: parse, plan, cost, and run inf programs.
//!
//! Commands:
//!   inf check <file>     parse + plan; report strata or errors
//!   inf plan  <file>     print the compiled IR
//!   inf cost  <file>     report a static cycle-ceiling estimate
//!   inf run   <file>     evaluate against the built-in demo graph and print rows
//!
//! `run`/`cost` evaluate over a built-in demo graph (the bootstrap has no bbg
//! source yet); the engine and pipeline are otherwise the real thing.

mod demo;

use inf_eval::{eval, Ctx, MutOp, Output};
use inf_parse::parse;
use inf_plan::plan;
use inf_source::RelationSource;
use inf_value::{Tuple, Value};
use std::process::exit;

fn main() {
    let args: Vec<String> = std::env::args().collect();
    if args.len() < 3 {
        eprintln!("usage: inf <check|plan|cost|run> <file.inf>");
        exit(2);
    }
    let cmd = args[1].as_str();
    let src = match std::fs::read_to_string(&args[2]) {
        Ok(s) => s,
        Err(e) => {
            eprintln!("cannot read {}: {e}", args[2]);
            exit(2);
        }
    };
    let code = match cmd {
        "check" => cmd_check(&src),
        "plan" => cmd_plan(&src),
        "cost" => cmd_cost(&src),
        "run" => cmd_run(&src),
        other => {
            eprintln!("unknown command `{other}` (use check|plan|cost|run)");
            2
        }
    };
    exit(code);
}

fn parse_plan(src: &str) -> Result<inf_ast::IrProgram, i32> {
    let prog = parse(src).map_err(|e| {
        eprintln!("parse error [{}:{}]: {}", e.line, e.col, e.msg);
        1
    })?;
    plan(&prog).map_err(|e| {
        eprintln!("plan error: {}", e.msg);
        1
    })
}

fn cmd_check(src: &str) -> i32 {
    match parse_plan(src) {
        Ok(ir) => {
            let rec = ir.strata.iter().filter(|s| s.recursive).count();
            println!(
                "ok: {} strata ({rec} recursive), entry `{}`{}",
                ir.strata.len(),
                ir.entry,
                if ir.mutation.is_some() { ", mutation" } else { "" }
            );
            0
        }
        Err(c) => c,
    }
}

fn cmd_plan(src: &str) -> i32 {
    match parse_plan(src) {
        Ok(ir) => {
            for (i, s) in ir.strata.iter().enumerate() {
                println!(
                    "stratum {i}{}{}:",
                    if s.recursive { " (recursive)" } else { "" },
                    s.bound.map(|b| format!(" bound={b}")).unwrap_or_default()
                );
                for r in &s.rules {
                    let h = r.head.name.clone().unwrap_or_else(|| "?".into());
                    if let Some(f) = &r.fixed {
                        println!("  {h} <~ {}({}[], ..)", f.algo, f.edges);
                    } else {
                        println!("  {h} := ({} atoms)", r.body.len());
                    }
                }
            }
            0
        }
        Err(c) => c,
    }
}

fn cmd_cost(src: &str) -> i32 {
    let ir = match parse_plan(src) {
        Ok(ir) => ir,
        Err(c) => return c,
    };
    let mut g = demo::graph();
    g.ensure_stats(); // compute committed stats from demo data

    // Committed stats when available (specs/cost.md): node_count + relation_sizes
    // from the BBG root give a static bound without scanning at query time.
    let stats = g.graph_stats();
    let node_count = stats.as_ref().map(|s| s.node_count).unwrap_or(64);
    let diameter = stats.as_ref().map(|s| s.diameter_bound).unwrap_or(16);

    // A static estimate: ฮฃ strata (rounds ร— ฮฃ rules ฮฃ read-atoms ร— relation size).
    // rounds = explicit `:bounded N` for recursive strata, else diameter_bound.
    let size = |rel: &str| -> u64 {
        if let Some(_s) = g.schema(rel) {
            g.scan(rel).count() as u64
        } else {
            // derived relation: bound by the committed node_count
            node_count
        }
    };
    let mut reads = 0u64;
    let mut combine = 0u64;
    let mut total = 0u64;
    let mut max_rounds = 1u64;
    for s in &ir.strata {
        let rounds = if s.recursive {
            s.bound.unwrap_or(diameter) // committed diameter if no explicit bound
        } else {
            1
        };
        max_rounds = max_rounds.max(rounds);
        let (mut sr, mut sc) = (0u64, 0u64);
        for r in &s.rules {
            if let Some(f) = &r.fixed {
                sr = sr.saturating_add(size(&f.edges));
                sc = sc.saturating_add(size(&f.edges).saturating_mul(7)); // algorithm core
            } else {
                let mut natoms = 0u64;
                for a in &r.body {
                    if let Some(rel) = a.rel_name() {
                        sr = sr.saturating_add(size(rel));
                        natoms += 1;
                    }
                }
                sc = sc.saturating_add(natoms.saturating_sub(1).saturating_mul(4)); // joins
            }
        }
        reads = reads.saturating_add(sr);
        combine = combine.saturating_add(sc);
        total = total.saturating_add(rounds.saturating_mul(sr.saturating_add(sc)));
    }
    println!("estimated work: ~{total} units");
    println!("  reads:     {reads}  (Lens openings / scans โ€” bbg side)");
    println!("  combine:   {combine}  (joins + algorithm cores โ€” inf side)");
    println!("  recursion: up to ร—{max_rounds} on recursive strata");
    if let Some(s) = &stats {
        println!("  committed: node_count={} diameter_bound={} max_degree={}",
            s.node_count, s.diameter_bound, s.max_degree);
    }
    0
}

fn cmd_run(src: &str) -> i32 {
    let ir = match parse_plan(src) {
        Ok(ir) => ir,
        Err(c) => return c,
    };
    match eval(&ir, &demo::graph(), &Ctx::default()) {
        Ok(out) => {
            print_output(&out);
            0
        }
        Err(e) => {
            eprintln!("eval error: {}", e.msg);
            1
        }
    }
}

fn print_output(out: &Output) {
    if let Some(m) = &out.mutation {
        let op = match m {
            MutOp::Link => "link".to_string(),
            MutOp::Unlink => "unlink".to_string(),
            MutOp::Put(r) => format!("put {r}"),
            MutOp::Rm(r) => format!("rm {r}"),
        };
        println!("signal ({op}) โ€” {} cyberlinks", out.rows.len());
    }
    println!("{}", out.columns.join("\t"));
    for row in &out.rows {
        let cells: Vec<String> = row.iter().map(fmt_value).collect();
        println!("{}", cells.join("\t"));
    }
    if out.mutation.is_none() {
        println!("({} rows)", out.rows.len());
    }
}

fn fmt_value(v: &Value) -> String {
    match v {
        Value::Null => "null".into(),
        Value::Bool(b) => b.to_string(),
        Value::Int(i) => i.to_string(),
        Value::Field(f) => format!("f{}", f.val()),
        Value::Word(w) => w.to_string(),
        Value::Hash(h) => format!("#{:02x}{:02x}{:02x}{:02x}", h[0], h[1], h[2], h[3]),
        Value::Bytes(b) => match std::str::from_utf8(b) {
            Ok(s) => format!("\"{s}\""),
            Err(_) => format!("0x{}", b.iter().map(|x| format!("{x:02x}")).collect::<String>()),
        },
        Value::List(items) => {
            let inner: Vec<String> = items.iter().map(fmt_value).collect();
            format!("[{}]", inner.join(", "))
        }
    }
}

#[allow(dead_code)]
fn _tuple_marker(_: &Tuple) {}

Homonyms

cyberia/src/main.rs
cyb/src-tauri/src/main.rs
soft3/tru/cli/main.rs
neural/rune/cli/main.rs
cyb/cyb-boot/src/main.rs
soft3/glia/import/main.rs
warriors/trisha/cli/main.rs
neural/trident/src/main.rs
cyb/optica/src/main.rs
soft3/nox/cli/main.rs
neural/rs/link/src/main.rs
neural/rs/macho-linker/src/main.rs
soft3/zheng/cli/src/main.rs
cyb/cyb/cyb-portal/src/main.rs
neural/rs/pure-rust-check/src/main.rs
cyb/cyb/cyb-ui/src/main.rs
soft3/foculus/src/bin/main.rs
neural/eidos/cli/src/main.rs
soft3/glia/run/cli/main.rs
soft3/radio/iroh-relay/src/main.rs
cyb/cyb/cyb-shell/src/main.rs
neural/rs/rsc/src/main.rs
soft3/cybergraph/cli/src/main.rs
soft3/bbg/cli/src/main.rs
soft3/radio/radio-cli/src/main.rs
soft3/radio/particle/src/main.rs
soft3/hemera/cli/src/main.rs
soft3/radio/iroh-dns-server/src/main.rs
soft3/strata/trop/cli/src/main.rs
cyb/honeycrisp/rane/src/probe/main.rs
soft3/strata/kuro/cli/src/main.rs
soft3/strata/genies/cli/src/main.rs
bootloader/go-cyber/mcp/rust/src/main.rs
cyb/wysm/crates/cli/src/main.rs
soft3/strata/nebu/cli/src/main.rs
cyb/honeycrisp/acpu/src/probe/main.rs
soft3/strata/jali/cli/src/main.rs
cyb/honeycrisp/unimem/experiments/hyp_probe/src/main.rs
cyb/honeycrisp/unimem/experiments/iosurface_probe/src/main.rs
cyb/honeycrisp/unimem/experiments/dext_iosurface_pa/client/src/main.rs
cyb/honeycrisp/unimem/experiments/dext_contiguous_alloc/client/src/main.rs

Graph