Skip to content

Locy Use Case: Probabilistic Risk Scoring (Rust)

Evaluate vendor reliability by combining independent quality signals with MNOR (noisy-OR failure) and MPROD (joint reliability).

This notebook uses schema-first mode and mirrors the Python flow using the Rust API (uni_db).

How To Read This Notebook

  • Define schema first, then load data.
  • Keep Locy rules declarative and focused.
  • Read output rows together with materialization stats.

1) Setup

Initialize an in-memory database and import DataType for schema definitions.

use uni_db::{DataType, Uni, Result};

let db = Uni::in_memory().build().await?;

Define labels, typed properties, and edge types before inserting graph facts.

db.schema()
    .label("Vendor")
        .property("name", DataType::String)
    .label("Component")
        .property("name", DataType::String)
    .label("QualitySignal")
        .property("name", DataType::String)
        .property("pass_rate", DataType::Float64)
    .edge_type("SUPPLIES", &["Vendor"], &["Component"])
    .edge_type("HAS_SIGNAL", &["Component"], &["QualitySignal"])
    .apply()
    .await?;

println!("Schema created");

3) Seed Graph Data

Insert the minimal graph needed for the scenario.

let session = db.session();
let tx = session.tx().await?;
tx.execute("CREATE (:Vendor {name: 'ReliaCorp'})").await?;
tx.execute("CREATE (:Vendor {name: 'QuickParts'})").await?;
tx.execute("CREATE (:Vendor {name: 'BudgetSupply'})").await?;
tx.execute("CREATE (:Component {name: 'Sensor'})").await?;
tx.execute("CREATE (:Component {name: 'Motor'})").await?;
tx.execute("CREATE (:Component {name: 'Controller'})").await?;
tx.execute("CREATE (:Component {name: 'Battery'})").await?;
tx.execute("CREATE (:QualitySignal {name: 'Thermal Test', pass_rate: 0.95})").await?;
tx.execute("CREATE (:QualitySignal {name: 'Vibration Test', pass_rate: 0.90})").await?;
tx.execute("CREATE (:QualitySignal {name: 'Voltage Tolerance', pass_rate: 0.85})").await?;
tx.execute("CREATE (:QualitySignal {name: 'Humidity Test', pass_rate: 0.92})").await?;
tx.execute("CREATE (:QualitySignal {name: 'Load Test', pass_rate: 0.88})").await?;
tx.execute("CREATE (:QualitySignal {name: 'EMC Test', pass_rate: 0.75})").await?;
tx.execute("CREATE (:QualitySignal {name: 'Cycle Life', pass_rate: 0.80})").await?;
tx.execute("CREATE (:QualitySignal {name: 'Drop Test', pass_rate: 0.70})").await?;
tx.execute("MATCH (v:Vendor {name:'ReliaCorp'}), (c:Component {name:'Sensor'}) CREATE (v)-[:SUPPLIES]->(c)").await?;
tx.execute("MATCH (v:Vendor {name:'ReliaCorp'}), (c:Component {name:'Motor'}) CREATE (v)-[:SUPPLIES]->(c)").await?;
tx.execute("MATCH (v:Vendor {name:'QuickParts'}), (c:Component {name:'Motor'}) CREATE (v)-[:SUPPLIES]->(c)").await?;
tx.execute("MATCH (v:Vendor {name:'QuickParts'}), (c:Component {name:'Controller'}) CREATE (v)-[:SUPPLIES]->(c)").await?;
tx.execute("MATCH (v:Vendor {name:'BudgetSupply'}), (c:Component {name:'Controller'}) CREATE (v)-[:SUPPLIES]->(c)").await?;
tx.execute("MATCH (v:Vendor {name:'BudgetSupply'}), (c:Component {name:'Battery'}) CREATE (v)-[:SUPPLIES]->(c)").await?;
tx.execute("MATCH (c:Component {name:'Sensor'}), (s:QualitySignal {name:'Thermal Test'}) CREATE (c)-[:HAS_SIGNAL]->(s)").await?;
tx.execute("MATCH (c:Component {name:'Sensor'}), (s:QualitySignal {name:'Vibration Test'}) CREATE (c)-[:HAS_SIGNAL]->(s)").await?;
tx.execute("MATCH (c:Component {name:'Motor'}), (s:QualitySignal {name:'Voltage Tolerance'}) CREATE (c)-[:HAS_SIGNAL]->(s)").await?;
tx.execute("MATCH (c:Component {name:'Motor'}), (s:QualitySignal {name:'Humidity Test'}) CREATE (c)-[:HAS_SIGNAL]->(s)").await?;
tx.execute("MATCH (c:Component {name:'Controller'}), (s:QualitySignal {name:'Load Test'}) CREATE (c)-[:HAS_SIGNAL]->(s)").await?;
tx.execute("MATCH (c:Component {name:'Controller'}), (s:QualitySignal {name:'EMC Test'}) CREATE (c)-[:HAS_SIGNAL]->(s)").await?;
tx.execute("MATCH (c:Component {name:'Battery'}), (s:QualitySignal {name:'Cycle Life'}) CREATE (c)-[:HAS_SIGNAL]->(s)").await?;
tx.execute("MATCH (c:Component {name:'Battery'}), (s:QualitySignal {name:'Drop Test'}) CREATE (c)-[:HAS_SIGNAL]->(s)").await?;
tx.commit().await?;
println!("Seeded graph data");

4) Locy Program

Rules derive relations, then QUERY ... WHERE ... RETURN ... projects the final answer.

let program = r#"CREATE RULE component_failure_risk AS\nMATCH (c:Component)-[:HAS_SIGNAL]->(s:QualitySignal)\nFOLD risk = MNOR(1.0 - s.pass_rate)\nYIELD KEY c, risk\n\nCREATE RULE vendor_reliability AS\nMATCH (v:Vendor)-[:SUPPLIES]->(c:Component)\nWHERE c IS component_failure_risk\nFOLD reliability = MPROD(1.0 - risk)\nYIELD KEY v, reliability\n\nQUERY component_failure_risk RETURN c.name AS component, risk\nQUERY vendor_reliability RETURN v.name AS vendor, reliability"#;

5) Evaluate

Evaluate the Locy program and inspect stats/rows.

let session = db.session();
let result = session.locy(program).await?;
println!("Derived relations: {:?}", result.derived.keys().collect::<Vec<_>>());
println!("Iterations: {}", result.stats().total_iterations);
println!("Queries executed: {}", result.stats().queries_executed);
for (name, rows) in &result.derived {
    println!("{}: {} row(s)", name, rows.len());
}

if let Some(rows) = result.rows() {
    println!("Rows: {:?}", rows);
}

6) What To Expect

Use these checks to validate output after evaluation: - Component risk ordering: Battery > Controller > Motor > Sensor (lower pass rates → higher risk). - Vendor reliability ordering: ReliaCorp > QuickParts > BudgetSupply. - MNOR values stay in [0, 1] — noisy-OR never exceeds 1.0 even with many signals. - MPROD values decrease with more components — each additional component can only reduce joint reliability. - Two query result blocks should appear: one for component_failure_risk, one for vendor_reliability.

Notes

  • Rust notebooks are included for API parity and learning.
  • In this docs build, Rust notebooks are rendered without execution.