Skip to content

Commit

Permalink
fix(implementationbase): WeibullTime now generate times based on freq…
Browse files Browse the repository at this point in the history
…uency as other time distributions (#3512)
  • Loading branch information
anitvam committed Jun 6, 2024
1 parent 3ca5a47 commit cbbb046
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 175 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public WeibullDistributedWeibullTime(

private static double weibullValue(final double mean, final double deviation, final RandomGenerator random) {
if (deviation > 0) {
final WeibullDistribution dist = weibullFromMean(mean, deviation, random);
final WeibullDistribution dist = WeibullTime.Companion.weibullFromMean(mean, deviation, random);
return dist.inverseCumulativeProbability(random.nextDouble());
}
return mean;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package it.unibo.alchemist.model.timedistributions

import it.unibo.alchemist.model.Environment
import it.unibo.alchemist.model.Node
import it.unibo.alchemist.model.Time
import it.unibo.alchemist.model.times.DoubleTime
import org.apache.commons.math3.distribution.WeibullDistribution
import org.apache.commons.math3.random.RandomGenerator
import org.apache.commons.math3.special.Gamma
import org.apache.commons.math3.util.FastMath

/**
* Weibull distributed events.
*
* @param <T> concentration type
*/
open class WeibullTime<T> private constructor(
private val randomGenerator: RandomGenerator,
private val backingDistribution: WeibullDistribution,
private val offset: Double,
start: Time,
) : AbstractDistribution<T?>(start) {

/**
* @param mean
* mean for this distribution
* @param deviation
* standard deviation for this distribution
* @param random
* {@link RandomGenerator} used internally
*/
constructor(mean: Double, deviation: Double, random: RandomGenerator) : this(
mean,
deviation,
DoubleTime(random.nextDouble() * mean),
random,
)

/**
* @param mean
* mean for this distribution
* @param deviation
* standard deviation for this distribution
* @param start
* initial time
* @param random
* {@link RandomGenerator} used internally
*/
constructor(mean: Double, deviation: Double, start: Time, random: RandomGenerator) : this(
random,
weibullFromMean(mean, deviation, random),
0.0,
start,
)

/**
* @param shapeParameter
* shape parameter for this distribution
* @param scaleParameter
* shape parameter for this distribution
* @param offsetParameter
* minimum possible time interval for this distribution
* @param start
* initial time
* @param random
* {@link RandomGenerator} used internally
*/
constructor(
shapeParameter: Double,
scaleParameter: Double,
offsetParameter: Double,
start: Time,
random: RandomGenerator,
) : this(
random,
WeibullDistribution(random, shapeParameter, scaleParameter, PREFERRED_INVERSE_CUMULATIVE_ACCURACY),
offsetParameter,
start,
)

override fun updateStatus(currentTime: Time, executed: Boolean, param: Double, environment: Environment<T?, *>?) {
if (executed) {
this.setNextOccurrence(currentTime.plus(DoubleTime(1.0 / this.genSample())))
}
}

/**
* @return a sample from the distribution
*/
protected fun genSample(): Double =
backingDistribution.inverseCumulativeProbability(randomGenerator.nextDouble()) + this.offset

/**
* @return the mean for this distribution.
*/
val mean: Double
get() = backingDistribution.numericalMean + this.offset

/**
* @return the standard deviation for this distribution.
*/
val deviation: Double
get() = FastMath.sqrt(backingDistribution.numericalVariance)

override fun getRate(): Double = this.mean

override fun cloneOnNewNode(
destination: Node<T?>,
currentTime: Time,
): WeibullTime<T?> = WeibullTime(
this.randomGenerator,
this.backingDistribution,
this.offset,
currentTime,
)

companion object {
private const val PREFERRED_INVERSE_CUMULATIVE_ACCURACY = 1.0E-9

/**
* Generates a {@link WeibullDistribution} given its mean and standard deviation.
*
* @param mean
* the mean
* @param deviation
* the standard deviation
* @param random
* the random generator
* @return a new {@link WeibullDistribution}
*/
protected fun weibullFromMean(mean: Double, deviation: Double, random: RandomGenerator?): WeibullDistribution {
val t = FastMath.log(deviation * deviation / (mean * mean) + 1.0)
var kmin = 0.0

var kmax: Double
kmax = 1.0
while (Gamma.logGamma(1.0 + 2.0 * kmax) - 2.0 * Gamma.logGamma(1.0 + kmax) < t) {
kmin = kmax
kmax *= 2.0
}

var k: Double
k = (kmin + kmax) / 2.0
while (kmin < k && k < kmax) {
if (Gamma.logGamma(1.0 + 2.0 * k) - 2.0 * Gamma.logGamma(1.0 + k) < t) {
kmin = k
} else {
kmax = k
}
k = (kmin + kmax) / 2.0
}

val shapeParameter = 1.0 / k
val scaleParameter = mean / FastMath.exp(Gamma.logGamma(1.0 + k))
return WeibullDistribution(random, shapeParameter, scaleParameter, PREFERRED_INVERSE_CUMULATIVE_ACCURACY)
}
}
}

0 comments on commit cbbb046

Please sign in to comment.