Native Ports
py-scm is the reference linear-Gaussian implementation, but it is not the
only runtime we maintain. The same continuous reasoning surface is also
available in the C#, Java, C++, and TypeScript/JavaScript Darkstar ports in
the darkstar-bbn superproject.
These ports are maintained against the same shared fixtures and benchmark harness used for the Python reference. Continuous parity is checked on both the committed oracle models and generated Gaussian BBN sweeps, with deterministic size/topology runs across the five implementations.
The maintained continuous surface targets parity for:
pqueryiqueryequerycquerysamplescontinuous
serdeseeded singly- and multi-connected Gaussian BBN generation
Current port names and namespaces:
C#:RocketVector.DarkStar.ContinuousJava:io.rocketvector.darkstar.continuousC++:rocketvector::darkstar::continuousTypeScript / JavaScript: package@rocketvector/darkstarunderdarkstar.continuous
Code Examples
Each example below builds the same small linear-Gaussian model, then runs associational, interventional, average-causal-effect, and counterfactual queries against it.
C#
using RocketVector.DarkStar.Continuous;
var graph = GraphData.Create(
new[] { "C", "X", "Y" },
new[]
{
new[] { "C", "X" },
new[] { "C", "Y" },
new[] { "X", "Y" },
});
var parameters = Parameters.FromPayload(
new[] { "C", "X", "Y" },
new[] { 1.0017, 4.9960, 10.5033 },
new[]
{
new[] { 0.9907, 2.9799, 6.9569 },
new[] { 2.9799, 9.9734, 22.4469 },
new[] { 6.9569, 22.4469, 52.1280 },
});
var model = Reasoning.CreateReasoningModel(graph, parameters);
var posterior = model.Pquery(new Dictionary<string, double> { ["X"] = 4.0 });
var interventional = model.Iquery("Y", new Dictionary<string, double> { ["X"] = 4.0 });
var ace =
model.Equery(
"Y",
new Dictionary<string, double> { ["X"] = 5.0 },
new Dictionary<string, double> { ["X"] = 3.0 });
var counterfactual =
model.Cquery(
"Y",
new Dictionary<string, double> { ["C"] = 1.0, ["X"] = 4.0, ["Y"] = 10.0 },
new[]
{
(IReadOnlyDictionary<string, double>)new Dictionary<string, double> { ["X"] = 2.0 },
new Dictionary<string, double> { ["X"] = 6.0 },
});
Console.WriteLine(posterior.Mean.Get("Y"));
Console.WriteLine(interventional.Mean);
Console.WriteLine(ace.Mean);
Console.WriteLine(counterfactual.Row(0)[0]);
Java
import io.rocketvector.darkstar.continuous.GraphData;
import io.rocketvector.darkstar.continuous.Parameters;
import io.rocketvector.darkstar.continuous.Reasoning;
import java.util.List;
import java.util.Map;
var graph =
new GraphData(
List.of("C", "X", "Y"),
List.of(List.of("C", "X"), List.of("C", "Y"), List.of("X", "Y")));
var parameters =
Parameters.fromPayload(
List.of("C", "X", "Y"),
new double[] {1.0017, 4.9960, 10.5033},
new double[][] {
{0.9907, 2.9799, 6.9569},
{2.9799, 9.9734, 22.4469},
{6.9569, 22.4469, 52.1280}
});
var model = Reasoning.createReasoningModel(graph, parameters);
var posterior = model.pquery(Map.of("X", 4.0));
var interventional = model.iquery("Y", Map.of("X", 4.0));
var ace = model.equery("Y", Map.of("X", 5.0), Map.of("X", 3.0));
var counterfactual =
model.cquery(
"Y",
Map.of("C", 1.0, "X", 4.0, "Y", 10.0),
List.of(Map.of("X", 2.0), Map.of("X", 6.0)));
System.out.println(posterior.mean().get("Y"));
System.out.println(interventional.mean());
System.out.println(ace.mean());
System.out.println(counterfactual.row(0)[0]);
C++
#include <iostream>
#include "continuous.h"
using rocketvector::darkstar::continuous::GraphData;
using rocketvector::darkstar::continuous::Parameters;
using rocketvector::darkstar::continuous::createReasoningModel;
GraphData graph{
{"C", "X", "Y"},
{{"C", "X"}, {"C", "Y"}, {"X", "Y"}},
};
Parameters parameters{
{{"C", "X", "Y"}, {1.0017, 4.9960, 10.5033}},
{{"C", "X", "Y"},
{
{0.9907, 2.9799, 6.9569},
{2.9799, 9.9734, 22.4469},
{6.9569, 22.4469, 52.1280},
}},
};
auto model = createReasoningModel(graph, parameters);
auto posterior = model.pquery({{"X", 4.0}});
auto interventional = model.iquery("Y", {{"X", 4.0}});
auto ace = model.equery("Y", {{"X", 5.0}}, {{"X", 3.0}});
auto counterfactual =
model.cquery("Y", {{"C", 1.0}, {"X", 4.0}, {"Y", 10.0}},
{{{"X", 2.0}}, {{"X", 6.0}}});
std::cout << posterior.mean.get("Y") << '\n';
std::cout << interventional.mean << '\n';
std::cout << ace.mean << '\n';
std::cout << counterfactual.row(0).at(0) << '\n';
TypeScript / JavaScript
The TypeScript port compiles to JavaScript for Node, so the same public API is available from either language. The example below is plain modern JavaScript.
import { darkstar } from '@rocketvector/darkstar';
const graph = {
nodes: ['C', 'X', 'Y'],
edges: [['C', 'X'], ['C', 'Y'], ['X', 'Y']],
};
const parameters = {
v: ['C', 'X', 'Y'],
m: [1.0017, 4.9960, 10.5033],
S: [
[0.9907, 2.9799, 6.9569],
[2.9799, 9.9734, 22.4469],
[6.9569, 22.4469, 52.1280],
],
};
const model = darkstar.continuous.createReasoningModel(graph, parameters);
const posterior = model.pquery({ X: 4.0 });
const interventional = model.iquery('Y', { X: 4.0 });
const ace = model.equery('Y', { X: 5.0 }, { X: 3.0 });
const counterfactual = model.cquery(
'Y',
{ C: 1.0, X: 4.0, Y: 10.0 },
[{ X: 2.0 }, { X: 6.0 }]
);
console.log(posterior.mean.get('Y'));
console.log(interventional.mean);
console.log(ace.mean);
console.log(counterfactual.row(0)[0]);
Runtime Comparison
The shared continuous benchmark harness runs deterministic Gaussian models
across all five implementations and checks every non-Python query/serde/startup
output against the Python reference. It also supports generated singly- and
multi-connected size sweeps at 30, 50, 100, 250, 500, and
1000 nodes.
The saved measurements below reflect a generated multi Gaussian network at
SIZE=1000 rerun locally on April 4, 2026 after the retained continuous
hot-path optimizations. They are useful for relative comparisons, not as
universal absolutes.
In the saved continuous query runs, every non-Python port matched the Python reference on the generated Gaussian workload.
1000-Node Generated Gaussian Query Sweep
Language |
Cold query (ms) |
Warm query (ms) |
|---|---|---|
Python |
16.066 |
0.046 |
TypeScript / JavaScript |
73.979 |
0.850 |
Java |
17.609 |
0.804 |
C# |
52.427 |
1.088 |
C++ |
12.979 |
6.150 |
1000-Node Generated Gaussian Sampling Sweep
Language |
Warm sampling (ms) |
|---|---|
Python |
43.898 |
TypeScript / JavaScript |
90.290 |
Java |
81.199 |
C# |
53.493 |
C++ |
20.660 |
The largest improvements in these saved runs came from structural Gaussian sampling and target-only interventional evaluation, which avoid unnecessary dense covariance work on repeated continuous queries.