AnyLogic中如何使代码创建的自定义分布每次生成不同随机值
Hey there! Let's figure out why your CustomDistribution keeps spitting out the same value (14) every time, and get it generating varied random values like you need.
What's Going Wrong with Your Current Code
The main issue here is that you're creating a new CustomDistribution and a new Random instance every time you run the function. Here's why that breaks things:
- Every time you initialize a
CustomDistribution, it has to recalculate the empirical distribution from yourleadtimeslist—this is inefficient, but more importantly, - Creating a new
Random(seed)each time resets the random number sequence from scratch. Even with different seeds, if the firstnextDouble()call from each newRandominstance happens to land in the probability range that maps to 14, you'll keep getting that value.
The Fix: Reuse Instances and Use AnyLogic's Built-in Random Tools
AnyLogic is designed to manage randomness efficiently, so let's adjust your approach to align with that:
Step 1: Initialize Your Distribution and Random Generator Once
Instead of creating these objects inside your custom function, set them up once when your model starts (e.g., in the onStartup event of your Main agent):
// First, define global variables in your Main agent (or wherever makes sense for your model) CustomDistribution leadTimeDistribution; RandomNumberGenerator rng; // In the onStartup event: // Convert your integer list to doubles (CustomDistribution expects double values) List<Double> leadTimesAsDoubles = leadtimes.stream() .map(Integer::doubleValue) .collect(Collectors.toList()); // Initialize the distribution once leadTimeDistribution = new CustomDistribution(leadTimesAsDoubles); // Use AnyLogic's built-in random generator (better integrated with model-wide randomness) rng = getEngine().getRandomNumberGenerator();
Step 2: Use the Reused Instances in Your Custom Function
Now, in your custom function, just call get() on the pre-initialized distribution with your shared random generator:
// Get a random lead time and cast back to int int delay = (int) leadTimeDistribution.get(rng);
Alternative: Use EmpiricalDistribution for Integer Values
If you're working strictly with integers, AnyLogic's EmpiricalDistribution is a better fit (it handles integer types directly, no casting needed):
// Global variable in Main agent EmpiricalDistribution<Integer> leadTimeEmpiricalDist; // On startup: leadTimeEmpiricalDist = new EmpiricalDistribution<>(leadtimes); rng = getEngine().getRandomNumberGenerator(); // In your function: int delay = leadTimeEmpiricalDist.sample(rng);
Why This Works
- Reusing the same
CustomDistribution/EmpiricalDistributionensures the empirical probability calculations are done once, and the distribution maintains its state between calls. - Using AnyLogic's
RandomNumberGenerator(instead of Java'sRandom) keeps your randomness aligned with the model's overall random seed management—you can even control the model's seed from the run configuration if needed.
内容的提问来源于stack exchange,提问作者 Annis99

