Java 复杂生产线未来货物数量的计算算法
这是一篇很长的文章,但只有前半部分才真正相关 第二部分只描述了我试图解决的问题,但在我看来效率太低的问题(这可能有助于了解我想要什么)。相关部分以粗体问题后的一行结束 我试图在一个想象中的工厂里模拟多个产品,以计算出每种已知类型的商品在最后会有多少。有几种不同的商品类型,它们都有特定的最大生产能力,只有在有足够的原料可用的情况下才能达到。生产线的外观示例如下: 底部的货物都有一个已知的运送到工厂的速度,因此对于这些货物来说,没有什么可计算的,尽管这个速度会随着时间的推移而变化(同时,最大生产能力也会在任何时间点发生变化,例如,可以通过增加工人或更多机器来增加产能) 如图所示,对于其他商品,有三个方面需要考虑:Java 复杂生产线未来货物数量的计算算法,java,algorithm,simulation,Java,Algorithm,Simulation,这是一篇很长的文章,但只有前半部分才真正相关 第二部分只描述了我试图解决的问题,但在我看来效率太低的问题(这可能有助于了解我想要什么)。相关部分以粗体问题后的一行结束 我试图在一个想象中的工厂里模拟多个产品,以计算出每种已知类型的商品在最后会有多少。有几种不同的商品类型,它们都有特定的最大生产能力,只有在有足够的原料可用的情况下才能达到。生产线的外观示例如下: 底部的货物都有一个已知的运送到工厂的速度,因此对于这些货物来说,没有什么可计算的,尽管这个速度会随着时间的推移而变化(同时,最大生产能
- 有些生产线从一条生产线到另一条生产线再生产一条
- 有些生产线从另外两条生产线中选出一条
- 一些行有一个好的用于创建多个新的好 (例如,请参见插图中间的“R8”)
- 每种商品的最大生产率(例如,每小时生产5台)
- 对于最底层的货物,我们有交付到工厂的数量(例如,每小时交付5次)
- 现在每个产品的库存量是多少(因此,如果交付的数量不够,如果我们还有一些库存,我们就不需要减少生产)
- 货物交付的时间会发生变化(可能发生在底部的任何货物上)
- 一种商品的最大生产率会在什么时候发生变化(可能发生在任何不在底部的商品上)
我试图解决这个问题的方法如下:
剩余的
集合和已检查的
集合中(底部的商品立即被检查)public class FactoryGoods {
private long future;
private long now;
private Map<String, Integer> availableGoods;
private Map<String, ArrayList<ProductionInterval>> hourlyGoodIncrease;
/**
*
* @param future long current time
* @param now long last time the factory's resources got updates
* @param availableGoods Map<String,Integer> of the goods in the factory
* @param hourlyGoodIncrease Map<String,ArrayList<ProductionInterval>> of the intervals of production quantities for the goods
*/
public factoryGoods(long future, long now, Map<String,Integer> availableGoods, Map<String,ArrayList<ProductionInterval>> hourlyGoodIncrease) {
this.future = future;
this.now = now;
this.availableGoods = availableGoods;
this.hourlyGoodIncrease = hourlyGoodIncrease;
}
/**
* Calculates the resources present in a factory's storage
* @return a Map of quantities mapped on the String name of the good
*/
public Map<String,Integer> getResources() {
// Make sure all goods to have all goods inside the loop, to work on goods,
// that are produced, but also those which are only in store
HashMap<String, Boolean> goodChecked = new HashMap<String,Boolean>();
Set<String> remaining = new HashSet<String>();
for (Goods good: Goods.values()) {
String g = good.get();
if (hourlyGoodIncrease.get(g) == null) {
ArrayList<ProductionInterval> prods = new ArrayList<ProductionInterval>();
ProductionInterval start = new ProductionInterval(now, 0);
prods.add(start);
hourlyGoodIncrease.put(g, prods);
}
if (availableGoods.get(g) == null) {
availableGoods.put(g, 0);
}
if (good.isPrimary()) {
goodChecked.put(g, true);
} else {
goodChecked.put(g, false);
}
remaining.add(g);
}
// As long as goods are remaining to be checked loops over the goods, and
// recalculates hourly good increases for goods, that have all its sources
// already calculated
while (remaining.size() > 0) {
Set<String> removes = new HashSet<String>();
for (String good: remaining) {
if (goodChecked.get(good)) {
Good g = GoodFactory.get(good);
Set<String> to = new HashSet<String>();
Map<String,Float> from = new HashMap<String,Float>();
setUpFromAndToGoods(g, to, from, availableGoods);
if (areGoodsAlreadyCalculated(to, goodChecked)) {
//remaining.remove(good);
removes.add(good);
} else {
if (areGoodsReadyForCalculation(to, goodChecked)) {
// Get all resources we are working on now
Map<String,Float> fromDecrease = new HashMap<String,Float>();
for (String t: to) {
for (String f: GoodFactory.get(t).isMadeFrom().keySet()) {
from.put(f, (float) availableGoods.get(f));
}
}
// Get all interval borders
ArrayList<Long> intervalBorders = new ArrayList<Long>();
for (String wGood: from.keySet()) {
ArrayList<ProductionInterval> intervals = hourlyGoodIncrease.get(wGood);
for (ProductionInterval interval: intervals) {
long intervalStart = interval.getStartTime();
if (!intervalBorders.contains(intervalStart)) {
intervalBorders.add(intervalStart);
}
}
}
Collections.sort(intervalBorders);
intervalBorders.add(future);
for (String f: from.keySet()) {
hourlyGoodIncrease.put(f, createNewProductionIntervalls(intervalBorders, hourlyGoodIncrease.get(f)));
}
// For all intervals
int iLast = intervalBorders.size() - 1;
for (int i = 0; i < iLast; i++) {
long elapsedTime = intervalBorders.get(i + 1) - intervalBorders.get(i);
for (String t: to) {
Map<String, Float> source = GoodFactory.get(t).isMadeFrom();
for (String s: source.keySet()) {
Float decrease = fromDecrease.get(s);
fromDecrease.put(s, (decrease != null ? decrease : 0) + source.get(s));
}
}
// Calculate amount after normal maximum production
Set<String> negatives = new HashSet<String>();
Map<String,Float> nextFrom = new HashMap<String,Float>();
for (String f: from.keySet()) {
float delta = from.get(f) + (hourlyGoodIncrease.get(f).get(i).getHourlyIncrease() - fromDecrease.get(f)) * elapsedTime / (1000 * 60 * 60);
nextFrom.put(f, delta);
if (delta < 0) {
negatives.add(f);
}
}
// Check if got under zero
if (negatives.size() == 0) {
for (String f: from.keySet()) {
float newIncrease = hourlyGoodIncrease.get(f).get(i).getHourlyIncrease() - fromDecrease.get(f);
hourlyGoodIncrease.get(f).get(i).setHourlyIncrease(newIncrease);
from.put(f, nextFrom.get(f));
}
} else {
// TODO: handle case when more is used than exists
}
// Else calculate point where at least one from is zero and add an interval
// before its maximum, after needs to be adjusted
}
// Break to remove all calculated goods from the remaining set and rerun the loop
removes = to;
break;
}
}
}
}
for (String remove: removes) {
remaining.remove(remove);
}
}
// Final calculation of the goods amounts that are available in the factory
for (String good: goodChecked.keySet()) {
ArrayList<ProductionInterval> intervals = hourlyGoodIncrease.get(good);
intervals.add(new ProductionInterval(future, 0));
float after = availableGoods.get(good);
for (int i = 0; i < (intervals.size() - 1); i++) {
after += intervals.get(i).getHourlyIncrease() * (intervals.get(i + 1).getStartTime() - intervals.get(i).getStartTime()) / (1000 * 60 * 60);
}
availableGoods.put(good, (int) after);
}
return availableGoods;
}
private static ArrayList<ProductionInterval> createNewProductionIntervalls(ArrayList<Long> intervalBorders, ArrayList<ProductionInterval> hourlyIncreases) {
System.out.print("intervalBorders\n");
System.out.print(intervalBorders + "\n");
System.out.print("hourlyIncreases\n");
System.out.print(hourlyIncreases + "\n");
ArrayList<ProductionInterval> intervalls = new ArrayList<ProductionInterval>();
int i = 0;
long iTime = 0;
long nextTime = 0;
for (long l: intervalBorders) {
float increase = 0;
iTime = hourlyIncreases.get(i).getStartTime();
if (i + 1 < hourlyIncreases.size()) {
nextTime = hourlyIncreases.get(i + 1).getStartTime();
}
if (l == iTime) {
increase = hourlyIncreases.get(i).getHourlyIncrease();
} else if (iTime < l && l < nextTime) {
increase = hourlyIncreases.get(i).getHourlyIncrease();
} else if (l == nextTime) {
increase = hourlyIncreases.get(++i).getHourlyIncrease();
}
intervalls.add(new ProductionInterval(l, increase));
}
return intervalls;
}
private static void setUpFromAndToGoods(Good g, Set<String> to, Map<String,Float> from, Map<String,Integer> availableGoods) {
Set<String> unchecked = g.isUsedToCreate();
while (unchecked.size() > 0) {
String good = unchecked.iterator().next();
unchecked.remove(good);
to.add(good);
Set<String> madeFrom = GoodFactory.get(good).isMadeFrom().keySet();
for (String fromGood: madeFrom) {
if (!from.containsKey(fromGood)) {
from.put(fromGood, (float) availableGoods.get(fromGood));
Set<String> additions = GoodFactory.get(fromGood).isUsedToCreate();
for (String addition: additions) {
if (!to.contains(addition) && !unchecked.contains(addition)) {
unchecked.add(addition);
}
}
}
}
}
}
private static boolean areGoodsReadyForCalculation(Set<String> toGoods, Map<String,Boolean> goodChecked) {
for (String t: toGoods) {
Good toGood = GoodFactory.get(t);
for (String from: toGood.isMadeFrom().keySet()) {
if (!goodChecked.get(from)) {
return false;
}
}
}
return true;
}
private static boolean areGoodsAlreadyCalculated(Set<String> toGoods, Map<String,Boolean> goodChecked) {
for (String t: toGoods) {
if (!goodChecked.get(t)) {
return false;
}
}
return true;
}
}
public class ProductionInterval {
private long startTime;
private float hourlyIncrease;
public ProductionInterval(long startTime, float hourlyIncrease) {
this.setStartTime(startTime);
this.setHourlyIncrease(hourlyIncrease);
}
public float getHourlyIncrease() {
return hourlyIncrease;
}
public void setHourlyIncrease(float hourlyIncrease) {
this.hourlyIncrease = hourlyIncrease;
}
public long getStartTime() {
return startTime;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
}
public String toString() {
return "<starttime=" + this.startTime + ", hourlyIncrease=" + this.hourlyIncrease + ">";
}
}
公共类工厂产品{
私人长远发展;
私人长现在;
可获得的私有地图;
私人地图小时增长;
/**
*
*@param未来长当前时间
*@param现在是上次工厂资源更新的时候了
*@param工厂内货物的可用goods地图
*@param hourlygoodIngress商品生产数量间隔图
*/
公共工厂商品(长期未来、长期现在、地图可用商品、地图小时增长){
this.future=未来;
this.now=现在;
this.availableGoods=availableGoods;
this.hourlyGoodIncrease=hourlyGoodIncrease;
}
/**
*计算工厂存储中存在的资源
*@返回货物字符串名称上映射的数量图
*/
公共地图获取资源(){
//确保所有货物都在回路中,以便处理货物,
//这些都是生产出来的,但也有那些只在商店里
HashMap goodChecked=新建HashMap();
Set剩余=新的HashSet();
对于(货物:good.values()){
字符串g=good.get();
if(hourlyGoodIncrease.get(g)==null){
ArrayList prods=新的ArrayList();
ProductionInterval开始=新ProductionInterval(现在为0);
产品添加(开始);
hourlyGoodIncrease.put(g,prods);
#include <cassert>
#include <iostream>
#include <limits>
#include <utility>
#include <vector>
// Identifies a type of good in some Factory.
using Good = int;
// Simulates a factory. The simulation is crude, assuming continuous,
// fractional, zero-latency production. Nevertheless it may be accurate enough
// for high production volumes over long periods of time.
class Factory {
public:
// Declares a new raw material. `delivery_rate` is the amount of this good
// delivered per hour.
Good NewRawMaterial(double stock, double delivery_rate) {
assert(stock >= 0.0);
assert(delivery_rate >= 0.0);
return NewGood(stock, delivery_rate, {});
}
// Declares a new manufactured good. `max_production_rate` is the max amount
// of this good produced per hour. Producing one of this good consumes one
// `input`.
Good NewManufacturedGood(double stock, double max_production_rate,
Good input) {
assert(stock >= 0.0);
assert(max_production_rate >= 0.0);
return NewGood(stock, max_production_rate, {input});
}
// Declares a new manufactured good. `max_production_rate` is the max amount
// of this good produced per hour. Producing one of this good consumes one
// `input_a` and one `input_b`.
Good NewManufacturedGood(double stock, double max_production_rate,
Good input_a, Good input_b) {
assert(stock >= 0.0);
assert(max_production_rate >= 0.0);
return NewGood(stock, max_production_rate, {input_a, input_b});
}
// Returns the number of hours since the start of the simulation.
double Now() const { return current_time_; }
// Advances the current time to `time` hours since the start of the
// simulation.
void AdvanceTo(double time);
// Returns the amount of `good` in stock as of the current time.
double Stock(Good good) const { return stock_[good]; }
// Sets the delivery rate of `good` to `delivery_rate` as of the current time.
void SetDeliveryRate(Good good, double delivery_rate) {
assert(delivery_rate >= 0.0);
max_production_rate_[good] = delivery_rate;
}
// Sets the max production rate of `good` to `max_production_rate` as of the
// current time.
void SetMaxProductionRate(Good good, double max_production_rate) {
assert(max_production_rate >= 0.0);
max_production_rate_[good] = max_production_rate;
}
private:
// Floating-point tolerance.
static constexpr double kEpsilon = 1e-06;
// Declares a new good. We handle raw materials as goods with no inputs.
Good NewGood(double stock, double max_production_rate,
std::vector<Good> inputs) {
assert(stock >= 0.0);
assert(max_production_rate >= 0.0);
Good good = stock_.size();
stock_.push_back(stock);
max_production_rate_.push_back(max_production_rate);
inputs_.push_back(std::move(inputs));
return good;
}
// Returns the right-hand derivative of stock.
std::vector<double> Derivative() const;
// Returns the next time at which a good is newly out of stock, or positive
// infinity if there is no such time.
double NextStockOutTime(const std::vector<double> &derivative) const;
// The current time, in hours since the start of the simulation.
double current_time_ = 0.0;
// `stock_[good]` is the amount of `good` in stock at the current time.
std::vector<double> stock_;
// `max_production_rate_[good]` is the max production rate of `good` at the
// current time.
std::vector<double> max_production_rate_;
// `inputs_[good]` is the list of goods required to produce `good` (empty for
// raw materials).
std::vector<std::vector<Good>> inputs_;
// Derivative of `stock_`.
std::vector<double> stock_rate_;
};
void Factory::AdvanceTo(double time) {
assert(time >= current_time_);
bool caught_up = false;
while (!caught_up) {
auto derivative = Derivative();
double next_time = NextStockOutTime(derivative);
if (time <= next_time) {
next_time = time;
caught_up = true;
}
for (Good good = 0; good < stock_.size(); good++) {
stock_[good] += (next_time - current_time_) * derivative[good];
}
current_time_ = next_time;
}
}
std::vector<double> Factory::Derivative() const {
// TODO: this code prioritizes limited supply by the order in which production
// is declared. You probably want to use linear programming or something.
std::vector<double> derivative = max_production_rate_;
for (Good good = 0; good < stock_.size(); good++) {
for (Good input : inputs_[good]) {
if (stock_[input] <= kEpsilon) {
derivative[good] = std::min(derivative[good], derivative[input]);
}
}
for (Good input : inputs_[good]) {
derivative[input] -= derivative[good];
}
}
return derivative;
}
double Factory::NextStockOutTime(const std::vector<double> &derivative) const {
double duration = std::numeric_limits<double>::infinity();
for (Good good = 0; good < stock_.size(); good++) {
if (stock_[good] > kEpsilon && derivative[good] < -kEpsilon) {
duration = std::min(duration, stock_[good] / -derivative[good]);
}
}
return current_time_ + duration;
}
int main() {
Factory factory;
Good r1 = factory.NewRawMaterial(60.0, 3.0);
Good r2 = factory.NewRawMaterial(20.0, 1.0);
Good r3 = factory.NewManufacturedGood(0.0, 2.0, r1);
Good r4 = factory.NewManufacturedGood(0.0, 1.0, r1, r2);
auto print_stocks = [&]() {
std::cout << "t : " << factory.Now() << "\n";
std::cout << "r1: " << factory.Stock(r1) << "\n";
std::cout << "r2: " << factory.Stock(r2) << "\n";
std::cout << "r3: " << factory.Stock(r3) << "\n";
std::cout << "r4: " << factory.Stock(r4) << "\n";
std::cout << "\n";
};
print_stocks();
// Everything running smoothly
factory.AdvanceTo(24.0);
print_stocks();
// Uh oh, r1 supply cut off. Stock out at 44 hours.
factory.SetDeliveryRate(r1, 0.0);
factory.AdvanceTo(48.0);
print_stocks();
// r1 supply at 50%. r3 production prioritized.
factory.SetDeliveryRate(r1, 1.5);
factory.AdvanceTo(72.0);
print_stocks();
// r1 oversupplied.
factory.SetDeliveryRate(r1, 4.0);
factory.AdvanceTo(96.0);
print_stocks();
}
t : 0
r1: 60
r2: 20
r3: 0
r4: 0
t : 24
r1: 60
r2: 20
r3: 48
r4: 24
t : 48
r1: 0
r2: 24
r3: 88
r4: 44
t : 72
r1: 0
r2: 48
r3: 124
r4: 44
t : 96
r1: 24
r2: 48
r3: 172
r4: 68