diff --git a/README.md b/README.md index a7bc61f..0a3bdb7 100644 --- a/README.md +++ b/README.md @@ -205,11 +205,11 @@ minutes, in this case: ## Using other distributions Although the Markov process is the most commonly used to model queueing systems, -your particular use case may be better modeled by some process. For example, in -many applications, batch jobs are triggered periodically by some scheduler -like [cron]. The service time may still be exponentially distributed, but the -inter-arrival time is now deterministic. To model these situations, use the -lower-level API provided by the _general_ process: +your particular use case may be better modeled by some other process. For +example, in many applications, batch jobs are triggered periodically by some +scheduler like [cron]. The service time may still be exponentially distributed, +but the inter-arrival time is now deterministic. To model these situations, use +the lower-level API provided by the `general` process: ```ts const simulator = BatchSimulator.general(stack); @@ -225,9 +225,10 @@ const report = simulator.simulate([{ }]); ``` -If you need to use some more probability distribution that is not available in -the `Distribution` class, you can bring your own, by implementing the -`IDistribution` interface. +In addition to deterministic and exponential distributions, the simulator also +offers an implementation of the [Erlang distribution]. But If you need to use +some probability distribution that is not available in the `Distribution` class, +you can bring your own, by implementing the `IDistribution` interface. ## Unsupported features (yet) @@ -248,4 +249,6 @@ Some of the AWS Batch features are not being simulated by this library: [mmc]: https://www.wikiwand.com/en/M/M/c_queue -[cron]: https://en.wikipedia.org/wiki/Cron \ No newline at end of file +[cron]: https://en.wikipedia.org/wiki/Cron + +[Erlang distribution]: https://en.wikipedia.org/wiki/Erlang_distribution \ No newline at end of file diff --git a/src/random.ts b/src/random.ts index 898e554..1e4ca39 100644 --- a/src/random.ts +++ b/src/random.ts @@ -26,6 +26,10 @@ export interface IDistribution { export class Distribution { static deterministic(value: number): IDistribution { + if (value <= 0) { + throw new Error(`The deterministic time must be positive. Got ${value}`); + } + return new class implements IDistribution { nextTime(): number { return value; @@ -34,9 +38,29 @@ export class Distribution { } static exponential(lambda: number): IDistribution { + if (lambda <= 0) { + throw new Error(`The parameter of the exponential distribution must be positive. Got ${lambda}`); + } + + return this.erlang(1, lambda); + } + + static erlang(k: number, lambda: number): IDistribution { + if (lambda <= 0) { + throw new Error(`The rate parameter (λ) of the Erlang distribution must be positive. Got ${lambda}`); + } + + if (!(Number.isInteger(k) && k > 0)) { + throw new Error(`The shape parameter (k) of the Erlang distribution must be a positive integer. Got ${k}`); + } + return new class implements IDistribution { nextTime(): number { - return -Math.log(Math.random()) / lambda; + let sum = 0; + for (let i = 0; i < k; i++) { + sum += Math.log(Math.random()); + } + return -sum / lambda; } }; }