Skip to content

Commit ec0176c

Browse files
kubeclaude
andcommitted
H-5641: Add Distribution.Lognormal(mu, sigma) support
Uses standard mathematical parameterization where mu and sigma are the mean and standard deviation of the underlying normal distribution ln(X). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1bfa504 commit ec0176c

2 files changed

Lines changed: 18 additions & 0 deletions

File tree

libs/@hashintel/petrinaut/src/lsp/lib/generate-virtual-files.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export function generateVirtualFiles(sdcpn: SDCPN): Map<string, VirtualFile> {
3232
`declare namespace Distribution {`,
3333
` function Gaussian(mean: number, deviation: number): Distribution;`,
3434
` function Uniform(min: number, max: number): Distribution;`,
35+
` function Lognormal(mu: number, sigma: number): Distribution;`,
3536
`}`,
3637
].join("\n"),
3738
});

libs/@hashintel/petrinaut/src/simulation/simulator/distribution.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ export type RuntimeDistribution =
1919
deviation: number;
2020
})
2121
| (DistributionBase & { type: "uniform"; min: number; max: number })
22+
| (DistributionBase & {
23+
type: "lognormal";
24+
mu: number;
25+
sigma: number;
26+
})
2227
| (DistributionBase & {
2328
type: "mapped";
2429
inner: RuntimeDistribution;
@@ -55,6 +60,9 @@ export const distributionRuntimeCode = `
5560
},
5661
Uniform: function(min, max) {
5762
return __addMap({ __brand: "distribution", type: "uniform", min: min, max: max });
63+
},
64+
Lognormal: function(mu, sigma) {
65+
return __addMap({ __brand: "distribution", type: "lognormal", mu: mu, sigma: sigma });
5866
}
5967
};
6068
`;
@@ -93,6 +101,15 @@ export function sampleDistribution(
93101
nextRng = newRng;
94102
break;
95103
}
104+
case "lognormal": {
105+
// Lognormal(μ, σ): if X ~ Normal(μ, σ), then e^X ~ Lognormal(μ, σ)
106+
const [u1, rng1] = nextRandom(rngState);
107+
const [u2, rng2] = nextRandom(rng1);
108+
const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
109+
value = Math.exp(distribution.mu + z * distribution.sigma);
110+
nextRng = rng2;
111+
break;
112+
}
96113
case "mapped": {
97114
const [innerValue, newRng] = sampleDistribution(
98115
distribution.inner,

0 commit comments

Comments
 (0)